diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..7481ade57b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,201 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = tab +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = true + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + +# Field preferences +dotnet_style_readonly_field = true:suggestion + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_local_function = true:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion + +# Expression-level preferences +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = false +csharp_new_line_before_else = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = methods,types +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = false + +# Space preferences +csharp_space_after_cast = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..72ffe3f6df --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ['https://paypal.me/pools/c/857bnxBTXg'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..d94a74e5f4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Platform (please complete the following information):** + - OS: [e.g. Windows, Linux, MacOS, iOS, Android, Windows Phone, etc.] + - .NET Runtime: [e.g. CoreCLR, Mono] + - .NET Framework: [e.g. .Net Core, .NET 4.5, UWP, etc.] + - MimeKit Version: + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..066b2d920a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.gitignore b/.gitignore index e45da4800f..89cd9f284c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ +MimeKit/Resources/Resource.designer.cs Mono.Data.Sqlite/Documentation +project.nuget.cache *project.lock.json *.csproj.nuget.cache +*.csproj.nuget.dgspec.json *.userprefs *.user *.suo diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8ac64ba8e6..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,7 +0,0 @@ -[submodule "submodules/Portable.Text.Encoding"] - path = submodules/Portable.Text.Encoding - url = https://github.com/jstedfast/Portable.Text.Encoding.git -[submodule "submodules/bc-csharp"] - path = submodules/bc-csharp - url = https://github.com/jstedfast/bc-csharp.git - branch = build-fix diff --git a/.nuget/packages.config b/.nuget/packages.config deleted file mode 100644 index eb80f3b1ce..0000000000 --- a/.nuget/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/.travis.yml b/.travis.yml index 5e950c527f..928ed87bf0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,8 @@ language: csharp -solution: MimeKit.Net45.sln +dotnet: 3.1.402 +solution: MimeKit.sln +install: + - dotnet restore MimeKit.sln +script: + - msbuild /p:Configuration=Debug /p:MonoRuntime=true MimeKit.sln + - mono ~/.nuget/packages/nunit.consolerunner/3.11.1/tools/nunit3-console.exe UnitTests/bin/Debug/net48/UnitTests.dll diff --git a/MimeKit/CancellationToken.cs b/Benchmarks/BenchmarkHelper.cs similarity index 51% rename from MimeKit/CancellationToken.cs rename to Benchmarks/BenchmarkHelper.cs index 9b3d8d6077..f0cc328b08 100644 --- a/MimeKit/CancellationToken.cs +++ b/Benchmarks/BenchmarkHelper.cs @@ -1,9 +1,9 @@ // -// CancellationToken.cs +// BenchmarkHelper.cs // -// Author: Jeffrey Stedfast +// Author: Jeffrey Stedfast // -// Copyright (c) 2015 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,52 +25,37 @@ // using System; +using System.IO; -namespace System.Threading { - public struct CancellationToken +namespace Benchmarks { + static class BenchmarkHelper { - public static readonly CancellationToken None = new CancellationToken (); + public static readonly string ProjectDir; + public static readonly string UnitTestsDir; - public bool CanBeCancelled { - get { return false; } - } - - public bool IsCancellationRequested { - get { return false; } - } - - public void ThrowIfCancellationRequested () + static BenchmarkHelper () { - if (IsCancellationRequested) - throw new OperationCanceledException (); - } + var codeBase = typeof (BenchmarkHelper).Assembly.CodeBase; + if (codeBase.StartsWith ("file://", StringComparison.OrdinalIgnoreCase)) + codeBase = codeBase.Substring ("file://".Length); - public bool Equals (CancellationToken other) - { - return true; - } + if (Path.DirectorySeparatorChar == '\\') { + if (codeBase[0] == '/') + codeBase = codeBase.Substring (1); - public override bool Equals (object obj) - { - if (obj is CancellationToken) - return Equals ((CancellationToken) obj); + codeBase = codeBase.Replace ('/', '\\'); + } - return false; - } + var dir = Path.GetDirectoryName (codeBase); - public override int GetHashCode () - { - return base.GetHashCode (); - } + while (Path.GetFileName (dir) != "Benchmarks") + dir = Path.GetFullPath (Path.Combine (dir, "..")); - public static bool operator == (CancellationToken left, CancellationToken right) - { - return left.Equals (right); - } + ProjectDir = Path.GetFullPath (dir); - public static bool operator != (CancellationToken left, CancellationToken right) - { - return !left.Equals (right); + dir = Path.Combine (dir, "..", "UnitTests"); + + UnitTestsDir = Path.GetFullPath (dir); } } } diff --git a/Benchmarks/Benchmarks.csproj b/Benchmarks/Benchmarks.csproj new file mode 100644 index 0000000000..d701b284c8 --- /dev/null +++ b/Benchmarks/Benchmarks.csproj @@ -0,0 +1,29 @@ + + + + net47 + true + $(DefineConstants);MONO + ..\MimeKit\mimekit.snk + false + false + Exe + + + + + + + + + + + + + + + + + + + diff --git a/Benchmarks/MimeParserBenchmarks.cs b/Benchmarks/MimeParserBenchmarks.cs new file mode 100644 index 0000000000..e315b93cf2 --- /dev/null +++ b/Benchmarks/MimeParserBenchmarks.cs @@ -0,0 +1,68 @@ +// +// MimeParserBenchmarks.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using BenchmarkDotNet.Attributes; + +using MimeKit; + +namespace Benchmarks { + public class MimeParserBenchmarks + { + static readonly string MessagesDataDir = Path.Combine (BenchmarkHelper.ProjectDir, "TestData", "messages"); + static readonly string MboxDataDir = Path.Combine (BenchmarkHelper.ProjectDir, "TestData", "mbox"); + + static void BenchmarkMimeParser (string fileName, bool persistent = false) + { + var path = Path.Combine (MessagesDataDir, fileName); + + using (var stream = File.OpenRead (path)) { + var parser = new MimeParser (stream, MimeFormat.Entity, persistent); + + for (int i = 0; i < 1000; i++) { + parser.ParseMessage (); + + stream.Position = 0; + parser.SetStream (stream, MimeFormat.Entity, persistent); + } + } + } + + [Benchmark] + public void BenchmarkStarTrekMessage () + { + BenchmarkMimeParser ("startrek.eml"); + } + + [Benchmark] + public void BenchmarkStarTrekMessagePersistent () + { + BenchmarkMimeParser ("startrek.eml", true); + } + } +} diff --git a/MimeKit/StreamExtensions.cs b/Benchmarks/Program.cs similarity index 66% rename from MimeKit/StreamExtensions.cs rename to Benchmarks/Program.cs index c8165facce..c0135ae221 100644 --- a/MimeKit/StreamExtensions.cs +++ b/Benchmarks/Program.cs @@ -1,9 +1,9 @@ // -// StreamExtensions.cs +// Program.cs // -// Author: Jeffrey Stedfast +// Author: Jeffrey Stedfast // -// Copyright (c) 2015 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,23 +24,16 @@ // THE SOFTWARE. // -using System.IO; +using System.Reflection; -namespace MimeKit { - static class StreamExtensions - { - public static void CopyTo (this Stream source, Stream destination, int bufferSize) - { - var buffer = new byte[bufferSize]; - int nread; +using BenchmarkDotNet.Running; - while ((nread = source.Read (buffer, 0, bufferSize)) > 0) - destination.Write (buffer, 0, nread); - } - - public static void CopyTo (this Stream source, Stream destination) +namespace Benchmarks { + public class Program + { + public static void Main (string[] args) { - CopyTo (source, destination, 4096); + var summary = BenchmarkRunner.Run (typeof (Program).Assembly); } } } diff --git a/Benchmarks/TestData/messages/startrek.eml b/Benchmarks/TestData/messages/startrek.eml new file mode 100644 index 0000000000..9b9454cdde --- /dev/null +++ b/Benchmarks/TestData/messages/startrek.eml @@ -0,0 +1,4548 @@ +Return-Path: +Received: by greenbush.bellcore.com (4.1/4.7) + id for nsb; Thu, 19 Sep 91 12:41:43 EDT +Date: Thu, 19 Sep 91 12:41:43 EDT +From: nsb (Nathaniel Borenstein) +Message-Id: <9109191641.AA12840@greenbush.bellcore.com> +To: abel, bianchi, braun, cameron, carmen, jfp, jxr, kraut, lamb, lowery, lynn, + mlittman, nancyg, sau, shoshi, slr, stornett@flash, tkl +Cc: nsb, trina@flash +Subject: Star Trek Party! +MIME-Version: RFC-XXXX +Content-type: multipart/mixed; boundary=Outermost_Trek + +--Outermost_Trek +MIME-Version: RFC-XXXX +Content-type: multipart/parallel; boundary=Where_No_One_Has_Gone_Before + +--Where_No_One_Has_Gone_Before + +You are invited to a + +*** STAR TREK 25TH ANNIVERSARY PARTY *** + +When: September 28, 1991, 4:30 PM until whenever +What: For those interested, we'll have a rerun of last year's season-ending + cliffhanger, and then we'll tune in the season opener and the 25th + anniversary TV special. Prior to that, if you bring some food + we'll have a pot-luck meal, and general merriment before and after. +Who: You and your family, including kids of course. +Where: 25 Washington Avenue, Morristown. + (See Nathaniel if you need directions.) +RSVP: 993-8586 + +What follows is some Star Trek related multimedia mail, the last of which will give you a chance to RSVP on line. + +Live Long and Prosper! -- Nathaniel & Trina +--Where_No_One_Has_Gone_Before +MIME-Version: RFC-XXXX +Content-type: audio/basic +Content-transfer-encoding: base64 + +LnNuZAAAACAAAFmUAAAAAQAAH0AAAAABAAAAAAAAAAD////////37+/r7e/z9/f7//93b29z +//////v37evv7+vr7+/z9/97b2NdVU9OT09RWmFr9+Pd3d3e4+vt/29la21ra2lra3vn3dzn +9+//YVtaV1tp9/PjzsjHxsbGy87P2ef3c2dz/+vr59/Z09HR1dLR2d7n/2lXTUU+OzY1NTQ1 +OD5ETmXf2dLP1dfb3O9jYWNhX19pb+/ZzsjIzMzP43dfVU1RX2/bybu6u7q7wcjN0+1ra1VR +Y3fv7+fZzsS/v8LEztXW62FPRj03Mi8sLCwsLTVFVffLwL6+v8XFy9b/W1tdV1RVWVtr2srG +ytXj/09LRT4/SVtd2MC0r66trrG2uL3I0/dOSE5WWVxn99nGvby7vsfR4VdKRT03MCwoJSYn +JyowPURb0cfHz9lrZ2tZRktdd+HazcrGv7iwrrC4usHR5W9VTl1pd8i7tLSztbm/xcrb91dF +Pj9DREhXb+vQv7y7uby/wsr3XUQ7My8pJiYnJiYsOEFK38G9vL7Fzc/R72f/1dXe69/v99/M +w87v919NSUU+PUVMTme8s66urKyvsrO2vcTNb1JVWVNLTmfr2szKx8HLzs3XY0o9ODQtKCYm +KCYoLjpHacnIx8fI1W9dU0A9RU5nZf/Zxru2rKuusrK3xM/cb1pvd2PXu7Ovr7O2vtVlS0M9 +ODM2Oj1ATVfr1cq/vbu6ur7DyutSPzoxKiUjJCUkJS48T+29trSxt7zCyNNYS1FYb+/t2c/H +vrq6x9HbW0E9PDg6QE1dxbGtqaenqayxtbnC3FFNS1NeZ//c18/SzM7Pz/ddTktAOTUvLCgl +JScmKCw3QV3bvru2trzCyMjrT0hTe+fXy767urCsq7G4vcn3WU4/P0NJTs+6tbS1uL3Oa0Y/ +PDcxMjg+SlBb3si8urq4uru+yNnvW0c9OTApJycmIyQpLzdFY8i8uLS2urzC71b/697j2sfC +vLivr7W9xM1bRT88ODxHSnu8rqyqqquvtsDXd1NGRERKUVphX+HTz9LV2t/3b1tNRDs2MC8p +JSUlJSUsND1I2MC3srK1urm7xldHRUtLTF7Vyr61rKutsLa8zmdKPjpDRlHPt6+ur7K7x+FZ +Rj86NzU3Pk9cb+/Nvry9wb6/w8jV/1pFOzgzLSssKygoLTQ9SNrHvbi3uLq8xNtMTE9eZWfn +x8G6r6yttLa9ymdGODQ1PUBHzrWtrauutLrC2VlNPj1BRE1be+/jzMLJzNPjXVtKQDo2NDEu +KygoKignKjA4QGvIv7u4uLq8v83hY2lvc+/Ovrm2r6utr7O7yetURzs5PUdbyrevrq+zusfP +91lEPjs5OT5FTFBd98zIzcvKy93ja1lPQzs6Mi4sLCsqKzRFT9a5s7O3ubm9vcPnY1dMS1NN +XdfMw7y9x8rI0V1VT1M+PUdvz76vq6+vr7zCy9VZTkpKTERhc1lr0d3Sy83azs5rXU5EODMu +KykmJSQkIygyOkTOuLWzrrG/xbu41s7I1+u9ubmyrKytrbS7uuFCOjY0ODlAc8O+tbbAyM3v +X11LRkZERV7f69PPz9vZyszKx8DYy8vrUT83Li8pJioqKCs0Oz13u7W0srXHwsXcUVQ9PEZE +QE/XzsC6uL28xcHhRz9HQD5axbavq6mssbC+z+PTRzI8Ojg700ZFd9dN47nDz7+47cjM7ztD +Qy4qLS0jJygqMDNP38vPu7m8vbq2vsfG19fXzsO1tLOvrbPfu77VO0xFNS9CQEXCzL+3rcvY +4108Qz0wO0jj/93awr7VwLW83bS6wtTDWzowMzMoIyYpIyorLkJd19W6r7K/vLH/zrz3Pc3M +P2O/zky5s9HIr+dMPkIvNkpM0LinpJ+fo6qvvU5LSzYuMjk4SdDP3sO9z8vFTzZHQi49U0Rd +zMnN59zrbzA3PDsuLi0xKTAuKz3rxb6urqWgsbe4n6Sqt6rGLTI2Kibrs8XBq8F7MDIfJCEn +Ljtfr6ain5+foqK1w0IvHyAoIzBByc+trKepq7HGZTErHx8fHx8fHyAnMkLIr6ifn5+fn5+f +o6Cx78HhLzRTPylHMysrOiwmTEU4P7Pew7P33atJSa6nc76sr0i2rMNevbs438hIJVlQLyx3 +OCgtNCslMTwuNOPQyLKtqqerrK7GzVvTNS0uRSwmRdM3T63FrqzM377eOT1fKy5XREjJt7Oq +sLKtqv++wUfXwUss3UYvxNg8c6zLvrLDv75eS2suNy0iLjMfJjsyPa62yq2ipsyrxUq+zT5O +20e5PTK8yz+8sV/VZ7NFS09NMi9UTTxetFzIu96yvt+7r1ezsMXMa1tO0z05KT0rIkAuMEn3 +QLfnabRWSkfJTDo3yk9DLN+qv1/RyUbrU0lFd0W5tr3Bv7xPZ9EwLsbEPFuvvVO+q7Cup7K4 +Y080HyUgHyMmP0BXraOroammta3Jv0tLOygpKT5EL+mst8q7q6zv0cu1UUFZP003LjMzXS00 +RkYq4z0wz0M4QrNFyrNIvsS3T7HG07DDsrasv7m/XbprOzFILS48KD4wRT3XO0TEUEjJy99M +3bPQY925RbbEa3OvQzrJOsTXTOvJ+9e/68FMr21aRMbDQcdCxMy92a9OwNXzX0bYOlVR33dO +rcDjw7V31Uc8d0w/OzxTUz4/VdDz99/Ore3G78xCPjxBNi8/Ly85OTMywT+3b83Gzu3Vx0lD +70nIzFHIt669966wU8RMUelET0DLNWdMa01ttmfBP824Ok9JPeEw6Va/O2e8ULZS07XHU7rK +uljVw1vXa/tfQ088STlLSmPnzGO/W7/Wx//TxDxNXm8x/85D30nP5bJMw+PNN9Y9V1bBUc8/ +7bG94cO+zmvHZ0zLRz9CQjhZSztAc0TOXjhO38FTyM1XzXNH5z1JNFMqT0RfTdeyXa/pwcXI +Y1fS/87bX9nKzGf/vuHHz/e4T8DzuUpX73vFOs/Nzcr/yOf33kC/d9tcYchP671PxNDUSsL3 +uL3VxLXF+8tMS009KjM4LS45OkTjMtBZ3Ei6wtFKb0rBb0zIxcg6u2HP10vM1O8z2M81QzbO +R8ZYtMzPU8vPz1HKU8tFYWvM90PdVMZY607HTkbcP8c9zuVFVDrINcw/QzzzZ0q9yeu0uLnJ +u8NXb9rV+06+Srbf80/Zx8/USctaREndOE04XGFvwsW367fR3L7ezzzeOfdEyEhfw0vBd8xD +xmvOWlNj5+c+Uzk+ODgvQDM+NUE/WVX/yMnAx3fA/7BlvGm+Ub5Rxsq+xdW988XhVmNGVzlL +OFpjRMLTtc68w9PMy9vT7VnY8+//593aXc3Wz8/I28vv4UHHUVlMUDxANUU9OktJa9fFy8jK +w9zM49nKTM5Zd1lR90/cXdTdz9vX3l5jUT5VTW9P2b++vbq/wdJ3Y1dKPkBGPUM+TFlvWs/F +083Hw9HVzu1nRUg+QTU2ODQ2MzpNTGfcw8nLw8nhx9bO3cnVyMrAxrjFwL3Cu9vC92dcQ005 +PD5BS1Prv8TVx87I1Gfe/9NOa3dvT1X3d3NvzM7vz8jI02drXVM8OTk6NDQ2MTw+UljN0MC7 +v77SynfMZ1djUWtOY3PX0+3ry9Xn3ddlWm9LW0pIR/vdyb6+usPB2tTNZUxJUERLSllXa1nv +x9bP2cfHx8rK1/9NVkM+NzM3NzM4PFxl18fFv8DFy8nMzszfxsXHzcTBwcjEyc/b299fR0M/ +PTs/TvfUyb64usHJ1W9hU01VV1JNUE1TVG9l49PcyNHN193r729OQ0Y1NjQyMTA2NUJKY8rE +wsfCxtnZ69Tr39nj7+/OztXdysbP5//vW0NDPT9ARf/OvrivsLK1vsPP0P9eU0peWVFUW2v/ +a9nZzdXO1P93d29IPz0+NTIxMC4tNjtFSf/TvLu+ubu5vb3Nztfez9LT19jLxczb/8f3UkRJ +Qz08QEpV28u/wcS/zdNvVE1fUD9DS0hMW13zzsfCur+3u77Jzd1PSUc/ODk2NTAvNzs/PmXj +z9bJzd7N1MzP29fMydPIxsbAvr7B0cjTy2fnSkJBQ1lRzce+t7u9xMbTd3tXTEdHSU1Tb9nb +6c7SzcjEyc/lWWFKOzk4Ly0uLSsuMkNPVM3Dvr28vL+8u73IzcTFzNDGy83X291rX1FGPDo+ +Ojo5P0Jb28C/vb3Ix9HOzNFzVE1VT1lYXWNn59jNx727vb68ydlfU0s/NDAyNS8vNkVGT2fP +zM3JzN/v1t1nb9/KzNPOzGGryd/Lw06zzMn3XNHb3TfG12dfsfPCVVfvsllvQkfDP8c64+NB +Ub9Ew9xc0+U8OL9K2FoyLjstOi89NOsuSz22ScPOrsixY8K/+04/47/e373FzcNQuMrTa2Vd +Y0AsP0M4z7a7q666y6v3R1XhPdZLNMjHQN3Id9m349m3wTTFRMI80zE+RTNfWVwsWka6UVlG +sk3nv8tR9zYwwq9HONTJa008Zaavus6tu1cxLS8sIjDlvNfJpqemtr61tjYrNiciIB8nPz1Y +q6Kon6GjpajBYfcvIx8iIx8nHys7vbemrZ+rs03rMy03Vc2trK+rr9c8QDo0PeW2tc6zpKW+ +yMXOTyYkJygjKy9GwaijoJ+fpKqryS8/LB8iIh8gKT0+Pb+wraOgpK9r4UY1LjXJwKu1tNVX +KikhHyErN0vIuMasoa6/zME6LyYuM1VDY6ynp6Ofn6WyxunfNR8fKB8fIyYp2zU5ta9GwKOf +xdGtrsZb2rGgpK2sqrc/LSwpHx8jMTQySc64rMfBs7c6PU44M2PZyq+ioqGfp62rtd3dPScu +Kx8jLiQr2z8uY6jRO7Gfw0ZfwMJPS8WiprW1r18tICQiIR8q08x3tKiuqq3S5VsnHyIoHy89 +X66foaSjqL5ZSUQ1MSk3KyknO0w7R8GzoqlvvqilTe+3vltS466hq7SutjkjJyYfHyAtPt9d +rau1r6y43U0sNTctNMjVZ6afq6yrvddKLC1FNjM3PS46RitnscU9rqZra6ejXVGzsr/Z072k +rNDOyDUfHyIfHyAwyb7DtJ+rw7W7dywoKy4rL1C+r6qfoamptNNvTz8/Qi45TCchLln3PDj3 +59/E+2Oon6/rqaHDP9G6p6/KuLdVIyInJiIlSry/ya6tvLnhz1Q1Kjo/LTe5sK6mn6Kps99v +Pi0kOD4vK0cyLEQ34cG+Ta2rrFU3UKeuNe+wxjI2R7atxdjB3SkfICsiISjntsLNqKOuX8Sx +xy4kN1xENc6qqKqmrbbHOTs3Ki93Oj7HUTk8Zy85zKpESK6t5+t7p6CqS6yoyDhPxcW+Tklh +Nh8iKiciLty7tr2vpalLSMPILC9fXE3z27+yq6motVhpYyotLixM5TQ+tOM2O+/7vDQ7vai3 +udA1XbSsVEG31zwzOruvs0/d0zghHyMnKitZq6mpt8GrsTQz7eMtM8/JtM5jwKWjrLOww08x +Mt1nND20uzUvSW05P08+zae8bbmhs8Y/PrGt3yu/r9UyV7atyTdT9zkfISs0KTTBqrG/taev +Rjvrxz0wX8LOb//BuK2ssrXYQTA0LixQ1c7JW+9CNSw7SzswP0Jcy6Owtq6zyz0rWa/nLT26 +ezwzS7GtzTFBUCkfJDFHRMKtn6evra/HPzE1NisuRqzXPGOyrq+2wrS4vtfDSDxNX0tGMi84 +Tj4wOrq30dqmp846wKqtRCc4vksvWq3JL0U3OTkuObGvTzbVUzYlL2vEvbSfn6Sps7zAVywn +Mjw6P0jbwUw7x6/M22dDX0gpKD85Nzw/TmlMOUiyxeO/qqbDWdW5zEzrrVsvNUUzva+v6TpR +MjQ6Q9exvP84MCwpKTN3uqyfn5+fn6KtvD0pKSsfHy42L0e+xrymuP9P8zgwQELv09c1Lyk5 +NS04tqaosbGvrcw9Pau0TCy+v+tALzTcwikqa8YqKTBNQj1Dt5+qurmzYy8oL9O6wa2fn6Os +r7bPLyAqLiIgLC0yTT1DvbHL1VlXXVUyNs/GRlG9urvD47iuwsqvqq+80ruqXzT3wzw5Pv/H +P1tfOSkxQDJBt7nVQEA4W09Uu6irzcvfbzAtQ72/uqafpqyzvVEuIB8fHx8gJCo3QLympbmr +ornLytvK1jo/+/83b763wK2oqa7L78/RRT0/dz4xLTg5N0BZSFH/T2d3b9RLzcbbd2/bSUnr +/1V7wcHEyr22sLm2trC4vcZ3Ri4pLjMrKjdDOz5Nb9B3Qz1ZUUI4TsvK1bmmpaqqpKesr7W1 +tM1f71UvNT89NTc3Ny8uNkU7NDg1LzE3Pmm/ta+yuLGuvr+4vMXMVUnZzVFjylZFQzk1OTQr +MDk4P93Pv73Bxs7zSlVv693EwMbCwr+9u8zR01tJPkNQ28vCu8Lfd15JPT5Oz8nfzr24ymdr +zk8/Pk5PUT5D2dNBP2fX3evPvrrRSklXRTlB/148SnfF0e/jy8pXUt3aZ+O+w1ta52nn72Fv +yc/3/8jB2/fGvcrvZ01GPzs4Oj88Slr/WGvOz9nEvsPlW2tINjU/U17Z083Jz93v3efrzsft +d2tIOj1EU2HZx7u1vMDAurzC2tO/y0lBTkQzLC82SURNz7u4vr+7t73BvbzEzs3O0dLzW/tb +SEpNSUxVZevrTz9KPTI6OTc8R1FOTkxTXV9VXffr187SycXNycnt2cnL0bmzubO3vr/DXD86 +Ozs7PkZEODU0OD5PZ8i6u7q6vt/dysjvadnHyv9U08zZa8jEUWM3PD0uLDU+S0ZMVFdES2HL +tbKzs7Czs7W9z9/Z1mNGS2vf/2Np2Ug5NDw7NDc8Zelnb9fLzM6+vLm9wr7Ed0lN4/9GQkJB +Ozk8RlNNYcbHzMvbWe3W68zEy83MbU1KTz5CTU9AQz9ASVFTY9zT1c/DvLm6v7vAz8vL1Wvp +7//ryNZ3/+lVUVlbb+fd287L2V/e1eNzX0pKRjk0Okhb5c/KytnV3OPzX1ljZ1NGQUNZ59vB +s7W8wMr3b3dfT05MXVtfY8a8xNPRzuNIOjg7PTk4RfdzW3fb3dbS07+8v7+8v8PEzN/n81VG +PTMxNDU1OD5AREtFSFv/3M7CxMXI0tXJxMfKuLi7xOvnztfXzdRPP2NfN3f318jYyMbrU0xV +5/Nf1cC+yMvf6917e+fba09VTUlEP0FVV0hBPzw+PkNES1Nr7czZ39nIwL68vMnJ7Xfv+1v3 +08vT2uv7/11PTldJPTw7Okbr2My/wMjN2VdaWktFWe9hXevjy8G+vru3xM/VaVNXSj9MV05M +91FJSlJX99ZvbWFP89X3V83K0W9zSE1NUf/Bws3LydTjyr3IyMj7UfdPUW/U78i+yuFvT0z/ +a1FOXFVcT0A9R1dQW+/z2+drd8rB09TK2U1LPTQ1NjVHW1tSysXS78bIw7q+0v9PR01PU9/J +xMnD309Y3/db691VR0U/SFvj0cDCy9vtNELKL9xWPcRD1dNZvNdrubjf0dfp18nPzNPY/1BI +PTg6MT7CPGPIxL5HRePFxtvjSt9KP2FZe83Jv9fj7U5PXlHl2XfvY1ZPS1nTyMC+2GV3Xmvd +98Y3vrA9PD88uuPRr3vLzEh33l/n3cXDylFPMzE6LjY9TENVa/fny8G9tLfC1N1zOlc+Y9Pa +uMPNx3Pj42Pr3lNXRj53Szaz6zi+P7m6NsRBQbc+XctXVkvczLfFusXd1VxGymHLZ9Xrad4z +Oj00TCphxy5S1y/PRFm/39bLZ0jZY9+9U7nP1k+/OEPFN8HNSc33Mki/P89N2rnTx99Kx1Xr +Os1fyUk6uz1by0mzc/fE9zx33Efc58Tzx0nlwTjKWzpX0MM199lHW7DptOe/30vPd1ZExtTV +ucA7uz/JwN9lutVDSEtDU9/SU7tBzdRAvE//1z7GRllMO88+uU1ruW+zwUvrb0zEQ8ZLS05W +PD08R91Gb0ha11XRRcJrb7TXVrpLQ8df17xnylPvvUXKukmxPlS7Ob9KQ7hD3NnIwTjA1Vuy +Se++81Tbb0Ln31nhzcfUvEbGPM7Pu1S+tjy4Pjm3O8zIUzbE5yzDTVO9vTu1uz62UD27VU+9 +Z3fMzjm+bze+Osq+RDW+7z68OWG8XF9I2zjRNvdc2U1E2Tu+dz64W+W3UVHKvjXF50S/2TDL +NzfPVTu7SEfITvPn0E292UvKXbhB29W8zle067/3R1awRb/Jzu9t3DhP1zXAW8rYrtA8x7tL +Rq9Xd+9ETdlXQkXAPbzZRNpZv03Ax8tLZzrjey5Ga8Ezw1s30/suz7bdSk7bWN9TPbtMVdFl +2TP/TsvFPLtZQ84z1Ek42s7nSbl7V8V7V8NvxVE/1VxRc2drwW9B2rNKT8y9ytXRw8FUQsTR +PURbVjrJPj5GXLFzTrW4zTvMvlLr90S7e0hDtU1GssnVukfY50s843dEONFTzOfMt2td6dHl +PzTjPys8Z0BMXdm2ulm5u+/nuMdO3N1PNkhVLlVELzJNWzHZxeO5uv9Z1ckyMlHtuzfWpbNd +16++RjFR0TUrPbzvLNuyVDSworJCr6a6RSlCsc0mMb3NMy3Nrq/DrKKnwWnntDYqQ0g4LTy2 +vse5srbeZT03LCcrMy4yPMO5t6ymoaWvsMZWQi8lJS4qLC03S764/7mpvDzrvy1ES7rWRUA/ +rkM0zavDSa6828XBPjE9QzD/bS7jt2/zzz1nuk4rQctBvUMxsq8+K/fKNSguurbPOUarrktG +rKGpvby0rN83Q984JSUuT8LHT66frdwww709JUzSUCsu662xSu+soMMrQK/BLCvvs7Q+L1u+ +ySoqwbIyMMdKSHdKy7CqX8Ct1d3tyMDNxkwxRTAqLO/dOzZdVUgvM1fRw907z7DBMjrPrLZ3 +26up1FHMvus4OExLMi1E49vnwbOusWHMsbBLNsm2Nf9ZLza8MSjfrDouxq3KY+k7Qcc+LNOv +38quvju7p61rLTq8qUclOLRnJyzXpK4zK8qtQSc3q7dKLVa4tFkqPbyqazzn685ZOzXDuj0q +OU0+LkG9r7U6OLGkySkv6aOvMi65o7s8JWmosDMsuKvZKTTDqtErKVOs0yw1rrMvLduotNgy +WKu2LSnAq9U2xbmxxTAytK82N7VrSrz3LsusVjWyyzHerzguxP8oMbG+NkW03TxHWEy3tz06 +ualON83eNkbAQ/Opu109PDU8S93fwL2/Uyouv0Ex26WrTURAPM29OTGzrkUtyaq+ODk7ratR +K0yyOSY76biw1SdErdEuSv9YrK5ML82nYzNH2XfB1TTzralBM2e090EsUautPzHXres2LVOz +sb+7V1e6QicnOGW7q9XjrsApKsvTRW9lyqzLJzi+vT8xN8SnxjQvx9dFNEXNwO/rvttTS0Y2 +PK+2PE/APWWyNzO+sTtcvddvvkMxX8//QUq00tjEucVNLylQwrxOMryo/0W/u+fRby1Lrbkt +U7zN2zw4uqe0Xc7HSigu3aas3F33z1k2K1+qqMo2O0P7bzUyR7S4v9NDTMi/4+OzxEztZ0Zf +WzE6uPM0OfutrcwoLbiq2TnTzsQvKDi02TvfwSopy62qwSgiVapWLDG3oao/Jy1Ctq3NRV62 +1WVLPz13rr1HSFlD0cBMN1nX18tGOcymwk/LsbpHMig2wbLWW8Oup9EsLOmvv0UvwK7KLTLN +sK3IOEXHxzwpK+2svG82c7SuVjlWZ29lzlEtSbrKP8O5QS5vw0/Jsj9IvqzdLiEoxKm0NCw1 +O9y+R1OrqNs2JS/BsbTvWee/w005O0e7rLhISbi8Py0+58vGa1PQyc7XU0BJa//Hs7nd/9XO +zWtCPkvbx8JnQsSzx03nvcXvYUo3M0xb69H398e6y0Q/W9O5v1hC0Md3REY/X8nhXFFbX+ta +TsW6vcfGb07XzUxE5+9PRT4/Ozc228BnPUA5U8hfR2W/zFVRP0fIvszvtsT7W+lb48LB3s7B +RjIvUOtPW9VSO0FvVVzRxe/X0/dG97zLyLjDy72270Y/S1bnymVF/7vC3drJzffdZTQuOV1z +41tAU7e7Z+HDe8u360dOe0k/Ni9Ou8/rXz1G2cXXw7/OwsRdRFF3vMo8NlVvV048Kk7BVztJ +RDvdwVNPycztz8PKv722sLi+02FCSffRWEM5QVdGPmfUX088OkvnvP89PcS9zsa72NPByGO8 +tr3tX1tV61h33VvfTzw+WktJzspJPVNYVV1vybu9yHfv/1Rdzru7vca/YTxnzsfezM5jd1dv +XWPX619j+0NLVDw+TUs/Sz82Nu/rXdLZY07r1OdXTlvbwcPfXFdU68jD1dTW1/vfa09Vz9dR +Rv9WQDdNzrWsvlJO08zR1crEvLvETjk7S93N41tnSjw5RWfMxVw9U/PjXf/v5d3n0dF7d+vL +wL/FTUvXymvvUE//u8FDOTxFUffvTU5hb2VRW/9d+9nGysr3R0nKxMDMVV1Y51Vj6+lMRkZd +829nSU/Kw2dET1Hc3crQ3e33/0pKXPfvysLJ2V0+PDxP0c7ad1dIRWPT08q/u793P0ZKYcDD +Y1vnX0BHTs64uMtj3s27uLu4ucPN70NCSFN370tPTEBBOj1Zys/nTU9XTUZpv77H70lHZ/vO +11/vx7/N90xGPEbjy8heQz5EQU1NSWvVY0c7RVPnwsjJy87nXXfDtri6yGdJa+9Tae3r5cnT +TTk8TNnAw15FW95HUdm/ytRdSV/nT0Rr1c9lPzgyP1H3wbm5ub3DzdTdw8fvVz05Oz09Rk5b +/29rb1rvyr+3s7i+0Vk/PUzMv9FdTEpLU/PLxcHHyvddSEVWe3dTSkpJRDo/78G/xdNrZVdB +TNfnY01FRT04Nj/NvL/O4+tvUlnXxru/yVtFPkJt59HFy9/pa1Nvyrq4vcTra1FNWuvNzMvd +a15PX9LJz8vr/2dPRU9r3tvdb0U8PD9Y187Wd1FNSkpV183Cv7zFaU5c993QXUA7NzY2P1/d +4d3ra29ZV823try/w8fj49fLxsvnTkA9PVHfysfJ111NPzxDX29fU0xJSlRjzsK8ycrjUUZV +XWve2eNTRkRGTd7JysnMYUpGRlnRx8nVd11KSUVLb8nAwczT5djCvri7vs7Zd0dEZ+PR019R +TVFNXtfHzNXn/2NMR0JU993pTEE+Q1Pn92NNT09XTlP/ycPP3F9tR0VJZ9nZ1+NJQUVVXc/F +zVtISUlh68nCwLy/xdPd48y8x9hvU0dEQ0h3zMrU3/9jTlD3ycrnTkVAQ0RI5cbBxc5lRkRc +y7/AyntNQD5CVtXIy9P7Xlv/49/EvsvaTT48QUdZZWNZc2NVe8a5tLW+ydNdSEdLb9jvYVxf +WV9ryr27v8d3SURDTf/zW0tDPD9CTWnPz+Prd0xIS0//09leV0ZAQEvvyMrX3t9v7+fp0cnf +X1lGQExrzL68wMbFy9Lb08G8xe9OQ0JGV//XzfNNTEVET2PZytfvX1dPU2fevri802tZSk5N +Tuvj/1xIRUZZa93Jz+9ZSUlOX+/PzOdPRkE/Rk1f0tHb4e//59XEuLe8y+lZSkZJc8/P+09T +VV37387ExM/hWUlGS1zv4e1bT0xHSU1l499dTUhGVXfXxcDE3Onna/fj2NPX41lTTUtUZ+Xh +33tjX1133tHFvL/EyczIx8nN095zWVZPTlVfc/NjTkhJSkhNUld3d19dXXPp08nAwc/j82FR +TExNWWNZU1NQV2Vt99v3V1RZXWd38+vvY1FQT0tTa/fa3+/p1dfLx8PAwMfZ/11aZXf73d/z +5/NrX2Nfa9vZ921jVFlfaefd52ttb19WTk9TV01MU1Bfd+vTx8jNztXz493l39XfY2lfU0lC +SE5dZ11n7efn3M+/vb6/ws7/Z1dv721TWU5MTlFSWf979+9tU1FOW//nb/Pj7fP3/+/f5WNf +T0FESE1X7+fj2/dfWFVb3dXb1dt3aWNhb+/pd3NhWWFjd8/DxsfGyM7R0c/K0eP7b1RNTVzj +yszn4953YV1d99X3a2taT1FWZ9jQ2+t3a05HSkxf93dfWVNUXWPdz+Xv/15bV1Nj2dLd+2tX +UEtQZ9HS2c7W397Wy7+7wMjVb1VPT1Xz4/drW05LTVRt0+ldV1JHREZT39HT1917Y19v49nf +Y1RTSkZKV+HFyc/T71tRUWfRzdfva1RNSU7/3dxnXF5fVl3fxr29wcXM193f18zO52NVTEtL +XuPM2P93XktFSFPr22tbV1BTUWXVys7vWkxJQT9IY+PpZ2dnY1tn3cvK429ZVVNRV93N0mta +W1lPTunMwsfN0dXX3s/EvsPO3GNWTEtZ18/Xb2FbUU5P5c/L3W9fUk1JUN3Iyc7nb19YUV7b +3/tZTktLSlfPw7/L2/djVU9b18zT61hJRkNFXNPV7WdYUFFd38W7u8LO2+tjc9nDx9l3WkxJ +SU3pzNN3U0dDP0NV69brXlVOTlNf0cPK1ltMRD9AS+3X3W9jU01LXNPJy9n/XlFMTV3azNbj +Y1VKR1bVwL7AxszX5evQwb7I1/tlTk1f28zM329VS0ZFV9fMzttzVUtFVd7Mxcvd711JRE5n +9/9WTEU+PEFrz8nM1/NjTk7ry8XFzm9rTD9HWefa2+9eUUlL98e+vsTXbVVNVtXDv8LXd1dL +SmHn09V3VUc+PUV30c3R5V1dUE/dxsPGzV9TRD5G99rT1d1vVUtMXNnIy873Z0pGTnfX0dj3 +V01ESe/Lv7y+x87X79fMxsPK12dTSUz/0snK2FtLRT5Eb+Pb33ddTUZKX9TFxMbdWkhDSVtj +Z29UST49Qlfr1c7R+15NT+fbycXG0OtOQ0hf697X22NORkvjz8rHx9VvU0dY59XNytLfZ1Zb +383NzM53UEJATO/W083db1lKVdHKxsfOWUs9PEln3NnT22NJQkZz09XV13tOQj9O39TT2P9b +ST1Ia8vGw8XM3W/v0cK9wcbdXklHUtvMy9HhV0g+O0lc6+//XUxBQUrvycTJy9VtTlNp2dnn +Z0xDPTtD+9bLzd1vU0hQ98bCxcnha09LVdrLyM3nXU5DS9/Iw8LJ62tMSFvhysbH1/9bTVLX +xcHCyfddTkdX1c7Ky+1fSUVLb87GydNvSTs6PlNz5+tzU0M/RHvOy8vNe1RCQVXj1M/W6VND +QErvysG+wtJrU1nVxL++xutPRD5K28zIyedYQTw/TfPVztVdRjw+TOvOycbYZ0xLVdjIx8zb +VUc8PUxv0MnO22NLRkrrysTFzW1LQURd0MnJzON3TUZZ08S/wMrZV0ZHVd7NycznWk5JWM/E +wcTWa1FGR2nbz87X/09DQ0vny8bK1V9IPjtGZ+/t61ZGQT5E+9TIytHvWktJT9nJycrnWUpH +Rm3Iw8HF229bVmvKwL/H3WNMREdazcPCxdRnT0hJ/87LzeNVS0JEWdvJxcrnY09OXd/GydX/ +TUE/P0rjzMvaa1FMRk3jx7/E1ftRSUNFc8vL0ndSS0xP98O7vcrfZVVLV9PGyONhU0tITV/M +v8znV0tFRU73zczfZ1VNSlfvw7zC2W9bSkNCSf/dXE5JREFCS+fHyeddVU5NU/PNv813Z1hP +VV3jwbzJ1d/v//ffw7zA221XS0dKYdfAzOfnd1lSVePHx91fU0dCQE3byc7/d19XVFfjzch7 +TElDQkdMa8vP92tnVlRb5cS+ym9bVEpHSFfdzHtRUUxLTl3PwsfZ6/dnX2PlysPVa11cV1t3 +28XE3HtnVlFTXuvW5VtTU1hl68y/vcXf721OSUpRaW9RS0hISUxf3c7Q91pbWVxj3c/Jz/9v +d2/z1czEv8zZ4+Hv49fMycnXX1dRTk9YZd3cZ11dVVll69bP31xRSkhMWm/TzeN773d773N7 +615FQkNESlBd4czV7+vt7+Pf1c3Pa1FOTEtMTlfnbU9NWGfz59nJw83f5+Pe3ePZy8jf8+fr +5d/f08rX/19fV1dPT2n3Z1FXc/fv7dPIzOdlYVVPTUta92FRTlZdW1VZ7+F3XG//d19d99va +b2/p3ePr3cvEy9LPz9XvZ2/d41dOVVVPSlRp2913d+//Y15r599fV1thWU9f18rM3dbR32NT +VlpvVUlKTEtITGPUz9vp3ed3XXPbz9n/e29jUU9d89fj79/n/23318bDytfR6W9de9PKytXU +1ON3Z3fYz+dvZ1BIQkNNXWdbd+t7e//by8fN42lXSkJDS23vc21vY1tPVu/Y3O9vWU1LTmPd +0+X3/21rW//Xw7/JzdPjXVVr2djhd15RUUpJd9zT3f9rXldQb93S3fNzW1lPU+XKxMbN4WtV +SUpdaWtYSkdGQUhezMfN0+13X1hr0MnO2G9WVU9Md8rFydPr3fdd6czBydn/V1FJSVvOxsnW +92VYTVTZzM3bYUxLQkJW6c/U43dhW1NZ2cnL12lNR0I/TOfT0uddVk5FRV/Z0dxjVUxEQkrn +z9PnY1lVVmPIuLW6v8vZXU5d3czK2OtnWExLd8nEydn/W0pHTPPPzuVfV05ETN3JwMPS32dI +PkJc39rhb1VMQkVvzcjI2m9fSkBP28zIzuttV0NFWdPExcrZ51dR98jBxM97T0U9QGXayMfV +62dGQ03bycbR71dHPkBc0cjJ0etfTkhd1MvJ21FJPTg+TO/Pzt1hTj8+TenNzdJrVEVASuvK +xMXQ72tQT9nDubm9w89jTlXdy8jI0/dVSEdrzsfGyutZS0NId+HT0u9XST5DT9/Kw8TU/0lC +Rln/3dx3VExCQ2fby8vS81lDPkpd59nV71RGP0Jj18nGyNXpYVfdwr6+wdhtSD9GX9zNyMnf +W0M/T9/QysnXZ0tFSfPOx8XD1u1RS2PXzMzN2FlDOTpIb93W0XdORD5K+9PPzd9dSz9I79HJ +xsrYY0pLd8a8vL3D2FdGTevZ19Xcb1dGRHfPwcPF2PtKQkln0M7P22dJPj9Y1czM0/9TQjs/ +WPvj3/9fTD9KZ9HLzNF7Uz48RG/b3N93VEQ9QGfSysbL191dW8+/urvAy+lMP0Nn08vKz+Nc +S0NW1cvLzfdVSD9J48zEwMjT51NSb8vGyc3/Tj89QV7Xzs7ZX04+PUlr6+f3V0s+PERb08nF +zetVSkvnw7y7vMjfWktd2c7O1+1fSD5AVc+/wcLPd0pIT93MzM3bX0Q+P1PXzMvPa1A9OTxI +Z+/l+1lKRkzrxr+/wdddR0VL683Nz+NWRz5Fd9PFwcfP/09OX8a7vb/J50tBRm/NyMfN62NI +QU/TysrM32dMQENP1cfGxdHpW1NZ28bEx9VZSz87R1zf2NfdVEM9PUdr5+9vSz86OT9j2dLM +2HdfVmPLvrm5vMHPa1lnz8vR1XtMRT8+T9XJyc/vWVNMV9jLyc3b/1RKTVvRx8rP71VDPjxK +/+Pf71lQSkxf1cK/yuN3VElNX9PJzNlhSkRCSO3Iw8nX92ldZ9PDvcHU61FGQENdz8nN32VT +TU1fzsHE1mtRS0ZM783Gy9z3Y1ZRW9fFy99TR0JARFXVy9NrT0dBP0Zf3+VdS0VBP0RN1sXS +6WdeZ2fZv7S0vMTL0+v/28vCz19OTElNU//Iwdp7W1JOUVnjysxvWlNTWGPdybzF43daTEVD +TtnO71pfVFRXY87Axf9WT0pNTF/bxt9XTklHRkhdzszna2938/fQvLnG52dTTExMb8jG529r +X2Nbb8rC129SSkZHSvfGxNh3Y11jXmvdyeNMRD9BRUdezszvZ1NNTk5P88zVa05LSkpNa93K +0/tpb//r3cW5ub3Fys/V3tnOzN9ZS0lJTVX308vjY11dXF9r49Hhd1VVVV/73czExuFfWUxJ +SExf/29XU1Fca2/h0+VjTEtLTlRb8+fvWU5PU1tp7dHKz9vb18/MycbGx9xfUU9TU1nz2+dh +XV1hb+/hzs3rZ1dXY2//48nI13fv49vj7+vjX0tGSE1bXGHn2f9fYWf/92/t0dNpTlFUXVpb +d9vvXF7/3NXZzMDAxs7V19Xbb+/Z41dRXGtvXV/r3P9bXWd7X1FY/3deUVr/3Xdr2M3VaV1V +UUlDSF/va1tdZ/djX/PX52tVYWdfTExdb1tOU1dfW2fjyMLHyMbBw8rOy8bO811dXU5IS237 +Y1ldZ15XXf/Mzt3r7d/rd2vRxsza39fa/11d9/tVSktOTkdHT//ta2dv/11VUf/j71hTUk9L +TmPj29/Z1NPW19HGwcTK0d7vXVJb8+tvaXdnWlNb693d7/P3d1pMTmX3ZVxdYV1RVuPNzdnh +b19NSVL/3djd5ef/Xl1v2tHd6/9bS0VETWl7Z15fV05V7c6+vb29wMfP09PIyNnpZ1FGSVPv +3N3j/1VMSU5n6dXa529dUVVf28jFys7XbVpVXvf3c11ORkJAR1lz2+Pra1RNTVbf1Nnj/1dL +R0x3187P09jfd/PRxr++xdl3UkdFTnfd3+d3XVBPX9nMzNHfd1xMS1dv5d93Y11VTVHhy8nL +3WtPQUBK/87N0ePzaVVY69HM1e9hTkA8PU138/tnV0tHTHfJv728v8PL09LIwb/J52VMPz9H +c9PW3WtQREJFX+PZ22tTTklDVeXCv8DGz99bU2vY1d9zT0Y/PURX39jfc1dNRUNSe9PV72NV +SEhO787Ex9Hjd2lv1cK8u73O91tOTmvjztd3Y1hOV3fOxcPI1ndUUVt729feY1FOTFjr0cTC +02NRQTxDTF3p63daT0tP98/Hx9BrTUQ9RFVv3Nl7W01FTv/SxL+/ytXr3s/Hv77E2l1HQ0ZY +/9/bb1RKP0Jb/97b42lOQkBFZ9fJxMXO32tz18vKz95fRj89TP/f0s/f+09ER1f34+fzVUc8 +OkJj2M/N1N3/W2/Lvbu7vcnR/2P/1crHzNp3TURKa9PLzM/nX0tGUe3Uzt5fXUhATG3Ry87r +X0o8O0NU9+97WVpJSFrRw8DDz29XQ0FRZ+Pnb1lMRUBH38jAw8jT32Nj28fBwsnrU0g/SHPc +zM/nZ1JFRlPdzsvN32NOSkzny8fFydPna13jzcrN2l9TRT5KX9XOzttfTUREV+3V1elTRz87 +P1n/2NXh92dZa8q+ubm7wtpjVFzbzMnK129QSUdn28/N011PQUFMY9/X3PNZSUFDZ83Gys9z +TUA+Rl/f2dxfT0dBTO/Xy8vZbU1AQEr3z83VZ05BP0nvysK+w87pZW/Rwr6/x+lfR0BJXdnM +zdpfT0ZHZ87Gx8rlXU1JT9nKwsLK3W1OTW/b0Nn/WUo+PkNpzsjIzntPRURO69nd91FJPzxD +UOfc4/9bTklTd8S7urvC12tZXePIxMreW05HSFrpy8fL1WNLRUZb4dHX71dNSUlWzsLAxddX +SkNBW9zL0N/3WU1KTefIyM3rTkQ/PEjfz83XZ1RLR03rwr2+wszl/+3Zwry8w91RSkRCVdnO +zdlbS0VGTvfGwMnWY0tGRU7XxL/G129cVVFrzcvcX0dCPj9IZ83I1OlXSERET+PO1mNNRUNC +R2vWytpdT0pGSWfRwL7L1mdjX13nw73D2WtTU1NfzsK/z+9rVE1OUu/N0fdUTkpLUe/Ev8bd +XUlFREvvzcfa/2dUTlhrzsLM51pKQ0FBTt3M1mdaU0tPXdG/usTO1efr3dTEvMffW0xHSEhV +0857T0dCQUZP/8XE3nNXT1Vde8a8xM3Zd2FdVXfPzmFNRkJESlH3ys9nWUxJS01e1c/lV01H +R09Z3cjM72NbWmP/1cW7v8/b7213b97Ew8zrbV9j7+PNxsfab2teW1he39HnV1FLTldb78/T +6VNKRkhMWeXOyd9rY15nc+vTzuNnVk1NTk9d5+NbTE1KTlb/z8fI1dvd2c3PzsfK91lTTU5R +W//Z1XNOSklLVmf309tjWVtn79nOxL/Iz9//b2tXW+vnV0pLTlFcY2vh61hPSExjX2Xn195b +U1Vj9//v19PrZ3Pz1czLxb6+zd/3/+//a+vW2nddZ2/j92/r1fdbV11jXFNV9+tlWVtv7/9h +b+9vTUlLU2Nj79nL0vd3d+97ZWfn5/9YVVpbUUlPX1xJSVNbXFt328bGzMvGxM3a39ndZ1hb +be/3d+PT1GtjaW9zY2/n1etdY//n83vnzsvZ5f9vYU5JVf/3Y3vv429bWXvf/2VjbWdXUFvp +329pd/tvV1n/29vv7eHR3ePfy8jP2+f/WUxHVe3d7/fj2+9dWW3b3e//e19PSU1z3ePn3en3 +d1xj6/9bUlVPTk1Qa9vc6//vY1dQUXvZ3+vrY09NSVF36+/7d2dlWW/ax8LDw8TJ2/P31tHV +3v9va1lSa9vP3elnW09IUF7f5+vvb19QTlvcx8fN2fdjSkVMXeXj3ud3XVVP/9HT2edeTkhH +S2nf63NZUExDRlnn09HV2+/7d+fHvcDGz/9RR0ln2M7O1+tvVElN59fU1913VUlFT93Ny83Z +82tXWe/R0O9fT0pCP0ph18/T2ftjTUxX18vP1f9hS0dM787Jy9Pn/1ZV886/v8PK0PdXVvfQ +zt1tU05HQU3nzcvV72NVSEz/2s7Z/19URkVO28fExs7nVkc/S2/r4/dtaU9LV9/Ix83j91lD +QUpr+2dXTEc/PUFl1c3V6/9vV1nbxLm5vsbTX0xP3svHydlzXUlFT9zMzNZ3W05AQlnjz87Y +5f9aVWfOxsnQY0o/OzxN3s3K0O//UUdX183HzO9jSz9EVenMzNT3YUxLZc7Cv8PR53dWWdrO +ydFnU0g+QE//0snP42dTSEzlzMjJ02lPRUBL4c7LzudrTUFFTF3v5+tfV0xNb83Bvr/K3ldJ +S1v/7/9tT0pAPUtl2c/N1ftbUVrTwry7vcnhY05l2c7IxtZ3V0hN79fNz9dvU0FASXfc2dnl +b11ST9vEwcXK81hBOj5O59XV3W9SREdX3dvb42FNPz1Ea9fV0tl7W0xT18nCwcXM315VY9TK +y9P/U0Q/QVXr2dned11RTV/b0c/Z72lVS05r1szO0edlTEdOd97d72FTTUhM38W/w8nW51VN +Z9PJy9xvTUA6O0/v19ffX1dLRl/Hv7u+ydPvU1Nz0cfIz9zvVkpZ1cfL03dUSD5BY9zRz+1b +V0lGV+HIx87rUkU7PEr709PeY1RJR07jzs3XY0xGP0Fc5c/R32NUSEpay767vMbN5W9j2sfD +x9dXSD89RHvVytD3XU1CRVLVx8nN71tKRk3Xv7u9xtxzSkdX387R52dPRkNN/8rBwsrvVUhF +U9jJx9D/S0M8PFHv1d1vWE1FRlHNvr7B0XtTTlHjyMTG1G9XUk3vxMDF0WFORD9DV9vKzdxf +TUdFV87Gxs9fRT47O1DhzM3XaVlNS1nbxcXP41VJQ0JXz8TH02VKR0VL28S8vcXN3fdt98y/ +wtdvS0M+P0/Xys3fV0pHRk3ey8XP719RTVNzw7q6vs13U0pFUt/X71NIQENEU9DDwtNvUUhC +Rk7TyNHvU0A9PT5SzsjO91ZPTlr3zbq3wM5nT0pMWM7Cx99jTk9OU9m/vsxvUUxGRk3/x8Pb +d1VPTlf/x73B900/PT1AWMa9x+dpYVtb986+vdllTklJS1rPwMV3TURDSFHpyrvC2etnX2dv +18DB6VlLRkdMX87Dy2dQS0xOVdzHweFRTUtRWWnMvL/R+1VOTUhL79z3SkVCRk1X3cfA111O +S09SUufJ1WdMREZITWfHwMrrb2dn++PPvbzPd1lPT1NZ2cfRd1VLTE9Vb8i/zm9fXF9rd9nA +wNLp/2X39+XJwMlfSEA/QkNR183hW1FPWWN33cbD3GVLSE1NWt3N019OS0xca9bIv8v/Z15n +Y//fzNVvU01PV1/pzsnQb1JRV2Fv0szMe05JSEtVX9/MytdfV1ddVV3/3eVZVFlb8+PQy8XR +b11bY3f/59/nZ0pER0xZbd3Oy93r79vRzsvGw833Z11bb3P/2dfnWlNbY2t33c/X92Fjb/vr +79jK1+tr99vX4evX611HQ0NDRUlXb2VPTlNf+//vzsjcb2Nnd29p99TW91dfb+n/d9PK029c +YXdzV1V361pPU2Xn523dzdNrWmv33f/r287tVVVl7+1z/8/L3Ptvc3dVSlPv811c/9/a/+3W +ydT3Z+fdc1lTd/9dSkpPVE1KWefa7+XTy8vZ1srAyd/j63dSSk5v4/9cZ21fSUhd59737eXb +e1NV68zR2tPQz/Npa9/3VUpHSEY/Q1vv+2Nrb/dhUVPdzdbb293vX1j/0tDb3+Pta1VR3cnI +0dXZ61JHSGHrd29v82tdW+PJyM3R1dv/WWHpz9nj4/NvXFlf1MnZ5+ttTkVASmn/a+/j72db +We/LzNvb3/dcUVPn2ev/Z1NKQkFV3tnf1dvd93fWx7/Hz9f/TkA/TO/b3+N3YVBHTf/n3+f3 +ZVFGSFXTyMbGydb/XF3d0+t3XU5APT1M69PY3ftvU0ZLY9XO0NXrX01MWNXJys/db1NMTenC +vb2/x85rT1Fv3t9nWE1GP0BS08PDy9j/XUxN+9XN3mddVEdJ98zExtLnWUQ8PEv/3+n3bVtR +TV/MwcHJ33dbS0xe2czP22lTRDs+X9na3GtdU1Fb18G9wM73Y0o9QlPb0M3X+3dSUnfQxsTP +61pMSEf3y8jFzc7T82/by8PL42NLPzo6TO3My/NVTEdGW8/H1e9lX1dKTdnNyMXd3+1MTFvZ +v7m7w91jXlvf2dXea05HPj5Lb9rMzdDvTTo6Tffb3f9PRENFZ83CvcHL419OVGdr5WtdW01G +RErdx8TE229JQ0z3z8vI1mtLQ0BN79nU0WtOQ0NZ2crAwL/I3VFHTWvXy8vR51tMXdvJxMnZ +Y05MW2vT0N/O0vdcSEbau8XI1UxOQjhET0tXYUlb7UdabdvDwsbdVzxPY8e/bVnjZUtVPT3N +yr21z9drX2/OzdvJz+9bODc9UePOzVvT1udrRC4qLkqyrK++1uNMZ1tJW0vav6u0t71F3VdC +PzU1OVJrzsZjX+fKurnM39nj42VGZ2NBY0xOSURANLSlo6VPKh8nSq+fn6Gq50YtJCQrLz69 +u7S998+9v797Ni4xKzpvXbWwrq3H32NI1r/D1vdnP0g9KDlCM/tAMTUvOb+vublGOfdOv6+r +qbC+SkUuLT9OvLzd1UZPzysuTbypt0ElHyy/p6Gfrba+OicfISnPtbOvvbm3sLe8xTkzKiIl +KCtFva6qqK+tuGPN28O8yE9jOzlrSfPbR0A4NTp716+tt79vV9rPx7i/0c8yKyslLjUpO6ys +qLkpHyYwtKu+q662sckvPWNXt9nnx8C1qKq0tV09MyMfHyQvO1NFT8zMvbKxr7DId0E0Li43 +Su/XzdLr1c7Fua+vr7zbzse5ra6uq7HLOTAlKjM0Ql1va+M6KjFbycTeOkL397ywuba3vLvK +UUppy7W62Uk4MzpP78XI5VM4LCYmLT9Ye//hy8fHyMS+vcnbb1Bf18q3tbzH61FVSkNZ59r7 +ST49PUNj0cC+ztPVXkxHQWPN09tpRkVPd8q5vO1dT01RPjpV3MG/xc7Myb++vsf/92VOPjo+ +U99nPTk8SePOzsTD0eljXV1b3b21t8vnc3fbz8e7vclrQDQyMzZK38jGyMzTSEy5REVZ3ExH +PkdI3b+4v9VfUl5NPTXD0kRBPUhNd86tvM9lSnvrY8K5zsffUDld7V9GSMldT0hOR1w6OstX +Y1tnVrC5wqy+wb9A20VKzvNDrrr33TlHudDOs0fbTzpBOz9fW9PaO1Tf12XG1XdIXThvQ0JX +v66suEJETeXl0Ve2vmk9Ly8tP1PNusqvu82/1b7C2UNMNjRbSjU6LzPKuLOqrKi12zk/NTg+ +S0vdwjxAQyMyRS3HxDbQybztNTpIvKWkuMq6srVvOiUutKaswCofJSw5u8a2oafGQC8rc9/V +tbCno6WzyT4uLyonJSsqNjhGurW1uMrTy+PDtke+rFPMtEu7vjNfPi7vQS334TTD2tuptl3p +Y7irt8g5MC4kZdH/PiwrQjkpMC/Koaauu1w+TzIvvLCmqNEz2N9JbSooTkg6LjrPprE7QsjG +vuM5uKq+ubbPsco8u1QsJCI4sqtBNzX3u0Et86ygo+vHrcOtr8a96yUlLShZqK21UiEfISk9 +rqmjn7NfUzQ0VVTVpaeur0I6STMqLzs+21kvRdK0smE3PETVu6+sqLRTNSMtPzVjuffpPic9 +Wb3IzL24SiwpNLKqqKCpuEEnID08zq65sMpCQTIjNbfGvjQjNVVDyKupn6pNQDg221M1trK4 +v0I9vb5bTzU7X0MvP1q+uMrCvr7Me2fExj7G2b+460TBsUozJifZRnvN0cFILWs9QLmyd6u6 +SVYuQ+3de9NvRy8jNberr98uMTU7P/exoKS0UT0vLSQzU/+9tL2xu2dKw+97XTM7NTIyPWm4 +va+pxazKzLGtv7lIVT05NztVyPM9LjtZvs2zqcTGTyzX0b+trMm4QycqKDmuvLezZV88KCxC +2bO4xLfDPlQuPnfX2b/X/+NXWNXHxrpcW1Q+PzcyP0pTz8LPwbK2t+/O619IKjEtPDdJN9E+ +wttJ07zLvb3MwtHH3Xfvwm9d4zxLPkXnzs7n48Jady5j0//DT9rN71xXOvdP1uNj2etK48rG +wWfIT1s//9O0ta69w3s9MTA7Y8Xd4c1GRT1Ib8bhzNRfTURFyL64v+NnXUFHZ8nIyndJRTc7 +Vdq6t75vQzU5PkzczcjpRTw8PEhYW9Pd520+PjxJ0cy9vuO1zL67u7a5ws5fTzszOj08Vk9V +Wj9DUsLMw85vzu9ZU+nfzcrTx8Ld17++vL3K0VtKPEdJ4+PX2W1va2XPxsHG0Fc+PC84Rltv +zMvZ0UxKNk4+X07PydnHwbTHw8rt9088QEGws29V/9xZ/+/fzf/f4UlBMTpJTtR7181TST9b +zW/AykvhTUdERj/Dy8Lpykb3Q01C2Gu9XD8+P8d7y8/LuMvtu97Vyr65tblVXEA6aUZv5Vvn +QmtZxWXv0dpGv2vD58u0Z8M93Dj7P7r3usrf00dCRkLPY2nCTUw/Umfv41Hd/81PPldPZ/Pb +S8s7Vjlv78i6wrzr50DnTNTfv9hf60fORlTFUbg/7zxRQP/UT7tpWUdEVzu6293G1sVJ2z7A +wsfTslXWSVPXOsFOtFW5RWVMyEpGvUPISL49ylPO1+NYuFPN6d61xMZnwzfOTU/hvU7fa0Zc +NVLrvt1H93dNWDXbTLBPUss+vkFXR8FJvl9bW0HMSV9Jx0TZQ2tXQ7ZPtD57N1NOMck4u8tJ +WEhnSfdIs1fFT2/fU9w/ulnFv1F3PzrOd1e40XfRLkXfOtfA/8iuTVW6Pce+RLXEV8PrPbrH +97zIPcY2K807Z8Nb7/+8P//fQq/3VcRIU0g3xP/LzVlZ/1VI2M/Gw7pWRdFHTHvdU3dTZ2NZ +PjdRacjr0ffN1kBtRP/VPk09PEVBy8HFusnR401PUs/K18xHSkJKW02+v76/TE7ZUstZzcrJ +ZUhHOEVVZ8e640Vvt7XM2uPJtLXF4ffpz+dcVTo9ODo1Nj/P6dvOb+vF1sy7vca8XfNhSENr +b2XjWVD3UF/Ku7i/yFNLMzQ5NlBDSkJGRUfr1Lu1uLy91sra38Bt49trRDgtPELvuMdfSTlB +OVtJU19Fd0JGPz5Kvrqusq+ytru9r8G63TkzJSYiKiw4S0vZybuzq6ukp7CxyW9QQUhJ005A +ODs/Ql/Kt7CvvN3Ma1U5RsO+a0UtLC41V+vVREQxP0lTR9HNwrq+u83Hu7GqoaSpqa+9y/9L +OykjIR8fHyAiMTxU08m7wrOusauuusnKY1PfTV3vY/9tZ9PJy7+2sbzL6VVJSjtFSThIQko5 +NzIzQOHLY1tAPkjOvLOtrbm4s6+pqaWqrLe72Vk/NDEuMCgoHx8gICcrNFFQzb+zrKekoZ+i +qq66ytlr+0tTPzIuMjE3RG3NztDR2/vnztXNxl/VQT85OTU9Rk0+Ozo4SExvyry5ubq3vre5 +t7GyucPT22tlV0E+NC8rKywpLi42PEdHV9fOvL23sq+ytbu2srS0sri8zOf3b2PcX2f7UUJH +QD5JOT4/Pjw1OzlNTO/ey83LxMG8v7vAuMXdZ0pIS0tLWm9jV1lUX1dvZ97e/1VnWV/Ta8XJ +61lMS01YTE9fd29349/Z3eXb1NNdae/ZzdPHxr3Jz9Hn72NUSFhPRENHSFtZTuvl/2tlY2Nf +S05ZWVhMWenb0dXMytvf+9Xj6effy8fV18/Kz8/XzMzfe/fn49Xz5dHdV1lcUVJISU1vTklO +T2FnWl/33G9hY19eW01Za/dfZ+n382Xd0t3rXf//929z38/V4/vtb1hPSFl3Tk1MT09JR2Pz +3f/3d/NpTWndys3RzcjT1OfVzcrd891391tW5+HtZ+Vv61RMXWNjWFtYb29WY9/b2+Pf2WtL +SVB36eXX3ON3d2vSzMzP2dvnX1Jd29vn9/dnXldf4dvc6d/l329v68/V43tdWUhGS1rr42tr +a1dIR1Fp6+//42NJR01319TX0s7be13t0tXb6+vzX1Ra2c7K09LX7V9VXefZe2dVUUk/QlP/ +9+93b2dPTlnTxr/Cv8HV71nt3dPa3/d7WVhd59DT3+HvWk1JTv/7b2ttXV1SV+nZz93/ZVRB +P0lV/+vf2d1zb+vMwMLGzNfnXVRj2dHj81lOSURLY29tb1lXWU5Z79PN1etVS0NBPdtzR7Zd +SsxUxd9KubHv91gw105H1ufQxs9lb+P/z8TU19tXSEDj5dG8d72+XMPrTP9hW8/fO1ZCPthL +X9VNXGdOSv/3c8a/Z7rAz7nAvthV50lIPUI5P1FG1mdVPUpP77vR3co741Jdurm9wrHnM08q +MMI3vLs7tzAu60tPOq6/tLAzRD02z3exoq28OiwlK0A0v7dLtt5EvVPEws9pZ9c6zEQ1yELj +t9+wVFa4SLq4TrnN/y7KtLqsVy0sJTytpqCgyTsqIjXF47i57bS/QkIvNNm1rLjVMSw5Pr6z +ycvzV0lWV2+9s7KzUylbt7mvSywlHylZr6mpvywqHy1D17yqqrOtPDEvJ1e6sq3OPVM8XcZU +uuFzx2lNQm9fsK+9Wiv/ubW0MykiJtyto6jDMigiOXu9rdXM3ry93s4+RcjDzcTtPNJBSesy +YUhnuLPUzr93qqtJPr3Jq8YuKh8o0a6kqksrJyBE48S061NPxMzfZzNPxsK9VDdBPUp3S09K +R1XazsfFuLy6wkKuvrWuQTwjJtOspqtfJSQjO7+/t1w1QNPKyvcuREpzwONfY07pyczlVVtM +48rBvbqs0zi5wqmv3dcpO821oK/TMicvP8u7bTw+aePNazpEPmPB381ZQlNAT1djy9dOSjbW +uLZQu620p287KSrNq6OmzjMkI0f3vb9K6b3EvDwqKDjKsb5OLSg1T7e0xt9IO0RpzrFz/7HC +qPc1SyzKtq6fuO8yKDZfu7rDS1NnzL3L30dHVU9HOC8yP9vCyrxIODgv07q+w6mzpbw0Lizr +rKWfs0IoIytItKqxtldN5z/XzrSrtXcvJh8qNme6wLlMMyooUU7RrKSoskMpLT20rKu0NzUt +LFrItL3NOV5N78Jrv77JyE00MC0wU0/CtPdWKyg+NkPbv6+ouzwmKE6tn5+r0zEsL1S3q6jT +zUtLyWe2t6620Fc1Mi85RHe9vsE8KjEtPF/Gy6nJv0ErQzDCp62q3UEuK0S+sry467uxwLpv +z8PNSz8uKi4rP2POustMOy8yOT/Hta7KPCgqLNy4prK50TNbWtumta2247C/v7rJzNlKRjor +LykpOkHfykVILyxfPEzTOLew37RPO1g+r62ssU1NP++tv7y/17a/wsfJuMfZXT03MC4pNDJF +3mfeRzI2NGPI2bzTvbS0uFNMQE24sauyzG85b8K4ucxeVcK2r8xIOTNBOzM7LTEvN+Pd91M0 +ODk6RUzr1+PIzq2qrb89PzjBqqqor8jlZ0lJQzrMz8HDZVFAPEpLQWc0R89IzGsvM2s381Y7 +777VzK5luLDTqefHs8nHu7G1uMdGXHtX3chDOF00azo090FQa026O09MYc08TznERUfLSLJT +sLZetEnzssSrZ6++vbZVuGO8VN86OdssSTYwQDIrSzlVPm0v4Uk6zDjaaz/Qv7G+vtq2Q7pG +3dDK4fu2V7J7xFW9QL9nZ1Q9wD3GNOc1a0JrRFVfQ8VX0EB720xvvtDHvM7O7enr0mfK07/I +a8Xe48bV1XNtPd84zj/ZRVb3T2tvS+dPXE3pPctHX0xB/+PV40q3SbZKzEPIyT/LN8tU92Nd +yG1La+FPwVW23Ne4XcNZwTrHP9BdRlRETUPvWm0740e/b0HjXMxbzMBKuN/FSMJvxMZKy/PV +UsFDe9HtOXfZa99KsljEzO2/493r0NnATbdD0jbzPt3jPuVEtlq6P70/uTxT60zaQL1PxErn +OOXlMtM0zlB3R0pZPnc32kvlTNFFxvdVxVddV10z3k3v69NjWsJP88lQxDjBO81X6/vnv1LR +5c02xDPPXnfJ77blvj67Qs89yfv3Wul3Yds6z+vYe+NXVdNYytzMP89MwMtBvsvKxMg3xzVb +TXdLXVxpY0nEMME/xsZV6dm8T7dIv03AXUjRP85CwVK8y1LXVGn/XMftS8s9zd86Ous8vknb +Ot4z7XM6wzPBTNtOO7pGs07SyEvOX+FOve/vSk/ZQWdjYbZvwkfnzVzMXc7Mukm+U0jbbT7r +1N3lQbVNvNPFb7mwQLvIWLlE0bs4yjRt3DbJO0fANs3LL9dGPb9TXE7jc3e8RrrOQq86ybU6 +s01OtTy6SjxNX0tvbW/P20tLvzO+b0W/Qla+L0q/S17ASl3FVP+63cK9Sc7zOdQzPN49c2NF +RldCXMdRWu9BY8ZFzVpZwdbVx03n2sXVvm+/xGvUSUvlzd3YysjfxUNC7We+usbjyj1XSEpS +Rk9F607/0eu21b/Azc7rS+NlZdlFT0VMyHfF1eG728tMTUBXZ+v3QUU4Pz9TR19Nzr7Lv0M8 +OmHEsa+94TQ2MkVOT1VFSOv7w7+5v77T1PNKPjU+Tnfze2dv7829sK+urrrIa0pvQ0VOQUM9 +OD42VWtdys/N0ddXzsC/uL7L31NLb0rMa1/PU+NcTlVV23PRXktRQUZdzrvDwO9QSU3lwb29 +xVM9MTdAU9fZzslcb1VZx8zH09XvTE9ITFrf385rX0E/P0nn1c/OX0tPPlpp3dzO1VdJRElL +42/f/1tJVUta1dvPxc/KzWfrd9O8v7+/3ttMTv/c2ettSFVDSu3nu72zvb7JY9N31evcW0RC +Mz88a2H/505GPD40Tl931tnv70v737y4trbAxu1XXF3nzOfEZU9BP05h1VvRTV1HPz9AZ1zP +a/NEPj4/U9nMzcne72/71b7DwMHZ/0pFQVnv88x371NFV0fp08rL2VpRQU//z8rIzuNcTk9Y +3czL3edbRkBLV+vGyMjR72dbb83Hxb3L2W9NR2ff38/vV0hBPkr/zsLGw9PfWVXj1cvO03tN +Qz1FV//K3+9RRT47Q2fv39NZa0nfd8i/w8DnaUJERFPj18/e911KSVxzwcHJd0pHUvPT0V9L +TEn/y7/Fzv9YS05dU1dN2cS3sri/50w+RFXl6+dJOz4+RlbMx8TGyNLP7e/fy8HIzfdpRUVH +T3dv61BMQz86SG/ZzMrM3M9z59XHz97Wa1pRTV3PzcrVTUk8OVfjw7u/1+9vT1ffxcDD305D +Qj9AU9labT85OTs7W8i/vc9jRUI/Ud++sbW4wM9aT09czNX/d1xET1ddxLy8zsnOT11OTM7P +Y18/OTg/RtjHzNDj2tVj08S/urTMz9FrTc7F68BLM089MUJH4bvKT2dXSkhtU9fR21/HVVVn +5dfOVkc+ST9S6+PK00hV3Ur/1e3DytpO+2k/U0xjwMvpytte71nhu8C93VxDQU09aczj3mdX +VW9N29PS11RKT0c+Rk7vbef//1vP7XfAxsbKTc7tUdH/zL7Oz9Fve2NTb8rz81tHQTxKU8m9 +7+N3RU5BWdXNwcnJyu/jTE7NycjOWXdAO0dT18FvVFVDRjxSWO/VTUfzPHdbP7zP0MJFXc9E +3vff2j9VTl9v69u86+ndREJNQ/fAxczvRl9RW3fz389n3/vRVctjxbjAwMZRVUxO2MnBv+dh +Y0lrTvNd7/NVZ01fTEpS51tr7+PczOPL29DOTkM+REhIbd3M2FdpUFfX98fAxMnj729T32vJ +2uPZVltWU+fRv87ca1JTVV3V2d9RPj89Q0JPTsvz5V9zQmdMY97Vy+9RWU7f3ci5zs1YVETZ +///A1+XdPVhARdFvv8/dXEBDRUfr3rzO2fdYTlRfVcfJysv/ymtvzcS6wdHvS05Qd93RzGtM +TEhIS1dnY1dJT1dHV0hn5+Nf2W1n2fvZw9TOSk5dS1tr0s3Fd1PjTOlpRtJGY15D1f9rym/N +2FNX62fY3WnOVeFVR+NPb2Vf729JR0tS62/nxefH0+nOb1nnSN3vVtvr2tFPb2vR29v3zFVN +VT7Rb1DP98nNXl1d///nZ8Npd+dNzNPNy83B3dRK2mNP3D3a52/PX7/KxdHYyEdVSU7LXNnn +R2s8O11N81lMSkI/Q0hd0+XN52/GXNe907vve/9HUURzysTH52tDY0JMW2/K9//dRVlRb8rK +ydx7b1xbb+XT0M5n0/ff3t3Ra8xpT3dMRVd7xtfJ69ldYXdK0NPpXndl2f/zzNfeUUNHd1fv +d3fXUltRSGtTe8DOudnzd2HjU8vjxtlrW1tr8+PYz29UP0lPd+vPzs/KSttLV/890mf31UNj +Xz9HREvcWdhZQWU8aV1j++v/c2d7bdHCvL7M9+ll/13329vJWFFvS2dX0+vS6Wd7UWtU5+PM +ztDbydPr0NXR2tnU3Hfbb//a995lX0g9TUbP1tTXX1dMTEj/3e/PZ9lNZ0VjzdHMzuFOS0Nb +c83O51NEPz1MVdDHx8rd72lPUv/rz8/O1llMRExf43v/b0tPUVvHv8fG+2djXWfZ18Hn71lN +W1NVY9Tj2GNIQkJCVtfpzmNeTWP/58u+xr7b3/9LZ03Tyr6//19HR1d33czM129ITFZNz9Zv +a2tX5U370N/B0f/TW1djd8jF299TWlNJQT9P89vf+0xJP1jhz2dPQlPd19/f2czJymNVSU9c +/+NfW1VZSkxFSczMw83nZUZdd3fGy+POT1tZRmnv2dbO5fdHW2frwrzFwsvVTlNX7+Xpymtn +Q0tP3MXf2Fd7XklHPUZv2e97UUlGS9nLw73O2l1OTmft0czN0Vv3TGdj38nO1ftfUE5TXsrP +119BQE5OWd/SxcXPUUk/XdDHusfXXU8+Pk1SxsrLSkVAO2X3a1/Vd/dTPkRU4cPN33da/15c +/8/M22VTW09ATP/Evcbba2NbW/vQ0cvNZ2NGVG3rwtXV011RX1fby7y+0dhz90pTY9z30d/3 +Szw+RtnPzednW0tHRe3Zy97XT0dDRm/Rv8bPe91LQU5P19vV309KQUNA38nIwtP3UUdO283Q +b+ffV05HRHu/wr/Za1tDY+PAucLJWVtOTk1e59PH5d9IP0Bd2MZp329XTDo8X83Hy+ddY1xT +1MnAw9vZY09DTnfBvcbbb1BFSErXy77Gc0I7SkxYY9XG0dtYU1l717y7vM1rVlpXa/fRy19v +QklCSPvWw9xDQ0lEXWVj3P/ZTEg/Qk3pzdXIxuNVSz9N58zBe0tPPlFPb9HFyMTrVVtr3b/E +w99VWU9KQ2/Xw8jO41db7+fUyL3D209GP0XfztPZ5WtbVkZP48nP505NSD5Md9nZ62VfXVlM +Zcy8vdVeTElh49fBw8bZVEpJS1tvXl/37WtRQUNLY9Tj71lNTV//zMfMvb+/20ld7ce+d09P +V1lFRFTXx9ZVQ0dPUVtt/+f/41tGT2nXw8Pb7+1OTkNEW8/L2HdTSkhf987Mxcn3X1/fycDA +zNvL129ORV/YwsPaZ1FPVd7b5+Xr0NdRPT5N99nW2d3lT0xW/83F1c9fSUBCXHfb1uP380tJ +XVHW19zaW09FT3PZzMzR7+NaTk5DT9vnZ1JMRUNOX9fGzNX/911j/8q8ubrQ2efv7//rzthn +SUZITlFNY9t7XVNJSUVQ39XO71Xv62ldd9zBx93/UldfaW//5+Xt/2FfX2nZx8v/+1FdaV/7 +79XI/09PRuXP0c7P69pvVVFKW2fbzNtbWUth/3Pr69n3a2ddd+9v2vdTUU9PVVdt69/la1tb +UWdjb/Pje2P/Z2/3593S2ePl73tz/2/n53tbUk9TX+ff3uvv6+Pv0dnPysXL13Nne+3n6dvf +7XdpXF1dZ2tvWVlYV2FXY2n/6ef/d2/v39/d3eP3X2NaW2l3/+//b+9v9+dvZ+/p5ettb//n +/3Nrb3d3729nbf/Zzt3r+93naVtYd+ttW11dZ2tv8+/j82drYV9jZ//j/29nd3N37/Pb3/93 +c3NrY2d77+dz93d7///73+H393trc/f/+/f/7f9tY2N77+/j6/fz9/v3997Z3e///29hZWv7 +9/f7d/97d3d3/3d3a2tjX11n++/t9/9zb3dvd/Pv93tvb21v/+/r93f/////d3f37/f3d3t3 +b3t3+/f/9/f3///38/f7/+/z/3t3//v/e3Nvd3d3d/////f7//97d///9///////////+/f3 +/////////////////y8= + +--Where_No_One_Has_Gone_Before-- +--Outermost_Trek +MIME-Version: RFC-XXXX +Content-type: multipart/mixed; boundary=Where_No_Man_Has_Gone_Before + +--Where_No_Man_Has_Gone_Before +MIME-Version: RFC-XXXX +Content-type: image/gif +Content-transfer-encoding: base64 + +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 +l7Vry4B9aM+yKjifMosAADs= + +--Where_No_Man_Has_Gone_Before +MIME-Version: RFC-XXXX +Content-type: image/gif +Content-transfer-encoding: base64 + +R0lGODdhQAHIAKcAACQkJNsAAAAAALZJJP+SbbZtJLYAANuSSZJJANttSf+2bZIkAJIAAEkk +AElJSbZtSZJJJG1JSduSbW0kAElJJLaSbZJtSZJtbdu2krYkAP+2kv/bbdtJJG1tSf9tSf/b +tgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAQAHIAEAI/gABCBxIsKDBgwgTKlzIsKHD +hxAjSpxIsaLFixgzCgCw0WDHgh8zchRJsqTJkxYdoCSokmHLgS8hqpzZMCbCkANxrtzJs6dP +mD8HIoAwFABRCBIpQIxQ0CZCm0wNOlWoM2jCBQiwah2AoMCABAXAik1wgGwCAmStqqU4NeLQ +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 +0CK3jI33rIAAADs= + +--Where_No_Man_Has_Gone_Before +Content-type: X-BE2; 12 +COMMENT: This is NOT a MIME-compliant content-type, but your software should be robust. + +\begindata{text, 269602880} +\textdsversion{12} +\template{messages} + +Where no man has gone before... + +Click on the "death star" icon to start the animation: + +\begindata{fad,270222644} +$N icon12 +$C 30 +$T 30 +$L andy12 +$P 0,0,20000,256 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$A 29,24 -1,76 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$S 216,264 +"Fire!" +$V 260,260 417,242 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 321,186 250,158 +$V 319,193 265,172 +$V 316,199 290,187 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 321,186 187,122 +$V 319,193 215,141 +$V 316,199 232,155 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,102 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,102 +$V 198,102 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 241,145 179,117 +$V 265,163 179,117 +$V 316,199 180,127 +$V 169,120 163,101 +$V 184,111 188,89 +$V 163,101 172,115 +$V 188,89 190,110 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,108 136,162 +$V 136,162 137,176 +$V 136,162 131,162 +$V 131,162 130,177 +$V 130,177 137,176 +$V 131,162 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,108 +$V 198,108 199,118 +$V 199,118 138,171 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 191,115 185,109 +$V 178,104 185,109 +$V 246,158 180,127 +$V 169,120 163,82 +$V 185,109 204,80 +$V 163,82 172,115 +$V 204,80 190,110 +$V 175,133 173,162 +$V 173,162 181,132 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 198,108 141,158 +$V 141,158 149,161 +$V 141,158 130,154 +$V 130,154 137,171 +$V 137,171 149,161 +$V 130,154 157,133 +$V 162,129 162,129 +$V 162,129 195,96 +$V 195,96 198,108 +$V 198,108 199,118 +$V 199,118 149,161 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 164,61 +$V 185,109 219,66 +$V 164,61 172,115 +$V 219,66 190,110 +$V 177,134 201,167 +$V 173,142 201,167 +$V 188,128 256,143 +$V 256,143 195,120 +$V 175,147 147,192 +$V 147,192 173,142 +$V 168,127 113,103 +$V 113,103 171,136 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 146,98 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 171,109 +$V 171,109 177,130 +$V 171,109 142,135 +$V 142,135 183,120 +$V 183,120 177,130 +$V 142,135 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 132,80 +$V 185,109 195,52 +$V 132,80 175,116 +$V 195,52 190,110 +$V 177,134 192,201 +$V 173,142 192,201 +$V 188,128 241,106 +$V 241,106 195,120 +$V 175,147 234,175 +$V 234,175 173,142 +$V 167,130 113,143 +$V 113,143 171,136 +$V 167,130 160,153 +$V 177,130 210,140 +$V 190,110 208,94 +$V 172,105 172,64 +$V 154,122 120,115 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 142,135 +$V 142,135 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 146,66 +$V 146,66 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 171,109 +$V 171,109 177,130 +$V 171,109 142,135 +$V 142,135 183,120 +$V 183,120 177,130 +$V 142,135 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 146,66 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 139,55 +$V 130,154 175,116 +$V 139,55 190,110 +$V 177,134 219,150 +$V 173,142 219,150 +$V 188,128 193,72 +$V 193,72 195,120 +$V 175,147 226,80 +$V 226,80 173,142 +$V 167,130 144,191 +$V 144,191 171,136 +$V 175,147 173,202 +$V 155,138 130,167 +$V 157,128 121,89 +$V 171,109 165,69 +$V 191,115 205,70 +$V 184,116 247,130 +$V 177,130 191,172 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 146,131 +$V 146,131 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 142,65 +$V 142,65 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 156,170 +$V 156,170 177,130 +$V 156,170 146,131 +$V 146,131 183,120 +$V 183,120 177,130 +$V 146,131 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 142,65 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 179,200 +$V 130,154 175,116 +$V 179,200 190,110 +$V 177,134 221,72 +$V 173,142 221,72 +$V 188,128 123,82 +$V 123,82 195,120 +$V 175,147 120,89 +$V 120,89 173,142 +$V 167,130 276,111 +$V 276,111 171,136 +$V 172,131 164,203 +$V 153,136 74,143 +$V 152,114 128,56 +$V 179,113 182,44 +$V 199,118 301,141 +$V 194,137 215,183 +$V 151,150 97,225 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 146,131 +$V 146,131 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 142,65 +$V 142,65 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 163,134 +$V 163,134 177,130 +$V 163,134 146,131 +$V 146,131 183,120 +$V 183,120 177,130 +$V 146,131 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 142,65 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 177,125 +$V 130,154 175,116 +$V 177,125 190,110 +$V 177,134 162,129 +$V 173,142 162,129 +$V 188,128 173,142 +$V 173,142 195,120 +$V 175,147 163,145 +$V 163,145 173,142 +$V 167,130 163,134 +$V 163,134 171,136 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 146,131 +$V 146,131 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 142,65 +$V 142,65 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 163,134 +$V 163,134 177,130 +$V 163,134 146,131 +$V 146,131 183,120 +$V 183,120 177,130 +$V 146,131 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 142,65 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 177,125 +$V 130,154 175,116 +$V 177,125 190,110 +$V 177,134 162,129 +$V 173,142 162,129 +$V 188,128 173,142 +$V 173,142 195,120 +$V 175,147 163,145 +$V 163,145 173,142 +$V 167,130 163,134 +$V 163,134 171,136 +$V 204,106 216,100 +$V 215,110 221,109 +$V 231,98 236,95 +$V 241,102 241,102 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 146,131 +$V 146,131 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 142,65 +$V 142,65 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 163,134 +$V 163,134 177,130 +$V 163,134 146,131 +$V 146,131 183,120 +$V 183,120 177,130 +$V 146,131 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 142,65 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 177,125 +$V 130,154 175,116 +$V 177,125 190,110 +$V 177,134 162,129 +$V 173,142 162,129 +$V 188,128 173,142 +$V 173,142 195,120 +$V 175,147 163,145 +$V 163,145 173,142 +$V 167,130 163,134 +$V 163,134 171,136 +$V 214,99 214,99 +$V 215,110 221,109 +$V 242,84 236,95 +$V 246,91 246,91 +$V 221,147 221,147 +$V 207,133 207,133 +$V 168,166 168,166 +$V 150,161 150,161 +$V 175,92 175,92 +$V 192,90 192,90 +$F +$V 428,132 377,142 +$V 377,142 327,179 +$V 327,179 306,219 +$V 306,219 304,271 +$V 304,271 318,309 +$V 318,309 350,344 +$V 428,132 479,134 +$V 479,134 520,154 +$V 520,154 549,192 +$V 549,192 562,230 +$V 562,230 564,265 +$V 564,265 553,296 +$V 553,296 531,322 +$V 531,322 511,340 +$V 301,290 318,321 +$V 318,321 338,343 +$V 301,290 299,253 +$V 299,253 306,219 +$V 527,162 563,144 +$V 544,181 570,152 +$V 520,154 590,101 +$V 549,192 592,157 +$V 578,109 569,68 +$V 590,101 581,61 +$V 506,90 503,105 +$V 503,105 510,108 +$V 510,108 521,89 +$V 521,89 507,86 +$V 507,86 594,23 +$V 521,89 593,35 +$V 510,108 591,50 +$V 418,224 410,232 +$V 410,232 409,248 +$V 409,248 420,258 +$V 420,258 432,257 +$V 432,257 446,246 +$V 446,246 457,219 +$V 457,219 447,211 +$V 447,211 418,224 +$V 425,233 421,238 +$V 421,238 427,243 +$V 427,243 434,239 +$V 434,239 425,233 +$V 507,147 548,197 +$V 344,235 358,232 +$V 358,232 346,243 +$V 346,243 359,237 +$V 365,248 357,243 +$V 357,243 349,247 +$V 349,247 354,257 +$V 371,259 367,253 +$V 367,253 354,257 +$V 354,257 364,267 +$V 381,274 374,281 +$V 387,277 391,281 +$V 391,281 381,289 +$V 397,284 402,288 +$V 402,288 392,297 +$V 392,297 389,292 +$V 389,292 397,284 +$V 407,291 399,300 +$V 76,56 51,65 +$V 51,65 34,80 +$V 34,80 21,108 +$V 21,108 21,129 +$V 21,129 31,153 +$V 31,153 54,167 +$V 54,167 88,169 +$V 88,169 123,153 +$V 123,153 139,129 +$V 139,129 146,105 +$V 146,105 139,76 +$V 139,76 118,58 +$V 118,58 93,53 +$V 93,53 76,56 +$V 34,157 47,167 +$V 47,167 82,175 +$V 82,175 115,163 +$V 115,163 130,154 +$V 130,154 146,131 +$V 146,131 146,115 +$V 146,115 131,123 +$V 71,102 63,110 +$V 63,110 65,120 +$V 65,120 73,124 +$V 73,124 83,123 +$V 83,123 97,103 +$V 97,103 87,93 +$V 87,93 71,102 +$V 73,109 71,113 +$V 71,113 71,113 +$V 75,115 73,109 +$V 73,109 75,115 +$V 73,109 79,112 +$V 71,113 75,115 +$V 75,115 79,112 +$V 39,105 39,105 +$V 40,111 40,111 +$V 40,111 53,115 +$V 47,118 47,118 +$V 44,123 44,123 +$V 44,123 44,123 +$V 44,123 48,127 +$V 52,130 52,130 +$V 52,130 50,135 +$V 55,134 55,134 +$V 59,136 59,136 +$V 59,141 59,141 +$V 66,142 66,142 +$V 70,141 70,141 +$V 70,141 74,143 +$V 74,143 74,143 +$V 93,40 112,42 +$V 112,42 142,65 +$V 142,65 151,89 +$V 93,40 80,53 +$V 151,89 146,105 +$V 147,109 157,90 +$V 157,90 155,65 +$V 155,65 122,39 +$V 122,39 93,40 +$V 93,40 86,54 +$V 146,105 163,134 +$V 146,119 157,133 +$V 167,130 163,134 +$V 163,134 177,130 +$V 163,134 146,131 +$V 146,131 183,120 +$V 183,120 177,130 +$V 146,131 157,133 +$V 162,129 162,129 +$V 162,129 175,116 +$V 175,116 167,130 +$V 167,130 199,118 +$V 199,118 177,130 +$V 112,42 105,48 +$V 105,48 136,67 +$V 136,67 142,65 +$V 191,115 185,109 +$V 178,104 185,109 +$V 183,125 183,125 +$V 169,120 130,154 +$V 185,109 177,125 +$V 130,154 175,116 +$V 177,125 190,110 +$V 177,134 162,129 +$V 173,142 162,129 +$V 188,128 173,142 +$V 173,142 195,120 +$V 175,147 163,145 +$V 163,145 173,142 +$V 167,130 163,134 +$V 163,134 171,136 +$V 220,75 220,75 +$V 215,110 221,109 +$V 242,84 236,95 +$V 278,93 278,93 +$V 248,151 248,151 +$V 211,172 211,172 +$V 176,196 176,196 +$V 137,186 137,186 +$V 178,70 178,70 +$V 198,64 198,64 +$V 169,100 169,100 +$V 192,97 192,97 +$V 204,137 204,137 +$V 151,150 151,150 +$$ +\enddata{fad,270222644} +\view{fadview,270222644,2,0,349} + +... by Curt Galloway +\enddata{text,269602880} +--Where_No_Man_Has_Gone_Before +MIME-Version: RFC-XXXX +Content-type: application/atomicmail + +; +; +; +; +; This message contains a ATOMICMAIL program. If you are reading +; this now, that probably means that your mail reader does not know +; how to handle ATOMICMAIL programs. +; +; If you were reading this with a mailer that had been extended to understand +; the ATOMICMAIL language, this mail message would automatically interact +; with you and take certain actions based on your responses. However, +; the language is designed in such a way that ATOMICMAIL programs can +; NEVER do you serious harm. +; +; If your computer has a ATOMICMAIL interpreter but it has not been linked +; into your mail system, you can run this program by piping the mail +; through the ATOMICMAIL interpreter. (In Berkeley mail, for example, you simply type +; "pipe atomicmail".) Otherwise, you can simply write the mail +; out to a file and then type "atomicmail that-file-name". +; +; If your computer doesn't have any ATOMICMAIL software at all, you +; should probably reply to the sender of this message to tell +; him or her that you were unable to run this program. +; + +(&checkversion 1 12) + +(defun init-ctrs () + (progn + (setq newline " +") + (setq summarizer "mmsurveyor@thumper.bellcore.com") + (setq global-survey-qid-ctr 0) + (setq global-nesting-level nil) + (setq this-level-ctr 0) + (setq total-questions 0)) +) + +(defun nextctr () + (progn + (setq this-level-ctr (plus this-level-ctr 1)) + (setq global-survey-qid-ctr (plus global-survey-qid-ctr 1)))) + +(defun pushnesting (txt) + (progn + (setq global-nesting-level + (cons (list this-level-ctr txt) global-nesting-level)) + (setq this-level-ctr 0))) + +(defun popnesting () + (progn + (setq this-level-ctr (caar global-nesting-level)) + (setq global-nesting-level (cdr global-nesting-level)))) + +(defunq onelevel (i) + (strcat (int-to-str (car i)) (cadr i) ".")) + +(defun apply (f l) + (magiceval (cons f l))) + +(defun getstring-oneline (prompt def) + (newlines-to-spaces (strip-newline (getstring prompt def)))) + +(defun getstring-notrailers (prompt def) + (strip-newline (getstring prompt def))) + +(defun newlines-to-spaces (s) + (let* ((l (strdecompose newline s))) + (cond + ((null l) s) + (t (strcat (car l) " " (newlines-to-spaces (car (cdr (cdr l))))))))) + +(defun strip-newline (s) + (do*((len (strlen s) (- len 1))) + ((or (lessp len 1) + (not (equal newline (substring s (- len 1) 1)))) + (substring s 0 len)))) + +(defun cadr (lis) (car (cdr lis))) + +(defun cadar (lis) (car (cdr (car lis)))) + +(defun caddr (lis) (car (cdr (cdr lis)))) + +(defun cdddr (lis) (cdr (cdr (cdr lis)))) + +(defun cadddr (lis) (car (cdr (cdr (cdr lis))))) + +(defun cddddr (lis) (cdr (cdr (cdr (cdr lis))))) + +(defun caar (lis) (car (car lis))) + +(defun cddr (lis) (cdr (cdr lis))) + +(defun caddar (lis) (car (cdr (cdr (car lis))))) + +(defun > (a b) (and (not (lessp a b)) (not (equal a b)))) + +(defun mapcar (func args) + (cond ((null args) NIL) + (T + (append + (list (magiceval (list func (car args)))) + (mapcar func (cdr args)))))) + +(defun thislabel () + (strcat + (cond + ((null global-nesting-level) "") + (t (apply (quote strcat) (mapcar (quote onelevel) (revlist global-nesting-level))))) + (int-to-str this-level-ctr))) + +(defun revlist (l) ; like common lisp REVERSE + (cond ((null l) nil) + (t (append (revlist (cdr l)) (list (car l)))))) + +(defun informative (p) + (strcat + "#" + (int-to-str global-survey-qid-ctr) + " (of at most " + (int-to-str total-questions) + "): " + p)) + +(defun survey-multiple-choice (prompt choices) + (progn + (nextctr) + (strcat + (thislabel) + " (" + prompt + "): " + (car + (car + (select (cons (list "" (informative prompt) NIL NIL) (cons (list "" "" NIL NIL) choices))))) + newline))) + +; USAGE: +;(SURVEY-BRANCH "What is your favorite color?" +; (quote ( +; ("red" "red" (branch-question-set "red" +; (quote ((SURVEY-SHORT-ANSWER "Why do you like red?"))))) +; ("green" "green" (branch-question-set "green" +; (quote ((SURVEY-BOOLEAN-ANSWER "Are you green with envy?")))))))) + +(defun survey-branch (prompt choices) + (progn + (nextctr) + (strcat + (thislabel) + " (" + prompt + "): " + (let* ((ans + (select (cons (list "" (informative prompt) NIL NIL) + (cons (list "" "" NIL NIL) choices))))) + (strcat + (caar ans) + newline + (cadar ans)))))) + +(defun branch-question-set (branch set) + (progn + (pushnesting (strcat "/" branch)) + (let* ((ans (ask-question-set set))) + (progn + (popnesting) + ans)))) + +; USAGE: (survey-short-answer "How are you? ") + +(defun survey-short-answer (prompt) + (progn + (nextctr) + (strcat + (thislabel) + " (" + prompt + "): " + (getstring (informative prompt) "") + newline))) + +; USAGE: (survey-integer-answer "How old are you? ") + +(defun survey-integer-answer (prompt) + (progn + (nextctr) + (strcat + (thislabel) + " (" + prompt + "): " + (int-to-str (getinteger (informative prompt))) + newline))) + +; USAGE: (survey-boolean-answer "Do you think I am sexy? ") + +(defun survey-boolean-answer (prompt) + (progn + (nextctr) + (strcat + (thislabel) + " (" + prompt + "): " + (cond ((getboolean (informative prompt)) "Yes") + (T "No")) + newline))) + +(defunq surv-pkg2 (q) + (progn + (nextctr) + (list (strcat (thislabel) + " (" + (car q) + "): ") + (informative (car q)) "" (car (cdr q))))) + +(defun formatfillinlist (lis) + (cond + ((null lis) "") + (T (strcat + (car (car lis)) + (cond + ((equal (cadar lis) t) "Yes") + ((equal (cadar lis) nil) "No") + (t (sexp-to-str (car (cdr (car lis)))))) + newline + (formatfillinlist (cdr lis)))))) + +(defun survey-complex-form (preface qlist) + (progn + (setq this-level-ctr (+ 1 this-level-ctr)) + (pushnesting "") + (let* ((ans + (formatfillinlist + (fillindata + (cons (list "" preface "" "i" NIL NIL) + (mapcar (quote surv-pkg2) qlist)))))) + (progn + (popnesting) + ans)))) + +(defun ask-question-set (qlist) + (cond + ((null qlist) "") + (T (strcat + (magiceval (car qlist)) + (ask-question-set (cdr qlist)))))) + +(defun qcount (l) + (cond + ((null l) 0) + ((equal (quote survey-branch) (caar l)) + (plus (branchcount (caddar l) 0) + (qcount (cdr l)))) + ((equal (quote survey-complex-form) (car (car l))) + (plus (dcount (magiceval (car (cdr (cdr (car l)))))) + (qcount (cdr l)))) + (T (plus 1 (qcount (cdr l)))))) + +(defun branchcount (l prevmax) + (cond + ((null l) prevmax) + (t (let* ((this (plus 1 (qcount (magiceval (caddr (caddar (magiceval l)))))))) + (cond + ((> this prevmax) this) + (t prevmax)))))) + +(defun dcount (l) + (cond + ((null l) 0) + (T (plus 1 (dcount (cdr l)))))) + +(defun handle-survey (to summarize subject id qlist) + (progn + (init-ctrs) + (setq total-questions (qcount qlist)) + (sendmessage + (cond + (summarize (strcat "\"" to "\" <" summarizer ">")) + (t to)) + nil + subject + (strcat + (cond + (summarize (strcat id newline to newline)) + (t "")) + (ask-question-set qlist)) + NIL + 0 + T))) + +(defun maybe-displaytext (tx) + (cond + ((equal tx NIL) NIL) + ((equal tx "") NIL) + (T (displaytext tx)))) + +; THIS IS THE END OF BOILERPLATE CODE FOR THE RECIPIENTS + +; user-generated part begins here + +(maybe-displaytext + "") +(handle-survey "nsb@greenbush.bellcore.com" T "RSVP NOW!" "nsb.greenbush.bellcore.com.1991.8.17.15.18.4" (quote((SURVEY-BRANCH + "So, can you come to the party?" + (QUOTE + (("Yes, I can come" + "Yes, I can come" + (BRANCH-QUESTION-SET + "Yes, I can come" + (QUOTE + ((SURVEY-INTEGER-ANSWER + "That's great! How many of you do you think will be coming (including yourself)?") + (SURVEY-SHORT-ANSWER + "What kind of *vegetarian* food would you like to bring, if you have any idea?") + ) + ) + ) + ) + ("No, I can't come." + "No, I can't come." + (BRANCH-QUESTION-SET + "No, I can't come." + (QUOTE + ((SURVEY-MULTIPLE-CHOICE + "Aw, that's too bad. Why not?" + (QUOTE + ("I'm busy that day." + "I hate Star Trek." + "I hate you." + "None of the above.") + ) + ) + ) + ) + ) + ) + ("I really don't know." + "I really don't know." + (BRANCH-QUESTION-SET + "I really don't know." + (QUOTE + ((SURVEY-BOOLEAN-ANSWER + "Well, please don't forget to RSVP when you decide, OK?") + ) + ) + ) + ) + ) + ) + ) + ) + )) + + +--Where_No_Man_Has_Gone_Before-- +--Outermost_Trek +MIME-Version: RFC-XXXX +Content-type: audio/basic +Content-transfer-encoding: base64 + +LnNuZAAAACAAAIguAAAAAQAAH0AAAAABAAAAAAAAAAD///////93//////////////////// +//////f/9/////////f39/f37+/37///9/fr6+vr5+/r5+Pn4+fv6+/r6+ff2dnT1dXZ29vd +5+fj6+//9//v///3//dv/2dnXV1dXV1fXVtVVVNVTk5MTU5PTU5XWV1bXV9r//f3/+////f/ +6+///3dfa/93b/d3d/f/5+fr49nZ3d3X3+Pn/29n///3//////f/d2dZUVFPVVVZX1lXWVtX +X11bW1trX2fv49/b19HO0dHNzMzLx8bGwcbDzc3R193X49nf59vn52/r48/T3c/d119jZ9t3 +79/nz99ZT1/jY29X/+tdRm//Z0lLT01PSkNGW0o9SkRrS05FV0A9Q0tVWUlK3/9fV87Zx8/N +2bzd68zBwMv3y8Ldzvf3xsrPyd3HyV3VzF3NTtf3zN/jSt93Tmtf71XrZ11VS+s/b3dLTmfn +91tG3U1N511na+NLym9v19PKwsvZ29P//2PZxs5f78RLQG//TdlTuc9O6//nd13KY1v/2VtC +vUHNO8VKv0dbw0b/SM9T11NIzlvZWb/n1VvK1WNXuv9FvzlPvzrB2UHHXUvEQ/fZRtlPytXO +RWf3P0pZUdvTd8Q9RslGSrg378Q+vb7b91/A1V3/1VvFUUTAW0W+3z+4TU7AzUPPU+93/9s/ +T8K7PEZHRd+4vm/AWUc80znrumvMSWf3vknGvufZtkO5/0fLwj27zz/Asz/C20DV/0FLxS+5 +RkLC20jPwz2//0e8x0LCd0jNzzvT6+vLQUPd1zjjuFc/uD85wU8868A3Y74927s/91ldSFfd +Se9fb3fd1z/f39dI08pHd85AWb3jQcHTT8fOPcnCT0XDz0xj2dFfZ9/F199ryuNfZ0TP/0x3 +PFnr/0lH2/fR0c/I3//jwFfX1ePf0//Z0cbLa8fbvGdjyGtX3+fdd2Pva9ffTufjTu/nY1nn +1Vdr3UvT31Pd/0ld12d391dn61tKb+NPTu9MROtPVUVrQ0lVS0g/b0JI71VbSvdR2U9Z4+/L +22PRyG//3dXfyszM68/Rxu/r293rZ+PLa9tfSOvK12f/Wd3j787bW+9r7//f5/9R60/TydfT +zNfd3crJ2evr387H22Pv2W9X79Vnb2NTZ1dnV91K9+v/513X92drY2d3//9r42P////jb09d +UVdXWVtNTFVMQU5NS0ZRSE5KTUxZV1X373dv39vR1+vf09fP49vf29vvzuNZb2fv2ev3b2ff +5/fR21dn293R63fn59fj619VZ29r487X293Lw9f3Y/dRWXfZ72PKxMPBv8bJxcTLb2d3X1Hr +W1tZ39/d9+ffVWtrU01fY1VP2d/Z1d/v901VSU9XTUk1ODQ8NTxKPDE1QUdCU9/TV2PJ4+tX +V04/StvRz8e3srCvra20uLm731dFPzQ5Oz05PUzjzMXDubq3ubrEyc7rTEdPTzxGS0pD4+9j +P/fTyDVP97hLVf+30W/PrLPO17e4XffP9z9Cb/88SF3I/0zR1dk/T189MTY3LCcrLjIvOE9n +Y8m0rrOura2urq2zsbO2wcK/z993W008Oz04LzU5MjE7QD85VfdfUVPT311r0crj68vG0Xdn +519RQkY8Pjw7ODxJPD9F/99398Syvd22q6y1sqywr6+vsbe1wbvCvdPNy7vJ0ci/v9vLzMXr +21tTS0M8OTcxLC0xLSkqMi4rLTUyMDA5PTY3Pk0/Rkj/X3ffy8TBxL23vLy5t7u+v7y8vr2/ +v73AxL++vLy9vr2/vsO9wcfGxcfIy8jd53dVSkI+PDg3NDg1NjQ4ODw/Q0lPTl9n43fd2dXV +08vV09/j/2tbT0dBRD06OT09PT9ARk1VZ+PZ68vGvr+7uri3tbKwra6tra2ur7O2tr7Fx9Pn +509PTkVAPDw5NzUzOTc3NTg4OTw6PTw8O0I9Pz49Q0Q/P0NLQU5RRP9Xd1XHX87JzcS+vsC/ +uLu9trG0srGvr662rLuytLXLvsPZzyrGrT8zw18zY808X3dVLz9IKD13PjhJPTQ9RzI9SjU4 +PkQ3Rk4/RFFXY1P/93fd58TRv8zExMXBwe+9xb7Iw8nCvMzCucO5vMq7xNu/z+P3a2dFY0tj +Pd82QjpNOlVJQldDTznJP9tBwEjB53fO1TzfvFnVxV9Ny+NVvtFPu8pN379J/0PLTUX3PFN3 +QTzNNE85XUs/Z0k859M+X8lbS8zTScfOv8m1zc68vsC6yr24v/+wU1O00V27XbzVstHO2cw4 +we/n17bP1/drWU5HPjs5LCxBMS01Pzw9Qk1Tzl9jw9VX/9dvQ1k+QFNKQd3M6+O6vMPHv8Vv +2+vP913NWdfP38zVwre9uK6zr62vsre6vHfOPEdHIyY0LyMlRSovPm80QmtOP9HI69HFzffJ +Z0r/RD45Tj5DSudb0dW8vsqusNdIb+M3L0vfQefBsK+wra2tra2tra2tra2yvNPMyF85RM8t +OjM0Ki4qLyg9NSwmO1NfLTnN3TxB09P3TUxIW0Y4MkJANjU/59lryrLvvq2rb0+9zC84X29j +17OvrKysrKysrKysrK23tbiyxGfCw9dDT0o1NDcuLio+KicvNzMtNFc3Ql9LPTxP4zk2UedH +TVNdP0hnWTxB69dNTdPIw8XEub++w2NPV8fO68q0sravra2tra2tra2tra+vtb7Ly9VfPz81 +MjA1Ni4sLi8yMDQ4Nj5DO0JKV2dKTllNWV1OSUdOUVNbb+tnXVFPT0dMTkxZXV3/38jBwry5 +srW1s7G0sbGyt7m5vMK/x8jJ09HT3dXV1ePd09Xj3+P/W1lRT0dFPzs2NzUyMDAzMjA0Nzg4 +Oj4+P05VY/fT083Iwb/AwL2+vsHBw8PBwsDCx8PHy9HT0+f319nT08vLy8bCwL6+u7+/v7/I +zc3T629bV1NKRz9KPkBDPkFHRklVT0xGRT8+PEA9OzhHMj03PTo0RjxGPltbd83nweu+wru8 +ura5u8W7tLzFzLvj09PG/13n/+Ndd19jRUpdX1FO69PbycW3vr+4srq5urW/xsjC1W9nW0dD +PkM5PT07OT09PERGRU1XSExZa01FY01JQkg8Nzk3OTQ8OkM96/d30726vLKtsrWsrrOzsb2+ +wcvbW/dDTUdJPU5BPj5VRU3/5+/ZxrvNvcW8x8rBx9nV3/dPTl9RSl1jb2P3b2dRTkg+Pzs3 +NDI0Mjw6Qj9bU3fj2cnIu8DFvbq6yL++xcXIx9fd2edv53fK11/v481n1cPO1dvTzvf351lX +TWNVU1lbX1dX//9bb2POV2tv70lGR1E/UVNMQE9XZ1VfX2dj1+vT2c/PydO/77/Cv9l3X99f +90pITkE6TVU9Rv/rUW+/uL65scS2trrBzsW4d/9vTmdIS0YvLy83LS8vNTtMTkNCyL3Hyb21 +sryztbSwtrXB08G6xb531edjb0w7RkJJOT9JSFtf50TNd07PUWc67706NddPTzxrTj8vb+dL +Kziw5zA70cHbxbG+w62070jdwDgsQf9DRO++ycC0yf/d/0UxNUs8OFPjwL6zrVWts2M6189E +Lt/ITreusa6trcbGutE9U0hIRUNdb8rjZ1fZZ0k5TVM4P904NcnfMD3FW0xOSE08QzI9UzYt +W0gvOUbOPz/Kz0jrxc5OyLa857u1wdPAt8e8s7S2sK+5vrm3yuPM0U/Xs87Rua/A39XXPjg6 +MTM4NS87QjYvODYuKyoqKy4qKDhIOztvv93Au7eyvrnC18K6w7vItK23ta2trrvFrK5X77a4 +xWvBsb/Cys3C0UE+Nzk3Ki05Oz85StXfWU1ISzouKy0vLCoxPD9FXV3Prb43yrVPRWvfxufJ +us6svbyssd+z0dtfPUM9St1bTbPEz6+7ubXKuszDz9nGz9XOyMXGb9fZ/9s7R2M/MDU1MD0z +NUM+TElFY1NHRkZJRkdX/9fM68bGv8XLv8vIx8nHxMzOwcHJxsHGz8vO99/M33fT/2/fZ1Nb +VVFKR0tDPUU4ODs4MzU7OTlCRUddXWvV2dHKx8K/wry8x768ysfCz9HV2+/v929VU1tIS1dN +SFfvZ3fr/+/d71Vn/29VW93j3c7MysfJyM3O0Wt3b1lOTE5VU11Z/+f/d9nX593b19HTyc7J +vcHKv8bO29V3VV1MUVtXV3dd79fvz87O0cbGy8PHzMrH39H3b2NHSEpAPDs8PDk5OTg4OTU3 +Ojg7PD4+QUNGS0pVW2//49vNz9XO3f/V4//R3dXJxs2/wMjHs+PftrzHxMrFur3Rxr+9xMG8 +y8O5wcXGxcXGxcfdwLpT57lLLbRPLDxdNS42PTAtMjY5LjE7OTQ6SEFASN/3Z9PJzcnIxsbI +xb/Hysi9w8y/v762tbm4ur7Bu8rKyNHbb+/dT09rP0VFOT9MMzpCPj5GQkZNY0BHZ0RHXURA +WUtIT01BU1U9SGNFWU53V07b1ePGvr26ub+3u7y1vbi4vbvBwb/EwL/O68rTz8/jzdHMzt/r +1f/n509ITk89OTo5OTg9Ozw/QkNHQU5VRj5MRkdXa1/nzdnPvtFj28jI7//FzP/Tu85MzLvE +X8LDXcq+x1vBvM9DQEdL39HX08rA011DLy8wLCgqLTVVy7u6sa2xtcs+NDUvLTE3RuO0try2 +s7W1vcfMyclv58nJxLi4sMK+r7vbyt1n1+Nfd0dbTDlVSU1jZ8vN1cb/TONdPzg6VUXfzz0x +SUpPXVtTR1dbOy4uKi42OURTxK6tr7G8x8zvTklPa8zAxc3vwbe8vcDIwr7A3V1PY93vS0/H +v723ubnTX81HKSs0Ly9XRUHdt89LRFVOVU9RR1NNRExLU+fHwl2+v1X/zk5KTm9r2b61vLy5 +1WtbX+v3v73Dv87ZyL3Dxec4LC0817yvsMPRPzIxNDxBW/9ry7S0srfHY1NKOjpEPVnvY19I +PzpERUtANjzZSlFvPDZjR0fL37/HX8HjXbG9vLPVssHTuMjfucnEtruvusjZPiwuLDhJY9HP +U01XvLu7wFEpJCw0za+4vsLDuLXPNCMlMMSsq6u7d0E8QEpd99XJys9dUUk/TlVOU1s4PUpF +R0xVUUxXd8Kzy81Xz05nrK+6u0tLsbu2rMBPPTIuPWdX2Vk5RV1vQTcyLS1N60RLPjA6P0rn +yetZy7q4ra20w626xLm/vrmura2trb1fRT9N2c/P1f9XSUE5MzU4PlVvT1E/Ni8vNjtGRj80 +M0FGSltrQUtLTFdI5+fLwV/v28C1trCzwb6ztb28ur3BubW4srW9z2dfd9Pj28LBv7rH2WNH +1cbbvcNMLCYpKDK4s7vCNiQiIis4Z9FrXUg1OTs4Pz9RUT1JOzxASGdv72NEQ9s8Wb68/7ay +4721vMStrbG3rbi8r7W9sK+yu8DjWcC/xb6/72/Nw9Hv199OSj0/PUJOVf9nM0z/Q0/VTDs4 +QDYsL0lNY9X3Vzs8SDY1OT1Pb+9JNkhjb9drQzc5Sv/369X/X+PDvte+ts7Ps7rEvdXXta+t +s7/I38m0t+NvT0/ny8bO38jLwbrL1+NNV29jV1tFPVH3Tj83Ly44RE7Xt7rTWzYvN1XCvbm0 +xcvXW05GQFFPSl1ZST86PD9LVUlBQVXj2+NnQUBO68DZY11f18rN4+fn3+fF02/Gvr7R/8zP +w7y80cXCyb/HwcPAvc1n/3fnx9XT09fBa0ZBQv++uNFJW8hjPz02Lj1RWz8/a8VfOj0yKC4+ +MyY2yNNCR2/jY2/ra2/Nwr/f28O2tMTHvrCxrrfPtbW+u7O4yMy8vtnEvMTIxMdvR05VRklN +Sjo6PkEzMTs+Ny8vOzYrKiwuLTM2Ny86Sk89PUvRye//ysW/ubq+u7Ovr66xta6tra6wr62v +tby9uLO3vb3By9Pb605fb2ddY1lKS1lfSUdKRU1IST1AOz4/OjYyNDo4Ojk7QEU6QEQ/S0g+ +Q0RJSkxVV09O511NW1dbb1vO2c3Ky7/Dwbq/wcDKwr2/vb62vcC2v7vFwry/vb3Rv8Xnv933 +2f/va/9vT2dZSltITl1CXT9ETD1DQD5OPUJNPkJBNk84QE09QVlLR3dIXXdny2v/y9VvxdXn +wcrHxcbMvsbIt8nDu8XHw8zryt3d79/ZV8tbWWNTU29NX1dOb1v3Z13bX+Pn3e/O18fL2cXj +b8jM/9PPXczVWd/vV2vnUVFXT0FTVUBPWUdNSEVCRD08PDk+PTo9Pzg6Pjs6Pz5ATk5ATFFN +UWdba9vb3dHJx8K/vru3ubWzsbGurq2tra2vr66vr7Cvs7e4u72+w8jM1d3jd1tPS0ZBQT8/ +Pj46NzU0NDIwMDAvLzEuLzEyNTQ4OTk7Pj1AP01TV2Nn99/f19HOy8TFxMfFxsDAwcC9v76+ +v7+/xMC7vLy+vr3DvsbFx8/TzdPd3dn3b2NvXWNTTlFIR0REQ0Q/QUNJS0pdWVtnb+/n///f +d+/r39nn2+vv92dnXVFXWU9XV29dW2dnb+dr99nV29fZ2ePv/29vY//vb//Z793b0dHP1c/T +zdPZ21Xd1SqtrDwjrqwvLa2sNDK4uEkx77rRMWe8VzDTuj4xybtGPN3PY0vn0d93z8jV583H +62fV3VFMS8NdPMjdRtFNz+vrSdm060qxzWutUVWtwziurS6+rHdHsVM/tl9Eb7o+vLsxvb5I +ML3rQD9v7z5H0T8uP7czNEXXPjw5XVEtR10tR+9VPTXv9znZdzeuWzbOu293xe/ZvMHPvky/ +rbxF562t6zStr0i+rsbOta3vzbews+tJurTJyELOtF0409dE71tALU68NShCuzUqMuM9Lz0+ +LTZdQyksRWcyKS/X5ysv004ySt06Q8q2Vz7DrsFD3bmv3cy3t823ssNfwK22Z8W0r9v3vLdr +0bvFW8i8vFd3urnZUb2832PN2Vdbzuc8Qs3jPDVG31kuQu9HOktXNTx3WT49T9NZNFVvTmdv +VffO0+9vzsTL3dHCx8nNwL3GxbrFzr6/083HwMpva8lvV2NNTGNXPj5LV05CTmfvSz5Db0s4 +OktCOjg8Ozg+STc8X99ZR1fCx0nPssvZvLvA472vv/+/ucbrb9nDV+vFzcm8u7i6trK4yMHB +z0s/Tk43O0I3RXdvW2/Kw8jd28/ja1s9OD09PTUuQD80OV9LTkv3yf9nytffy8bGxsu/vs7N +wr/Dxu/f0dlrWdfJ71Nj9/9MR1VFNzxLRTE4TVc8P2/PUWPI0WPvxsf3Y7i51/e/usTVxL/H +xbm7v7+/vMnOwcXj1d3r70xVZ01XUU1ZU0FPSzo8T0k2NUtvQzRATEk+TW9MRVtdTElPV9vP +62v3u77ZybzFzsPDvri5t7S+xbi568e93UVPvtk6SsDrT0TMu01CyE4vNk8/MThjVTo9X9tA +PURPNzRESTo/WWdHP0rXTkFFystMa8fXT83H11/Zsr7XurG5xLe1vt+8tr/BtLrVwbeyv9u6 +tttZxtlTQd13OD1jTTE3SkgtL0k4MThHPj0/21VI3brX/8fAxN3Xw0k4Tu9KSv+4u99OU2NK +My9LTUVd/1n/287d3b28zc7j/9tVP+fFw2fNu79vx7rAwsvFxMzjwc3vyL/C09vNzNPbXWfv +Q0dCPD8/Q0ZRU+9VRGvv51VV9+9FS1dHSVX302NX9z01PEU8PkJZ51lDY1tKTd/b487d6+/N +x77HvLi5vr++v7y9z8nEvMfByb7FzczL111KU2NDV9lKTOfvSE9NTv/nY01Z23dV3+fvxMhn +Z0RG3WNHX1fja0RGV0k6S09XQz7JWz5T/0VJRj9ZSV3RX0pbb3dTSs9348HOY8O/vMVTy7bT +v8PXvrvJ6/fZv8zn09W0tsbNus/GxmdVY+vvQkdvdzs2OTw3Nzs8Nz4/NjZTP0FnSmvnV9Pb +0+tn28ZKW8fna+fPzk//wNfj/9m9vsrKub/Gu7q8vL23uOPIvsfj48bBzN/L1efMTErI1UhT +710/PU1OQVlrTzs4PkQvPFFAPUJBQ0A0QFdB//9rRllv1VFNX9XM1c3Nwc7GxtXZysnv67y5 +yFfO393O009vy/9v5+vn3dNNSdPHTU/300o+Y29NZ8znVc7L61PR22fd49vJt8zj78G9yc25 +vdHIvs1rY89v486/10rn60xJ3e9JTk1MOzlAOjw2PFFbOD1AQk02Nj5CVWddV1lbZ2NP92/G +zePGvbzK1cvK2efHyMXLw8rbyr/Nd+/nyHd323fT2993/3fb1UxZb9tPT1vT3Vdrb1dT9+dr +X2vTTVPT90ZJR0VTR1NMX9fvV1VZSUpvd1//z8PXTOvN79vN0cLA6+//Y29na2vLxMfV09v/ +d/fPzMnV0ePr319KV93P91vb7/dnTGNjd+/f58rG119T705dV0lN30o9SllMRk5ORT1n60Vd +9106S19bSVvV09PT23fPx8rC3c3Ly9fJb+u/29vHxs7My/9Nb9dfa2fd18rZ/2tv3XfXX2/Z +TmfnV1ffV/dvS1lVT05ARW9NZ29NzNlOSlFd301HW1lb/8//WdnVa1tr92d3/99j/8jfb99d +/83P38/Z093/0ef319Pfy8Z368/nWUdNd2f/6+dda/f/909Pd9/ja+Pn19POb+ffa+tXX3ff +a//X61Fjd2tXSktbWU53d1VZ987b49X3/83Za3fVwb7vZ+fd591ja+Pn629dP11dT0n3d0pO +Z2tKb813W+trb9Pf/+Pd12/j31frzNX/z9HbY13r4/dTWfdvTm9ZSFld2/dbXXdbUWdd/1XL +xltX1+9v79fH0d/O/9ffb9X/SnfdXev/28//6+fn2+/rz29f1c13/+9r39Hv2eP/42fnWVNZ +Y2NZW1vr1d3/b99nWf9d99HLysXK1efV31Xj12tX2d3/Z2dXSE5ZTE1FR1FXTU9HTElTY0hG +Ue9bWU5dd193/9nf19Hnb/fv99HZ79PV2dXXb+/j58nL08rV18PH08rG173JzsnO28vCxcvZ +ztfvT2df7+tMSEJHW1NLSUxZVU9JRUtVTU5RX2P/VUdf31tf71tbb29VWVFMd1FKS11bSEtZ +X1djU1Pn/1tr52f309n30e/v0dfryc/VzsnH093P2dnMy87OysHHwb7Cvb6/ysTGzMvd59/d +3dn/X91fa1tVU1dvZ3ddT1dRT0JAP0tPRj9ETVdOTUpISltTSEVET1dbU19XSl9ZSkhFTUlb +WVn36+fTze/XxM7b18rIwr/GwcK/vrvEz8nNy2//W1VjV19ja1tTW1Nfa+//b/f3//9vb19V +Y9vf3//v59nj49Xf28/P4+vX3d/fa/f359nj/1tjX1tbUVf349nr19fV19X///9db2tXVU9H +P0E+RUVKS0lMUU5dTEj3d3fr3etrW2/nXVdd29nja+/n5+vn38932dPXzs7N287f1dvPyNHM +09Xr92dj4+fv4/d39193XVtdX2/f/19v5+drZ/9v599j9+f/z8zOx8rDycvOx8nLyMnHytPr +5+tnVV9jWVNZW09KQT9FRzw+Pj5ERUpOTVlLUV9JQ0pNSUlLTVVbTlln//93Y19ZY+ddZ+/b +y9XV08rH19/b59XKyMLEzsXKy8jNzNfn193R5+vRy8fEw8TDwcbDxNHj393Vzszb/29ZV2Nd +UVlNVU9TVU1NSUtKSkVIRkRHR1dbXVVOR0tfSUhNPkJRU01NU19rd/fv/1dv3dfOyMjLy8vf +293j59XR09vf2d3Z083OyM3PxM3My87Jzs7Nz9nf9+/j0etja2NjZ11ZUVdJT0pVU0pOSERD +P0NHSUZCSUpNSUZLS1drZ+vn783MzdPPzszN0dPJ0+fO3W/r09fV3+fPyM7b2/fV1dVv19PP +zutZV2d3Z2tra2drV1tfW1lTUWNv39ndTln3W1lXSVFjY93Z7//FyM7n9+/V52N3a+vRzMvf +29XV1eN32dXP2dP349/j43dTXV9bQ05GQ0tMV09RT11bR0JMTkxbT05MW/fb2/dv5+fO29/d +zM3PzM/R1+dj39Hj1+dbV3dfWVVn69/r52ddT13X0+Nn59vZztXrX9vR291v3+9v09Hfa1/v +42dV2ePfY/9ZW+PR0+tb3dfn499jV+vvb3dnd+N3b9fZ71VET09da1lOUUtXT0xNSFtbX1lb +Y2f/X//NwcjMz2/fybzI0dXPz8rjVV1r485PR0tVXVtJRU9jZ+t3W+/n411jb+vZ1+NrZ9vO +011MTmfr2c/Tzcvb32/j3+fV0cnFzdlv41dX91tKWWv/409JU1t33+tNT0RGUVtX/+tKSERH +SVtRWV9La89fU8/H1dvX39/rxLm958C6v7W90f/RwsLfW9nNydH352/DzF1nSlXTa0JNSERH +Pjw2O/9XSDtO29NTPEFHV93/V0Nb91NbS0JRXcfCy8Xn38rv577N09fPzc7LZ93Rx8HKvb7L +39nn18bK/+dvd9/N3VdRWUhDUTs4d0xNu1syMjBVzlVJWd/GwNk/MjxOwbxMS0/T07rHb7C/ +69lVPtGuvciwwk6+9z5ESOPIXzRRvv9vSzw+47+/zltFx81bw9lJT79RMT9fRmtTU9VZMdfb +PES5az/F51m7vM7byOvGvVXjv2fXzTj32UfdTUU/Rt9DOV09Y+NMvj882///Oj3HVdfZS01b +wbnjd8RbvbzB00mssuuvT0+us7/bQsy7vF3bz0xNtmMxyL430esy68frWWc9PlVTMVfKK10/ +MEhrNjLvNTjLSzV3wDdXzWdjwlvGMa1bvuM/vt/IzetXvs3HwkC32V3V1z9X177LyddMd99j +ylNrPMnd7/9rZ1XIxUlrY7tbv+c8tcvPY9nJT8a8PUi5U8q9XW//zuPHPkxTvEo4uTk40U9N +P0Q7W7cyM2ddSf9vMzm6z0tOQC21sDxjyUjHusw8Ubi3ur03Nq3DUUhO3bC6ySVA9+vF5z7J +vkz/zT5fW7xVRMNIPcxrOsDE3UxZRk9VV0pb10hKZ2vXQ1PIyLi8PFu3x3exzFe7xL7GycFT +y7Tdzbo3QKzNML3MMj9KZ76vvzNn5yMnQC48trzfvr5NTOf/yr5EO85fz77BXVu0zVFLJz6v +3y7T22vKti8luq1ET7Ur1a33Kz63rTw+RStLvNs3R99fd71FObGuW7/rMretvD08vbdd6+/P +r8ROYzpOYz5RvrisrLO5999fNEzvRMEyR7g7X73bLy1A2yN3rc05P7W2NyoyNrOuv8vZtbLN +Ozg+b9dvPjr/tb/rZ8XKyb7GRU7Nxzorx8ZRQVlCOkjJ4ztX389rSC5RtLfDvb69xOfOx8zF +LjzDubtjTz4qLT9VPV2urbmvu1Pjz++8dz7f0b671W/Mw7rZNzc0NDs3Ki1HZ99jPEVdTEdd +Rl29s73PTV24trrHx7y0sdfVV1PL2UosOuPJzkQrO7RXOTZLuqyuua+4tbfDyLzZ98XNyMvI +41tBOjkzNC4zMCstMjg3OT5DSkI6ODhHwL7C51drzdPIvsW0wri7wLq8zv9fSbq/07ndUXdj +WbO3y7W6ta+str7BXdfXX+fd2//VO09fSVc9LS82Li0uKzA2LiosLzc+S1XrzevAy8e7ybe3 +u766trOxw8PN49nVWV9rUe9ORknf3VfPV0/Pyc+2ub6zwbm/v8e7vtfZUVNHTU8zRTo1Pj47 +N0A1MSswOjQxLjE4QVVn3by2rqysrKysrKysrKyur6++xc/jTF08MTEpKiktLygsMi89P1c/ +19HIvbyxs7mvvb/Husu/zedfUV9ITUVOQkk+Qz85Pj41RUVGREM/TWPdwb+2rq6tra2tra2t +rbKyu73DyF9PQTg5LCwrLCwtKiowLTQ7PkZbW9nFu7itra2trbK0sbjBzP9JPT43Oj0/PDY+ +OUBDRUA6PTQ5NTE+PDw+QUlvwrmtq6ysraysrKysrKyytriysrS/70w/ODYuLSwnJCQmLDE2 +QEDdXfe/uq+trrevsLOvuLC7w8/dTz5CNTIuKiYnKCkrKiovMTM9U2PLxcG6uK6tra2tubm0 +uLOwtLa4vbq3uLW2ur7Fvbe5wru+w8xbY1P3V000MCwrKikoIyMjIyQrMD1NTmfZxLWurK2s +ubm5uLOzv8PO1ePN29PvVzkxLi8xMjIuMjU9Rv/bxry2raysrK2tra2trrG2ur7R51tFPjkv +KCkpKCYnKycqLTY+TN3r07uvuLKtrq2tsLCurbG0ucHDd01KQDYyLiwzLi81NzU6P0JPU0pR +V11d493PxsfGybyxtrq/w8PHzMzO39fEa7+0v1nn1cnNwL3AxcO9td9vd9fPXU9C3W9DNDA0 +KyMjKDI3OFHFwrm7sa++y8a/tr7CvLKusK+ytsfbTDstIyIiIiIiIycvOm/Py9vDtq2trq+t +ra+xubu/tri5zOvN50Y7KigvLCwxODpE58Wxuresq7K8u864xN22s7y3vc+1vPdJPC8sKCQu +PjA6TkVCQ0rrTTMvLjsvOUtnzri1sbbAvLHC513fwN3/ydfBvrq3xru2v7u6tcHfX1dVWUJL +RTZAY/80MkdINS4jKCowLCpCZ7vBrbaurbS3t77rw8O7vrmzra+ttb66ylc9LiojKSclKy0q +Nkb/vK+sq6usrK6wwN/J70VRQe/r/1NrTGc3OSszNikkJC42PTlRwK6svq+svqyuvsy/u7TI +0bTfu8JJTFFLYzguOCwzOCg6SDJAP0bb693FyK24u768s7PE0d3Xz/fFuLjVtLnHrbi/urS6 +28/Ryf/rTEvCzDk3LzM7KSMvYyszSSw/40Qv98pbUTf3WdPKTcKzu7OyvbW9x7/nzUdKPuc4 +MWPrX1m9ucF3wj9M3SlBOydFxVPjZ7z/xq3VvaznS61DzUGxRi6tuzS5X8RZ374o3UEryy8z +xlPARdnFStG0M7XLO8JfQLjvX7o/z7stu0g1vzs33zRBWyu9NbhHT641rkwvrkd3tC6xwePf +sz9vrCesKzmsM7yxNqw2Ub++PMvKNawurj/FSLY0tOc51U02v0I81TXJQ+suvi7B0zPbYy++ +Tz+tONW9QNe6Mm+xL61nN60sb602tK4+tWdBrS+/xi3MySyuNmc/QD3jN7Uqryxf4zW9TTuv +LcrBP607xa4yrev/rz66zkfj2z/EyU3Ru8rT68zKRMPOSc///z/rW0xKOcs6W+s7V9NOZ8Y2 +a9E9b0VPV13JyUy/U/fTxsi5PK09u8PJua1dsNXKvOfCPve/Mbc7/1n3Sdk21180xTczvyxn +1yq/My/ZMdVKM8MyN78tV1szxDJbuS2/VT3dw8ay77TLxa7Hxq13rcC9sLdbrT+t2V2yY7yy +/7xfw9vjPMRZRVHF00PEd1HNS85bTevMOLg4Sc8w9zA6UzlENk88QEkzUz9nNMlH389K20bH +d120R8K7NbfTP67nVbQvTrQvsUDXV7FAtV/PvNVHsDbLy0nFPMRVY9tHxTg/vy3KPD/rxDa2 +MN9ZZ0S4QblGu9fKXVvTSdvj1T65RuPGb0u6OrxPd3fnX/dV5022W9W9QbRPxWOvQLrAwL7O +y8i8PL1LtEPXV7k7xDjCO3fO4zq+PlnRREPXO88vQ0jrNmc9Y009RUkvuTRHdzpLPMY5TVnN +VT21U9XXyGu34768xneyXcLIv0a6P7nV18JXukTvtj/MS89BuFtLv1PZW9tR091CyldDvj3B +O9XPS9vKOsc7xz1jzTjTUePdVc8/skG7Mt3vb9k/uzq0U9/FQ9tB2c80uzu3OrtLzO/XVdlL +PMVE107HSl9r3WM9W2dJyzGwLr7ZRtF360++SuPf40PjX0rD3z26QcNIvz+9Qe+7O8LvVbk0 +tfddyNndb0C9VbtVxW/TX09TVUhJ70VXY009a1lH/0rTTfe/yPfD47tnxb+/z7fA2bLTXbVX +u0m/ScDOY9XOV1fNPms+azTPPTpfOT9FMFs9zzdJQu8+90VfWfc32TjRWW9vV9dv/2u/TblN +yEK+90K6PLhNxM5DuetVvefbTLjvw+O7zve6v0fDVchOtD+/013CM68wska9T8+/QM5HSc1R +711GzULKNboqzjvjTi+5Mt1vX0FK40ZX68pfXbtE28fKTsfdZ1XLVePN0zvX91M6wkxOPbg5 +RMI/zWO9SrnDxNXvvlG02f+tWbhPvd/fs0i80bpGw79Iv0vXQE9nMMs8QDZbPUlGMV9ESjnr +TUVKWzz/70dv28NMzNtFvl/Z49fFXchvWefRa1XFVdlXulXTvc/Rzs3jwc7RyMzIwcTNv8jd +yMm/19Pf6+dnS2/nTGtPQFlFRz9DPjg6PjxCQEJJSmNM30Z3a2dM7+ffR9/X21m81dPLz83I +vVnTxM9O3cpTxV9nUbxvU9PvSXdVX0bfR+vZZ8M/vVPNTb8+698+/1e/POvJ28PEuc23612+ +SGM2TD1L9zPFycK/w6zjrLGu17RBz0dVIy0vLykzMDk/Sjc9Zz48Ok1OZ87NraysrKysrK2t +usNROSYnIiIiIiMpLjVGu6+srK2tra2tr8PXXz0xMS8/SUbfv763vK/Gv8ZGL1NELytBOE9V +38mxr7q6rb3Bzrj/t8bHtbOzu7CzvMDXT0Y0JiIkIyMjIyMjJis5WcK9rKusrKyssrK0wsnn +38bbwevEuN9nusrXwkdTzM45Pci+Qbq7tbi1zsW541lO10ZL5+vDvLq9t7W+y9tRNCwnIyIi +IiIiIiMkKzRLa7Szra2tra2tra+zvv9n31tRTVv/d//n12PXxc/Da8zLv9X31b/G18zByb7K +xMK/w7/Gv8TGzt/O0Wd33VVrSk0/PTsxLSwqKCkpLCosLzEyPVXXyLazr6ysrayusrjBz85T +Qz44OTc2NzdHRFNd3f/PvcTn08C9vcG0r7Cysbi0ubnI519ZOjo1OzxHTVn/b13vRU9FPS8u +Ly4rMDA5QFdb/768tbezrbKvs7Kzt7m8v83Pzd3//1lIR0M/NDIyNCwvMTYzNz1GWU9j1b66 +vbGzrrK1tbq9vdfnY2tOSUlBRklBREFOPEg/TEJMTEljd9XPvbm3t6+1trW5u7zBxsLD1b/J +vsvH5/fnT0lJOjcvKykoJyUnKCsrLzc7OUz3/09v0cnPu7q2trW2tLy1ub3Cw87N/+tv6+vd +59HjysLOyb61ysvAv+/3zMzZx8nHwcnFys7Bwcy9x7/J09Nra04+Pzo1NC8uLSkoKSYjJywp +KTA6OjZT2dV3u7extqysrK6tsbnFvshvZ+/rX+vIzMzEwcTOwc3IzHfdvtXv1c/KZ9e/07+5 +u8DEzNNXV11fS1dn51lTXV88PjwwLSwuKSgpKyskLio0NUZV983Nx825tba8sqystK2vrLO4 +xcPO90xIUUJFV0hn39HTzsXCzdnEU9W/3+drzOtP08DAt7Kys7y9u9l36+vfT2fC0V9r3Ugz +OTwuKjAsJigtKiMsNjA9StPvW8+7xc3Auq+/r66vsrnAxW9RQzo2OTg9PUNZ5+fKyMHF09vj +TT7V31E+U+tPZ8m7t66sraysrLm3r661sK2tsK6vvc3TVzcvNSwlIickIyMqKC47REJLY8xT +0e/AxcPBtbi1wr/dXz88NDQuNDA2OEZVU9HNxtXRzv9R281JQf/XXee3uryysbm6sba2sq2u +rq2tra2vsLzLZ04/NDEvKSYmKCIrLjgqPEFLPVnO3dO/urO9s7u9ys1jRj0/PDg9P0FDTExj +TvdTTU1DRztPPktMUd3jy8W6s720uru4urK0rrGtra2tra2vtL3L3Vs+OzsvLyouKjcsPjlE +PktbRkbv3dvjtLm8ubG7xtv/QDswMi8tLjQ1NkBFTD9LPjw5OzkzO0s/R9fIxL+usrGurbKx +sK+xrK2srKysrKyzt7jMSm9INi80KyosLywwP0M+S9dVR2/v/9fGvLq0tLW7vtPbTUU7PDM1 +NDU0PTpGPkxISz0+PT41QUdFRc3XyL2vt7Wvr7aysra4sLWztK61r7m3zM9OSDUwLiwrKist +LjA3QUBXTtXI0d/Fv8m/t6+zrayttLa82U9JPjMxNTQ3NUU/TUxXR05EPTs7MzpERUlf08zN +ubnAvLS5xrO3u7qvr7GzsbG4wr7NWzU1NTUmJzA1KzI7Ty493/9BRr3rd8qusruura28uLTM +T013RDNEU0g/V91TR0dXOTI5MzAyPjZB3eNNb7rZzbq3vMO2vMW8uLq2rbK1ubG6x9FZSjIz +LDE0LDQ5PDJNRVNOwsDvu7u4xrKsxrfIrMPGtrvDyV9bMzQtMCktLTgwOU/nX8zrzkxXQ0M/ +PTpJREjKtnf3v7nv17Szvr21usK7uMC1rbTIuL7Rd01JMi4tKjEqKj0yOT0u32NB48S+wL+t +u8awr7fKvLPHY73B3V9r7zw2QDgzMTc/PEDr38/DwdVj3e88QUlAPDw0VbxrW86vvdG/rF+u +vbivwa25ra25vMDrxkItyy8pVzw0KS9HNyZEPC8yukPGz7evSrmw289Zvchb27lnudPrdzVJ +NSs0NzJBT/fP57i93dtXRzg3OTw1S19T666sw7Wsrry4tb63srG1rKyysLG2y1dPSDsuLC4w +Ky8+LSg2NzUuOltBRsHT67muu8HBs8LOws7Nyr6+yL6+y29VSjs8PDk8REZn3dvX4+drUUU+ +OTo6Oz1BQUlj19PbwcS/tra4tK+ur7Czub6/yf9nW0A+PjgwMS8uKy8rLTE2Nj5DT+PT08e9 +vb6/vL68tbW0r6+wr661ubi8ydHP3+/bb1tbWU9KTUxDRkhKSEpNS0pNRkFMSkVJTkpJW2/3 +48rHxMDGycbIztfXd1tXSz06OjIuLy8sLi4vLzY7P07v18S7srGwra2tra2tra6ur7O4ur/L +1e9LQkE7NDI0NTQ4OjtBTFdXX/9fX19KVVFCQ0lGRGPd2cm8uLu1sri4tbm+v73Izc7VW1VR +PTo8OzM1MzIuMTU0QUh30cS7s7Cvrq2vsK6vtrW1vsfGz+dnX0w/OjYtKyooKSkpLC41O0BT +Z9fOy77Fvbm9x8fK39fRz9PGv8XFwcvKxcPTycjJzsvK693bZ01ZV0VAQjsvNDMuMT47SVnv +1cy8urWzsa6ura2vtbW3u73Cw9vvXUM5NC8uLC8tLjQ8PUJVY93PzcjRvsLR0+9jTF9bTevR +y9HJy9nLzcvZzcrTycvR5+NvT0pIPz86NjAvLi0sLS41PUhP78e8uLSvr62tra2tra2tr7O3 +vsHLY089NjMsLCwsLS4zOD1ESuv/09PFytPN79lH72/32dXFu7+8vrvCv8a8wMHCvcvV09tP +U3c/PEA6MisuKyorLTE4UVXvzbi8tq+trKysrKysrq+0t7zI4/dbPjUzLysuLi0tODc6Ql1X +WePJz9vT71lrb0gwxb1B2f//tcHbu8+6tcGxvLmvvcnTz8vZZ1E3Pz0uJyQkJi8xKzJHY2/B +zbWtrKysrKurq6ysurO6xGdTPTg9NzEwNTU4Oz00N0BAN2dZRT1KTVPvxtHKtrb/99Vn9+/3 +27Gur62urLC4v9VHyT8vPDxILygpJC9CRiw0U0H/TDhfra2urbmtra2tt7TBx8VnNTpLX1tV +PUJrz0hCPjdDQDzn/0dLY2fd583BvrrfPT1BY+/398ivsK+1trm8tu/v3/dbPkFGPCsvKzXV +PztVN0BOMUqytcG0t7y1r6y8y7z/b2tdQkdf109FY0pnTzM4Nzg6TlVdQ0FE/7/Bxbm6zutv +b+fXtrjIuK+tsrq9vt9fZ0pJW0Y5Ni87My9nOiw9Y1M7PsO7wsm9v761rq26ur9rP0pZT1VV +42/bzspdS0E1ODg6OkZRTEpMZ2fPvrvAy2tb68nDu7Ozs7Ctra6yurzKXV1bVUAxLiooLi8t +MS8wMjM7R0tv0cvCvLi0uLe4wsXI0efTd11NSUdDRUFDU1/3TmPr3ePX029vWd/f0dPT92Nr +XdnPzs7L1dPGwbq4tLW1t7a3ubrB1WNKPUJANzUrLSwrKisyNzs3O03/zMC1s7a3tLS0tbq8 +xtNjV1NOSEY8Ojo6RE1PUVlnWUhGTVtjX1dOV1Pfzce/vbu3t7azr62ws7i7vb7IzutfQDky +LS4uKS4tKTAwNEhFY9nGvLyzra2tra2ur7G5usrbV0U8NC8vLi8tLS8vMzg6R0tT/2dv2+PV +ysfOxcfNwr++urq5t7a1sK+urrC0try9v9XZX0Y9ODAtLCoqKissMDI5Rknr1cC7tLK0r6+x +sbK8vsLZY19HOzoyLy4tLi4xMTc5P0pba9fIw8PHys3Nys7JyNnTysvNv8PBuru6t7a1srS2 +ub2/xMnVa2NLPTg0MTAtLi0uLzI3PUROW9nKvrm1sbK1srS4urrI28NIQD4+NTczMTEwMjM7 +PkVPXe/ZzMS/ur3CvcHMx8bXzcnT1dPV29PGxcXFx8PEv8TBwMPHzdfrX01JPjg3MTAuLi0u +Li8vMzk9Q0xd287Evbm7ubi6urq6vb7D1ed3V0hKR0dJR0ZMV13n1czCv7u5t7e5u7y9w8fX +2/djSktJSz/3JNW4TEkqTLO8/+fPysnRzN/f61lLPD5NPDw/PDs1Ozo4Mjk+RUhd3c/Hv7y4 +tLCsrLG+yce7u7nD11NJQD9IRUE/PTY3SVnZ3dnbycm/wsPPW1dXUUxBOz1AR2fHv7/Bwb++ +vr7GyWtn52ddT0VDSllbR0Q8Oz5AP0JFVWtNW+vEvby7urq4usPJyMrVSz06Sd3Kz+d3a/9j +W1VJQDs8RlN35+//08vAv8jTXUs9S1tPPjk5R9W7s7G0uLe4ur7OX1lOVV9bU1djZ1lbWU9H +RD4+PT1BPT1IW1lVXdPHuri1usn/18jH1Ug8Ru/Dwszr/9/n52dORTo0Nz9TX2Nba82+vL/O +519FQFNnSzsvTN+6s66vrq2srrjCzdv/VUxPRkVZX0w/QkpTTUk9NThATUs6PVN3y9fTxrq3 +ub3Fz9/r0eNLPUld99nIy9vf2e9ZR0Q+ODQ1OkRRX2/Rx8HDxdHfYz9HX1s9OD13wrm0srCt +ra28yMrM3VVHQ0ZKT05APD1LS09IPDdMWUE2O03RzGNZY8+1srrLyMDD5/fJx+9V793NycfH +09vb31lERj88Oj9DSk1b59fn2dlr/1tITW9HP0hfz7y2sLC0sq+3vr6/wc/Z419XW11AODg7 +PDw8OjM0PTw3OkRGR09n59HAt7vAwsHAu8XZ2d3VzMfFwMLMzs/nWVdJQT8+PDs9P1FZXWvb +729nX1lKPUffY0dHXdvOxrq3vbmvr7e4uLzAx8/Z729j71NJSFVMQT1BPTo5PDo8PT9RWVVO +58/T0czN3fdf0cxfU+Pn4+PT193359/3T09RSz8/REZHVWvr79HJxcjNysbN0cvV08TKzdfL +x8rIv76+wL++v8LHzdHd2ddvV0lLR0I/NzY0MzQ1NDY6P0VLUVtfd+/d19PTz8rExsXFw8O/ +xMnHy87Tztff619PTEdKTUxKS05VVVVPVVVZU11rX2/33dnP68rRyMnOz9PX083Jz83T19nO +0dvj929nX2NXUU9LT0xMTUtPUVNPT09NUUlKTUtTT2dd/9nOycvGwb68vL2/wMTByMzR23dn +TkVJRT8/QEA+PkFAQEdLV2v/1czFxb/Cv7/Ew8PFx8TIztXX19vd9+//7293X11nZ2tnW1VV +T0hFRUlDPz8/P0E+PkA/P0ZKV2dv4+vR0c7PzcjBwcC+vr29v77AvsbNztvjd11dT09HTEhM +SEZJTU1LTlFVVWfd19HPzcTCv76+wcTEy8zOzOvf42fjX2NTV1VVT09NTUpMRkxGSE1JT1FV +UVFPVVdOTkpMTUxLTlFbXW9rd3fn59vT0c/RycXBwcHBv77BxcHBx8jOyNHV29vd/29ZVUpK +R0VDREhHS05TXW/n09HOysbIxcjJy8/Tz9XT/2f/V2NXTldXS1dPT05NT01IR0dGRkdLQ0ZD +Q0dJS09bXWN379fPzcbIxcbCv8PCw7+/wcDEwsHIyszP0fdvZ3dfS01KSkVKSERCRkZGSk5T +TlNNT1ldb/fbzszIzMjIxMjFw8fIy83Z2eNjUU9TTU5MSUpHSElCSkpHV2d3d+/n6+fj5+/j +/+//d//j39fb0cvNz8rJx8LCxMfGxcnGys/Ozd3f4+NjWV1RR0dGRj9EPjw+Pzw5PDs8P0RG +TFddU193///n39nRz87OxsfGysfM19nduTQ9rL0lPqw6P63OQcJrRcTnOee6PWe16z+6ukhr +uchK3cpn99VZV9vZV3fD91nKyu/Iz3fX1Wfn13dv0+dX1cxF38dnQWtVPkZXPj9dRzxFRzxM +STk8Q0o9P1tHTs/r78TBwLvCwLi+xsbC32e/yk3CxUe9vUfd1d/b38rTb9m/RVtbxU41Qm9N +NUs4a2M72URGvtdRyNXPvlvfxNf3zuvLzcvN/87I29lb3evbVUpX701GS0dTU0RAQ05PRUxb +a+/X0dXOxr3X473BTcNO28TvRs7GTsHbyL+7utnCv9nVWWdBP04wNTQ+LTo7PNs230fjW1Xv +QWdNz01ZzE7E68G+wrzFvb2/zdPA58nJ113n1UVTRjs7Pjo3PDtFSkpX3cO+xLm5uLS5xbq7 +//9Za+PZzNW+sr68tse7w7/Fd29PU0M6QUZVMURNPDE2TjswRDs9QVM+Ud1TXc7Za8HF09vH +z87O92/j/9NDX09d/0FnPVk/PEY7TjrvXc69z7rByLa51f/PW1/fTU5d67rNRbDFtsC82bjA +N7gyrkU0rS65vz+8ONFCSzs9XzjbPk7vV9VPz8n/uMvCvcLJ48/Rd9NKb1HbT0r/V3dXS1dL +WzpFRUhHXz5n929jX8VvZ7hLY///OtNON79Eb75NvTe1rS+sPUu3Sbw7sV1v2edNW8I1Vc07 +Y01JUzLMMkfRP+9PyVPIS2/VTcBjSb4971u/5zm2SLs8tTeu2d3F3bjV48V3zcLAyNXJa7RO +u1O808nPXbZGu0O7QUe4RDW4L8tHZ18yzUk3Y/85ty+5Ns2/NMvPLbY0zzpMTDvbvjfr5zvj +Z09VWedTTcU8yjWtMrvFP7hLd7/du75dtUTFPNm9S1XDO7itLa0rTbUvrDG7ObzEO79BPLYu +rjbJazu2PlW7Lq850bsurjS00UC8Tj+5OLZIV8I1w0XnTz3AN8LPMK4vRb5Lu9dRyUPPZ9td +RfdJzkhJ43c/uji0OFm0LrAvtzS878tdU8RvUbsvrje3vj+0OK5IxcJCskS3/z2yU83B3U/f +vf9byj23P8rLQspOd0pjP2s5zU5GzT/NP91K30xGzDjr1TTP529G21PnU2NHR+dCvNtHxj6u +McFfW8nVzMz3utlT18pXyMpPxT5vwjmxR0+9P+vDS7/XXbtO/7hfz64urDg2rFnjsTuvb0+u +U3fTRdV3NP9TP7pBVd0860tZ69s4vj0yvi22TU7XTkrLQkK9Ql/EOlu9ObxNR68vXbhM2blI +ulu+1+/Zxv/M2dVZvVPP485dOsF3ObpTV0PPUz7vW0n/Re9Ld+tb/8E/zsJj3993zF9r33dK +51l3/z3ZyTPd10RvTtFbTt9NV1tf59d3d9nKd9XVy83Zv8vTwMDnwc++w2vEzNPj0+vn72vX +a2/nY+fnT89Ma/db/1Nf/0VfX1dbSN9XT1FjVU1vSmtOX1lrW1tZWU1ZTFtOUVtPSlNPV01b +VVtXWXdb71Nr6/f373fdY3fR/9HX18fZzNPR1c7b09fjz9fbytPGz83Pzt/L39fZ59X/zt3V +y9fK08vR08rXz9HV2+Pd6+fva2ddXVtMWUlMSkhJQEtEP0pDSUpFU1VLY0v3Uf9OZ1lRb09b +/1vr/9fv1+fd3+/d5+vZ79vj29nV29nd7+fd99l35+dv5/fr92v/Y+9f/2tn41vn929r713/ +d293W+93d+v34/fZd9v/69nv59X/0fff3dnj39nr3edr33fj9+dvY2tra2//9+fb5+vf3+Pj +293b09nd59/jb/9rb2dX91NfV01PSUhPSk5JUUlOUURXRVNRV11VY29rd+/r6+Pv6//392f/ +393Z2dHZzt/N19HX0dfZ2c/b18/Pzs/O19PZ49tr72db51n3W+9jd2dbXVdfVV9Xa1N3WW9v +d2v/7+tvb/dj62v/b/f/39/d2dHRys/O09PO68/Xa9XM21Fv0dfvZ9/3VVln3VlG511VU01f +U1FRY1NNUV1vQ0xOTUtR/09ZWV9ra/fv52dv783b9/fb19Xn1dnv0dPNb93Dy2tRzu9n4/9v +Sl3d31nv229ra19bTe9vZ9VTSVnf1WPZ79/fzdnI2cnJzdu4tlNN2b7CWevn31u7ykFJyLd3 +SV9Bvb9IOUZXzdfPQzLNs0JHbztbvko4PU3V7+c4OufBVz5L51t3zDlOZ19PzOc0Y8vO6+tf +xMfCb87BwL1rx8Ovul/Zv7iwvUpTvsvE01M3PN/Pazs6O0XGVTMuOG9dOC45R01NRTw6WdFd +WVnr2dHMw9vf38avw//fua2w2Wu7sL13zsnHx79XWdvKz87rd1nZysn/Y+/bz/9ZVUlI79/3 +R0tO59XvU0pXb1NBODtCPzw6PUVOUXdNVWPVW1dMPkVGRjpBQUld11Xfu7y+wte+tLLI69fH +zGNFQ1nX09v/zsvT09dZ2XdbY0c7TM/n59vTua+z2cO9tq+2vrm0v8bC1/9JRkpZSz5H07/D +62tXUzkrJCMjIyMkKTM/W8+/vLmsrMw0MUfIzEo097Kutse7tq+z0Wdb62PnUzhIXdfJWU/V +vbvDTnfVXetbRUn3vrm+xL+/w+9HT+fbY1lLQjo0MTAvKzI3O0v/ybCssba6v81ZOjAyMjI2 +WVtbsKutvLyyrKy+Ttu/vVVfa8u5sLTGxr7CyFUzLzg5MjAwPVNJTj083+9N6zkvQD1KZ05O +w7u1rLq/sbr3zcdJQUhJd8TIzL3AxNtnRjAwLzg7QvfZvry3tsTG609VOikmKjNLy7Wxr7G5 +y2M8Oj9G2c7JuK+0vr3Zz7XTNjw9Sus8WcFfr706PVPj4/85LCxEura5vMKxr8w6LDEsOjIt +Qe+1rKyvsLW4yz0qKSsuMzY6W7K3rL3Ar8HrSj490brPvbG0vMG60c3G09nO0U1rX1NvSi4v +vGMzRDY231MyMkRXPjdFPsy9XdlTza25yc0+Y7q6W0pL08vJy9m0trO5Y0xOOzIvMUV3xbiu +tLezr8FvV0EzOjYtQHdn79VvR/d3PTxNUUVRVS9My1PXzNHI519XTUdLTEhFVTs2TF9Dyb6+ +3a6svK2tvMbEubatrbiurbbBuNEpOU42Qkk3RcbAxcdfR0U+KiIiIiIkKCtE71dXP0xRY1E/ +P2ddu7G0r6ysrKyyt7Kssba1tL/Dwc9vuLGxv2++/8pONElBV8vVK0BNPDQyMiwx7009/zwy +Ny0nLSgoMS43PefTtLy7vs/Oyms+PtW8urSusq2svrq6t62trq2tra2tsrCtvL++v9W972Nb +OkE4PjY2LC8mKTAqOS1ELjs+MC8uLC00MkhKTF/Nyb3Xysn3V9e+X83nwNu4u1m9zr69vv/R +ur+yt7e9u7rOvtHP979fs8W+xd3IQudPQlXvQEc7OT8v/yrRP78/VetEyEvHXbjDtd+zd7W8 +00TRa0//X8swxTlZPl87YzFfPj28V1FVZ2/fyUpJd7pOzcpbyLvRuFevV7p3tj2uvb9vz8JM +zF+9M8VE2z3/O28v1S09M+swRDxNNkJOW01Pd0/jWVG6S8+3L6wvuFe3b1esRqw3rUCvrj+s +M7rfxFdVu1GuNbU3uEW6OcYub0NZNT1KN9sw2Tw8SUw6Ty/OML9NPdFM39lFvTjH0cjMzLrB +wbbEuL3XrUyt67atv7nCvrzbt1e2UbpPwMzZU933SEhKvDfvN0JAQixGI04qPCdCJElMJFkj +Uyw+MjE2RT88XUhHxj+vU7m3v7usa6zMrLutrK2srK6suazLrLmuv66turO1tOO5ys/FU81M +aztKPzdAKUsiOSkrLykqLCorLihHI04oPzI+QDPPOl0+znfnw3fCzLr3rf+zuq69tK23rcet +rrmsw6y+razHrMuzw8y6b71L51V3Tl8+TTfrMGMyNMslXTAvPj42Qjc1QTFGPzrVOOM/V1tZ +02tOv8vTtlW2U69BsUZRt1G2d8lfu8jJV8Bv17xEvdHTxlm4S8nGSrpKtc1nuUK3XcFjRrhj +d87ZyffZzUnGT83jb1lRxmNv2VFnU2tRWU9JYzxrSENJPUo3STc/Qj5MOlE8RERGTU5bW2Nf +d+NV2V3Z/9Xv2dXNy83JxcfGwcq+xL+/xbvJvsnJycjN38rZyt/Ib8/r0+fb3+/jd2/nV+9n +a9332dfv0+f/11PbX1tdR908bz1HTEFRQltAUUhbS1FKSkxHT0RJQkZHPko9ST5ORkpMS1lL +61nb49/P0crbxc/AyMHHv73Dur+4vbe3ubK3sbK2sruzu7m7vbvDwMTIytvb43drT1lGSD47 +PDk1NTIxLy4tLC0rLSwtLS4vMzE1Nzk8PUJHTFFVV19v39PJyL+/urq2tLOysrGvsK+vr6+v +r7Gyr7Wytba2uri7u7+9xcfL0dfvd2dXU0tHQz89PTg3MzQyMDAuLi4tLi4sLi0vLzM0NDk8 +Q0ZOWV3vb+Pf1cnMw7+8uLixs7CysLGzs7W2uLi6ube3urW4ure9xMbX2eP3U1VMSkpHTkRO +RkJFP0E+Pz04NzY8QUNCPDg8NT47Pz8+QkBJTedRTuvDW+9MTP/Ru7S3vsPDvL66s7a3tra3 +tri8vMXIysfX51VTV0lPW11dVVNMSEU/QkZFSkNAP0hGdzFAQFFvTTUrR0m+u0s7191Z02c3 +SOutray5wE/fz7m+uMK90761s7m3srm9wctPQE5TU2drRkhITFc9MDMxLjE2LiwuLzM5ODg+ +OkI+PkQ8QlNvZ+PXy8S5tbO4tbOvra2tra+vsq6zsLa0tre5vL7FzOP/X1dOQE1NVUt3OkVL +RFU+Rjg4OD01OTUzOD9ER0I/OzxFQ01NRmNrX9Hn2d3Oyr+9w8TMwsa/vru/xM/Ryc3Tb2tX +d8zMzF9CPT1K9/9XSj4/P01nZ2dPa013b8zZ59/j0c7KxtHr09HGxL7CztvV09nXzNv/X1dR +R0pKWVVfW0s/QEM+QERNUU9OU2tnz8vM0d/P48rCxMnPy9vDz76/ycXPz+PPZ99bVWNO03fr +b+vjX+PJ42Nv63dTd8pHPkZZT0vV70I+RD44P29BPkU8Oz1KTkZDVz89Y0FrX29b/9nXvMm1 +x8nFxbS8ure4vLXHurW7t8OuZ8W+79fLuP//290yRUI7S1VjSTdCQj5ZSkBROVs/V91R39NT +72t3yte7xu/TTE5v/2PT0dHv68hX49vbd1nKTFFfdz1MzndPX8hCTUfjd0jIwzhdy8vLwr9n +OjI5Ljzd58K62ctryr/AvbxfTEIvNjZFY3fLyGfH4//O3cLDzLvDxba9urvBzmvX51dj61Fr +XV9fRudLRllEPj48ODUySER30e//a01jXc3Fx7TBur/J18fjxcW/v8LGzu/PZ2NfPjYxLy41 +OknfzMPJwsvR31NKODI1MTtOY8m7tbq5ubm6v73Oz+9f2dPHvLvCwutjRz9HOjxLPD9BPUpZ +/+Pr998/TEk//0/fY1dXU2/O/8y+077Gv8a+ybrGxs5Z21VVw8jJusvK1Vf/X0lrU1tHVV1T +/8XIwL3Pyk9MPzY6PTU8Pzg6PEY9SO9TU28+PTo2RkBNye/n505XX+Pnzb/Hy7/Py7y+t7K6 +tbq+u7i5trC4urO70bvNx768wsnBy9PFymfOW1dGOTQpLSoqMC8tOS0pLyUqLS04LjM0LTw5 +RcPIuLS+tsPVwNPbucy8z7q+wa6ut6yvvLW9triyrbG4tMnHyNHDyczEd9vnU05IRUo+Tkk3 +SjtDSUNJPz5DNjJCMTxKOEU+PEk9WWdTXVVIRD0+UUPXzM2/yN3dZ9/R28S9zsLE1+vNwMe7 +s7m3uLm+vsnKz1lrR0T/a9PHu8vXa0Q2MjQuNjg6PkBIX1Vny9P/zttLS+NOT9/ZW2tv53dT +udHvusVn03fPy76tsbCsv8lnQD02Q933wLLBvsrTd0RIRC41NCsvMTc9OllGPEc5MUc7SdHJ +uLi0r7i1ubO6vL7KZ1dPNlNbT7/P0cXf491rWff/3ePLydG9487Ka9vV/3fX/2vvTk1OT0Hr +TlPXTUxvQjlZP0RGUTlFTjZGRFFr787BzO/HU0Rr79/HucC1sLS2tLO8v8PO29nR19vH2d9d +TUY+PkpDRvdHRO9FS048RTc4MzU4O0NFWWdfVev3SXdna+d3zd3NvMfGub7FuLzAw8O9w729 +xM3b2V9r38jFs6+3srnDzt1PRE1BS01LXVNMT0hJR0JKTT5fSExIPkg+QUdLV0//W0xLQDo1 +NS4vMTA0PkX/X1/vVV/3783Xx72+ubK5sLWys7SwtbKztbi/vr+9wc7TxlvLwN3H1dFvV189 +RmtNR01FPlNFSdNK0989Pjk4MEtIW8PFv8fXVUQ2Ly8sLjlFTtXJ1+9KPjo2PExC0bzLtbjF +vL6+vbu4wMHM3dl3373IwbvRXWffTtvOx7/KvVvn519vXf9RSEZMRk5r6+vZ3V9LSz46TjhK +90fKX1P3T1lZ40v331vPycjIyePr10tj3U7ZwdfdyF9fzt/b2+tbTU48TzxNd0/r9/dV60RH +RD9NQt/jy8fByrzXv85vylnNzM3BzL7F68lnUdtMz9lbxd/Gvby7wsrvPFFKOHdja8/X29vv +Z1NEODMvLDA3O2vLy7vB2VM8Ny80NEFdV8vVd+f3Rmt3Quv3Z//J1b2zurCvtbSxuL2wubyv +uri2wMfZz01fV0BTPEI9R0pIVU1DPDoyND42Rk5DZ0FVSkRRS/dVZ1tL/0xr29O+vrm7w8nv +WVHj69vJwtnM52NNS0xIUVdO21vO09XKwsfRwdvj2dNvyef/zNXK/9nZd09jSEVXSetOa3dK +PUBGPlP3d8vMXedJR9V3xcDJvmPVyGfJw8XJusDNxcHJ0dPrT0tZUU9VW2dORF02NUEvMzk7 +PT5KPj49OkdBTc1n38Hr38rj983J2dW+zLy6uLC7sLe9vMHK0cd30/ff4+vVV9Vba2NHa0FJ +Tmf/zc/IyddrWW9jb9Vdb+NRSE8+PD5KOD8+O01ASV9fV91rY8bX0b/Z58LJ47/b17xnzcpT +3/dZZ+Nd2+9X411j/9fZy8L349NLTldKXV1TTVtZPWdKQsj/3evbW9vb38/O38nNd8zrzs/R +0+/PX1HdVW9fU1VXRExrTV3/T1lbTEhKTD9RPkldT1FV/0vd6+/PyMDEw9PLz9PEvry2t7e/ +xs/ZZ2Pn5+Pfz93b3+t3V+t33dfX2WPjTmNFRz9CSzo8Qzk+PTpKSDxIRG9f0cfJusjLw19n +791vxcfJxdfT129jUWdVa+NR0U9V3UxV39NZ/1tPZ1/r3+PR4+fr/87J4727xMXI0dvOV+/X +SmdrVUhjSj1jTU9Vd0Z3d13X28vGztfO1Wfd213R02fMd99fd/9XY0JbSEFPRlFMZ19NUUFI +P0pCRVNJd89db+fPzt/CysHMwr/Gx9PIU/9FXVtP0UfrV11nWVnbz9vIwse9xMPGycrJxc7J +02vn993vyWfT42/nW1lZ30/nTkx3VVFbT0RPX0J3UU3jb3fR/+vP41/vW29ZV1VKVVs/UT9E +Pj5AQj9FY0Y+SENNRXdf0+PAvt3E28/r28LOucW4uLm4vr7Gyetv31f3Y1NnTutfd11bW1N3 +39nZz8bNv8bIvr2+ubzJxsF3zW9b60lrZ0Y9RDwxPTMvPDg5OUU9O0hIY0ZM1+Nn181va+dn +6/ffx8zdwMzjvsjEvsfGvd3TydfJwsx3x2dVy0bn52/Pze/nxO/HyNfIzNPbxmNXX0lXSUZO +O0Y+OjM5OjA+Njo2P0s9TUpTa2/r3dPPyc/fyNnKwMfAv7zFvr7CwMTAwsXDw8PrzMLbytPV +Y9n/WWNrze9T/11VY1t36/9TZ3dPWUZFXT9EP09CP1FITklXTlvnX/fdz8njw+fr191fb/9T +719n719Ga0lMVU9db29da1Hn/2Pjz1dj1/fnzd/Gz8/ExMe9vrm9t7rIu7++wMfGzdnZ593n +W1dJPEM+Pj05PDwvMi41NzY6M0FKOj9PSVdP51v/b9nC08jFvr6/ur2+wc67vdO+xMa5wL3I +xMbEycfK0cjI283L18TE1cvGY9XXZ8tba11TRkhMQ0VAPjo5NjNDNDQ5Mi4xLi1DNTE+OTU9 +PD1dQ13VW9vRxufEvse6vLaytrWvtbuyu766ssK4v727vrrDwc7PzcTH09PL20tvW1lZb1NZ +UUhTQUdKRUdMTj9VS0pKSENCUUlnUf9LRktTSk9rY9tbVU9IW1lvb9/Za9fn2+PR39Hf1dnn +z9/T0crVzc3Ozdfd7+tdY+9v919XUV9OX2dbY+NXTndNY1dXU09PU1tvW2v3TmddV2v/1Wvb +7+/O09++y8m9xsu+0cjE2cPT79Xb/19Xa1fOb2ffX+PT1efvV9NRT/dI3WffU0nVQ2tP91lv +d07vUWNOQddL699Db1tHz0rN2UvLZ9XRS87L3bpjycdfvW/v00vMUdFj4/f/V2fdP2NnQONH +U9U9bzw/Tzo9U0I6RTxEQ0ZTTUrKS8vT3cHb0cnJxsS908C9ybS4wLTEurTGsbfGsr6/u8DN +tcHNusvNw0zDbz3dQ0FnQTJOLzU+LTk0KT8sKz0mPTYzQy87PTlMVU7KZ9PPyd/AxdW5yr+5 +xLm8urfHssTNutO9vne14/e478O7/77dSbdJ0chN41tE70RXSD5nPVVbPllJSFtO7+M80TU7 +3zDn4zbnO0xfQNFPTctJV8VEyF1nzFPGvlvB09e9yrSy16zfvbLXtbnPu99bvlPHzk3LRznE +M9H/NtEw/1843TxDX0BXTkBRPUBdP1VXQe9FRP9GV+tCY0dRWT9jY03PY2/D68XI47rHwba/ +urfBtrrFr+O3w8+/0du5Z8fTWb9f3c8+6007Zz4+XzdIPjNHNjlGPEE+QUdAS09OVWtX12Pb +yufHyf++yr6839HK68fA38/302vIxsDv3VdRz9nja193T2PP/2tNTVVn4+NTTEtLVU9LTkVn +XUzjSV9ZWevf5+f/779d09fv1+fNyeO+42POW9PGy85n3c/rz/9P219Ty1vXZ9VnX19dY11j +U+Pd3efnV1/fV9vfzXdfZ11f20ZO2U3db05ZTV1X/29Na0xRV1lb/3d3Z/fX29PX2/fZ99XL +19HEzsLVz9PX383J1czb3dtXd01j90ZMQkBPREA/P0ZRRUxFTFVBW0tb71Nvb07f29vRX9nb +zcD32c93zevR08zG0ci/zcnT58/Lx8DFxdvV2dXV09fX49fn51ljXVHdZ9vbU/dVZ3djWVNM +UUZMQzpCPj1HQEpJREhCT01ESE9N711VX0dVXXfd293P79vbysbAv7u+vr28v8LIzcHBv8jM +2d/j13ff2///Y+NjZ2dbXW9LT19OV1tNT1VVVU5NSkJORktTSkZMTEhKRUdJR0lRTlNbW2v/ +49/VyMfFw8PAv72+vb+8vr7CxcHFwMHJxs3RzePj//f3a2tRUU5DR0ZCSkNCPT09O0BCRVVI +TVNRd1//193V0czJysvP08/Z1cnn2+Pv1etnX2tvY29ZW2vn//d3a2djW01NTElOWUtMRkxK +TE5LS1Vv6+PXz8jEzMnEyb2/wMHEx77EycPGy8rJ29fb/9f//3ddb2v/X1lZW1VZUVdXd1tb +TFVVTU1bSk1NU1VPX05fd1dOSk5NVV1ba2d34+/r6+PVz8jHx8vHzcnT19vj3evf5/9dV1FT +UVtTTldVTU9LS09PW1dfX1dfZ2/n5+vr3ePb3efX29PT08/b39nn39PbzM3NzMzRyM/XzM7P +29fd09fZ3+Pva1tVTk1MT0pGSUE7Pz1KS09RVV9nV2N379/f49nZ3dPOy87M0dPV19nP2//r +Y11fb//v6+dva/f35+9v4+ff4+fvb2tnXVlTZ1tdb2N3a1tjY19rW1tdZ2tdb+/v32tra2v/ +/2dfXW9b92tjVVdVT1lXY2//3efn59PNy8vLzcnJxcjIxcjOzc7N2+v37+dZVWNfZ2NdWV1b +U0xOVVVZUe//d+vZzdPOz8zM08vNzs/b0dvf62drd+9rV1NbV01JS0xVTUZLTEpMSUdKQD49 +Q0lDR0VIU05OUVtb/+vf19vT19fR0c3Nz8jIysfJx8rV39XXz8/KyMjCx8nJ1c/Nys7Xy8rJ +y87Ry9fR0dvdd2tnY11dV11bVUpEQUdEPzw+QkA9QENGSU1VTldrd9nVys3NyMXDxMXFyM3N +z9vP2d/j9+/vb/9fZ2djV1VZU09XWVFTTk1NTUxOTU5NS0pKTE9ZX//d3ePdztfT29fR0c3X +0+d3693r79/d2+d3/+f379/r9+vv5/f34+N3W2NfV1t369/r6+vj2dnf29nT09nj29PR0dvd +29PR2dvXzM3O2dPX2d3V2+vvd1tXWVlNR0lJTEZBQ0lOTk9OV1tVVVVjZ2t3d9XZ09XZ0d/n +9+v/b1lRS0xLR0pLS0tKSE1VU1NOV2NjY2/r69/Z0cnNz9fRztfd6+v3b//v59nX19PRzdHV +09vX2dHO087O0c/LzMfJx8rKzc/b3dnT19fVz87b29vj629fW1VTW1FfU09RTExLSERAQT5D +QD9DRUBDP0pMTU9NXWtjY1tnX2drb/9vd+Pfz83Kzs3IxsPBwsTGycPJyMvV1d/f62dvXVdZ +VVNOT09PU1tdX2fv7+vf929nY/9nZ2dna19na2936+vd49/r7///7+/f39PT0dXX1c/P2dfj +5///73f3b/d36+fZ0dXP0c/V2dHZ39tra11RUUtLS0lJTUlETEpOT0xPT1VnX2/r6+9r/+vn +Z2dnX2NXW3d3//9v//9nY19jZ05XXV1fU1trWVdXU1dbV1FVVWdTd9/b2+/X0cvOycnKyMvR +zcvFxMG/vL++vL29vry6vr7Ex8vP0dvf5+trX1ldWVNPT0pBRURHSkxLRklLS01MTUxNTU5X +V1dfVVlRV1NRV0xKR0tESEdOUU9TU1tXX11nd3dr7+vb2+fd6+PvZ3ff593V2efvd29nZ3dv +993Z29fX1dfTy8nDxsXHxsTHycXFxMbHyMfGys7P2dvn72/v/+P35/9vWVVVU1dVV1tZX19b +WVNRUUpMS0pOTU5MTElHRkdIS09RT1dZWVlXWV9fX1tfb3fj3dXX0dPV09HLzM3Nzs7Nz8vN +09fb19Pf3efv/2NjX1tZVVdTVVVXVVdPT01OU1ddY2dra2v/9/9r93d36+/f9//na+vj2dHI +y8fJxsTExMbGx8rLz9HV29XX29XV29vjb2dvY2tnXWNfX11fV1FNTExLTUxISkpHSUhJSUVJ +SUpITEpHTU9XY2Njb2vv5//v6/f/7+Pb0dPXztnV1d/j5+vn//9v6+PZ2dPKycfGxcXJxMfJ +yMzKzs7T0dfb39vf69vvd+93Z1NbT09RUVFNSkpLS0tRUU5PTEpMSUpPXWNn9//v///3393d +39vd69/d3efn929v5/f34//db2NnZ+93d93V3dvd4+vj99/32ePZz9HOz9nZ429v///n7+// +//9dWVFVU09VT1VPTFdTU05RW19XT09RXVlrd3f/b//f693n6+fd7+f/9+vvb+Pf3dnf0dXT +1c3T0c3OxtHLzNPb5+vv79/33+fV4+/373dvb2fn7+/rZ+fj/29v52/3Y3dfV1lNX1FRTFNP +T0xJS01LTkpRTElHSEtIR0RISUxMV1lv9+/n18/TzcjFys3RysjMysjCyszLz83Mzs3KyMjK +zMzNy8zJy83TztnZ1+Pn793f/2tnZ1dTT1VPSUpJTU9PVU5LS0hFSENERUNHSklLTExDP0RF +S008SEZMS0dGSUtPTUpMSUhCSVFVT1V3b//3/2/v1dHHyr++v73EzcnKwMXLzMrNz8fJxMbH +xMDDvcfFy9nrX2dnb11TXVtOT2Nf7/dva1/n42NfZ1lZZ09NTkFKS05dXWdfVf9PWVtbUU1G +TkhDTUxITldf/2Nb7/fj49XnzM7MzdPRzdPXy/fO69nXy8/Vy87P1c/L28/Xztf/0e/f1dPN +999rb1tbXV1XX0tTTk5MP1E7Pzo+Qz9LSEhPU09vb1vb39PMzsPEv8O/v768u7vAvsO9x8zV +3WNvWetnWVtVTUxbVVdXVWdX42/XZ1lPSU1LR0ZLR01DSkZEPkdKTldr49/J59fTzdXZz8jX +53fZV19j71Ndd1lvb/d3Y2fd9+PXz8nHyb3BvL+/v7/Av768wb/DyM/b32NFTkE8Pjo6ODM0 +NzY1NTU4PTo6QUpHRl9db3fj59nKzMLGwMDDvsbBxM3Kxb/Izc2/wMrJvr/AybzMwci9wr3A +3cPTyNnv/19fTldNVVtMSU9JRUg9R1c/SDtFPzo8OTo3Nzo3PTo9Pj88Q0pMU1drd+fd39PZ +59fNx8O+v769t7rBu77AvMPGw7/BxMPMzNXf7+/va/dnWU9NV2djX2dbXU5VQ01PU11XUVVR +TD9VVUxbVXfr1czRysTO09XK0czFyc/Z2f93z3fT63dra1tfV+9n9+/j4+vvZ/f/3//r4+dn +Z1dbUVFPVUhDRkNBODtAP0hHRFNVX1tvb2vv283Fxr++vru9vb24v73Av8rM29Xf7/9nU0tK +RkxGS1NKV0pGTUlMSUdCP0dKR11r49Pd0dV31d/ZzMnPxMS7v7zAub+7wsTPxM/n91tbW1Fb +Z19d/3dvZ1NNS0tNU1NZT1NKSkxRTU9NSlNPTldTT1FdV1VOUVVbX2NbXf/359vbz9PrXedb +53d319XO08XJ0dtba2dr/+fPzM3NzMjJzcvTzdvM2dfbzt3N38vF0dHfz8vPz9HVd9dr6+tn +a11bR0hHTlFdWVlNR01LU1dRX1tfR0tKQUI/PTo7Ojg7PD4+SUJBSUBLSFVZ3+vXzsvIyMq8 +vr69vr67tra2srCxr6+xrrKztbm7wMbO12tdX1tVVUhOR0xBSUE/Pj5APEM9QDs/ODY5OTk1 +Ojk+PEA/RT8+QE9jV+Nnx8PEwMO+wMPKxMvL18/Zz9fbz+PZ5+9n6+fv987Ry8XTzMjJwsDL +1dXDwcfJzszHwOdXa2f/d05JSlvnX0pDPk1TUVdNU0VbVUk9PkRXU19Oa//jVVldS1VMX1XL +vrvvUz5dv7rHwrrVzefZ19HK6+fn1cbbPTAuzr2ttNtIQDw0ODhNb8G9vFdnX/9dTl3dwut3 +z8RFTGNvPd/328O9/0bdXUc/WU7/T2dZTzw1NVnZSz41LzRF3dlrW9/Ty7+9vtusrKw9LzT/ +rKysrK+vtO9GOz7Er6640+vba0c+OEHjwWsvQzovLzEqKUDnQuPMXzxNzGfru7/BucDVa8HP +x8bP1VlnWbu4zz85L1ljxVFK213OuCQpr6yyNSMoKKyrrMqwrOffNigpPbeszLzDsLTTST0+ +u7mu32P321U6MiswQfdnb1fIztdTPUNfuruyt7S9uNPZ18HJ1dXvVUlfRTY7N0I6Q0BbXdH3 +Wzk2Oj08Sc3fx2eyrSNPra2vUyo2Ma2ttNOtrchTKykqScvNN9u4rc0+ODnXur3VX9u3vkwx +LDlKY2NHd7uwtt9nY8C4tbu5sq64yklZ59PRV1Nn30s9MDY6QDw6RF3FTkFCTT5LV1tfuLBG +K66srDolLTe/rLrBra2wUSoqNUHfX0TZra3AOzhT429MTNG4s8o7LzhDPTc7Ss2yrbbXz8rG +1cjGta2tts5j2e9nSElr529EOjQyMjQuMTxLRD9jQzkySG/nUdHnwLvnsOs8raysQSvNv66t +rqysrLM0LUxVOTNXya2srMHjw7lRNzlT193vTz9DPS8mJis0PkxjyL282V1LV2PTwLW0t8nj +a1U+NTg+TU9MSkNGQTw5SOvf39fOwsjvb93ZzdPBure9uLW1uVXbvrPOW9+trKxAd8a9Slf/ +s665TDQ4RSgjIy1FS13jwLm84zs5R1E5Nz/ZzNn3W93nXUFD2cfKxbu5tL3My7+5wM3Py9f3 +WUs/Pzw6ODk1NDY+Pzo/T29j38zNzL/IzNPOytPRx7m8w7aztcnMwsrTvclnzK65SzdTUTo0 +Ok7JyVE1PUs2JictNDQ4Qte9u7u7s7bB09nKzONn3cO/ys7Ju7u9vLzFw9Hj393b3d/3X1FM +SDw2MTAwLy4wNjc5QUdJT2/j0cfBw8G9vsLLy8G7vby2t7q6usrLxcvTxsv/29PnU0Zv51k+ +RkpEPjwzNDg5MzdBREFFUVNRb+fr39HLyL+8urq6u7q/wsPIzs7O3f9vd19fWVNOTltbV13/ +b2NZW1lTU01LTVdfW1tf///36+/n087N29PV1c/T3dHPysrO1+Pr72dTU1VbT05FQUJCP0FB +RkxVVVVZY19dWVNMUVFLT1NXb+fd29HIyMXBwb+9vL69vb3CwL28v8LFwL7DztnR3/9ZT09O +Sj89Pj4/PD1AREdJR0VJTUtPXevf2efd49tnV1dfa19dWWNdT0xLU19nb+fb0c/P19PN0c7M +y8rDysfJzM7Pzc3R09PR1d/n6+v3a2NfY1lVT09PU05NTk5VWV1fY2/v72/37+vj9+//5+f3 +92NvXWNXVVVdZ11jVVVXUU9LTktPT01NTE1GSktMU2fd0crGxL+8uru8vLq6vLq/vb7Ayc/O +09vj7/9v7/9nXV9Xa05NTEdTV09OSlFRSE1IUUxZUU5NWV9TU1FXT1dVVU5bVU9OT1FRT09X +W1lna/fn39XL08nKzc/Oz83NyMrHwMHCwMPEycrJy9XT0dPd3+/na19TSEhPSkhPW1VTWVtV +TVFZXWNjd2/d3d3r2dXb6+fj/+/rd19bZ2NdW2NrZ/9jY1FZU0tPTE1TS1lVV1tTVWNjd2Pr +9+fr99/j59/fzs3NzdPVztPj29XO19vMw8vKz8/LztXX387L1dfd2ePb3/d3a+dra2drWVVT +T0pNSkVGSklFREtLTUZBSEdEQ0ZDSk9TTFNnY/9n49nj2dHTztHM1dXTzNPVzdXX1c3X1dHM +ysrGx8XHwL3Fxb6+xcbJzMfJ0d3Z2f9Za2tZWXdjTmtTOmNMODlTRDk+Pj46PUI+PkJFRz1T +90VCVdldP1/LRES77zpZvU1O28XIX9W418a528y8ysrZvbzfQsex1zi8v29HwVnTzNfTxme5 +y0XBtlPvxf+972fMSP/FTUNNX1c3OUdbOFVGQFtOTks4b/83Rk9LU1fr2VfZwNX30dnL91/r +VVfvS1Pj39HT0ca5vb7Dvb3Ezd/TzN/j2d/Z2e/v187d/2djUUpBQUFNVUpLWXdrX19XZ+v3 +d1NV919JWe/vUU/31VFb99VO78vRTd/r/03v3V0+2fdDSV/nZ9X/2z1Z3ddDOlu1zndR9+/M +vcH/07C1xOfXzt1vX0BC2b2+y763tLy+zV1LUUU5MztDTl9nX+fMw8fb72v3Y1dMTW/371tv +Z29rVT89RkRFRUlDQ01MQ0RTSz5NZ1lNd93jycTAwr/DyL21xMG/xdu6xO9nys7RxL5nT09n +b1l33T1300lMSU5vT0hfa0ZT687V/3dOS2fZz9/Jwb7IxN1ZV1lTR0FXY11ra1NNTldnSlFV +UU9Zb/drZ9tXTld3d+ffydnKwL7JxcjM6//f32/d093X18rO293r59fX329ZTldTRltZT0NJ +V+fVzNlLR9HByNtbPTtO00lIUVdf78zNV0hdVztK12NBPzk4O9vCz+/Hxs7MyN0/RGdTSN/L +x720r7G6uMDNd91nTk7n2dvIvcnOy87nX2tbSk9fZ//f1d////dTUU1ITk9XVU9VXVd3b1lV +WV9OS2P372N3W0lOX1lvb2ddY+fv/+dnTFFRU1fvU05rzMLAy1tLV1n/02dn/0RL08zZWet3 +Su+5usXj905fv7rMa9vHyL67ushf/9tv68j3RU7XT07XXT06RPdCTvdKP2fr/2tV72dVxsLn +59nL0c2+v+PZztvj49vvTFnda2fva19bW1lfZ1tr6//jW29fa2NLS13r911b99lnUV9MVdfn +V0ZId3fT38dbLEu1tetTOCkvPbutuLPFUz1O0f8uKjEtQ8asrLK6uMvEvbpRNzQ6P3e8tsLf +187O08bLXURMY83AtbW7xMbI2etjX0M9QU5dd+//Q0JHSEVLS01JT//3Z2PvXVVfb2v338// +Y2v3V1tdW09MX2NTW+vb6+PMzetZZ1tEXdnZ793Z1edf39dd08bX6/9ZUefNwb53SFFOTtPM +y9VrW/fvxsLdU0xbXd3HyN9PW13v5+t3W0pXWWtZa2/v59/n62/31dv36+tbWWvv2/dj0ddj +X83jd03f1d131XdKTnfR6+PV/1NEV/ffy8XZY/9bW1tj6/9TV3dbT1XIzGNHPj08P2PKy9fb +/1NJTD88PD5Gd9fFvsLFwMXGycvnb1dbW//v7/9n7+vb29PV28rb1+Pf2dHOzcrP1dvX09/f +73drW1dTWVdfU1NOUWPn3dvP31Vfxcv//9XrP013/1n/2/9M//dvSe/Hb01EZ2tX58PCyN9r +SEtEPjo6PDs6P9/Czd/j19nV53d3WVlbU1Ff19nb3ePRy8jCzc3Oxsa/vry9vb2+zNvX619P +SkY9PT5APkZHX1lr79nOzs7X3eN3629va3dZ3W/Z79/j9//n3c/dz9XT28/b0dfVd11OXU1M +SU5CQEZVS0dPX0tTZ91379njWWdr72vv5+9ZU2P/a+/n5+vX0crMzs3X72v/W09RTkxGS1tr +X3fb5+/V09fV2c/Z29nTz9fX529nW19TUVlfV0/r29PVxcfOyNHN08zDTMzN72/LZ2NFy2ND +wkhbTUdMOWdZTlH3XWvN5+vT2dfr411fWVtba/f/d9vvX9/j4+fd1+f34+//6//n71tZX01T +TVFRTFtbV1tRW1lf6/fr1dnV0czV29vX/3f3Z+f/529r92v///d3/+fv5+/r7+fd5+/v32P3 +a+f/7+P35+Pf3+Pd52/v393Zzs7Xz9fNytHP0dVr5/dTU0Tf0z9OXz88PmtVTmPXU0t3129f +a2NHR0hdT0NTzFFd2dPGPm/GX+vbyt9L69NbT+vrW/fNytHTzcfKzr/Dzc3T29n379drV1dd +UUxRU0tESk1PVXfr7+fZ19XP08nN1c/Z4//v52t329/j99vv//ff7+vf1+fn7293X2f/W09n +WWNfXWddWWNfVVtTU11TW1dXX1ln/2vn4+vZ1dnO1czPys/M19Pv7/9fV11fZ2dr/2//Y3dn +Y29jV11dY1dnW2NfZ19bV1dVT09MVVFNW1tjZ293a+/n7+/b2d3f39HX19fX19vf0+/n3dXV +2c3PzsfNyMnHxcTIyMfIyc/R09XZ3dvn5+/r92dnWVtdV1VXUUtKS0VFRURES0pJTEtLS01J +T0tOTlVRV1NXT09OWVVXXWN3b/fr2dfZ2dnT59Xf2+fX9+Pf49/T5+Pd39vV19vT3dXV18/O +0c7R1dXO183/3dHZ3+vf73fr3+v/73f3Y3drY2NnX2ddWWNbd1tra2djXVlbWVtZW11jb/f/ +72//d+vr/+9vd2v3X/9n52fv6+vv53dvd29v7/ffY/9v/2dv71/37/fv73fr/13d/3f34//v +//drX1t3WVlvX1dbXV1bXWtnZ2dja/9fb3dn9+t3a3f/b+vv59vd39vb3+vja2Pd/2d3//9r +2+P/387r1dnP0dPZ2dXf793X59nP987Ta83Oz9fr6+9n62NfXV9VV1tOTlNVTE5OSllRWU1n +Z2tr3+9399/v5/fn59Pb3+Pv2+Prd+fv3/9j91lfW1NXX1FfV1lfWVtZU/9dW+db2e/329fZ +3dPT19Pf0dvR19/T3///d9v///9Z93dra2tdU19RV01ZT1VXV2dra1tnd/9369/n2efn1dnV +19nj793jd9Vnb+fj6//fa2//7+d33Xd34/d3Z+9r3d/V0dXr39Xf3dtv69/jX2vn5133d2f/ +b/drd2dnX2NPW1lZV1NnU09RU0xPVU1VXU1XXU5VXU9rWVnv5+Nd3d/n/9Xf593v79l33ePb +3dPTz9PT1dHZ1c/P78/b4/fn711nW11r/1tv62//Wevva93rd+/P29/b39vb39XZ19XT59vn +a3dvW05bV1lRS0pKRklFTk1NTFn/d/drXdNrXefV79nR28rL18hnx9XvxUc/vfdBv8A8wtc9 +U8xdRtXRwi+7PWu7OMa1QUq5zji2OErXYzmwPzy2ON9b50xT389VSsRL42/fSknr71lGVb5K +33fr69nn1VvZydfn28fPytnT293Ozevn2+Pd/1FTUf9vTVNv/+/dV+PZ0ddVVWfKZ2tv78pb +QFVrd1VCP87May9bvsLTd0hRzs3/RE3IwNtfb//T109N29lVRNPG5zs4Pm/ZwcjIv7a9WT4+ +Pzc8Oz1MvrO0vrmvtMlVRD45Ojs+W7/Da01TSzo1O0z/0c7Iure2v9fVuMvOxc9d50vLU9HR +a0DNSVdOvtlL57XBLi+urccpJkE+wsnO262tyTYsNSwkJSguR6+tt7utrcTnTD03SNnvTr+2 +vetbV05Z289v78W7wsXCv7m3vstfR0xGPkBfd/drb1NBR009SE7vY1PVwXc/Nz333z5frqzL +Rcm760pXut/Iuss9tKywMy9Hb++709m+t8kvJy06Kio9Q125rLxN2bbMR0tdX9O+utXRu7nv +U9vVb8jCwd/Mvr/Z59HfX0pBOC4zNzo6Pj9FSD8+Nzk6Pzpd38nbz7y821XLra62zF27rq2+ +W9m2wL6/viv3razDLSlbTsvTzWe0rro0LC01LjEwMTu6rblJT7/E1VtZRG+8uNVT37/FV09f +787AzdXdxclvRUZNS2fv91tdV0g6NzU3Njg7REpNU2NnY03rxsnGwcK9w7+/vlnZtK2vss1j +ObyvrVE4vK13NEe6xc/J2Tk5RVNATOs8KzdLPjVbxl9DT189NU/XSkvOtLu+t7TAvb6818/E +v+PXzsT/U05LRFNv/0tNY2dRVUtBO0zrazs6P1FVb0k+SGtZPj/PyNl3y8VrWcC5ubG3wFdb +yLe5ub7ZO0fMr733T10+NzzZydvRbysszq9nLCYuPe+2t+9jv8Y3LjVIP07O02vCra/Jzr/d +3cu9zc69u91RUVE/SltbPUprd11rW1lVb1tXT3fO01c+TU5nT+PrzMrH0/9f/9fR31/TybjB +Pzhrr7PBRT7rt7LROUHJvj41O++2rsk0JyxTz99ES+/D11szOE1rZ1lPd8XJU0NASufOzm9b +2bq4w8fGxsnK51VR48HIWVFMUVNJRklP6+9b9+vfy8zPzdvX2cvN6+v/Z3fnW9nrzONdSlFZ +xMZbO0zP20NLZ105O85rPUDDTVtR2etX2bo117PBLzBbrsvBwsVVybe7Qk53d0VVV0ZA09dn +PVHba13/UUI+VeNXRk9fVVlv42/v18rT0869wMPJzdXOwsHZ09HXZ2vv419bY0pHU1lDS0xf +b1/v70Zj38nM68zAz8Nra8PHsrlny9fH01XIvlFvS9/jzclJLTnVzGc2Liw5a9dPMjtNPTlD +zkZRXVE2PFvM/9u+vb28usjb073H083L08jCvsvZ1dFfTU5PW1dTW1NAXVlvT0prX2fPWVdf +zbrBd9vPz81RRFnbvLXdU1XV5+NPWV/V72M4S9/nVV1X2T9Fw81TWXfDvk5jxcd3vlVMSsy5 +zOvn2V/jW+/dw+vdRUtvb0rb183jWUpFOz1nUWtVRktVT3d3WV1TV8vNa/9n3+dfTk1K/2v/ +12tnyt1Tb1nvvsjO1+/Z690/48fB1XdEUWNXv80+z9tvxFHj2e+7wz5ITOu4wf9dW8+497vR +/3dd/8F3vb1XzcxXd8e/yD9ARj9K93dnTmdPOjg+ODs4OUBGXc7ZY2d3ysTBys/Pz9HPzcnJ +ycbI59/Mb9Nba+9jW+/Z33f/XU5ZREhTS0VGP05KRFFEO1NnWV3fzN3DvMtJWb++29Oyw0NZ +ycK2vudLTve1XUHOucTnQUNTXcO6w8fE31FDOz4+Ql9X99vd599339njyctRVWNnXUVGU0hN +X0tETnfbV05VW+PVz9vvz8HRWWf/73dM/+tPWeNbQU1nd3dfUevra8e93U7vxL/rRNe5w9fK +//e9xeNnV13Hzl/LPjbTt2tFOjpn42PJ20zV401GPUxXU09KXW/Nv87Pyb/Gy9tn0cLI02f3 +193v6+93a9fT///3d9HT493b39nvVU9nb1tNRkBGWUpDPUdPTENHRkpHX2dVTOPZUVm7ylXV +sdtv97fnz765d//Tz2/P/2//xdlORszF6z/bZz4+T0k/P01LRkNKS1Nfa11399Pd2dfT2c7N +0dPdy8rGxcrMysvMzs7O0cbJ3d/r09/f3/f3b+tjX2djZ29rX1NdZ2tvXW9379nvX13r61tZ +U11RVUxHSUtOSExFSElLTEBKSl9bW2tvY/f/4+9d53fj3evf39fR09vTzM3R09/d1cvd1c3X +1cvZ49vT4+fn49Xj3efR3e/d2ffvd2Pn//fvb29v/11jU1VVV1NdUWv//1n/a+tn/2tf5+PZ +5/ff5/9v9/9dXXddY29rY/93X2vv/2tna/djY1tn63f/d9v/b+9n72//X/fr4//v73fj//f/ +/2vn/+Nf42/d/+P35+ff//93Y+93/2df7//dWV1n6/9rXVvrd+t3593j73fvY2v/X1dv/1VV +X+9jZ/9vb//rb29v2+vf2c/r3c73593j79XVXefA7+PDyt/E41vAdz/b02dT019I22NFztdn +a11r92dPX/dN611T/1fnY2NM10/vTUDBOk9fRlPTPl3nOsrFP1Hda+P3791Jz8FdXd/Kz9X/ +/9PD/1v32ePr9+/TzdHV69nM2ffVy9P/09fb1///3+/j/19j1+9MTdnnVdvjW0ffX01R3dFN +V29JTstRS+vIdzpV0T9Pd91TVcm+S0q9xks+WbzJVUndz9NfSMC9w3fr0c9ROj5J7z09RM/T +XVvby9vI1VFr2fdHVWPvSVvRXU1d2c1v49XN68vI5+fFv9/VxcXT0c/M513Tb19b929RTmNK +QFNGTVlRU05F62tNUWN3XWvbSVPOU09T2c1jS2PXy0fKu79fSsy/d//V0azRSGe8wWNDz8HP +y1nZzdNdR2e/S1Pf70tfV09Cb11BSO9dQERvRj5TTk5KTF9LT13v29/v1ev3VVf3b2/j529Z +z2P3z8pX78TVWdu+3+vf0cDM/92+zv9Pz9HnU8nL61vXx+fdQkvfW0FI3czZ3/fvY11da09n +RXfP30df/9lR4+9vX+//SVljW0//a1Pfxe/vzNHG0dHfzdfb2c/37+N342tv/+NXVetjV1FT +W01GUUljX1lT7/dvTevX21tdzc7j683N09fP1+Pf905bT1lIU//3Tl/Vz01v0e/3VVvIzEhb +93dTXedrWbzTTNvB30j3w8Rnv8fZ1clrb9vG/0nGykpDa0hBT04+X/9NRlfvb2tV62ddSEl3 +Y0tj3dfV1dHbyt/r09PPxN/XyL/L2cu+71PO0eNbz8znd9dd3ddfW+fdV1FfVUZjVUtO/08/ +Ve9HT11VW9XvV2fMxetHUd/VQj9b3UxIR1XTd1Vb49f/Rf/P41Vj2d/jXffP0ev35+t3d1tj +z+v/28rK49nTa8C/7/e/ws7Gxt3Jxl1jxM9V38xVb+9PTOtPR0ljU09XWU5nY0lf711T93dV +XV1OXVljWWPb/2fn2dXn68zN3dvb/+ffZ2vn52tf72tRW3dbW11Vd2tOW/dTWXd3W+Pv7+vP +9+Pj53fj419n4+N3Z+/j9/fr6//nb1vv6+Nv79/TZ//j7//n6+v3z+P/59nrb9fr79/f4+/d +4+vf2+vv5+tnZ3dvZ2tnX19nZ133XVlTVVldZ2NnW113/2tv72f37+d349nn3d/V09vb3/fr +a2Nra1lZa19nX19TU19PT1VLTVVbUVFVWVtZX1dvd3dr3d3V08jPzdnP2dfR19fT09fb2czX +3czX2c3d39nf7/fj5+/d2+t333dvY1NXU11PV19bVVNrV2tbWVlvX3dd6//v63fv9/9f71/f +a+//3eP/92fd399v79nv9+vra2//a19TY09ZV1ddT1FOVVdZX1/vXf9fb/dv2f/d09nf09fX +3dfZ1+PR09PR09ff3dPj1evb19v36+/v4+fZ3e/va/9jZ1VbWVVPW1lXWV1bZ2NfX1VbS1lN +U0lJWVVNXXdfb3f3991r2e/P1dfX2dPj29PV09vT3dPbz9/Kz8/dzs7f1+fj3+PrZ3fj7/93 +Z1tjUV9LVVVPUU1KS01LTUhNVUxTUVlTW2dZd2tvZ2Nf7+dv39vjz83O0cjNztXI2czTx9PK +ytPL1dHbzc/T19fn7/93X2djX19XV1VbT1FXVU1NTldRTFFOU1VZY1NXb2NrW2Nbb2vr/3fn +Z///7/fj59/b4+fr6+fr5//P29XN1cvjz9vZ2+/P2d3d29XR39n/7+vn72P3b29db19RZ2NP +Y19dX1VdZ1lZVWtfd1lbY3fvd+93X/f3Y/9v//9vWd3dd//jb2trXVtfV11fY1n/WU1vWV1b +d2fv493j1dvR1czdzs7PzM7HzMnb3ePv39X/z9nf29/33efjd2fnZ2tfd19fV3drd1dna2dP +VV1dV1lZZ2NrX/9dTedV/2dX51lnX2f3Z+P30/fn9+9f591rb2PvVV33a/9r7+/ra3ffb+f/ +d+P/79nr3czVd83Ry+vT2+Pd39fv5+vn2ff/429n999f/193Z+/rb/dvb+939/9RWV13TEtr +U05NU1NXTENTWU1MSUxdd1NZ9/fr/93V19PN08zP2c3j18/X48jN3czZ0dnR1Xfr7//n5+v3 +62vr53ff4+vj3+dv91lrZ/9nW2trZ0pdTldRd11ZTlNnUWtbZ11nW+//W1dZU/9P93fv33fr +42tf2evPb+fv5+dn42ff39vnzdfj/3e6Vb1r39XZ1dPnzWPHa+dj2ePfSe9Na1v/THdZY2P/ +411rY2dPVevvZ+v/b0vV30TTY3f3/2fbV+Pnd2/rV9FdY1t3Tk93X05b61dnd//nb9/O1dPJ +ysLJycfL383F1dfP1+Pb59X/0//j51vZZ2tjX11ZX1dMU0NJRkdbTVdKd2NjVVFOSVdTY01r +Z0/jY+Pv0+vfyevf79XfVclv41X/W0/vVe/va+fj02vvzkrNy1vf58tR1cJvzcrv38zNzMzK +0b/b6//Xb/fE3cX/08pJwP/b51lbTe87Ttc5/0NExi652y+0Lsn3N8tLVzi9PTXEP2/nQ11b +W81Ld8VB18w2x0TA2U9r0dXT9/fbxE7f72PFWc1Jz8vT79nD3cDDZ8S668P/XbvGTcPdv13/ +x9Pnx+tXy2vRTzr31ztM7z5vWUdTQ0zbPDjOU0HrTlNNz1VdTffvWW9N7+P/R2fd2U/OTV3Z +W0dL31FH68tZ0d/P2cr30f/M/2PGy8rC48i7ycBfu71jy9tjumvXzP/Ld1fZW1XdS0/nUU9X +X01bQ9FTPf9Fb1tCb0lX2T1X0VHbV0jnU81KP75RY8rrZ8LZ7/dZwWtOv/drxv9bu0y5wky6 +TffXPtnf/+PMUW/Z//dCWVnfW1NDUc9v4+dVv9dVZ1Vv2UZN6+/VU2Nf/+t3S1dv72dGXcx3 +a//j2//3Z3fjzlNO61Pb70xr41ffb0/ba2vfd+PK1c3CztnX19nX0cbRz8fVxcPbydfZ083j +3c/jW1vf49/P1ePf1+d372dbS01LSj9MSEVHSkRKTERESEpDXUFLTUlHRk9ZVU1nRU9bVWNb +3/fv2ev349v/0+dr49PTys/RzsvXzdvJx9nH2cjLzc/Rx8vKycvIzMXOyMPIxcjPzdHb2evX +02/jZ3f3VWNrWWtdSE5LS0tCR0dESUpISEhHSUBIRkhJRElMSkpNSFFRTE5KVVFRU2Nv2e/v +zdvO1cnLxcfAxMPCw8jEyNXG2c7ZztvVzdXT0dHPz9PZ19Hj09fb3dnf3+//d29TTldOSkVF +Q0dHR0hCSkhMS0lVTUtOSU1OWUxfU2v3V//Z29HZysnIycHIvb2+v77FwMXJz9PX6/dbb1tX +WVtVV2dnUWtfWfddXWf/6+dn7+fv5+9n32tnWVNZVU9NT09OT0dZTWtZU1tTXVVRWVNTV1FV +XV9jWVl3b///b2d3a+vb2cnXzsvOzMzKzcvFzsXDysTHw8rKxMzK0dHT39Xd59vr3+P32+Pn +32fdb9/r69vv79/v493v7+9db1tjVU5XS0tKSkVJRUQ/QD89QTw/PDs9OzxAPD5BQ0RLS1FR +W2dd79nVyMPCv7y+vby7vLq9ury4vb25vb7AxL/DyM7MytXZ2+vj/1tvV11ZWWNdb29TW09f +SltNTFtjVVNTSlFKRExISkhNSE5JS0xLS05MV1NfV2tfX1VbZ2v3/+fV39Prys/d09Xf39HV +3d3KycjT183f0+fj29fT3ePR4+Pj29/P59vv3+/r59vr1d9r9+//d99Zd1dRVU5dTndnd2Pr +Z+tjY1lTU01rUU5ORktPRUpNS1lPU1lMb1lbVV1vU2tv72fn2evZ0dPNzcnPzcnKxca/xMC+ +vr6/xca/wczIzM7P3dPf/29v92dna1VMU05DSFFRQUtBQT8+PEJAP0E/QURGSUlNU1VdZ1ld +99939+PPd9Pd3/fP38/b1dvXzsvPzNfP48vj1czZxcfIy9PAxcbKxs3Rz8jH2dXT49tf/+db +d3dnY13rTWtRWVlDW09MTUhJQUJIS0ZJSU1ISEtKT1tPXUxfTVdXXV33Y2v33f/X2+v/39t3 +zd/X3eff1d3Z3dPv6+fv3dvZ18jHy8LIx8jHw8jFxsfNzuPf23fZ3fdr/+9fWVdVU0pRS0hP +R0pBS0tEVUtTT1lITE5RT2NTX29nb+v32efTz9HIysvRxsjLzcvJys7Mz9XT1dfd3dnj28/d +3e/f9+tbXVVTW0hPREtIRlFHT0xPSklJQ05GSVFPTl1RW1tfV+tvU3dv1eNr99/r19nZ0dXb +ys7VzMnKysrMzcvR09nX0+Pd1c/T0dvj593Rb+PZ6+fj5//rW2/vZ/9jZ2tjb2Nj73d3a2tr +d2dbb3dnWWdV73dbd1FrUVlMWU9fVV1dW1n/Z/9fa19VWWtbb19V19dd4//XzG/j60fE29nJ +VdXDVczZVdvF/93bW9tOY9dPb2dJV1FOX0RX/29rXW/v5/f3593Z0//XzufRztPnY89n5+tr +3e9v3+Nvd1vfb2/dY2Pf3e9rW3dvWetrVWdvY13rZ2tr2Xfb4+/V791j7/fv3f/rd/fnd9nr +a+td//9Vb1dn429fZ3fra3dnd/djW1XrW/93X293Wffjd2PnVXdnd1f/a11j92ffXXf3791v +5//n32P3a+Nj01fO/93P99fb2+fT2d3n7//d5+fr5+Pf3czZ2dPT19HN3dnX6+v/a//3Y3db +V2ddXWtXd2drb1lRWU5bYz9IW1VXd0j/W1VvVVvbTmtOY1F3WU5XW19vV11fV19bV/9rb9vX +69Pd29fV39HZzs7NzcrM1dfG29PM29PZ38jT68fN38hZ68lN01HRT2vnWdVX91NZZ1N3b1tv +T2NMX1H/UVVbX2tVZ2NPVVdjWV1OWVVjT1VZWV9Zd2Nf7/dv49lrzslnv9fFv9nr38nvyt3f +zmfOXd1d//fX4113V3dZ91f/71ljV1dXZ3drY19nV09XW19ZY1tVWW9bWWNnY29j42vj1+vj +zMrOzGfna8JVvlfZ3+93601vd//Td29jd1FdX+/352Pr//fv7+/Z2f/j6+/v/2v/b3dVWe9f +a2NjX3dvX+N3d9vZY9XXWcdZxshT3WN31ddEyU9O7/9ZX0RZXWt3V1tPVU9bTmtdY3dba3dr +79nf29/d5+P/a2dr62fr53ff6+vr3d33z9nR19Pb2c7bz83P593v2d932/9vY03n12dN70jv +//9O70ffRtlX/01bZ05ZX2NJX0pOX2NVXVdTZ2Nv72P35+fr1dvZ2dPR08vR19PM49XT59// +4+vnb+vn/+fv52/ZW+Pvb/d3a11na+9nb+dnZ+//a29rX2NZa1tZY2Nfb2f/a2/vX2v/91// +//f/4+Pr6+/v4+fj7+vdd/9vb29rd2/3d3dX3dnvX19P49n/0WNr32dv/1nv3etvb/fr29vX +49/d1+/v3efj92tvZ3dvb3d39/fv5+/r7//j6/9db2NRZ09nXV9ZV11rWVljb193Z2tfb2Nv +a2tnX2N3Z+vj79/r3d/Z1c/R087bzdvZ2+Pr28/d3d3v7/f/92Nra1tXXWtXWV1ZZ3dfZ29r +Y2dbW///929rb2/rd1trb29X/1ddXVnvX29j71/ra+fn/2933+9v29HT30+/zdfZ3d/Lzr/f +0c5ra9nV1+Pj3Q== + +--Outermost_Trek-- diff --git a/Documentation/Content/FrequentlyAskedQuestions.aml b/Documentation/Content/FrequentlyAskedQuestions.aml index e477ba967b..11dd7bfeef 100644 --- a/Documentation/Content/FrequentlyAskedQuestions.aml +++ b/Documentation/Content/FrequentlyAskedQuestions.aml @@ -1,4 +1,4 @@ - + If you only care about getting a flattened list of the mailbox addresses in one of - the address headers, you can simply do something like this: + the address headers, you can do something like this: foreach (var mailbox in message.To.Mailboxes) diff --git a/Documentation/Content/GettingStarted.aml b/Documentation/Content/GettingStarted.aml index 85e326b79f..0b1e0491a4 100644 --- a/Documentation/Content/GettingStarted.aml +++ b/Documentation/Content/GettingStarted.aml @@ -1,4 +1,4 @@ - + Package Manager Console http://docs.nuget.org/docs/start-here/using-the-package-manager-console - , simply enter the following command: + , enter the following command: Install-Package MimeKit @@ -97,7 +97,7 @@ Once you've opened the appropriate MimeKit solution file in either Xamarin Studio or - Visual Studio (either will work), you can simply + Visual Studio (either will work), you can choose the Debug or Release build configuration and then build. diff --git a/Documentation/Content/WorkingWithPGP.aml b/Documentation/Content/WorkingWithPGP.aml index 2ed3759e1f..2b5026bb97 100644 --- a/Documentation/Content/WorkingWithPGP.aml +++ b/Documentation/Content/WorkingWithPGP.aml @@ -1,4 +1,4 @@ - + multipart/encrypted mime-type to encapsulate encrypted data. To encrypt any T:MimeKit.MimeEntity, - simply use the + use the Overload:MimeKit.Cryptography.MultipartEncrypted.Create diff --git a/Documentation/Content/WorkingWithSMime.aml b/Documentation/Content/WorkingWithSMime.aml index e6cdb0a169..e1222c1b98 100644 --- a/Documentation/Content/WorkingWithSMime.aml +++ b/Documentation/Content/WorkingWithSMime.aml @@ -1,4 +1,4 @@ - + multipart/encrypted MIME part to encapsulate encrypted content like OpenPGP, S/MIME uses application/pkcs7-mime. To encrypt any T:MimeKit.MimeEntity, - simply use the + use the Overload:MimeKit.Cryptography.ApplicationPkcs7Mime.Encrypt diff --git a/Documentation/Documentation.shfbproj b/Documentation/Documentation.shfbproj index 1ee6febd83..56c2af87e5 100644 --- a/Documentation/Documentation.shfbproj +++ b/Documentation/Documentation.shfbproj @@ -1,5 +1,5 @@ - + @@ -7,7 +7,7 @@ AnyCPU 2.0 59115814-a1e3-46ae-ae30-4065ae8f4caf - 1.9.9.0 + 2017.9.26.0 Documentation Documentation @@ -85,16 +85,23 @@ + + + + + + + @@ -110,17 +117,12 @@ - - BouncyCastle - {4c235092-820c-4deb-9074-d356fb797d8b} - True - MimeKit - {d5f54a4f-d84b-430f-9271-f7861e285b3e} + {76894ada-0818-4556-83bd-6510d8ea2809} True - + \ No newline at end of file diff --git a/Documentation/Examples/ArcSignerExample.cs b/Documentation/Examples/ArcSignerExample.cs new file mode 100644 index 0000000000..d51ab53750 --- /dev/null +++ b/Documentation/Examples/ArcSignerExample.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using MimeKit; +using MimeKit.Cryptography; + +namespace ArcSignerExample +{ + class ExampleArcSigner : ArcSigner + { + public ExampleArcSigner (Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (stream, domain, selector, algorithm) + { + } + + public DummyArcSigner (string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (fileName, domain, selector, algorithm) + { + } + + public DummyArcSigner (AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (key, domain, selector, algorithm) + { + } + + public string AuthenticationServiceIdentifier { + get; set; + } + + /// + /// Generate the ARC-Authentication-Results header. + /// + /// + /// The ARC-Authentication-Results header contains information detailing the results of + /// authenticating/verifying the message via ARC, DKIM, SPF, etc. + /// + /// In the following implementation, we assume that all of these authentication results + /// have already been determined by other mail software that has added some Authentication-Results + /// headers containing this information. + /// + /// Note: This method is used when ArcSigner.Sign() is called instead of ArcSigner.SignAsync(). + /// + protected override AuthenticationResults GenerateArcAuthenticationResults (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + var results = new AuthenticationResults (AuthenticationServiceIdentifier); + + for (int i = 0; i < message.Headers.Count; i++) { + var header = message.Headers[i]; + + if (header.Id != HeaderId.AuthenticationResults) + continue; + + if (!AuthenticationResults.TryParse (header.RawValue, out AuthenticationResults authres)) + continue; + + if (authres.AuthenticationServiceIdentifier != AuthenticationServiceIdentifier) + continue; + + foreach (var result in authres.Results) { + if (!results.Results.Any (r => r.Method == result.Method)) + results.Results.Add (result); + } + } + + return results; + } + + protected override Task GenerateArcAuthenticationResultsAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + return Task.FromResult (GenerateArcAuthenticationResults (options, message, cancellationToken)); + } + } + + class Program + { + public static void Main (string[] args) + { + if (args.Length < 2) { + Help (); + return; + } + + for (int i = 0; i < args.Length; i++) { + if (args[i] == "--help") { + Help (); + return; + } + } + + var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }; + var signer = new ExampleArcSigner ("privatekey.pem", "example.com", "brisbane", DkimSignatureAlgorithm.RsaSha256) { + HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, + BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, + AgentOrUserIdentifier = "@eng.example.com", + }; + + if (!File.Exists (args[0])) { + Console.Error.WriteLine ("{0}: No such file.", args[0]); + return; + } + + var message = MimeMessage.Load (args[0]); + + // Prepare the message body to be sent over a 7bit transport (such as older versions of SMTP). + // Note: If the SMTP server you will be sending the message over supports the 8BITMIME extension, + // then you can use `EncodingConstraint.EightBit` instead. + message.Prepare (EncodingConstraint.SevenBit); + + signer.Sign (message, headers); + + using (var stream = File.Create (args[1])) + message.WriteTo (stream); + } + + static void Help () + { + Console.WriteLine ("Usage is: ArcSigner [options] [message] [output]"); + Console.WriteLine (); + Console.WriteLine ("Options:"); + Console.WriteLine (" --help This help menu."); + } + } +} diff --git a/Documentation/Examples/ArcVerifierExample.cs b/Documentation/Examples/ArcVerifierExample.cs new file mode 100644 index 0000000000..7b3b8e2c0c --- /dev/null +++ b/Documentation/Examples/ArcVerifierExample.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Heijden.DNS; + +using Org.BouncyCastle.Crypto; + +using MimeKit; +using MimeKit.Cryptography; + +namespace ArcVerifierExample +{ + // Note: By using the DkimPublicKeyLocatorBase, we avoid having to parse the DNS TXT records + // in order to get the public key ourselves. + class ExamplePublicKeyLocator : DkimPublicKeyLocatorBase + { + readonly Dictionary cache; + readonly Resolver resolver; + + public ExamplePublicKeyLocator () + { + cache = new Dictionary (); + + resolver = new Resolver ("8.8.8.8") { + TransportType = TransportType.Udp, + UseCache = true, + Retries = 3 + }; + } + + AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationToken cancellationToken) + { + var query = selector + "._domainkey." + domain; + AsymmetricKeyParameter pubkey; + + // checked if we've already fetched this key + if (cache.TryGetValue (query, out pubkey)) + return pubkey; + + // make a DNS query + var response = resolver.Query (query, QType.TXT); + var builder = new StringBuilder (); + + // combine the TXT records into 1 string buffer + foreach (var record in response.RecordsTXT) { + foreach (var text in record.TXT) + builder.Append (text); + } + + var txt = builder.ToString (); + + // DkimPublicKeyLocatorBase provides us with this helpful method. + pubkey = GetPublicKey (txt); + + cache.Add (query, pubkey); + + return pubkey; + } + + public AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + var methodList = methods.Split (new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < methodList.Length; i++) { + if (methodList[i] == "dns/txt") + return DnsLookup (domain, selector, cancellationToken); + } + + throw new NotSupportedException (string.Format ("{0} does not include any suported lookup methods.", methods)); + } + + public Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + return Task.Run (() => { + return LocatePublicKey (methods, domain, selector, cancellationToken); + }, cancellationToken); + } + } + + class Program + { + public static void Main (string[] args) + { + if (args.Length == 0) { + Help (); + return; + } + + for (int i = 0; i < args.Length; i++) { + if (args[i] == "--help") { + Help (); + return; + } + } + + var locator = new ExamplePublicKeyLocator (); + var verifier = new ArcVerifier (locator); + + for (int i = 0; i < args.Length; i++) { + if (!File.Exists (args[i])) { + Console.Error.WriteLine ("{0}: No such file.", args[i]); + continue; + } + + Console.Write ("{0} -> ", args[i]); + + var message = MimeMessage.Load (args[i]); + var result = verifier.Verify (message); + + switch (result.Chain) { + case ArcSignatureValidationResult.None: + Console.WriteLine ("No ARC signatures to verify."); + break; + case ArcSignatureValidationResult.Pass: + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine ("PASS"); + Console.ResetColor (); + break; + case ArcSignatureValidationResult.Fail: + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine ("FAIL"); + Console.ResetColor (); + break; + } + } + } + + static void Help () + { + Console.WriteLine ("Usage is: ArcVerifier [options] [messages]"); + Console.WriteLine (); + Console.WriteLine ("Options:"); + Console.WriteLine (" --help This help menu."); + } + } +} diff --git a/Documentation/Examples/AttachmentExamples.cs b/Documentation/Examples/AttachmentExamples.cs new file mode 100644 index 0000000000..ed81446736 --- /dev/null +++ b/Documentation/Examples/AttachmentExamples.cs @@ -0,0 +1,76 @@ +using System; + +using MimeKit; + +namespace MimeKit.Examples +{ + public static class AttachmentExamples + { + public static void SaveMimePart (MimePart attachment, string fileName) + { + #region SaveMimePart + using (var stream = File.Create (fileName)) + attachment.Content.DecodeTo (stream); + #endregion SaveMimePart + } + + public static void SaveMimePart (MessagePart attachment, string fileName) + { + #region SaveMessagePart + using (var stream = File.Create (fileName)) + attachment.Message.WriteTo (stream); + #endregion SaveMessagePart + } + + public static void SaveAttachments (MimeMessage message) + { + #region SaveAttachments + foreach (var attachment in message.Attachments) { + if (attachment is MessagePart) { + var fileName = attachment.ContentDisposition?.FileName; + var rfc822 = (MessagePart) attachment; + + if (string.IsNullOrEmoty (fileName)) + fileName = "attached-message.eml"; + + using (var stream = File.Create (fileName)) + rfc822.Message.WriteTo (stream); + } else { + var part = (MimePart) attachment; + var fileName = part.FileName; + + using (var stream = File.Create (fileName)) + part.Content.DecodeTo (stream); + } + } + #endregion SaveAttachments + } + + public static void SaveAttachments (MimeMessage message) + { + #region SaveBodyParts + foreach (var bodyPart in message.BodyParts) { + if (!bodyPart.IsAttachment) + continue; + + if (bodyPart is MessagePart) { + var fileName = attachment.ContentDisposition?.FileName; + var rfc822 = (MessagePart) attachment; + + if (string.IsNullOrEmoty (fileName)) + fileName = "attached-message.eml"; + + using (var stream = File.Create (fileName)) + rfc822.Message.WriteTo (stream); + } else { + var part = (MimePart) attachment; + var fileName = part.FileName; + + using (var stream = File.Create (fileName)) + part.Content.DecodeTo (stream); + } + } + #endregion SaveBodyParts + } + } +} diff --git a/Documentation/Examples/BodyBuilder.cs b/Documentation/Examples/BodyBuilder.cs index 1a5fbe973d..034659228b 100644 --- a/Documentation/Examples/BodyBuilder.cs +++ b/Documentation/Examples/BodyBuilder.cs @@ -1,12 +1,21 @@ -var message = new MimeMessage (); -message.From.Add (new MailboxAddress ("Joey", "joey@friends.com")); -message.To.Add (new MailboxAddress ("Alice", "alice@wonderland.com")); -message.Subject = "How you doin?"; +using MimeKit; -var builder = new BodyBuilder (); +namespace BodyBuilderExamples +{ + public class Program + { + public static void Complex () + { + #region Complex + var message = new MimeMessage (); + message.From.Add (new MailboxAddress ("Joey", "joey@friends.com")); + message.To.Add (new MailboxAddress ("Alice", "alice@wonderland.com")); + message.Subject = "How you doin?"; -// Set the plain-text version of the message text -builder.TextBody = @"Hey Alice, + var builder = new BodyBuilder (); + + // Set the plain-text version of the message text + builder.TextBody = @"Hey Alice, What are you up to this weekend? Monica is throwing one of her parties on Saturday and I was hoping you could make it. @@ -16,20 +25,54 @@ Will you be my +1? -- Joey "; -// Set the html version of the message text -builder.HtmlBody = @"

Hey Alice,
+ // In order to reference selfie.jpg from the html text, we'll need to add it + // to builder.LinkedResources and then use its Content-Id value in the img src. + var image = builder.LinkedResources.Add (@"C:\Users\Joey\Documents\Selfies\selfie.jpg"); + image.ContentId = MimeUtils.GenerateMessageId (); + + // Set the html version of the message text + builder.HtmlBody = string.Format (@"

Hey Alice,

What are you up to this weekend? Monica is throwing one of her parties on Saturday and I was hoping you could make it.

Will you be my +1?

-- Joey
-

"; +
", image.ContentId); + + // We may also want to attach a calendar event for Monica's party... + builder.Attachments.Add (@"C:\Users\Joey\Documents\party.ics"); + + // Now we just need to set the message body and we're done + message.Body = builder.ToMessageBody (); + #endregion + } + + public static void Simple () + { + #region Simple + var message = new MimeMessage (); + message.From.Add (new MailboxAddress ("Joey", "joey@friends.com")); + message.To.Add (new MailboxAddress ("Alice", "alice@wonderland.com")); + message.Subject = "How you doin?"; + + var builder = new BodyBuilder (); + + // Set the plain-text version of the message text + builder.TextBody = @"Hey Alice, -// Since sexy-pose.jpg is referenced from the html text, we'll need to add it -// to builder.LinkedResources -builder.LinkedResources.Add ("C:\\Users\\Joey\\Documents\\Selfies\\sexy-pose.jpg"); +What are you up to this weekend? Monica is throwing one of her parties on +Saturday and I was hoping you could make it. + +Will you be my +1? + +-- Joey +"; -// We may also want to attach a calendar event for Monica's party... -builder.Attachments.Add ("C:\\Users\Joey\\Documents\\party.ics"); + // We may also want to attach a calendar event for Monica's party... + builder.Attachments.Add (@"C:\Users\Joey\Documents\party.ics"); -// Now we just need to set the message body and we're done -message.Body = builder.ToMessageBody (); + // Now we just need to set the message body and we're done + message.Body = builder.ToMessageBody (); + #endregion + } + } +} diff --git a/Documentation/Examples/CreateMultipartAlternative.cs b/Documentation/Examples/CreateMultipartAlternative.cs index cca41d260d..4067578e23 100644 --- a/Documentation/Examples/CreateMultipartAlternative.cs +++ b/Documentation/Examples/CreateMultipartAlternative.cs @@ -5,7 +5,7 @@ // Note: it is important that the text/html part is added second, because it is the // most expressive version and (probably) the most faithful to the sender's WYSIWYG // editor. -var alternative = new Multipart ("alternative"); +var alternative = new MultipartAlternative (); alternative.Add (plain); alternative.Add (html); diff --git a/Documentation/Examples/DkimExamples.cs b/Documentation/Examples/DkimExamples.cs new file mode 100644 index 0000000000..aec9f71e8c --- /dev/null +++ b/Documentation/Examples/DkimExamples.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; + +using MimeKit; + +namespace MimeKit.Examples +{ + public static class DkimExamples + { + #region DkimSign + public static void DkimSign (MimeMessage message) + { + var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }; + var signer = new DkimSigner ("privatekey.pem", "example.com", "brisbane", DkimSignatureAlgorithm.RsaSha256) { + HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, + BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, + AgentOrUserIdentifier = "@eng.example.com", + QueryMethod = "dns/txt", + }; + + // Prepare the message body to be sent over a 7bit transport (such as older versions of SMTP). + // Note: If the SMTP server you will be sending the message over supports the 8BITMIME extension, + // then you can use `EncodingConstraint.EightBit` instead. + message.Prepare (EncodingConstraint.SevenBit); + + signer.Sign (message, headers); + } + #endregion + } +} diff --git a/Documentation/Examples/DkimVerifierExample.cs b/Documentation/Examples/DkimVerifierExample.cs new file mode 100644 index 0000000000..d89389dfa0 --- /dev/null +++ b/Documentation/Examples/DkimVerifierExample.cs @@ -0,0 +1,142 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Heijden.DNS; + +using Org.BouncyCastle.Crypto; + +using MimeKit; +using MimeKit.Cryptography; + +namespace DkimVerifierExample +{ + // Note: By using the DkimPublicKeyLocatorBase, we avoid having to parse the DNS TXT records + // in order to get the public key ourselves. + class ExamplePublicKeyLocator : DkimPublicKeyLocatorBase + { + readonly Dictionary cache; + readonly Resolver resolver; + + public ExamplePublicKeyLocator () + { + cache = new Dictionary (); + + resolver = new Resolver ("8.8.8.8") { + TransportType = TransportType.Udp, + UseCache = true, + Retries = 3 + }; + } + + AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationToken cancellationToken) + { + var query = selector + "._domainkey." + domain; + AsymmetricKeyParameter pubkey; + + // checked if we've already fetched this key + if (cache.TryGetValue (query, out pubkey)) + return pubkey; + + // make a DNS query + var response = resolver.Query (query, QType.TXT); + var builder = new StringBuilder (); + + // combine the TXT records into 1 string buffer + foreach (var record in response.RecordsTXT) { + foreach (var text in record.TXT) + builder.Append (text); + } + + var txt = builder.ToString (); + + // DkimPublicKeyLocatorBase provides us with this helpful method. + pubkey = GetPublicKey (txt); + + cache.Add (query, pubkey); + + return pubkey; + } + + public AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + var methodList = methods.Split (new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < methodList.Length; i++) { + if (methodList[i] == "dns/txt") + return DnsLookup (domain, selector, cancellationToken); + } + + throw new NotSupportedException (string.Format ("{0} does not include any suported lookup methods.", methods)); + } + + public Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + return Task.Run (() => { + return LocatePublicKey (methods, domain, selector, cancellationToken); + }, cancellationToken); + } + } + + class Program + { + public static void Main (string[] args) + { + if (args.Length == 0) { + Help (); + return; + } + + for (int i = 0; i < args.Length; i++) { + if (args[i] == "--help") { + Help (); + return; + } + } + + var locator = new ExamplePublicKeyLocator (); + var verifier = new DkimVerifier (locator); + + for (int i = 0; i < args.Length; i++) { + if (!File.Exists (args[i])) { + Console.Error.WriteLine ("{0}: No such file.", args[i]); + continue; + } + + Console.Write ("{0} -> ", args[i]); + + var message = MimeMessage.Load (args[i]); + var index = message.Headers.IndexOf (HeaderId.DkimSignature); + + if (index == -1) { + Console.WriteLine ("NO SIGNATURE"); + continue; + } + + var dkim = message.Headers[index]; + + if (verifier.Verify (message, dkim)) { + // the DKIM-Signature header is valid! + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine ("VALID"); + Console.ResetColor (); + } else { + // the DKIM-Signature is invalid! + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine ("INVALID"); + Console.ResetColor (); + } + } + } + + static void Help () + { + Console.WriteLine ("Usage is: DkimVerifier [options] [messages]"); + Console.WriteLine (); + Console.WriteLine ("Options:"); + Console.WriteLine (" --help This help menu."); + } + } +} diff --git a/Documentation/Examples/ForwardExamples.cs b/Documentation/Examples/ForwardExamples.cs new file mode 100644 index 0000000000..a7ca86cd09 --- /dev/null +++ b/Documentation/Examples/ForwardExamples.cs @@ -0,0 +1,104 @@ +// +// MimeVisitorExamples.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2016 Xamarin Inc. (www.xamarin.com) +// +// 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. +// + +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Collections.Generic; + +using MimeKit; + +namespace MimeKit.Examples +{ + public static class ForwardExamples + { + #region ForwardAttached + public static MimeMessage Forward (MimeMessage original, MailboxAddress from, IEnumerable to) + { + var message = new MimeMessage (); + message.From.Add (from); + message.To.AddRange (to); + + // set the forwarded subject + if (!original.Subject.StartsWith ("FW:", StringComparison.OrdinalIgnoreCase)) + message.Subject = "FW: " + original.Subject; + else + message.Subject = original.Subject; + + // create the main textual body of the message + var text = new TextPart ("plain") { Text = "Here's the forwarded message:" }; + + // create the message/rfc822 attachment for the original message + var rfc822 = new MessagePart { Message = original }; + + // create a multipart/mixed container for the text body and the forwarded message + var multipart = new Multipart ("mixed"); + multipart.Add (text); + multipart.Add (rfc822); + + // set the multipart as the body of the message + message.Body = multipart; + + return message; + } + #endregion ForwardAttached + + #region ForwardInline + public static MimeMessage Forward (MimeMessage original, MailboxAddress from, IEnumerable to) + { + var message = new MimeMessage (); + message.From.Add (from); + message.To.AddRange (to); + + // set the forwarded subject + if (!original.Subject.StartsWith ("FW:", StringComparison.OrdinalIgnoreCase)) + message.Subject = "FW: " + original.Subject; + else + message.Subject = original.Subject; + + // quote the original message text + using (var text = new StringWriter ()) { + text.WriteLine (); + text.WriteLine ("-----Original Message-----"); + test.WriteLine ("From: {0}", original.From); + text.WriteLine ("Sent: {0}", DateUtils.FormatDate (original.Date)); + text.WriteLine ("To: {0}", original.To); + text.WriteLine ("Subject: {0}", original.Subject); + text.WriteLine (); + + text.Write (original.TextBody); + + message.Body = new TextPart ("plain") { + Text = text.ToString () + }; + } + + return message; + } + #endregion ForwardInline + } +} \ No newline at end of file diff --git a/Documentation/Examples/MessageDeliveryStatusExamples.cs b/Documentation/Examples/MessageDeliveryStatusExamples.cs new file mode 100644 index 0000000000..8658655842 --- /dev/null +++ b/Documentation/Examples/MessageDeliveryStatusExamples.cs @@ -0,0 +1,86 @@ +// +// MessageDeliveryStatusExamples.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// +// 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. +// + +using System; +using System.Linq; + +using MimeKit; + +namespace MimeKit.Examples { + public static class MessageDeliveryStatusExamples + { + #region ProcessDeliveryStatusNotification + public void ProcessDeliveryStatusNotification (MimeMessage message) + { + var report = message.Body as MultipartReport; + + if (report == null || report.ReportType == null || !report.ReportType.Equals ("delivery-status", StringComparison.OrdinalIgnoreCase)) { + // this is not a delivery status notification message... + return; + } + + // process the report + foreach (var mds in report.OfType ()) { + // process the status groups - each status group represents a different recipient + + // The first status group contains information about the message + var envelopeId = mds.StatusGroups[0]["Original-Envelope-Id"]; + + // all of the other status groups contain per-recipient information + for (int i = 1; i < mds.StatusGroups.Length; i++) { + var recipient = mds.StatusGroups[i]["Original-Recipient"]; + var action = mds.StatusGroups[i]["Action"]; + + if (recipient == null) + recipient = mds.StatusGroups[i]["Final-Recipient"]; + + // the recipient string should be in the form: "rfc822;user@domain.com" + var index = recipient.IndexOf (';'); + var address = recipient.Substring (index + 1); + + switch (action) { + case "failed": + Console.WriteLine ("Delivery of message {0} failed for {1}", envelopeId, address); + break; + case "delayed": + Console.WriteLine ("Delivery of message {0} has been delayed for {1}", envelopeId, address); + break; + case "delivered": + Console.WriteLine ("Delivery of message {0} has been delivered to {1}", envelopeId, address); + break; + case "relayed": + Console.WriteLine ("Delivery of message {0} has been relayed for {1}", envelopeId, address); + break; + case "expanded": + Console.WriteLine ("Delivery of message {0} has been delivered to {1} and relayed to the the expanded recipients", envelopeId, address); + break; + } + } + } + } + #endregion + } +} diff --git a/Documentation/Examples/MimeIterator.cs b/Documentation/Examples/MimeIterator.cs index a2760e38a0..56e9831aaa 100644 --- a/Documentation/Examples/MimeIterator.cs +++ b/Documentation/Examples/MimeIterator.cs @@ -1,16 +1,17 @@ var attachments = new List (); var multiparts = new List (); -var iter = new MimeIterator (message); -// collect our list of attachments and their parent multiparts -while (iter.MoveNext ()) { - var multipart = iter.Parent as Multipart; - var part = iter.Current as MimePart; +using (var iter = new MimeIterator (message)) { + // collect our list of attachments and their parent multiparts + while (iter.MoveNext ()) { + var multipart = iter.Parent as Multipart; + var part = iter.Current as MimePart; - if (multipart != null && part != null && part.IsAttachment) { - // keep track of each attachment's parent multipart - multiparts.Add (multipart); - attachments.Add (part); + if (multipart != null && part != null && part.IsAttachment) { + // keep track of each attachment's parent multipart + multiparts.Add (multipart); + attachments.Add (part); + } } } diff --git a/Documentation/Examples/MimeVisitorExamples.cs b/Documentation/Examples/MimeVisitorExamples.cs new file mode 100644 index 0000000000..43ac3451a0 --- /dev/null +++ b/Documentation/Examples/MimeVisitorExamples.cs @@ -0,0 +1,547 @@ +// +// MimeVisitorExamples.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2016 Xamarin Inc. (www.xamarin.com) +// +// 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. +// + +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Collections.Generic; + +using MimeKit; +using MimeKit.Text; +using MimeKit.Tnef; + +namespace MimeKit.Examples +{ + #region HtmlPreviewVisitor + /// + /// Visits a MimeMessage and generates HTML suitable to be rendered by a browser control. + /// + class HtmlPreviewVisitor : MimeVisitor + { + List stack = new List (); + List attachments = new List (); + readonly string tempDir; + string body; + + /// + /// Creates a new HtmlPreviewVisitor. + /// + /// A temporary directory used for storing image files. + public HtmlPreviewVisitor (string tempDirectory) + { + tempDir = tempDirectory; + } + + /// + /// The list of attachments that were in the MimeMessage. + /// + public IList Attachments { + get { return attachments; } + } + + /// + /// The HTML string that can be set on the BrowserControl. + /// + public string HtmlBody { + get { return body ?? string.Empty; } + } + + protected override void VisitMultipartAlternative (MultipartAlternative alternative) + { + // walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful + for (int i = alternative.Count - 1; i >= 0 && body == null; i--) + alternative[i].Accept (this); + } + + protected override void VisitMultipartRelated (MultipartRelated related) + { + var root = related.Root; + + // push this multipart/related onto our stack + stack.Add (related); + + // visit the root document + root.Accept (this); + + // pop this multipart/related off our stack + stack.RemoveAt (stack.Count - 1); + } + + // look up the image based on the img src url within our multipart/related stack + bool TryGetImage (string url, out MimePart image) + { + UriKind kind; + int index; + Uri uri; + + if (Uri.IsWellFormedUriString (url, UriKind.Absolute)) + kind = UriKind.Absolute; + else if (Uri.IsWellFormedUriString (url, UriKind.Relative)) + kind = UriKind.Relative; + else + kind = UriKind.RelativeOrAbsolute; + + try { + uri = new Uri (url, kind); + } catch { + image = null; + return false; + } + + for (int i = stack.Count - 1; i >= 0; i--) { + if ((index = stack[i].IndexOf (uri)) == -1) + continue; + + image = stack[i][index] as MimePart; + return image != null; + } + + image = null; + + return false; + } + + // Save the image to our temp directory and return a "file://" url suitable for + // the browser control to load. + // Note: if you'd rather embed the image data into the HTML, you can construct a + // "data:" url instead. + string SaveImage (MimePart image, string url) + { + string fileName = url.Replace (':', '_').Replace ('\\', '_').Replace ('/', '_'); + + string path = Path.Combine (tempDir, fileName); + + if (!File.Exists (path)) { + using (var output = File.Create (path)) + image.Content.DecodeTo (output); + } + + return "file://" + path.Replace ('\\', '/'); + } + + // Replaces urls that refer to images embedded within the message with + // "file://" urls that the browser control will actually be able to load. + void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) + { + if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) { + ctx.WriteTag (htmlWriter, false); + + // replace the src attribute with a file:// URL + foreach (var attribute in ctx.Attributes) { + if (attribute.Id == HtmlAttributeId.Src) { + MimePart image; + string url; + + if (!TryGetImage (attribute.Value, out image)) { + htmlWriter.WriteAttribute (attribute); + continue; + } + + url = SaveImage (image, attribute.Value); + + htmlWriter.WriteAttributeName (attribute.Name); + htmlWriter.WriteAttributeValue (url); + } else { + htmlWriter.WriteAttribute (attribute); + } + } + } else if (ctx.TagId == HtmlTagId.Body && !ctx.IsEndTag) { + ctx.WriteTag (htmlWriter, false); + + // add and/or replace oncontextmenu="return false;" + foreach (var attribute in ctx.Attributes) { + if (attribute.Name.ToLowerInvariant () == "oncontextmenu") + continue; + + htmlWriter.WriteAttribute (attribute); + } + + htmlWriter.WriteAttribute ("oncontextmenu", "return false;"); + } else { + // pass the tag through to the output + ctx.WriteTag (htmlWriter, true); + } + } + + protected override void VisitTextPart (TextPart entity) + { + TextConverter converter; + + if (body != null) { + // since we've already found the body, treat this as an attachment + attachments.Add (entity); + return; + } + + if (entity.IsHtml) { + converter = new HtmlToHtml { + HtmlTagCallback = HtmlTagCallback + }; + } else if (entity.IsFlowed) { + var flowed = new FlowedToHtml (); + string delsp; + + if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp)) + flowed.DeleteSpace = delsp.ToLowerInvariant () == "yes"; + + converter = flowed; + } else { + converter = new TextToHtml (); + } + + body = converter.Convert (entity.Text); + } + + protected override void VisitTnefPart (TnefPart entity) + { + // extract any attachments in the MS-TNEF part + attachments.AddRange (entity.ExtractAttachments ()); + } + + protected override void VisitMessagePart (MessagePart entity) + { + // treat message/rfc822 parts as attachments + attachments.Add (entity); + } + + protected override void VisitMimePart (MimePart entity) + { + // realistically, if we've gotten this far, then we can treat this as an attachment + // even if the IsAttachment property is false. + attachments.Add (entity); + } + } + #endregion + + #region ReplyVisitor + public class ReplyVisitor : MimeVisitor + { + readonly Stack stack = new Stack (); + MimeMessage message; + MimeEntity body; + + /// + /// Creates a new ReplyVisitor. + /// + public ReplyVisitor () + { + } + + /// + /// Gets the reply. + /// + /// The reply. + public MimeEntity Body { + get { return body; } + } + + void Push (MimeEntity entity) + { + var multipart = entity as Multipart; + + if (body == null) { + body = entity; + } else { + var parent = stack.Peek (); + parent.Add (entity); + } + + if (multipart != null) + stack.Push (multipart); + } + + void Pop () + { + stack.Pop (); + } + + public static string GetOnDateSenderWrote (MimeMessage message) + { + var sender = message.Sender != null ? message.Sender : message.From.Mailboxes.FirstOrDefault (); + var name = sender != null ? (!string.IsNullOrEmpty (sender.Name) ? sender.Name : sender.Address) : "someone"; + + return string.Format ("On {0}, {1} wrote:", message.Date.ToString ("f"), name); + } + + /// + /// Visit the specified message. + /// + /// The message. + public override void Visit (MimeMessage message) + { + this.message = message; + stack.Clear (); + + base.Visit (message); + } + + protected override void VisitMultipartAlternative (MultipartAlternative alternative) + { + var multipart = new MultipartAlternative (); + + Push (multipart); + + for (int i = 0; i < alternative.Count; i++) + alternative[i].Accept (this); + + Pop (); + } + + protected override void VisitMultipartRelated (MultipartRelated related) + { + var multipart = new MultipartRelated (); + var root = related.Root; + + Push (multipart); + + root.Accept (this); + + for (int i = 0; i < related.Count; i++) { + if (related[i] != root) + related[i].Accept (this); + } + + Pop (); + } + + protected override void VisitMultipart (Multipart multipart) + { + foreach (var part in multipart) { + if (part is MultipartAlternative) + part.Accept (this); + else if (part is MultipartRelated) + part.Accept (this); + else if (part is TextPart) + part.Accept (this); + } + } + + void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) + { + if (ctx.TagId == HtmlTagId.Body && !ctx.IsEmptyElementTag) { + if (ctx.IsEndTag) { + // end our opening
+ htmlWriter.WriteEndTag (HtmlTagId.BlockQuote); + + // pass the tag through to the output + ctx.WriteTag (htmlWriter, true); + } else { + // pass the tag through to the output + ctx.WriteTag (htmlWriter, true); + + // prepend the HTML reply with "On {DATE}, {SENDER} wrote:" + htmlWriter.WriteStartTag (HtmlTagId.P); + htmlWriter.WriteText (GetOnDateSenderWrote (message)); + htmlWriter.WriteEndTag (HtmlTagId.P); + + // Wrap the original content in a
+ htmlWriter.WriteStartTag (HtmlTagId.BlockQuote); + htmlWriter.WriteAttribute (HtmlAttributeId.Style, "border-left: 1px #ccc solid; margin: 0 0 0 .8ex; padding-left: 1ex;"); + + ctx.InvokeCallbackForEndTag = true; + } + } else { + // pass the tag through to the output + ctx.WriteTag (htmlWriter, true); + } + } + + string QuoteText (string text) + { + using (var quoted = new StringWriter ()) { + quoted.WriteLine (GetOnDateSenderWrote (message)); + + using (var reader = new StringReader (text)) { + string line; + + while ((line = reader.ReadLine ()) != null) { + quoted.Write ("> "); + quoted.WriteLine (line); + } + } + + return quoted.ToString (); + } + } + + protected override void VisitTextPart (TextPart entity) + { + string text; + + if (entity.IsHtml) { + var converter = new HtmlToHtml { + HtmlTagCallback = HtmlTagCallback + }; + + text = converter.Convert (entity.Text); + } else if (entity.IsFlowed) { + var converter = new FlowedToText (); + + text = converter.Convert (entity.Text); + text = QuoteText (text); + } else { + // quote the original message text + text = QuoteText (entity.Text); + } + + var part = new TextPart (entity.ContentType.MediaSubtype.ToLowerInvariant ()) { + Text = text + }; + + Push (part); + } + + protected override void VisitMessagePart (MessagePart entity) + { + // don't descend into message/rfc822 parts + } + } + #endregion + + public class Program + { + #region RenderMessage + void Render (MimeMessage message) + { + var tmpDir = Path.Combine (Path.GetTempPath (), message.MessageId); + var visitor = new HtmlPreviewVisitor (tmpDir); + + Directory.CreateDirectory (tmpDir); + + message.Accept (visitor); + + DisplayHtml (visitor.HtmlBody); + DisplayAttachments (visitor.Attachments); + } + #endregion + + #region ReplySimple + public static MimeMessage Reply (MimeMessage message, MailboxAddress from, bool replyToAll) + { + var reply = new MimeMessage (); + + reply.From.Add (from); + + // reply to the sender of the message + if (message.ReplyTo.Count > 0) { + reply.To.AddRange (message.ReplyTo); + } else if (message.From.Count > 0) { + reply.To.AddRange (message.From); + } else if (message.Sender != null) { + reply.To.Add (message.Sender); + } + + if (replyToAll) { + // include all of the other original recipients (removing ourselves from the list) + reply.To.AddRange (message.To.Mailboxes.Where (x => x.Address != from.Address)); + reply.Cc.AddRange (message.Cc.Mailboxes.Where (x => x.Address != from.Address)); + } + + // set the reply subject + if (!message.Subject.StartsWith ("Re:", StringComparison.OrdinalIgnoreCase)) + reply.Subject = "Re: " + message.Subject; + else + reply.Subject = message.Subject; + + // construct the In-Reply-To and References headers + if (!string.IsNullOrEmpty (message.MessageId)) { + reply.InReplyTo = message.MessageId; + foreach (var id in message.References) + reply.References.Add (id); + reply.References.Add (message.MessageId); + } + + // quote the original message text + using (var quoted = new StringWriter ()) { + var sender = message.Sender ?? message.From.Mailboxes.FirstOrDefault (); + var name = sender != null ? (!string.IsNullOrEmpty (sender.Name) ? sender.Name : sender.Address) : "someone"; + + quoted.WriteLine ("On {0}, {1} wrote:", message.Date.ToString ("f"), name); + using (var reader = new StringReader (message.TextBody)) { + string line; + + while ((line = reader.ReadLine ()) != null) { + quoted.Write ("> "); + quoted.WriteLine (line); + } + } + + reply.Body = new TextPart ("plain") { + Text = quoted.ToString () + }; + } + + return reply; + } + #endregion + + #region Reply + public static MimeMessage Reply (MimeMessage message, MailboxAddress from, bool replyToAll) + { + var visitor = new ReplyVisitor (); + var reply = new MimeMessage (); + + reply.From.Add (from); + + // reply to the sender of the message + if (message.ReplyTo.Count > 0) { + reply.To.AddRange (message.ReplyTo); + } else if (message.From.Count > 0) { + reply.To.AddRange (message.From); + } else if (message.Sender != null) { + reply.To.Add (message.Sender); + } + + if (replyToAll) { + // include all of the other original recipients (removing ourselves from the list) + reply.To.AddRange (message.To.Mailboxes.Where (x => x.Address != from.Address)); + reply.Cc.AddRange (message.Cc.Mailboxes.Where (x => x.Address != from.Address)); + } + + // set the reply subject + if (!message.Subject.StartsWith ("Re:", StringComparison.OrdinalIgnoreCase)) + reply.Subject = "Re: " + message.Subject; + else + reply.Subject = message.Subject; + + // construct the In-Reply-To and References headers + if (!string.IsNullOrEmpty (message.MessageId)) { + reply.InReplyTo = message.MessageId; + foreach (var id in message.References) + reply.References.Add (id); + reply.References.Add (message.MessageId); + } + + visitor.Visit (message); + + reply.Body = visitor.Body ?? new TextPart ("plain") { Text = ReplyVisitor.GetOnDateSenderWrote (message) + Environment.NewLine }; + + return reply; + } + #endregion + } +} diff --git a/Documentation/Examples/MultipartFormDataExample.cs b/Documentation/Examples/MultipartFormDataExample.cs index 722f490e73..157af96124 100644 --- a/Documentation/Examples/MultipartFormDataExample.cs +++ b/Documentation/Examples/MultipartFormDataExample.cs @@ -11,7 +11,7 @@ MimeEntity ParseMultipartFormData (HttpWebResponse response) { var contentType = ContentType.Parse (response.ContentType); - return MimeEntity.Parse (contentType, response.GetResponseStream ()); + return MimeEntity.Load (contentType, response.GetResponseStream ()); } #endregion diff --git a/Documentation/Examples/OpenPGPExamples.cs b/Documentation/Examples/OpenPGPExamples.cs index de4b40589b..6007cce257 100644 --- a/Documentation/Examples/OpenPGPExamples.cs +++ b/Documentation/Examples/OpenPGPExamples.cs @@ -30,7 +30,7 @@ public void RegisterMyGnuPGeContext () #region RegisterCustomContext // Note: by registering our custom context it becomes the default OpenPGP context // instantiated by MimeKit when methods such as Encrypt(), Decrypt(), Sign(), and - // Verify() are used without an expliit context. + // Verify() are used without an explicit context. CryptographyContext.Register (typeof (MyGnuPGContext)); #endregion } diff --git a/Documentation/Examples/SMimeExamples.cs b/Documentation/Examples/SMimeExamples.cs index ac6431b310..fa5de663e7 100644 --- a/Documentation/Examples/SMimeExamples.cs +++ b/Documentation/Examples/SMimeExamples.cs @@ -39,7 +39,7 @@ public void RegisterMySecureMimeContext () #region RegisterCustomContext // Note: by registering our custom context it becomes the default S/MIME context // instantiated by MimeKit when methods such as Encrypt(), Decrypt(), Sign(), and - // Verify() are used without an expliit context. + // Verify() are used without an explicit context. CryptographyContext.Register (typeof (MySecureMimeContext)); #endregion } diff --git a/FAQ.md b/FAQ.md index 613774e514..8585343797 100644 --- a/FAQ.md +++ b/FAQ.md @@ -42,7 +42,7 @@ container which you'll then want to add the message body to first. Once you've a then add MIME parts to it that contain the content of the files you'd like to attach, being sure to set the `Content-Disposition` header value to attachment. You'll probably also want to set the `filename` parameter on the `Content-Disposition` header as well as the `name` parameter on the `Content-Type` -header. The most convenient way to do this is to simply use the +header. The most convenient way to do this is to use the [MimePart.FileName](http://www.mimekit.net/docs/html/P_MimeKit_MimePart_FileName.htm) property which will set both parameters for you as well as setting the `Content-Disposition` header value to `attachment` if it has not already been set to something else. @@ -113,7 +113,7 @@ builder.Attachments.Add (@"C:\Users\Joey\Documents\party.ics"); message.Body = builder.ToMessageBody (); ``` -For more information, see [Creating Messages](http://www.mimekit.net/docs/html/CreatingMessages.htm). +For more information, see [Creating Messages](http://www.mimekit.net/docs/html/Creating-Messages.htm). ### Q: How do I get the main body of a message? @@ -190,7 +190,7 @@ for this: [TextBody](http://www.mimekit.net/docs/html/P_MimeKit_MimeMessage_Text appropriate body part with a `Content-Type` of `text/html` that can be interpreted as the message body. Likewise, the `TextBody` property can be used to get the `text/plain` version of the message body. -For more information, see [Working with Messages](http://www.mimekit.net/docs/html/WorkingWithMessages.htm). +For more information, see [Working with Messages](http://www.mimekit.net/docs/html/Working-With-Messages.htm). ### Q: How do I tell if a message has attachments? @@ -302,11 +302,17 @@ class HtmlPreviewVisitor : MimeVisitor return false; } - // Save the image to our temp directory and return a "file://" url suitable for - // the browser control to load. - // Note: if you'd rather embed the image data into the HTML, you can construct a - // "data:" url instead. - string SaveImage (MimePart image, string url) + /// + /// Get a file:// URI for the image attachment. + /// + /// + /// Saves the image attachment to a temp file and returns a file:// URI for the + /// temp file. + /// + /// The file:// URI. + /// The image attachment. + /// The original HTML image URL. + string GetFileUri (MimePart image, string url) { string fileName = url.Replace (':', '_').Replace ('\\', '_').Replace ('/', '_'); @@ -320,6 +326,28 @@ class HtmlPreviewVisitor : MimeVisitor return "file://" + path.Replace ('\\', '/'); } + /// + /// Get a file:// URI for the image attachment. + /// + /// + /// Saves the image attachment to a temp file and returns a file:// URI for the + /// temp file. + /// + /// The file:// URI. + /// The image attachment. + /// The original HTML image URL. + string GetDataUri (MimePart image) + { + using (var memory = new MemoryStream ()) { + image.Content.DecodeTo (memory); + var buffer = memory.GetBuffer (); + var length = (int) memory.Length; + var base64 = Convert.ToBase64String (buffer, 0, length); + + return string.Format ("data:{0};base64,{1}", image.ContentType.MimeType, base64); + } + } + // Replaces urls that refer to images embedded within the message with // "file://" urls that the browser control will actually be able to load. void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) @@ -338,7 +366,10 @@ class HtmlPreviewVisitor : MimeVisitor continue; } - url = SaveImage (image, attribute.Value); + // Note: you can either use a "file://" URI or you can use a + // "data:" URI, the choice is yours. + url = GetFileUri (image, attribute.Value); + //uri = GetDataUri (image); htmlWriter.WriteAttributeName (attribute.Name); htmlWriter.WriteAttributeValue (url); @@ -614,7 +645,7 @@ To: John Smith ``` If you only care about getting a flattened list of the mailbox addresses in a `From`, `To`, or `Cc` -header, you can simply do something like this: +header, you can do something like this: ```csharp foreach (var mailbox in message.To.Mailboxes) @@ -649,13 +680,12 @@ if (attachment.ContentDisposition.Parameters.TryGetValue ("filename", out param) param.EncodingMethod = ParameterEncodingMethod.Rfc2047; ``` -The other way is to use a [FormatOptions](http://www.mimekit.net/docs/html/T_MimeKit_FormatOptions.htm): +Or ```csharp -var options = FormatOptions.Default.Clone (); -options.ParameterEncodingMethod = ParameterEncodingMethod.Rfc2047; - -message.WriteTo (options, stream); +foreach (var param in attachment.ContentDisposition.Parameters) { + param.EncodingMethod = ParameterEncodingMethod.Rfc2047; +} ``` ### Q: How do I decrypt PGP messages that are embedded in the main message text? @@ -1102,7 +1132,7 @@ public static MimeMessage Forward (MimeMessage original, MailboxAddress from, IE } ``` -To forward a message by simply inlining the original message's text content, you can do something like this: +To forward a message by inlining the original message's text content, you can do something like this: ```csharp public static MimeMessage Forward (MimeMessage original, MailboxAddress from, IEnumerable to) @@ -1162,6 +1192,6 @@ MimeEntity ParseMultipartFormData (HttpWebResponse response) { var contentType = ContentType.Parse (response.ContentType); - return MimeEntity.Parse (contentType, response.GetResponseStream ()); + return MimeEntity.Load (contentType, response.GetResponseStream ()); } ``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..7614a032f3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2012-2020 .NET Foundation and Contributors + +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. \ No newline at end of file diff --git a/License.md b/License.md deleted file mode 100644 index 5810935a00..0000000000 --- a/License.md +++ /dev/null @@ -1,21 +0,0 @@ -## License Information - -MimeKit is Copyright (C) 2012-2016 Xamarin Inc. and is licensed under the MIT license: - - 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/Makefile b/Makefile deleted file mode 100644 index 28679160d1..0000000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -OUTDIR=MimeKit/bin/Release/lib/net40 -ASSEMBLY=$(OUTDIR)/MimeKit.dll -XMLDOCS=$(OUTDIR)/MimeKit.xml - -all: - xbuild /target:Build /p:Configuration=Release MimeKit.Net40.sln - -debug: - xbuild /target:Build /p:Configuration=Debug MimeKit.Net40.sln - -clean: - xbuild /target:Clean /p:Configuration=Debug MimeKit.Net40.sln - xbuild /target:Clean /p:Configuration=Release MimeKit.Net40.sln - -check-docs: - @find docs/en -name "*.xml" -exec grep -l "To be added." {} \; - -update-docs: $(ASSEMBLY) - mdoc update --delete -o docs/en $(ASSEMBLY) - -merge-docs: $(ASSEMBLY) $(XMLDOCS) - mdoc update -i $(XMLDOCS) -o docs/en $(ASSEMBLY) - -html-docs: - mdoc export-html --force-update --template=docs/github-pages.xslt -o ../MimeKit-docs/docs docs/en diff --git a/MimeKit.Coverity.sln b/MimeKit.Coverity.sln index 226b4ce9db..891c66a136 100644 --- a/MimeKit.Coverity.sln +++ b/MimeKit.Coverity.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.12 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30711.63 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Net45", "MimeKit\MimeKit.Net45.csproj", "{D5F54A4F-D84B-430F-9271-F7861E285B3E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MimeKit", "MimeKit\MimeKit.csproj", "{29F68E0E-0119-45CC-B6B4-A0C70FADA4AD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,14 +11,17 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.Build.0 = Release|Any CPU + {29F68E0E-0119-45CC-B6B4-A0C70FADA4AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29F68E0E-0119-45CC-B6B4-A0C70FADA4AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29F68E0E-0119-45CC-B6B4-A0C70FADA4AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29F68E0E-0119-45CC-B6B4-A0C70FADA4AD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FE861017-7B1A-4D73-AAEC-0DEBA21F6C52} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.StandardHeader = $1 diff --git a/MimeKit.Documentation.sln b/MimeKit.Documentation.sln index 3d20677c84..fc9df2585c 100644 --- a/MimeKit.Documentation.sln +++ b/MimeKit.Documentation.sln @@ -1,31 +1,31 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Net45", "MimeKit\MimeKit.Net45.csproj", "{D5F54A4F-D84B-430F-9271-F7861E285B3E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BouncyCastle", "submodules\bc-csharp\crypto\BouncyCastle.csproj", "{4C235092-820C-4DEB-9074-D356FB797D8B}" -EndProject Project("{7CF6DF6D-3B04-46F8-A40B-537D21BCA0B4}") = "Documentation", "Documentation\Documentation.shfbproj", "{59115814-A1E3-46AE-AE30-4065AE8F4CAF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MimeKit", "MimeKit\MimeKit.csproj", "{76894ADA-0818-4556-83BD-6510D8EA2809}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4C235092-820C-4DEB-9074-D356FB797D8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C235092-820C-4DEB-9074-D356FB797D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C235092-820C-4DEB-9074-D356FB797D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C235092-820C-4DEB-9074-D356FB797D8B}.Release|Any CPU.Build.0 = Release|Any CPU {59115814-A1E3-46AE-AE30-4065AE8F4CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {59115814-A1E3-46AE-AE30-4065AE8F4CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU {59115814-A1E3-46AE-AE30-4065AE8F4CAF}.Release|Any CPU.Build.0 = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.Build.0 = Release|Any CPU + {76894ADA-0818-4556-83BD-6510D8EA2809}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76894ADA-0818-4556-83BD-6510D8EA2809}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76894ADA-0818-4556-83BD-6510D8EA2809}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76894ADA-0818-4556-83BD-6510D8EA2809}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {59220391-9856-4F95-AC74-AD4BC4FF2011} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 @@ -38,7 +38,4 @@ Global $2.inheritsSet = VisualStudio $2.inheritsScope = text/plain EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection EndGlobal diff --git a/MimeKit.Mobile.sln b/MimeKit.Mobile.sln deleted file mode 100644 index 77d7620476..0000000000 --- a/MimeKit.Mobile.sln +++ /dev/null @@ -1,68 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Android", "MimeKit\MimeKit.Android.csproj", "{004B4019-62B7-4A15-AF2C-C20968845C46}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.iOS", "MimeKit\MimeKit.iOS.csproj", "{4C1288AD-12C8-4BF7-AED7-6C4DC539C856}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BouncyCastle.Android", "submodules\bc-csharp\crypto\BouncyCastle.Android.csproj", "{A0D302CB-8866-4AB1-98B9-F0772EABF5DF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BouncyCastle.iOS", "submodules\bc-csharp\crypto\BouncyCastle.iOS.csproj", "{0249241C-205E-4AC0-828B-90F822359B9E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {004B4019-62B7-4A15-AF2C-C20968845C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Release|Any CPU.Build.0 = Release|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Release|Any CPU.Build.0 = Release|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Release|Any CPU.Build.0 = Release|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = MimeKit\MimeKit.iOS.csproj - Policies = $0 - $0.StandardHeader = $1 - $1.Text = @\n${FileName}\n \nAuthor: ${AuthorName} <${AuthorEmail}>\n\nCopyright (c) ${Year} ${CopyrightHolder}\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n - $1.IncludeInNewFiles = True - $0.TextStylePolicy = $2 - $2.inheritsSet = null - $2.scope = text/x-csharp - $0.CSharpFormattingPolicy = $3 - $3.NamespaceBraceStyle = EndOfLine - $3.StructBraceStyle = EndOfLine - $3.EnumBraceStyle = EndOfLine - $3.AfterDelegateDeclarationParameterComma = True - $3.BeforeSizeOfParentheses = True - $3.BeforeTypeOfParentheses = True - $3.SpacesBeforeBrackets = False - $3.SpacesAfterTypecast = True - $3.AlignToFirstIndexerArgument = True - $3.inheritsSet = Mono - $3.inheritsScope = text/x-csharp - $3.scope = text/x-csharp - $0.TextStylePolicy = $4 - $4.FileWidth = 120 - $4.TabsToSpaces = False - $4.EolMarker = Unix - $4.inheritsSet = VisualStudio - $4.inheritsScope = text/plain - $4.scope = text/plain - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/MimeKit.Net45.sln b/MimeKit.Net45.sln deleted file mode 100644 index de0208c582..0000000000 --- a/MimeKit.Net45.sln +++ /dev/null @@ -1,78 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Net45", "MimeKit\MimeKit.Net45.csproj", "{D5F54A4F-D84B-430F-9271-F7861E285B3E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Data.Sqlite", "Mono.Data.Sqlite\Mono.Data.Sqlite.csproj", "{F26434C1-BA3D-41FB-B560-C009CB72B1B6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{0225FDB7-CF63-4402-BB30-9B149AC06C2E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{C2CA4C1F-78BB-41D1-8E31-F723FC88CF38}" - ProjectSection(SolutionItems) = preProject - .nuget\packages.config = .nuget\packages.config - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Release|Any CPU.Build.0 = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.Build.0 = Release|Any CPU - {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - Policies = $0 - $0.StandardHeader = $1 - $1.Text = @\n${FileName}\n \nAuthor: ${AuthorName} <${AuthorEmail}>\n\nCopyright (c) ${Year} ${CopyrightHolder}\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n - $0.TextStylePolicy = $2 - $2.scope = text/plain - $2.EolMarker = Unix - $0.CSharpFormattingPolicy = $3 - $3.NamespaceBraceStyle = EndOfLine - $3.StructBraceStyle = EndOfLine - $3.EnumBraceStyle = EndOfLine - $3.AfterDelegateDeclarationParameterComma = True - $3.BeforeSizeOfParentheses = True - $3.BeforeTypeOfParentheses = True - $3.SpacesBeforeBrackets = False - $3.SpacesAfterTypecast = True - $3.AlignToFirstIndexerArgument = True - $3.scope = text/x-csharp - $3.SpaceAfterCast = True - $3.IndentSwitchSection = False - $3.NewLinesForBracesInProperties = False - $3.NewLinesForBracesInAccessors = False - $3.NewLinesForBracesInAnonymousMethods = False - $3.NewLinesForBracesInControlBlocks = False - $3.NewLinesForBracesInAnonymousTypes = False - $3.NewLinesForBracesInObjectCollectionArrayInitializers = False - $3.NewLinesForBracesInLambdaExpressionBody = False - $3.NewLineForElse = False - $3.NewLineForCatch = False - $3.NewLineForFinally = False - $3.NewLineForClausesInQuery = False - $3.SpacingAfterMethodDeclarationName = True - $3.SpaceAfterMethodCallName = True - $0.TextStylePolicy = $4 - $4.FileWidth = 120 - $4.TabsToSpaces = False - $4.EolMarker = Unix - $4.inheritsSet = VisualStudio - $4.inheritsScope = text/plain - $4.scope = text/plain - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/MimeKit.sln b/MimeKit.sln index ea073db237..ea49bc916b 100644 --- a/MimeKit.sln +++ b/MimeKit.sln @@ -1,31 +1,24 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2010 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Net45", "MimeKit\MimeKit.Net45.csproj", "{D5F54A4F-D84B-430F-9271-F7861E285B3E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{0225FDB7-CF63-4402-BB30-9B149AC06C2E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Android", "MimeKit\MimeKit.Android.csproj", "{004B4019-62B7-4A15-AF2C-C20968845C46}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.iOS", "MimeKit\MimeKit.iOS.csproj", "{4C1288AD-12C8-4BF7-AED7-6C4DC539C856}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.Portable", "MimeKit\MimeKit.Portable.csproj", "{BE542CE1-F773-467E-8DED-D02B89C5040A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BouncyCastle.Android", "submodules\bc-csharp\crypto\BouncyCastle.Android.csproj", "{A0D302CB-8866-4AB1-98B9-F0772EABF5DF}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BouncyCastle.iOS", "submodules\bc-csharp\crypto\BouncyCastle.iOS.csproj", "{0249241C-205E-4AC0-828B-90F822359B9E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4B4EB921-F77E-4A51-897F-BBA7FA3E3468}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Data.Sqlite", "Mono.Data.Sqlite\Mono.Data.Sqlite.csproj", "{F26434C1-BA3D-41FB-B560-C009CB72B1B6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.Text.Encoding", "submodules\Portable.Text.Encoding\Portable.Text.Encoding\Portable.Text.Encoding.csproj", "{EEE48C75-11BE-4B50-B759-F85B5052D473}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.Text.Encoding.WindowsUniversal81", "submodules\Portable.Text.Encoding\Portable.Text.Encoding\Portable.Text.Encoding.WindowsUniversal81.csproj", "{B76A64F9-B00E-4243-AE89-5D024CA3B436}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "UnitTests\UnitTests.csproj", "{88EC8D73-8099-4DD6-B78B-C21FCED97EA1}" + ProjectSection(ProjectDependencies) = postProject + {F26434C1-BA3D-41FB-B560-C009CB72B1B6} = {F26434C1-BA3D-41FB-B560-C009CB72B1B6} + {559F9C27-70F6-44C5-8F55-7292DBBC8F87} = {559F9C27-70F6-44C5-8F55-7292DBBC8F87} + EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit.WindowsUniversal81", "MimeKit\MimeKit.WindowsUniversal81.csproj", "{D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKit", "MimeKit\MimeKit.csproj", "{559F9C27-70F6-44C5-8F55-7292DBBC8F87}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MimeKit.NetStandard", "MimeKit\MimeKit.NetStandard.csproj", "{E8667DCE-A5BB-4D30-9815-FC8959E447F5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{1D6B883A-ABC9-4AC2-9E05-963D1D3F40EB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,54 +26,22 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E}.Release|Any CPU.Build.0 = Release|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E}.Release|Any CPU.Build.0 = Release|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {004B4019-62B7-4A15-AF2C-C20968845C46}.Release|Any CPU.Build.0 = Release|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856}.Release|Any CPU.Build.0 = Release|Any CPU - {BE542CE1-F773-467E-8DED-D02B89C5040A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE542CE1-F773-467E-8DED-D02B89C5040A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE542CE1-F773-467E-8DED-D02B89C5040A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE542CE1-F773-467E-8DED-D02B89C5040A}.Release|Any CPU.Build.0 = Release|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF}.Release|Any CPU.Build.0 = Release|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0249241C-205E-4AC0-828B-90F822359B9E}.Release|Any CPU.Build.0 = Release|Any CPU {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {F26434C1-BA3D-41FB-B560-C009CB72B1B6}.Release|Any CPU.Build.0 = Release|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Release|Any CPU.Build.0 = Release|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Release|Any CPU.Build.0 = Release|Any CPU - {D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C}.Release|Any CPU.Build.0 = Release|Any CPU - {E8667DCE-A5BB-4D30-9815-FC8959E447F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E8667DCE-A5BB-4D30-9815-FC8959E447F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E8667DCE-A5BB-4D30-9815-FC8959E447F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E8667DCE-A5BB-4D30-9815-FC8959E447F5}.Release|Any CPU.Build.0 = Release|Any CPU + {88EC8D73-8099-4DD6-B78B-C21FCED97EA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88EC8D73-8099-4DD6-B78B-C21FCED97EA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88EC8D73-8099-4DD6-B78B-C21FCED97EA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88EC8D73-8099-4DD6-B78B-C21FCED97EA1}.Release|Any CPU.Build.0 = Release|Any CPU + {559F9C27-70F6-44C5-8F55-7292DBBC8F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {559F9C27-70F6-44C5-8F55-7292DBBC8F87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {559F9C27-70F6-44C5-8F55-7292DBBC8F87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {559F9C27-70F6-44C5-8F55-7292DBBC8F87}.Release|Any CPU.Build.0 = Release|Any CPU + {1D6B883A-ABC9-4AC2-9E05-963D1D3F40EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D6B883A-ABC9-4AC2-9E05-963D1D3F40EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D6B883A-ABC9-4AC2-9E05-963D1D3F40EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D6B883A-ABC9-4AC2-9E05-963D1D3F40EB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MimeKit/AsyncMimeParser.cs b/MimeKit/AsyncMimeParser.cs index 70ee29bfde..763aadffb6 100644 --- a/MimeKit/AsyncMimeParser.cs +++ b/MimeKit/AsyncMimeParser.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -30,8 +30,8 @@ using System.Diagnostics; using System.Threading.Tasks; -using MimeKit.Utils; using MimeKit.IO; +using MimeKit.Utils; namespace MimeKit { public partial class MimeParser @@ -47,7 +47,7 @@ async Task ReadAheadAsync (int atleast, int save, CancellationToken cancell if (nread > 0) { inputEnd += nread; - offset += nread; + position += nread; } else { eos = true; } @@ -80,8 +80,7 @@ async Task StepByteOrderMarkAsync (CancellationToken cancellationToken) async Task StepMboxMarkerAsync (CancellationToken cancellationToken) { - bool complete = false; - bool needInput; + bool complete; int left = 0; mboxMarkerLength = 0; @@ -96,11 +95,9 @@ async Task StepMboxMarkerAsync (CancellationToken cancellationToken) return; } - needInput = false; - unsafe { fixed (byte* inbuf = input) { - StepMboxMarker (inbuf, ref needInput, ref complete, ref left); + complete = StepMboxMarker (inbuf, ref left); } } } while (!complete); @@ -117,6 +114,8 @@ async Task StepHeadersAsync (CancellationToken cancellationToken) bool valid = true; int left = 0; + headerBlockBegin = GetOffset (inputIndex); + boundary = BoundaryType.None; ResetRawHeaderData (); headers.Clear (); @@ -126,29 +125,43 @@ async Task StepHeadersAsync (CancellationToken cancellationToken) unsafe { fixed (byte *inbuf = input) { if (!StepHeaders (inbuf, ref scanningFieldName, ref checkFolded, ref midline, ref blank, ref valid, ref left)) - return; + break; } } var available = await ReadAheadAsync (left + 1, 0, cancellationToken).ConfigureAwait (false); - if (available == 0) { + if (available == left) { // EOF reached before we reached the end of the headers... - if (left > 0) { - AppendRawHeaderData (inputIndex, left); - inputIndex = inputEnd; - } + if (scanningFieldName && left > 0) { + // EOF reached right in the middle of a header field name. Throw an error. + // + // See private email from Feb 8, 2018 which contained a sample message w/o + // any breaks between the header and message body. The file also did not + // end with a newline sequence. + state = MimeParserState.Error; + } else { + // EOF reached somewhere in the middle of the value. + // + // Append whatever data we've got left and pretend we found the end + // of the header value (and the header block). + // + // For more details, see https://github.com/jstedfast/MimeKit/pull/51 + // and https://github.com/jstedfast/MimeKit/issues/348 + if (left > 0) { + AppendRawHeaderData (inputIndex, left); + inputIndex = inputEnd; + } - ParseAndAppendHeader (); + ParseAndAppendHeader (); - // fail gracefully by pretending we found the end of the headers... - // - // For more details, see https://github.com/jstedfast/MimeKit/pull/51 - // and https://github.com/jstedfast/MimeKit/issues/348 - state = MimeParserState.Content; - return; + state = MimeParserState.Content; + } + break; } } while (true); + + headerBlockEnd = GetOffset (inputIndex); } async Task SkipLineAsync (bool consumeNewLine, CancellationToken cancellationToken) @@ -183,29 +196,18 @@ async Task StepAsync (CancellationToken cancellationToken) case MimeParserState.MessageHeaders: case MimeParserState.Headers: await StepHeadersAsync (cancellationToken).ConfigureAwait (false); + toplevel = false; break; } return state; } - struct ScanContentResults - { - public readonly BoundaryType Boundary; - public readonly bool IsEmpty; - - public ScanContentResults (BoundaryType boundary, bool empty) - { - Boundary = boundary; - IsEmpty = empty; - } - } - - async Task ScanContentAsync (Stream content, bool trimNewLine, CancellationToken cancellationToken) + async Task ScanContentAsync (Stream content, bool trimNewLine, CancellationToken cancellationToken) { int atleast = Math.Max (ReadAheadSize, GetMaxBoundaryLength ()); - BoundaryType found = BoundaryType.None; int contentIndex = inputIndex; + var formats = new bool[2]; bool midline = false; int nleft; @@ -215,24 +217,24 @@ async Task ScanContentAsync (Stream content, bool trimNewLin nleft = inputEnd - inputIndex; if (await ReadAheadAsync (atleast, 2, cancellationToken).ConfigureAwait (false) <= 0) { + boundary = BoundaryType.Eos; contentIndex = inputIndex; - found = BoundaryType.Eos; break; } unsafe { fixed (byte* inbuf = input) { - ScanContent (inbuf, ref contentIndex, ref nleft, ref midline, ref found); + ScanContent (inbuf, ref contentIndex, ref nleft, ref midline, ref formats); } } - } while (found == BoundaryType.None); + } while (boundary == BoundaryType.None); if (contentIndex < inputIndex) content.Write (input, contentIndex, inputIndex - contentIndex); - var empty = content.Length == 0; + var isEmpty = content.Length == 0; - if (found != BoundaryType.Eos && trimNewLine) { + if (boundary != BoundaryType.Eos && trimNewLine) { // the last \r\n belongs to the boundary if (content.Length > 0) { if (input[inputIndex - 2] == (byte) '\r') @@ -242,45 +244,57 @@ async Task ScanContentAsync (Stream content, bool trimNewLin } } - return new ScanContentResults (found, empty); + return new ScanContentResult (formats, isEmpty); } - async Task ConstructMimePartAsync (MimePart part, CancellationToken cancellationToken) + async Task ConstructMimePartAsync (MimePart part, MimeEntityEndEventArgs args, CancellationToken cancellationToken) { - ScanContentResults results; + long endOffset, beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; + ScanContentResult result; Stream content; if (persistent) { - long begin = GetOffset (inputIndex); - long end; - using (var measured = new MeasuringStream ()) { - results = await ScanContentAsync (measured, true, cancellationToken).ConfigureAwait (false); - end = begin + measured.Length; + result = await ScanContentAsync (measured, true, cancellationToken).ConfigureAwait (false); + endOffset = beginOffset + measured.Length; } - content = new BoundStream (stream, begin, end, true); + content = new BoundStream (stream, beginOffset, endOffset, true); } else { content = new MemoryBlockStream (); - results = await ScanContentAsync (content, true, cancellationToken).ConfigureAwait (false); - content.Seek (0, SeekOrigin.Begin); + + try { + result = await ScanContentAsync (content, true, cancellationToken).ConfigureAwait (false); + content.Seek (0, SeekOrigin.Begin); + } catch { + content.Dispose (); + throw; + } + + endOffset = beginOffset + content.Length; } - if (!results.IsEmpty) - part.Content = new MimeContent (content, part.ContentTransferEncoding); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); - return results.Boundary; + if (!result.IsEmpty) + part.Content = new MimeContent (content, part.ContentTransferEncoding) { NewLineFormat = result.Format }; + else + content.Dispose (); } - async Task ConstructMessagePartAsync (MessagePart part, CancellationToken cancellationToken) + async Task ConstructMessagePartAsync (MessagePart rfc822, MimeEntityEndEventArgs args, int depth, CancellationToken cancellationToken) { - BoundaryType found; + var beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; if (bounds.Count > 0) { int atleast = Math.Max (ReadAheadSize, GetMaxBoundaryLength ()); - if (await ReadAheadAsync (atleast, 0, cancellationToken).ConfigureAwait (false) <= 0) - return BoundaryType.Eos; + if (await ReadAheadAsync (atleast, 0, cancellationToken).ConfigureAwait (false) <= 0) { + boundary = BoundaryType.Eos; + return; + } unsafe { fixed (byte* inbuf = input) { @@ -293,17 +307,18 @@ async Task ConstructMessagePartAsync (MessagePart part, Cancellati while (*inptr != (byte) '\n') inptr++; - found = CheckBoundary (inputIndex, start, (int) (inptr - start)); + boundary = CheckBoundary (inputIndex, start, (int) (inptr - start)); - switch (found) { + switch (boundary) { case BoundaryType.ImmediateEndBoundary: case BoundaryType.ImmediateBoundary: case BoundaryType.ParentBoundary: - return found; + return; case BoundaryType.ParentEndBoundary: // ignore "From " boundaries, broken mailers tend to include these... - if (!IsMboxMarker (start)) - return found; + if (!IsMboxMarker (start)) { + return; + } break; } } @@ -311,116 +326,199 @@ async Task ConstructMessagePartAsync (MessagePart part, Cancellati } // parse the headers... - state = MimeParserState.Headers; + state = MimeParserState.MessageHeaders; if (await StepAsync (cancellationToken).ConfigureAwait (false) == MimeParserState.Error) { // Note: this either means that StepHeaders() found the end of the stream // or an invalid header field name at the start of the message headers, // which likely means that this is not a valid MIME stream? - return BoundaryType.Eos; + boundary = BoundaryType.Eos; + return; } var message = new MimeMessage (options, headers, RfcComplianceMode.Loose); - var type = GetContentType (null); + var messageArgs = new MimeMessageEndEventArgs (message, rfc822) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeMessageBegin (messageArgs); if (preHeaderBuffer.Length > 0) { message.MboxMarker = new byte[preHeaderLength]; Buffer.BlockCopy (preHeaderBuffer, 0, message.MboxMarker, 0, preHeaderLength); } - var entity = options.CreateEntity (type, headers, true); + var type = GetContentType (null); + var entity = options.CreateEntity (type, headers, true, depth); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + message.Body = entity; if (entity is Multipart) - found = await ConstructMultipartAsync ((Multipart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMultipartAsync ((Multipart) entity, entityArgs, depth + 1, cancellationToken).ConfigureAwait (false); else if (entity is MessagePart) - found = await ConstructMessagePartAsync ((MessagePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMessagePartAsync ((MessagePart) entity, entityArgs, depth + 1, cancellationToken).ConfigureAwait (false); else - found = await ConstructMimePartAsync ((MimePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMimePartAsync ((MimePart) entity, entityArgs, cancellationToken).ConfigureAwait (false); + + rfc822.Message = message; - part.Message = message; + var endOffset = GetEndOffset (inputIndex); + messageArgs.HeadersEndOffset = entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + messageArgs.EndOffset = entityArgs.EndOffset = endOffset; - return found; + OnMimeEntityEnd (entityArgs); + OnMimeMessageEnd (messageArgs); + + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); } - async Task MultipartScanPreambleAsync (Multipart multipart, CancellationToken cancellationToken) + async Task MultipartScanPreambleAsync (Multipart multipart, CancellationToken cancellationToken) { using (var memory = new MemoryStream ()) { - var found = await ScanContentAsync (memory, false, cancellationToken).ConfigureAwait (false); + long offset = GetOffset (inputIndex); + + //OnMultipartPreambleBegin (multipart, offset); + await ScanContentAsync (memory, false, cancellationToken).ConfigureAwait (false); multipart.RawPreamble = memory.ToArray (); - return found.Boundary; + //OnMultipartPreambleEnd (multipart, offset + memory.Length); } } - async Task MultipartScanEpilogueAsync (Multipart multipart, CancellationToken cancellationToken) + async Task MultipartScanEpilogueAsync (Multipart multipart, CancellationToken cancellationToken) { using (var memory = new MemoryStream ()) { - var found = await ScanContentAsync (memory, true, cancellationToken).ConfigureAwait (false); - multipart.RawEpilogue = found.IsEmpty ? null : memory.ToArray (); - return found.Boundary; + long offset = GetOffset (inputIndex); + + //OnMultipartEpilogueBegin (multipart, offset); + var result = await ScanContentAsync (memory, true, cancellationToken).ConfigureAwait (false); + multipart.RawEpilogue = result.IsEmpty ? null : memory.ToArray (); + //OnMultipartEpilogueEnd (multipart, offset + memory.Length); } } - async Task MultipartScanSubpartsAsync (Multipart multipart, CancellationToken cancellationToken) + async Task MultipartScanSubpartsAsync (Multipart multipart, int depth, CancellationToken cancellationToken) { - BoundaryType found; + //var beginOffset = GetOffset (inputIndex); do { + //OnMultipartBoundaryBegin (multipart, beginOffset); + // skip over the boundary marker - if (!await SkipLineAsync (true, cancellationToken).ConfigureAwait (false)) - return BoundaryType.Eos; + if (!await SkipLineAsync (true, cancellationToken).ConfigureAwait (false)) { + //OnMultipartBoundaryEnd (multipart, GetOffset (inputIndex)); + boundary = BoundaryType.Eos; + return; + } + + //OnMultipartBoundaryEnd (multipart, GetOffset (inputIndex)); + + var beginLineNumber = lineNumber; // parse the headers state = MimeParserState.Headers; - if (await StepAsync (cancellationToken).ConfigureAwait (false) == MimeParserState.Error) - return BoundaryType.Eos; + if (await StepAsync (cancellationToken).ConfigureAwait (false) == MimeParserState.Error) { + boundary = BoundaryType.Eos; + return; + } + + if (state == MimeParserState.Boundary) { + if (headers.Count == 0) { + if (boundary == BoundaryType.ImmediateBoundary) { + //beginOffset = GetOffset (inputIndex); + continue; + } + return; + } + + // This part has no content, but that will be handled in ConstructMultipartAsync() + // or ConstructMimePartAsync(). + } //if (state == ParserState.Complete && headers.Count == 0) // return BoundaryType.EndBoundary; var type = GetContentType (multipart.ContentType); - var entity = options.CreateEntity (type, headers, false); + var entity = options.CreateEntity (type, headers, false, depth); + var entityArgs = new MimeEntityEndEventArgs (entity, multipart) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); if (entity is Multipart) - found = await ConstructMultipartAsync ((Multipart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMultipartAsync ((Multipart) entity, entityArgs, depth + 1, cancellationToken).ConfigureAwait (false); else if (entity is MessagePart) - found = await ConstructMessagePartAsync ((MessagePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMessagePartAsync ((MessagePart) entity, entityArgs, depth + 1, cancellationToken).ConfigureAwait (false); else - found = await ConstructMimePartAsync ((MimePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMimePartAsync ((MimePart) entity, entityArgs, cancellationToken).ConfigureAwait (false); - multipart.Add (entity); - } while (found == BoundaryType.ImmediateBoundary); + var endOffset = GetEndOffset (inputIndex); + entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + entityArgs.EndOffset = endOffset; + + OnMimeEntityEnd (entityArgs); - return found; + //beginOffset = endOffset; + multipart.Add (entity); + } while (boundary == BoundaryType.ImmediateBoundary); } - async Task ConstructMultipartAsync (Multipart multipart, CancellationToken cancellationToken) + async Task ConstructMultipartAsync (Multipart multipart, MimeEntityEndEventArgs args, int depth, CancellationToken cancellationToken) { - var boundary = multipart.Boundary; + var beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; + var marker = multipart.Boundary; + long endOffset; - if (boundary == null) { + if (marker == null) { #if DEBUG Debug.WriteLine ("Multipart without a boundary encountered!"); #endif // Note: this will scan all content into the preamble... - return await MultipartScanPreambleAsync (multipart, cancellationToken).ConfigureAwait (false); + await MultipartScanPreambleAsync (multipart, cancellationToken).ConfigureAwait (false); + + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + return; } - PushBoundary (boundary); + PushBoundary (marker); - var found = await MultipartScanPreambleAsync (multipart, cancellationToken).ConfigureAwait (false); - if (found == BoundaryType.ImmediateBoundary) - found = await MultipartScanSubpartsAsync (multipart, cancellationToken).ConfigureAwait (false); + await MultipartScanPreambleAsync (multipart, cancellationToken).ConfigureAwait (false); + if (boundary == BoundaryType.ImmediateBoundary) + await MultipartScanSubpartsAsync (multipart, depth, cancellationToken).ConfigureAwait (false); + + if (boundary == BoundaryType.ImmediateEndBoundary) { + //OnMultipartEndBoundaryBegin (multipart, GetEndOffset (inputIndex)); - if (found == BoundaryType.ImmediateEndBoundary) { // consume the end boundary and read the epilogue (if there is one) multipart.WriteEndBoundary = true; await SkipLineAsync (false, cancellationToken).ConfigureAwait (false); PopBoundary (); - return await MultipartScanEpilogueAsync (multipart, cancellationToken).ConfigureAwait (false); + //OnMultipartEndBoundaryEnd (multipart, GetOffset (inputIndex)); + + await MultipartScanEpilogueAsync (multipart, cancellationToken).ConfigureAwait (false); + + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + return; } + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + multipart.WriteEndBoundary = false; // We either found the end of the stream or we found a parent's boundary @@ -428,15 +526,12 @@ async Task ConstructMultipartAsync (Multipart multipart, Cancellat unsafe { fixed (byte* inbuf = input) { - if (found == BoundaryType.ParentEndBoundary && FoundImmediateBoundary (inbuf, true)) - return BoundaryType.ImmediateEndBoundary; - - if (found == BoundaryType.ParentBoundary && FoundImmediateBoundary (inbuf, false)) - return BoundaryType.ImmediateBoundary; + if (boundary == BoundaryType.ParentEndBoundary && FoundImmediateBoundary (inbuf, true)) + boundary = BoundaryType.ImmediateEndBoundary; + else if (boundary == BoundaryType.ParentBoundary && FoundImmediateBoundary (inbuf, false)) + boundary = BoundaryType.ImmediateBoundary; } } - - return found; } /// @@ -493,31 +588,48 @@ async Task ConstructMultipartAsync (Multipart multipart, Cancellat // Note: if a previously parsed MimePart's content has been read, // then the stream position will have moved and will need to be // reset. - if (persistent && stream.Position != offset) - stream.Seek (offset, SeekOrigin.Begin); + if (persistent && stream.Position != position) + stream.Seek (position, SeekOrigin.Begin); + + var beginLineNumber = lineNumber; state = MimeParserState.Headers; + toplevel = true; + if (await StepAsync (cancellationToken).ConfigureAwait (false) == MimeParserState.Error) throw new FormatException ("Failed to parse entity headers."); var type = GetContentType (null); - BoundaryType found; // Note: we pass 'false' as the 'toplevel' argument here because // we want the entity to consume all of the headers. - var entity = options.CreateEntity (type, headers, false); + var entity = options.CreateEntity (type, headers, false, 0); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + if (entity is Multipart) - found = await ConstructMultipartAsync ((Multipart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMultipartAsync ((Multipart) entity, entityArgs, 0, cancellationToken).ConfigureAwait (false); else if (entity is MessagePart) - found = await ConstructMessagePartAsync ((MessagePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMessagePartAsync ((MessagePart) entity, entityArgs, 0, cancellationToken).ConfigureAwait (false); else - found = await ConstructMimePartAsync ((MimePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMimePartAsync ((MimePart) entity, entityArgs, cancellationToken).ConfigureAwait (false); + + var endOffset = GetEndOffset (inputIndex); + entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + entityArgs.EndOffset = endOffset; - if (found != BoundaryType.Eos) + if (boundary != BoundaryType.Eos) state = MimeParserState.Complete; else state = MimeParserState.Eos; + OnMimeEntityEnd (entityArgs); + return entity; } @@ -540,13 +652,11 @@ async Task ConstructMultipartAsync (Multipart multipart, Cancellat /// public async Task ParseMessageAsync (CancellationToken cancellationToken = default (CancellationToken)) { - BoundaryType found; - // Note: if a previously parsed MimePart's content has been read, // then the stream position will have moved and will need to be // reset. - if (persistent && stream.Position != offset) - stream.Seek (offset, SeekOrigin.Begin); + if (persistent && stream.Position != position) + stream.Seek (position, SeekOrigin.Begin); // scan the from-line if we are parsing an mbox while (state != MimeParserState.MessageHeaders) { @@ -558,44 +668,67 @@ async Task ConstructMultipartAsync (Multipart multipart, Cancellat } } + toplevel = true; + // parse the headers + var beginLineNumber = lineNumber; if (state < MimeParserState.Content && await StepAsync (cancellationToken).ConfigureAwait (false) == MimeParserState.Error) throw new FormatException ("Failed to parse message headers."); var message = new MimeMessage (options, headers, RfcComplianceMode.Loose); + var messageArgs = new MimeMessageEndEventArgs (message) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeMessageBegin (messageArgs); if (format == MimeFormat.Mbox && options.RespectContentLength) { - bounds[0].ContentEnd = -1; + contentEnd = 0; for (int i = 0; i < headers.Count; i++) { - if (!headers[i].Field.Equals ("Content-Length", StringComparison.OrdinalIgnoreCase)) + if (headers[i].Id != HeaderId.ContentLength) continue; var value = headers[i].RawValue; - int length, index = 0; + int index = 0; - if (!ParseUtils.TryParseInt32 (value, ref index, value.Length, out length)) + if (!ParseUtils.SkipWhiteSpace (value, ref index, value.Length)) continue; - long endOffset = GetOffset (inputIndex) + length; + if (!ParseUtils.TryParseInt32 (value, ref index, value.Length, out int length)) + continue; - bounds[0].ContentEnd = endOffset; + contentEnd = GetOffset (inputIndex) + length; break; } } var type = GetContentType (null); - var entity = options.CreateEntity (type, headers, true); + var entity = options.CreateEntity (type, headers, true, 0); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + message.Body = entity; if (entity is Multipart) - found = await ConstructMultipartAsync ((Multipart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMultipartAsync ((Multipart) entity, entityArgs, 0, cancellationToken).ConfigureAwait (false); else if (entity is MessagePart) - found = await ConstructMessagePartAsync ((MessagePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMessagePartAsync ((MessagePart) entity, entityArgs, 0, cancellationToken).ConfigureAwait (false); else - found = await ConstructMimePartAsync ((MimePart) entity, cancellationToken).ConfigureAwait (false); + await ConstructMimePartAsync ((MimePart) entity, entityArgs, cancellationToken).ConfigureAwait (false); - if (found != BoundaryType.Eos) { + var endOffset = GetEndOffset (inputIndex); + messageArgs.HeadersEndOffset = entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + messageArgs.EndOffset = entityArgs.EndOffset = endOffset; + + if (boundary != BoundaryType.Eos) { if (format == MimeFormat.Mbox) state = MimeParserState.MboxMarker; else @@ -604,6 +737,9 @@ async Task ConstructMultipartAsync (Multipart multipart, Cancellat state = MimeParserState.Eos; } + OnMimeEntityEnd (entityArgs); + OnMimeMessageEnd (messageArgs); + return message; } } diff --git a/MimeKit/AttachmentCollection.cs b/MimeKit/AttachmentCollection.cs index b4291440bd..70a960b461 100644 --- a/MimeKit/AttachmentCollection.cs +++ b/MimeKit/AttachmentCollection.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Buffers; using System.Collections; using System.Collections.Generic; @@ -39,13 +40,18 @@ namespace MimeKit { /// /// The is only used when building a message body with a . /// + /// + /// + /// public class AttachmentCollection : IList { + const int BufferLength = 4096; + readonly List attachments; readonly bool linked; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -60,7 +66,7 @@ public AttachmentCollection (bool linkedResources) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -94,10 +100,10 @@ public bool IsReadOnly { } /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// The attachment at the specified index. /// The index. @@ -128,20 +134,32 @@ public MimeEntity this [int index] { static void LoadContent (MimePart attachment, Stream stream) { var content = new MemoryBlockStream (); - var filter = new BestEncodingFilter (); - var buf = new byte[4096]; - int index, length; - int nread; - - while ((nread = stream.Read (buf, 0, buf.Length)) > 0) { - filter.Filter (buf, 0, nread, out index, out length); - content.Write (buf, 0, nread); + + if (attachment.ContentType.IsMimeType ("text", "*")) { + var buf = ArrayPool.Shared.Rent (BufferLength); + var filter = new BestEncodingFilter (); + int index, length; + int nread; + + try { + while ((nread = stream.Read (buf, 0, BufferLength)) > 0) { + filter.Filter (buf, 0, nread, out index, out length); + content.Write (buf, 0, nread); + } + + filter.Flush (buf, 0, 0, out index, out length); + } finally { + ArrayPool.Shared.Return (buf); + } + + attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); + } else { + attachment.ContentTransferEncoding = ContentEncoding.Base64; + stream.CopyTo (content, 4096); } - filter.Flush (buf, 0, 0, out index, out length); content.Position = 0; - attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.Content = new MimeContent (content); } @@ -152,27 +170,42 @@ static ContentType GetMimeType (string fileName) return ContentType.Parse (mimeType); } - MimePart CreateAttachment (ContentType contentType, string fileName, Stream stream) + static string GetFileName (string path) { - MimePart attachment; + int index = path.LastIndexOf (Path.DirectorySeparatorChar); - if (contentType.IsMimeType ("text", "*")) { - attachment = new TextPart (contentType.MediaSubtype); - foreach (var param in contentType.Parameters) - attachment.ContentType.Parameters.Add (param); + return index > 0 ? path.Substring (index + 1) : path; + } - // TODO: should we try to auto-detect charsets if no charset parameter is specified? + MimeEntity CreateAttachment (ContentType contentType, string path, Stream stream) + { + var fileName = GetFileName (path); + MimeEntity attachment; + + if (contentType.IsMimeType ("message", "rfc822")) { + var message = MimeMessage.Load (stream); + + attachment = new MessagePart { Message = message }; } else { - attachment = new MimePart (contentType); + MimePart part; + + if (contentType.IsMimeType ("text", "*")) { + // TODO: should we try to auto-detect charsets if no charset parameter is specified? + part = new TextPart (contentType); + } else { + part = new MimePart (contentType); + } + + LoadContent (part, stream); + attachment = part; } - attachment.FileName = Path.GetFileName (fileName); - attachment.IsAttachment = !linked; + attachment.ContentDisposition = new ContentDisposition (linked ? ContentDisposition.Inline : ContentDisposition.Attachment); + attachment.ContentDisposition.FileName = fileName; + attachment.ContentType.Name = fileName; if (linked) - attachment.ContentLocation = new Uri (Path.GetFileName (fileName), UriKind.Relative); - - LoadContent (attachment, stream); + attachment.ContentLocation = new Uri (fileName, UriKind.Relative); return attachment; } @@ -351,7 +384,6 @@ public MimeEntity Add (string fileName, Stream stream) return attachment; } -#if !PORTABLE /// /// Add the specified attachment. /// @@ -406,6 +438,9 @@ public MimeEntity Add (string fileName, ContentType contentType) /// /// Adds the specified file as an attachment. /// + /// + /// + /// /// The newly added attachment . /// The name of the file. /// @@ -413,8 +448,7 @@ public MimeEntity Add (string fileName, ContentType contentType) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -444,7 +478,6 @@ public MimeEntity Add (string fileName) return attachment; } } -#endif /// /// Add the specified attachment. diff --git a/MimeKit/BodyBuilder.cs b/MimeKit/BodyBuilder.cs index 6b81e45052..bcf6730fdf 100644 --- a/MimeKit/BodyBuilder.cs +++ b/MimeKit/BodyBuilder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,14 +33,20 @@ namespace MimeKit { /// /// is a helper class for building common MIME body structures. /// + /// + /// + /// public class BodyBuilder { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . /// + /// + /// + /// public BodyBuilder () { LinkedResources = new AttachmentCollection (true); @@ -48,68 +54,83 @@ public BodyBuilder () } /// - /// Gets the attachments. + /// Get the attachments. /// /// /// Represents a collection of file attachments that will be included in the message. /// + /// + /// + /// /// The attachments. public AttachmentCollection Attachments { get; private set; } /// - /// Gets the linked resources. + /// Get the linked resources. /// /// /// Linked resources are a special type of attachment which are linked to from the . /// + /// + /// + /// /// The linked resources. public AttachmentCollection LinkedResources { get; private set; } /// - /// Gets or sets the text body. + /// Get or set the text body. /// /// /// Represents the plain-text formatted version of the message body. /// + /// + /// + /// /// The text body. public string TextBody { get; set; } /// - /// Gets or sets the html body. + /// Get or set the html body. /// /// /// Represents the html formatted version of the message body and may link to any of the . /// + /// + /// + /// /// The html body. public string HtmlBody { get; set; } /// - /// Constructs the message body based on the text-based bodies, the linked resources, and the attachments. + /// Construct the message body based on the text-based bodies, the linked resources, and the attachments. /// /// /// Combines the , , , /// and into the proper MIME structure suitable for display in many common /// mail clients. /// + /// + /// + /// /// The message body. public MimeEntity ToMessageBody () { MultipartAlternative alternative = null; MimeEntity body = null; - if (!string.IsNullOrEmpty (TextBody)) { + if (TextBody != null) { var text = new TextPart ("plain"); text.Text = TextBody; - if (!string.IsNullOrEmpty (HtmlBody)) { + if (HtmlBody != null) { alternative = new MultipartAlternative (); alternative.Add (text); body = alternative; @@ -118,11 +139,10 @@ public MimeEntity ToMessageBody () } } - if (!string.IsNullOrEmpty (HtmlBody)) { + if (HtmlBody != null) { var text = new TextPart ("html"); MimeEntity html; - text.ContentId = MimeUtils.GenerateMessageId (); text.Text = HtmlBody; if (LinkedResources.Count > 0) { @@ -145,6 +165,9 @@ public MimeEntity ToMessageBody () } if (Attachments.Count > 0) { + if (body == null && Attachments.Count == 1) + return Attachments[0]; + var mixed = new Multipart ("mixed"); if (body != null) diff --git a/MimeKit/ContentDisposition.cs b/MimeKit/ContentDisposition.cs index dbcdf45a2f..cafcfe88d2 100644 --- a/MimeKit/ContentDisposition.cs +++ b/MimeKit/ContentDisposition.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,7 @@ using System; using System.Text; - -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif +using System.Globalization; using MimeKit.Utils; @@ -72,7 +69,7 @@ public class ContentDisposition string disposition; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// The disposition should either be @@ -92,7 +89,7 @@ public ContentDisposition (string disposition) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// This is identical to with a disposition @@ -108,7 +105,7 @@ static bool IsAsciiAtom (byte c) } /// - /// Gets or sets the disposition. + /// Get or set the disposition. /// /// /// The disposition is typically either "attachment" or "inline". @@ -143,7 +140,7 @@ public string Disposition { } /// - /// Gets or sets a value indicating whether the is an attachment. + /// Get or set a value indicating whether the is an attachment. /// /// /// A convenience property to determine if the entity should be considered an attachment or not. @@ -155,7 +152,7 @@ public bool IsAttachment { } /// - /// Gets the parameters. + /// Get the list of parameters on the . /// /// /// In addition to specifying whether the entity should be treated as an @@ -163,6 +160,9 @@ public bool IsAttachment { /// contain parameters to provide further information to the receiving client /// such as the file attributes. /// + /// + /// + /// /// The parameters. public ParameterList Parameters { get { return parameters; } @@ -176,7 +176,7 @@ private set { } /// - /// Gets or sets the name of the file. + /// Get or set the name of the file. /// /// /// When set, this can provide a useful hint for a default file name for the @@ -210,7 +210,7 @@ static bool IsNullOrWhiteSpace (string value) } /// - /// Gets or sets the creation-date parameter. + /// Get or set the creation-date parameter. /// /// /// Refers to the date and time that the content file was created on the @@ -241,7 +241,7 @@ public DateTimeOffset? CreationDate { } /// - /// Gets or sets the modification-date parameter. + /// Get or set the modification-date parameter. /// /// /// Refers to the date and time that the content file was last modified on @@ -272,7 +272,7 @@ public DateTimeOffset? ModificationDate { } /// - /// Gets or sets the read-date parameter. + /// Get or set the read-date parameter. /// /// /// Refers to the date and time that the content file was last read on the @@ -303,7 +303,7 @@ public DateTimeOffset? ReadDate { } /// - /// Gets or sets the size parameter. + /// Get or set the size parameter. /// /// /// When set, the size parameter typically refers to the original size of the @@ -346,7 +346,7 @@ internal string Encode (FormatOptions options, Encoding charset) } /// - /// Serializes the to a string, + /// Serialize the to a string, /// optionally encoding the parameters. /// /// @@ -385,7 +385,7 @@ public string ToString (FormatOptions options, Encoding charset, bool encode) } /// - /// Serializes the to a string, + /// Serialize the to a string, /// optionally encoding the parameters. /// /// @@ -404,14 +404,13 @@ public string ToString (Encoding charset, bool encode) } /// - /// Returns a that represents the current - /// . + /// Serialize the to a string. /// /// /// Creates a string-representation of the . /// /// A that represents the current - /// . + /// . public override string ToString () { return ToString (FormatOptions.Default, Encoding.UTF8, false); @@ -442,7 +441,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Expected atom token at position {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Expected atom token at position {0}", index), index, index); return false; } @@ -450,7 +449,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index atom = index; if (text[index] == '"') { if (throwOnError) - throw new ParseException (string.Format ("Unxpected qstring token at position {0}", atom), atom, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unxpected qstring token at position {0}", atom), atom, index); // Note: This is a work-around for broken mailers that quote the disposition value... // @@ -466,7 +465,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } else { if (!ParseUtils.SkipAtom (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Invalid atom token at position {0}", atom), atom, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid atom token at position {0}", atom), atom, index); // Note: this is a work-around for broken mailers that do not specify a disposition value... // @@ -491,7 +490,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (text[index] != (byte) ';') { if (throwOnError) - throw new ParseException (string.Format ("Expected ';' at position {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Expected ';' at position {0}", index), index, index); return false; } @@ -514,13 +513,13 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The starting index of the input buffer. @@ -545,13 +544,13 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -569,12 +568,12 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Cont } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The starting index of the input buffer. @@ -597,12 +596,12 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The input buffer. /// The starting index of the input buffer. /// The parsed disposition. @@ -618,12 +617,12 @@ public static bool TryParse (byte[] buffer, int startIndex, out ContentDispositi } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the specified buffer. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The parsed disposition. @@ -642,12 +641,12 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out ContentDi } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Disposition value from the specified buffer. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The input buffer. /// The parsed disposition. /// @@ -659,12 +658,12 @@ public static bool TryParse (byte[] buffer, out ContentDisposition disposition) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a Content-Disposition value from the supplied text. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The parser options. /// The text to parse. /// The parsed disposition. @@ -684,12 +683,12 @@ public static bool TryParse (ParserOptions options, string text, out ContentDisp } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a Content-Disposition value from the supplied text. /// - /// true, if the disposition was successfully parsed, false otherwise. + /// true if the disposition was successfully parsed; otherwise, false. /// The text to parse. /// The parsed disposition. /// @@ -701,13 +700,13 @@ public static bool TryParse (string text, out ContentDisposition disposition) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// The start index of the buffer. @@ -737,13 +736,13 @@ public static ContentDisposition Parse (ParserOptions options, byte[] buffer, in } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The start index of the buffer. /// The length of the buffer. @@ -763,12 +762,12 @@ public static ContentDisposition Parse (byte[] buffer, int startIndex, int lengt } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// The start index of the buffer. @@ -796,12 +795,12 @@ public static ContentDisposition Parse (ParserOptions options, byte[] buffer, in } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The start index of the buffer. /// @@ -819,12 +818,12 @@ public static ContentDisposition Parse (byte[] buffer, int startIndex) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// @@ -848,12 +847,12 @@ public static ContentDisposition Parse (ParserOptions options, byte[] buffer) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Disposition value from the supplied buffer. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -867,12 +866,12 @@ public static ContentDisposition Parse (byte[] buffer) } /// - /// Parse the specified text into a new instance of the class. + /// Parse the specified text into a new instance of the class. /// /// /// Parses a Content-Disposition value from the specified text. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input text. /// @@ -897,12 +896,12 @@ public static ContentDisposition Parse (ParserOptions options, string text) } /// - /// Parse the specified text into a new instance of the class. + /// Parse the specified text into a new instance of the class. /// /// /// Parses a Content-Disposition value from the specified text. /// - /// The parsed . + /// The parsed . /// The input text. /// /// is null. diff --git a/MimeKit/ContentEncoding.cs b/MimeKit/ContentEncoding.cs index b2d30218d4..53c6cbd650 100644 --- a/MimeKit/ContentEncoding.cs +++ b/MimeKit/ContentEncoding.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,13 +27,13 @@ namespace MimeKit { /// /// An enumeration of all supported content transfer encodings. - /// . /// /// /// Some older mail software is unable to properly deal with /// data outside of the ASCII range, so it is sometimes /// necessary to encode the content of MIME entities. /// + /// public enum ContentEncoding { /// /// The default encoding (aka no encoding at all). @@ -41,65 +41,43 @@ public enum ContentEncoding { Default, /// - /// The 7bit content transfer encoding. - /// - /// - /// This encoding should be restricted to textual content + /// The 7bit content transfer encoding. This encoding should be restricted to textual content /// in the US-ASCII range. - /// + /// SevenBit, /// - /// The 8bit content transfer encoding. + /// The 8bit content transfer encoding. This encoding should be restricted to textual content + /// outside of the US-ASCII range but may not be supported by all transport services such as + /// older SMTP servers that do not support the 8BITMIME extension. /// - /// - /// This encoding should be restricted to textual content - /// outside of the US-ASCII range but may not be supported - /// by all transport services such as older SMTP servers - /// that do not support the 8BITMIME extension. - /// EightBit, /// - /// The binary content transfer encoding. + /// The binary content transfer encoding. This encoding is simply unencoded binary data. Typically + /// not supported by standard message transport services such as SMTP. /// - /// - /// This encoding is simply unencoded binary data. Typically not - /// supported by standard message transport services such as SMTP. - /// Binary, /// - /// The base64 content transfer encoding. - /// . + /// The base64 content transfer encoding. This encoding is typically used for encoding binary data + /// or textual content in a largely 8bit charset encoding and is supported by all message transport + /// services. /// - /// - /// This encoding is typically used for encoding binary data - /// or textual content in a largely 8bit charset encoding and - /// is supported by all message transport services. - /// Base64, /// - /// The quoted printable content transfer encoding. - /// . + /// The quoted-printable content transfer encoding. This encoding is used for textual content that + /// is in a charset that has a minority of characters outside of the US-ASCII range (such as + /// ISO-8859-1 and other single-byte charset encodings) and is supported by all message transport + /// services. /// - /// - /// This encoding is used for textual content that is in a charset - /// that has a minority of characters outside of the US-ASCII range - /// (such as ISO-8859-1 and other single-byte charset encodings) and - /// is supported by all message transport services. - /// QuotedPrintable, /// - /// The uuencode content transfer encoding. - /// . - /// - /// - /// This is an obsolete encoding meant for encoding binary + /// The uuencode content transfer encoding. This is an obsolete encoding meant for encoding binary /// data and has largely been superceeded by . - /// + /// UUEncode, } } diff --git a/MimeKit/ContentType.cs b/MimeKit/ContentType.cs index 382c01a79f..0c0ab73ed9 100644 --- a/MimeKit/ContentType.cs +++ b/MimeKit/ContentType.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,7 @@ using System; using System.Text; - -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif +using System.Globalization; using MimeKit.Utils; @@ -48,7 +45,7 @@ public class ContentType string type, subtype; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new based on the media type and subtype provided. @@ -73,18 +70,8 @@ public ContentType (string mediaType, string mediaSubtype) type = mediaType; } - static bool IsToken (byte c) - { - return c.IsToken (); - } - - static bool IsAsciiAtom (byte c) - { - return c.IsAsciiAtom (); - } - /// - /// Gets or sets the type of the media. + /// Get or set the type of the media. /// /// /// Represents the media type of the . Examples include @@ -111,7 +98,7 @@ public string MediaType { } /// - /// Gets or sets the media subtype. + /// Get or set the media subtype. /// /// /// Represents the media subtype of the . Examples include @@ -138,7 +125,7 @@ public string MediaSubtype { } /// - /// Gets the parameters. + /// Get the list of parameters on the . /// /// /// In addition to the media type and subtype, the Content-Type header may also @@ -158,7 +145,7 @@ internal set { } /// - /// Gets or sets the boundary parameter. + /// Get or set the boundary parameter. /// /// /// This is a special parameter on entities, designating to the @@ -176,7 +163,7 @@ public string Boundary { } /// - /// Gets or sets the charset parameter. + /// Get or set the charset parameter. /// /// /// Text-based entities will often include a charset parameter @@ -194,7 +181,33 @@ public string Charset { } /// - /// Gets or sets the format parameter. + /// Get or set the charset parameter as an . + /// + /// + /// Text-based entities will often include a charset parameter + /// so that the receiving client can properly render the text. + /// + /// The charset encoding. + public Encoding CharsetEncoding { + get { + var charset = Charset; + + if (charset == null) + return null; + + try { + return CharsetUtils.GetEncoding (charset); + } catch { + return null; + } + } + set { + Charset = value != null ? CharsetUtils.GetMimeCharset (value) : null; + } + } + + /// + /// Get or set the format parameter. /// /// /// The format parameter is typically use with text/plain @@ -223,7 +236,7 @@ public string MimeType { } /// - /// Gets or sets the name parameter. + /// Get or set the name parameter. /// /// /// The name parameter is a way for the originiating client to suggest @@ -243,7 +256,7 @@ public string Name { } /// - /// Checks if the this instance of matches + /// Check if the this instance of matches /// the specified MIME media type and subtype. /// /// @@ -291,7 +304,7 @@ internal string Encode (FormatOptions options, Encoding charset) } /// - /// Serializes the to a string, + /// Serialize the to a string, /// optionally encoding the parameters. /// /// @@ -332,7 +345,7 @@ public string ToString (FormatOptions options, Encoding charset, bool encode) } /// - /// Serializes the to a string, + /// Serialize the to a string, /// optionally encoding the parameters. /// /// @@ -351,14 +364,13 @@ public string ToString (Encoding charset, bool encode) } /// - /// Returns a that represents the current - /// . + /// Serialize the to a string. /// /// /// Creates a string-representation of the . /// /// A that represents the current - /// . + /// . public override string ToString () { return ToString (FormatOptions.Default, Encoding.UTF8, false); @@ -400,7 +412,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index start = index; if (!SkipType (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Invalid type token at position {0}", start), start, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid type token at position {0}", start), start, index); return false; } @@ -412,7 +424,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (index >= endIndex || text[index] != (byte) '/') { if (throwOnError) - throw new ParseException (string.Format ("Expected '/' at position {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Expected '/' at position {0}", index), index, index); return false; } @@ -426,7 +438,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index start = index; if (!ParseUtils.SkipToken (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Invalid atom token at position {0}", start), start, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid atom token at position {0}", start), start, index); return false; } @@ -443,7 +455,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (text[index] != (byte) ';') { if (throwOnError) - throw new ParseException (string.Format ("Expected ';' at position {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Expected ';' at position {0}", index), index, index); return false; } @@ -466,13 +478,13 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The starting index of the input buffer. @@ -497,13 +509,13 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -521,12 +533,12 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Cont } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the supplied buffer starting at the specified index. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The starting index of the input buffer. @@ -549,12 +561,12 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the supplied buffer starting at the specified index. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The input buffer. /// The starting index of the input buffer. /// The parsed content type. @@ -570,12 +582,12 @@ public static bool TryParse (byte[] buffer, int startIndex, out ContentType type } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the specified buffer. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The parser options. /// The input buffer. /// The parsed content type. @@ -594,12 +606,12 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out ContentTy } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a Content-Type value from the specified buffer. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The input buffer. /// The parsed content type. /// @@ -611,12 +623,12 @@ public static bool TryParse (byte[] buffer, out ContentType type) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a Content-Type value from the specified text. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// THe parser options. /// The text to parse. /// The parsed content type. @@ -636,12 +648,12 @@ public static bool TryParse (ParserOptions options, string text, out ContentType } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a Content-Type value from the specified text. /// - /// true, if the content type was successfully parsed, false otherwise. + /// true if the content type was successfully parsed; otherwise, false. /// The text to parse. /// The parsed content type. /// @@ -653,13 +665,13 @@ public static bool TryParse (string text, out ContentType type) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// The start index of the buffer. @@ -689,13 +701,13 @@ public static ContentType Parse (ParserOptions options, byte[] buffer, int start } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The start index of the buffer. /// The length of the buffer. @@ -715,12 +727,12 @@ public static ContentType Parse (byte[] buffer, int startIndex, int length) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// The start index of the buffer. @@ -748,12 +760,12 @@ public static ContentType Parse (ParserOptions options, byte[] buffer, int start } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The start index of the buffer. /// @@ -771,12 +783,12 @@ public static ContentType Parse (byte[] buffer, int startIndex) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the specified buffer. /// - /// The parsed . + /// The parsed . /// The parser options. /// The input buffer. /// @@ -800,12 +812,12 @@ public static ContentType Parse (ParserOptions options, byte[] buffer) } /// - /// Parse the specified input buffer into a new instance of the class. + /// Parse the specified input buffer into a new instance of the class. /// /// /// Parses a Content-Type value from the specified buffer. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -819,12 +831,12 @@ public static ContentType Parse (byte[] buffer) } /// - /// Parse the specified text into a new instance of the class. + /// Parse the specified text into a new instance of the class. /// /// /// Parses a Content-Type value from the specified text. /// - /// The parsed . + /// The parsed . /// The parser options. /// The text. /// @@ -849,12 +861,12 @@ public static ContentType Parse (ParserOptions options, string text) } /// - /// Parse the specified text into a new instance of the class. + /// Parse the specified text into a new instance of the class. /// /// /// Parses a Content-Type value from the specified text. /// - /// The parsed . + /// The parsed . /// The text. /// /// is null. diff --git a/MimeKit/Cryptography/ApplicationPgpEncrypted.cs b/MimeKit/Cryptography/ApplicationPgpEncrypted.cs index 70d6fd6198..05859d6fc7 100644 --- a/MimeKit/Cryptography/ApplicationPgpEncrypted.cs +++ b/MimeKit/Cryptography/ApplicationPgpEncrypted.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -40,11 +40,11 @@ namespace MimeKit.Cryptography { public class ApplicationPgpEncrypted : MimePart { /// - /// Initializes a new instance of the - /// class based on the . + /// Initialize a new instance of the + /// class based on the . /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -55,7 +55,7 @@ public ApplicationPgpEncrypted (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new MIME part with a Content-Type of application/pgp-encrypted @@ -75,12 +75,12 @@ public ApplicationPgpEncrypted () : base ("application", "pgp-encrypted") /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/Cryptography/ApplicationPgpSignature.cs b/MimeKit/Cryptography/ApplicationPgpSignature.cs index 95dec8d7a0..d7590e31c3 100644 --- a/MimeKit/Cryptography/ApplicationPgpSignature.cs +++ b/MimeKit/Cryptography/ApplicationPgpSignature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,11 +41,11 @@ namespace MimeKit.Cryptography { public class ApplicationPgpSignature : MimePart { /// - /// Initializes a new instance of the - /// class based on the . + /// Initialize a new instance of the + /// class based on the . /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -56,7 +56,7 @@ public ApplicationPgpSignature (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with a Content-Type of application/pgp-signature. /// /// @@ -84,12 +84,12 @@ public ApplicationPgpSignature (Stream stream) : base ("application", "pgp-signa /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/Cryptography/ApplicationPkcs7Mime.cs b/MimeKit/Cryptography/ApplicationPkcs7Mime.cs index 482329bc3e..12ebd8045a 100644 --- a/MimeKit/Cryptography/ApplicationPkcs7Mime.cs +++ b/MimeKit/Cryptography/ApplicationPkcs7Mime.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,10 +42,10 @@ namespace MimeKit.Cryptography { public class ApplicationPkcs7Mime : MimePart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -56,7 +56,7 @@ public ApplicationPkcs7Mime (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new MIME part with a Content-Type of application/pkcs7-mime @@ -127,6 +127,7 @@ public SecureMimeType SecureMimeType { return SecureMimeType.Unknown; switch (type.ToLowerInvariant ()) { + case "authenveloped-data": return SecureMimeType.AuthEnvelopedData; case "compressed-data": return SecureMimeType.CompressedData; case "enveloped-data": return SecureMimeType.EnvelopedData; case "signed-data": return SecureMimeType.SignedData; @@ -140,12 +141,12 @@ public SecureMimeType SecureMimeType { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -165,7 +166,7 @@ public override void Accept (MimeVisitor visitor) /// /// Decompresses the compressed-data using the specified . /// - /// The decompressed . + /// The decompressed . /// The S/MIME context to use for decompressing. /// /// is null. @@ -181,7 +182,7 @@ public MimeEntity Decompress (SecureMimeContext ctx) if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - if (SecureMimeType != SecureMimeType.CompressedData) + if (SecureMimeType != SecureMimeType.CompressedData && SecureMimeType != SecureMimeType.Unknown) throw new InvalidOperationException (); using (var memory = new MemoryBlockStream ()) { @@ -198,7 +199,7 @@ public MimeEntity Decompress (SecureMimeContext ctx) /// /// Decompresses the compressed-data using the default . /// - /// The decompressed . + /// The decompressed . /// /// The "smime-type" parameter on the Content-Type header is not "compressed-data". /// @@ -207,7 +208,7 @@ public MimeEntity Decompress (SecureMimeContext ctx) /// public MimeEntity Decompress () { - if (SecureMimeType != SecureMimeType.CompressedData) + if (SecureMimeType != SecureMimeType.CompressedData && SecureMimeType != SecureMimeType.Unknown) throw new InvalidOperationException (); using (var ctx = (SecureMimeContext) CryptographyContext.Create ("application/pkcs7-mime")) @@ -220,7 +221,7 @@ public MimeEntity Decompress () /// /// Decrypts the enveloped-data using the specified . /// - /// The decrypted . + /// The decrypted . /// The S/MIME context to use for decrypting. /// The cancellation token. /// @@ -240,7 +241,7 @@ public MimeEntity Decompress () if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - if (SecureMimeType != SecureMimeType.EnvelopedData) + if (SecureMimeType != SecureMimeType.EnvelopedData && SecureMimeType != SecureMimeType.Unknown) throw new InvalidOperationException (); using (var memory = new MemoryBlockStream ()) { @@ -257,7 +258,7 @@ public MimeEntity Decompress () /// /// Decrypts the enveloped-data using the default . /// - /// The decrypted . + /// The decrypted . /// The cancellation token. /// /// The "smime-type" parameter on the Content-Type header is not "certs-only". @@ -295,7 +296,7 @@ public void Import (SecureMimeContext ctx) if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - if (SecureMimeType != SecureMimeType.CertsOnly) + if (SecureMimeType != SecureMimeType.CertsOnly && SecureMimeType != SecureMimeType.Unknown) throw new InvalidOperationException (); using (var memory = new MemoryBlockStream ()) { @@ -307,10 +308,10 @@ public void Import (SecureMimeContext ctx) } /// - /// Verify the signed-data and return the unencapsulated . + /// Verify the signed-data and return the unencapsulated . /// /// - /// Verifies the signed-data and returns the unencapsulated . + /// Verifies the signed-data and returns the unencapsulated . /// /// The list of digital signatures. /// The S/MIME context to use for verifying the signature. @@ -336,7 +337,7 @@ public void Import (SecureMimeContext ctx) if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - if (SecureMimeType != SecureMimeType.SignedData) + if (SecureMimeType != SecureMimeType.SignedData && SecureMimeType != SecureMimeType.Unknown) throw new InvalidOperationException (); using (var memory = new MemoryBlockStream ()) { @@ -348,11 +349,11 @@ public void Import (SecureMimeContext ctx) } /// - /// Verifies the signed-data and returns the unencapsulated . + /// Verifies the signed-data and returns the unencapsulated . /// /// /// Verifies the signed-data using the default and returns the - /// unencapsulated . + /// unencapsulated . /// /// The list of digital signatures. /// The unencapsulated entity. @@ -377,8 +378,7 @@ public void Import (SecureMimeContext ctx) /// /// /// Compresses the specified entity using the specified . - /// Most mail clients, even among those that support S/MIME, - /// do not support compression. + /// Most mail clients, even among those that support S/MIME, do not support compression. /// /// The compressed entity. /// The S/MIME context to use for compressing. @@ -415,8 +415,7 @@ public static ApplicationPkcs7Mime Compress (SecureMimeContext ctx, MimeEntity e /// /// /// Compresses the specified entity using the default . - /// Most mail clients, even among those that support S/MIME, - /// do not support compression. + /// Most mail clients, even among those that support S/MIME, do not support compression. /// /// The compressed entity. /// The entity. diff --git a/MimeKit/Cryptography/ApplicationPkcs7Signature.cs b/MimeKit/Cryptography/ApplicationPkcs7Signature.cs index 612fa09c27..200d503211 100644 --- a/MimeKit/Cryptography/ApplicationPkcs7Signature.cs +++ b/MimeKit/Cryptography/ApplicationPkcs7Signature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,10 +41,10 @@ namespace MimeKit.Cryptography { public class ApplicationPkcs7Signature : MimePart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -55,7 +55,7 @@ public ApplicationPkcs7Signature (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with a Content-Type of application/pkcs7-signature. /// /// @@ -83,12 +83,12 @@ public ApplicationPkcs7Signature (Stream stream) : base ("application", "pkcs7-s /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/Cryptography/ArcSigner.cs b/MimeKit/Cryptography/ArcSigner.cs new file mode 100644 index 0000000000..d7c3485dea --- /dev/null +++ b/MimeKit/Cryptography/ArcSigner.cs @@ -0,0 +1,725 @@ +// +// ArcSigner.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Globalization; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Org.BouncyCastle.Crypto; + +using MimeKit.IO; +using MimeKit.Utils; + +namespace MimeKit.Cryptography { + /// + /// An ARC signer. + /// + /// + /// An ARC signer. + /// + /// + /// + /// + public abstract class ArcSigner : DkimSignerBase + { + static readonly string[] ArcShouldNotInclude = { "return-path", "received", "comments", "keywords", "bcc", "resent-bcc", "arc-seal" }; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The domain that the signer represents. + /// The selector subdividing the domain. + /// The signature algorithm. + /// + /// is null. + /// -or- + /// is null. + /// + protected ArcSigner (string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (domain, selector, algorithm) + { + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The signer's private key. + /// The domain that the signer represents. + /// The selector subdividing the domain. + /// The signature algorithm. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// is not a private key. + /// + protected ArcSigner (AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) + { + if (key == null) + throw new ArgumentNullException (nameof (key)); + + if (!key.IsPrivate) + throw new ArgumentException ("The key must be a private key.", nameof (key)); + + PrivateKey = key; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// + /// + /// + /// The file containing the private key. + /// The domain that the signer represents. + /// The selector subdividing the domain. + /// The signature algorithm. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// is a zero-length string, contains only white space, or + /// contains one or more invalid characters. + /// + /// + /// The file did not contain a private key. + /// + /// + /// is an invalid file path. + /// + /// + /// The specified file path could not be found. + /// + /// + /// The user does not have access to read the specified file. + /// + /// + /// An I/O error occurred. + /// + protected ArcSigner (string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) + { + if (fileName == null) + throw new ArgumentNullException (nameof (fileName)); + + if (fileName.Length == 0) + throw new ArgumentException ("The file name cannot be empty.", nameof (fileName)); + + using (var stream = File.OpenRead (fileName)) + PrivateKey = LoadPrivateKey (stream); + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The stream containing the private key. + /// The domain that the signer represents. + /// The selector subdividing the domain. + /// The signature algorithm. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// The file did not contain a private key. + /// + /// + /// An I/O error occurred. + /// + protected ArcSigner (Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) + { + if (stream == null) + throw new ArgumentNullException (nameof (stream)); + + PrivateKey = LoadPrivateKey (stream); + } + + /// + /// Generate an ARC-Authentication-Results header. + /// + /// + /// Generates an ARC-Authentication-Results header. + /// If the returned contains a + /// with a equal to "arc", then the + /// will be used as the cv= tag value + /// in the ARC-Seal header generated by the . + /// + /// + /// + /// + /// The format options. + /// The message to create the ARC-Authentication-Results header for. + /// The cancellation token. + /// The ARC-Authentication-Results header or null if the should not sign the message. + protected abstract AuthenticationResults GenerateArcAuthenticationResults (FormatOptions options, MimeMessage message, CancellationToken cancellationToken); + + /// + /// Asynchronously generate an ARC-Authentication-Results header. + /// + /// + /// Asynchronously generates an ARC-Authentication-Results header. + /// If the returned contains a + /// with a equal to "arc", then the + /// will be used as the cv= tag value + /// in the ARC-Seal header generated by the . + /// + /// + /// + /// + /// The format options. + /// The message to create the ARC-Authentication-Results header for. + /// The cancellation token. + /// The ARC-Authentication-Results header or null if the should not sign the message. + protected abstract Task GenerateArcAuthenticationResultsAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken); + + /// + /// Get the timestamp value. + /// + /// + /// Gets the timestamp to use as the t= value in the ARC-Message-Signature and ARC-Seal headers. + /// + /// A value representing the timestamp value. + protected virtual long GetTimestamp () + { + return (long) (DateTime.UtcNow - DateUtils.UnixEpoch).TotalSeconds; + } + + StringBuilder CreateArcHeaderBuilder (int instance) + { + var value = new StringBuilder (); + + value.AppendFormat ("i={0}", instance.ToString (CultureInfo.InvariantCulture)); + + switch (SignatureAlgorithm) { + case DkimSignatureAlgorithm.Ed25519Sha256: + value.Append ("; a=ed25519-sha256"); + break; + case DkimSignatureAlgorithm.RsaSha256: + value.Append ("; a=rsa-sha256"); + break; + default: + value.Append ("; a=rsa-sha1"); + break; + } + + return value; + } + + Header GenerateArcMessageSignature (FormatOptions options, MimeMessage message, int instance, long t, IList headers) + { + var value = CreateArcHeaderBuilder (instance); + byte[] signature, hash; + Header ams; + + value.AppendFormat ("; d={0}; s={1}", Domain, Selector); + value.AppendFormat ("; c={0}/{1}", + HeaderCanonicalizationAlgorithm.ToString ().ToLowerInvariant (), + BodyCanonicalizationAlgorithm.ToString ().ToLowerInvariant ()); + value.AppendFormat ("; t={0}", t); + + using (var stream = new DkimSignatureStream (CreateSigningContext ())) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (options.CreateNewLineFilter ()); + + // write the specified message headers + DkimVerifierBase.WriteHeaders (options, message, headers, HeaderCanonicalizationAlgorithm, filtered); + + value.AppendFormat ("; h={0}", string.Join (":", headers.ToArray ())); + + hash = message.HashBody (options, SignatureAlgorithm, BodyCanonicalizationAlgorithm, -1); + value.AppendFormat ("; bh={0}", Convert.ToBase64String (hash)); + value.Append ("; b="); + + ams = new Header (HeaderId.ArcMessageSignature, value.ToString ()); + + switch (HeaderCanonicalizationAlgorithm) { + case DkimCanonicalizationAlgorithm.Relaxed: + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, ams, true); + break; + default: + DkimVerifierBase.WriteHeaderSimple (options, filtered, ams, true); + break; + } + + filtered.Flush (); + } + + signature = stream.GenerateSignature (); + + ams.Value += Convert.ToBase64String (signature); + + return ams; + } + } + + Header GenerateArcSeal (FormatOptions options, int instance, string cv, long t, ArcHeaderSet[] sets, int count, Header aar, Header ams) + { + var value = CreateArcHeaderBuilder (instance); + byte[] signature; + Header seal; + + value.AppendFormat ("; cv={0}", cv); + + value.AppendFormat ("; d={0}; s={1}", Domain, Selector); + value.AppendFormat ("; t={0}", t); + + using (var stream = new DkimSignatureStream (CreateSigningContext ())) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (options.CreateNewLineFilter ()); + + for (int i = 0; i < count; i++) { + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, sets[i].ArcAuthenticationResult, false); + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, sets[i].ArcMessageSignature, false); + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, sets[i].ArcSeal, false); + } + + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, aar, false); + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, ams, false); + + value.Append ("; b="); + + seal = new Header (HeaderId.ArcSeal, value.ToString ()); + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, seal, true); + + filtered.Flush (); + } + + signature = stream.GenerateSignature (); + + seal.Value += Convert.ToBase64String (signature); + + return seal; + } + } + + async Task ArcSignAsync (FormatOptions options, MimeMessage message, IList headers, bool doAsync, CancellationToken cancellationToken) + { + ArcVerifier.GetArcHeaderSets (message, true, out ArcHeaderSet[] sets, out int count, out var errors); + AuthenticationResults authres; + int instance = count + 1; + string cv; + + // do not sign if there is already a failed/invalid ARC-Seal. + if (count > 0 && (errors & ArcValidationErrors.InvalidArcSealChainValidationValue) != 0) + return; + + options = options.Clone (); + options.NewLineFormat = NewLineFormat.Dos; + options.EnsureNewLine = true; + + if (doAsync) + authres = await GenerateArcAuthenticationResultsAsync (options, message, cancellationToken).ConfigureAwait (false); + else + authres = GenerateArcAuthenticationResults (options, message, cancellationToken); + + if (authres == null) + return; + + authres.Instance = instance; + + var aar = new Header (HeaderId.ArcAuthenticationResults, authres.ToString ()); + cv = "none"; + + if (count > 0) { + cv = "pass"; + + foreach (var method in authres.Results) { + if (method.Method.Equals ("arc", StringComparison.OrdinalIgnoreCase)) { + cv = method.Result; + break; + } + } + } + + var t = GetTimestamp (); + var ams = GenerateArcMessageSignature (options, message, instance, t, headers); + var seal = GenerateArcSeal (options, instance, cv, t, sets, count, aar, ams); + + message.Headers.Insert (0, aar); + message.Headers.Insert (0, ams); + message.Headers.Insert (0, seal); + } + + Task SignAsync (FormatOptions options, MimeMessage message, IList headers, bool doAsync, CancellationToken cancellationToken) + { + if (options == null) + throw new ArgumentNullException (nameof (options)); + + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (headers == null) + throw new ArgumentNullException (nameof (headers)); + + var fields = new string[headers.Count]; + var containsFrom = false; + + for (int i = 0; i < headers.Count; i++) { + if (headers[i] == null) + throw new ArgumentException ("The list of headers cannot contain null.", nameof (headers)); + + if (headers[i].Length == 0) + throw new ArgumentException ("The list of headers cannot contain empty string.", nameof (headers)); + + fields[i] = headers[i].ToLowerInvariant (); + + if (ArcShouldNotInclude.Contains (fields[i])) + throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i]), nameof (headers)); + + if (fields[i] == "from") + containsFrom = true; + } + + if (!containsFrom) + throw new ArgumentException ("The list of headers to sign MUST include the 'From' header.", nameof (headers)); + + return ArcSignAsync (options, message, fields, doAsync, cancellationToken); + } + + Task SignAsync (FormatOptions options, MimeMessage message, IList headers, bool doAsync, CancellationToken cancellationToken) + { + if (options == null) + throw new ArgumentNullException (nameof (options)); + + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (headers == null) + throw new ArgumentNullException (nameof (headers)); + + var fields = new string[headers.Count]; + var containsFrom = false; + + for (int i = 0; i < headers.Count; i++) { + if (headers[i] == HeaderId.Unknown) + throw new ArgumentException ("The list of headers to sign cannot include the 'Unknown' header.", nameof (headers)); + + fields[i] = headers[i].ToHeaderName ().ToLowerInvariant (); + + if (ArcShouldNotInclude.Contains (fields[i])) + throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i].ToHeaderName ()), nameof (headers)); + + if (headers[i] == HeaderId.From) + containsFrom = true; + } + + if (!containsFrom) + throw new ArgumentException ("The list of headers to sign MUST include the 'From' header.", nameof (headers)); + + return ArcSignAsync (options, message, fields, doAsync, cancellationToken); + } + + /// + /// Digitally sign and seal a message using ARC. + /// + /// + /// Digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public void Sign (FormatOptions options, MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + SignAsync (options, message, headers, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously digitally sign and seal a message using ARC. + /// + /// + /// Asynchronously digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// An awaitable task. + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public Task SignAsync (FormatOptions options, MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + return SignAsync (options, message, headers, true, cancellationToken); + } + + /// + /// Digitally sign and seal a message using ARC. + /// + /// + /// Digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public void Sign (MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + Sign (FormatOptions.Default, message, headers, cancellationToken); + } + + /// + /// Asynchronously digitally sign and seal a message using ARC. + /// + /// + /// Asynchronously digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// An awaitable task. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public Task SignAsync (MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + return SignAsync (FormatOptions.Default, message, headers, cancellationToken); + } + + /// + /// Digitally sign and seal a message using ARC. + /// + /// + /// Digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public void Sign (FormatOptions options, MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + SignAsync (options, message, headers, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously digitally sign and seal a message using ARC. + /// + /// + /// Asynchronously digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// An awaitable task. + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public Task SignAsync (FormatOptions options, MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + return SignAsync (options, message, headers, true, cancellationToken); + } + + /// + /// Digitally sign and seal a message using ARC. + /// + /// + /// Digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public void Sign (MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + Sign (FormatOptions.Default, message, headers, cancellationToken); + } + + /// + /// Asynchronously digitally sign and seal a message using ARC. + /// + /// + /// Asynchronously digitally signs and seals a message using ARC. + /// + /// + /// + /// + /// An awaitable task. + /// The message to sign. + /// The list of header fields to sign. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + /// + /// One or more ARC headers either did not contain an instance tag or the instance tag was invalid. + /// + public Task SignAsync (MimeMessage message, IList headers, CancellationToken cancellationToken = default (CancellationToken)) + { + return SignAsync (FormatOptions.Default, message, headers, cancellationToken); + } + } +} diff --git a/MimeKit/Cryptography/ArcVerifier.cs b/MimeKit/Cryptography/ArcVerifier.cs new file mode 100644 index 0000000000..726814916a --- /dev/null +++ b/MimeKit/Cryptography/ArcVerifier.cs @@ -0,0 +1,817 @@ +// +// ArcVerifier.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Threading; +using System.Globalization; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +using MimeKit.IO; + +namespace MimeKit.Cryptography { + /// + /// An ARC signature validation result. + /// + /// + /// An ARC signature validation result. + /// + /// + /// + /// + public enum ArcSignatureValidationResult + { + /// + /// No signatures to validate. + /// + None, + + /// + /// The validation passed. + /// + Pass, + + /// + /// The validation failed. + /// + Fail + } + + /// + /// An enumeration of possible ARC validation errors. + /// + /// + /// An enumeration of possible ARC validation errors. + /// + [Flags] + public enum ArcValidationErrors + { + /// + /// No errors. + /// + None = 0, + + /// + /// One or more duplicate ARC-Authentication-Results headers exist. + /// + DuplicateArcAuthenticationResults = 1 << 0, + + /// + /// One or more duplicate ARC-Message-Signature headers exist. + /// + DuplicateArcMessageSignature = 1 << 1, + + /// + /// One or more duplicate ARC-Seal headers exist. + /// + DuplicateArcSeal = 1 << 2, + + /// + /// One or more ARC-Authentication-Results headers are missing. + /// + MissingArcAuthenticationResults = 1 << 3, + + /// + /// One or more ARC-Message-Signature headers are missing. + /// + MissingArcMessageSignature = 1 << 4, + + /// + /// One or more ARC-Seal headers are missing. + /// + MissingArcSeal = 1 << 5, + + /// + /// One or more ARC-Authentication-Results headers could not be parsed. + /// + InvalidArcAuthenticationResults = 1 << 6, + + /// + /// One or more ARC-Message-Signature headers could not be parsed. + /// + InvalidArcMessageSignature = 1 << 7, + + /// + /// One or more ARC-Seal headers could not be parsed. + /// + InvalidArcSeal = 1 << 8, + + /// + /// One or more ARC-Seal headers have an invalid cv value. + /// + InvalidArcSealChainValidationValue = 1 << 9, + + /// + /// One or more ARC-Seal headers are missing a cv value. + /// + MissingArcSealChainValidationValue = 1 << 10, + + /// + /// Validation failed for the most recent ARC-Message-Signature header. + /// + MessageSignatureValidationFailed = 1 << 11, + + /// + /// Validation failed for one or more of the ARC-Seal headers. + /// + SealValidationFailed = 1 << 12 + } + + /// + /// An ARC header validation result. + /// + /// + /// Represents an ARC header and its signature validation result. + /// + /// + /// + /// + public class ArcHeaderValidationResult + { + /// + /// Initialize a new instance of the class. + /// + /// The ARC header. + /// + /// is null. + /// + internal ArcHeaderValidationResult (Header header) + { + if (header == null) + throw new ArgumentNullException (nameof (header)); + + Header = header; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The ARC header. + /// The signature validation result. + /// + /// is null. + /// + public ArcHeaderValidationResult (Header header, ArcSignatureValidationResult signature) : this (header) + { + Signature = signature; + } + + /// + /// Get the signature validation result. + /// + /// + /// Gets the signature validation result. + /// + /// The signature validation result. + public ArcSignatureValidationResult Signature { + get; internal set; + } + + /// + /// Get the ARC header. + /// + /// + /// Gets the ARC header. + /// + /// The ARC header. + public Header Header { + get; private set; + } + } + + /// + /// An ARC validation result. + /// + /// + /// Represents the results of ArcVerifier.Verify + /// or ArcVerifier.VerifyAsync. + /// If no ARC headers are found on the , then the result will be + /// and both and + /// will be null. + /// If ARC headers are found on the but could not be parsed, then the + /// result will be and both + /// and will be null. + /// + /// + /// + /// + public class ArcValidationResult + { + internal ArcValidationResult () + { + Chain = ArcSignatureValidationResult.None; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The signature validation results of the entire chain. + /// The validation results for the ARC-Message-Signature header. + /// The validation results for the ARC-Seal headers. + public ArcValidationResult (ArcSignatureValidationResult chain, ArcHeaderValidationResult messageSignature, ArcHeaderValidationResult[] seals) + { + MessageSignature = messageSignature; + Seals = seals; + Chain = chain; + } + + /// + /// Get the validation results for the ARC-Message-Signature header. + /// + /// + /// Gets the validation results for the ARC-Message-Signature header. + /// + /// The validation results for the ARC-Message-Signature header or null + /// if the ARC-Message-Signature header was not found. + public ArcHeaderValidationResult MessageSignature { + get; internal set; + } + + /// + /// Get the validation results for each of the ARC-Seal headers. + /// + /// + /// Gets the validation results for each of the ARC-Seal headers in + /// their instance order. + /// + /// The array of validation results for the ARC-Seal headers or null + /// if no ARC-Seal headers were found. + public ArcHeaderValidationResult[] Seals { + get; internal set; + } + + /// + /// Get the signature validation results of the entire chain. + /// + /// + /// Gets the signature validation results of the entire chain. + /// + /// + /// + /// + /// The signature validation results of the entire chain. + public ArcSignatureValidationResult Chain { + get; internal set; + } + + /// + /// Get the chain validation errors. + /// + /// + /// Gets the chain validation errors. + /// + /// The chain validation errors. + public ArcValidationErrors ChainErrors { + get; internal set; + } + } + + class ArcHeaderSet + { + public Header ArcAuthenticationResult { get; private set; } + + public Dictionary ArcMessageSignatureParameters { get; private set; } + public Header ArcMessageSignature { get; private set; } + + public Dictionary ArcSealParameters { get; private set; } + public Header ArcSeal { get; private set; } + + public bool Add (Header header, Dictionary parameters) + { + switch (header.Id) { + case HeaderId.ArcAuthenticationResults: + if (ArcAuthenticationResult != null) + return false; + + ArcAuthenticationResult = header; + break; + case HeaderId.ArcMessageSignature: + if (ArcMessageSignature != null) + return false; + + ArcMessageSignatureParameters = parameters; + ArcMessageSignature = header; + break; + case HeaderId.ArcSeal: + if (ArcSeal != null) + return false; + + ArcSealParameters = parameters; + ArcSeal = header; + break; + default: + return false; + } + + return true; + } + } + + /// + /// An ARC verifier. + /// + /// + /// Validates Authenticated Received Chains. + /// + /// + /// + /// + public class ArcVerifier : DkimVerifierBase + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// + /// + /// + /// The public key locator. + /// + /// is null. + /// + public ArcVerifier (IDkimPublicKeyLocator publicKeyLocator) : base (publicKeyLocator) + { + } + + static void ValidateArcMessageSignatureParameters (IDictionary parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm, + out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength) + { + ValidateCommonSignatureParameters ("ARC-Message-Signature", parameters, out algorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength); + } + + static void ValidateArcSealParameters (IDictionary parameters, out DkimSignatureAlgorithm algorithm, out string d, out string s, out string q, out string b) + { + ValidateCommonParameters ("ARC-Seal", parameters, out algorithm, out d, out s, out q, out b); + + if (parameters.TryGetValue ("h", out string h)) + throw new FormatException ("Malformed ARC-Seal header: the 'h' parameter tag is not allowed."); + } + + async Task VerifyArcMessageSignatureAsync (FormatOptions options, MimeMessage message, Header arcSignature, Dictionary parameters, bool doAsync, CancellationToken cancellationToken) + { + DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; + DkimSignatureAlgorithm signatureAlgorithm; + AsymmetricKeyParameter key; + string d, s, q, bh, b; + string[] headers; + int maxLength; + + ValidateArcMessageSignatureParameters (parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, + out d, out s, out q, out headers, out bh, out b, out maxLength); + + if (!IsEnabled (signatureAlgorithm)) + return false; + + options = options.Clone (); + options.NewLineFormat = NewLineFormat.Dos; + + // first check the body hash (if that's invalid, then the entire signature is invalid) + if (!VerifyBodyHash (options, message, signatureAlgorithm, bodyAlgorithm, maxLength, bh)) + return false; + + if (doAsync) + key = await PublicKeyLocator.LocatePublicKeyAsync (q, d, s, cancellationToken).ConfigureAwait (false); + else + key = PublicKeyLocator.LocatePublicKey (q, d, s, cancellationToken); + + if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) + return false; + + return VerifySignature (options, message, arcSignature, signatureAlgorithm, key, headers, headerAlgorithm, b); + } + + async Task VerifyArcSealAsync (FormatOptions options, ArcHeaderSet[] sets, int i, bool doAsync, CancellationToken cancellationToken) + { + DkimSignatureAlgorithm algorithm; + AsymmetricKeyParameter key; + string d, s, q, b; + + ValidateArcSealParameters (sets[i].ArcSealParameters, out algorithm, out d, out s, out q, out b); + + if (!IsEnabled (algorithm)) + return false; + + if (doAsync) + key = await PublicKeyLocator.LocatePublicKeyAsync (q, d, s, cancellationToken).ConfigureAwait (false); + else + key = PublicKeyLocator.LocatePublicKey (q, d, s, cancellationToken); + + if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) + return false; + + options = options.Clone (); + options.NewLineFormat = NewLineFormat.Dos; + + using (var stream = new DkimSignatureStream (CreateVerifyContext (algorithm, key))) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (options.CreateNewLineFilter ()); + + for (int j = 0; j < i; j++) { + WriteHeaderRelaxed (options, filtered, sets[j].ArcAuthenticationResult, false); + WriteHeaderRelaxed (options, filtered, sets[j].ArcMessageSignature, false); + WriteHeaderRelaxed (options, filtered, sets[j].ArcSeal, false); + } + + WriteHeaderRelaxed (options, filtered, sets[i].ArcAuthenticationResult, false); + WriteHeaderRelaxed (options, filtered, sets[i].ArcMessageSignature, false); + + // now include the ARC-Seal header that we are verifying, + // but only after removing the "b=" signature value. + var seal = GetSignedSignatureHeader (sets[i].ArcSeal); + + WriteHeaderRelaxed (options, filtered, seal, true); + + filtered.Flush (); + } + + return stream.VerifySignature (b); + } + } + + internal static ArcSignatureValidationResult GetArcHeaderSets (MimeMessage message, bool throwOnError, out ArcHeaderSet[] sets, out int count, out ArcValidationErrors errors) + { + ArcHeaderSet set; + + errors = ArcValidationErrors.None; + sets = new ArcHeaderSet[50]; + count = 0; + + for (int i = 0; i < message.Headers.Count; i++) { + Dictionary parameters = null; + var header = message.Headers[i]; + int instance = 0; + string value; + + switch (header.Id) { + case HeaderId.ArcAuthenticationResults: + if (!AuthenticationResults.TryParse (header.RawValue, out AuthenticationResults authres)) { + if (throwOnError) + throw new FormatException ("Invalid ARC-Authentication-Results header."); + + errors |= ArcValidationErrors.InvalidArcAuthenticationResults; + break; + } + + if (!authres.Instance.HasValue) { + if (throwOnError) + throw new FormatException ("Missing instance tag in ARC-Authentication-Results header."); + + errors |= ArcValidationErrors.InvalidArcAuthenticationResults; + break; + } + + instance = authres.Instance.Value; + + if (instance < 1 || instance > 50) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Invalid instance tag in ARC-Authentication-Results header: i={0}", instance)); + + errors |= ArcValidationErrors.InvalidArcAuthenticationResults; + instance = 0; + break; + } + break; + case HeaderId.ArcMessageSignature: + case HeaderId.ArcSeal: + try { + parameters = ParseParameterTags (header.Id, header.Value); + } catch { + if (throwOnError) + throw; + + if (header.Id == HeaderId.ArcMessageSignature) + errors |= ArcValidationErrors.InvalidArcMessageSignature; + else + errors |= ArcValidationErrors.InvalidArcSeal; + + break; + } + + if (!parameters.TryGetValue ("i", out value)) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing instance tag in {0} header.", header.Id.ToHeaderName ())); + + if (header.Id == HeaderId.ArcMessageSignature) + errors |= ArcValidationErrors.InvalidArcMessageSignature; + else + errors |= ArcValidationErrors.InvalidArcSeal; + + break; + } + + if (!int.TryParse (value, NumberStyles.Integer, CultureInfo.InvariantCulture, out instance) || instance < 1 || instance > 50) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Invalid instance tag in {0} header: i={1}", header.Id.ToHeaderName (), value)); + + if (header.Id == HeaderId.ArcMessageSignature) + errors |= ArcValidationErrors.InvalidArcMessageSignature; + else + errors |= ArcValidationErrors.InvalidArcSeal; + + instance = 0; + break; + } + break; + } + + if (instance == 0) + continue; + + set = sets[instance - 1]; + if (set == null) + sets[instance - 1] = set = new ArcHeaderSet (); + + if (!set.Add (header, parameters)) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Duplicate {0} header for i={1}", header.Id.ToHeaderName (), instance)); + + switch (header.Id) { + case HeaderId.ArcAuthenticationResults: + errors |= ArcValidationErrors.DuplicateArcAuthenticationResults; + break; + case HeaderId.ArcMessageSignature: + errors |= ArcValidationErrors.DuplicateArcMessageSignature; + break; + case HeaderId.ArcSeal: + errors |= ArcValidationErrors.DuplicateArcSeal; + break; + } + } + + if (instance > count) + count = instance; + } + + if (count == 0) { + // there are no ARC sets + return ArcSignatureValidationResult.None; + } + + // verify that all ARC sets are complete + for (int i = 0; i < count; i++) { + set = sets[i]; + + if (set == null) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing ARC headers for i={0}", i + 1)); + + if ((errors & ArcValidationErrors.InvalidArcAuthenticationResults) == 0) + errors |= ArcValidationErrors.MissingArcAuthenticationResults; + if ((errors & ArcValidationErrors.InvalidArcMessageSignature) == 0) + errors |= ArcValidationErrors.MissingArcMessageSignature; + if ((errors & ArcValidationErrors.InvalidArcSeal) == 0) + errors |= ArcValidationErrors.MissingArcSeal; + continue; + } + + if (set.ArcAuthenticationResult == null) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing ARC-Authentication-Results header for i={0}", i + 1)); + + if ((errors & ArcValidationErrors.InvalidArcAuthenticationResults) == 0) + errors |= ArcValidationErrors.MissingArcAuthenticationResults; + } + + if (set.ArcMessageSignature == null) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing ARC-Message-Signature header for i={0}", i + 1)); + + if ((errors & ArcValidationErrors.InvalidArcMessageSignature) == 0) + errors |= ArcValidationErrors.MissingArcMessageSignature; + } + + if (set.ArcSeal == null) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing ARC-Seal header for i={0}", i + 1)); + + if ((errors & ArcValidationErrors.InvalidArcSeal) == 0) + errors |= ArcValidationErrors.MissingArcSeal; + continue; + } + + if (!set.ArcSealParameters.TryGetValue ("cv", out string cv)) { + if (throwOnError) + throw new FormatException (string.Format (CultureInfo.InvariantCulture, "Missing chain validation tag in ARC-Seal header for i={0}.", i + 1)); + + errors |= ArcValidationErrors.MissingArcSealChainValidationValue; + continue; + } + + // The "cv" value for all ARC-Seal header fields MUST NOT be + // "fail". For ARC Sets with instance values > 1, the values + // MUST be "pass". For the ARC Set with instance value = 1, the + // value MUST be "none". + if (!cv.Equals (i == 0 ? "none" : "pass", StringComparison.Ordinal)) + errors |= ArcValidationErrors.InvalidArcSealChainValidationValue; + } + + return errors == ArcValidationErrors.None ? ArcSignatureValidationResult.Pass : ArcSignatureValidationResult.Fail; + } + + async Task VerifyAsync (FormatOptions options, MimeMessage message, bool doAsync, CancellationToken cancellationToken) + { + const ArcValidationErrors ArcSealCvParamErrors = ArcValidationErrors.InvalidArcSealChainValidationValue | ArcValidationErrors.MissingArcSealChainValidationValue; + + if (options == null) + throw new ArgumentNullException (nameof (options)); + + if (message == null) + throw new ArgumentNullException (nameof (message)); + + var result = new ArcValidationResult (); + + switch (GetArcHeaderSets (message, false, out ArcHeaderSet[] sets, out int count, out var errors)) { + case ArcSignatureValidationResult.None: return result; + case ArcSignatureValidationResult.Fail: + result.Chain = ArcSignatureValidationResult.Fail; + result.ChainErrors = errors; + + // If the only error(s) are invalid or missing 'cv' values, ignore the errors for now. + if ((errors & ~ArcSealCvParamErrors) == 0) + break; + + return result; + default: + result.Chain = ArcSignatureValidationResult.Pass; + break; + } + + int newest = count - 1; + + result.Seals = new ArcHeaderValidationResult[count]; + + // validate the most recent Arc-Message-Signature + try { + var parameters = sets[newest].ArcMessageSignatureParameters; + var header = sets[newest].ArcMessageSignature; + + result.MessageSignature = new ArcHeaderValidationResult (header); + + if (await VerifyArcMessageSignatureAsync (options, message, header, parameters, doAsync, cancellationToken).ConfigureAwait (false)) { + result.MessageSignature.Signature = ArcSignatureValidationResult.Pass; + } else { + result.MessageSignature.Signature = ArcSignatureValidationResult.Fail; + result.ChainErrors |= ArcValidationErrors.MessageSignatureValidationFailed; + result.Chain = ArcSignatureValidationResult.Fail; + } + } catch { + result.MessageSignature.Signature = ArcSignatureValidationResult.Fail; + result.ChainErrors |= ArcValidationErrors.MessageSignatureValidationFailed; + result.Chain = ArcSignatureValidationResult.Fail; + } + + // validate all Arc-Seals starting with the most recent and proceeding to the oldest + for (int i = newest; i >= 0; i--) { + result.Seals[i] = new ArcHeaderValidationResult (sets[i].ArcSeal); + + try { + if (await VerifyArcSealAsync (options, sets, i, doAsync, cancellationToken).ConfigureAwait (false)) { + result.Seals[i].Signature = ArcSignatureValidationResult.Pass; + } else { + result.Seals[i].Signature = ArcSignatureValidationResult.Fail; + result.ChainErrors |= ArcValidationErrors.SealValidationFailed; + result.Chain = ArcSignatureValidationResult.Fail; + } + } catch { + result.Seals[i].Signature = ArcSignatureValidationResult.Fail; + result.ChainErrors |= ArcValidationErrors.SealValidationFailed; + result.Chain = ArcSignatureValidationResult.Fail; + } + } + + return result; + } + + /// + /// Verify the ARC signature chain. + /// + /// + /// Verifies the ARC signature chain. + /// + /// + /// + /// + /// The ARC validation result. + /// The formatting options. + /// The message to verify. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public ArcValidationResult Verify (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (options, message, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously verify the ARC signature chain. + /// + /// + /// Asynchronously verifies the ARC signature chain. + /// + /// + /// + /// + /// The ARC validation result. + /// The formatting options. + /// The message to verify. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public Task VerifyAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (options, message, true, cancellationToken); + } + + /// + /// Verify the ARC signature chain. + /// + /// + /// Verifies the ARC signature chain. + /// + /// + /// + /// + /// The ARC validation result. + /// The message to verify. + /// The cancellation token. + /// + /// is null. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public ArcValidationResult Verify (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken)) + { + return Verify (FormatOptions.Default, message, cancellationToken); + } + + /// + /// Asynchronously verify the ARC signature chain. + /// + /// + /// Asynchronously verifies the ARC signature chain. + /// + /// + /// + /// + /// The ARC validation result. + /// The message to verify. + /// The cancellation token. + /// + /// is null. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public Task VerifyAsync (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (FormatOptions.Default, message, cancellationToken); + } + } +} diff --git a/MimeKit/Cryptography/AsymmetricAlgorithmExtensions.cs b/MimeKit/Cryptography/AsymmetricAlgorithmExtensions.cs index bf59ff25b3..a422250732 100644 --- a/MimeKit/Cryptography/AsymmetricAlgorithmExtensions.cs +++ b/MimeKit/Cryptography/AsymmetricAlgorithmExtensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ namespace MimeKit.Cryptography /// public static class AsymmetricAlgorithmExtensions { - static void GetAsymmetricKeyParameters (DSACryptoServiceProvider dsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key) + static void GetAsymmetricKeyParameters (DSA dsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key) { var dp = dsa.ExportParameters (!publicOnly); var validationParameters = dp.Seed != null ? new DsaValidationParameters (dp.Seed, dp.Counter) : null; @@ -57,26 +57,36 @@ static void GetAsymmetricKeyParameters (DSACryptoServiceProvider dsa, bool publi static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSACryptoServiceProvider dsa) { - AsymmetricKeyParameter pub, key; - - GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out pub, out key); + GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key); return dsa.PublicOnly ? pub : key; } static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSACryptoServiceProvider dsa) { - AsymmetricKeyParameter pub, key; - if (dsa.PublicOnly) throw new ArgumentException ("DSA key is not a private key.", "key"); - GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out pub, out key); + GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key); return new AsymmetricCipherKeyPair (pub, key); } - static void GetAsymmetricKeyParameters (RSACryptoServiceProvider rsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key) + static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSA dsa) + { + GetAsymmetricKeyParameters (dsa, false, out _, out var key); + + return key; + } + + static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSA dsa) + { + GetAsymmetricKeyParameters (dsa, false, out var pub, out var key); + + return new AsymmetricCipherKeyPair (pub, key); + } + + static void GetAsymmetricKeyParameters (RSA rsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key) { var rp = rsa.ExportParameters (!publicOnly); var modulus = new BigInteger (1, rp.Modulus); @@ -97,21 +107,31 @@ static void GetAsymmetricKeyParameters (RSACryptoServiceProvider rsa, bool publi static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSACryptoServiceProvider rsa) { - AsymmetricKeyParameter pub, key; - - GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out pub, out key); + GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key); return rsa.PublicOnly ? pub : key; } static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (RSACryptoServiceProvider rsa) { - AsymmetricKeyParameter pub, key; - if (rsa.PublicOnly) throw new ArgumentException ("RSA key is not a private key.", "key"); - GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out pub, out key); + GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key); + + return new AsymmetricCipherKeyPair (pub, key); + } + + static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSA rsa) + { + GetAsymmetricKeyParameters (rsa, false, out _, out var key); + + return key; + } + + static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (RSA rsa) + { + GetAsymmetricKeyParameters (rsa, false, out var pub, out var key); return new AsymmetricCipherKeyPair (pub, key); } @@ -136,11 +156,17 @@ public static AsymmetricKeyParameter AsAsymmetricKeyParameter (this AsymmetricAl if (key == null) throw new ArgumentNullException (nameof (key)); - if (key is DSACryptoServiceProvider) - return GetAsymmetricKeyParameter ((DSACryptoServiceProvider) key); + if (key is RSACryptoServiceProvider rsaKey) + return GetAsymmetricKeyParameter (rsaKey); + + if (key is RSA rsa) + return GetAsymmetricKeyParameter (rsa); - if (key is RSACryptoServiceProvider) - return GetAsymmetricKeyParameter ((RSACryptoServiceProvider) key); + if (key is DSACryptoServiceProvider dsaKey) + return GetAsymmetricKeyParameter (dsaKey); + + if (key is DSA dsa) + return GetAsymmetricKeyParameter (dsa); // TODO: support ECDiffieHellman and ECDsa? @@ -170,11 +196,17 @@ public static AsymmetricCipherKeyPair AsAsymmetricCipherKeyPair (this Asymmetric if (key == null) throw new ArgumentNullException (nameof (key)); - if (key is DSACryptoServiceProvider) - return GetAsymmetricCipherKeyPair ((DSACryptoServiceProvider) key); + if (key is RSACryptoServiceProvider rsaKey) + return GetAsymmetricCipherKeyPair (rsaKey); + + if (key is RSA rsa) + return GetAsymmetricCipherKeyPair (rsa); - if (key is RSACryptoServiceProvider) - return GetAsymmetricCipherKeyPair ((RSACryptoServiceProvider) key); + if (key is DSACryptoServiceProvider dsaKey) + return GetAsymmetricCipherKeyPair (dsaKey); + + if (key is DSA dsa) + return GetAsymmetricCipherKeyPair (dsa); // TODO: support ECDiffieHellman and ECDsa? @@ -220,6 +252,7 @@ static AsymmetricAlgorithm GetAsymmetricAlgorithm (DsaPrivateKeyParameters key, parameters.Y = pub.Y.ToByteArrayUnsigned (); var dsa = new DSACryptoServiceProvider (); + dsa.ImportParameters (parameters); return dsa; @@ -231,6 +264,7 @@ static AsymmetricAlgorithm GetAsymmetricAlgorithm (DsaPublicKeyParameters key) parameters.Y = key.Y.ToByteArrayUnsigned (); var dsa = new DSACryptoServiceProvider (); + dsa.ImportParameters (parameters); return dsa; @@ -251,6 +285,7 @@ static AsymmetricAlgorithm GetAsymmetricAlgorithm (RsaPrivateCrtKeyParameters ke parameters.DQ = GetPaddedByteArray (key.DQ, parameters.Q.Length); var rsa = new RSACryptoServiceProvider (); + rsa.ImportParameters (parameters); return rsa; @@ -263,6 +298,7 @@ static AsymmetricAlgorithm GetAsymmetricAlgorithm (RsaKeyParameters key) parameters.Modulus = key.Modulus.ToByteArrayUnsigned (); var rsa = new RSACryptoServiceProvider (); + rsa.ImportParameters (parameters); return rsa; @@ -289,17 +325,17 @@ public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricKeyParam throw new ArgumentNullException (nameof (key)); if (key.IsPrivate) { - if (key is DsaPrivateKeyParameters) - return GetAsymmetricAlgorithm ((DsaPrivateKeyParameters) key, null); + if (key is RsaPrivateCrtKeyParameters rsaPrivateKey) + return GetAsymmetricAlgorithm (rsaPrivateKey); - if (key is RsaPrivateCrtKeyParameters) - return GetAsymmetricAlgorithm ((RsaPrivateCrtKeyParameters) key); + if (key is DsaPrivateKeyParameters dsaPrivateKey) + return GetAsymmetricAlgorithm (dsaPrivateKey, null); } else { - if (key is DsaPublicKeyParameters) - return GetAsymmetricAlgorithm ((DsaPublicKeyParameters) key); + if (key is RsaKeyParameters rsaPublicKey) + return GetAsymmetricAlgorithm (rsaPublicKey); - if (key is RsaKeyParameters) - return GetAsymmetricAlgorithm ((RsaKeyParameters) key); + if (key is DsaPublicKeyParameters dsaPublicKey) + return GetAsymmetricAlgorithm (dsaPublicKey); } throw new NotSupportedException (string.Format ("{0} is currently not supported.", key.GetType ().Name)); @@ -325,11 +361,11 @@ public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricCipherKe if (key == null) throw new ArgumentNullException (nameof (key)); - if (key.Private is DsaPrivateKeyParameters) - return GetAsymmetricAlgorithm ((DsaPrivateKeyParameters) key.Private, (DsaPublicKeyParameters) key.Public); + if (key.Private is RsaPrivateCrtKeyParameters rsaPrivateKey) + return GetAsymmetricAlgorithm (rsaPrivateKey); - if (key.Private is RsaPrivateCrtKeyParameters) - return GetAsymmetricAlgorithm ((RsaPrivateCrtKeyParameters) key.Private); + if (key.Private is DsaPrivateKeyParameters dsaPrivateKey) + return GetAsymmetricAlgorithm (dsaPrivateKey, (DsaPublicKeyParameters) key.Public); throw new NotSupportedException (string.Format ("{0} is currently not supported.", key.GetType ().Name)); } diff --git a/MimeKit/Cryptography/AuthenticationResults.cs b/MimeKit/Cryptography/AuthenticationResults.cs new file mode 100644 index 0000000000..b8e710ebd3 --- /dev/null +++ b/MimeKit/Cryptography/AuthenticationResults.cs @@ -0,0 +1,1332 @@ +// +// AuthenticationResults.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; + +using MimeKit.Utils; + +namespace MimeKit.Cryptography { + /// + /// A parsed representation of the Authentication-Results header. + /// + /// + /// The Authentication-Results header is used with electronic mail messages to + /// indicate the results of message authentication efforts. Any receiver-side + /// software, such as mail filters or Mail User Agents (MUAs), can use this header + /// field to relay that information in a convenient and meaningful way to users or + /// to make sorting and filtering decisions. + /// + public class AuthenticationResults + { + AuthenticationResults () + { + Results = new List (); + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The authentication service identifier. + /// + /// is null. + /// + public AuthenticationResults (string authservid) : this () + { + if (authservid == null) + throw new ArgumentNullException (nameof (authservid)); + + AuthenticationServiceIdentifier = authservid; + } + + /// + /// Get the authentication service identifier. + /// + /// + /// Gets the authentication service identifier. + /// The authentication service identifier is the authserv-id token + /// as defined in rfc7601. + /// + /// The authserv-id token. + public string AuthenticationServiceIdentifier { + get; private set; + } + + /// + /// Get or set the instance value. + /// + /// + /// Gets or sets the instance value. + /// This value will only be set if the + /// represents an ARC-Authentication-Results header value. + /// + /// The instance. + public int? Instance { + get; set; + } + + /// + /// Get or set the Authentication-Results version. + /// + /// + /// Gets or sets the Authentication-Results version. + /// The version value is the authres-version token as defined in + /// rfc7601. + /// + /// The authres-version token. + public int? Version { + get; set; + } + + /// + /// Get the list of authentication results. + /// + /// + /// Gets the list of authentication results. + /// + /// The list of authentication results. + public List Results { + get; private set; + } + + internal void Encode (FormatOptions options, StringBuilder builder, int lineLength) + { + int space = 1; + + if (Instance.HasValue) { + var i = Instance.Value.ToString (CultureInfo.InvariantCulture); + + builder.AppendFormat (" i={0};", i); + lineLength += 4 + i.Length; + } + + if (AuthenticationServiceIdentifier != null) { + if (lineLength + space + AuthenticationServiceIdentifier.Length > options.MaxLineLength) { + builder.Append (options.NewLine); + builder.Append ('\t'); + lineLength = 1; + space = 0; + } + + if (space > 0) { + builder.Append (' '); + lineLength++; + } + + builder.Append (AuthenticationServiceIdentifier); + lineLength += AuthenticationServiceIdentifier.Length; + + if (Version.HasValue) { + var version = Version.Value.ToString (CultureInfo.InvariantCulture); + + if (lineLength + 1 + version.Length > options.MaxLineLength) { + builder.Append (options.NewLine); + builder.Append ('\t'); + lineLength = 1; + } else { + builder.Append (' '); + lineLength++; + } + + lineLength += version.Length; + builder.Append (version); + } + + builder.Append (';'); + lineLength++; + } + + if (Results.Count > 0) { + for (int i = 0; i < Results.Count; i++) { + if (i > 0) { + builder.Append (';'); + lineLength++; + } + + Results[i].Encode (options, builder, ref lineLength); + } + } else { + builder.Append (" none"); + } + + builder.Append (options.NewLine); + } + + /// + /// Serializes the to a string. + /// + /// + /// Creates a string-representation of the . + /// + /// The serialized string. + public override string ToString () + { + var builder = new StringBuilder (); + + if (Instance.HasValue) + builder.AppendFormat ("i={0}; ", Instance.Value.ToString (CultureInfo.InvariantCulture)); + + if (AuthenticationServiceIdentifier != null) { + builder.Append (AuthenticationServiceIdentifier); + + if (Version.HasValue) { + builder.Append (' '); + builder.Append (Version.Value.ToString (CultureInfo.InvariantCulture)); + } + + builder.Append ("; "); + } + + if (Results.Count > 0) { + for (int i = 0; i < Results.Count; i++) { + if (i > 0) + builder.Append ("; "); + builder.Append (Results[i]); + } + } else { + builder.Append ("none"); + } + + return builder.ToString (); + } + + static bool IsKeyword (byte c) + { + return (c >= (byte) 'A' && c <= (byte) 'Z') || + (c >= (byte) 'a' && c <= (byte) 'z') || + (c >= (byte) '0' && c <= (byte) '9') || + c == (byte) '-' || c == (byte) '_'; + } + + static bool SkipKeyword (byte[] text, ref int index, int endIndex) + { + int startIndex = index; + + while (index < endIndex && IsKeyword (text[index])) + index++; + + return index > startIndex; + } + + static bool SkipValue (byte[] text, ref int index, int endIndex, out bool quoted) + { + if (text[index] == (byte) '"') { + quoted = true; + + if (!ParseUtils.SkipQuoted (text, ref index, endIndex, false)) + return false; + } else { + quoted = false; + + if (!ParseUtils.SkipToken (text, ref index, endIndex)) + return false; + } + + return true; + } + + static bool SkipDomain (byte[] text, ref int index, int endIndex) + { + int startIndex = index; + + while (ParseUtils.SkipAtom (text, ref index, endIndex) && index < endIndex && text[index] == (byte) '.') + index++; + + if (index > startIndex && text[index - 1] != (byte) '.') + return true; + + return false; + } + + static bool SkipPropertyValue (byte[] text, ref int index, int endIndex, out bool quoted) + { + // pvalue := [CFWS] ( value / [ [ local-part ] "@" ] domain-name ) [CFWS] + // value := token / quoted-string + // token := 1* + // tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "=" + if (text[index] == (byte) '"') { + // quoted-string + quoted = true; + + if (!ParseUtils.SkipQuoted (text, ref index, endIndex, false)) + return false; + + return true; + } + + quoted = false; + + // Note: we're forced to accept even tspecials in the property value because they are used in the real-world. + // See https://github.com/jstedfast/MimeKit/issues/518 ('/') and https://github.com/jstedfast/MimeKit/issues/590 ('=') + // for details. + while (index < endIndex && !text[index].IsWhitespace() && text[index] != (byte) ';' && text[index] != (byte) '(') + index++; + + return true; + } + + static bool TryParseMethods (byte[] text, ref int index, int endIndex, bool throwOnError, AuthenticationResults authres) + { + string value; + bool quoted; + + while (index < endIndex) { + string srvid = null; + + method_token: + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) + break; + + int methodIndex = index; + + // skip the method name + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid method token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + // Note: Office365 seems to (sometimes) place a method-specific authserv-id token before each + // method. This block of code is here to handle that case. + // + // See https://github.com/jstedfast/MimeKit/issues/527 for details. + if (srvid == null && index < endIndex && text[index] == '.') { + index = methodIndex; + + if (!SkipDomain (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid Office365 authserv-id token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + srvid = Encoding.UTF8.GetString (text, methodIndex, index - methodIndex); + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Missing semi-colon after Office365 authserv-id token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + if (text[index] != (byte) ';') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token after Office365 authserv-id token at offset {0}", index), index, index); + + return false; + } + + // skip over ';' + index++; + + goto method_token; + } + + var method = Encoding.ASCII.GetString (text, methodIndex, index - methodIndex); + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (method != "none") { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete methodspec token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + if (authres.Results.Count > 0) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid no-result token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + break; + } + + var resinfo = new AuthenticationMethodResult (method); + resinfo.Office365AuthenticationServiceIdentifier = srvid; + authres.Results.Add (resinfo); + + int tokenIndex; + + if (text[index] == (byte) '/') { + // optional method-version token + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + tokenIndex = index; + + if (!ParseUtils.TryParseInt32 (text, ref index, endIndex, out int version)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid method-version token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + resinfo.Version = version; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete methodspec token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + } + + if (text[index] != (byte) '=') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid methodspec token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + // skip over '=' + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete methodspec token at offset {0}", methodIndex), methodIndex, index); + + return false; + } + + tokenIndex = index; + + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid result token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + resinfo.Result = Encoding.ASCII.GetString (text, tokenIndex, index - tokenIndex); + + ParseUtils.SkipWhiteSpace (text, ref index, endIndex); + + if (index < endIndex && text[index] == (byte) '(') { + int commentIndex = index; + + if (!ParseUtils.SkipComment (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete comment token at offset {0}", commentIndex), commentIndex, index); + + return false; + } + + commentIndex++; + + resinfo.ResultComment = Header.Unfold (Encoding.UTF8.GetString (text, commentIndex, (index - 1) - commentIndex)); + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + } + + if (index >= endIndex) + break; + + if (text[index] == (byte) ';') { + index++; + continue; + } + + // optional reasonspec or propspec + tokenIndex = index; + + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid reasonspec or propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + value = Encoding.ASCII.GetString (text, tokenIndex, index - tokenIndex); + + if (value == "reason" || value == "action") { + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete {0}spec token at offset {1}", value, tokenIndex), tokenIndex, index); + + return false; + } + + if (text[index] != (byte) '=') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid {0}spec token at offset {1}", value, tokenIndex), tokenIndex, index); + + return false; + } + + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + int reasonIndex = index; + + if (index >= endIndex || !SkipValue (text, ref index, endIndex, out quoted)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid {0}spec value token at offset {1}", value, reasonIndex), reasonIndex, index); + + return false; + } + + var reason = Encoding.UTF8.GetString (text, reasonIndex, index - reasonIndex); + + if (quoted) + reason = MimeUtils.Unquote (reason); + + if (value == "action") + resinfo.Action = reason; + else + resinfo.Reason = reason; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) + break; + + if (text[index] == (byte) ';') { + index++; + continue; + } + + // optional propspec + tokenIndex = index; + + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + value = Encoding.ASCII.GetString (text, tokenIndex, index - tokenIndex); + } + + do { + // value is a propspec ptype token + var ptype = value; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + if (text[index] != (byte) '.') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + int propertyIndex = index; + + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid property token at offset {0}", propertyIndex), propertyIndex, index); + + return false; + } + + var property = Encoding.ASCII.GetString (text, propertyIndex, index - propertyIndex); + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + if (text[index] != (byte) '=') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + int valueIndex = index; + + if (index >= text.Length || !SkipPropertyValue (text, ref index, endIndex, out quoted)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + value = Encoding.UTF8.GetString (text, valueIndex, index - valueIndex); + + if (quoted) + value = MimeUtils.Unquote (value); + + var propspec = new AuthenticationMethodProperty (ptype, property, value, quoted); + resinfo.Properties.Add (propspec); + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex || text[index] == (byte) ';') + break; + + tokenIndex = index; + + if (!SkipKeyword (text, ref index, endIndex)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid propspec token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + value = Encoding.ASCII.GetString (text, tokenIndex, index - tokenIndex); + } while (true); + + // skip over ';' + index++; + } + + return true; + } + + static bool TryParse (byte[] text, ref int index, int endIndex, bool throwOnError, out AuthenticationResults authres) + { + int? instance = null; + string srvid = null; + string value; + bool quoted; + + authres = null; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + do { + int start = index; + + if (index >= endIndex || !SkipValue (text, ref index, endIndex, out quoted)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete authserv-id token at offset {0}", start), start, index); + + return false; + } + + value = Encoding.UTF8.GetString (text, start, index - start); + + if (quoted) { + // this can only be the authserv-id token + srvid = MimeUtils.Unquote (value); + } else { + // this could either be the authserv-id or it could be "i=#" (ARC instance) + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index < endIndex && text[index] == (byte) '=') { + // probably i=# + if (instance.HasValue) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid token at offset {0}", start), start, index); + + return false; + } + + if (value != "i") { + // Office 365 Authentication-Results do not include an authserv-id token, so this is probably a method. + // Rewind the parser and start over again with the assumption that the Authentication-Results only + // contains methods. + // + // See https://github.com/jstedfast/MimeKit/issues/490 for details. + + authres = new AuthenticationResults (); + index = 0; + + return TryParseMethods (text, ref index, endIndex, throwOnError, authres); + } + + // skip over '=' + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + start = index; + + if (!ParseUtils.TryParseInt32 (text, ref index, endIndex, out int i)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid instance value at offset {0}", start), start, index); + + return false; + } + + instance = i; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Missing semi-colon after instance value at offset {0}", start), start, index); + + return false; + } + + if (text[index] != (byte) ';') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token after instance value at offset {0}", index), index, index); + + return false; + } + + // skip over ';' + index++; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + } else { + srvid = value; + } + } + } while (srvid == null); + + authres = new AuthenticationResults (srvid) { Instance = instance }; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) + return true; + + if (text[index] != (byte) ';') { + // might be the authres-version token + int start = index; + + if (!ParseUtils.TryParseInt32 (text, ref index, endIndex, out int version)) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid authres-version at offset {0}", start), start, index); + + return false; + } + + authres.Version = version; + + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) + return true; + + if (text[index] != (byte) ';') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unknown token at offset {0}", index), index, index); + + return false; + } + } + + // skip the ';' + index++; + + return TryParseMethods (text, ref index, endIndex, throwOnError, authres); + } + + /// + /// Try to parse the given input buffer into a new instance. + /// + /// + /// Parses an Authentication-Results header value from the supplied buffer starting at the given index + /// and spanning across the specified number of bytes. + /// + /// true if the authentication results were successfully parsed; otherwise, false. + /// The input buffer. + /// The starting index of the input buffer. + /// The number of bytes in the input buffer to parse. + /// The parsed authentication results. + /// + /// is null. + /// + /// + /// and do not specify + /// a valid range in the byte array. + /// + public static bool TryParse (byte[] buffer, int startIndex, int length, out AuthenticationResults authres) + { + ParseUtils.ValidateArguments (buffer, startIndex, length); + + int index = startIndex; + + return TryParse (buffer, ref index, startIndex + length, false, out authres); + } + + /// + /// Try to parse the given input buffer into a new instance. + /// + /// + /// Parses an Authentication-Results header value from the supplied buffer. + /// + /// true if the authentication results were successfully parsed; otherwise, false. + /// The input buffer. + /// The parsed authentication results. + /// + /// is null. + /// + public static bool TryParse (byte[] buffer, out AuthenticationResults authres) + { + if (buffer == null) + throw new ArgumentNullException (nameof (buffer)); + + int index = 0; + + return TryParse (buffer, ref index, buffer.Length, false, out authres); + } + + /// + /// Parse the specified input buffer into a new instance of the class. + /// + /// + /// Parses an Authentication-Results header value from the supplied buffer starting at the given index + /// and spanning across the specified number of bytes. + /// + /// The parsed . + /// The input buffer. + /// The start index of the buffer. + /// The length of the buffer. + /// + /// is null. + /// + /// + /// and do not specify + /// a valid range in the byte array. + /// + /// + /// The could not be parsed. + /// + public static AuthenticationResults Parse (byte[] buffer, int startIndex, int length) + { + ParseUtils.ValidateArguments (buffer, startIndex, length); + + AuthenticationResults authres; + int index = startIndex; + + TryParse (buffer, ref index, startIndex + length, true, out authres); + + return authres; + } + + /// + /// Parse the specified input buffer into a new instance of the class. + /// + /// + /// Parses an Authentication-Results header value from the supplied buffer. + /// + /// The parsed . + /// The input buffer. + /// + /// is null. + /// + /// + /// The could not be parsed. + /// + public static AuthenticationResults Parse (byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException (nameof (buffer)); + + AuthenticationResults authres; + int index = 0; + + TryParse (buffer, ref index, buffer.Length, true, out authres); + + return authres; + } + } + + /// + /// An authentication method results. + /// + /// + /// An authentication method results. + /// + public class AuthenticationMethodResult + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The method used for authentication. + /// + /// is null. + /// + internal AuthenticationMethodResult (string method) + { + if (method == null) + throw new ArgumentNullException (nameof (method)); + + Properties = new List (); + Method = method; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The method used for authentication. + /// The result of the authentication method. + /// + /// is null. + /// -or- + /// is null. + /// + public AuthenticationMethodResult (string method, string result) : this (method) + { + if (result == null) + throw new ArgumentNullException (nameof (result)); + + Result = result; + } + + /// + /// Get the Office365 method-specific authserv-id. + /// + /// + /// Gets the Office365 method-specific authserv-id. + /// An authentication service identifier is the authserv-id token + /// as defined in rfc7601. + /// Instead of specifying a single authentication service identifier at the + /// beginning of the header value, Office365 seems to provide a different + /// authentication service identifier for each method. + /// + /// The authserv-id token. + public string Office365AuthenticationServiceIdentifier { + get; internal set; + } + + /// + /// Get the authentication method. + /// + /// + /// Gets the authentication method. + /// + /// The authentication method. + public string Method { + get; private set; + } + + /// + /// Get the authentication method version. + /// + /// + /// Gets the authentication method version. + /// + /// The authentication method version. + public int? Version { + get; set; + } + + /// + /// Get the authentication method results. + /// + /// + /// Gets the authentication method results. + /// + /// The authentication method results. + public string Result { + get; internal set; + } + + /// + /// Get the comment regarding the authentication method result. + /// + /// + /// Gets the comment regarding the authentication method result. + /// + /// The comment regarding the authentication method result. + public string ResultComment { + get; set; + } + + /// + /// Get the action taken for the authentication method result. + /// + /// + /// Gets the action taken for the authentication method result. + /// + /// The action taken for the authentication method result. + public string Action { + get; internal set; + } + + /// + /// Get the reason for the authentication method result. + /// + /// + /// Gets the reason for the authentication method result. + /// + /// The reason for the authentication method result. + public string Reason { + get; set; + } + + /// + /// Get the properties used by the authentication method. + /// + /// + /// Gets the properties used by the authentication method. + /// + /// The properties used by the authentication method. + public List Properties { + get; private set; + } + + internal void Encode (FormatOptions options, StringBuilder builder, ref int lineLength) + { + // try to put the entire result on 1 line + var complete = ToString (); + + if (complete.Length + 1 < options.MaxLineLength) { + // if it fits, it sits... + if (lineLength + complete.Length + 1 > options.MaxLineLength) { + builder.Append (options.NewLine); + builder.Append ('\t'); + lineLength = 1; + } else { + builder.Append (' '); + lineLength++; + } + + lineLength += complete.Length; + builder.Append (complete); + return; + } + + // Note: if we've made it this far, then we can't put everything on one line... + + var tokens = new List (); + tokens.Add (" "); + + if (Office365AuthenticationServiceIdentifier != null) { + tokens.Add (Office365AuthenticationServiceIdentifier); + tokens.Add (";"); + tokens.Add (" "); + } + + if (Version.HasValue) { + var version = Version.Value.ToString (CultureInfo.InvariantCulture); + + if (Method.Length + 1 + version.Length + 1 + Result.Length < options.MaxLineLength) { + tokens.Add ($"{Method}/{version}={Result}"); + } else if (Method.Length + 1 + version.Length < options.MaxLineLength) { + tokens.Add ($"{Method}/{version}"); + tokens.Add ("="); + tokens.Add (Result); + } else { + tokens.Add (Method); + tokens.Add ("/"); + tokens.Add (version); + tokens.Add ("="); + tokens.Add (Result); + } + } else { + if (Method.Length + 1 + Result.Length < options.MaxLineLength) { + tokens.Add ($"{Method}={Result}"); + } else { + // we will have to break this up into individual tokens + tokens.Add (Method); + tokens.Add ("="); + tokens.Add (Result); + } + } + + if (!string.IsNullOrEmpty (ResultComment)) { + tokens.Add (" "); + tokens.Add ($"({ResultComment})"); + } + + if (!string.IsNullOrEmpty (Reason)) { + var reason = MimeUtils.Quote (Reason); + + tokens.Add (" "); + + if ("reason=".Length + reason.Length < options.MaxLineLength) { + tokens.Add ($"reason={reason}"); + } else { + tokens.Add ("reason="); + tokens.Add (reason); + } + } else if (!string.IsNullOrEmpty (Action)) { + var action = MimeUtils.Quote (Action); + + tokens.Add (" "); + + if ("action=".Length + action.Length < options.MaxLineLength) { + tokens.Add ($"action={action}"); + } else { + tokens.Add ("action="); + tokens.Add (action); + } + } + + for (int i = 0; i < Properties.Count; i++) + Properties[i].AppendTokens (options, tokens); + + builder.AppendTokens (options, ref lineLength, tokens); + } + + /// + /// Serializes the to a string. + /// + /// + /// Creates a string-representation of the . + /// + /// The serialized string. + public override string ToString () + { + var builder = new StringBuilder (); + + if (Office365AuthenticationServiceIdentifier != null) { + builder.Append (Office365AuthenticationServiceIdentifier); + builder.Append ("; "); + } + + builder.Append (Method); + + if (Version.HasValue) { + builder.Append ('/'); + builder.Append (Version.Value.ToString (CultureInfo.InvariantCulture)); + } + + builder.Append ('='); + builder.Append (Result); + + if (!string.IsNullOrEmpty (ResultComment)) { + builder.Append (" ("); + builder.Append (ResultComment); + builder.Append (')'); + } + + if (!string.IsNullOrEmpty (Reason)) { + builder.Append (" reason="); + builder.Append (MimeUtils.Quote (Reason)); + } else if (!string.IsNullOrEmpty (Action)) { + builder.Append (" action="); + builder.Append (MimeUtils.Quote (Action)); + } + + for (int i = 0; i < Properties.Count; i++) { + builder.Append (' '); + builder.Append (Properties[i]); + } + + return builder.ToString (); + } + } + + /// + /// An authentication method property. + /// + /// + /// An authentication method property. + /// + public class AuthenticationMethodProperty + { + static readonly char[] TokenSpecials = ByteExtensions.TokenSpecials.ToCharArray (); + bool? quoted; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The property type. + /// The name of the property. + /// The value of the property. + /// true if the property value was originally quoted; otherwise, false. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + internal AuthenticationMethodProperty (string ptype, string property, string value, bool? quoted) + { + if (ptype == null) + throw new ArgumentNullException (nameof (ptype)); + + if (property == null) + throw new ArgumentNullException (nameof (property)); + + if (value == null) + throw new ArgumentNullException (nameof (value)); + + this.quoted = quoted; + PropertyType = ptype; + Property = property; + Value = value; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The property type. + /// The name of the property. + /// The value of the property. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + public AuthenticationMethodProperty (string ptype, string property, string value) : this (ptype, property, value, null) + { + } + + /// + /// Get the type of the property. + /// + /// + /// Gets the type of the property. + /// + /// The type of the property. + public string PropertyType { + get; private set; + } + + /// + /// Get the property name. + /// + /// + /// Gets the property name. + /// + /// The name of the property. + public string Property { + get; private set; + } + + /// + /// Get the property value. + /// + /// + /// Gets the property value. + /// + /// The value of the property. + public string Value { + get; private set; + } + + internal void AppendTokens (FormatOptions options, List tokens) + { + var quote = quoted.HasValue ? quoted.Value : Value.IndexOfAny (TokenSpecials) != -1; + var value = quote ? MimeUtils.Quote (Value) : Value; + + tokens.Add (" "); + + if (PropertyType.Length + 1 + Property.Length + 1 + value.Length < options.MaxLineLength) { + tokens.Add ($"{PropertyType}.{Property}={value}"); + } else if (PropertyType.Length + 1 + Property.Length + 1 < options.MaxLineLength) { + tokens.Add ($"{PropertyType}.{Property}="); + tokens.Add (value); + } else { + tokens.Add (PropertyType); + tokens.Add ("."); + tokens.Add (Property); + tokens.Add ("="); + tokens.Add (value); + } + } + + /// + /// Serializes the to a string. + /// + /// + /// Creates a string-representation of the . + /// + /// The serialized string. + public override string ToString () + { + var quote = quoted.HasValue ? quoted.Value : Value.IndexOfAny (TokenSpecials) != -1; + var value = quote ? MimeUtils.Quote (Value) : Value; + + return $"{PropertyType}.{Property}={value}"; + } + } +} diff --git a/MimeKit/Cryptography/BouncyCastleCertificateExtensions.cs b/MimeKit/Cryptography/BouncyCastleCertificateExtensions.cs index 4bb201f330..10d2e31394 100644 --- a/MimeKit/Cryptography/BouncyCastleCertificateExtensions.cs +++ b/MimeKit/Cryptography/BouncyCastleCertificateExtensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,10 +34,9 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Asn1.Smime; using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; -#if !PORTABLE using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; -#endif namespace MimeKit.Cryptography { /// @@ -48,7 +47,6 @@ namespace MimeKit.Cryptography { /// public static class BouncyCastleCertificateExtensions { -#if !PORTABLE /// /// Convert a BouncyCastle certificate into an X509Certificate2. /// @@ -67,7 +65,11 @@ public static X509Certificate2 AsX509Certificate2 (this X509Certificate certific return new X509Certificate2 (certificate.GetEncoded ()); } -#endif + + internal static bool IsSelfSigned (this X509Certificate certificate) + { + return certificate.SubjectDN.Equivalent (certificate.IssuerDN); + } /// /// Gets the issuer name info. @@ -89,7 +91,7 @@ public static string GetIssuerNameInfo (this X509Certificate certificate, DerObj // FIXME: GetValueList() should be fixed to return IList var list = certificate.IssuerDN.GetValueList (identifier); if (list.Count == 0) - return null; + return string.Empty; return (string) list[0]; } @@ -114,7 +116,7 @@ public static string GetSubjectNameInfo (this X509Certificate certificate, DerOb // FIXME: GetValueList() should be fixed to return IList var list = certificate.SubjectDN.GetValueList (identifier); if (list.Count == 0) - return null; + return string.Empty; return (string) list[0]; } @@ -168,13 +170,13 @@ public static string GetSubjectEmailAddress (this X509Certificate certificate) { var address = certificate.GetSubjectNameInfo (X509Name.EmailAddress); - if (address != null) + if (!string.IsNullOrEmpty (address)) return address; var alt = certificate.GetExtensionValue (X509Extensions.SubjectAlternativeName); if (alt == null) - return null; + return string.Empty; var seq = Asn1Sequence.GetInstance (Asn1Object.FromByteArray (alt.GetOctets ())); @@ -188,6 +190,16 @@ public static string GetSubjectEmailAddress (this X509Certificate certificate) return null; } + internal static string AsHex (this byte[] blob) + { + var hex = new StringBuilder (blob.Length * 2); + + for (int i = 0; i < blob.Length; i++) + hex.Append (blob[i].ToString ("x2")); + + return hex.ToString (); + } + /// /// Gets the fingerprint of the certificate. /// @@ -206,17 +218,46 @@ public static string GetFingerprint (this X509Certificate certificate) throw new ArgumentNullException (nameof (certificate)); var encoded = certificate.GetEncoded (); - var fingerprint = new StringBuilder (); var sha1 = new Sha1Digest (); - var data = new byte[20]; sha1.BlockUpdate (encoded, 0, encoded.Length); - sha1.DoFinal (data, 0); - for (int i = 0; i < data.Length; i++) - fingerprint.Append (data[i].ToString ("x2")); + var fingerprint = new byte[20]; + sha1.DoFinal (fingerprint, 0); + + return fingerprint.AsHex (); + } + + /// + /// Gets the public key algorithm for the certificate. + /// + /// + /// Gets the public key algorithm for the ceretificate. + /// + /// The public key algorithm. + /// The certificate. + /// + /// is null. + /// + public static PublicKeyAlgorithm GetPublicKeyAlgorithm (this X509Certificate certificate) + { + if (certificate == null) + throw new ArgumentNullException (nameof (certificate)); + + var pubkey = certificate.GetPublicKey (); + + if (pubkey is DsaKeyParameters) + return PublicKeyAlgorithm.Dsa; + if (pubkey is RsaKeyParameters) + return PublicKeyAlgorithm.RsaGeneral; + if (pubkey is ElGamalKeyParameters) + return PublicKeyAlgorithm.ElGamalGeneral; + if (pubkey is ECKeyParameters) + return PublicKeyAlgorithm.EllipticCurve; + if (pubkey is DHKeyParameters) + return PublicKeyAlgorithm.DiffieHellman; - return fingerprint.ToString (); + return PublicKeyAlgorithm.None; } internal static X509KeyUsageFlags GetKeyUsageFlags (bool[] usage) @@ -319,7 +360,7 @@ internal static bool IsDelta (this X509Crl crl) { var critical = crl.GetCriticalExtensionOids (); - return critical.Contains (X509Extensions.DeltaCrlIndicator.Id); + return critical != null ? critical.Contains (X509Extensions.DeltaCrlIndicator.Id) : false; } } } diff --git a/MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs b/MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs index 2d2aa6e867..616060f332 100644 --- a/MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs +++ b/MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,17 +42,20 @@ using Org.BouncyCastle.Pkix; using Org.BouncyCastle.X509; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Security; using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.Smime; using Org.BouncyCastle.X509.Store; using Org.BouncyCastle.Utilities.Date; +using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Utilities.Collections; -using Org.BouncyCastle.Asn1.Smime; -using Org.BouncyCastle.Asn1.X509; using AttributeTable = Org.BouncyCastle.Asn1.Cms.AttributeTable; +using IssuerAndSerialNumber = Org.BouncyCastle.Asn1.Cms.IssuerAndSerialNumber; using MimeKit.IO; -using MimeKit.Utils; namespace MimeKit.Cryptography { @@ -64,30 +67,36 @@ namespace MimeKit.Cryptography /// public abstract class BouncyCastleSecureMimeContext : SecureMimeContext { + static readonly string RsassaPssOid = PkcsObjectIdentifiers.IdRsassaPss.Id; + HttpClient client; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new /// protected BouncyCastleSecureMimeContext () { - CheckCertificateRevocation = true; client = new HttpClient (); } /// - /// Get or set whether or not certificate revocation should be checked when verifying signatures. + /// Get or set whether or not certificate revocation lists should be downloaded when verifying signatures. /// /// - /// Gets or sets whether or not certificate revocation should be checked when verifying signatures. + /// Gets or sets whether or not certificate revocation lists should be downloaded when verifying + /// signatures. /// If enabled, the will attempt to automatically download /// Certificate Revocation Lists (CRLs) from the internet based on the CRL Distribution Point extension on /// each certificate. + /// Enabling this feature opens the client up to potential privacy risks. An attacker + /// can generate a custom X.509 certificate containing a CRL Distribution Point or OCSP URL pointing to an + /// attacker-controlled server, thereby getting a notification when the user decrypts the message or verifies + /// its digital signature. /// - /// true if certificate revocation should be checked; otherwise, false. + /// true if CRLs should be downloaded automatically; otherwise, false. public bool CheckCertificateRevocation { get; set; } @@ -237,20 +246,40 @@ protected CmsRecipientCollection GetCmsRecipients (IEnumerable m /// The timestamp. protected abstract void UpdateSecureMimeCapabilities (X509Certificate certificate, EncryptionAlgorithm[] algorithms, DateTime timestamp); - AttributeTable AddSecureMimeCapabilities (AttributeTable signedAttributes) + CmsAttributeTableGenerator AddSecureMimeCapabilities (AttributeTable signedAttributes) { - var attr = GetSecureMimeCapabilitiesAttribute (); + var attr = GetSecureMimeCapabilitiesAttribute (true); // populate our signed attributes with some S/MIME capabilities - return signedAttributes.Add (attr.AttrType, attr.AttrValues[0]); + return new DefaultSignedAttributeTableGenerator (signedAttributes.Add (attr.AttrType, attr.AttrValues[0])); } Stream Sign (CmsSigner signer, Stream content, bool encapsulate) { + var unsignedAttributes = new SimpleAttributeTableGenerator (signer.UnsignedAttributes); + var signedAttributes = AddSecureMimeCapabilities (signer.SignedAttributes); var signedData = new CmsSignedDataStreamGenerator (); + var digestOid = GetDigestOid (signer.DigestAlgorithm); + byte[] subjectKeyId = null; + + if (signer.SignerIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) { + var subjectKeyIdentifier = signer.Certificate.GetExtensionValue (X509Extensions.SubjectKeyIdentifier); + if (subjectKeyIdentifier != null) { + var id = (Asn1OctetString) Asn1Object.FromByteArray (subjectKeyIdentifier.GetOctets ()); + subjectKeyId = id.GetOctets (); + } + } - signedData.AddSigner (signer.PrivateKey, signer.Certificate, GetDigestOid (signer.DigestAlgorithm), - AddSecureMimeCapabilities (signer.SignedAttributes), signer.UnsignedAttributes); + if (signer.PrivateKey is RsaKeyParameters && signer.RsaSignaturePadding == RsaSignaturePadding.Pss) { + if (subjectKeyId == null) + signedData.AddSigner (signer.PrivateKey, signer.Certificate, RsassaPssOid, digestOid, signedAttributes, unsignedAttributes); + else + signedData.AddSigner (signer.PrivateKey, subjectKeyId, RsassaPssOid, digestOid, signedAttributes, unsignedAttributes); + } else if (subjectKeyId == null) { + signedData.AddSigner (signer.PrivateKey, signer.Certificate, digestOid, signedAttributes, unsignedAttributes); + } else { + signedData.AddSigner (signer.PrivateKey, subjectKeyId, digestOid, signedAttributes, unsignedAttributes); + } signedData.AddCertificates (signer.CertificateChain); @@ -270,7 +299,7 @@ Stream Sign (CmsSigner signer, Stream content, bool encapsulate) /// /// Cryptographically signs and encapsulates the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -299,7 +328,7 @@ public override ApplicationPkcs7Mime EncapsulatedSign (CmsSigner signer, Stream /// /// Cryptographically signs and encapsulates the content using the specified signer and digest algorithm. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -340,7 +369,7 @@ public override ApplicationPkcs7Mime EncapsulatedSign (MailboxAddress signer, Di /// /// Cryptographically signs the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -369,7 +398,7 @@ public override ApplicationPkcs7Signature Sign (CmsSigner signer, Stream content /// /// Cryptographically signs the content using the specified signer and digest algorithm. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -414,30 +443,69 @@ X509Certificate GetCertificate (IX509Store store, SignerID signer) return GetCertificate (signer); } - PkixCertPath BuildCertPath (HashSet anchors, IX509Store certificates, IX509Store crls, X509Certificate certificate, DateTime? signingTime) + /// + /// Build a certificate chain. + /// + /// + /// Builds a certificate chain for the provided certificate to include when signing. + /// This method is ideal for use with custom + /// implementations when it is desirable to include the certificate chain + /// in the signature. + /// + /// The certificate to build the chain for. + /// The certificate chain, including the specified certificate. + protected IList BuildCertificateChain (X509Certificate certificate) { - var intermediate = new X509CertificateStore (); - foreach (X509Certificate cert in certificates.GetMatches (null)) - intermediate.Add (cert); - var selector = new X509CertStoreSelector (); selector.Certificate = certificate; - var parameters = new PkixBuilderParameters (anchors, selector); + var intermediates = new X509CertificateStore (); + intermediates.Add (certificate); + + var parameters = new PkixBuilderParameters (GetTrustedAnchors (), selector); + parameters.ValidityModel = PkixParameters.PkixValidityModel; + parameters.AddStore (intermediates); parameters.AddStore (GetIntermediateCertificates ()); - parameters.AddStore (intermediate); + parameters.IsRevocationEnabled = false; + parameters.Date = new DateTimeObject (DateTime.UtcNow); + + var builder = new PkixCertPathBuilder (); + var result = builder.Build (parameters); + + var chain = new X509Certificate[result.CertPath.Certificates.Count]; - var localCrls = GetCertificateRevocationLists (); - parameters.AddStore (localCrls); + for (int i = 0; i < chain.Length; i++) + chain[i] = (X509Certificate) result.CertPath.Certificates[i]; + + return chain; + } + + PkixCertPath BuildCertPath (HashSet anchors, IX509Store certificates, IX509Store crls, X509Certificate certificate, DateTime signingTime) + { + var selector = new X509CertStoreSelector (); + selector.Certificate = certificate; + + var intermediates = new X509CertificateStore (); + intermediates.Add (certificate); + + foreach (X509Certificate cert in certificates.GetMatches (null)) + intermediates.Add (cert); + + var parameters = new PkixBuilderParameters (anchors, selector); + parameters.AddStore (intermediates); parameters.AddStore (crls); + parameters.AddStore (GetIntermediateCertificates ()); + parameters.AddStore (GetCertificateRevocationLists ()); + parameters.ValidityModel = PkixParameters.PkixValidityModel; parameters.IsRevocationEnabled = false; - if (signingTime.HasValue) - parameters.Date = new DateTimeObject (signingTime.Value); + if (signingTime != default (DateTime)) + parameters.Date = new DateTimeObject (signingTime); - var result = new PkixCertPathBuilder ().Build (parameters); + var builder = new PkixCertPathBuilder (); + var result = builder.Build (parameters); return result.CertPath; } @@ -456,7 +524,7 @@ PkixCertPath BuildCertPath (HashSet anchors, IX509Store certificates, IX509Store /// /// is null. /// - protected static bool TryGetDigestAlgorithm (AlgorithmIdentifier identifier, out DigestAlgorithm algorithm) + internal protected static bool TryGetDigestAlgorithm (AlgorithmIdentifier identifier, out DigestAlgorithm algorithm) { if (identifier == null) throw new ArgumentNullException (nameof (identifier)); @@ -576,23 +644,14 @@ internal protected static bool TryGetEncryptionAlgorithm (AlgorithmIdentifier id return false; } - static DateTime ToAdjustedDateTime (DerUtcTime time) - { - //try { - // return time.ToAdjustedDateTime (); - //} catch { - return DateUtils.Parse (time.AdjustedTimeString, "yyyyMMddHHmmsszzz"); - //} - } - async Task DownloadCrlsOverHttpAsync (string location, Stream stream, bool doAsync, CancellationToken cancellationToken) { try { if (doAsync) { - using (var response = await client.GetAsync (location, cancellationToken)) - await response.Content.CopyToAsync (stream); + using (var response = await client.GetAsync (location, cancellationToken).ConfigureAwait (false)) + await response.Content.CopyToAsync (stream).ConfigureAwait (false); } else { -#if !NETSTANDARD && !PORTABLE +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 cancellationToken.ThrowIfCancellationRequested (); var request = (HttpWebRequest) WebRequest.Create (location); @@ -750,58 +809,22 @@ async Task GetDigitalSignaturesAsync (CmsSignedDataP foreach (SignerInformation signerInfo in store.GetSigners ()) { var certificate = GetCertificate (certificates, signerInfo.SignerID); - var signature = new SecureMimeDigitalSignature (signerInfo); - var algorithms = new List (); - DateTime? signedDate = null; - DigestAlgorithm digestAlgo; + var signature = new SecureMimeDigitalSignature (signerInfo, certificate); if (CheckCertificateRevocation && certificate != null) await DownloadCrlsAsync (certificate, doAsync, cancellationToken).ConfigureAwait (false); - if (signerInfo.SignedAttributes != null) { - Asn1EncodableVector vector = signerInfo.SignedAttributes.GetAll (CmsAttributes.SigningTime); - foreach (Org.BouncyCastle.Asn1.Cms.Attribute attr in vector) { - var signingTime = (DerUtcTime) ((DerSet) attr.AttrValues)[0]; - signature.CreationDate = ToAdjustedDateTime (signingTime); - signedDate = signature.CreationDate; - break; - } - - vector = signerInfo.SignedAttributes.GetAll (SmimeAttributes.SmimeCapabilities); - foreach (Org.BouncyCastle.Asn1.Cms.Attribute attr in vector) { - foreach (Asn1Sequence sequence in attr.AttrValues) { - for (int i = 0; i < sequence.Count; i++) { - var identifier = AlgorithmIdentifier.GetInstance (sequence[i]); - EncryptionAlgorithm algorithm; - - if (TryGetEncryptionAlgorithm (identifier, out algorithm)) - algorithms.Add (algorithm); - } - } - } - - signature.EncryptionAlgorithms = algorithms.ToArray (); - } - - if (TryGetDigestAlgorithm (signerInfo.DigestAlgorithmID, out digestAlgo)) - signature.DigestAlgorithm = digestAlgo; - if (certificate != null) { - signature.SignerCertificate = new SecureMimeDigitalCertificate (certificate); - if (algorithms.Count > 0 && signedDate != null) { - UpdateSecureMimeCapabilities (certificate, signature.EncryptionAlgorithms, signedDate.Value); - } else { - try { - Import (certificate); - } catch { - } - } + Import (certificate); + + if (signature.EncryptionAlgorithms.Length > 0 && signature.CreationDate != default (DateTime)) + UpdateSecureMimeCapabilities (certificate, signature.EncryptionAlgorithms, signature.CreationDate); } var anchors = GetTrustedAnchors (); try { - signature.Chain = BuildCertPath (anchors, certificates, crls, certificate, signedDate); + signature.Chain = BuildCertPath (anchors, certificates, crls, certificate, signature.CreationDate); } catch (Exception ex) { signature.ChainException = ex; } @@ -959,6 +982,73 @@ async Task GetDigitalSignaturesAsync (CmsSignedDataP return content; } + class CmsRecipientInfoGenerator : RecipientInfoGenerator + { + readonly CmsRecipient recipient; + + public CmsRecipientInfoGenerator (CmsRecipient recipient) + { + this.recipient = recipient; + } + + IWrapper CreateWrapper (AlgorithmIdentifier keyExchangeAlgorithm) + { + string name; + + if (PkcsObjectIdentifiers.IdRsaesOaep.Id.Equals (keyExchangeAlgorithm.Algorithm.Id, StringComparison.Ordinal)) { + var oaepParameters = RsaesOaepParameters.GetInstance (keyExchangeAlgorithm.Parameters); + name = "RSA//OAEPWITH" + DigestUtilities.GetAlgorithmName (oaepParameters.HashAlgorithm.Algorithm) + "ANDMGF1Padding"; + } else if (PkcsObjectIdentifiers.RsaEncryption.Id.Equals (keyExchangeAlgorithm.Algorithm.Id, StringComparison.Ordinal)) { + name = "RSA//PKCS1Padding"; + } else { + name = keyExchangeAlgorithm.Algorithm.Id; + } + + return WrapperUtilities.GetWrapper (name); + } + + byte[] GenerateWrappedKey (KeyParameter contentEncryptionKey, AlgorithmIdentifier keyEncryptionAlgorithm, AsymmetricKeyParameter publicKey, SecureRandom random) + { + var keyWrapper = CreateWrapper (keyEncryptionAlgorithm); + var keyBytes = contentEncryptionKey.GetKey (); + + keyWrapper.Init (true, new ParametersWithRandom (publicKey, random)); + + return keyWrapper.Wrap (keyBytes, 0, keyBytes.Length); + } + + public RecipientInfo Generate (KeyParameter contentEncryptionKey, SecureRandom random) + { + var tbs = Asn1Object.FromByteArray (recipient.Certificate.GetTbsCertificate ()); + var certificate = TbsCertificateStructure.GetInstance (tbs); + var publicKey = recipient.Certificate.GetPublicKey (); + var publicKeyInfo = certificate.SubjectPublicKeyInfo; + AlgorithmIdentifier keyEncryptionAlgorithm; + + if (publicKey is RsaKeyParameters && recipient.RsaEncryptionPadding?.Scheme == RsaEncryptionPaddingScheme.Oaep) { + keyEncryptionAlgorithm = recipient.RsaEncryptionPadding.GetAlgorithmIdentifier (); + } else { + keyEncryptionAlgorithm = publicKeyInfo.AlgorithmID; + } + + var encryptedKeyBytes = GenerateWrappedKey (contentEncryptionKey, keyEncryptionAlgorithm, publicKey, random); + RecipientIdentifier recipientIdentifier = null; + + if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) { + var subjectKeyIdentifier = recipient.Certificate.GetExtensionValue (X509Extensions.SubjectKeyIdentifier); + recipientIdentifier = new RecipientIdentifier (subjectKeyIdentifier); + } + + if (recipientIdentifier == null) { + var issuerAndSerial = new IssuerAndSerialNumber (certificate.Issuer, certificate.SerialNumber.Value); + recipientIdentifier = new RecipientIdentifier (issuerAndSerial); + } + + return new RecipientInfo (new KeyTransRecipientInfo (recipientIdentifier, keyEncryptionAlgorithm, + new DerOctetString (encryptedKeyBytes))); + } + } + Stream Envelope (CmsRecipientCollection recipients, Stream content) { var unique = new HashSet (); @@ -967,7 +1057,7 @@ Stream Envelope (CmsRecipientCollection recipients, Stream content) foreach (var recipient in recipients) { if (unique.Add (recipient.Certificate)) { - cms.AddKeyTransRecipient (recipient.Certificate); + cms.AddRecipientInfoGenerator (new CmsRecipientInfoGenerator (recipient)); count++; } } @@ -1041,7 +1131,7 @@ Stream Envelope (CmsRecipientCollection recipients, Stream content) /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance + /// A new instance /// containing the encrypted content. /// The recipients. /// The content. @@ -1070,7 +1160,7 @@ public override ApplicationPkcs7Mime Encrypt (CmsRecipientCollection recipients, /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance + /// A new instance /// containing the encrypted data. /// The recipients. /// The content. @@ -1105,7 +1195,7 @@ public override MimePart Encrypt (IEnumerable recipients, Stream /// /// Decrypts the specified encryptedData. /// - /// The decrypted . + /// The decrypted . /// The encrypted data. /// The cancellation token. /// @@ -1147,22 +1237,22 @@ public override MimePart Encrypt (IEnumerable recipients, Stream /// Decrypts the specified encryptedData to an output stream. /// /// The encrypted data. - /// The output stream. + /// The output stream. /// /// is null. /// -or- - /// is null. + /// is null. /// /// /// An error occurred in the cryptographic message syntax subsystem. /// - public override void DecryptTo (Stream encryptedData, Stream output) + public override void DecryptTo (Stream encryptedData, Stream decryptedData) { if (encryptedData == null) throw new ArgumentNullException (nameof (encryptedData)); - if (output == null) - throw new ArgumentNullException (nameof (output)); + if (decryptedData == null) + throw new ArgumentNullException (nameof (decryptedData)); var parser = new CmsEnvelopedDataParser (encryptedData); var recipients = parser.GetRecipientInfos (); @@ -1174,8 +1264,7 @@ public override void DecryptTo (Stream encryptedData, Stream output) continue; var content = recipient.GetContentStream (key); - - content.ContentStream.CopyTo (output, 4096); + content.ContentStream.CopyTo (decryptedData, 4096); return; } @@ -1188,7 +1277,7 @@ public override void DecryptTo (Stream encryptedData, Stream output) /// /// Exports the certificates for the specified mailboxes. /// - /// A new instance containing + /// A new instance containing /// the exported keys. /// The mailboxes. /// @@ -1221,9 +1310,9 @@ public override MimePart Export (IEnumerable mailboxes) throw new ArgumentException ("No mailboxes specified.", nameof (mailboxes)); var cms = new CmsSignedDataStreamGenerator (); - var memory = new MemoryBlockStream (); - cms.AddCertificates (certificates); + + var memory = new MemoryBlockStream (); cms.Open (memory).Dispose (); memory.Position = 0; diff --git a/MimeKit/Cryptography/CertificateNotFoundException.cs b/MimeKit/Cryptography/CertificateNotFoundException.cs index 87cba4d7d6..1d538e75da 100644 --- a/MimeKit/Cryptography/CertificateNotFoundException.cs +++ b/MimeKit/Cryptography/CertificateNotFoundException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ public class CertificateNotFoundException : Exception { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -66,7 +66,7 @@ protected CertificateNotFoundException (SerializationInfo info, StreamingContext #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -95,12 +95,9 @@ public CertificateNotFoundException (MailboxAddress mailbox, string message) : b [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("Mailbox", Mailbox.ToString (true)); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/Cryptography/CmsRecipient.cs b/MimeKit/Cryptography/CmsRecipient.cs index f05e8bcb76..aae14c1aeb 100644 --- a/MimeKit/Cryptography/CmsRecipient.cs +++ b/MimeKit/Cryptography/CmsRecipient.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,9 +29,7 @@ using Org.BouncyCastle.X509; -#if !PORTABLE && !NETSTANDARD using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; -#endif namespace MimeKit.Cryptography { /// @@ -46,7 +44,7 @@ namespace MimeKit.Cryptography { public class CmsRecipient { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new based on the provided certificate. @@ -66,7 +64,7 @@ public CmsRecipient (X509Certificate certificate, SubjectIdentifierType recipien if (certificate == null) throw new ArgumentNullException (nameof (certificate)); - if (recipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber) + if (recipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) RecipientIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; else RecipientIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; @@ -76,7 +74,7 @@ public CmsRecipient (X509Certificate certificate, SubjectIdentifierType recipien } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new , loading the certificate from the specified stream. @@ -102,14 +100,13 @@ public CmsRecipient (Stream stream, SubjectIdentifierType recipientIdentifierTyp if (stream == null) throw new ArgumentNullException (nameof (stream)); - if (recipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber) + if (recipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) RecipientIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; else RecipientIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; var parser = new X509CertificateParser (); - RecipientIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; Certificate = parser.ReadCertificate (stream); if (Certificate == null) @@ -118,9 +115,8 @@ public CmsRecipient (Stream stream, SubjectIdentifierType recipientIdentifierTyp EncryptionAlgorithms = Certificate.GetEncryptionAlgorithms (); } -#if !PORTABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new , loading the certificate from the specified file. @@ -137,8 +133,7 @@ public CmsRecipient (Stream stream, SubjectIdentifierType recipientIdentifierTyp /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -160,26 +155,26 @@ public CmsRecipient (string fileName, SubjectIdentifierType recipientIdentifierT if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - var parser = new X509CertificateParser (); - - if (recipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber) + if (recipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) RecipientIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; else RecipientIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; - using (var stream = File.OpenRead (fileName)) + using (var stream = File.OpenRead (fileName)) { + var parser = new X509CertificateParser (); + Certificate = parser.ReadCertificate (stream); + } if (Certificate == null) throw new FormatException (); EncryptionAlgorithms = Certificate.GetEncryptionAlgorithms (); } -#endif -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new based on the provided certificate. @@ -199,7 +194,7 @@ public CmsRecipient (X509Certificate2 certificate, SubjectIdentifierType recipie if (certificate == null) throw new ArgumentNullException (nameof (certificate)); - if (recipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber) + if (recipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) RecipientIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; else RecipientIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; @@ -245,5 +240,17 @@ public SubjectIdentifierType RecipientIdentifierType { public EncryptionAlgorithm[] EncryptionAlgorithms { get; set; } + + /// + /// Get or set the RSA key encryption padding. + /// + /// + /// Gets or sets the padding to use for key encryption when + /// the 's public key is an RSA key. + /// + /// The encryption padding scheme. + public RsaEncryptionPadding RsaEncryptionPadding { + get; set; + } } } diff --git a/MimeKit/Cryptography/CmsRecipientCollection.cs b/MimeKit/Cryptography/CmsRecipientCollection.cs index 6b704940ec..e50234cd4c 100644 --- a/MimeKit/Cryptography/CmsRecipientCollection.cs +++ b/MimeKit/Cryptography/CmsRecipientCollection.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ public class CmsRecipientCollection : ICollection readonly IList recipients; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -67,14 +67,14 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether the is read only. /// /// /// A is never read-only. /// /// true if this instance is read only; otherwise, false. public bool IsReadOnly { - get; private set; + get { return false; } } /// diff --git a/MimeKit/Cryptography/CmsSigner.cs b/MimeKit/Cryptography/CmsSigner.cs index 9a3a8a51d2..47c8ee8d3c 100644 --- a/MimeKit/Cryptography/CmsSigner.cs +++ b/MimeKit/Cryptography/CmsSigner.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,16 +28,14 @@ using System.IO; using System.Collections.Generic; -#if !PORTABLE -using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; -#endif - using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Asn1.Cms; +using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; + namespace MimeKit.Cryptography { /// /// An S/MIME signer. @@ -50,11 +48,11 @@ namespace MimeKit.Cryptography { public class CmsSigner { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// The initial value of the will be set to - /// and both the + /// and both the /// and properties /// will be initialized to empty tables. /// @@ -62,28 +60,37 @@ public class CmsSigner { UnsignedAttributes = new AttributeTable (new Dictionary ()); SignedAttributes = new AttributeTable (new Dictionary ()); - DigestAlgorithm = DigestAlgorithm.Sha1; + DigestAlgorithm = DigestAlgorithm.Sha256; } - static void CheckCertificateCanBeUsedForSigning (X509Certificate certificate) + static bool CanSign (X509Certificate certificate) { var flags = certificate.GetKeyUsageFlags (); if (flags != X509KeyUsageFlags.None && (flags & SecureMimeContext.DigitalSignatureKeyUsageFlags) == 0) - throw new ArgumentException ("The certificate cannot be used for signing."); + return false; + + return true; + } + + static void CheckCertificateCanBeUsedForSigning (X509Certificate certificate) + { + if (!CanSign (certificate)) + throw new ArgumentException ("The certificate cannot be used for signing.", nameof (certificate)); } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// The initial value of the will be set to - /// and both the + /// and both the /// and properties /// will be initialized to empty tables. /// /// The chain of certificates starting with the signer's certificate back to the root. /// The signer's private key. + /// The scheme used for identifying the signer certificate. /// /// is null. /// -or- @@ -96,7 +103,7 @@ static void CheckCertificateCanBeUsedForSigning (X509Certificate certificate) /// -or- /// is not a private key. /// - public CmsSigner (IEnumerable chain, AsymmetricKeyParameter key) : this () + public CmsSigner (IEnumerable chain, AsymmetricKeyParameter key, SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber) : this () { if (chain == null) throw new ArgumentNullException (nameof (chain)); @@ -114,21 +121,27 @@ public CmsSigner (IEnumerable chain, AsymmetricKeyParameter key if (!key.IsPrivate) throw new ArgumentException ("The key must be a private key.", nameof (key)); + if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) + SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; + else + SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; + Certificate = CertificateChain[0]; PrivateKey = key; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// The initial value of the will - /// be set to and both the + /// The initial value of the will + /// be set to and both the /// and properties will be /// initialized to empty tables. /// /// The signer's certificate. /// The signer's private key. + /// The scheme used for identifying the signer certificate. /// /// is null. /// -or- @@ -139,7 +152,7 @@ public CmsSigner (IEnumerable chain, AsymmetricKeyParameter key /// -or- /// is not a private key. /// - public CmsSigner (X509Certificate certificate, AsymmetricKeyParameter key) : this () + public CmsSigner (X509Certificate certificate, AsymmetricKeyParameter key, SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber) : this () { if (certificate == null) throw new ArgumentNullException (nameof (certificate)); @@ -152,15 +165,21 @@ public CmsSigner (X509Certificate certificate, AsymmetricKeyParameter key) : thi if (!key.IsPrivate) throw new ArgumentException ("The key must be a private key.", nameof (key)); + if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) + SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; + else + SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; + CertificateChain = new X509CertificateChain (); CertificateChain.Add (certificate); Certificate = certificate; PrivateKey = key; } - void LoadPkcs12 (Stream stream, string password) + void LoadPkcs12 (Stream stream, string password, SubjectIdentifierType signerIdentifierType) { var pkcs12 = new Pkcs12Store (stream, password.ToCharArray ()); + bool hasPrivateKey = false; foreach (string alias in pkcs12.Aliases) { if (!pkcs12.IsKeyEntry (alias)) @@ -169,15 +188,18 @@ void LoadPkcs12 (Stream stream, string password) var chain = pkcs12.GetCertificateChain (alias); var key = pkcs12.GetKey (alias); - if (!key.Key.IsPrivate || chain.Length == 0) + if (!key.Key.IsPrivate) continue; - var flags = chain[0].Certificate.GetKeyUsageFlags (); + hasPrivateKey = true; - if (flags != X509KeyUsageFlags.None && (flags & SecureMimeContext.DigitalSignatureKeyUsageFlags) == 0) + if (chain.Length == 0 || !CanSign (chain[0].Certificate)) continue; - CheckCertificateCanBeUsedForSigning (chain[0].Certificate); + if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) + SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; + else + SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; CertificateChain = new X509CertificateChain (); Certificate = chain[0].Certificate; @@ -186,38 +208,43 @@ void LoadPkcs12 (Stream stream, string password) foreach (var entry in chain) CertificateChain.Add (entry.Certificate); - break; + return; } - if (PrivateKey == null) + if (!hasPrivateKey) throw new ArgumentException ("The stream did not contain a private key.", nameof (stream)); + + throw new ArgumentException ("The stream did not contain a certificate that could be used to create digital signatures.", nameof (stream)); } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new , loading the X.509 certificate and private key /// from the specified stream. - /// The initial value of the will - /// be set to and both the + /// The initial value of the will + /// be set to and both the /// and properties will be /// initialized to empty tables. /// /// The raw certificate and key data in pkcs12 format. /// The password to unlock the stream. + /// The scheme used for identifying the signer certificate. /// /// is null. /// -or- /// is null. /// /// - /// does not contain a private key. + /// does not contain a private key. + /// -or- + /// does not contain a certificate that could be used for signing. /// /// /// An I/O error occurred. /// - public CmsSigner (Stream stream, string password) : this () + public CmsSigner (Stream stream, string password, SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber) : this () { if (stream == null) throw new ArgumentNullException (nameof (stream)); @@ -225,32 +252,35 @@ public CmsSigner (Stream stream, string password) : this () if (password == null) throw new ArgumentNullException (nameof (password)); - LoadPkcs12 (stream, password); + LoadPkcs12 (stream, password, signerIdentifierType); } -#if !PORTABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new , loading the X.509 certificate and private key /// from the specified file. - /// The initial value of the will - /// be set to and both the + /// The initial value of the will + /// be set to and both the /// and properties will be /// initialized to empty tables. /// /// The raw certificate and key data in pkcs12 format. /// The password to unlock the stream. + /// The scheme used for identifying the signer certificate. /// /// is null. /// -or- /// is null. /// /// - /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// is a zero-length string, contains only white space, or + /// contains one or more invalid characters. + /// -or- + /// does not contain a private key. + /// -or- + /// does not contain a certificate that could be used for signing. /// /// /// is an invalid file path. @@ -264,7 +294,7 @@ public CmsSigner (Stream stream, string password) : this () /// /// An I/O error occurred. /// - public CmsSigner (string fileName, string password) : this () + public CmsSigner (string fileName, string password, SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber) : this () { if (fileName == null) throw new ArgumentNullException (nameof (fileName)); @@ -273,28 +303,28 @@ public CmsSigner (string fileName, string password) : this () throw new ArgumentNullException (nameof (password)); using (var stream = File.OpenRead (fileName)) - LoadPkcs12 (stream, password); + LoadPkcs12 (stream, password, signerIdentifierType); } -#endif -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// The initial value of the will - /// be set to and both the + /// The initial value of the will + /// be set to and both the /// and properties will be /// initialized to empty tables. /// /// The signer's certificate. + /// The scheme used for identifying the signer certificate. /// /// is null. /// /// /// cannot be used for signing. /// - public CmsSigner (X509Certificate2 certificate) : this () + public CmsSigner (X509Certificate2 certificate, SubjectIdentifierType signerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber) : this () { if (certificate == null) throw new ArgumentNullException (nameof (certificate)); @@ -307,6 +337,11 @@ public CmsSigner (X509Certificate2 certificate) : this () CheckCertificateCanBeUsedForSigning (cert); + if (signerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) + SignerIdentifierType = SubjectIdentifierType.IssuerAndSerialNumber; + else + SignerIdentifierType = SubjectIdentifierType.SubjectKeyIdentifier; + CertificateChain = new X509CertificateChain (); CertificateChain.Add (cert); Certificate = cert; @@ -315,7 +350,7 @@ public CmsSigner (X509Certificate2 certificate) : this () #endif /// - /// Gets the signer's certificate. + /// Get the signer's certificate. /// /// /// The signer's certificate that contains a public key that can be used for @@ -327,7 +362,7 @@ public X509Certificate Certificate { } /// - /// Gets the certificate chain. + /// Get the certificate chain. /// /// /// Gets the certificate chain. @@ -338,7 +373,7 @@ public X509CertificateChain CertificateChain { } /// - /// Gets or sets the digest algorithm. + /// Get or set the digest algorithm. /// /// /// Specifies which digest algorithm to use to generate the @@ -350,7 +385,7 @@ public DigestAlgorithm DigestAlgorithm { } /// - /// Gets the private key. + /// Get the private key. /// /// /// The private key used for signing. @@ -361,7 +396,50 @@ public AsymmetricKeyParameter PrivateKey { } /// - /// Gets or sets the signed attributes. + /// Get or set the RSA signature padding scheme. + /// + /// + /// Gets or sets the signature padding scheme to use for signing when + /// the is an RSA key. + /// + /// The signature padding scheme. + [Obsolete ("Use RsaSignaturePadding instead.")] + public RsaSignaturePaddingScheme RsaSignaturePaddingScheme { + get { return RsaSignaturePadding?.Scheme ?? RsaSignaturePaddingScheme.Pkcs1; } + set { + switch (value) { + case RsaSignaturePaddingScheme.Pkcs1: RsaSignaturePadding = RsaSignaturePadding.Pkcs1; break; + case RsaSignaturePaddingScheme.Pss: RsaSignaturePadding = RsaSignaturePadding.Pss; break; + default: throw new ArgumentOutOfRangeException (nameof (value)); + } + } + } + + /// + /// Get or set the RSA signature padding. + /// + /// + /// Gets or sets the signature padding to use for signing when + /// the is an RSA key. + /// + /// The signature padding scheme. + public RsaSignaturePadding RsaSignaturePadding { + get; set; + } + + /// + /// Gets the signer identifier type. + /// + /// + /// Specifies how the certificate should be looked up on the recipient's end. + /// + /// The signer identifier type. + public SubjectIdentifierType SignerIdentifierType { + get; private set; + } + + /// + /// Get or set the signed attributes. /// /// /// A table of attributes that should be included in the signature. @@ -372,7 +450,7 @@ public AttributeTable SignedAttributes { } /// - /// Gets or sets the unsigned attributes. + /// Get or set the unsigned attributes. /// /// /// A table of attributes that should not be signed in the signature, diff --git a/MimeKit/Cryptography/CryptographyContext.cs b/MimeKit/Cryptography/CryptographyContext.cs index 37188bb21e..60bed14d8d 100644 --- a/MimeKit/Cryptography/CryptographyContext.cs +++ b/MimeKit/Cryptography/CryptographyContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,7 +44,7 @@ public abstract class CryptographyContext : IDisposable { const string SubclassAndRegisterFormat = "You need to subclass {0} and then register it with MimeKit.Cryptography.CryptographyContext.Register()."; static Func SecureMimeContextFactory; - static Func OpenPgpContextFactory; + static Func PgpContextFactory; static readonly object mutex = new object (); EncryptionAlgorithm[] encryptionAlgorithmRank; @@ -54,7 +54,7 @@ public abstract class CryptographyContext : IDisposable int enabledDigestAlgorithms; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -108,7 +108,7 @@ protected CryptographyContext () #if NOT_YET /// - /// Gets or sets a value indicating whether this allows online + /// Gets or sets a value indicating whether this allows online /// certificate retrieval. /// /// true if online certificate retrieval should be allowed; otherwise, false. @@ -349,7 +349,7 @@ public bool IsEnabled (DigestAlgorithm algorithm) /// /// Cryptographically signs the content using the specified signer and digest algorithm. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -416,7 +416,7 @@ public bool IsEnabled (DigestAlgorithm algorithm) /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance containing the encrypted data. + /// A new instance containing the encrypted data. /// The recipients. /// The content. /// @@ -435,7 +435,7 @@ public bool IsEnabled (DigestAlgorithm algorithm) /// /// Decrypts the specified encryptedData. /// - /// The decrypted . + /// The decrypted . /// The encrypted data. /// The cancellation token. /// @@ -467,7 +467,7 @@ public bool IsEnabled (DigestAlgorithm algorithm) /// /// Exports the keys for the specified mailboxes. /// - /// A new instance containing the exported keys. + /// A new instance containing the exported keys. /// The mailboxes. /// /// is null. @@ -495,12 +495,12 @@ protected virtual void Dispose (bool disposing) } /// - /// Releases all resources used by the object. + /// Releases all resources used by the object. /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After - /// calling , you must release all references to the so - /// the garbage collector can reclaim the memory that the was occupying. + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After + /// calling , you must release all references to the so + /// the garbage collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); @@ -542,28 +542,15 @@ public static CryptographyContext Create (string protocol) if (SecureMimeContextFactory != null) return SecureMimeContextFactory (); -#if !PORTABLE - if (!SqliteCertificateDatabase.IsAvailable) { - const string format = "SQLite is not available. Either install the {0} nuget or subclass MimeKit.Cryptography.SecureMimeContext and register it with MimeKit.Cryptography.CryptographyContext.Register()."; -#if NETSTANDARD - throw new NotSupportedException (string.Format (format, "Microsoft.Data.Sqlite")); -#else - throw new NotSupportedException (string.Format (format, "System.Data.SQLite")); -#endif - } - return new DefaultSecureMimeContext (); -#else - throw new NotSupportedException (string.Format (SubclassAndRegisterFormat, "MimeKit.Cryptography.SecureMimeContext")); -#endif case "application/x-pgp-signature": case "application/pgp-signature": case "application/x-pgp-encrypted": case "application/pgp-encrypted": case "application/x-pgp-keys": case "application/pgp-keys": - if (OpenPgpContextFactory != null) - return OpenPgpContextFactory (); + if (PgpContextFactory != null) + return PgpContextFactory (); throw new NotSupportedException (string.Format (SubclassAndRegisterFormat, "MimeKit.Cryptography.OpenPgpContext or MimeKit.Cryptography.GnuPGContext")); default: @@ -572,22 +559,6 @@ public static CryptographyContext Create (string protocol) } } -#if PORTABLE - static ConstructorInfo GetConstructor (TypeInfo type) - { - foreach (var ctor in type.DeclaredConstructors) { - var args = ctor.GetParameters (); - - if (args.Length != 0) - continue; - - return ctor; - } - - return null; - } -#endif - /// /// Registers a default or . /// @@ -611,17 +582,13 @@ public static void Register (Type type) if (type == null) throw new ArgumentNullException (nameof (type)); -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 var info = type.GetTypeInfo (); #else var info = type; #endif - -#if PORTABLE - var ctor = GetConstructor (info); -#else var ctor = type.GetConstructor (new Type[0]); -#endif + if (ctor == null) throw new ArgumentException ("The specified type must have a parameterless constructor.", nameof (type)); @@ -629,9 +596,9 @@ public static void Register (Type type) lock (mutex) { SecureMimeContextFactory = () => (SecureMimeContext) ctor.Invoke (new object[0]); } - } else if (info.IsSubclassOf (typeof (OpenPgpContext))) { + } else if (info.IsSubclassOf (typeof (OpenPgpContextBase))) { lock (mutex) { - OpenPgpContextFactory = () => (OpenPgpContext) ctor.Invoke (new object[0]); + PgpContextFactory = () => (OpenPgpContextBase) ctor.Invoke (new object[0]); } } else { throw new ArgumentException ("The specified type must be a subclass of SecureMimeContext or OpenPgpContext.", nameof (type)); @@ -668,13 +635,13 @@ public static void Register (Func factory) /// /// is null. /// - public static void Register (Func factory) + public static void Register (Func factory) { if (factory == null) throw new ArgumentNullException(nameof (factory)); lock (mutex) { - OpenPgpContextFactory = factory; + PgpContextFactory = factory; } } } diff --git a/MimeKit/Cryptography/DbExtensions.cs b/MimeKit/Cryptography/DbExtensions.cs index 7f12c89085..0d66fa1015 100644 --- a/MimeKit/Cryptography/DbExtensions.cs +++ b/MimeKit/Cryptography/DbExtensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/DefaultSecureMimeContext.cs b/MimeKit/Cryptography/DefaultSecureMimeContext.cs index bdec9eaf6f..ceee70cf56 100644 --- a/MimeKit/Cryptography/DefaultSecureMimeContext.cs +++ b/MimeKit/Cryptography/DefaultSecureMimeContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -68,7 +68,7 @@ static DefaultSecureMimeContext () { string path; -#if !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 if (Path.DirectorySeparatorChar == '\\') { var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); path = Path.Combine (appData, "Roaming\\mimekit"); @@ -83,8 +83,20 @@ static DefaultSecureMimeContext () DefaultDatabasePath = Path.Combine (path, "smime.db"); } + static void CheckIsAvailable () + { + if (!SqliteCertificateDatabase.IsAvailable) { + const string format = "SQLite is not available. Install the {0} nuget."; +#if NETSTANDARD1_3 || NETSTANDARD1_6 + throw new NotSupportedException (string.Format (format, "Microsoft.Data.Sqlite")); +#else + throw new NotSupportedException (string.Format (format, "System.Data.SQLite")); +#endif + } + } + /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Allows the program to specify its own location for the SQLite database. If the file does not exist, @@ -118,16 +130,15 @@ public DefaultSecureMimeContext (string fileName, string password) if (password == null) throw new ArgumentNullException (nameof (password)); + CheckIsAvailable (); + var dir = Path.GetDirectoryName (fileName); var exists = File.Exists (fileName); if (!string.IsNullOrEmpty (dir) && !Directory.Exists (dir)) Directory.CreateDirectory (dir); - if (SqliteCertificateDatabase.IsAvailable) - dbase = new SqliteCertificateDatabase (fileName, password); - else - throw new NotSupportedException ("Mono.Data.Sqlite is not available."); + dbase = new SqliteCertificateDatabase (fileName, password); if (!exists) { // TODO: initialize our dbase with some root CA certificates. @@ -135,7 +146,7 @@ public DefaultSecureMimeContext (string fileName, string password) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Allows the program to specify its own password for the default database. @@ -156,7 +167,7 @@ public DefaultSecureMimeContext (string password) : this (DefaultDatabasePath, p } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Not recommended for production use as the password to unlock the private keys is hard-coded. @@ -176,7 +187,7 @@ public DefaultSecureMimeContext () : this (DefaultDatabasePath, "no.secret") } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// This constructor is useful for supplying a custom . @@ -290,9 +301,8 @@ protected override Org.BouncyCastle.Utilities.Collections.HashSet GetTrustedAnch keyUsage[(int) X509KeyUsageBits.KeyCertSign] = true; selector.KeyUsage = keyUsage; - foreach (var record in dbase.Find (selector, true, X509CertificateRecordFields.Certificate)) { + foreach (var record in dbase.Find (selector, true, X509CertificateRecordFields.Certificate)) anchors.Add (new TrustAnchor (record.Certificate, null)); - } return anchors; } @@ -308,6 +318,19 @@ protected override Org.BouncyCastle.Utilities.Collections.HashSet GetTrustedAnch /// The intermediate certificates. protected override IX509Store GetIntermediateCertificates () { + //var intermediates = new X509CertificateStore (); + //var selector = new X509CertStoreSelector (); + //var keyUsage = new bool[9]; + + //keyUsage[(int) X509KeyUsageBits.KeyCertSign] = true; + //selector.KeyUsage = keyUsage; + + //foreach (var record in dbase.Find (selector, false, X509CertificateRecordFields.Certificate)) { + // if (!record.Certificate.IsSelfSigned ()) + // intermediates.Add (record.Certificate); + //} + + //return intermediates; return dbase; } @@ -393,11 +416,20 @@ protected override CmsRecipient GetCmsRecipient (MailboxAddress mailbox) /// protected override CmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgorithm digestAlgo) { + AsymmetricKeyParameter privateKey = null; + X509Certificate certificate = null; + foreach (var record in dbase.Find (mailbox, DateTime.UtcNow, true, CmsSignerFields)) { - if (record.KeyUsage != X509KeyUsageFlags.None && (record.KeyUsage & SecureMimeContext.DigitalSignatureKeyUsageFlags) == 0) + if (record.KeyUsage != X509KeyUsageFlags.None && (record.KeyUsage & DigitalSignatureKeyUsageFlags) == 0) continue; - var signer = new CmsSigner (record.Certificate, record.PrivateKey); + certificate = record.Certificate; + privateKey = record.PrivateKey; + break; + } + + if (certificate != null && privateKey != null) { + var signer = new CmsSigner (BuildCertificateChain (certificate), privateKey); signer.DigestAlgorithm = digestAlgo; return signer; @@ -547,29 +579,61 @@ public override void Import (Stream stream, string password) startIndex = 1; } - for (int i = startIndex; i < chain.Length; i++) { - if ((record = dbase.Find (chain[i].Certificate, X509CertificateRecordFields.Id)) == null) - dbase.Add (new X509CertificateRecord (chain[i].Certificate) { IsTrusted = true }); - } + for (int i = startIndex; i < chain.Length; i++) + Import (chain[i].Certificate, true); } else if (pkcs12.IsCertificateEntry (alias)) { var entry = pkcs12.GetCertificate (alias); - if ((record = dbase.Find (entry.Certificate, X509CertificateRecordFields.Id)) == null) - dbase.Add (new X509CertificateRecord (entry.Certificate) { IsTrusted = true }); + Import (entry.Certificate, true); } } } -#endregion + #endregion + + /// + /// Imports a certificate. + /// + /// + /// Imports the certificate. + /// If the certificate already exists in the database and is true, + /// then the IsTrusted state is updated otherwise the certificate is added to the database with the + /// specified trust. + /// + /// The certificate. + /// true if the certificate is trusted; otherwise, false. + /// + /// is null. + /// + public void Import (X509Certificate certificate, bool trusted) + { + if (certificate == null) + throw new ArgumentNullException (nameof (certificate)); + + X509CertificateRecord record; + + if ((record = dbase.Find (certificate, X509CertificateRecordFields.Id | X509CertificateRecordFields.Trusted)) != null) { + if (trusted && !record.IsTrusted) { + record.IsTrusted = trusted; + dbase.Update (record, X509CertificateRecordFields.Trusted); + } + + return; + } + + record = new X509CertificateRecord (certificate); + record.IsTrusted = trusted; + dbase.Add (record); + } /// /// Imports a DER-encoded certificate stream. /// /// - /// Imports all of the certificates in the DER-encoded stream. + /// Imports the certificate(s). /// /// The raw certificate(s). - /// true if the certificates are trusted. + /// true if the certificates are trusted; othewrwise, false. /// /// is null. /// @@ -580,21 +644,8 @@ public void Import (Stream stream, bool trusted) var parser = new X509CertificateParser (); - foreach (X509Certificate certificate in parser.ReadCertificates (stream)) { - X509CertificateRecord record; - - if ((record = dbase.Find (certificate, X509CertificateRecordFields.Id | X509CertificateRecordFields.Trusted)) != null) { - if (trusted && !record.IsTrusted) { - record.IsTrusted = trusted; - dbase.Update (record, X509CertificateRecordFields.Trusted); - } - continue; - } - - record = new X509CertificateRecord (certificate); - record.IsTrusted = trusted; - dbase.Add (record); - } + foreach (X509Certificate certificate in parser.ReadCertificates (stream)) + Import (certificate, trusted); } /// diff --git a/MimeKit/Cryptography/DigestAlgorithm.cs b/MimeKit/Cryptography/DigestAlgorithm.cs index 4a0a16815b..154f73a237 100644 --- a/MimeKit/Cryptography/DigestAlgorithm.cs +++ b/MimeKit/Cryptography/DigestAlgorithm.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/DigitalSignatureCollection.cs b/MimeKit/Cryptography/DigitalSignatureCollection.cs index 6aff3ad713..211dfe46f3 100644 --- a/MimeKit/Cryptography/DigitalSignatureCollection.cs +++ b/MimeKit/Cryptography/DigitalSignatureCollection.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ namespace MimeKit.Cryptography { public class DigitalSignatureCollection : ReadOnlyCollection { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/DigitalSignatureVerifyException.cs b/MimeKit/Cryptography/DigitalSignatureVerifyException.cs index 1bb0cc6ea7..cd491ebcd4 100644 --- a/MimeKit/Cryptography/DigitalSignatureVerifyException.cs +++ b/MimeKit/Cryptography/DigitalSignatureVerifyException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ namespace MimeKit.Cryptography { /// - /// An exception that is thrown when an error occurrs in . + /// An exception that is thrown when an error occurrs in . /// /// /// For more information about the error condition, check the property. @@ -44,7 +44,7 @@ public class DigitalSignatureVerifyException : Exception { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -61,7 +61,7 @@ protected DigitalSignatureVerifyException (SerializationInfo info, StreamingCont #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -75,7 +75,7 @@ public DigitalSignatureVerifyException (long keyId, string message, Exception in } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -88,7 +88,7 @@ public DigitalSignatureVerifyException (long keyId, string message) : base (mess } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -100,7 +100,7 @@ public DigitalSignatureVerifyException (string message, Exception innerException } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -127,12 +127,9 @@ public DigitalSignatureVerifyException (string message) : base (message) [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("KeyId", KeyId, typeof (long?)); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/Cryptography/DkimBodyFilter.cs b/MimeKit/Cryptography/DkimBodyFilter.cs index 7cce65ccb0..b675cc3cbf 100644 --- a/MimeKit/Cryptography/DkimBodyFilter.cs +++ b/MimeKit/Cryptography/DkimBodyFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -60,7 +60,7 @@ abstract class DkimBodyFilter : MimeFilterBase protected int EmptyLines; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/DkimCanonicalizationAlgorithm.cs b/MimeKit/Cryptography/DkimCanonicalizationAlgorithm.cs index 090f9997e6..67f0f75019 100644 --- a/MimeKit/Cryptography/DkimCanonicalizationAlgorithm.cs +++ b/MimeKit/Cryptography/DkimCanonicalizationAlgorithm.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,6 +39,9 @@ namespace MimeKit.Cryptography { /// result in a signature verification failure. These signers prefer a canonicalization /// algorithm that does not tolerate in-transit modification of the signed email. /// + /// + /// + /// public enum DkimCanonicalizationAlgorithm { /// /// The simple canonicalization algorithm tolerates almost no modification diff --git a/MimeKit/Cryptography/DkimHashStream.cs b/MimeKit/Cryptography/DkimHashStream.cs index 9caab74aba..b639b74466 100644 --- a/MimeKit/Cryptography/DkimHashStream.cs +++ b/MimeKit/Cryptography/DkimHashStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -53,7 +53,7 @@ class DkimHashStream : Stream int max; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -64,6 +64,7 @@ public DkimHashStream (DkimSignatureAlgorithm algorithm, int maxLength = -1) { #if ENABLE_NATIVE_DKIM switch (algorithm) { + case DkimSignatureAlgorithm.Ed25519Sha256: case DkimSignatureAlgorithm.RsaSha256: digest = SHA256.Create (); break; @@ -73,6 +74,7 @@ public DkimHashStream (DkimSignatureAlgorithm algorithm, int maxLength = -1) } #else switch (algorithm) { + case DkimSignatureAlgorithm.Ed25519Sha256: case DkimSignatureAlgorithm.RsaSha256: digest = new Sha256Digest (); break; diff --git a/MimeKit/Cryptography/DkimPublicKeyLocatorBase.cs b/MimeKit/Cryptography/DkimPublicKeyLocatorBase.cs new file mode 100644 index 0000000000..d86c8b83ae --- /dev/null +++ b/MimeKit/Cryptography/DkimPublicKeyLocatorBase.cs @@ -0,0 +1,189 @@ +// +// DkimPublicKeyLocatorBase.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Crypto.Parameters; + +namespace MimeKit.Cryptography { + /// + /// A base class for implemnentations of . + /// + /// + /// The class provides a helpful + /// method for parsing DNS TXT records in order to extract the public key. + /// + /// + /// + /// + /// + /// + /// + public abstract class DkimPublicKeyLocatorBase : IDkimPublicKeyLocator + { + /// + /// Get the public key from a DNS TXT record. + /// + /// + /// Gets the public key from a DNS TXT record. + /// + /// The DNS TXT record. + /// The public key. + /// + /// The is null. + /// + /// + /// There was an error parsing the DNS TXT record. + /// + protected AsymmetricKeyParameter GetPublicKey (string txt) + { + AsymmetricKeyParameter pubkey; + string k = "rsa", p = null; + int index = 0; + + if (txt == null) + throw new ArgumentNullException (nameof (txt)); + + // parse the response (will look something like: "k=rsa; p=") + while (index < txt.Length) { + while (index < txt.Length && char.IsWhiteSpace (txt[index])) + index++; + + if (index == txt.Length) + break; + + // find the end of the key + int startIndex = index; + while (index < txt.Length && txt[index] != '=') + index++; + + if (index == txt.Length) + break; + + var key = txt.Substring (startIndex, index - startIndex); + + // skip over the '=' + index++; + + // find the end of the value + startIndex = index; + while (index < txt.Length && txt[index] != ';') + index++; + + var value = txt.Substring (startIndex, index - startIndex); + + switch (key) { + case "k": + switch (value) { + case "rsa": case "ed25519": k = value; break; + default: throw new ParseException ($"Unknown public key algorithm: {value}", startIndex, index); + } + break; + case "p": + p = value.Replace (" ", ""); + break; + } + + // skip over the ';' + index++; + } + + if (p != null) { + if (k == "ed25519") { + var decoded = Convert.FromBase64String (p); + + return new Ed25519PublicKeyParameters (decoded, 0); + } + + var data = "-----BEGIN PUBLIC KEY-----\r\n" + p + "\r\n-----END PUBLIC KEY-----\r\n"; + var rawData = Encoding.ASCII.GetBytes (data); + + using (var stream = new MemoryStream (rawData, false)) { + using (var reader = new StreamReader (stream)) { + var pem = new PemReader (reader); + + pubkey = pem.ReadObject () as AsymmetricKeyParameter; + + if (pubkey != null) + return pubkey; + } + } + } + + throw new ParseException ("Public key parameters not found in DNS TXT record.", 0, txt.Length); + } + + /// + /// Locate and retrieve the public key for the given domain and selector. + /// + /// + /// Locates and retrieves the public key for the given domain and selector. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The public key. + /// A colon-separated list of query methods used to retrieve the public key. The default is "dns/txt". + /// The domain. + /// The selector. + /// The cancellation token. + public abstract AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)); + + /// + /// Asynchronously locate and retrieve the public key for the given domain and selector. + /// + /// + /// Locates and retrieves the public key for the given domain and selector. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// The public key. + /// A colon-separated list of query methods used to retrieve the public key. The default is "dns/txt". + /// The domain. + /// The selector. + /// The cancellation token. + public abstract Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)); + } +} diff --git a/MimeKit/Cryptography/DkimRelaxedBodyFilter.cs b/MimeKit/Cryptography/DkimRelaxedBodyFilter.cs index 9d06048581..91905ac019 100644 --- a/MimeKit/Cryptography/DkimRelaxedBodyFilter.cs +++ b/MimeKit/Cryptography/DkimRelaxedBodyFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ class DkimRelaxedBodyFilter : DkimBodyFilter bool lwsp, cr; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/DkimSignatureAlgorithm.cs b/MimeKit/Cryptography/DkimSignatureAlgorithm.cs index 43c6c9fbf0..5b38ddc736 100644 --- a/MimeKit/Cryptography/DkimSignatureAlgorithm.cs +++ b/MimeKit/Cryptography/DkimSignatureAlgorithm.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,9 @@ namespace MimeKit.Cryptography { /// /// A DKIM signature algorithm. /// + /// + /// + /// public enum DkimSignatureAlgorithm { /// /// The RSA-SHA1 signature algorithm. @@ -40,6 +43,11 @@ public enum DkimSignatureAlgorithm { /// /// The RSA-SHA256 signature algorithm. /// - RsaSha256 + RsaSha256, + + /// + /// The Ed25519-SHA256 signature algorithm. + /// + Ed25519Sha256 } } diff --git a/MimeKit/Cryptography/DkimSignatureStream.cs b/MimeKit/Cryptography/DkimSignatureStream.cs index 28812a7642..83badb54dd 100644 --- a/MimeKit/Cryptography/DkimSignatureStream.cs +++ b/MimeKit/Cryptography/DkimSignatureStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,7 +42,7 @@ class DkimSignatureStream : Stream long length; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/DkimSigner.cs b/MimeKit/Cryptography/DkimSigner.cs index 30c5187bdf..8b86833d92 100644 --- a/MimeKit/Cryptography/DkimSigner.cs +++ b/MimeKit/Cryptography/DkimSigner.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,15 +26,14 @@ using System; using System.IO; -#if ENABLE_NATIVE_DKIM -using System.Security.Cryptography; -#endif +using System.Linq; +using System.Text; +using System.Collections.Generic; -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.OpenSsl; -using Org.BouncyCastle.Security; + +using MimeKit.IO; +using MimeKit.Utils; namespace MimeKit.Cryptography { /// @@ -43,13 +42,22 @@ namespace MimeKit.Cryptography { /// /// A DKIM signer. /// - public class DkimSigner + /// + /// + /// + public class DkimSigner : DkimSignerBase { + static readonly string[] DkimShouldNotInclude = { "return-path", "received", "comments", "keywords", "bcc", "resent-bcc", "dkim-signature" }; + /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Creates a new . + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. /// /// The domain that the signer represents. /// The selector subdividing the domain. @@ -59,24 +67,19 @@ public class DkimSigner /// -or- /// is null. /// - protected DkimSigner (string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + protected DkimSigner (string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (domain, selector, algorithm) { - if (domain == null) - throw new ArgumentNullException (nameof (domain)); - - if (selector == null) - throw new ArgumentNullException (nameof (selector)); - - SignatureAlgorithm = algorithm; - Selector = selector; - Domain = domain; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Creates a new . + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. /// /// The signer's private key. /// The domain that the signer represents. @@ -92,60 +95,30 @@ protected DkimSigner (string domain, string selector, DkimSignatureAlgorithm alg /// /// is not a private key. /// - public DkimSigner (AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + public DkimSigner (AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) { if (key == null) throw new ArgumentNullException (nameof (key)); - if (domain == null) - throw new ArgumentNullException (nameof (domain)); - - if (selector == null) - throw new ArgumentNullException (nameof (selector)); - if (!key.IsPrivate) throw new ArgumentException ("The key must be a private key.", nameof (key)); - SignatureAlgorithm = algorithm; - Selector = selector; PrivateKey = key; - Domain = domain; } - static AsymmetricKeyParameter LoadPrivateKey (Stream stream) - { - AsymmetricKeyParameter key = null; - - using (var reader = new StreamReader (stream)) { - var pem = new PemReader (reader); - - var keyObject = pem.ReadObject (); - - if (keyObject != null) { - key = keyObject as AsymmetricKeyParameter; - - if (key == null) { - var pair = keyObject as AsymmetricCipherKeyPair; - - if (pair != null) - key = pair.Private; - } - } - } - - if (key == null || !key.IsPrivate) - throw new FormatException ("Private key not found."); - - return key; - } - -#if !PORTABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Creates a new . + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. /// + /// + /// + /// /// The file containing the private key. /// The domain that the signer represents. /// The selector subdividing the domain. @@ -159,8 +132,7 @@ static AsymmetricKeyParameter LoadPrivateKey (Stream stream) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The file did not contain a private key. @@ -177,7 +149,7 @@ static AsymmetricKeyParameter LoadPrivateKey (Stream stream) /// /// An I/O error occurred. /// - public DkimSigner (string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + public DkimSigner (string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) { if (fileName == null) throw new ArgumentNullException (nameof (fileName)); @@ -185,26 +157,19 @@ public DkimSigner (string fileName, string domain, string selector, DkimSignatur if (fileName.Length == 0) throw new ArgumentException ("The file name cannot be empty.", nameof (fileName)); - if (domain == null) - throw new ArgumentNullException (nameof (domain)); - - if (selector == null) - throw new ArgumentNullException (nameof (selector)); - using (var stream = File.OpenRead (fileName)) PrivateKey = LoadPrivateKey (stream); - - SignatureAlgorithm = algorithm; - Selector = selector; - Domain = domain; } -#endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Creates a new . + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. /// /// The stream containing the private key. /// The domain that the signer represents. @@ -223,54 +188,12 @@ public DkimSigner (string fileName, string domain, string selector, DkimSignatur /// /// An I/O error occurred. /// - public DkimSigner (Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + public DkimSigner (Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : this (domain, selector, algorithm) { if (stream == null) throw new ArgumentNullException (nameof (stream)); - if (domain == null) - throw new ArgumentNullException (nameof (domain)); - - if (selector == null) - throw new ArgumentNullException (nameof (selector)); - PrivateKey = LoadPrivateKey (stream); - SignatureAlgorithm = algorithm; - Selector = selector; - Domain = domain; - } - - /// - /// Gets the private key. - /// - /// - /// The private key used for signing. - /// - /// The private key. - protected AsymmetricKeyParameter PrivateKey { - get; set; - } - - /// - /// Get the domain that the signer represents. - /// - /// - /// Gets the domain that the signer represents. - /// - /// The domain. - public string Domain { - get; private set; - } - - /// - /// Get the selector subdividing the domain. - /// - /// - /// Gets the selector subdividing the domain. - /// - /// The selector. - public string Selector { - get; private set; } /// @@ -279,22 +202,14 @@ public string Selector { /// /// Gets or sets the agent or user identifier. /// + /// + /// + /// /// The agent or user identifier. public string AgentOrUserIdentifier { get; set; } - /// - /// Get or set the algorithm to use for signing. - /// - /// - /// Gets or sets the algorithm to use for signing. - /// - /// The signature algorithm. - public DkimSignatureAlgorithm SignatureAlgorithm { - get; set; - } - /// /// Get or set the public key query method. /// @@ -305,107 +220,264 @@ public DkimSignatureAlgorithm SignatureAlgorithm { /// query method is of the form "type[/options]", where the syntax and /// semantics of the options depend on the type and specified options. /// + /// + /// + /// /// The public key query method. public string QueryMethod { get; set; } /// - /// Get the digest signing context for a specified signature algorithm. + /// Get the timestamp value. /// /// - /// Gets the digest signing context for the specified signature algorithm. + /// Gets the timestamp to use as the t= value in the DKIM-Signature header. /// - /// The digest signer. - public virtual ISigner DigestSigner { - get { -#if ENABLE_NATIVE_DKIM - return new SystemSecuritySigner (SignatureAlgorithm, PrivateKey.AsAsymmetricAlgorithm ()); -#else - DerObjectIdentifier id; - - if (SignatureAlgorithm == DkimSignatureAlgorithm.RsaSha256) - id = PkcsObjectIdentifiers.Sha256WithRsaEncryption; - else - id = PkcsObjectIdentifiers.Sha1WithRsaEncryption; - - var signer = SignerUtilities.GetSigner (id); - - signer.Init (true, PrivateKey); - - return signer; -#endif - } + /// A value representing the timestamp value. + protected virtual long GetTimestamp () + { + return (long) (DateTime.UtcNow - DateUtils.UnixEpoch).TotalSeconds; } - } - -#if ENABLE_NATIVE_DKIM - class SystemSecuritySigner : ISigner - { - readonly RSACryptoServiceProvider rsa; - readonly HashAlgorithm hash; - readonly string oid; - public SystemSecuritySigner (DkimSignatureAlgorithm algorithm, AsymmetricAlgorithm key) + void DkimSign (FormatOptions options, MimeMessage message, IList headers) { - rsa = key as RSACryptoServiceProvider; - - switch (algorithm) { + var value = new StringBuilder ("v=1"); + var t = GetTimestamp (); + byte[] signature, hash; + Header dkim; + + options = options.Clone (); + options.NewLineFormat = NewLineFormat.Dos; + options.EnsureNewLine = true; + + switch (SignatureAlgorithm) { + case DkimSignatureAlgorithm.Ed25519Sha256: + value.Append ("; a=ed25519-sha256"); + break; case DkimSignatureAlgorithm.RsaSha256: - oid = SecureMimeContext.GetDigestOid (DigestAlgorithm.Sha256); - AlgorithmName = "RSASHA256"; - hash = SHA256.Create (); + value.Append ("; a=rsa-sha256"); break; default: - oid = SecureMimeContext.GetDigestOid (DigestAlgorithm.Sha1); - AlgorithmName = "RSASHA1"; - hash = SHA1.Create (); + value.Append ("; a=rsa-sha1"); break; } - } - public string AlgorithmName { - get; private set; - } + value.AppendFormat ("; d={0}; s={1}", Domain, Selector); + value.AppendFormat ("; c={0}/{1}", + HeaderCanonicalizationAlgorithm.ToString ().ToLowerInvariant (), + BodyCanonicalizationAlgorithm.ToString ().ToLowerInvariant ()); + if (!string.IsNullOrEmpty (QueryMethod)) + value.AppendFormat ("; q={0}", QueryMethod); + if (!string.IsNullOrEmpty (AgentOrUserIdentifier)) + value.AppendFormat ("; i={0}", AgentOrUserIdentifier); + value.AppendFormat ("; t={0}", t); + + using (var stream = new DkimSignatureStream (CreateSigningContext ())) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (options.CreateNewLineFilter ()); + + // write the specified message headers + DkimVerifierBase.WriteHeaders (options, message, headers, HeaderCanonicalizationAlgorithm, filtered); + + value.AppendFormat ("; h={0}", string.Join (":", headers.ToArray ())); + + hash = message.HashBody (options, SignatureAlgorithm, BodyCanonicalizationAlgorithm, -1); + value.AppendFormat ("; bh={0}", Convert.ToBase64String (hash)); + value.Append ("; b="); + + dkim = new Header (HeaderId.DkimSignature, value.ToString ()); + message.Headers.Insert (0, dkim); + + switch (HeaderCanonicalizationAlgorithm) { + case DkimCanonicalizationAlgorithm.Relaxed: + DkimVerifierBase.WriteHeaderRelaxed (options, filtered, dkim, true); + break; + default: + DkimVerifierBase.WriteHeaderSimple (options, filtered, dkim, true); + break; + } - public void BlockUpdate (byte[] input, int inOff, int length) - { - hash.TransformBlock (input, inOff, length, null, 0); - } + filtered.Flush (); + } - public byte[] GenerateSignature () - { - hash.TransformFinalBlock (new byte[0], 0, 0); + signature = stream.GenerateSignature (); - return rsa.SignHash (hash.Hash, oid); + dkim.Value += Convert.ToBase64String (signature); + } } - public void Init (bool forSigning, ICipherParameters parameters) + /// + /// Digitally sign the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// Digitally signs the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// + /// + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + public void Sign (FormatOptions options, MimeMessage message, IList headers) { - throw new NotImplementedException (); - } + if (options == null) + throw new ArgumentNullException (nameof (options)); - public void Reset () - { - hash.Initialize (); + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (headers == null) + throw new ArgumentNullException (nameof (headers)); + + var fields = new string[headers.Count]; + var containsFrom = false; + + for (int i = 0; i < headers.Count; i++) { + if (headers[i] == null) + throw new ArgumentException ("The list of headers cannot contain null.", nameof (headers)); + + if (headers[i].Length == 0) + throw new ArgumentException ("The list of headers cannot contain empty string.", nameof (headers)); + + fields[i] = headers[i].ToLowerInvariant (); + + if (DkimShouldNotInclude.Contains (fields[i])) + throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i]), nameof (headers)); + + if (fields[i] == "from") + containsFrom = true; + } + + if (!containsFrom) + throw new ArgumentException ("The list of headers to sign MUST include the 'From' header.", nameof (headers)); + + DkimSign (options, message, fields); } - public void Update (byte input) + /// + /// Digitally sign the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// Digitally signs the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// + /// + /// The message to sign. + /// The headers to sign. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + public void Sign (MimeMessage message, IList headers) { - hash.TransformBlock (new byte[] { input }, 0, 1, null, 0); + Sign (FormatOptions.Default, message, headers); } - public bool VerifySignature (byte[] signature) + /// + /// Digitally sign the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// Digitally signs the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// + /// + /// The formatting options. + /// The message to sign. + /// The list of header fields to sign. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + public void Sign (FormatOptions options, MimeMessage message, IList headers) { - hash.TransformFinalBlock (new byte[0], 0, 0); + if (options == null) + throw new ArgumentNullException (nameof (options)); + + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (headers == null) + throw new ArgumentNullException (nameof (headers)); + + var fields = new string[headers.Count]; + var containsFrom = false; - return rsa.VerifyHash (hash.Hash, oid, signature); + for (int i = 0; i < headers.Count; i++) { + if (headers[i] == HeaderId.Unknown) + throw new ArgumentException ("The list of headers to sign cannot include the 'Unknown' header.", nameof (headers)); + + fields[i] = headers[i].ToHeaderName ().ToLowerInvariant (); + + if (DkimShouldNotInclude.Contains (fields[i])) + throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i].ToHeaderName ()), nameof (headers)); + + if (headers[i] == HeaderId.From) + containsFrom = true; + } + + if (!containsFrom) + throw new ArgumentException ("The list of headers to sign MUST include the 'From' header.", nameof (headers)); + + DkimSign (options, message, fields); } - public void Dispose () + /// + /// Digitally sign the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// Digitally signs the message using a DomainKeys Identified Mail (DKIM) signature. + /// + /// + /// + /// + /// The message to sign. + /// The headers to sign. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain the 'From' header. + /// -or- + /// contains one or more of the following headers: Return-Path, + /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. + /// + public void Sign (MimeMessage message, IList headers) { - rsa.Dispose (); + Sign (FormatOptions.Default, message, headers); } } -#endif } diff --git a/MimeKit/Cryptography/DkimSignerBase.cs b/MimeKit/Cryptography/DkimSignerBase.cs new file mode 100644 index 0000000000..a7f525785e --- /dev/null +++ b/MimeKit/Cryptography/DkimSignerBase.cs @@ -0,0 +1,293 @@ +// +// DkimSignerBase.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +#if ENABLE_NATIVE_DKIM +using System.Security.Cryptography; +#endif + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Signers; + +namespace MimeKit.Cryptography { + /// + /// A base class for DKIM and ARC signers. + /// + /// + /// The base class for and . + /// + public abstract class DkimSignerBase + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. + /// + /// The domain that the signer represents. + /// The selector subdividing the domain. + /// The signature algorithm. + /// + /// is null. + /// -or- + /// is null. + /// + protected DkimSignerBase (string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + { + if (domain == null) + throw new ArgumentNullException (nameof (domain)); + + if (selector == null) + throw new ArgumentNullException (nameof (selector)); + + SignatureAlgorithm = algorithm; + Selector = selector; + Domain = domain; + } + + /// + /// Get the domain that the signer represents. + /// + /// + /// Gets the domain that the signer represents. + /// + /// + /// + /// + /// The domain. + public string Domain { + get; private set; + } + + /// + /// Get the selector subdividing the domain. + /// + /// + /// Gets the selector subdividing the domain. + /// + /// + /// + /// + /// The selector. + public string Selector { + get; private set; + } + + /// + /// Get or set the algorithm to use for signing. + /// + /// + /// Gets or sets the algorithm to use for signing. + /// Creates a new . + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be used. + /// + /// + /// + /// + /// The signature algorithm. + public DkimSignatureAlgorithm SignatureAlgorithm { + get; set; + } + + /// + /// Get or set the canonicalization algorithm to use for the message body. + /// + /// + /// Gets or sets the canonicalization algorithm to use for the message body. + /// + /// + /// + /// + /// The canonicalization algorithm. + public DkimCanonicalizationAlgorithm BodyCanonicalizationAlgorithm { + get; set; + } + + /// + /// Get or set the canonicalization algorithm to use for the message headers. + /// + /// + /// Gets or sets the canonicalization algorithm to use for the message headers. + /// + /// + /// + /// + /// The canonicalization algorithm. + public DkimCanonicalizationAlgorithm HeaderCanonicalizationAlgorithm { + get; set; + } + + /// + /// Gets the private key. + /// + /// + /// The private key used for signing. + /// + /// The private key. + protected AsymmetricKeyParameter PrivateKey { + get; set; + } + + internal static AsymmetricKeyParameter LoadPrivateKey (Stream stream) + { + AsymmetricKeyParameter key = null; + + using (var reader = new StreamReader (stream)) { + var pem = new PemReader (reader); + + var keyObject = pem.ReadObject (); + + if (keyObject is AsymmetricCipherKeyPair pair) { + key = pair.Private; + } else if (keyObject is AsymmetricKeyParameter) { + key = (AsymmetricKeyParameter) keyObject; + } + } + + if (key == null || !key.IsPrivate) + throw new FormatException ("Private key not found."); + + return key; + } + + /// + /// Create the digest signing context. + /// + /// + /// Creates a new digest signing context. + /// + /// The digest signer. + /// + /// The is not supported. + /// + internal protected virtual ISigner CreateSigningContext () + { +#if ENABLE_NATIVE_DKIM + return new SystemSecuritySigner (SignatureAlgorithm, PrivateKey.AsAsymmetricAlgorithm ()); +#else + ISigner signer; + + switch (SignatureAlgorithm) { + case DkimSignatureAlgorithm.RsaSha1: + signer = new RsaDigestSigner (new Sha1Digest ()); + break; + case DkimSignatureAlgorithm.RsaSha256: + signer = new RsaDigestSigner (new Sha256Digest ()); + break; + case DkimSignatureAlgorithm.Ed25519Sha256: + signer = new Ed25519DigestSigner (new Sha256Digest ()); + break; + default: + throw new NotSupportedException (string.Format ("{0} is not supported.", SignatureAlgorithm)); + } + + signer.Init (true, PrivateKey); + + return signer; +#endif + } + } + +#if ENABLE_NATIVE_DKIM + class SystemSecuritySigner : ISigner + { + readonly RSACryptoServiceProvider rsa; + readonly HashAlgorithm hash; + readonly string oid; + + public SystemSecuritySigner (DkimSignatureAlgorithm algorithm, AsymmetricAlgorithm key) + { + rsa = key as RSACryptoServiceProvider; + + switch (algorithm) { + case DkimSignatureAlgorithm.RsaSha256: + oid = SecureMimeContext.GetDigestOid (DigestAlgorithm.Sha256); + AlgorithmName = "RSASHA256"; + hash = SHA256.Create (); + break; + default: + oid = SecureMimeContext.GetDigestOid (DigestAlgorithm.Sha1); + AlgorithmName = "RSASHA1"; + hash = SHA1.Create (); + break; + } + } + + public string AlgorithmName { + get; private set; + } + + public void BlockUpdate (byte[] input, int inOff, int length) + { + hash.TransformBlock (input, inOff, length, null, 0); + } + + public byte[] GenerateSignature () + { + hash.TransformFinalBlock (new byte[0], 0, 0); + + return rsa.SignHash (hash.Hash, oid); + } + + public void Init (bool forSigning, ICipherParameters parameters) + { + throw new NotImplementedException (); + } + + public void Reset () + { + hash.Initialize (); + } + + public void Update (byte input) + { + hash.TransformBlock (new byte[] { input }, 0, 1, null, 0); + } + + public bool VerifySignature (byte[] signature) + { + hash.TransformFinalBlock (new byte[0], 0, 0); + + return rsa.VerifyHash (hash.Hash, oid, signature); + } + + public void Dispose () + { + rsa.Dispose (); + } + } +#endif +} diff --git a/MimeKit/Cryptography/DkimSimpleBodyFilter.cs b/MimeKit/Cryptography/DkimSimpleBodyFilter.cs index d1afe759dc..1c1e440f57 100644 --- a/MimeKit/Cryptography/DkimSimpleBodyFilter.cs +++ b/MimeKit/Cryptography/DkimSimpleBodyFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,7 @@ namespace MimeKit.Cryptography { class DkimSimpleBodyFilter : DkimBodyFilter { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/DkimVerifier.cs b/MimeKit/Cryptography/DkimVerifier.cs new file mode 100644 index 0000000000..e836101efc --- /dev/null +++ b/MimeKit/Cryptography/DkimVerifier.cs @@ -0,0 +1,281 @@ +// +// DkimVerifier.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; + +namespace MimeKit.Cryptography { + /// + /// A DKIM-Signature verifier. + /// + /// + /// Verifies DomainKeys Identified Mail (DKIM) signatures. + /// + /// + /// + /// + public class DkimVerifier : DkimVerifierBase + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// + /// + /// + /// The public key locator. + /// + /// is null. + /// + public DkimVerifier (IDkimPublicKeyLocator publicKeyLocator) : base (publicKeyLocator) + { + } + + static void ValidateDkimSignatureParameters (IDictionary parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm, + out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength) + { + bool containsFrom = false; + + if (!parameters.TryGetValue ("v", out string v)) + throw new FormatException ("Malformed DKIM-Signature header: no version parameter detected."); + + if (v != "1") + throw new FormatException (string.Format ("Unrecognized DKIM-Signature version: v={0}", v)); + + ValidateCommonSignatureParameters ("DKIM-Signature", parameters, out algorithm, out headerAlgorithm, out bodyAlgorithm, out d, out s, out q, out headers, out bh, out b, out maxLength); + + for (int i = 0; i < headers.Length; i++) { + if (headers[i].Equals ("from", StringComparison.OrdinalIgnoreCase)) { + containsFrom = true; + break; + } + } + + if (!containsFrom) + throw new FormatException ("Malformed DKIM-Signature header: From header not signed."); + + if (parameters.TryGetValue ("i", out string id)) { + string ident; + int at; + + if ((at = id.LastIndexOf ('@')) == -1) + throw new FormatException ("Malformed DKIM-Signature header: no @ in the AUID value."); + + ident = id.Substring (at + 1); + + if (!ident.Equals (d, StringComparison.OrdinalIgnoreCase) && !ident.EndsWith ("." + d, StringComparison.OrdinalIgnoreCase)) + throw new FormatException ("Invalid DKIM-Signature header: the domain in the AUID does not match the domain parameter."); + } + } + + async Task VerifyAsync (FormatOptions options, MimeMessage message, Header dkimSignature, bool doAsync, CancellationToken cancellationToken) + { + if (options == null) + throw new ArgumentNullException (nameof (options)); + + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (dkimSignature == null) + throw new ArgumentNullException (nameof (dkimSignature)); + + if (dkimSignature.Id != HeaderId.DkimSignature) + throw new ArgumentException ("The signature parameter MUST be a DKIM-Signature header.", nameof (dkimSignature)); + + var parameters = ParseParameterTags (dkimSignature.Id, dkimSignature.Value); + DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; + DkimSignatureAlgorithm signatureAlgorithm; + AsymmetricKeyParameter key; + string d, s, q, bh, b; + string[] headers; + int maxLength; + + ValidateDkimSignatureParameters (parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, + out d, out s, out q, out headers, out bh, out b, out maxLength); + + if (!IsEnabled (signatureAlgorithm)) + return false; + + options = options.Clone (); + options.NewLineFormat = NewLineFormat.Dos; + + // first check the body hash (if that's invalid, then the entire signature is invalid) + if (!VerifyBodyHash (options, message, signatureAlgorithm, bodyAlgorithm, maxLength, bh)) + return false; + + if (doAsync) + key = await PublicKeyLocator.LocatePublicKeyAsync (q, d, s, cancellationToken).ConfigureAwait (false); + else + key = PublicKeyLocator.LocatePublicKey (q, d, s, cancellationToken); + + if ((key is RsaKeyParameters rsa) && rsa.Modulus.BitLength < MinimumRsaKeyLength) + return false; + + return VerifySignature (options, message, dkimSignature, signatureAlgorithm, key, headers, headerAlgorithm, b); + } + + /// + /// Verify the specified DKIM-Signature header. + /// + /// + /// Verifies the specified DKIM-Signature header. + /// + /// + /// + /// + /// true if the DKIM-Signature is valid; otherwise, false. + /// The formatting options. + /// The message to verify. + /// The DKIM-Signature header. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// is not a DKIM-Signature header. + /// + /// + /// The DKIM-Signature header value is malformed. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public bool Verify (FormatOptions options, MimeMessage message, Header dkimSignature, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (options, message, dkimSignature, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously verify the specified DKIM-Signature header. + /// + /// + /// Verifies the specified DKIM-Signature header. + /// + /// + /// + /// + /// true if the DKIM-Signature is valid; otherwise, false. + /// The formatting options. + /// The message to verify. + /// The DKIM-Signature header. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// is not a DKIM-Signature header. + /// + /// + /// The DKIM-Signature header value is malformed. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public Task VerifyAsync (FormatOptions options, MimeMessage message, Header dkimSignature, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (options, message, dkimSignature, true, cancellationToken); + } + + /// + /// Verify the specified DKIM-Signature header. + /// + /// + /// Verifies the specified DKIM-Signature header. + /// + /// + /// + /// + /// true if the DKIM-Signature is valid; otherwise, false. + /// The message to verify. + /// The DKIM-Signature header. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// is not a DKIM-Signature header. + /// + /// + /// The DKIM-Signature header value is malformed. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public bool Verify (MimeMessage message, Header dkimSignature, CancellationToken cancellationToken = default (CancellationToken)) + { + return Verify (FormatOptions.Default, message, dkimSignature, cancellationToken); + } + + /// + /// Asynchronously verify the specified DKIM-Signature header. + /// + /// + /// Verifies the specified DKIM-Signature header. + /// + /// + /// + /// + /// true if the DKIM-Signature is valid; otherwise, false. + /// The message to verify. + /// The DKIM-Signature header. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// is not a DKIM-Signature header. + /// + /// + /// The DKIM-Signature header value is malformed. + /// + /// + /// The operation was canceled via the cancellation token. + /// + public Task VerifyAsync (MimeMessage message, Header dkimSignature, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (FormatOptions.Default, message, dkimSignature, cancellationToken); + } + } +} diff --git a/MimeKit/Cryptography/DkimVerifierBase.cs b/MimeKit/Cryptography/DkimVerifierBase.cs new file mode 100644 index 0000000000..fdaca3fa70 --- /dev/null +++ b/MimeKit/Cryptography/DkimVerifierBase.cs @@ -0,0 +1,559 @@ +// +// DkimVerifierBase.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; +using System.Globalization; +using System.Collections.Generic; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Signers; + +using MimeKit.IO; +using MimeKit.Utils; + +namespace MimeKit.Cryptography { + /// + /// A base class for DKIM and ARC verifiers. + /// + /// + /// The base class for and . + /// + public abstract class DkimVerifierBase + { + int enabledSignatureAlgorithms; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Initializes the . + /// + /// The public key locator. + /// + /// is null. + /// + protected DkimVerifierBase (IDkimPublicKeyLocator publicKeyLocator) + { + if (publicKeyLocator == null) + throw new ArgumentNullException (nameof (publicKeyLocator)); + + PublicKeyLocator = publicKeyLocator; + + Enable (DkimSignatureAlgorithm.Ed25519Sha256); + Enable (DkimSignatureAlgorithm.RsaSha256); + //Enable (DkimSignatureAlgorithm.RsaSha1); + MinimumRsaKeyLength = 1024; + } + + /// + /// Get the public key locator. + /// + /// + /// Gets the public key locator. + /// + /// The public key locator. + protected IDkimPublicKeyLocator PublicKeyLocator { + get; private set; + } + + /// + /// Get or set the minimum allowed RSA key length. + /// + /// + /// Gets the minimum allowed RSA key length. + /// The DKIM specifications specify a single signing algorithm, RSA, + /// and recommend key sizes of 1024 to 2048 bits (but require verification of 512-bit keys). + /// As discussed in US-CERT Vulnerability Note VU#268267, the operational community has + /// recognized that shorter keys compromise the effectiveness of DKIM. While 1024-bit + /// signatures are common, stronger signatures are not. Widely used DNS configuration + /// software places a practical limit on key sizes, because the software only handles a + /// single 256-octet string in a TXT record, and RSA keys significantly longer than 1024 + /// bits don't fit in 256 octets. + /// + public int MinimumRsaKeyLength { + get; set; + } + + /// + /// Enable a DKIM signature algorithm. + /// + /// + /// Enables the specified DKIM signature algorithm. + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be enabled. + /// + /// The DKIM signature algorithm. + public void Enable (DkimSignatureAlgorithm algorithm) + { + enabledSignatureAlgorithms |= 1 << (int) algorithm; + } + + /// + /// Disable a DKIM signature algorithm. + /// + /// + /// Disables the specified DKIM signature algorithm. + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be enabled. + /// + /// The DKIM signature algorithm. + public void Disable (DkimSignatureAlgorithm algorithm) + { + enabledSignatureAlgorithms &= ~(1 << (int) algorithm); + } + + /// + /// Check whether a DKIM signature algorithm is enabled. + /// + /// + /// Determines whether the specified DKIM signature algorithm is enabled. + /// Due to the recognized weakness of the SHA-1 hash algorithm + /// and the wide availability of the SHA-256 hash algorithm (it has been a required + /// part of DKIM since it was originally standardized in 2007), it is recommended + /// that NOT be enabled. + /// + /// true if the specified DKIM signature algorithm is enabled; otherwise, false. + /// The DKIM signature algorithm. + public bool IsEnabled (DkimSignatureAlgorithm algorithm) + { + return (enabledSignatureAlgorithms & (1 << (int) algorithm)) != 0; + } + + static bool IsWhiteSpace (char c) + { + return c == ' ' || c == '\t'; + } + + static bool IsAlpha (char c) + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + } + + internal static Dictionary ParseParameterTags (HeaderId header, string signature) + { + var parameters = new Dictionary (); + var value = new StringBuilder (); + int index = 0; + + while (index < signature.Length) { + while (index < signature.Length && IsWhiteSpace (signature[index])) + index++; + + if (index >= signature.Length) + break; + + if (signature[index] == ';' || !IsAlpha (signature[index])) + throw new FormatException (string.Format ("Malformed {0} value.", header.ToHeaderName ())); + + int startIndex = index++; + + while (index < signature.Length && signature[index] != '=') + index++; + + if (index >= signature.Length) + continue; + + var name = signature.Substring (startIndex, index - startIndex).TrimEnd (); + + // skip over '=' and clear value buffer + value.Length = 0; + index++; + + while (index < signature.Length && signature[index] != ';') { + if (!IsWhiteSpace (signature[index])) + value.Append (signature[index]); + index++; + } + + if (parameters.ContainsKey (name)) + throw new FormatException (string.Format ("Malformed {0} value: duplicate parameter '{1}'.", header.ToHeaderName (), name)); + + parameters.Add (name, value.ToString ()); + + // skip over ';' + index++; + } + + return parameters; + } + + internal static void ValidateCommonParameters (string header, IDictionary parameters, out DkimSignatureAlgorithm algorithm, + out string d, out string s, out string q, out string b) + { + if (!parameters.TryGetValue ("a", out string a)) + throw new FormatException (string.Format ("Malformed {0} header: no signature algorithm parameter detected.", header)); + + switch (a.ToLowerInvariant ()) { + case "ed25519-sha256": algorithm = DkimSignatureAlgorithm.Ed25519Sha256; break; + case "rsa-sha256": algorithm = DkimSignatureAlgorithm.RsaSha256; break; + case "rsa-sha1": algorithm = DkimSignatureAlgorithm.RsaSha1; break; + default: throw new FormatException (string.Format ("Unrecognized {0} algorithm parameter: a={1}", header, a)); + } + + if (!parameters.TryGetValue ("d", out d)) + throw new FormatException (string.Format ("Malformed {0} header: no domain parameter detected.", header)); + + if (d.Length == 0) + throw new FormatException (string.Format ("Malformed {0} header: empty domain parameter detected.", header)); + + if (!parameters.TryGetValue ("s", out s)) + throw new FormatException (string.Format ("Malformed {0} header: no selector parameter detected.", header)); + + if (s.Length == 0) + throw new FormatException (string.Format ("Malformed {0} header: empty selector parameter detected.", header)); + + if (!parameters.TryGetValue ("q", out q)) + q = "dns/txt"; + + if (!parameters.TryGetValue ("b", out b)) + throw new FormatException (string.Format ("Malformed {0} header: no signature parameter detected.", header)); + + if (b.Length == 0) + throw new FormatException (string.Format ("Malformed {0} header: empty signature parameter detected.", header)); + + if (parameters.TryGetValue ("t", out string t)) { + if (!int.TryParse (t, NumberStyles.Integer, CultureInfo.InvariantCulture, out int timestamp) || timestamp < 0) + throw new FormatException (string.Format ("Malformed {0} header: invalid timestamp parameter: t={1}.", header, t)); + } + } + + internal static void ValidateCommonSignatureParameters (string header, IDictionary parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm, + out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength) + { + ValidateCommonParameters (header, parameters, out algorithm, out d, out s, out q, out b); + + if (parameters.TryGetValue ("l", out string l)) { + if (!int.TryParse (l, NumberStyles.Integer, CultureInfo.InvariantCulture, out maxLength) || maxLength < 0) + throw new FormatException (string.Format ("Malformed {0} header: invalid length parameter: l={1}", header, l)); + } else { + maxLength = -1; + } + + if (parameters.TryGetValue ("c", out string c)) { + var tokens = c.ToLowerInvariant ().Split ('/'); + + if (tokens.Length == 0 || tokens.Length > 2) + throw new FormatException (string.Format ("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c)); + + switch (tokens[0]) { + case "relaxed": headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break; + case "simple": headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; break; + default: throw new FormatException (string.Format ("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c)); + } + + if (tokens.Length == 2) { + switch (tokens[1]) { + case "relaxed": bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break; + case "simple": bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; break; + default: throw new FormatException (string.Format ("Malformed {0} header: invalid canonicalization parameter: c={1}", header, c)); + } + } else { + bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; + } + } else { + headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; + bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; + } + + if (!parameters.TryGetValue ("h", out string h)) + throw new FormatException (string.Format ("Malformed {0} header: no signed header parameter detected.", header)); + + headers = h.Split (':'); + + if (!parameters.TryGetValue ("bh", out bh)) + throw new FormatException (string.Format ("Malformed {0} header: no body hash parameter detected.", header)); + } + + internal static void WriteHeaderRelaxed (FormatOptions options, Stream stream, Header header, bool isDkimSignature) + { + // o Convert all header field names (not the header field values) to + // lowercase. For example, convert "SUBJect: AbC" to "subject: AbC". + var name = Encoding.ASCII.GetBytes (header.Field.ToLowerInvariant ()); + var rawValue = header.GetRawValue (options); + int index = 0; + + // o Delete any WSP characters remaining before and after the colon + // separating the header field name from the header field value. The + // colon separator MUST be retained. + stream.Write (name, 0, name.Length); + stream.WriteByte ((byte) ':'); + + // trim leading whitespace... + while (index < rawValue.Length && rawValue[index].IsWhitespace ()) + index++; + + while (index < rawValue.Length) { + int startIndex = index; + + // look for the first non-whitespace character + while (index < rawValue.Length && rawValue[index].IsWhitespace ()) + index++; + + // o Delete all WSP characters at the end of each unfolded header field + // value. + if (index >= rawValue.Length) + break; + + // o Convert all sequences of one or more WSP characters to a single SP + // character. WSP characters here include those before and after a + // line folding boundary. + if (index > startIndex) + stream.WriteByte ((byte) ' '); + + startIndex = index; + + while (index < rawValue.Length && !rawValue[index].IsWhitespace ()) + index++; + + if (index > startIndex) + stream.Write (rawValue, startIndex, index - startIndex); + } + + if (!isDkimSignature) + stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length); + } + + internal static void WriteHeaderSimple (FormatOptions options, Stream stream, Header header, bool isDkimSignature) + { + var rawValue = header.GetRawValue (options); + int rawLength = rawValue.Length; + + if (isDkimSignature && rawLength > 0) { + if (rawValue[rawLength - 1] == (byte) '\n') { + rawLength--; + + if (rawLength > 0 && rawValue[rawLength - 1] == (byte) '\r') + rawLength--; + } + } + + stream.Write (header.RawField, 0, header.RawField.Length); + stream.Write (Header.Colon, 0, Header.Colon.Length); + stream.Write (rawValue, 0, rawLength); + } + + /// + /// Create the digest signing context. + /// + /// + /// Creates a new digest signing context that uses the specified algorithm. + /// + /// The DKIM signature algorithm. + /// The public key. + /// The digest signer. + internal virtual ISigner CreateVerifyContext (DkimSignatureAlgorithm algorithm, AsymmetricKeyParameter key) + { +#if ENABLE_NATIVE_DKIM + return new SystemSecuritySigner (algorithm, key.AsAsymmetricAlgorithm ()); +#else + ISigner signer; + + switch (algorithm) { + case DkimSignatureAlgorithm.RsaSha1: + signer = new RsaDigestSigner (new Sha1Digest ()); + break; + case DkimSignatureAlgorithm.RsaSha256: + signer = new RsaDigestSigner (new Sha256Digest ()); + break; + case DkimSignatureAlgorithm.Ed25519Sha256: + signer = new Ed25519DigestSigner (new Sha256Digest ()); + break; + default: + throw new NotSupportedException (string.Format ("{0} is not supported.", algorithm)); + } + + signer.Init (key.IsPrivate, key); + + return signer; +#endif + } + + internal static void WriteHeaders (FormatOptions options, MimeMessage message, IList fields, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm, Stream stream) + { + var counts = new Dictionary (StringComparer.Ordinal); + + for (int i = 0; i < fields.Count; i++) { + var headers = fields[i].StartsWith ("Content-", StringComparison.OrdinalIgnoreCase) ? message.Body.Headers : message.Headers; + var name = fields[i].ToLowerInvariant (); + int index, count, n = 0; + + if (!counts.TryGetValue (name, out count)) + count = 0; + + // Note: signers choosing to sign an existing header field that occurs more + // than once in the message (such as Received) MUST sign the physically last + // instance of that header field in the header block. Signers wishing to sign + // multiple instances of such a header field MUST include the header field + // name multiple times in the list of header fields and MUST sign such header + // fields in order from the bottom of the header field block to the top. + index = headers.LastIndexOf (name); + + // find the n'th header with this name + while (n < count && --index >= 0) { + if (headers[index].Field.Equals (name, StringComparison.OrdinalIgnoreCase)) + n++; + } + + if (index < 0) + continue; + + var header = headers[index]; + + switch (headerCanonicalizationAlgorithm) { + case DkimCanonicalizationAlgorithm.Relaxed: + WriteHeaderRelaxed (options, stream, header, false); + break; + default: + WriteHeaderSimple (options, stream, header, false); + break; + } + + counts[name] = ++count; + } + } + + internal static Header GetSignedSignatureHeader (Header header) + { + // modify the raw DKIM-Signature header value by chopping off the signature value after the "b=" + var rawValue = (byte[]) header.RawValue.Clone (); + int length = 0, index = 0; + + do { + while (index < rawValue.Length && rawValue[index].IsWhitespace ()) + index++; + + if (index + 2 < rawValue.Length) { + var param = (char) rawValue[index++]; + + while (index < rawValue.Length && rawValue[index].IsWhitespace ()) + index++; + + if (index < rawValue.Length && rawValue[index] == (byte) '=' && param == 'b') { + length = ++index; + + while (index < rawValue.Length && rawValue[index] != (byte) ';') + index++; + + if (index == rawValue.Length && rawValue[index - 1] == (byte) '\n') { + index--; + + if (rawValue[index - 1] == (byte) '\r') + index--; + } + + break; + } + } + + while (index < rawValue.Length && rawValue[index] != (byte) ';') + index++; + + if (index < rawValue.Length) + index++; + } while (index < rawValue.Length); + + if (index == rawValue.Length) + throw new FormatException (string.Format ("Malformed {0} header: missing signature parameter.", header.Id.ToHeaderName ())); + + while (index < rawValue.Length) + rawValue[length++] = rawValue[index++]; + + Array.Resize (ref rawValue, length); + + return new Header (header.Options, header.RawField, rawValue, false); + } + + /// + /// Verify the hash of the message body. + /// + /// + /// Verifies the hash of the message body. + /// + /// The formatting options. + /// The signed MIME message. + /// The algorithm used to sign the message. + /// The algorithm used to canonicalize the message body. + /// The max length of the message body to hash or -1 to hash the entire message body. + /// The expected message body hash encoded in base64. + /// true if the calculated body hash matches ; otherwise, false. + protected bool VerifyBodyHash (FormatOptions options, MimeMessage message, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm canonicalizationAlgorithm, int maxLength, string bodyHash) + { + var hash = Convert.ToBase64String (message.HashBody (options, signatureAlgorithm, canonicalizationAlgorithm, maxLength)); + + return hash == bodyHash; + } + + /// + /// Verify the signature of the message headers. + /// + /// + /// Verifies the signature of the message headers. + /// + /// The formatting options. + /// The signed MIME message. + /// The DKIM-Signature or ARC-Message-Signature header. + /// The algorithm used to sign the message headers. + /// The public key used to verify the signature. + /// The list of headers that were signed. + /// The algorithm used to canonicalize the headers. + /// The expected signature of the headers encoded in base64. + /// true if the calculated signature matches ; otherwise, false. + protected bool VerifySignature (FormatOptions options, MimeMessage message, Header dkimSignature, DkimSignatureAlgorithm signatureAlgorithm, AsymmetricKeyParameter key, string[] headers, DkimCanonicalizationAlgorithm canonicalizationAlgorithm, string signature) + { + using (var stream = new DkimSignatureStream (CreateVerifyContext (signatureAlgorithm, key))) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (options.CreateNewLineFilter ()); + + WriteHeaders (options, message, headers, canonicalizationAlgorithm, filtered); + + // now include the DKIM-Signature header that we are verifying, + // but only after removing the "b=" signature value. + var header = GetSignedSignatureHeader (dkimSignature); + + switch (canonicalizationAlgorithm) { + case DkimCanonicalizationAlgorithm.Relaxed: + WriteHeaderRelaxed (options, filtered, header, true); + break; + default: + WriteHeaderSimple (options, filtered, header, true); + break; + } + + filtered.Flush (); + } + + return stream.VerifySignature (signature); + } + } + } +} diff --git a/MimeKit/Cryptography/Ed25519DigestSigner.cs b/MimeKit/Cryptography/Ed25519DigestSigner.cs new file mode 100644 index 0000000000..ec100de3da --- /dev/null +++ b/MimeKit/Cryptography/Ed25519DigestSigner.cs @@ -0,0 +1,114 @@ +// +// Ed25519DigestSigner.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Math.EC.Rfc8032; +using Org.BouncyCastle.Crypto.Parameters; + +namespace MimeKit.Cryptography { + class Ed25519DigestSigner : ISigner + { + Ed25519PrivateKeyParameters privateKey; + Ed25519PublicKeyParameters publicKey; + readonly IDigest digest; + + public Ed25519DigestSigner (IDigest digest) + { + this.digest = digest; + } + + public string AlgorithmName { + get { return digest.AlgorithmName + "withEd25519"; } + } + + public void Init (bool forSigning, ICipherParameters parameters) + { + if (forSigning) { + privateKey = (Ed25519PrivateKeyParameters) parameters; + publicKey = privateKey.GeneratePublicKey (); + } else { + publicKey = (Ed25519PublicKeyParameters) parameters; + privateKey = null; + } + + Reset (); + } + + public void Update (byte input) + { + digest.Update (input); + } + + public void BlockUpdate (byte[] input, int inOff, int length) + { + digest.BlockUpdate (input, inOff, length); + } + + public byte[] GenerateSignature () + { + if (privateKey == null) + throw new InvalidOperationException ("Ed25519DigestSigner not initialised for signature generation."); + + var hash = new byte[digest.GetDigestSize ()]; + + digest.DoFinal (hash, 0); + + var signature = new byte[Ed25519PrivateKeyParameters.SignatureSize]; + privateKey.Sign (Ed25519.Algorithm.Ed25519, null, hash, 0, hash.Length, signature, 0); + + Reset (); + + return signature; + } + + public bool VerifySignature (byte[] signature) + { + if (privateKey != null) + throw new InvalidOperationException ("Ed25519DigestSigner not initialised for verification"); + + if (Ed25519.SignatureSize != signature.Length) + return false; + + var hash = new byte[digest.GetDigestSize ()]; + + digest.DoFinal (hash, 0); + + var pk = publicKey.GetEncoded (); + var result = Ed25519.Verify (signature, 0, pk, 0, hash, 0, hash.Length); + + Reset (); + + return result; + } + + public void Reset () + { + digest.Reset (); + } + } +} diff --git a/MimeKit/Cryptography/EncryptionAlgorithm.cs b/MimeKit/Cryptography/EncryptionAlgorithm.cs index 8aa15f1671..cc092f2d6f 100644 --- a/MimeKit/Cryptography/EncryptionAlgorithm.cs +++ b/MimeKit/Cryptography/EncryptionAlgorithm.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/GnuPGContext.cs b/MimeKit/Cryptography/GnuPGContext.cs index 1af582f2e0..efbe928782 100644 --- a/MimeKit/Cryptography/GnuPGContext.cs +++ b/MimeKit/Cryptography/GnuPGContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -40,6 +40,7 @@ public abstract class GnuPGContext : OpenPgpContext static readonly Dictionary EncryptionAlgorithms; //static readonly Dictionary PublicKeyAlgorithms; static readonly Dictionary DigestAlgorithms; + static readonly char[] Whitespace = { ' ', '\t' }; static readonly string PublicKeyRing; static readonly string SecretKeyRing; static readonly string Configuration; @@ -49,7 +50,7 @@ static GnuPGContext () var gnupg = Environment.GetEnvironmentVariable ("GNUPGHOME"); if (gnupg == null) { -#if !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 if (Path.DirectorySeparatorChar == '\\') { var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData); gnupg = Path.Combine (appData, "gnupg"); @@ -66,7 +67,7 @@ static GnuPGContext () SecretKeyRing = Path.Combine (gnupg, "secring.gpg"); Configuration = Path.Combine (gnupg, "gpg.conf"); - EncryptionAlgorithms = new Dictionary { + EncryptionAlgorithms = new Dictionary (StringComparer.Ordinal) { { "AES", EncryptionAlgorithm.Aes128 }, { "AES128", EncryptionAlgorithm.Aes128 }, { "AES192", EncryptionAlgorithm.Aes192 }, @@ -90,7 +91,7 @@ static GnuPGContext () // { "RSA", PublicKeyAlgorithm.RsaGeneral } //}; - DigestAlgorithms = new Dictionary { + DigestAlgorithms = new Dictionary (StringComparer.Ordinal) { { "RIPEMD160", DigestAlgorithm.RipeMD160 }, { "SHA1", DigestAlgorithm.Sha1 }, { "SHA224", DigestAlgorithm.Sha224 }, @@ -101,7 +102,7 @@ static GnuPGContext () } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -135,7 +136,7 @@ void UpdateKeyServerOptions (string value) if (string.IsNullOrEmpty (value)) return; - var options = value.Split (new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var options = value.Split (Whitespace, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < options.Length; i++) { switch (options[i]) { case "auto-key-retrieve": @@ -147,7 +148,7 @@ void UpdateKeyServerOptions (string value) static EncryptionAlgorithm[] ParseEncryptionAlgorithms (string value) { - var names = value.Split (new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var names = value.Split (Whitespace, StringSplitOptions.RemoveEmptyEntries); var algorithms = new List (); var seen = new HashSet (); @@ -187,7 +188,7 @@ static EncryptionAlgorithm[] ParseEncryptionAlgorithms (string value) static DigestAlgorithm[] ParseDigestAlgorithms (string value) { - var names = value.Split (new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + var names = value.Split (Whitespace, StringSplitOptions.RemoveEmptyEntries); var algorithms = new List (); var seen = new HashSet (); diff --git a/MimeKit/Cryptography/IDigitalCertificate.cs b/MimeKit/Cryptography/IDigitalCertificate.cs index 05206c9b11..45e6fac287 100644 --- a/MimeKit/Cryptography/IDigitalCertificate.cs +++ b/MimeKit/Cryptography/IDigitalCertificate.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/IDigitalSignature.cs b/MimeKit/Cryptography/IDigitalSignature.cs index e39dda5a11..aa26eb09df 100644 --- a/MimeKit/Cryptography/IDigitalSignature.cs +++ b/MimeKit/Cryptography/IDigitalSignature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -77,10 +77,23 @@ public interface IDigitalSignature /// /// Verifies the digital signature. /// - /// true if the signature is valid; otherwise false. + /// true if the signature is valid; otherwise, false. /// /// An error verifying the signature has occurred. /// bool Verify (); + + /// + /// Verifies the digital signature. + /// + /// + /// Verifies the digital signature. + /// + /// true if only the signature itself should be verified; otherwise, both the signature and the certificate chain are validated. + /// true if the signature is valid; otherwise, false. + /// + /// An error verifying the signature has occurred. + /// + bool Verify (bool verifySignatureOnly); } } diff --git a/MimeKit/Cryptography/IDkimPublicKeyLocator.cs b/MimeKit/Cryptography/IDkimPublicKeyLocator.cs index 151ded7ad9..c729dbf2d4 100644 --- a/MimeKit/Cryptography/IDkimPublicKeyLocator.cs +++ b/MimeKit/Cryptography/IDkimPublicKeyLocator.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,23 +37,33 @@ namespace MimeKit.Cryptography { /// An interface for a service which locates and retrieves DKIM public keys (probably via DNS). /// Since MimeKit itself does not implement DNS, it is up to the client to implement public key lookups /// via DNS. - /// /// /// /// /// + /// + /// + /// + /// + /// + /// public interface IDkimPublicKeyLocator { /// - /// Locate and retrieves the public key for the given domain and selector. + /// Locate and retrieve the public key for the given domain and selector. /// /// /// Locates and retrieves the public key for the given domain and selector. - /// /// /// /// /// + /// + /// + /// + /// + /// + /// /// The public key. /// A colon-separated list of query methods used to retrieve the public key. The default is "dns/txt". /// The domain. @@ -62,15 +72,20 @@ public interface IDkimPublicKeyLocator AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)); /// - /// Asynchronously locate and retrieves the public key for the given domain and selector. + /// Asynchronously locate and retrieve the public key for the given domain and selector. /// /// /// Locates and retrieves the public key for the given domain and selector. - /// /// /// /// /// + /// + /// + /// + /// + /// + /// /// The public key. /// A colon-separated list of query methods used to retrieve the public key. The default is "dns/txt". /// The domain. diff --git a/MimeKit/Cryptography/IX509CertificateDatabase.cs b/MimeKit/Cryptography/IX509CertificateDatabase.cs index a8ee7e7819..9be106ad4f 100644 --- a/MimeKit/Cryptography/IX509CertificateDatabase.cs +++ b/MimeKit/Cryptography/IX509CertificateDatabase.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -101,9 +101,9 @@ public interface IX509CertificateDatabase : IX509Store, IDisposable /// /// The matching certificate records populated with the desired fields. /// The match selector or null to match all certificates. - /// true if only trusted certificates should be returned. + /// true if only trusted anchor certificates should be returned. /// The desired fields. - IEnumerable Find (IX509Selector selector, bool trustedOnly, X509CertificateRecordFields fields); + IEnumerable Find (IX509Selector selector, bool trustedAnchorsOnly, X509CertificateRecordFields fields); /// /// Add the specified certificate record. diff --git a/MimeKit/Cryptography/LdapUri.cs b/MimeKit/Cryptography/LdapUri.cs index 9a20d12d2d..0533814a89 100644 --- a/MimeKit/Cryptography/LdapUri.cs +++ b/MimeKit/Cryptography/LdapUri.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2019 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/MD5.cs b/MimeKit/Cryptography/MD5.cs index dcb45deddd..10719be8dc 100644 --- a/MimeKit/Cryptography/MD5.cs +++ b/MimeKit/Cryptography/MD5.cs @@ -70,7 +70,7 @@ public sealed class MD5 : IDisposable ulong count; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new instance of an MD5 hash algorithm context. @@ -85,7 +85,7 @@ public sealed class MD5 : IDisposable } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new instance of an MD5 hash algorithm context. @@ -97,11 +97,11 @@ public static MD5 Create () /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// ~MD5 () { @@ -733,12 +733,12 @@ void Dispose (bool disposing) } /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After calling - /// , you must release all references to the so the - /// garbage collector can reclaim the memory that the was occupying. + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After calling + /// , you must release all references to the so the + /// garbage collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); diff --git a/MimeKit/Cryptography/MultipartEncrypted.cs b/MimeKit/Cryptography/MultipartEncrypted.cs index b15ce2eb44..d6a69fc9a4 100644 --- a/MimeKit/Cryptography/MultipartEncrypted.cs +++ b/MimeKit/Cryptography/MultipartEncrypted.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,10 +44,10 @@ namespace MimeKit.Cryptography { public class MultipartEncrypted : Multipart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -58,7 +58,7 @@ public MultipartEncrypted (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -71,12 +71,12 @@ public MultipartEncrypted () : base ("encrypted") /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -1029,11 +1029,10 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); if (string.IsNullOrEmpty (protocol)) throw new FormatException (); - protocol = protocol.Trim ().ToLowerInvariant (); if (!ctx.Supports (protocol)) throw new NotSupportedException (); @@ -1046,7 +1045,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, var ctype = version.ContentType; var value = string.Format ("{0}/{1}", ctype.MediaType, ctype.MediaSubtype); - if (value.ToLowerInvariant () != protocol) + if (!value.Equals (protocol, StringComparison.OrdinalIgnoreCase)) throw new FormatException (); var encrypted = this[1] as MimePart; @@ -1097,9 +1096,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, /// public MimeEntity Decrypt (OpenPgpContext ctx, CancellationToken cancellationToken = default (CancellationToken)) { - DigitalSignatureCollection signatures; - - return Decrypt (ctx, out signatures, cancellationToken); + return Decrypt (ctx, out _, cancellationToken); } /// @@ -1118,7 +1115,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, /// The multipart is malformed in some way. /// /// - /// A suitable for + /// A suitable for /// decrypting could not be found. /// /// @@ -1134,12 +1131,10 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, /// public MimeEntity Decrypt (out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default (CancellationToken)) { - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); if (string.IsNullOrEmpty (protocol)) throw new FormatException (); - protocol = protocol.Trim ().ToLowerInvariant (); - if (Count < 2) throw new FormatException (); @@ -1149,7 +1144,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, var ctype = version.ContentType; var value = string.Format ("{0}/{1}", ctype.MediaType, ctype.MediaSubtype); - if (value.ToLowerInvariant () != protocol) + if (!value.Equals (protocol, StringComparison.OrdinalIgnoreCase)) throw new FormatException (); var encrypted = this[1] as MimePart; @@ -1190,7 +1185,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, /// The multipart is malformed in some way. /// /// - /// A suitable for + /// A suitable for /// decrypting could not be found. /// /// @@ -1206,9 +1201,7 @@ public static MultipartEncrypted Encrypt (IEnumerable recipients, /// public MimeEntity Decrypt (CancellationToken cancellationToken = default (CancellationToken)) { - DigitalSignatureCollection signatures; - - return Decrypt (out signatures, cancellationToken); + return Decrypt (out _, cancellationToken); } } } diff --git a/MimeKit/Cryptography/MultipartSigned.cs b/MimeKit/Cryptography/MultipartSigned.cs index cf3b06b122..04b30c01ad 100644 --- a/MimeKit/Cryptography/MultipartSigned.cs +++ b/MimeKit/Cryptography/MultipartSigned.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,9 +46,9 @@ namespace MimeKit.Cryptography { public class MultipartSigned : Multipart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// - /// This constructor is used by . + /// This constructor is used by . /// Information used by the constructor. /// /// is null. @@ -58,7 +58,7 @@ public MultipartSigned (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -71,12 +71,12 @@ public MultipartSigned () : base ("signed") /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -409,11 +409,11 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); if (string.IsNullOrEmpty (protocol)) throw new FormatException ("The multipart/signed part did not specify a protocol."); - if (!ctx.Supports (protocol.Trim ())) + if (!ctx.Supports (protocol)) throw new NotSupportedException ("The specified cryptography context does not support the signature protocol."); if (Count < 2) @@ -436,6 +436,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = // Note: see rfc2015 or rfc3156, section 5.1 var options = FormatOptions.CloneDefault (); options.NewLineFormat = NewLineFormat.Dos; + options.VerifyingSignature = true; this[0].WriteTo (options, cleartext); cleartext.Position = 0; @@ -474,11 +475,11 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = if (ctx == null) throw new ArgumentNullException (nameof (ctx)); - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); if (string.IsNullOrEmpty (protocol)) throw new FormatException ("The multipart/signed part did not specify a protocol."); - if (!ctx.Supports (protocol.Trim ())) + if (!ctx.Supports (protocol)) throw new NotSupportedException ("The specified cryptography context does not support the signature protocol."); if (Count < 2) @@ -501,6 +502,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = // Note: see rfc2015 or rfc3156, section 5.1 var options = FormatOptions.CloneDefault (); options.NewLineFormat = NewLineFormat.Dos; + options.VerifyingSignature = true; await this[0].WriteToAsync (options, cleartext, cancellationToken); cleartext.Position = 0; @@ -534,12 +536,11 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = /// public DigitalSignatureCollection Verify (CancellationToken cancellationToken = default (CancellationToken)) { - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); + if (string.IsNullOrEmpty (protocol)) throw new FormatException ("The multipart/signed part did not specify a protocol."); - protocol = protocol.Trim ().ToLowerInvariant (); - using (var ctx = CryptographyContext.Create (protocol)) return Verify (ctx, cancellationToken); } @@ -568,12 +569,11 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = /// public Task VerifyAsync (CancellationToken cancellationToken = default (CancellationToken)) { - var protocol = ContentType.Parameters["protocol"]; + var protocol = ContentType.Parameters["protocol"]?.Trim (); + if (string.IsNullOrEmpty (protocol)) throw new FormatException ("The multipart/signed part did not specify a protocol."); - protocol = protocol.Trim ().ToLowerInvariant (); - using (var ctx = CryptographyContext.Create (protocol)) return VerifyAsync (ctx, cancellationToken); } diff --git a/MimeKit/Cryptography/NpgsqlCertificateDatabase.cs b/MimeKit/Cryptography/NpgsqlCertificateDatabase.cs index c2d7fb98f0..1bee953df6 100644 --- a/MimeKit/Cryptography/NpgsqlCertificateDatabase.cs +++ b/MimeKit/Cryptography/NpgsqlCertificateDatabase.cs @@ -3,7 +3,7 @@ // // Author: Federico Di Gregorio // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2019 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ using System.Text; using System.Reflection; using System.Data.Common; +using System.Collections.Generic; namespace MimeKit.Cryptography { /// @@ -115,89 +116,149 @@ public NpgsqlCertificateDatabase (DbConnection connection, string password) : ba } /// - /// Gets the command to create the certificates table. + /// Gets the columns for the specified table. /// /// - /// Constructs the command to create a certificates table suitable for storing - /// objects. + /// Gets the list of columns for the specified table. /// - /// The . /// The . - protected override DbCommand GetCreateCertificatesTableCommand (DbConnection connection) + /// The name of the table. + /// The list of columns. + protected override IList GetTableColumns (DbConnection connection, string tableName) { - var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS CERTIFICATES("); - var columns = X509CertificateRecord.ColumnNames; - - for (int i = 0; i < columns.Length; i++) { - if (i > 0) - statement.Append (", "); - - statement.Append (columns[i]).Append (' '); - switch (columns[i]) { - case "ID": statement.Append ("serial PRIMARY KEY"); break; - case "BASICCONSTRAINTS": statement.Append ("integer NOT NULL"); break; - case "TRUSTED": statement.Append ("boolean NOT NULL"); break; - case "KEYUSAGE": statement.Append ("integer NOT NULL"); break; - case "NOTBEFORE": statement.Append ("timestamp NOT NULL"); break; - case "NOTAFTER": statement.Append ("timestamp NOT NULL"); break; - case "ISSUERNAME": statement.Append ("text NOT NULL"); break; - case "SERIALNUMBER": statement.Append ("text NOT NULL"); break; - case "SUBJECTEMAIL": statement.Append ("text "); break; - case "FINGERPRINT": statement.Append ("text NOT NULL"); break; - case "ALGORITHMS": statement.Append ("text"); break; - case "ALGORITHMSUPDATED": statement.Append ("timestamp NOT NULL"); break; - case "CERTIFICATE": statement.Append ("bytea UNIQUE NOT NULL"); break; - case "PRIVATEKEY": statement.Append ("bytea"); break; + using (var command = connection.CreateCommand ()) { + command.CommandText = $"PRAGMA table_info({tableName})"; + using (var reader = command.ExecuteReader ()) { + var columns = new List (); + + while (reader.Read ()) { + var column = new DataColumn (); + + for (int i = 0; i < reader.FieldCount; i++) { + var field = reader.GetName (i).ToUpperInvariant (); + + switch (field) { + case "NAME": + column.ColumnName = reader.GetString (i); + break; + case "TYPE": + var type = reader.GetString (i); + switch (type) { + case "boolean": column.DataType = typeof (bool); break; + case "integer": column.DataType = typeof (long); break; + case "bytea": column.DataType = typeof (byte[]); break; + case "text": column.DataType = typeof (string); break; + } + break; + case "NOTNULL": + column.AllowDBNull = !reader.GetBoolean (i); + break; + } + } + + columns.Add (column); + } + + return columns; } } + } - statement.Append (')'); + static void Build (StringBuilder statement, DataTable table, DataColumn column, ref int primaryKeys) + { + statement.Append (column.ColumnName); + statement.Append (' '); + + if (column.DataType == typeof (long) || column.DataType == typeof (int)) { + if (column.AutoIncrement) + statement.Append ("serial"); + else + statement.Append ("integer"); + } else if (column.DataType == typeof (bool)) { + statement.Append ("boolean"); + } else if (column.DataType == typeof (byte[])) { + statement.Append ("bytea"); + } else if (column.DataType == typeof (string)) { + statement.Append ("text"); + } else { + throw new NotImplementedException (); + } - var command = connection.CreateCommand (); + bool isPrimaryKey = false; + if (table != null && table.PrimaryKey != null && primaryKeys < table.PrimaryKey.Length) { + for (int i = 0; i < table.PrimaryKey.Length; i++) { + if (column == table.PrimaryKey[i]) { + statement.Append (" PRIMARY KEY"); + isPrimaryKey = true; + primaryKeys++; + break; + } + } + } - command.CommandText = statement.ToString (); - command.CommandType = CommandType.Text; + if (column.Unique && !isPrimaryKey) + statement.Append (" UNIQUE"); - return command; + if (!column.AllowDBNull) + statement.Append (" NOT NULL"); } /// - /// Gets the command to create the CRLs table. + /// Create a table. /// /// - /// Constructs the command to create a CRLs table suitable for storing - /// objects. + /// Creates the specified table. /// - /// The . /// The . - protected override DbCommand GetCreateCrlsTableCommand (DbConnection connection) + /// The table. + protected override void CreateTable (DbConnection connection, DataTable table) { - var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS CRLS("); - var columns = X509CrlRecord.ColumnNames; - - for (int i = 0; i < columns.Length; i++) { - if (i > 0) - statement.Append (", "); - - statement.Append (columns[i]).Append (' '); - switch (columns[i]) { - case "ID": statement.Append ("serial PRIMARY KEY"); break; - case "DELTA" : statement.Append ("integer NOT NULL"); break; - case "ISSUERNAME": statement.Append ("text NOT NULL"); break; - case "THISUPDATE": statement.Append ("integer NOT NULL"); break; - case "NEXTUPDATE": statement.Append ("integer NOT NULL"); break; - case "CRL": statement.Append ("bytea NOT NULL"); break; - } + var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS "); + int primaryKeys = 0; + + statement.Append (table.TableName); + statement.Append ('('); + + foreach (DataColumn column in table.Columns) { + Build (statement, table, column, ref primaryKeys); + statement.Append (", "); } + if (table.Columns.Count > 0) + statement.Length -= 2; + statement.Append (')'); - var command = connection.CreateCommand (); + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } + } - command.CommandText = statement.ToString (); - command.CommandType = CommandType.Text; + /// + /// Adds a column to a table. + /// + /// + /// Adds a column to a table. + /// + /// The . + /// The table. + /// The column to add. + protected override void AddTableColumn (DbConnection connection, DataTable table, DataColumn column) + { + var statement = new StringBuilder ("ALTER TABLE "); + int primaryKeys = table.PrimaryKey?.Length ?? 0; + + statement.Append (table.TableName); + statement.Append (" ADD COLUMN "); + Build (statement, table, column, ref primaryKeys); - return command; + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } } } } diff --git a/MimeKit/Cryptography/OpenPgpBlockFilter.cs b/MimeKit/Cryptography/OpenPgpBlockFilter.cs index 33c21a7d6b..d5c109b42d 100644 --- a/MimeKit/Cryptography/OpenPgpBlockFilter.cs +++ b/MimeKit/Cryptography/OpenPgpBlockFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ class OpenPgpBlockFilter : MimeFilterBase bool midline; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Cryptography/OpenPgpContext.cs b/MimeKit/Cryptography/OpenPgpContext.cs index cdc3348fe3..37c504d5ef 100644 --- a/MimeKit/Cryptography/OpenPgpContext.cs +++ b/MimeKit/Cryptography/OpenPgpContext.cs @@ -1,9 +1,9 @@ -// +// // OpenPgpContext.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,7 @@ using System; using System.IO; -using System.Net; using System.Linq; -using System.Text; -using System.Net.Http; using System.Threading; using System.Diagnostics; using System.Threading.Tasks; @@ -39,6 +36,7 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Crypto.Parameters; @@ -47,112 +45,32 @@ namespace MimeKit.Cryptography { /// - /// An abstract OpenPGP cryptography context which can be used for PGP/MIME. + /// An abstract OpenPGP cryptography context which can be used for OpenPGP and PGP/MIME that + /// manages keyrings stored on the local file system as keyring bundles. /// /// - /// Generally speaking, applications should not use a + /// PGP software such as older versions of GnuPG (pre 2.1.0) typically store the user's + /// keyrings on the file system using the OpenPGP Keyring Bundle format. + /// Generally speaking, applications should not use a /// directly, but rather via higher level APIs such as - /// and . + /// and . /// - public abstract class OpenPgpContext : CryptographyContext + public abstract class OpenPgpContext : OpenPgpContextBase { - const string BeginPublicKeyBlock = "-----BEGIN PGP PUBLIC KEY BLOCK-----"; - const string EndPublicKeyBlock = "-----END PGP PUBLIC KEY BLOCK-----"; - - internal static readonly EncryptionAlgorithm[] DefaultEncryptionAlgorithmRank = { - EncryptionAlgorithm.Idea, - EncryptionAlgorithm.TripleDes, - EncryptionAlgorithm.Cast5, - EncryptionAlgorithm.Blowfish, - EncryptionAlgorithm.Aes128, - EncryptionAlgorithm.Aes192, - EncryptionAlgorithm.Aes256, - EncryptionAlgorithm.Twofish, - EncryptionAlgorithm.Camellia128, - EncryptionAlgorithm.Camellia192, - EncryptionAlgorithm.Camellia256 - }; - - internal static readonly DigestAlgorithm[] DefaultDigestAlgorithmRank = { - DigestAlgorithm.Sha1, - DigestAlgorithm.RipeMD160, - DigestAlgorithm.Sha256, - DigestAlgorithm.Sha384, - DigestAlgorithm.Sha512, - DigestAlgorithm.Sha224 - }; - - EncryptionAlgorithm defaultAlgorithm; - HttpClient client; - Uri keyServer; - /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Subclasses choosing to use this constructor MUST set the , /// , , and the /// properties themselves. /// - protected OpenPgpContext () + protected OpenPgpContext () : base () { - EncryptionAlgorithmRank = DefaultEncryptionAlgorithmRank; - DigestAlgorithmRank = DefaultDigestAlgorithmRank; - - foreach (var algorithm in EncryptionAlgorithmRank) - Enable (algorithm); - - foreach (var algorithm in DigestAlgorithmRank) - Enable (algorithm); - - defaultAlgorithm = EncryptionAlgorithm.Cast5; - - client = new HttpClient (); } -#if PORTABLE - /// - /// Initializes a new instance of the class. - /// - /// - /// Creates a new using the specified public and private keyrings. - /// - /// The public keyring. - /// The secret keyring. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// An error occurred while reading one of the keyring files. - /// - /// - /// An error occurred while parsing one of the keyring files. - /// - protected OpenPgpContext (Stream pubring, Stream secring) : this () - { - if (pubring == null) - throw new ArgumentNullException ("pubring"); - - if (secring == null) - throw new ArgumentNullException ("secring"); - - PublicKeyRing = pubring; - SecretKeyRing = secring; - - PublicKeyRingBundle = new PgpPublicKeyRingBundle (pubring); - SecretKeyRingBundle = new PgpSecretKeyRingBundle (secring); - - if (pubring.CanSeek) - pubring.Seek (0, SeekOrigin.Begin); - - if (secring.CanSeek) - secring.Seek (0, SeekOrigin.Begin); - } -#else /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new using the specified public and private keyring paths. @@ -182,7 +100,7 @@ protected OpenPgpContext (string pubring, string secring) : this () SecretKeyRingPath = secring; if (File.Exists (pubring)) { - using (var file = File.Open (pubring, FileMode.Open, FileAccess.Read)) { + using (var file = File.OpenRead (pubring)) { PublicKeyRingBundle = new PgpPublicKeyRingBundle (file); } } else { @@ -190,103 +108,14 @@ protected OpenPgpContext (string pubring, string secring) : this () } if (File.Exists (secring)) { - using (var file = File.Open (secring, FileMode.Open, FileAccess.Read)) { + using (var file = File.OpenRead (secring)) { SecretKeyRingBundle = new PgpSecretKeyRingBundle (file); } } else { SecretKeyRingBundle = new PgpSecretKeyRingBundle (new byte[0]); } } -#endif - - /// - /// Get or set the default encryption algorithm. - /// - /// - /// Gets or sets the default encryption algorithm. - /// - /// The encryption algorithm. - /// - /// The specified encryption algorithm is not supported. - /// - public EncryptionAlgorithm DefaultEncryptionAlgorithm { - get { return defaultAlgorithm; } - set { - GetSymmetricKeyAlgorithm (value); - defaultAlgorithm = value; - } - } - - bool IsValidKeyServer { - get { - if (keyServer == null) - return false; - - switch (keyServer.Scheme.ToLowerInvariant ()) { - case "https": case "http": case "hkp": return true; - default: return false; - } - } - } - - /// - /// Get or set the key server to use when automatically retrieving keys. - /// - /// - /// Gets or sets the key server to use when verifying keys that are - /// not already in the public keychain. - /// Only HTTP and HKP protocols are supported. - /// - /// The key server. - /// - /// is not an absolute URI. - /// - public Uri KeyServer { - get { return keyServer; } - set { - if (value != null && !value.IsAbsoluteUri) - throw new ArgumentException ("The key server URI must be absolute.", nameof (value)); - - keyServer = value; - } - } - - /// - /// Get or set whether unknown PGP keys should automtically be retrieved. - /// - /// - /// Gets or sets whether or not the should automatically - /// fetch keys as needed from the keyserver when verifying signatures. - /// Requires a valid to be set. - /// - /// true if unknown PGP keys should automatically be retrieved; otherwise, false. - public bool AutoKeyRetrieve { - get; set; - } - -#if PORTABLE - /// - /// Get the public keyring. - /// - /// - /// Gets the public keyring. - /// - /// The public key ring. - protected Stream PublicKeyRing { - get; set; - } - /// - /// Get the secret keyring. - /// - /// - /// Gets the secret keyring. - /// - /// The secret key ring. - protected Stream SecretKeyRing { - get; set; - } -#else /// /// Get the public keyring path. /// @@ -308,7 +137,6 @@ protected string PublicKeyRingPath { protected string SecretKeyRingPath { get; set; } -#endif /// /// Get the public keyring bundle. @@ -332,271 +160,74 @@ public PgpSecretKeyRingBundle SecretKeyRingBundle { get; protected set; } - /// - /// Get the signature protocol. - /// - /// - /// The signature protocol is used by - /// in order to determine what the protocol parameter of the Content-Type - /// header should be. - /// - /// The signature protocol. - public override string SignatureProtocol { - get { return "application/pgp-signature"; } - } + bool TryGetPublicKeyRing (long keyId, out PgpPublicKeyRing keyring) + { + foreach (PgpPublicKeyRing ring in PublicKeyRingBundle.GetKeyRings ()) { + foreach (PgpPublicKey key in ring.GetPublicKeys ()) { + if (key.KeyId == keyId) { + keyring = ring; + return true; + } + } + } - /// - /// Get the encryption protocol. - /// - /// - /// The encryption protocol is used by - /// in order to determine what the protocol parameter of the Content-Type - /// header should be. - /// - /// The encryption protocol. - public override string EncryptionProtocol { - get { return "application/pgp-encrypted"; } - } + keyring = null; - /// - /// Get the key exchange protocol. - /// - /// - /// Gets the key exchange protocol. - /// - /// The key exchange protocol. - public override string KeyExchangeProtocol { - get { return "application/pgp-keys"; } + return false; } /// - /// Check whether or not the specified protocol is supported. + /// Get the public keyring that contains the specified key. /// /// - /// Used in order to make sure that the protocol parameter value specified in either a multipart/signed - /// or multipart/encrypted part is supported by the supplied cryptography context. + /// Gets the public keyring that contains the specified key. + /// Implementations should first try to obtain the keyring stored (or cached) locally. + /// Failing that, if is enabled, they should use + /// to attempt to + /// retrieve the keyring from the configured . /// - /// true if the protocol is supported; otherwise false - /// The protocol. - /// - /// is null. + /// The public key identifier. + /// The cancellation token. + /// The public keyring that contains the specified key or null if the keyring could not be found. + /// + /// The operation was cancelled. /// - public override bool Supports (string protocol) + protected override PgpPublicKeyRing GetPublicKeyRing (long keyId, CancellationToken cancellationToken) { - if (protocol == null) - throw new ArgumentNullException (nameof (protocol)); - - var type = protocol.ToLowerInvariant ().Split ('/'); - if (type.Length != 2 || type[0] != "application") - return false; + if (TryGetPublicKeyRing (keyId, out var keyring)) + return keyring; - if (type[1].StartsWith ("x-", StringComparison.Ordinal)) - type[1] = type[1].Substring (2); - - return type[1] == "pgp-signature" || type[1] == "pgp-encrypted" || type[1] == "pgp-keys"; - } + if (AutoKeyRetrieve) + return RetrievePublicKeyRing (keyId, cancellationToken); - /// - /// Get the string name of the digest algorithm for use with the micalg parameter of a multipart/signed part. - /// - /// - /// Maps the to the appropriate string identifier - /// as used by the micalg parameter value of a multipart/signed Content-Type - /// header. For example: - /// - /// AlgorithmName - /// pgp-md5 - /// pgp-sha1 - /// pgp-ripemd160 - /// pgp-md2 - /// pgp-tiger192 - /// pgp-haval-5-160 - /// pgp-sha256 - /// pgp-sha384 - /// pgp-sha512 - /// pgp-sha224 - /// - /// - /// The micalg value. - /// The digest algorithm. - /// - /// is out of range. - /// - public override string GetDigestAlgorithmName (DigestAlgorithm micalg) - { - switch (micalg) { - case DigestAlgorithm.MD5: return "pgp-md5"; - case DigestAlgorithm.Sha1: return "pgp-sha1"; - case DigestAlgorithm.RipeMD160: return "pgp-ripemd160"; - case DigestAlgorithm.MD2: return "pgp-md2"; - case DigestAlgorithm.Tiger192: return "pgp-tiger192"; - case DigestAlgorithm.Haval5160: return "pgp-haval-5-160"; - case DigestAlgorithm.Sha256: return "pgp-sha256"; - case DigestAlgorithm.Sha384: return "pgp-sha384"; - case DigestAlgorithm.Sha512: return "pgp-sha512"; - case DigestAlgorithm.Sha224: return "pgp-sha224"; - case DigestAlgorithm.MD4: return "pgp-md4"; - default: throw new ArgumentOutOfRangeException (nameof (micalg)); - } + return null; } /// - /// Get the digest algorithm from the micalg parameter value in a multipart/signed part. + /// Asynchronously get the public keyring that contains the specified key. /// /// - /// Maps the micalg parameter value string back to the appropriate . + /// Gets the public keyring that contains the specified key. + /// Implementations should first try to obtain the keyring stored (or cached) locally. + /// Failing that, if is enabled, they should use + /// to attempt to + /// retrieve the keyring from the configured . /// - /// The digest algorithm. - /// The micalg parameter value. - /// - /// is null. + /// The public key identifier. + /// The cancellation token. + /// The public keyring that contains the specified key or null if the keyring could not be found. + /// + /// The operation was cancelled. /// - public override DigestAlgorithm GetDigestAlgorithm (string micalg) - { - if (micalg == null) - throw new ArgumentNullException (nameof (micalg)); - - switch (micalg.ToLowerInvariant ()) { - case "pgp-md5": return DigestAlgorithm.MD5; - case "pgp-sha1": return DigestAlgorithm.Sha1; - case "pgp-ripemd160": return DigestAlgorithm.RipeMD160; - case "pgp-md2": return DigestAlgorithm.MD2; - case "pgp-tiger192": return DigestAlgorithm.Tiger192; - case "pgp-haval-5-160": return DigestAlgorithm.Haval5160; - case "pgp-sha256": return DigestAlgorithm.Sha256; - case "pgp-sha384": return DigestAlgorithm.Sha384; - case "pgp-sha512": return DigestAlgorithm.Sha512; - case "pgp-sha224": return DigestAlgorithm.Sha224; - case "pgp-md4": return DigestAlgorithm.MD4; - default: return DigestAlgorithm.None; - } - } - - static string HexEncode (byte[] data) - { - var fingerprint = new StringBuilder (); - - for (int i = 0; i < data.Length; i++) - fingerprint.Append (data[i].ToString ("x2")); - - return fingerprint.ToString (); - } - - static bool PgpPublicKeyMatches (PgpPublicKey key, MailboxAddress mailbox) - { - var secure = mailbox as SecureMailboxAddress; - - if (secure != null && !string.IsNullOrEmpty (secure.Fingerprint)) { - if (secure.Fingerprint.Length > 16) { - var fingerprint = HexEncode (key.GetFingerprint ()); - - return secure.Fingerprint.Equals (fingerprint, StringComparison.OrdinalIgnoreCase); - } - - var id = ((int) key.KeyId).ToString ("X2"); - - return secure.Fingerprint.EndsWith (id, StringComparison.OrdinalIgnoreCase); - } - - foreach (string userId in key.GetUserIds ()) { - MailboxAddress email; - - if (!MailboxAddress.TryParse (userId, out email)) - continue; - - if (mailbox.Address.Equals (email.Address, StringComparison.OrdinalIgnoreCase)) - return true; - } - - return false; - } - - async Task RetrievePublicKeyRingAsync (long keyId, bool doAsync, CancellationToken cancellationToken) - { - var scheme = keyServer.Scheme.ToLowerInvariant (); - var uri = new UriBuilder (); - - uri.Scheme = scheme == "hkp" ? "http" : scheme; - uri.Host = keyServer.Host; - - if (keyServer.IsDefaultPort) { - if (scheme == "hkp") - uri.Port = 11371; - } else { - uri.Port = keyServer.Port; - } - - uri.Path = "/pks/lookup"; - uri.Query = string.Format ("op=get&search=0x{0:X}", keyId); - - using (var stream = new MemoryBlockStream ()) { - using (var filtered = new FilteredStream (stream)) { - filtered.Add (new OpenPgpBlockFilter (BeginPublicKeyBlock, EndPublicKeyBlock)); - - if (doAsync) { - using (var response = await client.GetAsync (uri.ToString (), cancellationToken)) - await response.Content.CopyToAsync (filtered); - } else { -#if !NETSTANDARD && !PORTABLE - var request = (HttpWebRequest) WebRequest.Create (uri.ToString ()); - using (var response = request.GetResponse ()) { - var content = response.GetResponseStream (); - content.CopyTo (filtered, 4096); - } -#else - using (var response = client.GetAsync (uri.ToString (), cancellationToken).GetAwaiter ().GetResult ()) - response.Content.CopyToAsync (filtered).GetAwaiter ().GetResult (); -#endif - } - - filtered.Flush (); - } - - stream.Position = 0; - - using (var armored = new ArmoredInputStream (stream, true)) { - var bundle = new PgpPublicKeyRingBundle (armored); - - Import (bundle); - - return bundle.GetPublicKeyRing (keyId); - } - } - } - - class KeyRetrievalResults - { - public readonly PgpPublicKeyRing KeyRing; - public readonly PgpPublicKey Key; - - public KeyRetrievalResults (PgpPublicKeyRing keyring, PgpPublicKey pubkey) - { - KeyRing = keyring; - Key = pubkey; - } - } - - async Task GetPublicKeyRingAsync (long keyId, bool doAsync, CancellationToken cancellationToken) + protected override async Task GetPublicKeyRingAsync (long keyId, CancellationToken cancellationToken) { - foreach (PgpPublicKeyRing ring in PublicKeyRingBundle.GetKeyRings ()) { - foreach (PgpPublicKey key in ring.GetPublicKeys ()) { - if (key.KeyId == keyId) - return new KeyRetrievalResults (ring, key); - } - } - - if (AutoKeyRetrieve && IsValidKeyServer) { - try { - var keyring = await RetrievePublicKeyRingAsync (keyId, doAsync, cancellationToken).ConfigureAwait (false); + if (TryGetPublicKeyRing (keyId, out var keyring)) + return keyring; - return new KeyRetrievalResults (keyring, keyring.GetPublicKey (keyId)); - } catch (OperationCanceledException) { - throw; - } catch { - } - } + if (AutoKeyRetrieve) + return await RetrievePublicKeyRingAsync (keyId, cancellationToken).ConfigureAwait (false); - return new KeyRetrievalResults (null, null); + return null; } /// @@ -606,7 +237,7 @@ async Task GetPublicKeyRingAsync (long keyId, bool doAsync, /// Enumerates all public keyrings. /// /// The list of available public keyrings. - public IEnumerable EnumeratePublicKeyRings () + public virtual IEnumerable EnumeratePublicKeyRings () { foreach (PgpPublicKeyRing keyring in PublicKeyRingBundle.GetKeyRings ()) yield return keyring; @@ -621,7 +252,7 @@ public IEnumerable EnumeratePublicKeyRings () /// Enumerates all public keys. /// /// The list of available public keys. - public IEnumerable EnumeratePublicKeys () + public virtual IEnumerable EnumeratePublicKeys () { foreach (var keyring in EnumeratePublicKeyRings ()) { foreach (PgpPublicKey key in keyring.GetPublicKeys ()) @@ -642,13 +273,13 @@ public IEnumerable EnumeratePublicKeys () /// /// is null. /// - public IEnumerable EnumeratePublicKeyRings (MailboxAddress mailbox) + public virtual IEnumerable EnumeratePublicKeyRings (MailboxAddress mailbox) { if (mailbox == null) throw new ArgumentNullException (nameof (mailbox)); foreach (var keyring in EnumeratePublicKeyRings ()) { - if (PgpPublicKeyMatches (keyring.GetPublicKey (), mailbox)) + if (IsMatch (keyring.GetPublicKey (), mailbox)) yield return keyring; } @@ -666,7 +297,7 @@ public IEnumerable EnumeratePublicKeyRings (MailboxAddress mai /// /// is null. /// - public IEnumerable EnumeratePublicKeys (MailboxAddress mailbox) + public virtual IEnumerable EnumeratePublicKeys (MailboxAddress mailbox) { foreach (var keyring in EnumeratePublicKeyRings (mailbox)) { foreach (PgpPublicKey key in keyring.GetPublicKeys ()) @@ -683,7 +314,7 @@ public IEnumerable EnumeratePublicKeys (MailboxAddress mailbox) /// Enumerates all secret keyrings. /// /// The list of available secret keyrings. - public IEnumerable EnumerateSecretKeyRings () + public virtual IEnumerable EnumerateSecretKeyRings () { foreach (PgpSecretKeyRing keyring in SecretKeyRingBundle.GetKeyRings ()) yield return keyring; @@ -698,7 +329,7 @@ public IEnumerable EnumerateSecretKeyRings () /// Enumerates all secret keys. /// /// The list of available secret keys. - public IEnumerable EnumerateSecretKeys () + public virtual IEnumerable EnumerateSecretKeys () { foreach (var keyring in EnumerateSecretKeyRings ()) { foreach (PgpSecretKey key in keyring.GetSecretKeys ()) @@ -719,13 +350,13 @@ public IEnumerable EnumerateSecretKeys () /// /// is null. /// - public IEnumerable EnumerateSecretKeyRings (MailboxAddress mailbox) + public virtual IEnumerable EnumerateSecretKeyRings (MailboxAddress mailbox) { if (mailbox == null) throw new ArgumentNullException (nameof (mailbox)); foreach (var keyring in EnumerateSecretKeyRings ()) { - if (PgpSecretKeyMatches (keyring.GetSecretKey (), mailbox)) + if (IsMatch (keyring.GetSecretKey (), mailbox)) yield return keyring; } @@ -743,7 +374,7 @@ public IEnumerable EnumerateSecretKeyRings (MailboxAddress mai /// /// is null. /// - public IEnumerable EnumerateSecretKeys (MailboxAddress mailbox) + public virtual IEnumerable EnumerateSecretKeys (MailboxAddress mailbox) { foreach (var keyring in EnumerateSecretKeyRings (mailbox)) { foreach (PgpSecretKey key in keyring.GetSecretKeys ()) @@ -770,16 +401,9 @@ public IEnumerable EnumerateSecretKeys (MailboxAddress mailbox) protected virtual PgpPublicKey GetPublicKey (MailboxAddress mailbox) { foreach (var key in EnumeratePublicKeys (mailbox)) { - if (!key.IsEncryptionKey || key.IsRevoked ()) + if (!key.IsEncryptionKey || key.IsRevoked () || IsExpired (key)) continue; - long seconds = key.GetValidSeconds (); - if (seconds != 0) { - var expires = key.CreationTime.AddSeconds ((double) seconds); - if (expires <= DateTime.Now) - continue; - } - return key; } @@ -800,46 +424,38 @@ protected virtual PgpPublicKey GetPublicKey (MailboxAddress mailbox) /// /// A public key for one or more of the could not be found. /// - internal protected virtual IList GetPublicKeys (IEnumerable mailboxes) + public override IList GetPublicKeys (IEnumerable mailboxes) { if (mailboxes == null) throw new ArgumentNullException (nameof (mailboxes)); - var recipients = new List (); + var keys = new List (); foreach (var mailbox in mailboxes) - recipients.Add (GetPublicKey (mailbox)); + keys.Add (GetPublicKey (mailbox)); - return recipients; + return keys; } - static bool PgpSecretKeyMatches (PgpSecretKey key, MailboxAddress mailbox) + /// + /// Get the secret key for a specified key identifier. + /// + /// + /// Gets the secret key for a specified key identifier. + /// + /// The key identifier for the desired secret key. + /// The secret key. + /// + /// The secret key specified by the could not be found. + /// + protected override PgpSecretKey GetSecretKey (long keyId) { - var secure = mailbox as SecureMailboxAddress; - - if (secure != null && !string.IsNullOrEmpty (secure.Fingerprint)) { - if (secure.Fingerprint.Length > 16) { - var fingerprint = HexEncode (key.PublicKey.GetFingerprint ()); - - return secure.Fingerprint.Equals (fingerprint, StringComparison.OrdinalIgnoreCase); - } - - var id = ((int) key.KeyId).ToString ("X2"); - - return secure.Fingerprint.EndsWith (id, StringComparison.OrdinalIgnoreCase); - } - - foreach (string userId in key.UserIds) { - MailboxAddress email; - - if (!MailboxAddress.TryParse (userId, out email)) - continue; - - if (mailbox.Address.Equals (email.Address, StringComparison.OrdinalIgnoreCase)) - return true; + foreach (var key in EnumerateSecretKeys ()) { + if (key.KeyId == keyId) + return key; } - return false; + throw new PrivateKeyNotFoundException (keyId, "The secret key could not be found."); } /// @@ -854,32 +470,22 @@ static bool PgpSecretKeyMatches (PgpSecretKey key, MailboxAddress mailbox) /// is null. /// /// - /// A private key for the specified could not be found. + /// A secret key for the specified could not be found. /// - internal protected virtual PgpSecretKey GetSigningKey (MailboxAddress mailbox) + public override PgpSecretKey GetSigningKey (MailboxAddress mailbox) { if (mailbox == null) throw new ArgumentNullException (nameof (mailbox)); - foreach (PgpSecretKeyRing keyring in SecretKeyRingBundle.GetKeyRings ()) { + foreach (var keyring in EnumerateSecretKeyRings (mailbox)) { foreach (PgpSecretKey key in keyring.GetSecretKeys ()) { - if (!PgpSecretKeyMatches (keyring.GetSecretKey (), mailbox)) - continue; - if (!key.IsSigningKey) continue; var pubkey = key.PublicKey; - if (pubkey.IsRevoked ()) + if (pubkey.IsRevoked () || IsExpired (pubkey)) continue; - long seconds = pubkey.GetValidSeconds (); - if (seconds != 0) { - var expires = pubkey.CreationTime.AddSeconds ((double) seconds); - if (expires <= DateTime.Now) - continue; - } - return key; } } @@ -888,77 +494,59 @@ internal protected virtual PgpSecretKey GetSigningKey (MailboxAddress mailbox) } /// - /// Gets the password for key. + /// Check whether or not a particular mailbox address can be used for signing. /// /// - /// Gets the password for key. + /// Checks whether or not as particular mailbocx address can be used for signing. /// - /// The password for key. - /// The key. - /// - /// The user chose to cancel the password request. + /// true if the mailbox address can be used for signing; otherwise, false. + /// The signer. + /// + /// is null. /// - protected abstract string GetPasswordForKey (PgpSecretKey key); + public override bool CanSign (MailboxAddress signer) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + foreach (var key in EnumerateSecretKeys (signer)) { + if (!key.IsSigningKey) + continue; + + var pubkey = key.PublicKey; + if (pubkey.IsRevoked () || IsExpired (pubkey)) + continue; + + return true; + } + + return false; + } /// - /// Gets the private key from the specified secret key. + /// Check whether or not the cryptography context can encrypt to a particular recipient. /// /// - /// Gets the private key from the specified secret key. + /// Checks whether or not the cryptography context can be used to encrypt to a particular recipient. /// - /// The private key. - /// The secret key. + /// true if the cryptography context can be used to encrypt to the designated recipient; otherwise, false. + /// The recipient's mailbox address. /// - /// is null. - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. + /// is null. /// - protected PgpPrivateKey GetPrivateKey (PgpSecretKey key) + public override bool CanEncrypt (MailboxAddress mailbox) { - int attempts = 0; - string password; - - if (key == null) - throw new ArgumentNullException (nameof (key)); - - do { - if ((password = GetPasswordForKey (key)) == null) - throw new OperationCanceledException (); - - try { - var privateKey = key.ExtractPrivateKey (password.ToCharArray ()); - - // Note: the private key will be null if the private key is empty. - if (privateKey == null) - break; - - return privateKey; - } catch (Exception ex) { -#if DEBUG - Debug.WriteLine (string.Format ("Failed to extract secret key: {0}", ex)); -#endif - } - - attempts++; - } while (attempts < 3); + if (mailbox == null) + throw new ArgumentNullException (nameof (mailbox)); - throw new UnauthorizedAccessException (); - } + foreach (var key in EnumeratePublicKeys (mailbox)) { + if (!key.IsEncryptionKey || key.IsRevoked () || IsExpired (key)) + continue; - PgpSecretKey GetSecretKey (long keyId) - { - foreach (PgpSecretKeyRing keyring in SecretKeyRingBundle.GetKeyRings ()) { - foreach (PgpSecretKey key in keyring.GetSecretKeys ()) { - if (key.KeyId == keyId) - return key; - } + return true; } - throw new PrivateKeyNotFoundException (keyId, "The private key could not be found."); + return false; } #if false @@ -1025,7 +613,7 @@ void AddEncryptionKeyPair (PgpKeyRingGenerator keyRingGenerator, KeyGenerationPa keyRingGenerator.AddSubKey (keyPair, subpacketGenerator.Generate (), null); } - PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAlgorithm algorithm, long expirationTime, string password, DateTime now) + PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAlgorithm algorithm, long expirationTime, string password, DateTime now, SecureRandom random) { var enabledEncryptionAlgorithms = EnabledEncryptionAlgorithms; var enabledDigestAlgorithms = EnabledDigestAlgorithms; @@ -1037,7 +625,7 @@ PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAl for (int i = 0; i < enabledDigestAlgorithms.Length; i++) digestAlgorithms[i] = (int) enabledDigestAlgorithms[i]; - var parameters = new RsaKeyGenerationParameters (BigInteger.ValueOf (0x10001), new SecureRandom (), 2048, 12); + var parameters = new RsaKeyGenerationParameters (BigInteger.ValueOf (0x10001), random, 2048, 12); var signingAlgorithm = PublicKeyAlgorithmTag.RsaSign; var keyPairGenerator = GeneratorUtilities.GetKeyPairGenerator ("RSA"); @@ -1067,7 +655,7 @@ PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAl true, subpacketGenerator.Generate (), null, - new SecureRandom ()); + random); // Add the (optional) encryption subkey. AddEncryptionKeyPair (keyRingGenerator, parameters, PublicKeyAlgorithmTag.RsaGeneral, now, expirationTime, encryptionAlgorithms, digestAlgorithms); @@ -1085,6 +673,7 @@ PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAl /// The password to be set on the secret key. /// The expiration date for the generated key pair. /// The symmetric key algorithm to use. + /// The source of randomness to use when generating the key pair. /// /// is null. /// -or- @@ -1093,7 +682,7 @@ PgpKeyRingGenerator CreateKeyRingGenerator (MailboxAddress mailbox, EncryptionAl /// /// is not a date in the future. /// - public void GenerateKeyPair (MailboxAddress mailbox, string password, DateTime? expirationDate = null, EncryptionAlgorithm algorithm = EncryptionAlgorithm.Aes256) + public void GenerateKeyPair (MailboxAddress mailbox, string password, DateTime? expirationDate = null, EncryptionAlgorithm algorithm = EncryptionAlgorithm.Aes256, SecureRandom random = null) { var now = DateTime.UtcNow; long expirationTime = 0; @@ -1108,13 +697,21 @@ public void GenerateKeyPair (MailboxAddress mailbox, string password, DateTime? var utc = expirationDate.Value.ToUniversalTime (); if (utc <= now) - throw new ArgumentException ("expirationDate needs to be greater than DateTime.Now"); + throw new ArgumentException ("expirationDate needs to be greater than DateTime.Now", nameof (expirationDate)); if ((expirationTime = Convert.ToInt64 (utc.Subtract (now).TotalSeconds)) <= 0) - throw new ArgumentException ("expirationDate needs to be greater than DateTime.Now"); + throw new ArgumentException ("expirationDate needs to be greater than DateTime.Now", nameof (expirationDate)); + } + + if (random == null) { +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 + random = new SecureRandom (new CryptoApiRandomGenerator ()); +#else + random = new SecureRandom (); +#endif } - var generator = CreateKeyRingGenerator (mailbox, algorithm, expirationTime, password, now); + var generator = CreateKeyRingGenerator (mailbox, algorithm, expirationTime, password, now, random); Import (generator.GenerateSecretKeyRing ()); Import (generator.GeneratePublicKeyRing ()); @@ -1173,1222 +770,11 @@ public void SignKey (PgpSecretKey secretKey, PgpPublicKey publicKey, DigestAlgor if (keyring == null) keyring = new PgpPublicKeyRing (signedKey.GetEncoded ()); - PublicKeyRingBundle = PgpPublicKeyRingBundle.AddPublicKeyRing (PublicKeyRingBundle, keyring); - SavePublicKeyRingBundle (); + Import (keyring); } /// - /// Gets the equivalent for the - /// specified . - /// - /// - /// Maps a to the equivalent . - /// - /// The hash algorithm. - /// The digest algorithm. - /// - /// is out of range. - /// - /// - /// is not a supported digest algorithm. - /// - public static HashAlgorithmTag GetHashAlgorithm (DigestAlgorithm digestAlgo) - { - switch (digestAlgo) { - case DigestAlgorithm.MD5: return HashAlgorithmTag.MD5; - case DigestAlgorithm.Sha1: return HashAlgorithmTag.Sha1; - case DigestAlgorithm.RipeMD160: return HashAlgorithmTag.RipeMD160; - case DigestAlgorithm.DoubleSha: throw new NotSupportedException ("The Double SHA digest algorithm is not supported."); - case DigestAlgorithm.MD2: return HashAlgorithmTag.MD2; - case DigestAlgorithm.Tiger192: throw new NotSupportedException ("The Tiger-192 digest algorithm is not supported."); - case DigestAlgorithm.Haval5160: throw new NotSupportedException ("The HAVAL 5 160 digest algorithm is not supported."); - case DigestAlgorithm.Sha256: return HashAlgorithmTag.Sha256; - case DigestAlgorithm.Sha384: return HashAlgorithmTag.Sha384; - case DigestAlgorithm.Sha512: return HashAlgorithmTag.Sha512; - case DigestAlgorithm.Sha224: return HashAlgorithmTag.Sha224; - case DigestAlgorithm.MD4: throw new NotSupportedException ("The MD4 digest algorithm is not supported."); - default: throw new ArgumentOutOfRangeException (nameof (digestAlgo)); - } - } - - /// - /// Check whether or not a particular mailbox address can be used for signing. - /// - /// - /// Checks whether or not as particular mailbocx address can be used for signing. - /// - /// true if the mailbox address can be used for signing; otherwise, false. - /// The signer. - /// - /// is null. - /// - public override bool CanSign (MailboxAddress signer) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - foreach (PgpSecretKeyRing keyring in SecretKeyRingBundle.GetKeyRings ()) { - foreach (PgpSecretKey key in keyring.GetSecretKeys ()) { - if (!PgpSecretKeyMatches (keyring.GetSecretKey (), signer)) - continue; - - if (!key.IsSigningKey) - continue; - - var pubkey = key.PublicKey; - if (pubkey.IsRevoked ()) - continue; - - long seconds = pubkey.GetValidSeconds (); - if (seconds != 0) { - var expires = pubkey.CreationTime.AddSeconds ((double) seconds); - if (expires <= DateTime.Now) - continue; - } - - return true; - } - } - - return false; - } - - /// - /// Check whether or not the cryptography context can encrypt to a particular recipient. - /// - /// - /// Checks whether or not the cryptography context can be used to encrypt to a particular recipient. - /// - /// true if the cryptography context can be used to encrypt to the designated recipient; otherwise, false. - /// The recipient's mailbox address. - /// - /// is null. - /// - public override bool CanEncrypt (MailboxAddress mailbox) - { - if (mailbox == null) - throw new ArgumentNullException (nameof (mailbox)); - - foreach (var key in EnumeratePublicKeys (mailbox)) { - if (!key.IsEncryptionKey || key.IsRevoked ()) - continue; - - long seconds = key.GetValidSeconds (); - if (seconds != 0) { - var expires = key.CreationTime.AddSeconds ((double) seconds); - if (expires <= DateTime.Now) - continue; - } - - return true; - } - - return false; - } - - /// - /// Cryptographically signs the content. - /// - /// - /// Cryptographically signs the content using the specified signer and digest algorithm. - /// - /// A new instance - /// containing the detached signature data. - /// The signer. - /// The digest algorithm to use for signing. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// is out of range. - /// - /// - /// The specified is not supported by this context. - /// - /// - /// A signing key could not be found for . - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public override MimePart Sign (MailboxAddress signer, DigestAlgorithm digestAlgo, Stream content) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var key = GetSigningKey (signer); - - return Sign (key, digestAlgo, content); - } - - /// - /// Cryptographically signs the content. - /// - /// - /// Cryptographically signs the content using the specified signer and digest algorithm. - /// - /// A new instance - /// containing the detached signature data. - /// The signer. - /// The digest algorithm to use for signing. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// cannot be used for signing. - /// - /// - /// The was out of range. - /// - /// - /// The is not supported. - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public ApplicationPgpSignature Sign (PgpSecretKey signer, DigestAlgorithm digestAlgo, Stream content) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - if (!signer.IsSigningKey) - throw new ArgumentException ("The specified secret key cannot be used for signing.", nameof (signer)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var hashAlgorithm = GetHashAlgorithm (digestAlgo); - var memory = new MemoryBlockStream (); - - using (var armored = new ArmoredOutputStream (memory)) { - armored.SetHeader ("Version", null); - - var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); - using (var compressed = compresser.Open (armored)) { - var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); - var buf = new byte[4096]; - int nread; - - signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); - - while ((nread = content.Read (buf, 0, buf.Length)) > 0) - signatureGenerator.Update (buf, 0, nread); - - var signature = signatureGenerator.Generate (); - - signature.Encode (compressed); - compressed.Flush (); - } - - armored.Flush (); - } - - memory.Position = 0; - - return new ApplicationPgpSignature (memory); - } - - /// - /// Gets the equivalent for the specified - /// . - /// - /// - /// Gets the equivalent for the specified - /// . - /// - /// The digest algorithm. - /// The hash algorithm. - /// - /// is out of range. - /// - /// - /// does not have an equivalent value. - /// - public static DigestAlgorithm GetDigestAlgorithm (HashAlgorithmTag hashAlgorithm) - { - switch (hashAlgorithm) { - case HashAlgorithmTag.MD5: return DigestAlgorithm.MD5; - case HashAlgorithmTag.Sha1: return DigestAlgorithm.Sha1; - case HashAlgorithmTag.RipeMD160: return DigestAlgorithm.RipeMD160; - case HashAlgorithmTag.DoubleSha: return DigestAlgorithm.DoubleSha; - case HashAlgorithmTag.MD2: return DigestAlgorithm.MD2; - case HashAlgorithmTag.Tiger192: return DigestAlgorithm.Tiger192; - case HashAlgorithmTag.Haval5pass160: return DigestAlgorithm.Haval5160; - case HashAlgorithmTag.Sha256: return DigestAlgorithm.Sha256; - case HashAlgorithmTag.Sha384: return DigestAlgorithm.Sha384; - case HashAlgorithmTag.Sha512: return DigestAlgorithm.Sha512; - case HashAlgorithmTag.Sha224: return DigestAlgorithm.Sha224; - default: throw new ArgumentOutOfRangeException (nameof (hashAlgorithm)); - } - } - - /// - /// Gets the equivalent for the specified - /// . - /// - /// - /// Gets the equivalent for the specified - /// . - /// - /// The public-key algorithm. - /// The public-key algorithm. - /// - /// is out of range. - /// - /// - /// does not have an equivalent value. - /// - public static PublicKeyAlgorithm GetPublicKeyAlgorithm (PublicKeyAlgorithmTag algorithm) - { - switch (algorithm) { - case PublicKeyAlgorithmTag.RsaGeneral: return PublicKeyAlgorithm.RsaGeneral; - case PublicKeyAlgorithmTag.RsaEncrypt: return PublicKeyAlgorithm.RsaEncrypt; - case PublicKeyAlgorithmTag.RsaSign: return PublicKeyAlgorithm.RsaSign; - case PublicKeyAlgorithmTag.ElGamalEncrypt: return PublicKeyAlgorithm.ElGamalEncrypt; - case PublicKeyAlgorithmTag.Dsa: return PublicKeyAlgorithm.Dsa; - case PublicKeyAlgorithmTag.ECDH: return PublicKeyAlgorithm.EllipticCurve; - case PublicKeyAlgorithmTag.ECDsa: return PublicKeyAlgorithm.EllipticCurveDsa; - case PublicKeyAlgorithmTag.ElGamalGeneral: return PublicKeyAlgorithm.ElGamalGeneral; - case PublicKeyAlgorithmTag.DiffieHellman: return PublicKeyAlgorithm.DiffieHellman; - default: throw new ArgumentOutOfRangeException (nameof (algorithm)); - } - } - - async Task GetDigitalSignaturesAsync (PgpSignatureList signatureList, Stream content, bool doAsync, CancellationToken cancellationToken) - { - var signatures = new List (); - var buf = new byte[4096]; - int nread; - - for (int i = 0; i < signatureList.Count; i++) { - long keyId = signatureList[i].KeyId; - KeyRetrievalResults results; - - if (doAsync) - results = await GetPublicKeyRingAsync (keyId, doAsync, cancellationToken).ConfigureAwait (false); - else - results = GetPublicKeyRingAsync (keyId, doAsync, cancellationToken).GetAwaiter ().GetResult (); - - var signature = new OpenPgpDigitalSignature (results.KeyRing, results.Key, signatureList[i]) { - PublicKeyAlgorithm = GetPublicKeyAlgorithm (signatureList[i].KeyAlgorithm), - DigestAlgorithm = GetDigestAlgorithm (signatureList[i].HashAlgorithm), - CreationDate = signatureList[i].CreationTime, - }; - - if (results.Key != null) - signatureList[i].InitVerify (results.Key); - - signatures.Add (signature); - } - - while ((nread = content.Read (buf, 0, buf.Length)) > 0) { - for (int i = 0; i < signatures.Count; i++) { - if (signatures[i].SignerCertificate != null) { - var pgp = (OpenPgpDigitalSignature) signatures[i]; - pgp.Signature.Update (buf, 0, nread); - } - } - } - - return new DigitalSignatureCollection (signatures); - } - - Task VerifyAsync (Stream content, Stream signatureData, bool doAsync, CancellationToken cancellationToken) - { - if (content == null) - throw new ArgumentNullException (nameof (content)); - - if (signatureData == null) - throw new ArgumentNullException (nameof (signatureData)); - - using (var armored = new ArmoredInputStream (signatureData)) { - var factory = new PgpObjectFactory (armored); - var data = factory.NextPgpObject (); - PgpSignatureList signatureList; - - var compressed = data as PgpCompressedData; - if (compressed != null) { - factory = new PgpObjectFactory (compressed.GetDataStream ()); - data = factory.NextPgpObject (); - } - - if (data == null) - throw new FormatException ("Invalid PGP format."); - - signatureList = (PgpSignatureList) data; - - return GetDigitalSignaturesAsync (signatureList, content, doAsync, cancellationToken); - } - } - - /// - /// Verify the specified content using the detached signatureData. - /// - /// - /// Verifies the specified content using the detached signatureData. - /// If any of the signatures were made with an unrecognized key and is enabled, - /// an attempt will be made to retrieve said key(s). The can be used to cancel - /// key retrieval. - /// - /// A list of digital signatures. - /// The content. - /// The signature data. - /// The cancellation token. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// does not contain valid PGP signature data. - /// - public override DigitalSignatureCollection Verify (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) - { - return VerifyAsync (content, signatureData, false, cancellationToken).GetAwaiter ().GetResult (); - } - - /// - /// Asynchronously verify the specified content using the detached signatureData. - /// - /// - /// Verifies the specified content using the detached signatureData. - /// If any of the signatures were made with an unrecognized key and is enabled, - /// an attempt will be made to retrieve said key(s). The can be used to cancel - /// key retrieval. - /// - /// A list of digital signatures. - /// The content. - /// The signature data. - /// The cancellation token. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// does not contain valid PGP signature data. - /// - public override Task VerifyAsync (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) - { - return VerifyAsync (content, signatureData, true, cancellationToken); - } - - static Stream Compress (Stream content, byte[] buf) - { - var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); - var memory = new MemoryBlockStream (); - - using (var compressed = compresser.Open (memory)) { - var literalGenerator = new PgpLiteralDataGenerator (); - - using (var literal = literalGenerator.Open (compressed, 't', "mime.txt", content.Length, DateTime.Now)) { - int nread; - - while ((nread = content.Read (buf, 0, buf.Length)) > 0) - literal.Write (buf, 0, nread); - - literal.Flush (); - } - - compressed.Flush (); - } - - memory.Position = 0; - - return memory; - } - - static Stream Encrypt (PgpEncryptedDataGenerator encrypter, Stream content) - { - var memory = new MemoryBlockStream (); - - using (var armored = new ArmoredOutputStream (memory)) { - var buf = new byte[4096]; - - armored.SetHeader ("Version", null); - - using (var compressed = Compress (content, buf)) { - using (var encrypted = encrypter.Open (armored, compressed.Length)) { - int nread; - - while ((nread = compressed.Read (buf, 0, buf.Length)) > 0) - encrypted.Write (buf, 0, nread); - - encrypted.Flush (); - } - } - - armored.Flush (); - } - - memory.Position = 0; - - return memory; - } - - static SymmetricKeyAlgorithmTag GetSymmetricKeyAlgorithm (EncryptionAlgorithm algorithm) - { - switch (algorithm) { - case EncryptionAlgorithm.Aes128: return SymmetricKeyAlgorithmTag.Aes128; - case EncryptionAlgorithm.Aes192: return SymmetricKeyAlgorithmTag.Aes192; - case EncryptionAlgorithm.Aes256: return SymmetricKeyAlgorithmTag.Aes256; - case EncryptionAlgorithm.Camellia128: return SymmetricKeyAlgorithmTag.Camellia128; - case EncryptionAlgorithm.Camellia192: return SymmetricKeyAlgorithmTag.Camellia192; - case EncryptionAlgorithm.Camellia256: return SymmetricKeyAlgorithmTag.Camellia256; - case EncryptionAlgorithm.Cast5: return SymmetricKeyAlgorithmTag.Cast5; - case EncryptionAlgorithm.Des: return SymmetricKeyAlgorithmTag.Des; - case EncryptionAlgorithm.TripleDes: return SymmetricKeyAlgorithmTag.TripleDes; - case EncryptionAlgorithm.Idea: return SymmetricKeyAlgorithmTag.Idea; - case EncryptionAlgorithm.Blowfish: return SymmetricKeyAlgorithmTag.Blowfish; - case EncryptionAlgorithm.Twofish: return SymmetricKeyAlgorithmTag.Twofish; - default: throw new NotSupportedException (string.Format ("{0} is not supported.", algorithm)); - } - } - - /// - /// Encrypt the specified content for the specified recipients. - /// - /// - /// Encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// A public key could not be found for one or more of the . - /// - public override MimePart Encrypt (IEnumerable recipients, Stream content) - { - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - // TODO: document the exceptions that can be thrown by BouncyCastle - return Encrypt (GetPublicKeys (recipients), content); - } - - /// - /// Encrypt the specified content for the specified recipients. - /// - /// - /// Encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The encryption algorithm. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// A public key could not be found for one or more of the . - /// - /// - /// The specified encryption algorithm is not supported. - /// - public MimePart Encrypt (EncryptionAlgorithm algorithm, IEnumerable recipients, Stream content) - { - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - // TODO: document the exceptions that can be thrown by BouncyCastle - return Encrypt (algorithm, GetPublicKeys (recipients), content); - } - - /// - /// Encrypt the specified content for the specified recipients. - /// - /// - /// Encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The encryption algorithm. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// The specified encryption algorithm is not supported. - /// - public MimePart Encrypt (EncryptionAlgorithm algorithm, IEnumerable recipients, Stream content) - { - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (algorithm), true); - var unique = new HashSet (); - int count = 0; - - foreach (var recipient in recipients) { - if (!recipient.IsEncryptionKey) - throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", nameof (recipients)); - - if (unique.Add (recipient.KeyId)) { - encrypter.AddMethod (recipient); - count++; - } - } - - if (count == 0) - throw new ArgumentException ("No recipients specified.", nameof (recipients)); - - var encrypted = Encrypt (encrypter, content); - - return new MimePart ("application", "octet-stream") { - ContentDisposition = new ContentDisposition (ContentDisposition.Attachment), - Content = new MimeContent (encrypted), - }; - } - - /// - /// Encrypt the specified content for the specified recipients. - /// - /// - /// Encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - public MimePart Encrypt (IEnumerable recipients, Stream content) - { - return Encrypt (defaultAlgorithm, recipients, content); - } - - /// - /// Cryptographically sign and encrypt the specified content for the specified recipients. - /// - /// - /// Cryptographically signs and encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The signer. - /// The digest algorithm to use for signing. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// -or- - /// is null. - /// - /// - /// is out of range. - /// - /// - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// The specified is not supported by this context. - /// - /// - /// The private key could not be found for . - /// - /// - /// A public key could not be found for one or more of the . - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public MimePart SignAndEncrypt (MailboxAddress signer, DigestAlgorithm digestAlgo, IEnumerable recipients, Stream content) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var key = GetSigningKey (signer); - - return SignAndEncrypt (key, digestAlgo, GetPublicKeys (recipients), content); - } - - /// - /// Cryptographically sign and encrypt the specified content for the specified recipients. - /// - /// - /// Cryptographically signs and encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The signer. - /// The digest algorithm to use for signing. - /// The encryption algorithm. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// -or- - /// is null. - /// - /// - /// cannot be used for signing. - /// -or- - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// The specified encryption algorithm is not supported. - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public MimePart SignAndEncrypt (MailboxAddress signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable recipients, Stream content) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var key = GetSigningKey (signer); - - return SignAndEncrypt (key, digestAlgo, cipherAlgo, GetPublicKeys (recipients), content); - } - - /// - /// Cryptographically sign and encrypt the specified content for the specified recipients. - /// - /// - /// Cryptographically signs and encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The signer. - /// The digest algorithm to use for signing. - /// The encryption algorithm. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// -or- - /// is null. - /// - /// - /// cannot be used for signing. - /// -or- - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// The specified encryption algorithm is not supported. - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable recipients, Stream content) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - if (!signer.IsSigningKey) - throw new ArgumentException ("The specified secret key cannot be used for signing.", nameof (signer)); - - if (recipients == null) - throw new ArgumentNullException (nameof (recipients)); - - if (content == null) - throw new ArgumentNullException (nameof (content)); - - var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (cipherAlgo), true); - var hashAlgorithm = GetHashAlgorithm (digestAlgo); - var unique = new HashSet (); - var buf = new byte[4096]; - int nread, count = 0; - - foreach (var recipient in recipients) { - if (!recipient.IsEncryptionKey) - throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", nameof (recipients)); - - if (unique.Add (recipient.KeyId)) { - encrypter.AddMethod (recipient); - count++; - } - } - - if (count == 0) - throw new ArgumentException ("No recipients specified.", nameof (recipients)); - - var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); - - using (var compressed = new MemoryBlockStream ()) { - using (var signed = compresser.Open (compressed)) { - var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); - signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); - var subpacket = new PgpSignatureSubpacketGenerator (); - - foreach (string userId in signer.PublicKey.GetUserIds ()) { - subpacket.SetSignerUserId (false, userId); - break; - } - - signatureGenerator.SetHashedSubpackets (subpacket.Generate ()); - - var onepass = signatureGenerator.GenerateOnePassVersion (false); - onepass.Encode (signed); - - var literalGenerator = new PgpLiteralDataGenerator (); - using (var literal = literalGenerator.Open (signed, 't', "mime.txt", content.Length, DateTime.Now)) { - while ((nread = content.Read (buf, 0, buf.Length)) > 0) { - signatureGenerator.Update (buf, 0, nread); - literal.Write (buf, 0, nread); - } - - literal.Flush (); - } - - var signature = signatureGenerator.Generate (); - signature.Encode (signed); - - signed.Flush (); - } - - compressed.Position = 0; - - var memory = new MemoryBlockStream (); - - using (var armored = new ArmoredOutputStream (memory)) { - armored.SetHeader ("Version", null); - - using (var encrypted = encrypter.Open (armored, compressed.Length)) { - while ((nread = compressed.Read (buf, 0, buf.Length)) > 0) - encrypted.Write (buf, 0, nread); - - encrypted.Flush (); - } - - armored.Flush (); - } - - memory.Position = 0; - - return new MimePart ("application", "octet-stream") { - ContentDisposition = new ContentDisposition (ContentDisposition.Attachment), - Content = new MimeContent (memory) - }; - } - } - - /// - /// Cryptographically sign and encrypt the specified content for the specified recipients. - /// - /// - /// Cryptographically signs and encrypts the specified content for the specified recipients. - /// - /// A new instance - /// containing the encrypted data. - /// The signer. - /// The digest algorithm to use for signing. - /// The recipients. - /// The content. - /// - /// is null. - /// -or- - /// is null. - /// -or- - /// is null. - /// - /// - /// cannot be used for signing. - /// -or- - /// One or more of the recipient keys cannot be used for encrypting. - /// -or- - /// No recipients were specified. - /// - /// - /// The user chose to cancel the password prompt. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable recipients, Stream content) - { - return SignAndEncrypt (signer, digestAlgo, defaultAlgorithm, recipients, content); - } - - async Task DecryptToAsync (Stream encryptedData, Stream decryptedData, bool doAsync, CancellationToken cancellationToken) - { - if (encryptedData == null) - throw new ArgumentNullException (nameof (encryptedData)); - - if (decryptedData == null) - throw new ArgumentNullException (nameof (decryptedData)); - - using (var armored = new ArmoredInputStream (encryptedData)) { - var factory = new PgpObjectFactory (armored); - var obj = factory.NextPgpObject (); - var list = obj as PgpEncryptedDataList; - - if (list == null) { - // probably a PgpMarker... - obj = factory.NextPgpObject (); - - list = obj as PgpEncryptedDataList; - - if (list == null) - throw new PgpException ("Unexpected OpenPGP packet."); - } - - PgpPublicKeyEncryptedData encrypted = null; - PrivateKeyNotFoundException pkex = null; - bool hasEncryptedPackets = false; - PgpSecretKey secret = null; - - foreach (PgpEncryptedData data in list.GetEncryptedDataObjects ()) { - if ((encrypted = data as PgpPublicKeyEncryptedData) == null) - continue; - - hasEncryptedPackets = true; - - try { - secret = GetSecretKey (encrypted.KeyId); - break; - } catch (PrivateKeyNotFoundException ex) { - pkex = ex; - } - } - - if (!hasEncryptedPackets) - throw new PgpException ("No encrypted packets found."); - - if (secret == null) - throw pkex; - - factory = new PgpObjectFactory (encrypted.GetDataStream (GetPrivateKey (secret))); - List onepassList = null; - DigitalSignatureCollection signatures; - PgpSignatureList signatureList = null; - PgpCompressedData compressed = null; - var position = decryptedData.Position; - long nwritten = 0; - - obj = factory.NextPgpObject (); - while (obj != null) { - if (obj is PgpCompressedData) { - if (compressed != null) - throw new PgpException ("Recursive compression packets are not supported."); - - compressed = (PgpCompressedData) obj; - factory = new PgpObjectFactory (compressed.GetDataStream ()); - } else if (obj is PgpOnePassSignatureList) { - if (nwritten == 0) { - var onepasses = (PgpOnePassSignatureList) obj; - - onepassList = new List (); - - for (int i = 0; i < onepasses.Count; i++) { - var onepass = onepasses[i]; - - var results = await GetPublicKeyRingAsync (onepass.KeyId, doAsync, cancellationToken).ConfigureAwait (false); - - if (results.KeyRing == null) { - // too messy, pretend we never found a one-pass signature list - onepassList = null; - break; - } - - onepass.InitVerify (results.Key); - - var signature = new OpenPgpDigitalSignature (results.KeyRing, results.Key, onepass) { - PublicKeyAlgorithm = GetPublicKeyAlgorithm (onepass.KeyAlgorithm), - DigestAlgorithm = GetDigestAlgorithm (onepass.HashAlgorithm), - }; - - onepassList.Add (signature); - } - } - } else if (obj is PgpSignatureList) { - signatureList = (PgpSignatureList) obj; - } else if (obj is PgpLiteralData) { - var literal = (PgpLiteralData) obj; - - using (var stream = literal.GetDataStream ()) { - var buffer = new byte[4096]; - int nread; - - while ((nread = stream.Read (buffer, 0, buffer.Length)) > 0) { - if (onepassList != null) { - // update our one-pass signatures... - for (int index = 0; index < nread; index++) { - byte c = buffer[index]; - - for (int i = 0; i < onepassList.Count; i++) { - var pgp = (OpenPgpDigitalSignature) onepassList[i]; - pgp.OnePassSignature.Update (c); - } - } - } - - if (doAsync) - await decryptedData.WriteAsync (buffer, 0, nread, cancellationToken).ConfigureAwait (false); - else - decryptedData.Write (buffer, 0, nread); - - nwritten += nread; - } - } - } - - obj = factory.NextPgpObject (); - } - - if (signatureList != null) { - if (onepassList != null && signatureList.Count == onepassList.Count) { - for (int i = 0; i < onepassList.Count; i++) { - var pgp = (OpenPgpDigitalSignature) onepassList[i]; - pgp.CreationDate = signatureList[i].CreationTime; - pgp.Signature = signatureList[i]; - } - - signatures = new DigitalSignatureCollection (onepassList); - } else { - decryptedData.Position = position; - signatures = await GetDigitalSignaturesAsync (signatureList, decryptedData, doAsync, cancellationToken).ConfigureAwait (false); - decryptedData.Position = decryptedData.Length; - } - } else { - signatures = null; - } - - return signatures; - } - } - - /// - /// Decrypt an encrypted stream and extract the digital signers if the content was also signed. - /// - /// - /// Decrypts an encrypted stream and extracts the digital signers if the content was also signed. - /// If any of the signatures were made with an unrecognized key and is enabled, - /// an attempt will be made to retrieve said key(s). The can be used to cancel - /// key retrieval. - /// - /// The list of digital signatures if the data was both signed and encrypted; otherwise, null. - /// The encrypted data. - /// The stream to write the decrypted data to. - /// The cancellation token. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// The private key could not be found to decrypt the stream. - /// - /// - /// The user chose to cancel the password prompt. - /// -or- - /// The operation was cancelled via the cancellation token. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - /// - /// An OpenPGP error occurred. - /// - public DigitalSignatureCollection DecryptTo (Stream encryptedData, Stream decryptedData, CancellationToken cancellationToken = default (CancellationToken)) - { - return DecryptToAsync (encryptedData, decryptedData, false, cancellationToken).GetAwaiter ().GetResult (); - } - - /// - /// Asynchronously decrypt an encrypted stream and extract the digital signers if the content was also signed. - /// - /// - /// Decrypts an encrypted stream and extracts the digital signers if the content was also signed. - /// If any of the signatures were made with an unrecognized key and is enabled, - /// an attempt will be made to retrieve said key(s). The can be used to cancel - /// key retrieval. - /// - /// The list of digital signatures if the data was both signed and encrypted; otherwise, null. - /// The encrypted data. - /// The stream to write the decrypted data to. - /// The cancellation token. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// The private key could not be found to decrypt the stream. - /// - /// - /// The user chose to cancel the password prompt. - /// -or- - /// The operation was cancelled via the cancellation token. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - /// - /// An OpenPGP error occurred. - /// - public Task DecryptToAsync (Stream encryptedData, Stream decryptedData, CancellationToken cancellationToken = default (CancellationToken)) - { - return DecryptToAsync (encryptedData, decryptedData, true, cancellationToken); - } - - /// - /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. - /// - /// - /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. - /// - /// The decrypted . - /// The encrypted data. - /// A list of digital signatures if the data was both signed and encrypted. - /// The cancellation token. - /// - /// is null. - /// - /// - /// The private key could not be found to decrypt the stream. - /// - /// - /// The user chose to cancel the password prompt. - /// -or- - /// The operation was cancelled via the cancellation token. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - /// - /// An OpenPGP error occurred. - /// - public MimeEntity Decrypt (Stream encryptedData, out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default (CancellationToken)) - { - var decryptedData = new MemoryBlockStream (); - - signatures = DecryptTo (encryptedData, decryptedData, cancellationToken); - decryptedData.Position = 0; - - return MimeEntity.Load (decryptedData, true, cancellationToken); - } - - /// - /// Decrypts the specified encryptedData. - /// - /// - /// Decrypts the specified encryptedData. - /// - /// The decrypted . - /// The encrypted data. - /// The cancellation token. - /// - /// is null. - /// - /// - /// The private key could not be found to decrypt the stream. - /// - /// - /// The user chose to cancel the password prompt. - /// -or- - /// The operation was cancelled via the cancellation token. - /// - /// - /// 3 bad attempts were made to unlock the secret key. - /// - /// - /// An OpenPGP error occurred. - /// - public override MimeEntity Decrypt (Stream encryptedData, CancellationToken cancellationToken = default (CancellationToken)) - { - var decryptedData = new MemoryBlockStream (); - - DecryptTo (encryptedData, decryptedData, cancellationToken); - decryptedData.Position = 0; - - return MimeEntity.Load (decryptedData, true, cancellationToken); - } - - /// - /// Saves the public key-ring bundle. + /// Saves the public key-ring bundle. /// /// /// Atomically saves the public key-ring bundle to the path specified by . @@ -2399,7 +785,6 @@ async Task DecryptToAsync (Stream encryptedData, Str /// protected void SavePublicKeyRingBundle () { -#if !PORTABLE var filename = Path.GetFileName (PublicKeyRingPath) + "~"; var dirname = Path.GetDirectoryName (PublicKeyRingPath); var tmp = Path.Combine (dirname, "." + filename); @@ -2413,7 +798,7 @@ protected void SavePublicKeyRingBundle () } if (File.Exists (PublicKeyRingPath)) { -#if !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 File.Replace (tmp, PublicKeyRingPath, bak); #else if (File.Exists (bak)) @@ -2424,10 +809,6 @@ protected void SavePublicKeyRingBundle () } else { File.Move (tmp, PublicKeyRingPath); } -#else - PublicKeyRingBundle.Encode (PublicKeyRing); - PublicKeyRing.Seek (0, SeekOrigin.Begin); -#endif } /// @@ -2442,7 +823,6 @@ protected void SavePublicKeyRingBundle () /// protected void SaveSecretKeyRingBundle () { -#if !PORTABLE var filename = Path.GetFileName (SecretKeyRingPath) + "~"; var dirname = Path.GetDirectoryName (SecretKeyRingPath); var tmp = Path.Combine (dirname, "." + filename); @@ -2456,7 +836,7 @@ protected void SaveSecretKeyRingBundle () } if (File.Exists (SecretKeyRingPath)) { -#if !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 File.Replace (tmp, SecretKeyRingPath, bak); #else if (File.Exists (bak)) @@ -2467,10 +847,6 @@ protected void SaveSecretKeyRingBundle () } else { File.Move (tmp, SecretKeyRingPath); } -#else - SecretKeyRingBundle.Encode (SecretKeyRing); - SecretKeyRing.Seek (0, SeekOrigin.Begin); -#endif } /// @@ -2483,7 +859,7 @@ protected void SaveSecretKeyRingBundle () /// /// is null. /// - public void Import (PgpPublicKeyRing keyring) + public virtual void Import (PgpPublicKeyRing keyring) { if (keyring == null) throw new ArgumentNullException (nameof (keyring)); @@ -2502,7 +878,7 @@ public void Import (PgpPublicKeyRing keyring) /// /// is null. /// - public void Import (PgpPublicKeyRingBundle bundle) + public override void Import (PgpPublicKeyRingBundle bundle) { if (bundle == null) throw new ArgumentNullException (nameof (bundle)); @@ -2552,7 +928,7 @@ public override void Import (Stream stream) /// /// is null. /// - public void Import (PgpSecretKeyRing keyring) + public virtual void Import (PgpSecretKeyRing keyring) { if (keyring == null) throw new ArgumentNullException (nameof (keyring)); @@ -2571,7 +947,7 @@ public void Import (PgpSecretKeyRing keyring) /// /// is null. /// - public void Import (PgpSecretKeyRingBundle bundle) + public virtual void Import (PgpSecretKeyRingBundle bundle) { if (bundle == null) throw new ArgumentNullException (nameof (bundle)); @@ -2593,7 +969,7 @@ public void Import (PgpSecretKeyRingBundle bundle) /// /// Exports the public keys for the specified mailboxes. /// - /// A new instance containing the exported public keys. + /// A new instance containing the exported public keys. /// The mailboxes associated with the public keys to export. /// /// is null. @@ -2621,7 +997,7 @@ public override MimePart Export (IEnumerable mailboxes) /// /// Exports the specified public keys. /// - /// A new instance containing the exported public keys. + /// A new instance containing the exported public keys. /// The public keys to export. /// /// is null. @@ -2643,7 +1019,7 @@ public MimePart Export (IEnumerable keys) /// /// Exports the specified public keys. /// - /// A new instance containing the exported public keys. + /// A new instance containing the exported public keys. /// The public keys to export. /// /// is null. @@ -2705,7 +1081,7 @@ public void Export (IEnumerable mailboxes, Stream stream, bool a /// /// Exports the specified public keys. /// - /// A new instance containing the exported public keys. + /// A new instance containing the exported public keys. /// The public keys to export. /// The output stream. /// true if the output should be armored; otherwise, false. @@ -2778,7 +1154,7 @@ public void Export (PgpPublicKeyRingBundle keys, Stream stream, bool armor) /// /// is null. /// - public void Delete (PgpPublicKeyRing keyring) + public virtual void Delete (PgpPublicKeyRing keyring) { if (keyring == null) throw new ArgumentNullException (nameof (keyring)); @@ -2797,7 +1173,7 @@ public void Delete (PgpPublicKeyRing keyring) /// /// is null. /// - public void Delete (PgpSecretKeyRing keyring) + public virtual void Delete (PgpSecretKeyRing keyring) { if (keyring == null) throw new ArgumentNullException (nameof (keyring)); @@ -2805,22 +1181,5 @@ public void Delete (PgpSecretKeyRing keyring) SecretKeyRingBundle = PgpSecretKeyRingBundle.RemoveSecretKeyRing (SecretKeyRingBundle, keyring); SaveSecretKeyRingBundle (); } - - /// - /// Releases all resources used by the object. - /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After - /// calling , you must release all references to the so - /// the garbage collector can reclaim the memory that the was occupying. - protected override void Dispose (bool disposing) - { - if (disposing && client != null) { - client.Dispose (); - client = null; - } - - base.Dispose (disposing); - } } } diff --git a/MimeKit/Cryptography/OpenPgpContextBase.cs b/MimeKit/Cryptography/OpenPgpContextBase.cs new file mode 100644 index 0000000000..32bd421b74 --- /dev/null +++ b/MimeKit/Cryptography/OpenPgpContextBase.cs @@ -0,0 +1,1924 @@ +// +// OpenPgpContext.cs +// +// Authors: Jeffrey Stedfast +// Thomas Hansen +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Buffers; +using System.Net.Http; +using System.Threading; +using System.Diagnostics; +using System.Globalization; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Org.BouncyCastle.Bcpg; +using Org.BouncyCastle.Bcpg.OpenPgp; + +using MimeKit.IO; + +namespace MimeKit.Cryptography { + /// + /// An abstract OpenPGP cryptography context which can be used for PGP/MIME. + /// + /// + /// Generally speaking, applications should not use a + /// directly, but rather via higher level APIs such as + /// and . + /// + public abstract class OpenPgpContextBase : CryptographyContext + { + static readonly string[] ProtocolSubtypes = { "pgp-signature", "pgp-encrypted", "pgp-keys", "x-pgp-signature", "x-pgp-encrypted", "x-pgp-keys" }; + const string BeginPublicKeyBlock = "-----BEGIN PGP PUBLIC KEY BLOCK-----"; + const string EndPublicKeyBlock = "-----END PGP PUBLIC KEY BLOCK-----"; + const int BufferLength = 4096; + + static readonly EncryptionAlgorithm[] DefaultEncryptionAlgorithmRank = { + EncryptionAlgorithm.Idea, + EncryptionAlgorithm.TripleDes, + EncryptionAlgorithm.Cast5, + EncryptionAlgorithm.Blowfish, + EncryptionAlgorithm.Aes128, + EncryptionAlgorithm.Aes192, + EncryptionAlgorithm.Aes256, + EncryptionAlgorithm.Twofish, + EncryptionAlgorithm.Camellia128, + EncryptionAlgorithm.Camellia192, + EncryptionAlgorithm.Camellia256 + }; + + static readonly DigestAlgorithm[] DefaultDigestAlgorithmRank = { + DigestAlgorithm.Sha1, + DigestAlgorithm.RipeMD160, + DigestAlgorithm.Sha256, + DigestAlgorithm.Sha384, + DigestAlgorithm.Sha512, + DigestAlgorithm.Sha224 + }; + + EncryptionAlgorithm defaultAlgorithm; + HttpClient client; + Uri keyServer; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + protected OpenPgpContextBase () + { + EncryptionAlgorithmRank = DefaultEncryptionAlgorithmRank; + DigestAlgorithmRank = DefaultDigestAlgorithmRank; + + foreach (var algorithm in EncryptionAlgorithmRank) + Enable (algorithm); + + foreach (var algorithm in DigestAlgorithmRank) + Enable (algorithm); + + defaultAlgorithm = EncryptionAlgorithm.Cast5; + + client = new HttpClient (); + } + + /// + /// Get the password for a secret key. + /// + /// + /// Gets the password for a secret key. + /// + /// The password for the secret key. + /// The secret key. + /// + /// The user chose to cancel the password request. + /// + protected abstract string GetPasswordForKey (PgpSecretKey key); // FIXME: rename this to GetPassword() in the future + + /// + /// Get the public keyring that contains the specified key. + /// + /// + /// Gets the public keyring that contains the specified key. + /// Implementations should first try to obtain the keyring stored (or cached) locally. + /// Failing that, if is enabled, they should use + /// to attempt to + /// retrieve the keyring from the configured . + /// + /// The public key identifier. + /// The cancellation token. + /// The public keyring that contains the specified key or null if the keyring could not be found. + /// + /// The operation was cancelled. + /// + protected abstract PgpPublicKeyRing GetPublicKeyRing (long keyId, CancellationToken cancellationToken); + + /// + /// Get the public keyring that contains the specified key asynchronously. + /// + /// + /// Gets the public keyring that contains the specified key. + /// Implementations should first try to obtain the keyring stored (or cached) locally. + /// Failing that, if is enabled, they should use + /// to attempt to + /// retrieve the keyring from the configured . + /// + /// The public key identifier. + /// The cancellation token. + /// The public keyring that contains the specified key or null if the keyring could not be found. + /// + /// The operation was cancelled. + /// + protected abstract Task GetPublicKeyRingAsync (long keyId, CancellationToken cancellationToken); + + /// + /// Get the secret key for a specified key identifier. + /// + /// + /// Gets the secret key for a specified key identifier. + /// + /// The key identifier for the desired secret key. + /// The secret key. + /// + /// The secret key specified by the could not be found. + /// + protected abstract PgpSecretKey GetSecretKey (long keyId); + + /// + /// Get the public keys for the specified mailbox addresses. + /// + /// + /// Gets a list of valid public keys for the specified mailbox addresses that can be used for encryption. + /// + /// The encryption keys. + /// The mailboxes. + /// + /// is null. + /// + /// + /// A public key for one or more of the could not be found. + /// + public abstract IList GetPublicKeys (IEnumerable mailboxes); + + /// + /// Get the signing key associated with the mailbox address. + /// + /// + /// Gets the signing key associated with the mailbox address. + /// + /// The signing key. + /// The mailbox. + /// + /// is null. + /// + /// + /// A secret key for the specified could not be found. + /// + public abstract PgpSecretKey GetSigningKey (MailboxAddress mailbox); + + /// + /// Get or set the default encryption algorithm. + /// + /// + /// Gets or sets the default encryption algorithm. + /// + /// The encryption algorithm. + /// + /// The specified encryption algorithm is not supported. + /// + public EncryptionAlgorithm DefaultEncryptionAlgorithm { + get { return defaultAlgorithm; } + set { + GetSymmetricKeyAlgorithm (value); + defaultAlgorithm = value; + } + } + + bool IsValidKeyServer { + get { + if (keyServer == null) + return false; + + switch (keyServer.Scheme.ToLowerInvariant ()) { + case "https": case "http": case "hkp": return true; + default: return false; + } + } + } + + /// + /// Get or set the key server to use when automatically retrieving keys. + /// + /// + /// Gets or sets the key server to use when verifying keys that are + /// not already in the public keychain. + /// Only HTTP and HKP protocols are supported. + /// + /// The key server. + /// + /// is not an absolute URI. + /// + public Uri KeyServer { + get { return keyServer; } + set { + if (value != null && !value.IsAbsoluteUri) + throw new ArgumentException ("The key server URI must be absolute.", nameof (value)); + + keyServer = value; + } + } + + /// + /// Get or set whether unknown PGP keys should automtically be retrieved. + /// + /// + /// Gets or sets whether or not the should automatically + /// fetch keys as needed from the keyserver when verifying signatures. + /// Requires a valid to be set. + /// + /// true if unknown PGP keys should automatically be retrieved; otherwise, false. + public bool AutoKeyRetrieve { + get; set; + } + + /// + /// Get the signature protocol. + /// + /// + /// The signature protocol is used by + /// in order to determine what the protocol parameter of the Content-Type + /// header should be. + /// + /// The signature protocol. + public override string SignatureProtocol { + get { return "application/pgp-signature"; } + } + + /// + /// Get the encryption protocol. + /// + /// + /// The encryption protocol is used by + /// in order to determine what the protocol parameter of the Content-Type + /// header should be. + /// + /// The encryption protocol. + public override string EncryptionProtocol { + get { return "application/pgp-encrypted"; } + } + + /// + /// Get the key exchange protocol. + /// + /// + /// Gets the key exchange protocol. + /// + /// The key exchange protocol. + public override string KeyExchangeProtocol { + get { return "application/pgp-keys"; } + } + + /// + /// Check whether or not the specified protocol is supported. + /// + /// + /// Used in order to make sure that the protocol parameter value specified in either a multipart/signed + /// or multipart/encrypted part is supported by the supplied cryptography context. + /// + /// true if the protocol is supported; otherwise false + /// The protocol. + /// + /// is null. + /// + public override bool Supports (string protocol) + { + if (protocol == null) + throw new ArgumentNullException (nameof (protocol)); + + if (!protocol.StartsWith ("application/", StringComparison.OrdinalIgnoreCase)) + return false; + + int startIndex = "application/".Length; + int subtypeLength = protocol.Length - startIndex; + + for (int i = 0; i < ProtocolSubtypes.Length; i++) { + if (subtypeLength != ProtocolSubtypes[i].Length) + continue; + + if (string.Compare (protocol, startIndex, ProtocolSubtypes[i], 0, subtypeLength, StringComparison.OrdinalIgnoreCase) == 0) + return true; + } + + return false; + } + + /// + /// Get the string name of the digest algorithm for use with the micalg parameter of a multipart/signed part. + /// + /// + /// Maps the to the appropriate string identifier + /// as used by the micalg parameter value of a multipart/signed Content-Type + /// header. For example: + /// + /// AlgorithmName + /// pgp-md5 + /// pgp-sha1 + /// pgp-ripemd160 + /// pgp-md2 + /// pgp-tiger192 + /// pgp-haval-5-160 + /// pgp-sha256 + /// pgp-sha384 + /// pgp-sha512 + /// pgp-sha224 + /// + /// + /// The micalg value. + /// The digest algorithm. + /// + /// is out of range. + /// + public override string GetDigestAlgorithmName (DigestAlgorithm micalg) + { + switch (micalg) { + case DigestAlgorithm.MD5: return "pgp-md5"; + case DigestAlgorithm.Sha1: return "pgp-sha1"; + case DigestAlgorithm.RipeMD160: return "pgp-ripemd160"; + case DigestAlgorithm.MD2: return "pgp-md2"; + case DigestAlgorithm.Tiger192: return "pgp-tiger192"; + case DigestAlgorithm.Haval5160: return "pgp-haval-5-160"; + case DigestAlgorithm.Sha256: return "pgp-sha256"; + case DigestAlgorithm.Sha384: return "pgp-sha384"; + case DigestAlgorithm.Sha512: return "pgp-sha512"; + case DigestAlgorithm.Sha224: return "pgp-sha224"; + case DigestAlgorithm.MD4: return "pgp-md4"; + default: throw new ArgumentOutOfRangeException (nameof (micalg)); + } + } + + /// + /// Get the digest algorithm from the micalg parameter value in a multipart/signed part. + /// + /// + /// Maps the micalg parameter value string back to the appropriate . + /// + /// The digest algorithm. + /// The micalg parameter value. + /// + /// is null. + /// + public override DigestAlgorithm GetDigestAlgorithm (string micalg) + { + if (micalg == null) + throw new ArgumentNullException (nameof (micalg)); + + switch (micalg.ToLowerInvariant ()) { + case "pgp-md5": return DigestAlgorithm.MD5; + case "pgp-sha1": return DigestAlgorithm.Sha1; + case "pgp-ripemd160": return DigestAlgorithm.RipeMD160; + case "pgp-md2": return DigestAlgorithm.MD2; + case "pgp-tiger192": return DigestAlgorithm.Tiger192; + case "pgp-haval-5-160": return DigestAlgorithm.Haval5160; + case "pgp-sha256": return DigestAlgorithm.Sha256; + case "pgp-sha384": return DigestAlgorithm.Sha384; + case "pgp-sha512": return DigestAlgorithm.Sha512; + case "pgp-sha224": return DigestAlgorithm.Sha224; + case "pgp-md4": return DigestAlgorithm.MD4; + default: return DigestAlgorithm.None; + } + } + + /// + /// Hex encode an array of bytes. + /// + /// + /// This method is used to hex-encode the PGP key fingerprints. + /// + /// The data to encode. + /// A string representing the hex-encoded data. + static string HexEncode (byte[] data) + { + var fingerprint = new StringBuilder (); + + for (int i = 0; i < data.Length; i++) + fingerprint.Append (data[i].ToString ("x2")); + + return fingerprint.ToString (); + } + + /// + /// Check that a public key is a match for the specified mailbox. + /// + /// + /// Checks that the public key is a match for the specified mailbox. + /// If the is a with a non-empty + /// , then the fingerprint is used to match the key's + /// fingerprint. Otherwise, the email address(es) contained within the key's user identifier strings + /// are compared to the mailbox address. + /// + /// The public key. + /// The mailbox address. + /// true if the key is a match for the specified mailbox; otherwise, false. + /// + /// is null. + /// -or- + /// is null. + /// + protected static bool IsMatch (PgpPublicKey key, MailboxAddress mailbox) + { + if (key == null) + throw new ArgumentNullException (nameof (key)); + + if (mailbox == null) + throw new ArgumentNullException (nameof (mailbox)); + + if (mailbox is SecureMailboxAddress secure && !string.IsNullOrEmpty (secure.Fingerprint)) { + if (secure.Fingerprint.Length > 16) { + var fingerprint = HexEncode (key.GetFingerprint ()); + + return secure.Fingerprint.Equals (fingerprint, StringComparison.OrdinalIgnoreCase); + } + + var id = ((int) key.KeyId).ToString ("X2"); + + return secure.Fingerprint.EndsWith (id, StringComparison.OrdinalIgnoreCase); + } + + foreach (string userId in key.GetUserIds ()) { + if (!MailboxAddress.TryParse (userId, out var email)) + continue; + + if (mailbox.Address.Equals (email.Address, StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; + } + + /// + /// Check that a secret key is a match for the specified mailbox. + /// + /// + /// Checks that the secret key is a match for the specified mailbox. + /// If the is a with a non-empty + /// , then the fingerprint is used to match the key's + /// fingerprint. Otherwise, the email address(es) contained within the key's user identifier strings + /// are compared to the mailbox address. + /// + /// The secret key. + /// The mailbox address. + /// true if the key is a match for the specified mailbox; otherwise, false. + /// + /// is null. + /// -or- + /// is null. + /// + protected static bool IsMatch (PgpSecretKey key, MailboxAddress mailbox) + { + if (key == null) + throw new ArgumentNullException (nameof (key)); + + if (mailbox == null) + throw new ArgumentNullException (nameof (mailbox)); + + if (mailbox is SecureMailboxAddress secure && !string.IsNullOrEmpty (secure.Fingerprint)) { + if (secure.Fingerprint.Length > 16) { + var fingerprint = HexEncode (key.PublicKey.GetFingerprint ()); + + return secure.Fingerprint.Equals (fingerprint, StringComparison.OrdinalIgnoreCase); + } + + var id = ((int) key.KeyId).ToString ("X2"); + + return secure.Fingerprint.EndsWith (id, StringComparison.OrdinalIgnoreCase); + } + + foreach (string userId in key.UserIds) { + if (!MailboxAddress.TryParse (userId, out var email)) + continue; + + if (mailbox.Address.Equals (email.Address, StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; + } + + /// + /// Check if a public key is expired. + /// + /// + /// Checks if a public key is expired. + /// + /// The public key. + /// true if the public key is expired; otherwise, false. + /// + /// is null. + /// + protected static bool IsExpired (PgpPublicKey key) + { + if (key == null) + throw new ArgumentNullException (nameof (key)); + + long seconds = key.GetValidSeconds (); + + if (seconds != 0) { + var expires = key.CreationTime.AddSeconds ((double) seconds); + if (expires <= DateTime.Now) + return true; + } + + return false; + } + + /// + /// Retrieves the public keyring, using the preferred key server, automatically importing it afterwards. + /// + /// The identifier of the key to be retrieved. + /// true if this operation should be done asynchronously; otherweise, false. + /// The cancellation token. + /// The public key ring. + async Task RetrievePublicKeyRingAsync (long keyId, bool doAsync, CancellationToken cancellationToken) + { + if (!IsValidKeyServer) + return null; + + var scheme = keyServer.Scheme.ToLowerInvariant (); + var uri = new UriBuilder (); + + uri.Scheme = scheme == "hkp" ? "http" : scheme; + uri.Host = keyServer.Host; + + if (keyServer.IsDefaultPort) { + if (scheme == "hkp") + uri.Port = 11371; + } else { + uri.Port = keyServer.Port; + } + + uri.Path = "/pks/lookup"; + uri.Query = string.Format (CultureInfo.InvariantCulture, "op=get&search=0x{0:X}", keyId); + + using (var stream = new MemoryBlockStream ()) { + using (var filtered = new FilteredStream (stream)) { + filtered.Add (new OpenPgpBlockFilter (BeginPublicKeyBlock, EndPublicKeyBlock)); + + if (doAsync) { + using (var response = await client.GetAsync (uri.ToString (), cancellationToken).ConfigureAwait (false)) + await response.Content.CopyToAsync (filtered).ConfigureAwait (false); + } else { +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 + var request = (HttpWebRequest) WebRequest.Create (uri.ToString ()); + using (var response = request.GetResponse ()) { + var content = response.GetResponseStream (); + content.CopyTo (filtered, 4096); + } +#else + using (var response = client.GetAsync (uri.ToString (), cancellationToken).GetAwaiter ().GetResult ()) + response.Content.CopyToAsync (filtered).GetAwaiter ().GetResult (); +#endif + } + + filtered.Flush (); + } + + stream.Position = 0; + + using (var armored = new ArmoredInputStream (stream, true)) { + var bundle = new PgpPublicKeyRingBundle (armored); + + Import (bundle); + + return bundle.GetPublicKeyRing (keyId); + } + } + } + + /// + /// Retrieve the public keyring using the configured key server. + /// + /// + /// Retrieves the public keyring specified by the from the key server + /// set on the property. If the keyring is successfully retrieved, it will + /// be imported via . + /// This method should be called by + /// when the keyring is not available locally. + /// + /// The identifier of the public key to be retrieved. + /// The cancellation token. + /// The public key ring. + protected PgpPublicKeyRing RetrievePublicKeyRing (long keyId, CancellationToken cancellationToken) + { + return RetrievePublicKeyRingAsync (keyId, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously retrieve the public keyring using the configured key server. + /// + /// + /// Retrieves the public keyring specified by the from the key server + /// set on the property. If the keyring is successfully retrieved, it will + /// be imported via . + /// This method should be called by + /// when the keyring is not available locally. + /// + /// The identifier of the public key to be retrieved. + /// The cancellation token. + /// The public key ring. + protected Task RetrievePublicKeyRingAsync (long keyId, CancellationToken cancellationToken) + { + return RetrievePublicKeyRingAsync (keyId, true, cancellationToken); + } + + /// + /// Gets the private key from the specified secret key. + /// + /// + /// Gets the private key from the specified secret key. + /// + /// The private key. + /// The secret key. + /// + /// is null. + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + protected PgpPrivateKey GetPrivateKey (PgpSecretKey key) + { + int attempts = 0; + string password; + + if (key == null) + throw new ArgumentNullException (nameof (key)); + + do { + if ((password = GetPasswordForKey (key)) == null) + throw new OperationCanceledException (); + + try { + var privateKey = key.ExtractPrivateKey (password.ToCharArray ()); + + // Note: the private key will be null if the private key is empty. + if (privateKey == null) + break; + + return privateKey; + } catch (Exception ex) { +#if DEBUG + Debug.WriteLine (string.Format ("Failed to extract secret key: {0}", ex)); +#endif + } + + attempts++; + } while (attempts < 3); + + throw new UnauthorizedAccessException (); + } + + /// + /// Gets the equivalent for the + /// specified . + /// + /// + /// Maps a to the equivalent . + /// + /// The hash algorithm. + /// The digest algorithm. + /// + /// is out of range. + /// + /// + /// is not a supported digest algorithm. + /// + public static HashAlgorithmTag GetHashAlgorithm (DigestAlgorithm digestAlgo) + { + switch (digestAlgo) { + case DigestAlgorithm.MD5: return HashAlgorithmTag.MD5; + case DigestAlgorithm.Sha1: return HashAlgorithmTag.Sha1; + case DigestAlgorithm.RipeMD160: return HashAlgorithmTag.RipeMD160; + case DigestAlgorithm.DoubleSha: throw new NotSupportedException ("The Double SHA digest algorithm is not supported."); + case DigestAlgorithm.MD2: return HashAlgorithmTag.MD2; + case DigestAlgorithm.Tiger192: throw new NotSupportedException ("The Tiger-192 digest algorithm is not supported."); + case DigestAlgorithm.Haval5160: throw new NotSupportedException ("The HAVAL 5 160 digest algorithm is not supported."); + case DigestAlgorithm.Sha256: return HashAlgorithmTag.Sha256; + case DigestAlgorithm.Sha384: return HashAlgorithmTag.Sha384; + case DigestAlgorithm.Sha512: return HashAlgorithmTag.Sha512; + case DigestAlgorithm.Sha224: return HashAlgorithmTag.Sha224; + case DigestAlgorithm.MD4: throw new NotSupportedException ("The MD4 digest algorithm is not supported."); + default: throw new ArgumentOutOfRangeException (nameof (digestAlgo)); + } + } + + /// + /// Cryptographically signs the content. + /// + /// + /// Cryptographically signs the content using the specified signer and digest algorithm. + /// + /// A new instance + /// containing the detached signature data. + /// The signer. + /// The digest algorithm to use for signing. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// is out of range. + /// + /// + /// The specified is not supported by this context. + /// + /// + /// A signing key could not be found for . + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public override MimePart Sign (MailboxAddress signer, DigestAlgorithm digestAlgo, Stream content) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var key = GetSigningKey (signer); + + return Sign (key, digestAlgo, content); + } + + /// + /// Cryptographically signs the content. + /// + /// + /// Cryptographically signs the content using the specified signer and digest algorithm. + /// + /// A new instance + /// containing the detached signature data. + /// The signer. + /// The digest algorithm to use for signing. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// cannot be used for signing. + /// + /// + /// The was out of range. + /// + /// + /// The is not supported. + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public ApplicationPgpSignature Sign (PgpSecretKey signer, DigestAlgorithm digestAlgo, Stream content) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + if (!signer.IsSigningKey) + throw new ArgumentException ("The specified secret key cannot be used for signing.", nameof (signer)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var hashAlgorithm = GetHashAlgorithm (digestAlgo); + var memory = new MemoryBlockStream (); + + using (var armored = new ArmoredOutputStream (memory)) { + armored.SetHeader ("Version", null); + + var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); + using (var compressed = compresser.Open (armored)) { + var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + + try { + signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); + + while ((nread = content.Read (buf, 0, BufferLength)) > 0) + signatureGenerator.Update (buf, 0, nread); + } finally { + ArrayPool.Shared.Return (buf); + } + + var signature = signatureGenerator.Generate (); + + signature.Encode (compressed); + compressed.Flush (); + } + + armored.Flush (); + } + + memory.Position = 0; + + return new ApplicationPgpSignature (memory); + } + + /// + /// Gets the equivalent for the specified + /// . + /// + /// + /// Gets the equivalent for the specified + /// . + /// + /// The digest algorithm. + /// The hash algorithm. + /// + /// is out of range. + /// + /// + /// does not have an equivalent value. + /// + public static DigestAlgorithm GetDigestAlgorithm (HashAlgorithmTag hashAlgorithm) + { + switch (hashAlgorithm) { + case HashAlgorithmTag.MD5: return DigestAlgorithm.MD5; + case HashAlgorithmTag.Sha1: return DigestAlgorithm.Sha1; + case HashAlgorithmTag.RipeMD160: return DigestAlgorithm.RipeMD160; + case HashAlgorithmTag.DoubleSha: return DigestAlgorithm.DoubleSha; + case HashAlgorithmTag.MD2: return DigestAlgorithm.MD2; + case HashAlgorithmTag.Tiger192: return DigestAlgorithm.Tiger192; + case HashAlgorithmTag.Haval5pass160: return DigestAlgorithm.Haval5160; + case HashAlgorithmTag.Sha256: return DigestAlgorithm.Sha256; + case HashAlgorithmTag.Sha384: return DigestAlgorithm.Sha384; + case HashAlgorithmTag.Sha512: return DigestAlgorithm.Sha512; + case HashAlgorithmTag.Sha224: return DigestAlgorithm.Sha224; + default: throw new ArgumentOutOfRangeException (nameof (hashAlgorithm)); + } + } + + /// + /// Gets the equivalent for the specified + /// . + /// + /// + /// Gets the equivalent for the specified + /// . + /// + /// The public-key algorithm. + /// The public-key algorithm. + /// + /// is out of range. + /// + /// + /// does not have an equivalent value. + /// + public static PublicKeyAlgorithm GetPublicKeyAlgorithm (PublicKeyAlgorithmTag algorithm) + { + switch (algorithm) { + case PublicKeyAlgorithmTag.RsaGeneral: return PublicKeyAlgorithm.RsaGeneral; + case PublicKeyAlgorithmTag.RsaEncrypt: return PublicKeyAlgorithm.RsaEncrypt; + case PublicKeyAlgorithmTag.RsaSign: return PublicKeyAlgorithm.RsaSign; + case PublicKeyAlgorithmTag.ElGamalGeneral: return PublicKeyAlgorithm.ElGamalGeneral; + case PublicKeyAlgorithmTag.ElGamalEncrypt: return PublicKeyAlgorithm.ElGamalEncrypt; + case PublicKeyAlgorithmTag.Dsa: return PublicKeyAlgorithm.Dsa; + case PublicKeyAlgorithmTag.ECDH: return PublicKeyAlgorithm.EllipticCurve; + case PublicKeyAlgorithmTag.ECDsa: return PublicKeyAlgorithm.EllipticCurveDsa; + case PublicKeyAlgorithmTag.DiffieHellman: return PublicKeyAlgorithm.DiffieHellman; + default: throw new ArgumentOutOfRangeException (nameof (algorithm)); + } + } + + bool TryGetPublicKey (PgpPublicKeyRing keyring, long keyId, out PgpPublicKey pubkey) + { + if (keyring != null) { + foreach (PgpPublicKey key in keyring.GetPublicKeys ()) { + if (key.KeyId == keyId) { + pubkey = key; + return true; + } + } + } + + pubkey = null; + + return false; + } + + async Task GetDigitalSignaturesAsync (PgpSignatureList signatureList, Stream content, bool doAsync, CancellationToken cancellationToken) + { + var signatures = new List (); + + for (int i = 0; i < signatureList.Count; i++) { + long keyId = signatureList[i].KeyId; + PgpPublicKeyRing keyring; + + if (doAsync) + keyring = await GetPublicKeyRingAsync (keyId, cancellationToken).ConfigureAwait (false); + else + keyring = GetPublicKeyRing (keyId, cancellationToken); + + TryGetPublicKey (keyring, keyId, out var key); + + var signature = new OpenPgpDigitalSignature (keyring, key, signatureList[i]) { + PublicKeyAlgorithm = GetPublicKeyAlgorithm (signatureList[i].KeyAlgorithm), + DigestAlgorithm = GetDigestAlgorithm (signatureList[i].HashAlgorithm), + CreationDate = signatureList[i].CreationTime, + }; + + if (key != null) + signatureList[i].InitVerify (key); + + signatures.Add (signature); + } + + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + + try { + while ((nread = content.Read (buf, 0, BufferLength)) > 0) { + for (int i = 0; i < signatures.Count; i++) { + if (signatures[i].SignerCertificate != null) { + var pgp = (OpenPgpDigitalSignature) signatures[i]; + pgp.Signature.Update (buf, 0, nread); + } + } + } + } finally { + ArrayPool.Shared.Return (buf); + } + + return new DigitalSignatureCollection (signatures); + } + + Task VerifyAsync (Stream content, Stream signatureData, bool doAsync, CancellationToken cancellationToken) + { + if (content == null) + throw new ArgumentNullException (nameof (content)); + + if (signatureData == null) + throw new ArgumentNullException (nameof (signatureData)); + + using (var armored = new ArmoredInputStream (signatureData)) { + var factory = new PgpObjectFactory (armored); + var data = factory.NextPgpObject (); + PgpSignatureList signatureList; + + var compressed = data as PgpCompressedData; + if (compressed != null) { + factory = new PgpObjectFactory (compressed.GetDataStream ()); + data = factory.NextPgpObject (); + } + + if (data == null) + throw new FormatException ("Invalid PGP format."); + + signatureList = (PgpSignatureList) data; + + return GetDigitalSignaturesAsync (signatureList, content, doAsync, cancellationToken); + } + } + + /// + /// Verify the specified content using the detached signatureData. + /// + /// + /// Verifies the specified content using the detached signatureData. + /// If any of the signatures were made with an unrecognized key and is enabled, + /// an attempt will be made to retrieve said key(s). The can be used to cancel + /// key retrieval. + /// + /// A list of digital signatures. + /// The content. + /// The signature data. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain valid PGP signature data. + /// + public override DigitalSignatureCollection Verify (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (content, signatureData, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously verify the specified content using the detached signatureData. + /// + /// + /// Verifies the specified content using the detached signatureData. + /// If any of the signatures were made with an unrecognized key and is enabled, + /// an attempt will be made to retrieve said key(s). The can be used to cancel + /// key retrieval. + /// + /// A list of digital signatures. + /// The content. + /// The signature data. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// does not contain valid PGP signature data. + /// + public override Task VerifyAsync (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) + { + return VerifyAsync (content, signatureData, true, cancellationToken); + } + + static Stream Compress (Stream content, byte[] buf, int bufferLength) + { + var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); + var memory = new MemoryBlockStream (); + + using (var compressed = compresser.Open (memory)) { + var literalGenerator = new PgpLiteralDataGenerator (); + + using (var literal = literalGenerator.Open (compressed, 't', "mime.txt", content.Length, DateTime.Now)) { + int nread; + + while ((nread = content.Read (buf, 0, bufferLength)) > 0) + literal.Write (buf, 0, nread); + + literal.Flush (); + } + + compressed.Flush (); + } + + memory.Position = 0; + + return memory; + } + + static Stream Encrypt (PgpEncryptedDataGenerator encrypter, Stream content) + { + var memory = new MemoryBlockStream (); + + using (var armored = new ArmoredOutputStream (memory)) { + var buf = ArrayPool.Shared.Rent (BufferLength); + + try { + armored.SetHeader ("Version", null); + + using (var compressed = Compress (content, buf, BufferLength)) { + using (var encrypted = encrypter.Open (armored, compressed.Length)) { + int nread; + + try { + while ((nread = compressed.Read (buf, 0, BufferLength)) > 0) + encrypted.Write (buf, 0, nread); + } finally { + ArrayPool.Shared.Return (buf); + } + + encrypted.Flush (); + } + } + + armored.Flush (); + } finally { + ArrayPool.Shared.Return (buf); + } + } + + memory.Position = 0; + + return memory; + } + + internal static SymmetricKeyAlgorithmTag GetSymmetricKeyAlgorithm (EncryptionAlgorithm algorithm) + { + switch (algorithm) { + case EncryptionAlgorithm.Aes128: return SymmetricKeyAlgorithmTag.Aes128; + case EncryptionAlgorithm.Aes192: return SymmetricKeyAlgorithmTag.Aes192; + case EncryptionAlgorithm.Aes256: return SymmetricKeyAlgorithmTag.Aes256; + case EncryptionAlgorithm.Camellia128: return SymmetricKeyAlgorithmTag.Camellia128; + case EncryptionAlgorithm.Camellia192: return SymmetricKeyAlgorithmTag.Camellia192; + case EncryptionAlgorithm.Camellia256: return SymmetricKeyAlgorithmTag.Camellia256; + case EncryptionAlgorithm.Cast5: return SymmetricKeyAlgorithmTag.Cast5; + case EncryptionAlgorithm.Des: return SymmetricKeyAlgorithmTag.Des; + case EncryptionAlgorithm.TripleDes: return SymmetricKeyAlgorithmTag.TripleDes; + case EncryptionAlgorithm.Idea: return SymmetricKeyAlgorithmTag.Idea; + case EncryptionAlgorithm.Blowfish: return SymmetricKeyAlgorithmTag.Blowfish; + case EncryptionAlgorithm.Twofish: return SymmetricKeyAlgorithmTag.Twofish; + default: throw new NotSupportedException (string.Format ("{0} is not supported.", algorithm)); + } + } + + /// + /// Encrypt the specified content for the specified recipients. + /// + /// + /// Encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// A public key could not be found for one or more of the . + /// + public override MimePart Encrypt (IEnumerable recipients, Stream content) + { + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + // TODO: document the exceptions that can be thrown by BouncyCastle + return Encrypt (GetPublicKeys (recipients), content); + } + + /// + /// Encrypt the specified content for the specified recipients. + /// + /// + /// Encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The encryption algorithm. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// A public key could not be found for one or more of the . + /// + /// + /// The specified encryption algorithm is not supported. + /// + public MimePart Encrypt (EncryptionAlgorithm algorithm, IEnumerable recipients, Stream content) + { + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + // TODO: document the exceptions that can be thrown by BouncyCastle + return Encrypt (algorithm, GetPublicKeys (recipients), content); + } + + /// + /// Encrypt the specified content for the specified recipients. + /// + /// + /// Encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The encryption algorithm. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// The specified encryption algorithm is not supported. + /// + public MimePart Encrypt (EncryptionAlgorithm algorithm, IEnumerable recipients, Stream content) + { + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (algorithm), true); + var unique = new HashSet (); + int count = 0; + + foreach (var recipient in recipients) { + if (!recipient.IsEncryptionKey) + throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", nameof (recipients)); + + if (unique.Add (recipient.KeyId)) { + encrypter.AddMethod (recipient); + count++; + } + } + + if (count == 0) + throw new ArgumentException ("No recipients specified.", nameof (recipients)); + + var encrypted = Encrypt (encrypter, content); + + return new MimePart ("application", "octet-stream") { + ContentDisposition = new ContentDisposition (ContentDisposition.Attachment), + Content = new MimeContent (encrypted), + }; + } + + /// + /// Encrypt the specified content for the specified recipients. + /// + /// + /// Encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + public MimePart Encrypt (IEnumerable recipients, Stream content) + { + return Encrypt (defaultAlgorithm, recipients, content); + } + + /// + /// Cryptographically sign and encrypt the specified content for the specified recipients. + /// + /// + /// Cryptographically signs and encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The signer. + /// The digest algorithm to use for signing. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// is out of range. + /// + /// + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// The specified is not supported by this context. + /// + /// + /// The private key could not be found for . + /// + /// + /// A public key could not be found for one or more of the . + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public MimePart SignAndEncrypt (MailboxAddress signer, DigestAlgorithm digestAlgo, IEnumerable recipients, Stream content) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var key = GetSigningKey (signer); + + return SignAndEncrypt (key, digestAlgo, GetPublicKeys (recipients), content); + } + + /// + /// Cryptographically sign and encrypt the specified content for the specified recipients. + /// + /// + /// Cryptographically signs and encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The signer. + /// The digest algorithm to use for signing. + /// The encryption algorithm. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// cannot be used for signing. + /// -or- + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// The specified encryption algorithm is not supported. + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public MimePart SignAndEncrypt (MailboxAddress signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable recipients, Stream content) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var key = GetSigningKey (signer); + + return SignAndEncrypt (key, digestAlgo, cipherAlgo, GetPublicKeys (recipients), content); + } + + /// + /// Cryptographically sign and encrypt the specified content for the specified recipients. + /// + /// + /// Cryptographically signs and encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The signer. + /// The digest algorithm to use for signing. + /// The encryption algorithm. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// cannot be used for signing. + /// -or- + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// The specified encryption algorithm is not supported. + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable recipients, Stream content) + { + if (signer == null) + throw new ArgumentNullException (nameof (signer)); + + if (!signer.IsSigningKey) + throw new ArgumentException ("The specified secret key cannot be used for signing.", nameof (signer)); + + if (recipients == null) + throw new ArgumentNullException (nameof (recipients)); + + if (content == null) + throw new ArgumentNullException (nameof (content)); + + var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (cipherAlgo), true); + var hashAlgorithm = GetHashAlgorithm (digestAlgo); + var unique = new HashSet (); + int count = 0; + + foreach (var recipient in recipients) { + if (!recipient.IsEncryptionKey) + throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", nameof (recipients)); + + if (unique.Add (recipient.KeyId)) { + encrypter.AddMethod (recipient); + count++; + } + } + + if (count == 0) + throw new ArgumentException ("No recipients specified.", nameof (recipients)); + + var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); + + using (var compressed = new MemoryBlockStream ()) { + using (var signed = compresser.Open (compressed)) { + var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); + signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); + var subpacket = new PgpSignatureSubpacketGenerator (); + + foreach (string userId in signer.PublicKey.GetUserIds ()) { + subpacket.SetSignerUserId (false, userId); + break; + } + + signatureGenerator.SetHashedSubpackets (subpacket.Generate ()); + + var onepass = signatureGenerator.GenerateOnePassVersion (false); + onepass.Encode (signed); + + var literalGenerator = new PgpLiteralDataGenerator (); + using (var literal = literalGenerator.Open (signed, 't', "mime.txt", content.Length, DateTime.Now)) { + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + + try { + while ((nread = content.Read (buf, 0, BufferLength)) > 0) { + signatureGenerator.Update (buf, 0, nread); + literal.Write (buf, 0, nread); + } + } finally { + ArrayPool.Shared.Return (buf); + } + + literal.Flush (); + } + + var signature = signatureGenerator.Generate (); + signature.Encode (signed); + + signed.Flush (); + } + + compressed.Position = 0; + + var memory = new MemoryBlockStream (); + + using (var armored = new ArmoredOutputStream (memory)) { + armored.SetHeader ("Version", null); + + using (var encrypted = encrypter.Open (armored, compressed.Length)) { + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + + try { + while ((nread = compressed.Read (buf, 0, BufferLength)) > 0) + encrypted.Write (buf, 0, nread); + } finally { + ArrayPool.Shared.Return (buf); + } + + encrypted.Flush (); + } + + armored.Flush (); + } + + memory.Position = 0; + + return new MimePart ("application", "octet-stream") { + ContentDisposition = new ContentDisposition (ContentDisposition.Attachment), + Content = new MimeContent (memory) + }; + } + } + + /// + /// Cryptographically sign and encrypt the specified content for the specified recipients. + /// + /// + /// Cryptographically signs and encrypts the specified content for the specified recipients. + /// + /// A new instance + /// containing the encrypted data. + /// The signer. + /// The digest algorithm to use for signing. + /// The recipients. + /// The content. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// cannot be used for signing. + /// -or- + /// One or more of the recipient keys cannot be used for encrypting. + /// -or- + /// No recipients were specified. + /// + /// + /// The user chose to cancel the password prompt. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable recipients, Stream content) + { + return SignAndEncrypt (signer, digestAlgo, defaultAlgorithm, recipients, content); + } + + async Task DecryptToAsync (Stream encryptedData, Stream decryptedData, bool doAsync, CancellationToken cancellationToken) + { + if (encryptedData == null) + throw new ArgumentNullException (nameof (encryptedData)); + + if (decryptedData == null) + throw new ArgumentNullException (nameof (decryptedData)); + + using (var armored = new ArmoredInputStream (encryptedData)) { + var factory = new PgpObjectFactory (armored); + var obj = factory.NextPgpObject (); + var list = obj as PgpEncryptedDataList; + + if (list == null) { + // probably a PgpMarker... + obj = factory.NextPgpObject (); + + list = obj as PgpEncryptedDataList; + + if (list == null) + throw new PgpException ("Unexpected OpenPGP packet."); + } + + PgpPublicKeyEncryptedData encrypted = null; + PrivateKeyNotFoundException pkex = null; + bool hasEncryptedPackets = false; + PgpSecretKey secret = null; + + foreach (PgpEncryptedData data in list.GetEncryptedDataObjects ()) { + if ((encrypted = data as PgpPublicKeyEncryptedData) == null) + continue; + + hasEncryptedPackets = true; + + try { + secret = GetSecretKey (encrypted.KeyId); + break; + } catch (PrivateKeyNotFoundException ex) { + pkex = ex; + } + } + + if (!hasEncryptedPackets) + throw new PgpException ("No encrypted packets found."); + + if (secret == null) + throw pkex; + + factory = new PgpObjectFactory (encrypted.GetDataStream (GetPrivateKey (secret))); + List onepassList = null; + DigitalSignatureCollection signatures; + PgpSignatureList signatureList = null; + PgpCompressedData compressed = null; + var position = decryptedData.Position; + long nwritten = 0; + + obj = factory.NextPgpObject (); + while (obj != null) { + if (obj is PgpCompressedData) { + if (compressed != null) + throw new PgpException ("Recursive compression packets are not supported."); + + compressed = (PgpCompressedData) obj; + factory = new PgpObjectFactory (compressed.GetDataStream ()); + } else if (obj is PgpOnePassSignatureList) { + if (nwritten == 0) { + var onepasses = (PgpOnePassSignatureList) obj; + + onepassList = new List (); + + for (int i = 0; i < onepasses.Count; i++) { + var onepass = onepasses[i]; + PgpPublicKeyRing keyring; + + if (doAsync) + keyring = await GetPublicKeyRingAsync (onepass.KeyId, cancellationToken).ConfigureAwait (false); + else + keyring = GetPublicKeyRing (onepass.KeyId, cancellationToken); + + if (!TryGetPublicKey (keyring, onepass.KeyId, out var key)) { + // too messy, pretend we never found a one-pass signature list + onepassList = null; + break; + } + + onepass.InitVerify (key); + + var signature = new OpenPgpDigitalSignature (keyring, key, onepass) { + PublicKeyAlgorithm = GetPublicKeyAlgorithm (onepass.KeyAlgorithm), + DigestAlgorithm = GetDigestAlgorithm (onepass.HashAlgorithm), + }; + + onepassList.Add (signature); + } + } + } else if (obj is PgpSignatureList) { + signatureList = (PgpSignatureList) obj; + } else if (obj is PgpLiteralData) { + var literal = (PgpLiteralData) obj; + + using (var stream = literal.GetDataStream ()) { + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + + try { + while ((nread = stream.Read (buf, 0, BufferLength)) > 0) { + if (onepassList != null) { + // update our one-pass signatures... + for (int index = 0; index < nread; index++) { + byte c = buf[index]; + + for (int i = 0; i < onepassList.Count; i++) { + var pgp = (OpenPgpDigitalSignature) onepassList[i]; + pgp.OnePassSignature.Update (c); + } + } + } + + if (doAsync) + await decryptedData.WriteAsync (buf, 0, nread, cancellationToken).ConfigureAwait (false); + else + decryptedData.Write (buf, 0, nread); + + nwritten += nread; + } + } finally { + ArrayPool.Shared.Return (buf); + } + } + } + + obj = factory.NextPgpObject (); + } + + if (signatureList != null) { + if (onepassList != null && signatureList.Count == onepassList.Count) { + for (int i = 0; i < onepassList.Count; i++) { + var pgp = (OpenPgpDigitalSignature) onepassList[i]; + pgp.CreationDate = signatureList[i].CreationTime; + pgp.Signature = signatureList[i]; + } + + signatures = new DigitalSignatureCollection (onepassList); + } else { + decryptedData.Position = position; + signatures = await GetDigitalSignaturesAsync (signatureList, decryptedData, doAsync, cancellationToken).ConfigureAwait (false); + decryptedData.Position = decryptedData.Length; + } + } else { + signatures = null; + } + + return signatures; + } + } + + /// + /// Decrypt an encrypted stream and extract the digital signers if the content was also signed. + /// + /// + /// Decrypts an encrypted stream and extracts the digital signers if the content was also signed. + /// If any of the signatures were made with an unrecognized key and is enabled, + /// an attempt will be made to retrieve said key(s). The can be used to cancel + /// key retrieval. + /// + /// The list of digital signatures if the data was both signed and encrypted; otherwise, null. + /// The encrypted data. + /// The stream to write the decrypted data to. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// The private key could not be found to decrypt the stream. + /// + /// + /// The user chose to cancel the password prompt. + /// -or- + /// The operation was cancelled via the cancellation token. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + /// + /// An OpenPGP error occurred. + /// + public DigitalSignatureCollection DecryptTo (Stream encryptedData, Stream decryptedData, CancellationToken cancellationToken = default (CancellationToken)) + { + return DecryptToAsync (encryptedData, decryptedData, false, cancellationToken).GetAwaiter ().GetResult (); + } + + /// + /// Asynchronously decrypt an encrypted stream and extract the digital signers if the content was also signed. + /// + /// + /// Decrypts an encrypted stream and extracts the digital signers if the content was also signed. + /// If any of the signatures were made with an unrecognized key and is enabled, + /// an attempt will be made to retrieve said key(s). The can be used to cancel + /// key retrieval. + /// + /// The list of digital signatures if the data was both signed and encrypted; otherwise, null. + /// The encrypted data. + /// The stream to write the decrypted data to. + /// The cancellation token. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// The private key could not be found to decrypt the stream. + /// + /// + /// The user chose to cancel the password prompt. + /// -or- + /// The operation was cancelled via the cancellation token. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + /// + /// An OpenPGP error occurred. + /// + public Task DecryptToAsync (Stream encryptedData, Stream decryptedData, CancellationToken cancellationToken = default (CancellationToken)) + { + return DecryptToAsync (encryptedData, decryptedData, true, cancellationToken); + } + + /// + /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. + /// + /// + /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. + /// + /// The decrypted . + /// The encrypted data. + /// A list of digital signatures if the data was both signed and encrypted. + /// The cancellation token. + /// + /// is null. + /// + /// + /// The private key could not be found to decrypt the stream. + /// + /// + /// The user chose to cancel the password prompt. + /// -or- + /// The operation was cancelled via the cancellation token. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + /// + /// An OpenPGP error occurred. + /// + public MimeEntity Decrypt (Stream encryptedData, out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default (CancellationToken)) + { + using (var decryptedData = new MemoryBlockStream ()) { + signatures = DecryptTo (encryptedData, decryptedData, cancellationToken); + decryptedData.Position = 0; + + return MimeEntity.Load (decryptedData, cancellationToken); + } + } + + /// + /// Decrypts the specified encryptedData. + /// + /// + /// Decrypts the specified encryptedData. + /// + /// The decrypted . + /// The encrypted data. + /// The cancellation token. + /// + /// is null. + /// + /// + /// The private key could not be found to decrypt the stream. + /// + /// + /// The user chose to cancel the password prompt. + /// -or- + /// The operation was cancelled via the cancellation token. + /// + /// + /// 3 bad attempts were made to unlock the secret key. + /// + /// + /// An OpenPGP error occurred. + /// + public override MimeEntity Decrypt (Stream encryptedData, CancellationToken cancellationToken = default (CancellationToken)) + { + using (var decryptedData = new MemoryBlockStream ()) { + DecryptTo (encryptedData, decryptedData, cancellationToken); + decryptedData.Position = 0; + + return MimeEntity.Load (decryptedData, cancellationToken); + } + } + + /// + /// Import the specified public keyring bundle. + /// + /// + /// Imports the specified public keyring bundle. + /// + /// THe bundle of public keyrings to import. + public abstract void Import (PgpPublicKeyRingBundle bundle); + + /// + /// Releases all resources used by the object. + /// + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After + /// calling , you must release all references to the so + /// the garbage collector can reclaim the memory that the was occupying. + protected override void Dispose (bool disposing) + { + if (disposing && client != null) { + client.Dispose (); + client = null; + } + + base.Dispose (disposing); + } + } +} diff --git a/MimeKit/Cryptography/OpenPgpDataType.cs b/MimeKit/Cryptography/OpenPgpDataType.cs index d0b0b7908c..55cdc30718 100644 --- a/MimeKit/Cryptography/OpenPgpDataType.cs +++ b/MimeKit/Cryptography/OpenPgpDataType.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/OpenPgpDetectionFilter.cs b/MimeKit/Cryptography/OpenPgpDetectionFilter.cs index 0ea3f0dd9c..ea9c7574c5 100644 --- a/MimeKit/Cryptography/OpenPgpDetectionFilter.cs +++ b/MimeKit/Cryptography/OpenPgpDetectionFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -84,7 +84,7 @@ public OpenPgpMarker (string marker, OpenPgpState initial, OpenPgpState detected bool midline; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -300,10 +300,7 @@ protected override byte[] Filter (byte[] input, int startIndex, int length, out return input; } - outputLength = index - outputIndex; - position += index - startIndex; - - return input; + break; } index++; diff --git a/MimeKit/Cryptography/OpenPgpDigitalCertificate.cs b/MimeKit/Cryptography/OpenPgpDigitalCertificate.cs index 60102de14e..bba0c865a5 100644 --- a/MimeKit/Cryptography/OpenPgpDigitalCertificate.cs +++ b/MimeKit/Cryptography/OpenPgpDigitalCertificate.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -139,7 +139,11 @@ public DateTime CreationDate { /// /// The expiration date. public DateTime ExpirationDate { - get { return CreationDate.AddSeconds ((double) PublicKey.GetValidSeconds ()); } + get { + long seconds = PublicKey.GetValidSeconds (); + + return seconds > 0 ? CreationDate.AddSeconds ((double) seconds) : DateTime.MaxValue; + } } /// diff --git a/MimeKit/Cryptography/OpenPgpDigitalSignature.cs b/MimeKit/Cryptography/OpenPgpDigitalSignature.cs index 74efaa9d2e..f74e079af3 100644 --- a/MimeKit/Cryptography/OpenPgpDigitalSignature.cs +++ b/MimeKit/Cryptography/OpenPgpDigitalSignature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ // using System; +using System.Globalization; using Org.BouncyCastle.Bcpg.OpenPgp; @@ -112,7 +113,7 @@ public DateTime CreationDate { /// /// Verifies the digital signature. /// - /// true if the signature is valid; otherwise false. + /// true if the signature is valid; otherwise, false. /// /// An error verifying the signature has occurred. /// @@ -125,7 +126,7 @@ public bool Verify () throw vex; if (SignerCertificate == null) { - var message = string.Format ("Failed to verify digital signature: no public key found for {0:X8}", (int) Signature.KeyId); + var message = string.Format (CultureInfo.InvariantCulture, "Failed to verify digital signature: no public key found for {0:X8}", (int) Signature.KeyId); vex = new DigitalSignatureVerifyException (Signature.KeyId, message); throw vex; } @@ -143,6 +144,22 @@ public bool Verify () } } + /// + /// Verifies the digital signature. + /// + /// + /// Verifies the digital signature. + /// + /// This option is ignored for OpenPGP digital signatures. + /// true if the signature is valid; otherwise, false. + /// + /// An error verifying the signature has occurred. + /// + public bool Verify (bool verifySignatureOnly) + { + return Verify (); + } + #endregion } } diff --git a/MimeKit/Cryptography/OpenPgpKeyCertification.cs b/MimeKit/Cryptography/OpenPgpKeyCertification.cs index b0b84a2ca6..656315b5c7 100644 --- a/MimeKit/Cryptography/OpenPgpKeyCertification.cs +++ b/MimeKit/Cryptography/OpenPgpKeyCertification.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/PrivateKeyNotFoundException.cs b/MimeKit/Cryptography/PrivateKeyNotFoundException.cs index a297b4b554..b4bf7bb259 100644 --- a/MimeKit/Cryptography/PrivateKeyNotFoundException.cs +++ b/MimeKit/Cryptography/PrivateKeyNotFoundException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ public class PrivateKeyNotFoundException : Exception { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -62,7 +62,7 @@ protected PrivateKeyNotFoundException (SerializationInfo info, StreamingContext #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -81,7 +81,7 @@ public PrivateKeyNotFoundException (MailboxAddress mailbox, string message) : ba } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -100,7 +100,7 @@ public PrivateKeyNotFoundException (string keyid, string message) : base (messag } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -132,12 +132,9 @@ public PrivateKeyNotFoundException (long keyid, string message) : base (message) [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("KeyId", KeyId); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/Cryptography/PublicKeyAlgorithm.cs b/MimeKit/Cryptography/PublicKeyAlgorithm.cs index 7d174ab6ec..8ece4b6096 100644 --- a/MimeKit/Cryptography/PublicKeyAlgorithm.cs +++ b/MimeKit/Cryptography/PublicKeyAlgorithm.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/PublicKeyNotFoundException.cs b/MimeKit/Cryptography/PublicKeyNotFoundException.cs index e1c106cc8b..2221f8f000 100644 --- a/MimeKit/Cryptography/PublicKeyNotFoundException.cs +++ b/MimeKit/Cryptography/PublicKeyNotFoundException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ public class PublicKeyNotFoundException : Exception { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -66,7 +66,7 @@ protected PublicKeyNotFoundException (SerializationInfo info, StreamingContext c #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -95,12 +95,9 @@ public PublicKeyNotFoundException (MailboxAddress mailbox, string message) : bas [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("Mailbox", Mailbox.ToString (true)); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/Cryptography/RsaEncryptionPadding.cs b/MimeKit/Cryptography/RsaEncryptionPadding.cs new file mode 100644 index 0000000000..e009605a8e --- /dev/null +++ b/MimeKit/Cryptography/RsaEncryptionPadding.cs @@ -0,0 +1,251 @@ +// +// RsaEncryptionPadding.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +#if NETCOREAPP3_0 +using System.Security.Cryptography; +#endif + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; + +namespace MimeKit.Cryptography { + /// + /// The RSA encryption padding schemes and parameters used by S/MIME. + /// + /// + /// The RSA encryption padding schemes and parameters used by S/MIME as described in + /// rfc8017. + /// + public sealed class RsaEncryptionPadding : IEquatable + { + /// + /// The PKCS #1 v1.5 encryption padding. + /// + public static readonly RsaEncryptionPadding Pkcs1 = new RsaEncryptionPadding (RsaEncryptionPaddingScheme.Pkcs1, DigestAlgorithm.None); + + /// + /// The Optimal Asymmetric Encryption Padding (OAEP) scheme using the default (SHA-1) hash algorithm. + /// + public static readonly RsaEncryptionPadding OaepSha1 = new RsaEncryptionPadding (RsaEncryptionPaddingScheme.Oaep, DigestAlgorithm.Sha1); + + /// + /// The Optimal Asymmetric Encryption Padding (OAEP) scheme using the SHA-256 hash algorithm. + /// + public static readonly RsaEncryptionPadding OaepSha256 = new RsaEncryptionPadding (RsaEncryptionPaddingScheme.Oaep, DigestAlgorithm.Sha256); + + /// + /// The Optimal Asymmetric Encryption Padding (OAEP) scheme using the SHA-384 hash algorithm. + /// + public static readonly RsaEncryptionPadding OaepSha384 = new RsaEncryptionPadding (RsaEncryptionPaddingScheme.Oaep, DigestAlgorithm.Sha384); + + /// + /// The Optimal Asymmetric Encryption Padding (OAEP) scheme using the SHA-512 hash algorithm. + /// + public static readonly RsaEncryptionPadding OaepSha512 = new RsaEncryptionPadding (RsaEncryptionPaddingScheme.Oaep, DigestAlgorithm.Sha512); + + RsaEncryptionPadding (RsaEncryptionPaddingScheme scheme, DigestAlgorithm oaepHashAlgorithm) + { + OaepHashAlgorithm = oaepHashAlgorithm; + Scheme = scheme; + } + + /// + /// Get the RSA encryption padding scheme. + /// + /// + /// Gets the RSA encryption padding scheme. + /// + /// The RSA encryption padding scheme. + public RsaEncryptionPaddingScheme Scheme { + get; private set; + } + + /// + /// Get the hash algorithm used for RSAES-OAEP padding. + /// + /// + /// Gets the hash algorithm used for RSAES-OAEP padding. + /// + public DigestAlgorithm OaepHashAlgorithm { + get; private set; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// Compares two RSA encryption paddings to determine if they are identical or not. + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. + public bool Equals (RsaEncryptionPadding other) + { + if (other == null) + return false; + + return other.Scheme == Scheme && other.OaepHashAlgorithm == OaepHashAlgorithm; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// + /// The type of comparison between the current instance and the parameter depends on whether + /// the current instance is a reference type or a value type. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals (object obj) + { + return Equals (obj as RsaEncryptionPadding); + } + + /// + /// Returns the hash code for this instance. + /// + /// + /// Returns the hash code for this instance. + /// + /// A hash code for the current object. + public override int GetHashCode () + { + int hash = Scheme.GetHashCode (); + + return ((hash << 5) + hash) ^ OaepHashAlgorithm.GetHashCode (); + } + + /// + /// Returns a that represents the current + /// . + /// + /// + /// Creates a string-representation of the . + /// + /// A that represents the current + /// . + public override string ToString () + { + return Scheme == RsaEncryptionPaddingScheme.Pkcs1 ? "Pkcs1" : "Oaep" + OaepHashAlgorithm.ToString (); + } + + /// + /// Compare two objects for equality. + /// + /// + /// Compares two objects for equality. + /// + /// The first object to compare. + /// The second object to compare. + /// true if and are equal; otherwise, false. + public static bool operator == (RsaEncryptionPadding left, RsaEncryptionPadding right) + { + if (ReferenceEquals (left, null)) + return ReferenceEquals (right, null); + + return left.Equals (right); + } + + /// + /// Compare two objects for inequality. + /// + /// + /// Compares two objects for inequality. + /// + /// The first object to compare. + /// The second object to compare. + /// true if and are unequal; otherwise, false. + public static bool operator != (RsaEncryptionPadding left, RsaEncryptionPadding right) + { + return !(left == right); + } + + /// + /// Create a new using and the specified hash algorithm. + /// + /// + /// Creates a new using and the specified hash algorithm. + /// + /// The hash algorithm. + /// An using and the specified hash algorithm. + /// + /// The is not supported. + /// + public static RsaEncryptionPadding CreateOaep (DigestAlgorithm hashAlgorithm) + { + switch (hashAlgorithm) { + case DigestAlgorithm.Sha1: return OaepSha1; + case DigestAlgorithm.Sha256: return OaepSha256; + case DigestAlgorithm.Sha384: return OaepSha384; + case DigestAlgorithm.Sha512: return OaepSha512; + default: throw new NotSupportedException ($"The {hashAlgorithm} hash algorithm is not supported."); + } + } + + internal RsaesOaepParameters GetRsaesOaepParameters () + { + if (OaepHashAlgorithm == DigestAlgorithm.Sha1) + return new RsaesOaepParameters (); + + var oid = SecureMimeContext.GetDigestOid (OaepHashAlgorithm); + var hashAlgorithm = new AlgorithmIdentifier (new DerObjectIdentifier (oid), DerNull.Instance); + var maskGenFunction = new AlgorithmIdentifier (PkcsObjectIdentifiers.IdMgf1, hashAlgorithm); + + return new RsaesOaepParameters (hashAlgorithm, maskGenFunction, RsaesOaepParameters.DefaultPSourceAlgorithm); + } + + internal AlgorithmIdentifier GetAlgorithmIdentifier () + { + if (Scheme != RsaEncryptionPaddingScheme.Oaep) + return null; + + return new AlgorithmIdentifier (PkcsObjectIdentifiers.IdRsaesOaep, GetRsaesOaepParameters ()); + } + +#if NETCOREAPP3_0 + internal RSAEncryptionPadding AsRSAEncryptionPadding () + { + switch (Scheme) { + case RsaEncryptionPaddingScheme.Oaep: + switch (OaepHashAlgorithm) { + case DigestAlgorithm.Sha1: return RSAEncryptionPadding.OaepSHA1; + case DigestAlgorithm.Sha256: return RSAEncryptionPadding.OaepSHA256; + case DigestAlgorithm.Sha384: return RSAEncryptionPadding.OaepSHA384; + case DigestAlgorithm.Sha512: return RSAEncryptionPadding.OaepSHA512; + default: return null; + } + case RsaEncryptionPaddingScheme.Pkcs1: + return RSAEncryptionPadding.Pkcs1; + default: + return null; + } + } +#endif + } +} diff --git a/MimeKit/Cryptography/RsaEncryptionPaddingScheme.cs b/MimeKit/Cryptography/RsaEncryptionPaddingScheme.cs new file mode 100644 index 0000000000..c867bc3778 --- /dev/null +++ b/MimeKit/Cryptography/RsaEncryptionPaddingScheme.cs @@ -0,0 +1,47 @@ +// +// RsaEncryptionPaddingScheme.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +namespace MimeKit.Cryptography { + /// + /// The RSA encryption padding schemes used by S/MIME. + /// + /// + /// The RSA encryption padding schemes used by S/MIME as described in + /// rfc8017. + /// + public enum RsaEncryptionPaddingScheme + { + /// + /// The PKCS #1 v1.5 encryption padding scheme. + /// + Pkcs1, + + /// + /// The Optimal Asymmetric Encryption Padding (OAEP) scheme. + /// + Oaep + } +} diff --git a/MimeKit/Cryptography/RsaSignaturePadding.cs b/MimeKit/Cryptography/RsaSignaturePadding.cs new file mode 100644 index 0000000000..dce313236e --- /dev/null +++ b/MimeKit/Cryptography/RsaSignaturePadding.cs @@ -0,0 +1,153 @@ +// +// RsaSignaturePadding.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit.Cryptography { + /// + /// The RSA signature padding schemes and parameters used by S/MIME. + /// + /// + /// The RSA signature padding schemes and parameters used by S/MIME as described in + /// rfc8017. + /// + public sealed class RsaSignaturePadding : IEquatable + { + /// + /// The PKCS #1 v1.5 signature padding. + /// + public static readonly RsaSignaturePadding Pkcs1 = new RsaSignaturePadding (RsaSignaturePaddingScheme.Pkcs1); + + /// + /// The Probibilistic Signature Scheme (PSS) padding. + /// + public static readonly RsaSignaturePadding Pss = new RsaSignaturePadding (RsaSignaturePaddingScheme.Pss); + + RsaSignaturePadding (RsaSignaturePaddingScheme scheme) + { + Scheme = scheme; + } + + /// + /// Get the RSA signature padding scheme. + /// + /// + /// Gets the RSA signature padding scheme. + /// + /// The RSA signature padding scheme. + public RsaSignaturePaddingScheme Scheme { + get; private set; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// Compares two RSA Signature paddings to determine if they are identical or not. + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. + public bool Equals (RsaSignaturePadding other) + { + if (other == null) + return false; + + return other.Scheme == Scheme; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// + /// The type of comparison between the current instance and the parameter depends on whether + /// the current instance is a reference type or a value type. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals (object obj) + { + return Equals (obj as RsaSignaturePadding); + } + + /// + /// Returns the hash code for this instance. + /// + /// + /// Returns the hash code for this instance. + /// + /// A hash code for the current object. + public override int GetHashCode () + { + return Scheme.GetHashCode (); + } + + /// + /// Returns a that represents the current + /// . + /// + /// + /// Creates a string-representation of the . + /// + /// A that represents the current + /// . + public override string ToString () + { + return Scheme == RsaSignaturePaddingScheme.Pkcs1 ? "Pkcs1" : "Pss"; + } + + /// + /// Compare two objects for equality. + /// + /// + /// Compares two objects for equality. + /// + /// The first object to compare. + /// The second object to compare. + /// true if and are equal; otherwise, false. + public static bool operator == (RsaSignaturePadding left, RsaSignaturePadding right) + { + if (ReferenceEquals (left, null)) + return ReferenceEquals (right, null); + + return left.Equals (right); + } + + /// + /// Compare two objects for inequality. + /// + /// + /// Compares two objects for inequality. + /// + /// The first object to compare. + /// The second object to compare. + /// true if and are unequal; otherwise, false. + public static bool operator != (RsaSignaturePadding left, RsaSignaturePadding right) + { + return !(left == right); + } + } +} diff --git a/MimeKit/Cryptography/RsaSignaturePaddingScheme.cs b/MimeKit/Cryptography/RsaSignaturePaddingScheme.cs new file mode 100644 index 0000000000..c408c47877 --- /dev/null +++ b/MimeKit/Cryptography/RsaSignaturePaddingScheme.cs @@ -0,0 +1,47 @@ +// +// RsaSignaturePaddingScheme.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +namespace MimeKit.Cryptography { + /// + /// The RSA signature padding schemes used by S/MIME. + /// + /// + /// The RSA signature padding schemes used by S/MIME as described in + /// rfc8017. + /// + public enum RsaSignaturePaddingScheme + { + /// + /// The PKCS #1 v1.5 signature padding scheme. + /// + Pkcs1, + + /// + /// The Probibilistic Signature Scheme (PSS). + /// + Pss + } +} diff --git a/MimeKit/Cryptography/SQLServerCertificateDatabase.cs b/MimeKit/Cryptography/SQLServerCertificateDatabase.cs new file mode 100644 index 0000000000..806c94285d --- /dev/null +++ b/MimeKit/Cryptography/SQLServerCertificateDatabase.cs @@ -0,0 +1,297 @@ +// +// SQLServerCertificateDatabase.cs +// +// Author: Rob Blackin +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Text; +using System.Data; +using System.Data.Common; +using System.Collections.Generic; + +using MimeKit.Utils; + +using Org.BouncyCastle.X509; + +namespace MimeKit.Cryptography { + /// + /// An X.509 certificate database built on SQL Server. + /// + /// + /// An X.509 certificate database is used for storing certificates, metdata related to the certificates + /// (such as encryption algorithms supported by the associated client), certificate revocation lists (CRLs), + /// and private keys. + /// This particular database uses SQL Server to store the data. + /// + public class SQLServerCertificateDatabase : SqlCertificateDatabase + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new using the provided SQL Server database connection. + /// + /// The SQL Server connection. + /// The password used for encrypting and decrypting the private keys. + /// + /// is null. + /// -or- + /// is null. + /// + public SQLServerCertificateDatabase (DbConnection connection, string password) : base (connection, password) + { + } + + /// + /// Adds a column to a table. + /// + /// + /// Adds a column to a table. + /// + /// The . + /// The table. + /// The column to add. + protected override void AddTableColumn (DbConnection connection, DataTable table, DataColumn column) + { + var statement = new StringBuilder ("ALTER TABLE "); + int primaryKeys = table.PrimaryKey?.Length ?? 0; + + statement.Append (table.TableName); + statement.Append (" ADD COLUMN "); + Build (statement, table, column, ref primaryKeys); + + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } + } + + /// + /// Create a table. + /// + /// + /// Creates the specified table. + /// + /// The . + /// The table. + protected override void CreateTable (DbConnection connection, DataTable table) + { + var statement = new StringBuilder ($"if not exists (select * from sysobjects where name='{table.TableName}' and xtype='U') "); + int primaryKeys = 0; + + statement.Append ($"Create table {table.TableName} ("); + + foreach (DataColumn column in table.Columns) { + Build (statement, table, column, ref primaryKeys); + statement.Append (", "); + } + + if (table.Columns.Count > 0) + statement.Length -= 2; + + statement.Append (')'); + + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } + } + + static void Build (StringBuilder statement, DataTable table, DataColumn column, ref int primaryKeys) + { + statement.Append (column.ColumnName); + statement.Append (' '); + + if (column.DataType == typeof (long) || column.DataType == typeof (int)) { + if (column.AutoIncrement) + statement.Append ("int identity(1,1)"); + else if (column.DataType == typeof (long)) + statement.Append ("DateTime"); + else + statement.Append ("int"); + } else if (column.DataType == typeof (bool)) { + statement.Append ("bit"); + } else if (column.DataType == typeof (byte[])) { + statement.Append ($"varbinary(4096)"); + } else if (column.DataType == typeof (string)) { + statement.Append ("varchar(256)"); + } else { + throw new NotImplementedException (); + } + + if (table != null && table.PrimaryKey != null && primaryKeys < table.PrimaryKey.Length) { + for (int i = 0; i < table.PrimaryKey.Length; i++) { + if (column == table.PrimaryKey[i]) { + statement.Append (" PRIMARY KEY Clustered"); + primaryKeys++; + break; + } + } + } + + if (!column.AllowDBNull) + statement.Append (" NOT NULL"); + } + + /// + /// Gets the columns for the specified table. + /// + /// + /// Gets the list of columns for the specified table. + /// + /// The . + /// The name of the table. + /// The list of columns. + protected override IList GetTableColumns (DbConnection connection, string tableName) + { + using (var command = connection.CreateCommand ()) { + command.CommandText = $"select top 1 * from {tableName}"; + using (var reader = command.ExecuteReader ()) { + var columns = new List (); + var table = reader.GetSchemaTable (); + + foreach (DataRow row in table.Rows) + columns.Add (new DataColumn { ColumnName = row.Field ("ColumnName") }); + + return columns; + } + } + } + + /// + /// Creates an index for faster table lookups. + /// + /// + /// Creates an index for faster table lookups. + /// + /// The . + /// The name of the table. + /// The names of the columns to index. + protected override void CreateIndex (DbConnection connection, string tableName, string[] columnNames) + { + var indexName = GetIndexName (tableName, columnNames); + var query = string.Format ("IF NOT EXISTS (Select 8 from sys.indexes where name='{0}' and object_id=OBJECT_ID('{1}')) CREATE INDEX {0} ON {1}({2})", indexName, tableName, string.Join (", ", columnNames)); + + using (var command = connection.CreateCommand ()) { + command.CommandText = query; + command.ExecuteNonQuery (); + } + } + + /// + /// Removes an index that is no longer needed. + /// + /// + /// Removes an index that is no longer needed. + /// + /// The . + /// The name of the table. + /// The names of the columns that were indexed. + protected override void RemoveIndex (DbConnection connection, string tableName, string[] columnNames) + { + var indexName = GetIndexName (tableName, columnNames); + var query = string.Format ("IF EXISTS (Select 8 from sys.indexes where name='{0}' and object_id=OBJECT_ID('{1}')) DROP INDEX {0} ON {1}", indexName, tableName); + + using (var command = connection.CreateCommand ()) { + command.CommandText = query; + command.ExecuteNonQuery (); + } + } + + /// + /// Gets the database command to select the record matching the specified certificate. + /// + /// + /// Gets the database command to select the record matching the specified certificate. + /// + /// The database command. + /// The certificate. + /// The fields to return. + protected override DbCommand GetSelectCommand (X509Certificate certificate, X509CertificateRecordFields fields) + { + var fingerprint = certificate.GetFingerprint ().ToLowerInvariant (); + var serialNumber = certificate.SerialNumber.ToString (); + var issuerName = certificate.IssuerDN.ToString (); + var command = Connection.CreateCommand (); + var query = CreateSelectQuery (fields).Replace ("SELECT", "SELECT top 1"); + + // FIXME: Is this really the best way to query for an exact match of a certificate? + query = query.Append (" WHERE ISSUERNAME = @ISSUERNAME AND SERIALNUMBER = @SERIALNUMBER AND FINGERPRINT = @FINGERPRINT"); + command.AddParameterWithValue ("@ISSUERNAME", issuerName); + command.AddParameterWithValue ("@SERIALNUMBER", serialNumber); + command.AddParameterWithValue ("@FINGERPRINT", fingerprint); + + command.CommandText = query.ToString (); + command.CommandType = CommandType.Text; + + return command; + } + + /// + /// Gets the database command to insert the specified certificate record. + /// + /// + /// Gets the database command to insert the specified certificate record. + /// + /// The database command. + /// The certificate record. + protected override DbCommand GetInsertCommand (X509CertificateRecord record) + { + var statement = new StringBuilder ("INSERT INTO CERTIFICATES("); + var variables = new StringBuilder ("VALUES("); + var command = Connection.CreateCommand (); + var columns = CertificatesTable.Columns; + + for (int i = 1; i < columns.Count; i++) { + if (i > 1) { + statement.Append (", "); + variables.Append (", "); + } + + var value = GetValue (record, columns[i].ColumnName); + if (value is DateTime dateTime && dateTime < DateUtils.UnixEpoch) + value = DateUtils.UnixEpoch; + + if (columns[i].ColumnName == "PRIVATEKEY" && value is DBNull) + value = new byte[0]; + + var variable = "@" + columns[i]; + + command.AddParameterWithValue (variable, value); + statement.Append (columns[i]); + variables.Append (variable); + } + + statement.Append (')'); + variables.Append (')'); + + command.CommandText = statement + " " + variables; + command.CommandType = CommandType.Text; + + return command; + } + } +} diff --git a/MimeKit/Cryptography/SecureMailboxAddress.cs b/MimeKit/Cryptography/SecureMailboxAddress.cs index 0dec732e15..c93bd8dc90 100644 --- a/MimeKit/Cryptography/SecureMailboxAddress.cs +++ b/MimeKit/Cryptography/SecureMailboxAddress.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,6 @@ using System.Text; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.Utils; namespace MimeKit.Cryptography { @@ -48,7 +44,7 @@ namespace MimeKit.Cryptography { public class SecureMailboxAddress : MailboxAddress { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified fingerprint. @@ -75,7 +71,7 @@ public SecureMailboxAddress (Encoding encoding, string name, IEnumerable } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified fingerprint. @@ -99,7 +95,7 @@ public SecureMailboxAddress (string name, IEnumerable route, string addr } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified fingerprint. @@ -114,6 +110,7 @@ public SecureMailboxAddress (string name, IEnumerable route, string addr /// -or- /// is null. /// + [Obsolete ("Use new SecureMailboxAddress (string.Empty, route, address, fingerprint) instead.")] public SecureMailboxAddress (IEnumerable route, string address, string fingerprint) : base (route, address) { ValidateFingerprint (fingerprint); @@ -122,7 +119,7 @@ public SecureMailboxAddress (IEnumerable route, string address, string f } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified fingerprint. @@ -146,7 +143,7 @@ public SecureMailboxAddress (Encoding encoding, string name, string address, str } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified fingerprint. @@ -167,7 +164,7 @@ public SecureMailboxAddress (string name, string address, string fingerprint) : } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified address. @@ -186,6 +183,7 @@ public SecureMailboxAddress (string name, string address, string fingerprint) : /// -or- /// is null. /// + [Obsolete ("Use new SecureMailboxAddress (string.Empty, address, fingerprint) instead.")] public SecureMailboxAddress (string address, string fingerprint) : base (address) { ValidateFingerprint (fingerprint); @@ -206,13 +204,13 @@ static void ValidateFingerprint (string fingerprint) /// /// Gets the fingerprint of the certificate and/or key to use for signing or encrypting. - /// - /// /// /// /// A fingerprint is a SHA-1 hash of the raw certificate data and is often used /// as a unique identifier for a particular certificate in a certificate store. /// + /// + /// /// The fingerprint of the certificate. public string Fingerprint { get; private set; diff --git a/MimeKit/Cryptography/SecureMimeContext.cs b/MimeKit/Cryptography/SecureMimeContext.cs index 171d0e36cf..2aa2978f6b 100644 --- a/MimeKit/Cryptography/SecureMimeContext.cs +++ b/MimeKit/Cryptography/SecureMimeContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,10 +31,11 @@ using Org.BouncyCastle.Cms; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.X509; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.Smime; using Org.BouncyCastle.Asn1.Ntt; using Org.BouncyCastle.Asn1.Kisa; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Smime; namespace MimeKit.Cryptography { /// @@ -47,13 +48,14 @@ namespace MimeKit.Cryptography { /// public abstract class SecureMimeContext : CryptographyContext { + static readonly string[] ProtocolSubtypes = { "pkcs7-signature", "pkcs7-mime", "pkcs7-keys", "x-pkcs7-signature", "x-pkcs7-mime", "x-pkcs7-keys" }; internal const X509KeyUsageFlags DigitalSignatureKeyUsageFlags = X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation; internal static readonly int EncryptionAlgorithmCount = Enum.GetValues (typeof (EncryptionAlgorithm)).Length; internal static readonly DerObjectIdentifier Blowfish = new DerObjectIdentifier ("1.3.6.1.4.1.3029.1.2"); internal static readonly DerObjectIdentifier Twofish = new DerObjectIdentifier ("1.3.6.1.4.1.25258.3.3"); /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Enables the following encryption algorithms by default: @@ -159,14 +161,21 @@ public override bool Supports (string protocol) if (protocol == null) throw new ArgumentNullException (nameof (protocol)); - var type = protocol.ToLowerInvariant ().Split (new [] { '/' }); - if (type.Length != 2 || type[0] != "application") + if (!protocol.StartsWith ("application/", StringComparison.OrdinalIgnoreCase)) return false; - if (type[1].StartsWith ("x-", StringComparison.Ordinal)) - type[1] = type[1].Substring (2); + int startIndex = "application/".Length; + int subtypeLength = protocol.Length - startIndex; - return type[1] == "pkcs7-signature" || type[1] == "pkcs7-mime" || type[1] == "pkcs7-keys"; + for (int i = 0; i < ProtocolSubtypes.Length; i++) { + if (subtypeLength != ProtocolSubtypes[i].Length) + continue; + + if (string.Compare (protocol, startIndex, ProtocolSubtypes[i], 0, subtypeLength, StringComparison.OrdinalIgnoreCase) == 0) + return true; + } + + return false; } /// @@ -423,7 +432,7 @@ protected virtual EncryptionAlgorithm GetPreferredEncryptionAlgorithm (CmsRecipi /// /// Compresses the specified stream. /// - /// A new instance + /// A new instance /// containing the compressed content. /// The stream to compress. /// @@ -500,7 +509,7 @@ public virtual void DecompressTo (Stream stream, Stream output) content.ContentStream.CopyTo (output, 4096); } - internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () + internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute (bool includeRsaesOaep) { var capabilities = new SmimeCapabilityVector (); @@ -560,6 +569,13 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () } } + if (includeRsaesOaep) { + capabilities.AddCapability (PkcsObjectIdentifiers.IdRsaesOaep, RsaEncryptionPadding.OaepSha1.GetRsaesOaepParameters ()); + capabilities.AddCapability (PkcsObjectIdentifiers.IdRsaesOaep, RsaEncryptionPadding.OaepSha256.GetRsaesOaepParameters ()); + capabilities.AddCapability (PkcsObjectIdentifiers.IdRsaesOaep, RsaEncryptionPadding.OaepSha384.GetRsaesOaepParameters ()); + capabilities.AddCapability (PkcsObjectIdentifiers.IdRsaesOaep, RsaEncryptionPadding.OaepSha512.GetRsaesOaepParameters ()); + } + return new SmimeCapabilitiesAttribute (capabilities); } @@ -569,7 +585,7 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () /// /// Cryptographically signs and encapsulates the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -586,7 +602,7 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () /// /// Cryptographically signs and encapsulates the content using the specified signer and digest algorithm. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -616,7 +632,7 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () /// /// Cryptographically signs the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -675,7 +691,7 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance + /// A new instance /// containing the encrypted content. /// The recipients. /// The content. @@ -719,6 +735,54 @@ internal SmimeCapabilitiesAttribute GetSecureMimeCapabilitiesAttribute () /// public abstract void Import (Stream stream, string password); + /// + /// Imports certificates and keys from a pkcs12 file. + /// + /// + /// Imports certificates and keys from a pkcs12 file. + /// + /// The raw certificate and key data in pkcs12 format. + /// The password to unlock the stream. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// is a zero-length string, contains only white space, or + /// contains one or more invalid characters. + /// -or- + /// does not contain a private key. + /// -or- + /// does not contain a certificate that could be used for signing. + /// + /// + /// is an invalid file path. + /// + /// + /// The specified file path could not be found. + /// + /// + /// The user does not have access to read the specified file. + /// + /// + /// An I/O error occurred. + /// + /// + /// Importing keys is not supported by this cryptography context. + /// + public virtual void Import (string fileName, string password) + { + if (fileName == null) + throw new ArgumentNullException (nameof (fileName)); + + if (password == null) + throw new ArgumentNullException (nameof (password)); + + using (var stream = File.OpenRead (fileName)) + Import (stream, password); + } + /// /// Imports the specified certificate. /// diff --git a/MimeKit/Cryptography/SecureMimeDigitalCertificate.cs b/MimeKit/Cryptography/SecureMimeDigitalCertificate.cs index 928a258695..073460a142 100644 --- a/MimeKit/Cryptography/SecureMimeDigitalCertificate.cs +++ b/MimeKit/Cryptography/SecureMimeDigitalCertificate.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,6 @@ using System; using Org.BouncyCastle.X509; -using Org.BouncyCastle.Crypto.Parameters; namespace MimeKit.Cryptography { /// @@ -39,7 +38,7 @@ namespace MimeKit.Cryptography { public class SecureMimeDigitalCertificate : IDigitalCertificate { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -50,21 +49,12 @@ public class SecureMimeDigitalCertificate : IDigitalCertificate /// public SecureMimeDigitalCertificate (X509Certificate certificate) { - Certificate = certificate; - - var pubkey = certificate.GetPublicKey (); - if (pubkey is DsaKeyParameters) - PublicKeyAlgorithm = PublicKeyAlgorithm.Dsa; - else if (pubkey is RsaKeyParameters) - PublicKeyAlgorithm = PublicKeyAlgorithm.RsaGeneral; - else if (pubkey is ElGamalKeyParameters) - PublicKeyAlgorithm = PublicKeyAlgorithm.ElGamalGeneral; - else if (pubkey is ECKeyParameters) - PublicKeyAlgorithm = PublicKeyAlgorithm.EllipticCurve; - else if (pubkey is DHKeyParameters) - PublicKeyAlgorithm = PublicKeyAlgorithm.DiffieHellman; + if (certificate == null) + throw new ArgumentNullException (nameof (certificate)); + Certificate = certificate; Fingerprint = certificate.GetFingerprint (); + PublicKeyAlgorithm = certificate.GetPublicKeyAlgorithm (); } /// diff --git a/MimeKit/Cryptography/SecureMimeDigitalSignature.cs b/MimeKit/Cryptography/SecureMimeDigitalSignature.cs index 667be711b5..9739810f8c 100644 --- a/MimeKit/Cryptography/SecureMimeDigitalSignature.cs +++ b/MimeKit/Cryptography/SecureMimeDigitalSignature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,10 +25,17 @@ // using System; +using System.Collections.Generic; using Org.BouncyCastle.Cms; using Org.BouncyCastle.X509; using Org.BouncyCastle.Pkix; +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Smime; +using Org.BouncyCastle.Asn1.X509; + +using MimeKit.Utils; namespace MimeKit.Cryptography { /// @@ -42,9 +49,65 @@ public class SecureMimeDigitalSignature : IDigitalSignature DigitalSignatureVerifyException vex; bool? valid; - internal SecureMimeDigitalSignature (SignerInformation signerInfo) + static DateTime ToAdjustedDateTime (DerUtcTime time) { + //try { + // return time.ToAdjustedDateTime (); + //} catch { + return DateUtils.Parse (time.AdjustedTimeString, "yyyyMMddHHmmsszzz"); + //} + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The information about the signer. + /// The signer's certificate. + /// + /// is null. + /// + public SecureMimeDigitalSignature (SignerInformation signerInfo, X509Certificate certificate) + { + if (signerInfo == null) + throw new ArgumentNullException (nameof (signerInfo)); + SignerInfo = signerInfo; + + var algorithms = new List (); + DigestAlgorithm digestAlgo; + + if (signerInfo.SignedAttributes != null) { + Asn1EncodableVector vector = signerInfo.SignedAttributes.GetAll (CmsAttributes.SigningTime); + foreach (Org.BouncyCastle.Asn1.Cms.Attribute attr in vector) { + var signingTime = (DerUtcTime) ((DerSet) attr.AttrValues)[0]; + CreationDate = ToAdjustedDateTime (signingTime); + break; + } + + vector = signerInfo.SignedAttributes.GetAll (SmimeAttributes.SmimeCapabilities); + foreach (Org.BouncyCastle.Asn1.Cms.Attribute attr in vector) { + foreach (Asn1Sequence sequence in attr.AttrValues) { + for (int i = 0; i < sequence.Count; i++) { + var identifier = AlgorithmIdentifier.GetInstance (sequence[i]); + EncryptionAlgorithm algorithm; + + if (BouncyCastleSecureMimeContext.TryGetEncryptionAlgorithm (identifier, out algorithm)) + algorithms.Add (algorithm); + } + } + } + } + + EncryptionAlgorithms = algorithms.ToArray (); + + if (BouncyCastleSecureMimeContext.TryGetDigestAlgorithm (signerInfo.DigestAlgorithmID, out digestAlgo)) + DigestAlgorithm = digestAlgo; + + if (certificate != null) + SignerCertificate = new SecureMimeDigitalCertificate (certificate); } /// @@ -68,7 +131,7 @@ public SignerInformation SignerInfo { /// /// The S/MIME encryption algorithms. public EncryptionAlgorithm[] EncryptionAlgorithms { - get; internal set; + get; private set; } /// @@ -104,7 +167,7 @@ public Exception ChainException { /// /// The signer's certificate. public IDigitalCertificate SignerCertificate { - get; internal set; + get; private set; } /// @@ -115,7 +178,7 @@ public IDigitalCertificate SignerCertificate { /// /// The public key algorithm. public PublicKeyAlgorithm PublicKeyAlgorithm { - get { return PublicKeyAlgorithm.None; } + get { return SignerCertificate != null ? SignerCertificate.PublicKeyAlgorithm : PublicKeyAlgorithm.None; } } /// @@ -126,7 +189,7 @@ public PublicKeyAlgorithm PublicKeyAlgorithm { /// /// The digest algorithm. public DigestAlgorithm DigestAlgorithm { - get; internal set; + get; private set; } /// @@ -137,7 +200,7 @@ public DigestAlgorithm DigestAlgorithm { /// /// The creation date in coordinated universal time (UTC). public DateTime CreationDate { - get; internal set; + get; private set; } /// @@ -146,39 +209,55 @@ public DateTime CreationDate { /// /// Verifies the digital signature. /// - /// true if the signature is valid; otherwise false. + /// true if the signature is valid; otherwise, false. /// /// An error verifying the signature has occurred. /// public bool Verify () { - if (valid.HasValue) - return valid.Value; + return Verify (false); + } + /// + /// Verifies the digital signature. + /// + /// + /// Verifies the digital signature. + /// + /// true if only the signature itself should be verified; otherwise, both the signature and the certificate chain are validated. + /// true if the signature is valid; otherwise, false. + /// + /// An error verifying the signature has occurred. + /// + public bool Verify (bool verifySignatureOnly) + { if (vex != null) throw vex; if (SignerCertificate == null) { - var message = string.Format ("Failed to verify digital signature: missing certificate."); + var message = "Failed to verify digital signature: missing certificate."; vex = new DigitalSignatureVerifyException (message); throw vex; } - if (ChainException != null) { - var message = string.Format ("Failed to verify digital signature: {0}", ChainException.Message); - vex = new DigitalSignatureVerifyException (message, ChainException); - throw vex; + if (!valid.HasValue) { + try { + var certificate = ((SecureMimeDigitalCertificate) SignerCertificate).Certificate; + valid = SignerInfo.Verify (certificate); + } catch (Exception ex) { + var message = string.Format ("Failed to verify digital signature: {0}", ex.Message); + vex = new DigitalSignatureVerifyException (message, ex); + throw vex; + } } - try { - var certificate = ((SecureMimeDigitalCertificate) SignerCertificate).Certificate; - valid = SignerInfo.Verify (certificate); - return valid.Value; - } catch (Exception ex) { - var message = string.Format ("Failed to verify digital signature: {0}", ex.Message); - vex = new DigitalSignatureVerifyException (message, ex); - throw vex; + if (!verifySignatureOnly && ChainException != null) { + var message = string.Format ("Failed to verify digital signature chain: {0}", ChainException.Message); + + throw new DigitalSignatureVerifyException (message, ChainException); } + + return valid.Value; } #endregion diff --git a/MimeKit/Cryptography/SecureMimeType.cs b/MimeKit/Cryptography/SecureMimeType.cs index 00f0cf0438..150e0022f2 100644 --- a/MimeKit/Cryptography/SecureMimeType.cs +++ b/MimeKit/Cryptography/SecureMimeType.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,28 +33,33 @@ namespace MimeKit.Cryptography { /// public enum SecureMimeType { /// - /// S/MIME compressed data. + /// The S/MIME data type is unknown. + /// + Unknown = -1, + + /// + /// The S/MIME content is compressed. /// CompressedData, /// - /// S/MIME enveloped data. + /// The S/MIME content is encrypted. /// EnvelopedData, /// - /// S/MIME signed data. + /// The S/MIME content is signed. /// SignedData, /// - /// S/MIME certificate data. + /// The S/MIME content contains only certificates. /// CertsOnly, /// - /// The S/MIME data type is unknown. + /// The S/MIME content is both signed and encrypted. /// - Unknown + AuthEnvelopedData, } } diff --git a/MimeKit/Cryptography/SqlCertificateDatabase.cs b/MimeKit/Cryptography/SqlCertificateDatabase.cs index 603b0af1f2..bffa3863ec 100644 --- a/MimeKit/Cryptography/SqlCertificateDatabase.cs +++ b/MimeKit/Cryptography/SqlCertificateDatabase.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ using System.Data; using System.Text; using System.Data.Common; +using System.Collections.Generic; #if __MOBILE__ using Mono.Data.Sqlite; @@ -35,6 +36,7 @@ using System.Reflection; #endif +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.X509; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.X509.Store; @@ -51,11 +53,10 @@ namespace MimeKit.Cryptography { /// public abstract class SqlCertificateDatabase : X509CertificateDatabase { - readonly DbConnection connection; bool disposed; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new using the provided database connection. @@ -72,40 +73,219 @@ protected SqlCertificateDatabase (DbConnection connection, string password) : ba if (connection == null) throw new ArgumentNullException (nameof (connection)); - this.connection = connection; + Connection = connection; if (connection.State != ConnectionState.Open) connection.Open (); - CreateCertificatesTable (); - CreateCrlsTable (); + CertificatesTable = CreateCertificatesDataTable ("CERTIFICATES"); + CrlsTable = CreateCrlsDataTable ("CRLS"); + + CreateCertificatesTable (CertificatesTable); + CreateCrlsTable (CrlsTable); + } + + /// + /// Gets the database connection. + /// + /// + /// Gets the database connection. + /// + /// The database connection. + protected DbConnection Connection { + get; private set; // TODO: push this down into X509CertificateDatabase and fix GetSelectCommand()/GetInsertCommand()/etc to take a DbConnection arg, then this could be private. + } + + /// + /// Gets the X.509 certificate table definition. + /// + /// + /// Gets the X.509 certificate table definition. + /// + /// The X.509 certificates table definition. + protected DataTable CertificatesTable { + get; private set; + } + + /// + /// Gets the X.509 certificate revocation lists (CRLs) table definition. + /// + /// + /// Gets the X.509 certificate revocation lists (CRLs) table definition. + /// + /// The X.509 certificate revocation lists table definition. + protected DataTable CrlsTable { + get; private set; + } + +#if NETSTANDARD1_3 || NETSTANDARD1_6 +#pragma warning disable 1591 + protected class DataColumn + { + public DataColumn (string columnName, Type dataType) + { + ColumnName = columnName; + DataType = dataType; + } + + public DataColumn () + { + } + + public bool AllowDBNull { + get; set; + } + + public bool AutoIncrement { + get; set; + } + + public string ColumnName { + get; set; + } + + public Type DataType { + get; set; + } + + public bool Unique { + get; set; + } + } + + protected class DataColumnCollection : List + { + public int IndexOf (string columnName) + { + for (int i = 0; i < Count; i++) { + if (this[i].ColumnName.Equals (columnName, StringComparison.Ordinal)) + return i; + } + + return -1; + } + } + + protected class DataTable + { + public DataTable (string tableName) + { + Columns = new DataColumnCollection (); + TableName = tableName; + } + + public string TableName { + get; set; + } + + public DataColumnCollection Columns { + get; private set; + } + + public DataColumn[] PrimaryKey { + get; set; + } + } +#pragma warning restore 1591 +#endif + + static DataTable CreateCertificatesDataTable (string tableName) + { + var table = new DataTable (tableName); + table.Columns.Add (new DataColumn ("ID", typeof (int)) { AutoIncrement = true }); + table.Columns.Add (new DataColumn ("TRUSTED", typeof (bool)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("ANCHOR", typeof (bool)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("BASICCONSTRAINTS", typeof (int)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("KEYUSAGE", typeof (int)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("NOTBEFORE", typeof (long)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("NOTAFTER", typeof (long)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("ISSUERNAME", typeof (string)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("SERIALNUMBER", typeof (string)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("SUBJECTNAME", typeof (string)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("SUBJECTKEYIDENTIFIER", typeof (string)) { AllowDBNull = true }); + table.Columns.Add (new DataColumn ("SUBJECTEMAIL", typeof (string)) { AllowDBNull = true }); + table.Columns.Add (new DataColumn ("FINGERPRINT", typeof (string)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("ALGORITHMS", typeof (string)) { AllowDBNull = true }); + table.Columns.Add (new DataColumn ("ALGORITHMSUPDATED", typeof (long)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("CERTIFICATE", typeof (byte[])) { AllowDBNull = false, Unique = true }); + table.Columns.Add (new DataColumn ("PRIVATEKEY", typeof (byte[])) { AllowDBNull = true }); + table.PrimaryKey = new DataColumn[] { table.Columns[0] }; + + return table; } + static DataTable CreateCrlsDataTable (string tableName) + { + var table = new DataTable (tableName); + table.Columns.Add (new DataColumn ("ID", typeof (int)) { AutoIncrement = true }); + table.Columns.Add (new DataColumn ("DELTA", typeof (bool)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("ISSUERNAME", typeof (string)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("THISUPDATE", typeof (long)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("NEXTUPDATE", typeof (long)) { AllowDBNull = false }); + table.Columns.Add (new DataColumn ("CRL", typeof (byte[])) { AllowDBNull = false }); + table.PrimaryKey = new DataColumn[] { table.Columns[0] }; + + return table; + } + + /// + /// Gets the columns for the specified table. + /// + /// + /// Gets the list of columns for the specified table. + /// + /// The . + /// The name of the table. + /// The list of columns. + protected abstract IList GetTableColumns (DbConnection connection, string tableName); + /// - /// Gets the command to create the certificates table. + /// Gets the command to create a table. /// /// - /// Constructs the command to create a certificates table suitable for storing - /// objects. + /// Constructs the command to create a table. /// - /// The . /// The . - protected abstract DbCommand GetCreateCertificatesTableCommand (DbConnection connection); + /// The table. + protected abstract void CreateTable (DbConnection connection, DataTable table); /// - /// Gets the command to create the CRLs table. + /// Adds a column to a table. /// /// - /// Constructs the command to create a CRLs table suitable for storing - /// objects. + /// Adds a column to a table. /// - /// The . /// The . - protected abstract DbCommand GetCreateCrlsTableCommand (DbConnection connection); + /// The table. + /// The column to add. + protected abstract void AddTableColumn (DbConnection connection, DataTable table, DataColumn column); - static void CreateIndex (DbConnection connection, string tableName, string[] columnNames) + /// + /// Gets the name of an index based on the table and columns that it is built against. + /// + /// + /// Gets the name of an index based on the table and columns that it is built against. + /// + /// The name of the table. + /// The names of the columns that are indexed. + /// + protected string GetIndexName (string tableName, string[] columnNames) { - var indexName = string.Format ("{0}_{1}_INDEX", tableName, string.Join ("_", columnNames)); + return string.Format ("{0}_{1}_INDEX", tableName, string.Join ("_", columnNames)); + } + + /// + /// Creates an index for faster table lookups. + /// + /// + /// Creates an index for faster table lookups. + /// + /// The . + /// The name of the table. + /// The names of the columns to index. + protected virtual void CreateIndex (DbConnection connection, string tableName, string[] columnNames) + { + var indexName = GetIndexName (tableName, columnNames); var query = string.Format ("CREATE INDEX IF NOT EXISTS {0} ON {1}({2})", indexName, tableName, string.Join (", ", columnNames)); using (var command = connection.CreateCommand ()) { @@ -114,26 +294,128 @@ static void CreateIndex (DbConnection connection, string tableName, string[] col } } - void CreateCertificatesTable () + /// + /// Removes an index that is no longer needed. + /// + /// + /// Removes an index that is no longer needed. + /// + /// The . + /// The name of the table. + /// The names of the columns that were indexed. + protected virtual void RemoveIndex (DbConnection connection, string tableName, string[] columnNames) { - using (var command = GetCreateCertificatesTableCommand (connection)) + var indexName = GetIndexName (tableName, columnNames); + var query = string.Format ("DROP INDEX IF EXISTS {0}", indexName); + + using (var command = connection.CreateCommand ()) { + command.CommandText = query; command.ExecuteNonQuery (); + } + } + + void CreateCertificatesTable (DataTable table) + { + CreateTable (Connection, table); + + var currentColumns = GetTableColumns (Connection, table.TableName); + bool hasAnchorColumn = false; + + for (int i = 0; i < currentColumns.Count; i++) { + if (currentColumns[i].ColumnName.Equals ("ANCHOR", StringComparison.Ordinal)) { + hasAnchorColumn = true; + break; + } + } + + // Note: The ANCHOR, SUBJECTNAME and SUBJECTKEYIDENTIFIER columns were all added in the same version, + // so if the ANCHOR column is missing, they all are. + if (!hasAnchorColumn) { + using (var transaction = Connection.BeginTransaction ()) { + try { + var column = table.Columns[table.Columns.IndexOf ("ANCHOR")]; + AddTableColumn (Connection, table, column); + + column = table.Columns[table.Columns.IndexOf ("SUBJECTNAME")]; + AddTableColumn (Connection, table, column); + + column = table.Columns[table.Columns.IndexOf ("SUBJECTKEYIDENTIFIER")]; + AddTableColumn (Connection, table, column); + + foreach (var record in Find (null, false, X509CertificateRecordFields.Id | X509CertificateRecordFields.Certificate)) { + var statement = "UPDATE CERTIFICATES SET ANCHOR = @ANCHOR, SUBJECTNAME = @SUBJECTNAME, SUBJECTKEYIDENTIFIER = @SUBJECTKEYIDENTIFIER WHERE ID = @ID"; + + using (var command = Connection.CreateCommand ()) { + command.AddParameterWithValue ("@ID", record.Id); + command.AddParameterWithValue ("@ANCHOR", record.IsAnchor); + command.AddParameterWithValue ("@SUBJECTNAME", record.SubjectName); + command.AddParameterWithValue ("@SUBJECTKEYIDENTIFIER", record.SubjectKeyIdentifier?.AsHex ()); + command.CommandType = CommandType.Text; + command.CommandText = statement; + + command.ExecuteNonQuery (); + } + } + + transaction.Commit (); + } catch { + transaction.Rollback (); + throw; + } + } + + // Remove some old indexes + RemoveIndex (Connection, table.TableName, new[] { "TRUSTED" }); + RemoveIndex (Connection, table.TableName, new[] { "TRUSTED", "BASICCONSTRAINTS", "ISSUERNAME", "SERIALNUMBER" }); + RemoveIndex (Connection, table.TableName, new[] { "BASICCONSTRAINTS", "ISSUERNAME", "SERIALNUMBER" }); + RemoveIndex (Connection, table.TableName, new[] { "BASICCONSTRAINTS", "FINGERPRINT" }); + RemoveIndex (Connection, table.TableName, new[] { "BASICCONSTRAINTS", "SUBJECTEMAIL" }); + } + + // Note: Use "EXPLAIN QUERY PLAN SELECT ... FROM CERTIFICATES WHERE ..." to verify that any indexes we create get used as expected. + + // Index for matching against a specific certificate + CreateIndex (Connection, table.TableName, new [] { "ISSUERNAME", "SERIALNUMBER", "FINGERPRINT" }); - CreateIndex (connection, "CERTIFICATES", new [] { "ISSUERNAME", "SERIALNUMBER", "FINGERPRINT" }); - CreateIndex (connection, "CERTIFICATES", new [] { "BASICCONSTRAINTS", "FINGERPRINT" }); - CreateIndex (connection, "CERTIFICATES", new [] { "BASICCONSTRAINTS", "SUBJECTEMAIL" }); - CreateIndex (connection, "CERTIFICATES", new [] { "TRUSTED" }); - CreateIndex (connection, "CERTIFICATES", new [] { "TRUSTED", "BASICCONSTRAINTS", "ISSUERNAME", "SERIALNUMBER" }); - CreateIndex (connection, "CERTIFICATES", new [] { "BASICCONSTRAINTS", "ISSUERNAME", "SERIALNUMBER" }); + // Index for searching for a certificate based on a SecureMailboxAddress + CreateIndex (Connection, table.TableName, new [] { "BASICCONSTRAINTS", "FINGERPRINT", "NOTBEFORE", "NOTAFTER" }); + + // Index for searching for a certificate based on a MailboxAddress + CreateIndex (Connection, table.TableName, new [] { "BASICCONSTRAINTS", "SUBJECTEMAIL", "NOTBEFORE", "NOTAFTER" }); + + // Index for gathering a list of Trusted Anchors + CreateIndex (Connection, table.TableName, new [] { "TRUSTED", "ANCHOR", "KEYUSAGE" }); } - void CreateCrlsTable () + void CreateCrlsTable (DataTable table) { - using (var command = GetCreateCrlsTableCommand (connection)) - command.ExecuteNonQuery (); + CreateTable (Connection, table); - CreateIndex (connection, "CRLS", new [] { "ISSUERNAME" }); - CreateIndex (connection, "CRLS", new [] { "DELTA", "ISSUERNAME", "THISUPDATE" }); + CreateIndex (Connection, table.TableName, new [] { "ISSUERNAME" }); + CreateIndex (Connection, table.TableName, new [] { "DELTA", "ISSUERNAME", "THISUPDATE" }); + } + + /// + /// Creates a SELECT query string builder for the specified fields of an X.509 certificate record. + /// + /// + /// Creates a SELECT query string builder for the specified fields of an X.509 certificate record. + /// + /// THe X.509 certificate fields. + /// A containing a basic SELECT query string. + protected StringBuilder CreateSelectQuery (X509CertificateRecordFields fields) + { + var query = new StringBuilder ("SELECT "); + var columns = GetColumnNames (fields); + + for (int i = 0; i < columns.Length; i++) { + if (i > 0) + query = query.Append (", "); + + query = query.Append (columns[i]); + } + + return query.Append (" FROM CERTIFICATES"); } /// @@ -147,23 +429,26 @@ void CreateCrlsTable () /// The fields to return. protected override DbCommand GetSelectCommand (X509Certificate certificate, X509CertificateRecordFields fields) { - var query = "SELECT " + string.Join (", ", GetColumnNames (fields)) + " FROM CERTIFICATES "; var fingerprint = certificate.GetFingerprint ().ToLowerInvariant (); var serialNumber = certificate.SerialNumber.ToString (); var issuerName = certificate.IssuerDN.ToString (); - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); + var query = CreateSelectQuery (fields); - command.CommandText = query + "WHERE ISSUERNAME = @ISSUERNAME AND SERIALNUMBER = @SERIALNUMBER AND FINGERPRINT = @FINGERPRINT LIMIT 1"; + // FIXME: Is this really the best way to query for an exact match of a certificate? + query = query.Append (" WHERE ISSUERNAME = @ISSUERNAME AND SERIALNUMBER = @SERIALNUMBER AND FINGERPRINT = @FINGERPRINT LIMIT 1"); command.AddParameterWithValue ("@ISSUERNAME", issuerName); command.AddParameterWithValue ("@SERIALNUMBER", serialNumber); command.AddParameterWithValue ("@FINGERPRINT", fingerprint); + + command.CommandText = query.ToString (); command.CommandType = CommandType.Text; return command; } /// - /// Gets the database command to select the certificate records for the specified mailbox. + /// Get the database command to select the certificate records for the specified mailbox. /// /// /// Gets the database command to select the certificate records for the specified mailbox. @@ -175,85 +460,140 @@ protected override DbCommand GetSelectCommand (X509Certificate certificate, X509 /// The fields to return. protected override DbCommand GetSelectCommand (MailboxAddress mailbox, DateTime now, bool requirePrivateKey, X509CertificateRecordFields fields) { - var query = "SELECT " + string.Join (", ", GetColumnNames (fields)) + " FROM CERTIFICATES"; var secure = mailbox as SecureMailboxAddress; - var command = connection.CreateCommand (); - var constraints = " WHERE "; + var command = Connection.CreateCommand (); + var query = CreateSelectQuery (fields); - constraints += "BASICCONSTRAINTS = @BASICCONSTRAINTS "; + query = query.Append (" WHERE BASICCONSTRAINTS = @BASICCONSTRAINTS "); command.AddParameterWithValue ("@BASICCONSTRAINTS", -1); if (secure != null && !string.IsNullOrEmpty (secure.Fingerprint)) { if (secure.Fingerprint.Length < 40) { - constraints += "AND FINGERPRINT LIKE @FINGERPRINT "; command.AddParameterWithValue ("@FINGERPRINT", secure.Fingerprint.ToLowerInvariant () + "%"); + query = query.Append ("AND FINGERPRINT LIKE @FINGERPRINT "); } else { - constraints += "AND FINGERPRINT = @FINGERPRINT "; command.AddParameterWithValue ("@FINGERPRINT", secure.Fingerprint.ToLowerInvariant ()); + query = query.Append ("AND FINGERPRINT = @FINGERPRINT "); } } else { - constraints += "AND SUBJECTEMAIL = @SUBJECTEMAIL "; command.AddParameterWithValue ("@SUBJECTEMAIL", mailbox.Address.ToLowerInvariant ()); + query = query.Append ("AND SUBJECTEMAIL = @SUBJECTEMAIL "); } - constraints += "AND NOTBEFORE < @NOW AND NOTAFTER > @NOW "; + query = query.Append ("AND NOTBEFORE < @NOW AND NOTAFTER > @NOW"); command.AddParameterWithValue ("@NOW", now.ToUniversalTime ()); if (requirePrivateKey) - constraints += "AND PRIVATEKEY IS NOT NULL"; + query = query.Append (" AND PRIVATEKEY IS NOT NULL"); - command.CommandText = query + constraints; + command.CommandText = query.ToString (); command.CommandType = CommandType.Text; return command; } /// - /// Gets the database command to select the certificate records for the specified mailbox. + /// Get the database command to select the requested certificate records. /// /// - /// Gets the database command to select the certificate records for the specified mailbox. + /// Gets the database command to select the requested certificate records. /// /// The database command. - /// Selector. - /// If set to true trusted only. - /// true + /// The certificate selector. + /// true if only trusted anchor certificates should be matched; otherwise, false. + /// true if the certificate must have a private key; otherwise, false. /// The fields to return. - protected override DbCommand GetSelectCommand (IX509Selector selector, bool trustedOnly, bool requirePrivateKey, X509CertificateRecordFields fields) + protected override DbCommand GetSelectCommand (IX509Selector selector, bool trustedAnchorsOnly, bool requirePrivateKey, X509CertificateRecordFields fields) { - var query = "SELECT " + string.Join (", ", GetColumnNames (fields)) + " FROM CERTIFICATES"; var match = selector as X509CertStoreSelector; - var command = connection.CreateCommand (); - var constraints = " WHERE "; + var command = Connection.CreateCommand (); + var query = CreateSelectQuery (fields); + int baseQueryLength = query.Length; - if (trustedOnly) { + query = query.Append (" WHERE "); + + // FIXME: We could create an X509CertificateDatabaseSelector subclass of X509CertStoreSelector that + // adds properties like bool Trusted, bool Anchor, and bool HasPrivateKey ? Then we could drop the + // bool method arguments... + if (trustedAnchorsOnly) { + query = query.Append ("TRUSTED = @TRUSTED AND ANCHOR = @ANCHOR"); command.AddParameterWithValue ("@TRUSTED", true); - constraints += "TRUSTED = @TRUSTED"; + command.AddParameterWithValue ("@ANCHOR", true); } if (match != null) { - if (match.BasicConstraints != -1) { + if (match.BasicConstraints >= 0 || match.BasicConstraints == -2) { if (command.Parameters.Count > 0) - constraints += " AND "; + query = query.Append (" AND "); + + if (match.BasicConstraints == -2) { + command.AddParameterWithValue ("@BASICCONSTRAINTS", -1); + query = query.Append ("BASICCONSTRAINTS = @BASICCONSTRAINTS"); + } else { + command.AddParameterWithValue ("@BASICCONSTRAINTS", match.BasicConstraints); + query = query.Append ("BASICCONSTRAINTS >= @BASICCONSTRAINTS"); + } + } + + if (match.CertificateValid != null) { + if (command.Parameters.Count > 0) + query = query.Append (" AND "); - command.AddParameterWithValue ("@BASICCONSTRAINTS", match.BasicConstraints); - constraints += "BASICCONSTRAINTS = @BASICCONSTRAINTS"; + command.AddParameterWithValue ("@DATETIME", match.CertificateValid.Value.ToUniversalTime ()); + query = query.Append ("NOTBEFORE < @DATETIME AND NOTAFTER > @DATETIME"); } - if (match.Issuer != null) { + if (match.Issuer != null || match.Certificate != null) { + // Note: GetSelectCommand (X509Certificate certificate, X509CertificateRecordFields fields) + // queries for ISSUERNAME, SERIALNUMBER, and FINGERPRINT so we'll do the same. + var issuer = match.Issuer ?? match.Certificate.IssuerDN; + if (command.Parameters.Count > 0) - constraints += " AND "; + query = query.Append (" AND "); - command.AddParameterWithValue ("@ISSUERNAME", match.Issuer.ToString ()); - constraints += "ISSUERNAME = @ISSUERNAME"; + command.AddParameterWithValue ("@ISSUERNAME", issuer.ToString ()); + query = query.Append ("ISSUERNAME = @ISSUERNAME"); } - if (match.SerialNumber != null) { + if (match.SerialNumber != null || match.Certificate != null) { + // Note: GetSelectCommand (X509Certificate certificate, X509CertificateRecordFields fields) + // queries for ISSUERNAME, SERIALNUMBER, and FINGERPRINT so we'll do the same. + var serialNumber = match.SerialNumber ?? match.Certificate.SerialNumber; + + if (command.Parameters.Count > 0) + query = query.Append (" AND "); + + command.AddParameterWithValue ("@SERIALNUMBER", serialNumber.ToString ()); + query = query.Append ("SERIALNUMBER = @SERIALNUMBER"); + } + + if (match.Certificate != null) { + // Note: GetSelectCommand (X509Certificate certificate, X509CertificateRecordFields fields) + // queries for ISSUERNAME, SERIALNUMBER, and FINGERPRINT so we'll do the same. + if (command.Parameters.Count > 0) + query = query.Append (" AND "); + + command.AddParameterWithValue ("@FINGERPRINT", match.Certificate.GetFingerprint ()); + query = query.Append ("FINGERPRINT = @FINGERPRINT"); + } + + if (match.Subject != null) { if (command.Parameters.Count > 0) - constraints += " AND "; + query = query.Append (" AND "); - command.AddParameterWithValue ("@SERIALNUMBER", match.SerialNumber.ToString ()); - constraints += "SERIALNUMBER = @SERIALNUMBER"; + command.AddParameterWithValue ("@SUBJECTNAME", match.Subject.ToString ()); + query = query.Append ("SUBJECTNAME = @SUBJECTNAME"); + } + + if (match.SubjectKeyIdentifier != null) { + if (command.Parameters.Count > 0) + query = query.Append (" AND "); + + var id = (Asn1OctetString) Asn1Object.FromByteArray (match.SubjectKeyIdentifier); + var subjectKeyIdentifier = id.GetOctets ().AsHex (); + + command.AddParameterWithValue ("@SUBJECTKEYIDENTIFIER", subjectKeyIdentifier); + query = query.Append ("SUBJECTKEYIDENTIFIER = @SUBJECTKEYIDENTIFIER"); } if (match.KeyUsage != null) { @@ -261,24 +601,24 @@ protected override DbCommand GetSelectCommand (IX509Selector selector, bool trus if (flags != X509KeyUsageFlags.None) { if (command.Parameters.Count > 0) - constraints += " AND "; + query = query.Append (" AND "); command.AddParameterWithValue ("@FLAGS", (int) flags); - constraints += "(KEYUSAGE == 0 OR (KEYUSAGE & @FLAGS) == @FLAGS)"; + query = query.Append ("(KEYUSAGE = 0 OR (KEYUSAGE & @FLAGS) = @FLAGS)"); } } } if (requirePrivateKey) { if (command.Parameters.Count > 0) - constraints += " AND "; + query = query.Append (" AND "); - constraints += "PRIVATEKEY IS NOT NULL"; + query = query.Append ("PRIVATEKEY IS NOT NULL"); } else if (command.Parameters.Count == 0) { - constraints = string.Empty; + query.Length = baseQueryLength; } - command.CommandText = query + constraints; + command.CommandText = query.ToString (); command.CommandType = CommandType.Text; return command; @@ -296,7 +636,7 @@ protected override DbCommand GetSelectCommand (IX509Selector selector, bool trus protected override DbCommand GetSelectCommand (X509Name issuer, X509CrlRecordFields fields) { var query = "SELECT " + string.Join (", ", GetColumnNames (fields)) + " FROM CRLS "; - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); command.CommandText = query + "WHERE ISSUERNAME = @ISSUERNAME"; command.AddParameterWithValue ("@ISSUERNAME", issuer.ToString ()); @@ -318,7 +658,7 @@ protected override DbCommand GetSelectCommand (X509Crl crl, X509CrlRecordFields { var query = "SELECT " + string.Join (", ", GetColumnNames (fields)) + " FROM CRLS "; var issuerName = crl.IssuerDN.ToString (); - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); command.CommandText = query + "WHERE DELTA = @DELTA AND ISSUERNAME = @ISSUERNAME AND THISUPDATE = @THISUPDATE LIMIT 1"; command.AddParameterWithValue ("@DELTA", crl.IsDelta ()); @@ -338,7 +678,7 @@ protected override DbCommand GetSelectCommand (X509Crl crl, X509CrlRecordFields /// The database command. protected override DbCommand GetSelectAllCrlsCommand () { - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); command.CommandText = "SELECT ID, CRL FROM CRLS"; command.CommandType = CommandType.Text; @@ -356,7 +696,7 @@ protected override DbCommand GetSelectAllCrlsCommand () /// The certificate record. protected override DbCommand GetDeleteCommand (X509CertificateRecord record) { - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); command.CommandText = "DELETE FROM CERTIFICATES WHERE ID = @ID"; command.AddParameterWithValue ("@ID", record.Id); @@ -375,7 +715,7 @@ protected override DbCommand GetDeleteCommand (X509CertificateRecord record) /// The record. protected override DbCommand GetDeleteCommand (X509CrlRecord record) { - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); command.CommandText = "DELETE FROM CRLS WHERE ID = @ID"; command.AddParameterWithValue ("@ID", record.Id); @@ -395,17 +735,17 @@ protected override DbCommand GetDeleteCommand (X509CrlRecord record) protected override DbCommand GetInsertCommand (X509CertificateRecord record) { var statement = new StringBuilder ("INSERT INTO CERTIFICATES("); - var columns = X509CertificateRecord.ColumnNames; var variables = new StringBuilder ("VALUES("); - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); + var columns = CertificatesTable.Columns; - for (int i = 1; i < columns.Length; i++) { + for (int i = 1; i < columns.Count; i++) { if (i > 1) { statement.Append (", "); variables.Append (", "); } - var value = GetValue (record, columns[i]); + var value = GetValue (record, columns[i].ColumnName); var variable = "@" + columns[i]; command.AddParameterWithValue (variable, value); @@ -434,16 +774,16 @@ protected override DbCommand GetInsertCommand (X509CrlRecord record) { var statement = new StringBuilder ("INSERT INTO CRLS("); var variables = new StringBuilder ("VALUES("); - var columns = X509CrlRecord.ColumnNames; - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); + var columns = CrlsTable.Columns; - for (int i = 1; i < columns.Length; i++) { + for (int i = 1; i < columns.Count; i++) { if (i > 1) { statement.Append (", "); variables.Append (", "); } - var value = GetValue (record, columns[i]); + var value = GetValue (record, columns[i].ColumnName); var variable = "@" + columns[i]; command.AddParameterWithValue (variable, value); @@ -473,7 +813,7 @@ protected override DbCommand GetUpdateCommand (X509CertificateRecord record, X50 { var statement = new StringBuilder ("UPDATE CERTIFICATES SET "); var columns = GetColumnNames (fields & ~X509CertificateRecordFields.Id); - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); for (int i = 0; i < columns.Length; i++) { var value = GetValue (record, columns[i]); @@ -509,11 +849,11 @@ protected override DbCommand GetUpdateCommand (X509CertificateRecord record, X50 protected override DbCommand GetUpdateCommand (X509CrlRecord record) { var statement = new StringBuilder ("UPDATE CRLS SET "); - var columns = X509CrlRecord.ColumnNames; - var command = connection.CreateCommand (); + var command = Connection.CreateCommand (); + var columns = CrlsTable.Columns; - for (int i = 1; i < columns.Length; i++) { - var value = GetValue (record, columns[i]); + for (int i = 1; i < columns.Count; i++) { + var value = GetValue (record, columns[i].ColumnName); var variable = "@" + columns[i]; if (i > 1) @@ -548,8 +888,8 @@ protected override DbCommand GetUpdateCommand (X509CrlRecord record) protected override void Dispose (bool disposing) { if (disposing && !disposed) { - if (connection != null) - connection.Dispose (); + if (Connection != null) + Connection.Dispose (); disposed = true; } diff --git a/MimeKit/Cryptography/SqliteCertificateDatabase.cs b/MimeKit/Cryptography/SqliteCertificateDatabase.cs index 678509d51d..50f430da43 100644 --- a/MimeKit/Cryptography/SqliteCertificateDatabase.cs +++ b/MimeKit/Cryptography/SqliteCertificateDatabase.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ using System.Data; using System.Text; using System.Data.Common; +using System.Collections.Generic; #if __MOBILE__ using Mono.Data.Sqlite; @@ -49,9 +50,44 @@ namespace MimeKit.Cryptography { public class SqliteCertificateDatabase : SqlCertificateDatabase { #if !__MOBILE__ - static readonly Type sqliteConnectionStringBuilderClass; - static readonly Type sqliteConnectionClass; - static readonly Assembly sqliteAssembly; + class SQLiteAssembly + { + public Type ConnectionStringBuilderType { get; private set; } + public Type ConnectionType { get; private set; } + public Assembly Assembly { get; private set; } + + public PropertyInfo ConnectionStringProperty { get; private set; } + public PropertyInfo DateTimeFormatProperty { get; private set; } + public PropertyInfo DataSourceProperty { get; private set; } + + public static SQLiteAssembly Load (string assemblyName) + { + try { + int dot = assemblyName.LastIndexOf ('.'); + var prefix = assemblyName.Substring (dot + 1); + + var assembly = Assembly.Load (new AssemblyName (assemblyName)); + var builderType = assembly.GetType (assemblyName + "." + prefix + "ConnectionStringBuilder"); + var connectionType = assembly.GetType (assemblyName + "." + prefix + "Connection"); + var connectionString = builderType.GetProperty ("ConnectionString"); + var dateTimeFormat = builderType.GetProperty ("DateTimeFormat"); + var dataSource = builderType.GetProperty ("DataSource"); + + return new SQLiteAssembly { + Assembly = assembly, + ConnectionType = connectionType, + ConnectionStringBuilderType = builderType, + ConnectionStringProperty = connectionString, + DateTimeFormatProperty = dateTimeFormat, + DataSourceProperty = dataSource + }; + } catch { + return null; + } + } + } + + static readonly SQLiteAssembly sqliteAssembly; #endif // At class initialization we try to use reflection to load the @@ -60,61 +96,66 @@ public class SqliteCertificateDatabase : SqlCertificateDatabase // assembly. static SqliteCertificateDatabase () { -#if NETSTANDARD - try { - if ((sqliteAssembly = Assembly.Load (new AssemblyName ("Microsoft.Data.Sqlite"))) != null) { - sqliteConnectionClass = sqliteAssembly.GetType ("Microsoft.Data.Sqlite.SqliteConnection"); - sqliteConnectionStringBuilderClass = sqliteAssembly.GetType ("Microsoft.Data.Sqlite.SqliteConnectionStringBuilder"); - - // Make sure that the runtime can load the native sqlite library - var builder = Activator.CreateInstance (sqliteConnectionStringBuilderClass); +#if __MOBILE__ + IsAvailable = true; +#else // !__MOBILE__ +#if NETFRAMEWORK || NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_0 + var platform = Environment.OSVersion.Platform; +#endif +#if NETSTANDARD1_3 || NETSTANDARD1_6 || NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_0 + if ((sqliteAssembly = SQLiteAssembly.Load ("Microsoft.Data.Sqlite")) != null) { + // Make sure that the runtime can load the native sqlite library + if (VerifySQLiteAssemblyIsUsable ()) { IsAvailable = true; + return; } - } catch (FileNotFoundException) { - } catch (FileLoadException) { - } catch (BadImageFormatException) { } -#elif !__MOBILE__ - var platform = Environment.OSVersion.Platform; - - try { - // Mono.Data.Sqlite will only work on Unix-based platforms and 32-bit Windows platforms. - if (platform == PlatformID.Unix || platform == PlatformID.MacOSX || IntPtr.Size == 4) { - if ((sqliteAssembly = Assembly.Load ("Mono.Data.Sqlite")) != null) { - sqliteConnectionClass = sqliteAssembly.GetType ("Mono.Data.Sqlite.SqliteConnection"); - sqliteConnectionStringBuilderClass = sqliteAssembly.GetType ("Mono.Data.Sqlite.SqliteConnectionStringBuilder"); - - // Make sure that the runtime can load the native sqlite3 library - var builder = Activator.CreateInstance (sqliteConnectionStringBuilderClass); - sqliteConnectionStringBuilderClass.GetProperty ("DateTimeFormat").SetValue (builder, 0, null); +#endif +#if NETFRAMEWORK || NETCOREAPP3_0 + // Mono.Data.Sqlite will only work on Unix-based platforms. + if (platform == PlatformID.Unix || platform == PlatformID.MacOSX) { + if ((sqliteAssembly = SQLiteAssembly.Load ("Mono.Data.Sqlite")) != null) { + // Make sure that the runtime can load the native sqlite3 library + if (VerifySQLiteAssemblyIsUsable ()) { IsAvailable = true; + return; } } + } +#endif - // System.Data.Sqlite is only available for Windows-based platforms. - if (!IsAvailable && platform != PlatformID.Unix && platform != PlatformID.MacOSX) { - if ((sqliteAssembly = Assembly.Load ("System.Data.SQLite")) != null) { - sqliteConnectionClass = sqliteAssembly.GetType ("System.Data.SQLite.SQLiteConnection"); - sqliteConnectionStringBuilderClass = sqliteAssembly.GetType ("System.Data.SQLite.SQLiteConnectionStringBuilder"); - - // Make sure that the runtime can load the native sqlite3 library - var builder = Activator.CreateInstance (sqliteConnectionStringBuilderClass); - sqliteConnectionStringBuilderClass.GetProperty ("DateTimeFormat").SetValue (builder, 0, null); - - IsAvailable = true; - } +#if NETFRAMEWORK || NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_0 + if ((sqliteAssembly = SQLiteAssembly.Load ("System.Data.SQLite")) != null) { + // Make sure that the runtime can load the native sqlite3 library + if (VerifySQLiteAssemblyIsUsable ()) { + IsAvailable = true; + return; } - } catch (FileNotFoundException) { - } catch (FileLoadException) { - } catch (BadImageFormatException) { } -#else - IsAvailable = true; #endif +#endif // __MOBILE__ } +#if !__MOBILE__ + static bool VerifySQLiteAssemblyIsUsable () + { + // Make sure that the runtime can load the native sqlite3 library. + var fileName = Path.GetTempFileName (); + + try { + var connection = CreateConnection (fileName); + connection.Dispose (); + return true; + } catch { + return false; + } finally { + File.Delete (fileName); + } + } +#endif + internal static bool IsAvailable { get; private set; } @@ -127,47 +168,39 @@ static DbConnection CreateConnection (string fileName) if (fileName.Length == 0) throw new ArgumentException ("The file name cannot be empty.", nameof (fileName)); -#if !__MOBILE__ - var dateTimeFormat = sqliteConnectionStringBuilderClass.GetProperty ("DateTimeFormat"); - var builder = Activator.CreateInstance (sqliteConnectionStringBuilderClass); - - sqliteConnectionStringBuilderClass.GetProperty ("DataSource").SetValue (builder, fileName, null); - - if (dateTimeFormat != null) - dateTimeFormat.SetValue (builder, 0, null); - if (!File.Exists (fileName)) { var dir = Path.GetDirectoryName (fileName); if (!string.IsNullOrEmpty (dir) && !Directory.Exists (dir)) Directory.CreateDirectory (dir); +#if __MOBILE__ + SqliteConnection.CreateFile (fileName); +#else File.Create (fileName).Dispose (); +#endif } - var connectionString = (string) sqliteConnectionStringBuilderClass.GetProperty ("ConnectionString").GetValue (builder, null); +#if !__MOBILE__ + var builder = Activator.CreateInstance (sqliteAssembly.ConnectionStringBuilderType); + + sqliteAssembly.DataSourceProperty.SetValue (builder, fileName, null); + sqliteAssembly.DateTimeFormatProperty?.SetValue (builder, 0, null); + + var connectionString = (string) sqliteAssembly.ConnectionStringProperty.GetValue (builder, null); - return (DbConnection) Activator.CreateInstance (sqliteConnectionClass, new [] { connectionString }); + return (DbConnection) Activator.CreateInstance (sqliteAssembly.ConnectionType, new [] { connectionString }); #else var builder = new SqliteConnectionStringBuilder (); builder.DateTimeFormat = SQLiteDateFormats.Ticks; builder.DataSource = fileName; - if (!File.Exists (fileName)) { - var dir = Path.GetDirectoryName (fileName); - - if (!string.IsNullOrEmpty (dir) && !Directory.Exists (dir)) - Directory.CreateDirectory (dir); - - SqliteConnection.CreateFile (fileName); - } - return new SqliteConnection (builder.ConnectionString); #endif } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new and opens a connection to the @@ -193,12 +226,12 @@ static DbConnection CreateConnection (string fileName) /// /// An error occurred reading the file. /// - public SqliteCertificateDatabase (string fileName, string password) : base (CreateConnection (fileName), password) + public SqliteCertificateDatabase (string fileName, string password) : this (CreateConnection (fileName), password) { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new using the provided SQLite database connection. @@ -215,89 +248,147 @@ public SqliteCertificateDatabase (DbConnection connection, string password) : ba } /// - /// Gets the command to create the certificates table. + /// Gets the columns for the specified table. /// /// - /// Constructs the command to create a certificates table suitable for storing - /// objects. + /// Gets the list of columns for the specified table. /// - /// The . /// The . - protected override DbCommand GetCreateCertificatesTableCommand (DbConnection connection) + /// The name of the table. + /// The list of columns. + protected override IList GetTableColumns (DbConnection connection, string tableName) { - var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS CERTIFICATES("); - var columns = X509CertificateRecord.ColumnNames; - - for (int i = 0; i < columns.Length; i++) { - if (i > 0) - statement.Append (", "); - - statement.Append (columns[i] + " "); - switch (columns[i]) { - case "ID": statement.Append ("INTEGER PRIMARY KEY AUTOINCREMENT"); break; - case "BASICCONSTRAINTS": statement.Append ("INTEGER NOT NULL"); break; - case "TRUSTED": statement.Append ("INTEGER NOT NULL"); break; - case "KEYUSAGE": statement.Append ("INTEGER NOT NULL"); break; - case "NOTBEFORE": statement.Append ("INTEGER NOT NULL"); break; - case "NOTAFTER": statement.Append ("INTEGER NOT NULL"); break; - case "ISSUERNAME": statement.Append ("TEXT NOT NULL"); break; - case "SERIALNUMBER": statement.Append ("TEXT NOT NULL"); break; - case "SUBJECTEMAIL": statement.Append ("TEXT"); break; - case "FINGERPRINT": statement.Append ("TEXT NOT NULL"); break; - case "ALGORITHMS": statement.Append ("TEXT"); break; - case "ALGORITHMSUPDATED": statement.Append ("INTEGER NOT NULL"); break; - case "CERTIFICATE": statement.Append ("BLOB UNIQUE NOT NULL"); break; - case "PRIVATEKEY": statement.Append ("BLOB"); break; + using (var command = connection.CreateCommand ()) { + command.CommandText = $"PRAGMA table_info({tableName})"; + using (var reader = command.ExecuteReader ()) { + var columns = new List (); + + while (reader.Read ()) { + var column = new DataColumn (); + + for (int i = 0; i < reader.FieldCount; i++) { + var field = reader.GetName (i).ToUpperInvariant (); + + switch (field) { + case "NAME": + column.ColumnName = reader.GetString (i); + break; + case "TYPE": + var type = reader.GetString (i); + switch (type) { + case "INTEGER": column.DataType = typeof (long); break; + case "BLOB": column.DataType = typeof (byte[]); break; + case "TEXT": column.DataType = typeof (string); break; + } + break; + case "NOTNULL": + column.AllowDBNull = !reader.GetBoolean (i); + break; + } + } + + columns.Add (column); + } + + return columns; } } + } - statement.Append (')'); + static void Build (StringBuilder statement, DataTable table, DataColumn column, ref int primaryKeys, bool create) + { + statement.Append (column.ColumnName); + statement.Append (' '); + + if (column.DataType == typeof (long) || column.DataType == typeof (int) || column.DataType == typeof (bool)) { + statement.Append ("INTEGER"); + } else if (column.DataType == typeof (byte[])) { + statement.Append ("BLOB"); + } else if (column.DataType == typeof (string)) { + statement.Append ("TEXT"); + } else { + throw new NotImplementedException (); + } + + bool isPrimaryKey = false; + if (table != null && table.PrimaryKey != null && primaryKeys < table.PrimaryKey.Length) { + for (int i = 0; i < table.PrimaryKey.Length; i++) { + if (column == table.PrimaryKey[i]) { + statement.Append (" PRIMARY KEY"); + isPrimaryKey = true; + primaryKeys++; + break; + } + } + } - var command = connection.CreateCommand (); + if (column.AutoIncrement) + statement.Append (" AUTOINCREMENT"); - command.CommandText = statement.ToString (); - command.CommandType = CommandType.Text; + if (column.Unique && !isPrimaryKey) + statement.Append (" UNIQUE"); - return command; + // Note: Normally we'd want to include NOT NULL, but we can't *add* new columns with the NOT NULL restriction + if (create && !column.AllowDBNull) + statement.Append (" NOT NULL"); } /// - /// Gets the command to create the CRLs table. + /// Create a table. /// /// - /// Constructs the command to create a CRLs table suitable for storing - /// objects. + /// Creates the specified table. /// - /// The . /// The . - protected override DbCommand GetCreateCrlsTableCommand (DbConnection connection) + /// The table. + protected override void CreateTable (DbConnection connection, DataTable table) { - var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS CRLS("); - var columns = X509CrlRecord.ColumnNames; - - for (int i = 0; i < columns.Length; i++) { - if (i > 0) - statement.Append (", "); - - statement.Append (columns[i] + " "); - switch (columns[i]) { - case "ID": statement.Append ("INTEGER PRIMARY KEY AUTOINCREMENT"); break; - case "DELTA" : statement.Append ("INTEGER NOT NULL"); break; - case "ISSUERNAME": statement.Append ("TEXT NOT NULL"); break; - case "THISUPDATE": statement.Append ("INTEGER NOT NULL"); break; - case "NEXTUPDATE": statement.Append ("INTEGER NOT NULL"); break; - case "CRL": statement.Append ("BLOB NOT NULL"); break; - } + var statement = new StringBuilder ("CREATE TABLE IF NOT EXISTS "); + int primaryKeys = 0; + + statement.Append (table.TableName); + statement.Append ('('); + + foreach (DataColumn column in table.Columns) { + Build (statement, table, column, ref primaryKeys, true); + statement.Append (", "); } + if (table.Columns.Count > 0) + statement.Length -= 2; + statement.Append (')'); - var command = connection.CreateCommand (); + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } + } - command.CommandText = statement.ToString (); - command.CommandType = CommandType.Text; + /// + /// Adds a column to a table. + /// + /// + /// Adds a column to a table. + /// + /// The . + /// The table. + /// The column to add. + protected override void AddTableColumn (DbConnection connection, DataTable table, DataColumn column) + { + var statement = new StringBuilder ("ALTER TABLE "); + int primaryKeys = table.PrimaryKey?.Length ?? 0; - return command; + statement.Append (table.TableName); + statement.Append (" ADD COLUMN "); + Build (statement, table, column, ref primaryKeys, false); + + using (var command = connection.CreateCommand ()) { + command.CommandText = statement.ToString (); + command.CommandType = CommandType.Text; + command.ExecuteNonQuery (); + } } } } diff --git a/MimeKit/Cryptography/SubjectIdentifierType.cs b/MimeKit/Cryptography/SubjectIdentifierType.cs index 2eb5e0e2bc..6206f45f71 100644 --- a/MimeKit/Cryptography/SubjectIdentifierType.cs +++ b/MimeKit/Cryptography/SubjectIdentifierType.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Cryptography/TemporarySecureMimeContext.cs b/MimeKit/Cryptography/TemporarySecureMimeContext.cs index 6ea222a295..7400847475 100644 --- a/MimeKit/Cryptography/TemporarySecureMimeContext.cs +++ b/MimeKit/Cryptography/TemporarySecureMimeContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,22 +46,24 @@ namespace MimeKit.Cryptography { /// public class TemporarySecureMimeContext : BouncyCastleSecureMimeContext { - readonly Dictionary capabilities; - readonly Dictionary keys; - readonly List certificates; + readonly Dictionary capabilities; + internal readonly Dictionary keys; + internal readonly List certificates; + readonly HashSet fingerprints; readonly List crls; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . /// public TemporarySecureMimeContext () { - capabilities = new Dictionary (); - keys = new Dictionary (); + capabilities = new Dictionary (StringComparer.Ordinal); + keys = new Dictionary (StringComparer.Ordinal); certificates = new List (); + fingerprints = new HashSet (); crls = new List (); } @@ -139,9 +141,10 @@ protected override X509Certificate GetCertificate (IX509Selector selector) protected override AsymmetricKeyParameter GetPrivateKey (IX509Selector selector) { foreach (var certificate in certificates) { + var fingerprint = certificate.GetFingerprint (); AsymmetricKeyParameter key; - if (!keys.TryGetValue (certificate, out key)) + if (!keys.TryGetValue (fingerprint, out key)) continue; if (selector != null && !selector.Match (certificate)) @@ -166,7 +169,10 @@ protected override Org.BouncyCastle.Utilities.Collections.HashSet GetTrustedAnch var anchors = new Org.BouncyCastle.Utilities.Collections.HashSet (); foreach (var certificate in certificates) { - anchors.Add (new TrustAnchor (certificate, null)); + var keyUsage = certificate.GetKeyUsage (); + + if (keyUsage != null && keyUsage[(int) X509KeyUsageBits.KeyCertSign] && certificate.IsSelfSigned ()) + anchors.Add (new TrustAnchor (certificate, null)); } return anchors; @@ -183,13 +189,16 @@ protected override Org.BouncyCastle.Utilities.Collections.HashSet GetTrustedAnch /// The intermediate certificates. protected override IX509Store GetIntermediateCertificates () { - var store = new X509CertificateStore (); + var intermediates = new X509CertificateStore (); foreach (var certificate in certificates) { - store.Add (certificate); + var keyUsage = certificate.GetKeyUsage (); + + if (keyUsage != null && keyUsage[(int) X509KeyUsageBits.KeyCertSign] && !certificate.IsSelfSigned ()) + intermediates.Add (certificate); } - return store; + return intermediates; } /// @@ -249,7 +258,7 @@ X509Certificate GetCmsRecipientCertificate (MailboxAddress mailbox) } else { var address = certificate.GetSubjectEmailAddress (); - if (address == null || !address.Equals (mailbox.Address, StringComparison.OrdinalIgnoreCase)) + if (!address.Equals (mailbox.Address, StringComparison.OrdinalIgnoreCase)) continue; } @@ -284,7 +293,7 @@ protected override CmsRecipient GetCmsRecipient (MailboxAddress mailbox) var recipient = new CmsRecipient (certificate); EncryptionAlgorithm[] algorithms; - if (capabilities.TryGetValue (certificate, out algorithms)) + if (capabilities.TryGetValue (certificate.GetFingerprint (), out algorithms)) recipient.EncryptionAlgorithms = algorithms; return recipient; @@ -303,18 +312,18 @@ X509Certificate GetCmsSignerCertificate (MailboxAddress mailbox, out AsymmetricK if (keyUsage != 0 && (keyUsage & DigitalSignatureKeyUsageFlags) == 0) continue; - if (!keys.TryGetValue (certificate, out key)) + var fingerprint = certificate.GetFingerprint (); + + if (!keys.TryGetValue (fingerprint, out key)) continue; if (secure != null) { - var fingerprint = certificate.GetFingerprint (); - if (!fingerprint.Equals (secure.Fingerprint, StringComparison.OrdinalIgnoreCase)) continue; } else { var address = certificate.GetSubjectEmailAddress (); - if (address == null || !address.Equals (mailbox.Address, StringComparison.OrdinalIgnoreCase)) + if (!address.Equals (mailbox.Address, StringComparison.OrdinalIgnoreCase)) continue; } @@ -350,7 +359,7 @@ protected override CmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgorit if ((certificate = GetCmsSignerCertificate (mailbox, out key)) == null) throw new CertificateNotFoundException (mailbox, "A valid signing certificate could not be found."); - return new CmsSigner (certificate, key) { + return new CmsSigner (BuildCertificateChain (certificate), key) { DigestAlgorithm = digestAlgo }; } @@ -366,7 +375,7 @@ protected override CmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgorit /// The timestamp. protected override void UpdateSecureMimeCapabilities (X509Certificate certificate, EncryptionAlgorithm[] algorithms, DateTime timestamp) { - capabilities[certificate] = algorithms; + capabilities[certificate.GetFingerprint ()] = algorithms; } /// @@ -398,12 +407,15 @@ public override void Import (Stream stream, string password) var entry = pkcs12.GetKey (alias); for (int i = 0; i < chain.Length; i++) - certificates.Add (chain[i].Certificate); + Import (chain[i].Certificate); - keys.Add (chain[0].Certificate, entry.Key); + var fingerprint = chain[0].Certificate.GetFingerprint (); + if (!keys.ContainsKey (fingerprint)) + keys.Add (fingerprint, entry.Key); } else if (pkcs12.IsCertificateEntry (alias)) { var entry = pkcs12.GetCertificate (alias); - certificates.Add (entry.Certificate); + + Import (entry.Certificate); } } } @@ -423,7 +435,8 @@ public override void Import (X509Certificate certificate) if (certificate == null) throw new ArgumentNullException (nameof (certificate)); - certificates.Add (certificate); + if (fingerprints.Add (certificate.GetFingerprint ())) + certificates.Add (certificate); } /// diff --git a/MimeKit/Cryptography/WindowsSecureMimeContext.cs b/MimeKit/Cryptography/WindowsSecureMimeContext.cs index 2fa96705d8..ac3efaced6 100644 --- a/MimeKit/Cryptography/WindowsSecureMimeContext.cs +++ b/MimeKit/Cryptography/WindowsSecureMimeContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -60,7 +60,7 @@ public class WindowsSecureMimeContext : SecureMimeContext const X509KeyStorageFlags DefaultKeyStorageFlags = X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -90,7 +90,7 @@ public WindowsSecureMimeContext (StoreLocation location) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Constructs an S/MIME context using the current user's X.509 store location. @@ -223,7 +223,7 @@ protected virtual RealCmsRecipient GetCmsRecipient (MailboxAddress mailbox) if ((certificate = GetRecipientCertificate (mailbox)) == null) throw new CertificateNotFoundException (mailbox, "A valid certificate could not be found."); - return new RealCmsRecipient (RealSubjectIdentifierType.SubjectKeyIdentifier, certificate); + return new RealCmsRecipient (certificate); } /// @@ -260,13 +260,28 @@ RealCmsRecipientCollection GetCmsRecipients (CmsRecipientCollection recipients) foreach (var recipient in recipients) { var certificate = new X509Certificate2 (recipient.Certificate.GetEncoded ()); RealSubjectIdentifierType type; + RealCmsRecipient real; - if (recipient.RecipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber) + if (recipient.RecipientIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) type = RealSubjectIdentifierType.IssuerAndSerialNumber; else type = RealSubjectIdentifierType.SubjectKeyIdentifier; - collection.Add (new RealCmsRecipient (type, certificate)); +#if NETCOREAPP3_0 + var padding = recipient.RsaEncryptionPadding?.AsRSAEncryptionPadding (); + + if (padding != null) + real = new RealCmsRecipient (type, certificate, padding); + else + real = new RealCmsRecipient (type, certificate); +#else + if (recipient.RsaEncryptionPadding?.Scheme == RsaEncryptionPaddingScheme.Oaep) + throw new NotSupportedException ("The RSAES-OAEP encryption padding scheme is not supported by the WindowsSecureMimeContext. You must use a subclass of BouncyCastleSecureMimeContext to get this feature."); + + real = new RealCmsRecipient (type, certificate); +#endif + + collection.Add (real); } return collection; @@ -324,14 +339,14 @@ protected virtual X509Certificate2 GetSignerCertificate (MailboxAddress mailbox) AsnEncodedData GetSecureMimeCapabilities () { - var attr = GetSecureMimeCapabilitiesAttribute (); + var attr = GetSecureMimeCapabilitiesAttribute (false); return new AsnEncodedData (attr.AttrType.Id, attr.AttrValues[0].GetEncoded ()); } - RealCmsSigner GetRealCmsSigner (X509Certificate2 certificate, DigestAlgorithm digestAlgo) + RealCmsSigner GetRealCmsSigner (RealSubjectIdentifierType type, X509Certificate2 certificate, DigestAlgorithm digestAlgo) { - var signer = new RealCmsSigner (certificate); + var signer = new RealCmsSigner (type, certificate); signer.DigestAlgorithm = new Oid (GetDigestOid (digestAlgo)); signer.SignedAttributes.Add (GetSecureMimeCapabilities ()); signer.SignedAttributes.Add (new Pkcs9SigningTime ()); @@ -341,11 +356,20 @@ RealCmsSigner GetRealCmsSigner (X509Certificate2 certificate, DigestAlgorithm di RealCmsSigner GetRealCmsSigner (CmsSigner signer) { + if (signer.RsaSignaturePadding == RsaSignaturePadding.Pss) + throw new NotSupportedException ("The RSASSA-PSS signature padding scheme is not supported by the WindowsSecureMimeContext. You must use a subclass of BouncyCastleSecureMimeContext to get this feature."); + var certificate = signer.Certificate.AsX509Certificate2 (); + RealSubjectIdentifierType type; + + if (signer.SignerIdentifierType != SubjectIdentifierType.SubjectKeyIdentifier) + type = RealSubjectIdentifierType.IssuerAndSerialNumber; + else + type = RealSubjectIdentifierType.SubjectKeyIdentifier; certificate.PrivateKey = signer.PrivateKey.AsAsymmetricAlgorithm (); - return GetRealCmsSigner (certificate, signer.DigestAlgorithm); + return GetRealCmsSigner (type, certificate, signer.DigestAlgorithm); } /// @@ -371,7 +395,7 @@ protected virtual RealCmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgo if ((certificate = GetSignerCertificate (mailbox)) == null) throw new CertificateNotFoundException (mailbox, "A valid signing certificate could not be found."); - return GetRealCmsSigner (certificate, digestAlgo); + return GetRealCmsSigner (RealSubjectIdentifierType.IssuerAndSerialNumber, certificate, digestAlgo); } /// @@ -379,8 +403,9 @@ protected virtual RealCmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgo /// /// /// Updates the known S/MIME capabilities of the client used by the recipient that owns the specified certificate. - /// This method is called from , allowing custom implementations - /// to update the X.509 certificate records with the list of preferred encryption algorithms specified by the sending client. + /// This method is called when decoding digital signatures that include S/MIME capabilities in the metadata, allowing custom + /// implementations to update the X.509 certificate records with the list of preferred encryption algorithms specified by the + /// sending client. /// /// The certificate. /// The encryption algorithm capabilities of the client (in preferred order). @@ -424,10 +449,10 @@ Stream Sign (RealCmsSigner signer, Stream content, bool detach) var signed = new SignedCms (contentInfo, detach); try { - signed.ComputeSignature (signer); + signed.ComputeSignature (signer, false); } catch (CryptographicException) { signer.IncludeOption = X509IncludeOption.EndCertOnly; - signed.ComputeSignature (signer); + signed.ComputeSignature (signer, false); } var signedData = signed.Encode (); @@ -441,7 +466,7 @@ Stream Sign (RealCmsSigner signer, Stream content, bool detach) /// /// Cryptographically signs and encapsulates the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -463,7 +488,7 @@ public override ApplicationPkcs7Mime EncapsulatedSign (CmsSigner signer, Stream var real = GetRealCmsSigner (signer); - return new ApplicationPkcs7Mime (SecureMimeType.SignedData, Sign (real, content, true)); + return new ApplicationPkcs7Mime (SecureMimeType.SignedData, Sign (real, content, false)); } /// @@ -472,7 +497,7 @@ public override ApplicationPkcs7Mime EncapsulatedSign (CmsSigner signer, Stream /// /// Sign and encapsulate the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -513,7 +538,7 @@ public override ApplicationPkcs7Mime EncapsulatedSign (MailboxAddress signer, Di /// /// Cryptographically signs the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The content. @@ -535,7 +560,7 @@ public override ApplicationPkcs7Signature Sign (CmsSigner signer, Stream content var real = GetRealCmsSigner (signer); - return new ApplicationPkcs7Signature (Sign (real, content, false)); + return new ApplicationPkcs7Signature (Sign (real, content, true)); } /// @@ -544,7 +569,7 @@ public override ApplicationPkcs7Signature Sign (CmsSigner signer, Stream content /// /// Sign the content using the specified signer. /// - /// A new instance + /// A new instance /// containing the detached signature data. /// The signer. /// The digest algorithm to use for signing. @@ -638,12 +663,12 @@ DigitalSignatureCollection GetDigitalSignatures (SignedCms signed) /// -or- /// is null. /// - /// - /// An error occurred in the cryptographic message syntax subsystem. - /// /// /// The operation was cancelled via the cancellation token. /// + /// + /// An error occurred in the cryptographic message syntax subsystem. + /// public override DigitalSignatureCollection Verify (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) { if (content == null) @@ -675,12 +700,12 @@ DigitalSignatureCollection GetDigitalSignatures (SignedCms signed) /// -or- /// is null. /// - /// - /// An error occurred in the cryptographic message syntax subsystem. - /// /// /// The operation was cancelled via the cancellation token. /// + /// + /// An error occurred in the cryptographic message syntax subsystem. + /// public override async Task VerifyAsync (Stream content, Stream signatureData, CancellationToken cancellationToken = default (CancellationToken)) { if (content == null) @@ -713,21 +738,21 @@ DigitalSignatureCollection GetDigitalSignatures (SignedCms signed) /// /// The extracted content could not be parsed as a MIME entity. /// - /// - /// An error occurred in the cryptographic message syntax subsystem. - /// /// /// The operation was cancelled via the cancellation token. /// + /// + /// An error occurred in the cryptographic message syntax subsystem. + /// public override DigitalSignatureCollection Verify (Stream signedData, out MimeEntity entity, CancellationToken cancellationToken = default (CancellationToken)) { if (signedData == null) throw new ArgumentNullException (nameof (signedData)); - var contentInfo = new ContentInfo (ReadAllBytes (signedData)); + var content = ReadAllBytes (signedData); var signed = new SignedCms (); - signed.Decode (ReadAllBytes (signedData)); + signed.Decode (content); var memory = new MemoryStream (signed.ContentInfo.Content, false); @@ -754,21 +779,21 @@ DigitalSignatureCollection GetDigitalSignatures (SignedCms signed) /// /// is null. /// - /// - /// An error occurred in the cryptographic message syntax subsystem. - /// /// /// The operation was cancelled via the cancellation token. /// + /// + /// An error occurred in the cryptographic message syntax subsystem. + /// public override Stream Verify (Stream signedData, out DigitalSignatureCollection signatures, CancellationToken cancellationToken = default (CancellationToken)) { if (signedData == null) throw new ArgumentNullException (nameof (signedData)); - var contentInfo = new ContentInfo (ReadAllBytes (signedData)); + var content = ReadAllBytes (signedData); var signed = new SignedCms (); - signed.Decode (ReadAllBytes (signedData)); + signed.Decode (content); signatures = GetDigitalSignatures (signed); @@ -885,7 +910,7 @@ Stream Envelope (CmsRecipientCollection recipients, Stream content) /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance + /// A new instance /// containing the encrypted content. /// The recipients. /// The content. @@ -914,7 +939,7 @@ public override ApplicationPkcs7Mime Encrypt (CmsRecipientCollection recipients, /// /// Encrypts the specified content for the specified recipients. /// - /// A new instance + /// A new instance /// containing the encrypted data. /// The recipients. /// The content. @@ -951,7 +976,7 @@ public override MimePart Encrypt (IEnumerable recipients, Stream /// /// Decrypt the encrypted data. /// - /// The decrypted . + /// The decrypted . /// The encrypted data. /// The cancellation token. /// @@ -969,9 +994,22 @@ public override MimePart Encrypt (IEnumerable recipients, Stream throw new ArgumentNullException (nameof (encryptedData)); var enveloped = new EnvelopedCms (); + CryptographicException ce = null; enveloped.Decode (ReadAllBytes (encryptedData)); - enveloped.Decrypt (); + + foreach (var recipient in enveloped.RecipientInfos) { + try { + enveloped.Decrypt (recipient); + ce = null; + break; + } catch (CryptographicException ex) { + ce = ex; + } + } + + if (ce != null) + throw ce; var decryptedData = enveloped.Encode (); @@ -1101,7 +1139,12 @@ public override void Import (X509Crl crl) if (crl == null) throw new ArgumentNullException (nameof (crl)); - foreach (Org.BouncyCastle.X509.X509Certificate certificate in crl.GetRevokedCertificates ()) + var revoked = crl.GetRevokedCertificates (); + + if (revoked == null) + return; + + foreach (Org.BouncyCastle.X509.X509Certificate certificate in revoked) Import (StoreName.Disallowed, certificate); } @@ -1161,7 +1204,7 @@ public override void Import (Stream stream, string password) /// /// Exports the certificates for the specified mailboxes. /// - /// A new instance containing + /// A new instance containing /// the exported keys. /// The mailboxes. /// @@ -1173,7 +1216,7 @@ public override void Import (Stream stream, string password) /// /// A certificate for one or more of the could not be found. /// - /// + /// /// An error occurred in the cryptographic message syntax subsystem. /// public override MimePart Export (IEnumerable mailboxes) @@ -1197,9 +1240,9 @@ public override MimePart Export (IEnumerable mailboxes) throw new ArgumentException ("No mailboxes specified.", nameof (mailboxes)); var cms = new CmsSignedDataStreamGenerator (); - var memory = new MemoryBlockStream (); - cms.AddCertificates (certificates); + + var memory = new MemoryBlockStream (); cms.Open (memory).Dispose (); memory.Position = 0; diff --git a/MimeKit/Cryptography/WindowsSecureMimeDigitalCertificate.cs b/MimeKit/Cryptography/WindowsSecureMimeDigitalCertificate.cs index 218b0713c3..c95b8233e1 100644 --- a/MimeKit/Cryptography/WindowsSecureMimeDigitalCertificate.cs +++ b/MimeKit/Cryptography/WindowsSecureMimeDigitalCertificate.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ namespace MimeKit.Cryptography { public class WindowsSecureMimeDigitalCertificate : IDigitalCertificate { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -53,17 +53,7 @@ public WindowsSecureMimeDigitalCertificate (X509Certificate2 certificate) throw new ArgumentNullException (nameof (certificate)); Certificate = certificate; - - var algorithm = certificate.PublicKey.Key; - - if (algorithm is DSA) - PublicKeyAlgorithm = PublicKeyAlgorithm.Dsa; - else if (algorithm is RSA) - PublicKeyAlgorithm = PublicKeyAlgorithm.RsaGeneral; - else if (algorithm is ECDiffieHellman) - PublicKeyAlgorithm = PublicKeyAlgorithm.DiffieHellman; - else if (algorithm is ECDsa) - PublicKeyAlgorithm = PublicKeyAlgorithm.EdwardsCurveDsa; + PublicKeyAlgorithm = certificate.GetPublicKeyAlgorithm (); } /// diff --git a/MimeKit/Cryptography/WindowsSecureMimeDigitalSignature.cs b/MimeKit/Cryptography/WindowsSecureMimeDigitalSignature.cs index 5bb7fdadcf..7754ab3489 100644 --- a/MimeKit/Cryptography/WindowsSecureMimeDigitalSignature.cs +++ b/MimeKit/Cryptography/WindowsSecureMimeDigitalSignature.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ public class WindowsSecureMimeDigitalSignature : IDigitalSignature DigitalSignatureVerifyException vex; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -141,7 +141,7 @@ public IDigitalCertificate SignerCertificate { /// /// The public key algorithm. public PublicKeyAlgorithm PublicKeyAlgorithm { - get { return PublicKeyAlgorithm.None; } + get { return SignerCertificate != null ? SignerCertificate.PublicKeyAlgorithm : PublicKeyAlgorithm.None; } } /// @@ -177,12 +177,28 @@ public DateTime CreationDate { /// An error verifying the signature has occurred. /// public bool Verify () + { + return Verify (false); + } + + /// + /// Verifies the digital signature. + /// + /// + /// Verifies the digital signature. + /// + /// true if only the signature itself should be verified; otherwise, both the signature and the certificate chain are validated. + /// true if the signature is valid; otherwise, false. + /// + /// An error verifying the signature has occurred. + /// + public bool Verify (bool verifySignatureOnly) { if (vex != null) throw vex; try { - SignerInfo.CheckSignature (false); + SignerInfo.CheckSignature (verifySignatureOnly); return true; } catch (Exception ex) { var message = string.Format ("Failed to verify digital signature: {0}", ex.Message); @@ -193,4 +209,4 @@ public bool Verify () #endregion } -} \ No newline at end of file +} diff --git a/MimeKit/Cryptography/X509Certificate2Extensions.cs b/MimeKit/Cryptography/X509Certificate2Extensions.cs index 4107178568..9184315ab4 100644 --- a/MimeKit/Cryptography/X509Certificate2Extensions.cs +++ b/MimeKit/Cryptography/X509Certificate2Extensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 Xamarin Inc. (www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ using System; using System.IO; using System.Collections.Generic; +using System.Security.Cryptography; using Org.BouncyCastle.X509; using Org.BouncyCastle.Asn1; @@ -61,8 +62,38 @@ public static X509Certificate AsBouncyCastleCertificate (this X509Certificate2 c throw new ArgumentNullException (nameof (certificate)); var rawData = certificate.GetRawCertData (); + var parser = new X509CertificateParser (); + var cert = parser.ReadCertificate (rawData); - return new X509CertificateParser ().ReadCertificate (rawData); + return cert; + } + + /// + /// Gets the public key algorithm for the certificate. + /// + /// + /// Gets the public key algorithm for the ceretificate. + /// + /// The public key algorithm. + /// The certificate. + /// + /// is null. + /// + public static PublicKeyAlgorithm GetPublicKeyAlgorithm (this X509Certificate2 certificate) + { + if (certificate == null) + throw new ArgumentNullException (nameof (certificate)); + + var identifier = certificate.GetKeyAlgorithm (); + var oid = new Oid (identifier); + + switch (oid.FriendlyName) { + case "DSA": return PublicKeyAlgorithm.Dsa; + case "RSA": return PublicKeyAlgorithm.RsaGeneral; + case "ECC": return PublicKeyAlgorithm.EllipticCurve; + case "DH": return PublicKeyAlgorithm.DiffieHellman; + default: return PublicKeyAlgorithm.None; + } } static EncryptionAlgorithm[] DecodeEncryptionAlgorithms (byte[] rawData) diff --git a/MimeKit/Cryptography/X509CertificateChain.cs b/MimeKit/Cryptography/X509CertificateChain.cs index 09d81e7035..9193fe323a 100644 --- a/MimeKit/Cryptography/X509CertificateChain.cs +++ b/MimeKit/Cryptography/X509CertificateChain.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ public class X509CertificateChain : IList, IX509Store readonly List certificates; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new X.509 certificate chain. @@ -54,7 +54,7 @@ public X509CertificateChain () } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new X.509 certificate chain based on the specified collection of certificates. @@ -168,7 +168,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether the is read only. /// /// /// A is never read-only. diff --git a/MimeKit/Cryptography/X509CertificateDatabase.cs b/MimeKit/Cryptography/X509CertificateDatabase.cs index c8fb2f98c9..2a64837a3d 100644 --- a/MimeKit/Cryptography/X509CertificateDatabase.cs +++ b/MimeKit/Cryptography/X509CertificateDatabase.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -60,7 +60,7 @@ public abstract class X509CertificateDatabase : IX509CertificateDatabase readonly char[] passwd; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// The password is used to encrypt and decrypt private keys in the database and cannot be null. @@ -83,11 +83,11 @@ protected X509CertificateDatabase (string password) /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// ~X509CertificateDatabase () { @@ -131,7 +131,7 @@ protected int SaltSize { static int ReadBinaryBlob (DbDataReader reader, int column, ref byte[] buffer) { -#if NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 buffer = reader.GetFieldValue (column); return (int) buffer.Length; #else @@ -373,7 +373,7 @@ protected static string[] GetColumnNames (X509CertificateRecordFields fields) /// The database command. /// The mailbox. /// The date and time for which the certificate should be valid. - /// true if the certificate must have a private key. + /// true if the certificate must have a private key; otherwise, false. /// The fields to return. protected abstract DbCommand GetSelectCommand (MailboxAddress mailbox, DateTime now, bool requirePrivateKey, X509CertificateRecordFields fields); @@ -384,11 +384,11 @@ protected static string[] GetColumnNames (X509CertificateRecordFields fields) /// Gets the database command to select certificate records matching the specified selector. /// /// The database command. - /// Selector. - /// true if only trusted certificates should be matched. - /// true if the certificate must have a private key. + /// The certificate selector. + /// true if only trusted anchor certificates should be matched; otherwise, false. + /// true if the certificate must have a private key; otherwise, false. /// The fields to return. - protected abstract DbCommand GetSelectCommand (IX509Selector selector, bool trustedOnly, bool requirePrivateKey, X509CertificateRecordFields fields); + protected abstract DbCommand GetSelectCommand (IX509Selector selector, bool trustedAnchorsOnly, bool requirePrivateKey, X509CertificateRecordFields fields); /// /// Gets the column names for the specified fields. @@ -400,13 +400,6 @@ protected static string[] GetColumnNames (X509CertificateRecordFields fields) /// The fields. protected static string[] GetColumnNames (X509CrlRecordFields fields) { - const X509CrlRecordFields all = X509CrlRecordFields.Id | X509CrlRecordFields.IsDelta | - X509CrlRecordFields.IssuerName | X509CrlRecordFields.ThisUpdate | - X509CrlRecordFields.NextUpdate | X509CrlRecordFields.Crl; - - if (fields == all) - return new [] { "*" }; - var columns = new List (); if ((fields & X509CrlRecordFields.Id) != 0) @@ -491,14 +484,17 @@ protected static string[] GetColumnNames (X509CrlRecordFields fields) protected object GetValue (X509CertificateRecord record, string columnName) { switch (columnName) { - case "ID": return record.Id; + //case "ID": return record.Id; case "BASICCONSTRAINTS": return record.BasicConstraints; case "TRUSTED": return record.IsTrusted; + case "ANCHOR": return record.IsAnchor; case "KEYUSAGE": return (int) record.KeyUsage; case "NOTBEFORE": return record.NotBefore.ToUniversalTime (); case "NOTAFTER": return record.NotAfter.ToUniversalTime (); case "ISSUERNAME": return record.IssuerName; case "SERIALNUMBER": return record.SerialNumber; + case "SUBJECTNAME": return record.SubjectName; + case "SUBJECTKEYIDENTIFIER": return record.SubjectKeyIdentifier?.AsHex (); case "SUBJECTEMAIL": return record.SubjectEmail != null ? record.SubjectEmail.ToLowerInvariant () : string.Empty; case "FINGERPRINT": return record.Fingerprint.ToLowerInvariant (); case "ALGORITHMS": return EncodeEncryptionAlgorithms (record.Algorithms); @@ -524,7 +520,7 @@ protected object GetValue (X509CertificateRecord record, string columnName) protected static object GetValue (X509CrlRecord record, string columnName) { switch (columnName) { - case "ID": return record.Id; + //case "ID": return record.Id; case "DELTA": return record.IsDelta; case "ISSUERNAME": return record.IssuerName; case "THISUPDATE": return record.ThisUpdate; @@ -594,21 +590,13 @@ public X509CertificateRecord Find (X509Certificate certificate, X509CertificateR throw new ArgumentNullException (nameof (certificate)); using (var command = GetSelectCommand (certificate, fields)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { if (reader.Read ()) { var parser = new X509CertificateParser (); var buffer = new byte[4096]; return LoadCertificateRecord (reader, parser, ref buffer); } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -627,9 +615,7 @@ public X509CertificateRecord Find (X509Certificate certificate, X509CertificateR public IEnumerable FindCertificates (IX509Selector selector) { using (var command = GetSelectCommand (selector, false, false, X509CertificateRecordFields.Certificate)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { var parser = new X509CertificateParser (); var buffer = new byte[4096]; @@ -638,12 +624,6 @@ public IEnumerable FindCertificates (IX509Selector selector) if (selector == null || selector.Match (record.Certificate)) yield return record.Certificate; } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -662,9 +642,7 @@ public IEnumerable FindCertificates (IX509Selector selector) public IEnumerable FindPrivateKeys (IX509Selector selector) { using (var command = GetSelectCommand (selector, false, true, PrivateKeyFields)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { var parser = new X509CertificateParser (); var buffer = new byte[4096]; @@ -674,12 +652,6 @@ public IEnumerable FindPrivateKeys (IX509Selector select if (selector == null || selector.Match (record.Certificate)) yield return record.PrivateKey; } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -708,21 +680,13 @@ public IEnumerable Find (MailboxAddress mailbox, DateTime throw new ArgumentNullException (nameof (mailbox)); using (var command = GetSelectCommand (mailbox, now, requirePrivateKey, fields)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { var parser = new X509CertificateParser (); var buffer = new byte[4096]; while (reader.Read ()) { yield return LoadCertificateRecord (reader, parser, ref buffer); } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -738,14 +702,12 @@ public IEnumerable Find (MailboxAddress mailbox, DateTime /// /// The matching certificate records populated with the desired fields. /// The match selector or null to match all certificates. - /// true if only trusted certificates should be returned. + /// true if only trusted anchor certificates should be returned. /// The desired fields. - public IEnumerable Find (IX509Selector selector, bool trustedOnly, X509CertificateRecordFields fields) + public IEnumerable Find (IX509Selector selector, bool trustedAnchorsOnly, X509CertificateRecordFields fields) { - using (var command = GetSelectCommand (selector, trustedOnly, false, fields | X509CertificateRecordFields.Certificate)) { - var reader = command.ExecuteReader (); - - try { + using (var command = GetSelectCommand (selector, trustedAnchorsOnly, false, fields | X509CertificateRecordFields.Certificate)) { + using (var reader = command.ExecuteReader ()) { var parser = new X509CertificateParser (); var buffer = new byte[4096]; @@ -755,12 +717,6 @@ public IEnumerable Find (IX509Selector selector, bool tru if (selector == null || selector.Match (record.Certificate)) yield return record; } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -782,9 +738,8 @@ public void Add (X509CertificateRecord record) if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetInsertCommand (record)) { + using (var command = GetInsertCommand (record)) command.ExecuteNonQuery (); - } } /// @@ -802,9 +757,8 @@ public void Remove (X509CertificateRecord record) if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetDeleteCommand (record)) { + using (var command = GetDeleteCommand (record)) command.ExecuteNonQuery (); - } } /// @@ -823,9 +777,8 @@ public void Update (X509CertificateRecord record, X509CertificateRecordFields fi if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetUpdateCommand (record, fields)) { + using (var command = GetUpdateCommand (record, fields)) command.ExecuteNonQuery (); - } } /// @@ -847,21 +800,13 @@ public IEnumerable Find (X509Name issuer, X509CrlRecordFields fie throw new ArgumentNullException (nameof (issuer)); using (var command = GetSelectCommand (issuer, fields)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { var parser = new X509CrlParser (); var buffer = new byte[4096]; while (reader.Read ()) { yield return LoadCrlRecord (reader, parser, ref buffer); } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -887,21 +832,13 @@ public X509CrlRecord Find (X509Crl crl, X509CrlRecordFields fields) throw new ArgumentNullException (nameof (crl)); using (var command = GetSelectCommand (crl, fields)) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { if (reader.Read ()) { var parser = new X509CrlParser (); var buffer = new byte[4096]; return LoadCrlRecord (reader, parser, ref buffer); } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -923,9 +860,8 @@ public void Add (X509CrlRecord record) if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetInsertCommand (record)) { + using (var command = GetInsertCommand (record)) command.ExecuteNonQuery (); - } } /// @@ -943,9 +879,8 @@ public void Remove (X509CrlRecord record) if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetDeleteCommand (record)) { + using (var command = GetDeleteCommand (record)) command.ExecuteNonQuery (); - } } /// @@ -963,9 +898,8 @@ public void Update (X509CrlRecord record) if (record == null) throw new ArgumentNullException (nameof (record)); - using (var command = GetUpdateCommand (record)) { + using (var command = GetUpdateCommand (record)) command.ExecuteNonQuery (); - } } /// @@ -974,15 +908,13 @@ public void Update (X509CrlRecord record) /// /// Gets a certificate revocation list store. /// - /// A certificate recovation list store. + /// A certificate revocation list store. public IX509Store GetCrlStore () { var crls = new List (); using (var command = GetSelectAllCrlsCommand ()) { - var reader = command.ExecuteReader (); - - try { + using (var reader = command.ExecuteReader ()) { var parser = new X509CrlParser (); var buffer = new byte[4096]; @@ -990,12 +922,6 @@ public IX509Store GetCrlStore () var record = LoadCrlRecord (reader, parser, ref buffer); crls.Add (record.Crl); } - } finally { -#if NETSTANDARD - reader.Dispose (); -#else - reader.Close (); -#endif } } @@ -1033,19 +959,21 @@ ICollection IX509Store.GetMatches (IX509Selector selector) /// false to release only the unmanaged resources. protected virtual void Dispose (bool disposing) { - for (int i = 0; i < passwd.Length; i++) - passwd[i] = '\0'; + if (passwd != null) { + for (int i = 0; i < passwd.Length; i++) + passwd[i] = '\0'; + } } /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// /// Call when you are finished using the - /// . The method leaves the - /// in an unusable state. After calling + /// . The method leaves the + /// in an unusable state. After calling /// , you must release all references to the - /// so the garbage collector can reclaim the memory that - /// the was occupying. + /// so the garbage collector can reclaim the memory that + /// the was occupying. public void Dispose () { Dispose (true); diff --git a/MimeKit/Cryptography/X509CertificateRecord.cs b/MimeKit/Cryptography/X509CertificateRecord.cs index 33dcead980..fa971db127 100644 --- a/MimeKit/Cryptography/X509CertificateRecord.cs +++ b/MimeKit/Cryptography/X509CertificateRecord.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,8 +26,10 @@ using System; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.X509; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Asn1.X509; namespace MimeKit.Cryptography { /// @@ -84,23 +86,6 @@ public enum X509CertificateRecordFields { /// public class X509CertificateRecord { - internal static readonly string[] ColumnNames = { - "ID", - "BASICCONSTRAINTS", - "TRUSTED", - "KEYUSAGE", - "NOTBEFORE", - "NOTAFTER", - "ISSUERNAME", - "SERIALNUMBER", - "SUBJECTEMAIL", - "FINGERPRINT", - "ALGORITHMS", - "ALGORITHMSUPDATED", - "CERTIFICATE", - "PRIVATEKEY" - }; - /// /// Gets the identifier. /// @@ -129,6 +114,15 @@ public class X509CertificateRecord /// true if the certificate is trusted; otherwise, false. public bool IsTrusted { get; set; } + /// + /// Gets whether or not the certificate is an anchor. + /// + /// + /// Gets whether or not the certificate is an anchor. + /// + /// true if the certificate is an anchor; otherwise, false. + public bool IsAnchor { get { return Certificate.IsSelfSigned (); } } + /// /// Gets the key usage flags for the certificate. /// @@ -157,12 +151,12 @@ public class X509CertificateRecord public DateTime NotAfter { get { return Certificate.NotAfter.ToUniversalTime (); } } /// - /// Gets the certificate issuer's name. + /// Gets the certificate's issuer name. /// /// - /// Gets the certificate issuer's name. + /// Gets the certificate's issuer name. /// - /// The issuer's name. + /// The certificate's issuer name. public string IssuerName { get { return Certificate.IssuerDN.ToString (); } } /// @@ -174,6 +168,33 @@ public class X509CertificateRecord /// The serial number. public string SerialNumber { get { return Certificate.SerialNumber.ToString (); } } + /// + /// Gets the certificate's subject name. + /// + /// + /// Gets the certificate's subject name. + /// + /// The certificate's subject name. + public string SubjectName { get { return Certificate.SubjectDN.ToString (); } } + + /// + /// Gets the certificate's subject key identifier. + /// + /// + /// Gets the certificate's subject key identifier. + /// + /// The certificate's subject key identifier. + public byte[] SubjectKeyIdentifier { + get { + var subjectKeyIdentifier = Certificate.GetExtensionValue (X509Extensions.SubjectKeyIdentifier); + + if (subjectKeyIdentifier != null) + subjectKeyIdentifier = (Asn1OctetString) Asn1Object.FromByteArray (subjectKeyIdentifier.GetOctets ()); + + return subjectKeyIdentifier?.GetOctets (); + } + } + /// /// Gets the subject email address. /// @@ -229,7 +250,7 @@ public class X509CertificateRecord public AsymmetricKeyParameter PrivateKey { get; set; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new certificate record with a private key for storing in a @@ -262,7 +283,7 @@ public X509CertificateRecord (X509Certificate certificate, AsymmetricKeyParamete } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new certificate record for storing in a . @@ -281,7 +302,7 @@ public X509CertificateRecord (X509Certificate certificate) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// This constructor is only meant to be used by implementors of diff --git a/MimeKit/Cryptography/X509CertificateStore.cs b/MimeKit/Cryptography/X509CertificateStore.cs index c807392a79..6bdd6e0c22 100644 --- a/MimeKit/Cryptography/X509CertificateStore.cs +++ b/MimeKit/Cryptography/X509CertificateStore.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ public class X509CertificateStore : IX509Store readonly List certs; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -196,7 +196,6 @@ public void Import (Stream stream) } } -#if !PORTABLE /// /// Imports the certificate(s) from the specified file. /// @@ -221,7 +220,6 @@ public void Import (string fileName) using (var stream = File.OpenRead (fileName)) Import (stream); } -#endif /// /// Imports the certificate(s) from the specified byte array. @@ -289,7 +287,6 @@ public void Import (Stream stream, string password) } } -#if !PORTABLE /// /// Imports certificates and private keys from the specified file. /// @@ -305,8 +302,7 @@ public void Import (Stream stream, string password) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The specified file could not be found. @@ -325,7 +321,6 @@ public void Import (string fileName, string password) using (var stream = File.OpenRead (fileName)) Import (stream, password); } -#endif /// /// Imports certificates and private keys from the specified byte array. @@ -373,7 +368,6 @@ public void Export (Stream stream) } } -#if !PORTABLE /// /// Exports the certificates to an unencrypted file. /// @@ -386,8 +380,7 @@ public void Export (Stream stream) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The specified path exceeds the maximum allowed path length of the system. @@ -409,7 +402,6 @@ public void Export (string fileName) using (var file = File.Create (fileName)) Export (file); } -#endif /// /// Exports the specified stream and password to a pkcs12 encrypted file. @@ -468,7 +460,6 @@ public void Export (Stream stream, string password) store.Save (stream, password.ToCharArray (), new SecureRandom ()); } -#if !PORTABLE /// /// Exports the specified stream and password to a pkcs12 encrypted file. /// @@ -484,8 +475,7 @@ public void Export (Stream stream, string password) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The specified path exceeds the maximum allowed path length of the system. @@ -510,7 +500,6 @@ public void Export (string fileName, string password) using (var file = File.Create (fileName)) Export (file, password); } -#endif /// /// Gets an enumerator of matching X.509 certificates based on the specified selector. diff --git a/MimeKit/Cryptography/X509CrlRecord.cs b/MimeKit/Cryptography/X509CrlRecord.cs index 4812c2fcaf..1bb17b6eec 100644 --- a/MimeKit/Cryptography/X509CrlRecord.cs +++ b/MimeKit/Cryptography/X509CrlRecord.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -78,15 +78,6 @@ public enum X509CrlRecordFields { /// public class X509CrlRecord { - internal static readonly string[] ColumnNames = { - "ID", - "DELTA", - "ISSUERNAME", - "THISUPDATE", - "NEXTUPDATE", - "CRL" - }; - /// /// Gets the identifier. /// @@ -144,7 +135,7 @@ public class X509CrlRecord public X509Crl Crl { get; set; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new CRL record for storing in a . @@ -168,7 +159,7 @@ public X509CrlRecord (X509Crl crl) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// This constructor is only meant to be used by implementors of diff --git a/MimeKit/Cryptography/X509KeyUsageFlags.cs b/MimeKit/Cryptography/X509KeyUsageFlags.cs index c0156f8e73..689924acd6 100644 --- a/MimeKit/Cryptography/X509KeyUsageFlags.cs +++ b/MimeKit/Cryptography/X509KeyUsageFlags.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,9 +33,9 @@ namespace MimeKit.Cryptography { /// /// The X.509 Key Usage Flags can be used to determine what operations /// a certificate can be used for. - /// A value of indicates that + /// A value of indicates that /// there are no restrictions on the use of the - /// . + /// . /// [Flags] public enum X509KeyUsageFlags { diff --git a/MimeKit/DomainList.cs b/MimeKit/DomainList.cs index 0654a003bd..14d4e33f65 100644 --- a/MimeKit/DomainList.cs +++ b/MimeKit/DomainList.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ using System; using System.Text; using System.Collections; +using System.Globalization; using System.Collections.Generic; using MimeKit.Utils; @@ -44,7 +45,7 @@ public class DomainList : IList readonly List domains; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new based on the domains provided. @@ -62,7 +63,7 @@ public DomainList (IEnumerable domains) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -216,7 +217,7 @@ public bool Contains (string domain) } /// - /// Copies all of the domains in the to the specified array. + /// Copies all of the domains in the to the specified array. /// /// /// Copies all of the domains within the into the array, @@ -260,7 +261,7 @@ public bool Remove (string domain) } /// - /// Gets the number of domains in the . + /// Gets the number of domains in the . /// /// /// Indicates the number of domains in the list. @@ -271,7 +272,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether the is read only. /// /// /// A is never read-only. @@ -333,15 +334,12 @@ internal string Encode (FormatOptions options) var builder = new StringBuilder (); for (int i = 0; i < domains.Count; i++) { - if (IsNullOrWhiteSpace (domains[i]) && builder.Length == 0) + if (IsNullOrWhiteSpace (domains[i])) continue; if (builder.Length > 0) builder.Append (','); - if (IsNullOrWhiteSpace (domains[i])) - continue; - builder.Append ('@'); if (!options.International && ParseUtils.IsInternational (domains[i])) { @@ -369,14 +367,13 @@ public override string ToString () var builder = new StringBuilder (); for (int i = 0; i < domains.Count; i++) { - if (IsNullOrWhiteSpace (domains[i]) && builder.Length == 0) + if (IsNullOrWhiteSpace (domains[i])) continue; if (builder.Length > 0) builder.Append (','); - if (!IsNullOrWhiteSpace (domains[i])) - builder.Append ('@'); + builder.Append ('@'); builder.Append (domains[i]); } @@ -393,7 +390,7 @@ void OnChanged () } /// - /// Tries to parse a list of domains. + /// Try to parse a list of domains. /// /// /// Attempts to parse a from the text buffer starting at the @@ -422,7 +419,7 @@ internal static bool TryParse (byte[] buffer, ref int index, int endIndex, bool if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete domain-list at offset: {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete domain-list at offset: {0}", startIndex), startIndex, index); return false; } @@ -453,7 +450,7 @@ internal static bool TryParse (byte[] buffer, ref int index, int endIndex, bool } /// - /// Tries to parse a list of domains. + /// Try to parse a list of domains. /// /// /// Attempts to parse a from the supplied text. The index diff --git a/MimeKit/EncodingConstraint.cs b/MimeKit/EncodingConstraint.cs index b86f4bbdfa..d3ce03b205 100644 --- a/MimeKit/EncodingConstraint.cs +++ b/MimeKit/EncodingConstraint.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Encodings/Base64Decoder.cs b/MimeKit/Encodings/Base64Decoder.cs index 35e43c9aea..ba2e5b2aca 100644 --- a/MimeKit/Encodings/Base64Decoder.cs +++ b/MimeKit/Encodings/Base64Decoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ public class Base64Decoder : IMimeDecoder byte npad; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new base64 decoder. diff --git a/MimeKit/Encodings/Base64Encoder.cs b/MimeKit/Encodings/Base64Encoder.cs index 70a60d86f4..5dcf0f45ec 100644 --- a/MimeKit/Encodings/Base64Encoder.cs +++ b/MimeKit/Encodings/Base64Encoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -52,7 +52,7 @@ public class Base64Encoder : IMimeEncoder byte saved; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new base64 encoder. @@ -72,7 +72,7 @@ internal Base64Encoder (bool rfc2047, int maxLineLength = 72) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new base64 encoder. @@ -277,7 +277,7 @@ unsafe int Flush (byte* input, int length, byte* output) *outptr++ = (byte) '\n'; Reset (); - + return (int) (outptr - output); } diff --git a/MimeKit/Encodings/HexDecoder.cs b/MimeKit/Encodings/HexDecoder.cs index 8f2606642a..d7fb2e5155 100644 --- a/MimeKit/Encodings/HexDecoder.cs +++ b/MimeKit/Encodings/HexDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ enum HexDecoderState : byte { byte saved; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new hex decoder. diff --git a/MimeKit/Encodings/HexEncoder.cs b/MimeKit/Encodings/HexEncoder.cs index 19cf2d4ebd..5a7beaea5d 100644 --- a/MimeKit/Encodings/HexEncoder.cs +++ b/MimeKit/Encodings/HexEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,7 +44,7 @@ public class HexEncoder : IMimeEncoder }; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new hex encoder. diff --git a/MimeKit/Encodings/IMimeDecoder.cs b/MimeKit/Encodings/IMimeDecoder.cs index d940ad5995..dec3d763ef 100644 --- a/MimeKit/Encodings/IMimeDecoder.cs +++ b/MimeKit/Encodings/IMimeDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Encodings/IMimeEncoder.cs b/MimeKit/Encodings/IMimeEncoder.cs index 8733114d2f..741bb1255e 100644 --- a/MimeKit/Encodings/IMimeEncoder.cs +++ b/MimeKit/Encodings/IMimeEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Encodings/PassThroughDecoder.cs b/MimeKit/Encodings/PassThroughDecoder.cs index 63b01d889f..87aaf73f6c 100644 --- a/MimeKit/Encodings/PassThroughDecoder.cs +++ b/MimeKit/Encodings/PassThroughDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ namespace MimeKit.Encodings { public class PassThroughDecoder : IMimeDecoder { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// The encoding to return in the property. /// diff --git a/MimeKit/Encodings/PassThroughEncoder.cs b/MimeKit/Encodings/PassThroughEncoder.cs index 3931ba5c2e..3dc50db2ad 100644 --- a/MimeKit/Encodings/PassThroughEncoder.cs +++ b/MimeKit/Encodings/PassThroughEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ namespace MimeKit.Encodings { public class PassThroughEncoder : IMimeEncoder { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// The encoding to return in the property. /// diff --git a/MimeKit/Encodings/QEncoder.cs b/MimeKit/Encodings/QEncoder.cs index 53acc7382a..e8a5ba3d8c 100644 --- a/MimeKit/Encodings/QEncoder.cs +++ b/MimeKit/Encodings/QEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -66,7 +66,7 @@ public class QEncoder : IMimeEncoder readonly CharType mask; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new rfc2047 quoted-printable encoder. diff --git a/MimeKit/Encodings/QuotedPrintableDecoder.cs b/MimeKit/Encodings/QuotedPrintableDecoder.cs index 1178248351..eee3f167ac 100644 --- a/MimeKit/Encodings/QuotedPrintableDecoder.cs +++ b/MimeKit/Encodings/QuotedPrintableDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -51,7 +51,7 @@ enum QpDecoderState : byte { byte saved; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new quoted-printable decoder. @@ -65,7 +65,7 @@ public QuotedPrintableDecoder (bool rfc2047) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new quoted-printable decoder. diff --git a/MimeKit/Encodings/QuotedPrintableEncoder.cs b/MimeKit/Encodings/QuotedPrintableEncoder.cs index 1bf7cbf4b7..ff7d4fc892 100644 --- a/MimeKit/Encodings/QuotedPrintableEncoder.cs +++ b/MimeKit/Encodings/QuotedPrintableEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -52,7 +52,7 @@ public class QuotedPrintableEncoder : IMimeEncoder short saved; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new quoted-printable encoder. diff --git a/MimeKit/Encodings/UUDecoder.cs b/MimeKit/Encodings/UUDecoder.cs index f40ec6b22d..59a86c8ed5 100644 --- a/MimeKit/Encodings/UUDecoder.cs +++ b/MimeKit/Encodings/UUDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -77,7 +77,7 @@ enum UUDecoderState : byte { uint saved; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new Unix-to-Unix decoder. @@ -92,7 +92,7 @@ public UUDecoder (bool payloadOnly) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new Unix-to-Unix decoder. diff --git a/MimeKit/Encodings/UUEncoder.cs b/MimeKit/Encodings/UUEncoder.cs index 93dcc10064..eef18cdc1f 100644 --- a/MimeKit/Encodings/UUEncoder.cs +++ b/MimeKit/Encodings/UUEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ public class UUEncoder : IMimeEncoder byte uulen; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new Unix-to-Unix encoder. @@ -134,17 +134,17 @@ unsafe int Encode (byte* input, int length, byte[] outbuf, byte* output, byte *u byte* bufptr; byte b0, b1, b2; - if ((length + uulen) < 45) { + if ((length + nsaved + uulen) < 45) { // not enough input to write a full uuencoded line bufptr = uuptr + ((uulen / 3) * 4); } else { bufptr = outptr + 1; - + if (uulen > 0) { // copy the previous call's uubuf to output int n = (uulen / 3) * 4; - Buffer.BlockCopy (uubuf, 0, outbuf, (int) (bufptr - output), n); + Buffer.BlockCopy (uubuf, 0, outbuf, 1, n); bufptr += n; } } @@ -186,8 +186,8 @@ unsafe int Encode (byte* input, int length, byte[] outbuf, byte* output, byte *u } } - while (inptr < inend) { - while (uulen < 45 && (inptr + 3) <= inend) { + do { + while (uulen < 45 && (inptr + 2) < inend) { b0 = *inptr++; b1 = *inptr++; b2 = *inptr++; @@ -216,10 +216,12 @@ unsafe int Encode (byte* input, int length, byte[] outbuf, byte* output, byte *u } } else { // not enough input to continue... - for (nsaved = 0, saved = 0; inptr < inend; nsaved++) + while (inptr < inend) { saved = (saved << 8) | *inptr++; + nsaved++; + } } - } + } while (inptr < inend); return (int) (outptr - output); } diff --git a/MimeKit/Encodings/YDecoder.cs b/MimeKit/Encodings/YDecoder.cs index caaeac9267..61d8cbbf5c 100644 --- a/MimeKit/Encodings/YDecoder.cs +++ b/MimeKit/Encodings/YDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -72,7 +72,7 @@ enum YDecoderState : byte { Crc32 crc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new yEnc decoder. @@ -88,7 +88,7 @@ public YDecoder (bool payloadOnly) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new yEnc decoder. diff --git a/MimeKit/Encodings/YEncoder.cs b/MimeKit/Encodings/YEncoder.cs index 49f25dbd39..0873eec5fe 100644 --- a/MimeKit/Encodings/YEncoder.cs +++ b/MimeKit/Encodings/YEncoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,7 +44,7 @@ public class YEncoder : IMimeEncoder Crc32 crc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new yEnc encoder. diff --git a/MimeKit/FormatOptions.cs b/MimeKit/FormatOptions.cs index 56d99dd74b..8866754dc8 100644 --- a/MimeKit/FormatOptions.cs +++ b/MimeKit/FormatOptions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -50,6 +50,12 @@ public enum NewLineFormat : byte { /// The DOS New-Line format ("\r\n"). /// Dos, + + /// + /// A mixed New-Line format where some lines use Unix-based line endings and + /// other lines use DOS-based line endings. + /// + Mixed, } /// @@ -73,7 +79,10 @@ public class FormatOptions ParameterEncodingMethod parameterEncodingMethod; bool allowMixedHeaderCharsets; NewLineFormat newLineFormat; + bool verifyingSignature; + bool ensureNewLine; bool international; + int maxLineLength; /// /// The default formatting options. @@ -86,25 +95,43 @@ public class FormatOptions public static readonly FormatOptions Default; /// - /// Gets the maximum line length used by the encoders. The encoders + /// Gets or sets the maximum line length used by the encoders. The encoders /// use this value to determine where to place line breaks. /// /// /// Specifies the maximum line length to use when line-wrapping headers. /// /// The maximum line length. + /// + /// is out of range. It must be between 60 and 998. + /// + /// + /// cannot be changed. + /// public int MaxLineLength { - get { return DefaultMaxLineLength; } + get { return maxLineLength; } + set { + if (this == Default) + throw new InvalidOperationException ("The default formatting options cannot be changed."); + + if (value < MinimumLineLength || value > MaximumLineLength) + throw new ArgumentOutOfRangeException (nameof (value)); + + maxLineLength = value; + } } /// - /// Gets or sets the new-line format. + /// Get or set the new-line format. /// /// /// Specifies the new-line encoding to use when writing the message /// or entity to a stream. /// /// The new-line format. + /// + /// is not a valid . + /// /// /// cannot be changed. /// @@ -114,7 +141,39 @@ public NewLineFormat NewLineFormat { if (this == Default) throw new InvalidOperationException ("The default formatting options cannot be changed."); - newLineFormat = value; + switch (newLineFormat) { + case NewLineFormat.Unix: + case NewLineFormat.Dos: + newLineFormat = value; + break; + default: + throw new ArgumentOutOfRangeException (nameof (value)); + } + } + } + + /// + /// Get or set whether the formatter should ensure that messages end with a new-line sequence. + /// + /// + /// By default, when writing a to a stream, the serializer attempts to + /// maintain byte-for-byte compatibility with the original stream that the message was parsed from. + /// This means that if the ogirinal message stream did not end with a new-line sequence, then the + /// output of writing the message back to a stream will also not end with a new-line sequence. + /// To override this behavior, you can set this property to true in order to ensure + /// that writing the message back to a stream will always end with a new-line sequence. + /// + /// true in order to ensure that the message will end with a new-line sequence; otherwise, false. + /// + /// cannot be changed. + /// + public bool EnsureNewLine { + get { return ensureNewLine; } + set { + if (this == Default) + throw new InvalidOperationException ("The default formatting options cannot be changed."); + + ensureNewLine = value; } } @@ -136,8 +195,13 @@ internal byte[] NewLineBytes { get { return NewLineFormats[(int) NewLineFormat]; } } + internal bool VerifyingSignature { + get { return verifyingSignature; } + set { verifyingSignature = value; } + } + /// - /// Gets the message headers that should be hidden. + /// Get the message headers that should be hidden. /// /// /// Specifies the set of headers that should be removed when @@ -152,7 +216,7 @@ public HashSet HiddenHeaders { } /// - /// Gets or sets whether the new "Internationalized Email" formatting standards should be used. + /// Get or set whether the new "Internationalized Email" formatting standards should be used. /// /// /// The new "Internationalized Email" format is defined by @@ -178,11 +242,11 @@ public bool International { } /// - /// Gets or sets whether the formatter should allow mixed charsets in the headers. + /// Get or set whether the formatter should allow mixed charsets in the headers. /// /// - /// When this option is enabled, the MIME formatter will try to use US-ASCII and/or - /// ISO-8859-1 to encode headers when appropriate rather than being forced to use the + /// When this option is enabled, the MIME formatter will try to use us-ascii and/or + /// iso-8859-1 to encode headers when appropriate rather than being forced to use the /// specified charset for all encoded-word tokens in order to maximize readability. /// Unfortunately, mail clients like Outlook and Thunderbird do not treat /// encoded-word tokens individually and assume that all tokens are encoded using the @@ -192,7 +256,7 @@ public bool International { /// /// https://bugzilla.mozilla.org/show_bug.cgi?id=317263. /// - /// true if the formatter should be allowed to use ISO-8859-1 when encoding headers; otherwise, false. + /// true if the formatter should be allowed to use us-ascii and/or iso-8859-1 when encoding headers; otherwise, false. public bool AllowMixedHeaderCharsets { get { return allowMixedHeaderCharsets; } set { @@ -204,12 +268,12 @@ public bool AllowMixedHeaderCharsets { } /// - /// The method to use for encoding Content-Type and Content-Disposition parameter values. + /// Get or set the method to use for encoding Content-Type and Content-Disposition parameter values. /// /// /// The method to use for encoding Content-Type and Content-Disposition parameter /// values when the is set to - /// . + /// . /// The MIME specifications specify that the proper method for encoding Content-Type /// and Content-Disposition parameter values is the method described in /// rfc2231. However, it is common for @@ -243,7 +307,7 @@ static FormatOptions () } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new set of formatting options for use with methods such as @@ -253,8 +317,9 @@ public FormatOptions () { HiddenHeaders = new HashSet (); parameterEncodingMethod = ParameterEncodingMethod.Rfc2231; - //maxLineLength = DefaultMaxLineLength; + maxLineLength = DefaultMaxLineLength; allowMixedHeaderCharsets = false; + ensureNewLine = false; international = false; if (Environment.NewLine.Length == 1) @@ -264,7 +329,7 @@ public FormatOptions () } /// - /// Clones an instance of . + /// Clones an instance of . /// /// /// Clones the formatting options. @@ -273,11 +338,13 @@ public FormatOptions () public FormatOptions Clone () { var options = new FormatOptions (); - //options.maxLineLength = maxLineLength; + options.maxLineLength = maxLineLength; options.newLineFormat = newLineFormat; + options.ensureNewLine = ensureNewLine; options.HiddenHeaders = new HashSet (HiddenHeaders); options.allowMixedHeaderCharsets = allowMixedHeaderCharsets; options.parameterEncodingMethod = parameterEncodingMethod; + options.verifyingSignature = verifyingSignature; options.international = international; return options; } diff --git a/MimeKit/GroupAddress.cs b/MimeKit/GroupAddress.cs index 0e0a248904..deedc742f0 100644 --- a/MimeKit/GroupAddress.cs +++ b/MimeKit/GroupAddress.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,12 +27,9 @@ using System; using System.Linq; using System.Text; +using System.Globalization; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.Utils; namespace MimeKit { @@ -46,7 +43,7 @@ namespace MimeKit { public class GroupAddress : InternetAddress { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name and list of addresses. The @@ -65,7 +62,7 @@ public GroupAddress (Encoding encoding, string name, IEnumerable - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name and list of addresses. @@ -77,7 +74,7 @@ public GroupAddress (string name, IEnumerable addresses) : this } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name. The specified @@ -95,7 +92,7 @@ public GroupAddress (Encoding encoding, string name) : base (encoding, name) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name. @@ -121,23 +118,21 @@ public override InternetAddress Clone () /// Gets the members of the group. /// /// - /// Represents the member addresses of the group. Typically the member addresses - /// will be of the variety, but it is possible - /// for groups to contain other groups. + /// Represents the member addresses of the group. If the group address properly conforms + /// to the internet standards, every group member should be of the + /// variety. When handling group addresses constructed by third-party software, it is possible + /// for groups to contain members of the variety. + /// When constructing new messages, it is recommended that address groups not contain + /// anything other than members in order to comply with internet + /// standards. /// /// The list of members. public InternetAddressList Members { get; private set; } - internal override void Encode (FormatOptions options, StringBuilder builder, ref int lineLength) + internal override void Encode (FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength) { - if (builder == null) - throw new ArgumentNullException (nameof (builder)); - - if (lineLength < 0) - throw new ArgumentOutOfRangeException (nameof (lineLength)); - if (!string.IsNullOrEmpty (Name)) { string name; @@ -151,11 +146,11 @@ internal override void Encode (FormatOptions options, StringBuilder builder, ref if (lineLength + name.Length > options.MaxLineLength) { if (name.Length > options.MaxLineLength) { // we need to break up the name... - builder.AppendFolded (options, name, ref lineLength); + builder.AppendFolded (options, firstToken, name, ref lineLength); } else { // the name itself is short enough to fit on a single line, // but only if we write it on a line by itself - if (lineLength > 1) { + if (!firstToken && lineLength > 1) { builder.LineWrap (options); lineLength = 1; } @@ -173,7 +168,7 @@ internal override void Encode (FormatOptions options, StringBuilder builder, ref builder.Append (": "); lineLength += 2; - Members.Encode (options, builder, ref lineLength); + Members.Encode (options, builder, false, ref lineLength); builder.Append (';'); lineLength++; @@ -205,7 +200,7 @@ public override string ToString (FormatOptions options, bool encode) if (encode) { int lineLength = 0; - Encode (options, builder, ref lineLength); + Encode (options, builder, true, ref lineLength); } else { builder.Append (Name); builder.Append (':'); @@ -227,14 +222,14 @@ public override string ToString (FormatOptions options, bool encode) #region IEquatable implementation /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// /// Compares two group addresses to determine if they are identical or not. /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals (InternetAddress other) { var group = other as GroupAddress; @@ -271,7 +266,7 @@ static bool TryParse (ParserOptions options, byte[] text, ref int index, int end } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -311,7 +306,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -335,7 +330,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Grou } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -373,7 +368,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -395,7 +390,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out GroupAddress gro } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -429,7 +424,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out GroupAddr } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -447,7 +442,7 @@ public static bool TryParse (byte[] buffer, out GroupAddress group) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -484,7 +479,7 @@ public static bool TryParse (ParserOptions options, string text, out GroupAddres } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single . If the address is not a group address or @@ -502,13 +497,13 @@ public static bool TryParse (string text, out GroupAddress group) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -539,19 +534,19 @@ public static bool TryParse (string text, out GroupAddress group) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return group; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -571,13 +566,13 @@ public static bool TryParse (string text, out GroupAddress group) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -606,19 +601,19 @@ public static bool TryParse (string text, out GroupAddress group) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return group; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// @@ -636,13 +631,13 @@ public static bool TryParse (string text, out GroupAddress group) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// @@ -667,19 +662,19 @@ public static bool TryParse (string text, out GroupAddress group) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return group; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -693,13 +688,13 @@ public static bool TryParse (string text, out GroupAddress group) } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The text. /// @@ -729,19 +724,19 @@ public static bool TryParse (string text, out GroupAddress group) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return group; } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single . If the address is not a group address or /// there is more than a single group address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The text. /// /// is null. diff --git a/MimeKit/Header.cs b/MimeKit/Header.cs index d31a5e7a04..24b60853e1 100644 --- a/MimeKit/Header.cs +++ b/MimeKit/Header.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,11 +28,8 @@ using System.Text; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.Utils; +using MimeKit.Cryptography; namespace MimeKit { /// @@ -53,11 +50,12 @@ public class Header //Encoding charset = CharsetUtils.UTF8; readonly byte[] rawField; + bool explicitRawValue; string textValue; byte[] rawValue; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -96,7 +94,7 @@ public Header (Encoding encoding, HeaderId id, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -139,7 +137,7 @@ public Header (string charset, HeaderId id, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -158,7 +156,7 @@ public Header (HeaderId id, string value) : this (Encoding.UTF8, id, value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -207,7 +205,7 @@ public Header (Encoding encoding, string field, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -260,7 +258,7 @@ public Header (string charset, string field, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message or entity header for the specified field and @@ -280,8 +278,19 @@ public Header (string field, string value) : this (Encoding.UTF8, field, value) { } - // Note: this .ctor is only used by Clone() - internal Header (ParserOptions options, HeaderId id, string name, byte[] field, byte[] value) + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new message or entity header with the specified values. + /// This constructor is used by . + /// + /// The parser options used. + /// The id of the header. + /// The name of the header field. + /// The raw header field. + /// The raw value of the header. + protected Header (ParserOptions options, HeaderId id, string name, byte[] field, byte[] value) { Options = options; rawField = field; @@ -290,12 +299,24 @@ internal Header (ParserOptions options, HeaderId id, string name, byte[] field, Id = id; } - internal Header (ParserOptions options, byte[] field, byte[] value) + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new message or entity header with the specified raw values. + /// This constructor is used by the + /// TryParse methods. + /// + /// The parser options used. + /// The raw header field. + /// The raw value of the header. + /// true if the header field is invalid; othereise, false. + internal protected Header (ParserOptions options, byte[] field, byte[] value, bool invalid) { var chars = new char[field.Length]; int count = 0; - while (count < field.Length && !field[count].IsBlank ()) { + while (count < field.Length && (invalid || !field[count].IsBlank ())) { chars[count] = (char) field[count]; count++; } @@ -306,9 +327,22 @@ internal Header (ParserOptions options, byte[] field, byte[] value) Field = new string (chars, 0, count); Id = Field.ToHeaderId (); + IsInvalid = invalid; } - internal Header (ParserOptions options, HeaderId id, string field, byte[] value) + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new message or entity header with the specified raw values. + /// This constructor is used by and + /// when serializing new values for headers. + /// + /// The parser options used. + /// The id of the header. + /// The raw header field. + /// The raw value of the header. + internal protected Header (ParserOptions options, HeaderId id, string field, byte[] value) { Options = options; rawField = Encoding.ASCII.GetBytes (field); @@ -326,7 +360,10 @@ internal Header (ParserOptions options, HeaderId id, string field, byte[] value) /// A copy of the header with its current state. public Header Clone () { - var header = new Header (Options, Id, Field, RawField, RawValue); + var header = new Header (Options, Id, Field, rawField, rawValue) { + explicitRawValue = explicitRawValue, + IsInvalid = IsInvalid + }; // if the textValue has already been calculated, set it on the cloned header as well. header.textValue = textValue; @@ -368,6 +405,10 @@ public HeaderId Id { get; private set; } + internal bool IsInvalid { + get; private set; + } + /// /// Gets the raw field name of the header. /// @@ -403,7 +444,7 @@ public byte[] RawValue { public string Value { get { if (textValue == null) - textValue = Unfold (Rfc2047.DecodeText (Options, RawValue)); + textValue = Unfold (Rfc2047.DecodeText (Options, rawValue)); return textValue; } @@ -433,7 +474,7 @@ public string GetValue (Encoding encoding) var options = Options.Clone (); options.CharsetEncoding = encoding; - return Unfold (Rfc2047.DecodeText (options, RawValue)); + return Unfold (Rfc2047.DecodeText (options, rawValue)); } /// @@ -459,7 +500,7 @@ public string GetValue (string charset) return GetValue (encoding); } - static byte[] EncodeAddressHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeAddressHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var encoded = new StringBuilder (" "); int lineLength = field.Length + 2; @@ -468,7 +509,7 @@ static byte[] EncodeAddressHeader (ParserOptions options, FormatOptions format, if (!InternetAddressList.TryParse (options, value, out list)) return (byte[]) format.NewLineBytes.Clone (); - list.Encode (format, encoded, ref lineLength); + list.Encode (format, encoded, true, ref lineLength); encoded.Append (format.NewLine); if (format.International) @@ -477,9 +518,9 @@ static byte[] EncodeAddressHeader (ParserOptions options, FormatOptions format, return Encoding.ASCII.GetBytes (encoded.ToString ()); } - static byte[] EncodeMessageIdHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeMessageIdHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { - return charset.GetBytes (" " + value + format.NewLine); + return encoding.GetBytes (" " + value + format.NewLine); } delegate void ReceivedTokenSkipValueFunc (byte[] text, ref int index); @@ -583,10 +624,10 @@ public ReceivedTokenValue (int startIndex, int length) } } - static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var tokens = new List (); - var rawValue = charset.GetBytes (value); + var rawValue = encoding.GetBytes (value); var encoded = new StringBuilder (); int lineLength = field.Length + 1; bool date = false; @@ -605,7 +646,7 @@ static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format, while (index < rawValue.Length && !rawValue[index].IsWhitespace ()) index++; - var atom = charset.GetString (rawValue, startIndex, index - startIndex); + var atom = encoding.GetString (rawValue, startIndex, index - startIndex); for (int i = 0; i < ReceivedTokens.Length; i++) { if (atom == ReceivedTokens[i].Atom) { @@ -644,7 +685,7 @@ static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format, } foreach (var token in tokens) { - var text = charset.GetString (rawValue, token.StartIndex, token.Length).TrimEnd (); + var text = encoding.GetString (rawValue, token.StartIndex, token.Length).TrimEnd (); if (count > 0 && lineLength + text.Length + 1 > format.MaxLineLength) { encoded.Append (format.NewLine); @@ -663,7 +704,22 @@ static byte[] EncodeReceivedHeader (ParserOptions options, FormatOptions format, encoded.Append (format.NewLine); - return charset.GetBytes (encoded.ToString ()); + return encoding.GetBytes (encoded.ToString ()); + } + + static byte[] EncodeAuthenticationResultsHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) + { + var buffer = Encoding.UTF8.GetBytes (value); + + if (!AuthenticationResults.TryParse (buffer, out AuthenticationResults authres)) + return EncodeUnstructuredHeader (options, format, encoding, field, value); + + var encoded = new StringBuilder (); + int lineLength = field.Length + 1; + + authres.Encode (format, encoded, lineLength); + + return encoding.GetBytes (encoded.ToString ()); } static void EncodeDkimLongValue (FormatOptions format, StringBuilder encoded, ref int lineLength, string value) @@ -716,7 +772,7 @@ static void EncodeDkimHeaderList (FormatOptions format, StringBuilder encoded, r } } - static byte[] EncodeDkimSignatureHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeDkimOrArcSignatureHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var encoded = new StringBuilder (); int lineLength = field.Length + 1; @@ -780,10 +836,10 @@ static byte[] EncodeDkimSignatureHeader (ParserOptions options, FormatOptions fo encoded.Append (format.NewLine); - return charset.GetBytes (encoded.ToString ()); + return encoding.GetBytes (encoded.ToString ()); } - static byte[] EncodeReferencesHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeReferencesHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var encoded = new StringBuilder (); int lineLength = field.Length + 1; @@ -807,7 +863,7 @@ static byte[] EncodeReferencesHeader (ParserOptions options, FormatOptions forma encoded.Append (format.NewLine); - return charset.GetBytes (encoded.ToString ()); + return encoding.GetBytes (encoded.ToString ()); } static bool IsWhiteSpace (char c) @@ -936,23 +992,23 @@ internal static string Fold (FormatOptions format, string field, string value) return folded.ToString (); } - static byte[] EncodeContentDisposition (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeContentDisposition (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var disposition = ContentDisposition.Parse (options, value); - var encoded = disposition.Encode (format, charset); + var encoded = disposition.Encode (format, encoding); return Encoding.UTF8.GetBytes (encoded); } - static byte[] EncodeContentType (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeContentType (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { var contentType = ContentType.Parse (options, value); - var encoded = contentType.Encode (format, charset); + var encoded = contentType.Encode (format, encoding); return Encoding.UTF8.GetBytes (encoded); } - static byte[] EncodeUnstructuredHeader (ParserOptions options, FormatOptions format, Encoding charset, string field, string value) + static byte[] EncodeUnstructuredHeader (ParserOptions options, FormatOptions format, Encoding encoding, string field, string value) { if (format.International) { var folded = Fold (format, field, value); @@ -960,12 +1016,24 @@ static byte[] EncodeUnstructuredHeader (ParserOptions options, FormatOptions for return Encoding.UTF8.GetBytes (folded); } - var encoded = Rfc2047.EncodeText (format, charset, value); + var encoded = Rfc2047.EncodeText (format, encoding, value); return Rfc2047.FoldUnstructuredHeader (format, field, encoded); } - byte[] FormatRawValue (FormatOptions format, Encoding encoding) + /// + /// Format the raw value of the header to conform with the specified formatting options. + /// + /// + /// This method will called by the SetValue + /// methods and may also be conditionally called when the header is being written to a + /// . + /// + /// The formatting options. + /// The character encoding to be used. + /// The decoded (and unfolded) header value. + /// A byte array containing the raw header value that should be written. + protected virtual byte[] FormatRawValue (FormatOptions format, Encoding encoding, string value) { switch (Id) { case HeaderId.DispositionNotificationTo: @@ -981,34 +1049,40 @@ byte[] FormatRawValue (FormatOptions format, Encoding encoding) case HeaderId.Bcc: case HeaderId.Cc: case HeaderId.To: - return EncodeAddressHeader (Options, format, encoding, Field, textValue); + return EncodeAddressHeader (Options, format, encoding, Field, value); case HeaderId.Received: - return EncodeReceivedHeader (Options, format, encoding, Field, textValue); + return EncodeReceivedHeader (Options, format, encoding, Field, value); case HeaderId.ResentMessageId: + case HeaderId.InReplyTo: case HeaderId.MessageId: case HeaderId.ContentId: - return EncodeMessageIdHeader (Options, format, encoding, Field, textValue); + return EncodeMessageIdHeader (Options, format, encoding, Field, value); case HeaderId.References: - return EncodeReferencesHeader (Options, format, encoding, Field, textValue); + return EncodeReferencesHeader (Options, format, encoding, Field, value); case HeaderId.ContentDisposition: - return EncodeContentDisposition (Options, format, encoding, Field, textValue); + return EncodeContentDisposition (Options, format, encoding, Field, value); case HeaderId.ContentType: - return EncodeContentType (Options, format, encoding, Field, textValue); + return EncodeContentType (Options, format, encoding, Field, value); + case HeaderId.ArcAuthenticationResults: + case HeaderId.AuthenticationResults: + return EncodeAuthenticationResultsHeader (Options, format, encoding, Field, value); + case HeaderId.ArcMessageSignature: + case HeaderId.ArcSeal: case HeaderId.DkimSignature: - return EncodeDkimSignatureHeader (Options, format, encoding, Field, textValue); + return EncodeDkimOrArcSignatureHeader (Options, format, encoding, Field, value); default: - return EncodeUnstructuredHeader (Options, format, encoding, Field, textValue); + return EncodeUnstructuredHeader (Options, format, encoding, Field, value); } } internal byte[] GetRawValue (FormatOptions format) { - if (format.International) { + if (format.International && !explicitRawValue) { if (textValue == null) - textValue = Unfold (Rfc2047.DecodeText (Options, RawValue)); + textValue = Unfold (Rfc2047.DecodeText (Options, rawValue)); // Note: if we're reformatting to be International, then charset doesn't matter. - return FormatRawValue (format, CharsetUtils.UTF8); + return FormatRawValue (format, CharsetUtils.UTF8, textValue); } return rawValue; @@ -1045,7 +1119,7 @@ public void SetValue (FormatOptions format, Encoding encoding, string value) textValue = Unfold (value.Trim ()); - rawValue = FormatRawValue (format, encoding); + rawValue = FormatRawValue (format, encoding, textValue); // cache the formatting options that change the way the header is formatted //allowMixedHeaderCharsets = format.AllowMixedHeaderCharsets; @@ -1138,6 +1212,36 @@ public void SetValue (string charset, string value) SetValue (FormatOptions.Default, encoding, value); } + /// + /// Set the raw header value. + /// + /// + /// Sets the raw header value. + /// This method can be used to override default encoding and folding behavior + /// for a particular header. + /// + /// The raw header value. + /// + /// is null. + /// + /// + /// does not end with a new-line character. + /// + public void SetRawValue (byte[] value) + { + if (value == null) + throw new ArgumentNullException (nameof (value)); + + if (value.Length == 0 || value[value.Length - 1] != (byte) '\n') + throw new ArgumentException ("The raw value MUST end with a new-line character.", nameof (value)); + + explicitRawValue = true; + rawValue = value; + textValue = null; + + OnChanged (); + } + internal event EventHandler Changed; void OnChanged () @@ -1155,7 +1259,7 @@ void OnChanged () /// A string representing the . public override string ToString () { - return Field + ": " + Value; + return IsInvalid ? Field : Field + ": " + Value; } /// @@ -1228,6 +1332,7 @@ internal static unsafe bool TryParse (ParserOptions options, byte* input, int le byte* inend = input + length; byte* start = input; byte* inptr = input; + var invalid = false; // find the end of the field name if (strict) { @@ -1242,8 +1347,13 @@ internal static unsafe bool TryParse (ParserOptions options, byte* input, int le inptr++; if (inptr == inend || *inptr != ':') { - header = null; - return false; + if (strict) { + header = null; + return false; + } + + invalid = true; + inptr = inend; } var field = new byte[(int) (inptr - start)]; @@ -1254,25 +1364,31 @@ internal static unsafe bool TryParse (ParserOptions options, byte* input, int le *outptr++ = *start++; } - inptr++; + byte[] value; - int count = (int) (inend - inptr); - var value = new byte[count]; + if (inptr < inend) { + inptr++; - fixed (byte *outbuf = value) { - byte* outptr = outbuf; + int count = (int) (inend - inptr); + value = new byte[count]; - while (inptr < inend) - *outptr++ = *inptr++; + fixed (byte* outbuf = value) { + byte* outptr = outbuf; + + while (inptr < inend) + *outptr++ = *inptr++; + } + } else { + value = new byte[0]; } - header = new Header (options, field, value); + header = new Header (options, field, value, invalid); return true; } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the supplied buffer starting at the given index @@ -1305,7 +1421,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the supplied buffer starting at the given index @@ -1329,7 +1445,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Head } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the supplied buffer starting at the specified index. @@ -1361,7 +1477,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the supplied buffer starting at the specified index. @@ -1382,7 +1498,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out Header header) } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the specified buffer. @@ -1398,17 +1514,11 @@ public static bool TryParse (byte[] buffer, int startIndex, out Header header) /// public static bool TryParse (ParserOptions options, byte[] buffer, out Header header) { - ParseUtils.ValidateArguments (options, buffer); - - unsafe { - fixed (byte* inptr = buffer) { - return TryParse (options.Clone (), inptr, buffer.Length, true, out header); - } - } + return TryParse (options, buffer, 0, out header); } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a header from the specified buffer. @@ -1425,7 +1535,7 @@ public static bool TryParse (byte[] buffer, out Header header) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a header from the specified text. @@ -1453,7 +1563,7 @@ public static bool TryParse (ParserOptions options, string text, out Header head } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a header from the specified text. diff --git a/MimeKit/HeaderId.cs b/MimeKit/HeaderId.cs index 3177ca1888..a3ea7f8ca7 100644 --- a/MimeKit/HeaderId.cs +++ b/MimeKit/HeaderId.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,11 +41,21 @@ namespace MimeKit { /// comparing strings. /// public enum HeaderId { + /// + /// The Accept-Language header field. + /// + AcceptLanguage, + /// /// The Ad-Hoc header field. /// AdHoc, + /// + /// The Alternate-Recipient header field. + /// + AlternateRecipient, + /// /// The Apparently-To header field. /// @@ -56,16 +66,89 @@ public enum HeaderId { /// Approved, + /// + /// The ARC-Authentication-Results header field. + /// + [HeaderName ("ARC-Authentication-Results")] + ArcAuthenticationResults, + + /// + /// The ARC-Message-Signature header field. + /// + [HeaderName ("ARC-Message-Signature")] + ArcMessageSignature, + + /// + /// The ARC-Seal header field. + /// + [HeaderName ("ARC-Seal")] + ArcSeal, + + /// + /// The Archive header field. + /// + Archive, + + /// + /// The Archived-At header field. + /// + ArchivedAt, + /// /// The Article header field. /// Article, + /// + /// The Authentication-Results header field. + /// + AuthenticationResults, + + /// + /// The Autocrypt header field. + /// + Autocrypt, + + /// + /// The Autocrypt-Gossip header field. + /// + AutocryptGossip, + + /// + /// The Autocrypt-Setup-Message header field. + /// + AutocryptSetupMessage, + + /// + /// The Autoforwarded header field. + /// + Autoforwarded, + + /// + /// The Auto-Submitted header field. + /// + AutoSubmitted, + + /// + /// The Autosubmitted header field. + /// + Autosubmitted, + + /// + /// The Base header field. + /// + Base, + /// /// The Bcc header field. /// Bcc, + /// + /// The Body header field. + /// + Body, + /// /// The Bytes header field. /// @@ -81,6 +164,11 @@ public enum HeaderId { /// Comments, + /// + /// The Content-Alternative header field. + /// + ContentAlternative, + /// /// The Content-Base header field. /// @@ -106,11 +194,21 @@ public enum HeaderId { /// ContentDuration, + /// + /// The Content-Features header field. + /// + ContentFeatures, + /// /// The Content-Id header field. /// ContentId, + /// + /// The Content-Identifier header field. + /// + ContentIdentifier, + /// /// The Content-Language header field. /// @@ -131,11 +229,21 @@ public enum HeaderId { /// ContentMd5, + /// + /// The Content-Return header field. + /// + ContentReturn, + /// /// The Content-Transfer-Encoding header field. /// ContentTransferEncoding, + /// + /// The Content-Translation-Type header field. + /// + ContentTranslationType, + /// /// The Content-Type header field. /// @@ -146,16 +254,41 @@ public enum HeaderId { /// Control, + /// + /// The Conversion header field. + /// + Conversion, + + /// + /// The Conversion-With-Loss header field. + /// + ConversionWithLoss, + /// /// The Date header field. /// Date, + /// + /// The Date-Received header field. + /// + DateReceived, + /// /// The Deferred-Delivery header field. /// DeferredDelivery, + /// + /// The Delivery-Date header field. + /// + DeliveryDate, + + /// + /// The Disclose-Recipients header field. + /// + DiscloseRecipients, + /// /// The Disposition-Notification-Options header field. /// @@ -213,11 +346,26 @@ public enum HeaderId { /// From, + /// + /// The Generate-Delivery-Report header field. + /// + GenerateDeliveryReport, + /// /// The Importance header field. /// Importance, + /// + /// The Injection-Date header field. + /// + InjectionDate, + + /// + /// The Injection-Info header field. + /// + InjectionInfo, + /// /// The In-Reply-To header field. /// @@ -228,16 +376,46 @@ public enum HeaderId { /// Keywords, + /// + /// The Language header. + /// + Language, + + /// + /// The Latest-Delivery-Time header. + /// + LatestDeliveryTime, + /// /// The Lines header field. /// Lines, + /// + /// THe List-Archive header field. + /// + ListArchive, + /// /// The List-Help header field. /// ListHelp, + /// + /// The List-Id header field. + /// + ListId, + + /// + /// The List-Owner header field. + /// + ListOwner, + + /// + /// The List-Post header field. + /// + ListPost, + /// /// The List-Subscribe header field. /// @@ -248,6 +426,11 @@ public enum HeaderId { /// ListUnsubscribe, + /// + /// The List-Unsubscribe-Post header field. + /// + ListUnsubscribePost, + /// /// The Message-Id header field. /// @@ -274,11 +457,31 @@ public enum HeaderId { /// Organization, + /// + /// The Original-From header field. + /// + OriginalFrom, + + /// + /// The Original-Message-Id header field. + /// + OriginalMessageId, + /// /// The Original-Recipient header field. /// OriginalRecipient, + /// + /// The Original-Return-Address header field. + /// + OriginalReturnAddress, + + /// + /// The Original-Subject header field. + /// + OriginalSubject, + /// /// The Path header field. /// @@ -289,6 +492,12 @@ public enum HeaderId { /// Precedence, + /// + /// The Prevent-NonDelivery-Report header field. + /// + [HeaderName ("Prevent-NonDelivery-Report")] + PreventNonDeliveryReport, + /// /// The Priority header field. /// @@ -299,11 +508,22 @@ public enum HeaderId { /// Received, + /// + /// The Received-SPF header field. + /// + [HeaderName ("Received-SPF")] + ReceivedSPF, + /// /// The References header field. /// References, + /// + /// The Relay-Version header field. + /// + RelayVersion, + /// /// The Reply-By header field. /// @@ -314,6 +534,11 @@ public enum HeaderId { /// ReplyTo, + /// + /// The Require-Recipient-Valid-Since header field. + /// + RequireRecipientValidSince, + /// /// The Resent-Bcc header field. /// @@ -364,6 +589,11 @@ public enum HeaderId { /// ReturnReceiptTo, + /// + /// The See-Also header field. + /// + SeeAlso, + /// /// The Sender header field. /// @@ -374,6 +604,11 @@ public enum HeaderId { /// Sensitivity, + /// + /// The Solicitation header field. + /// + Solicitation, + /// /// The Status header field. /// @@ -394,6 +629,12 @@ public enum HeaderId { /// Supersedes, + /// + /// The TLS-Required header field. + /// + [HeaderName ("TLS-Required")] + TLSRequired, + /// /// The To header field. /// @@ -404,6 +645,54 @@ public enum HeaderId { /// UserAgent, + /// + /// The X400-Content-Identifier header field. + /// + [HeaderName ("X400-Content-Identifier")] + X400ContentIdentifier, + + /// + /// The X400-Content-Return header field. + /// + [HeaderName ("X400-Content-Return")] + X400ContentReturn, + + /// + /// The X400-Content-Type header field. + /// + [HeaderName ("X400-Content-Type")] + X400ContentType, + + /// + /// The X400-MTS-Identifier header field. + /// + [HeaderName ("X400-MTS-Identifier")] + X400MTSIdentifier, + + /// + /// The X400-Originator header field. + /// + [HeaderName ("X400-Originator")] + X400Originator, + + /// + /// The X400-Received header field. + /// + [HeaderName ("X400-Received")] + X400Received, + + /// + /// The X400-Recipients header field. + /// + [HeaderName ("X400-Recipients")] + X400Recipients, + + /// + /// The X400-Trace header field. + /// + [HeaderName ("X400-Trace")] + X400Trace, + /// /// The X-Mailer header field. /// @@ -475,7 +764,7 @@ public static string ToHeaderName (this HeaderId value) { var name = value.ToString (); -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 var field = typeof (HeaderId).GetTypeInfo ().GetDeclaredField (name); var attrs = field.GetCustomAttributes (typeof (HeaderNameAttribute), false).ToArray (); #else diff --git a/MimeKit/HeaderList.cs b/MimeKit/HeaderList.cs index d8f0a396a9..0317d412fa 100644 --- a/MimeKit/HeaderList.cs +++ b/MimeKit/HeaderList.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,16 +32,12 @@ using System.Threading.Tasks; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.IO; using MimeKit.Utils; namespace MimeKit { /// - /// A list of s. + /// A list of s. /// /// /// Represents a list of headers as found in a @@ -63,7 +59,7 @@ internal HeaderList (ParserOptions options) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new empty header list. @@ -73,7 +69,7 @@ public HeaderList () : this (ParserOptions.Default.Clone ()) } /// - /// Adds a header with the specified field and value. + /// Add a header with the specified field and value. /// /// /// Adds a new header for the specified field and value pair. @@ -92,7 +88,7 @@ public void Add (HeaderId id, string value) } /// - /// Adds a header with the specified field and value. + /// Add a header with the specified field and value. /// /// /// Adds a new header for the specified field and value pair. @@ -113,7 +109,7 @@ public void Add (string field, string value) } /// - /// Adds a header with the specified field and value. + /// Add a header with the specified field and value. /// /// /// Adds a new header for the specified field and value pair. @@ -135,7 +131,7 @@ public void Add (HeaderId id, Encoding encoding, string value) } /// - /// Adds a header with the specified field and value. + /// Add a header with the specified field and value. /// /// /// Adds a new header for the specified field and value pair. @@ -159,7 +155,7 @@ public void Add (string field, Encoding encoding, string value) } /// - /// Checks if the contains a header with the specified field name. + /// Check if the contains a header with the specified field name. /// /// /// Determines whether or not the header list contains the specified header. @@ -179,7 +175,7 @@ public bool Contains (HeaderId id) } /// - /// Checks if the contains a header with the specified field name. + /// Check if the contains a header with the specified field name. /// /// /// Determines whether or not the header list contains the specified header. @@ -199,7 +195,7 @@ public bool Contains (string field) } /// - /// Gets the index of the requested header, if it exists. + /// Get the index of the requested header, if it exists. /// /// /// Finds the first index of the specified header, if it exists. @@ -223,7 +219,7 @@ public int IndexOf (HeaderId id) } /// - /// Gets the index of the requested header, if it exists. + /// Get the index of the requested header, if it exists. /// /// /// Finds the first index of the specified header, if it exists. @@ -247,7 +243,7 @@ public int IndexOf (string field) } /// - /// Inserts a header with the specified field and value at the given index. + /// Insert a header with the specified field and value at the given index. /// /// /// Inserts the header at the specified index in the list. @@ -269,7 +265,7 @@ public void Insert (int index, HeaderId id, string value) } /// - /// Inserts a header with the specified field and value at the given index. + /// Insert a header with the specified field and value at the given index. /// /// /// Inserts the header at the specified index in the list. @@ -294,7 +290,7 @@ public void Insert (int index, string field, string value) } /// - /// Inserts a header with the specified field and value at the given index. + /// Insert a header with the specified field and value at the given index. /// /// /// Inserts the header at the specified index in the list. @@ -319,7 +315,7 @@ public void Insert (int index, HeaderId id, Encoding encoding, string value) } /// - /// Inserts a header with the specified field and value at the given index. + /// Insert a header with the specified field and value at the given index. /// /// /// Inserts the header at the specified index in the list. @@ -347,7 +343,7 @@ public void Insert (int index, string field, Encoding encoding, string value) } /// - /// Gets the last index of the requested header, if it exists. + /// Get the last index of the requested header, if it exists. /// /// /// Finds the last index of the specified header, if it exists. @@ -371,7 +367,7 @@ public int LastIndexOf (HeaderId id) } /// - /// Gets the last index of the requested header, if it exists. + /// Get the last index of the requested header, if it exists. /// /// /// Finds the last index of the specified header, if it exists. @@ -395,7 +391,7 @@ public int LastIndexOf (string field) } /// - /// Removes the first occurance of the specified header field. + /// Remove the first occurance of the specified header field. /// /// /// Removes the first occurance of the specified header field, if any exist. @@ -419,7 +415,7 @@ public bool Remove (HeaderId id) } /// - /// Removes the first occurance of the specified header field. + /// Remove the first occurance of the specified header field. /// /// /// Removes the first occurance of the specified header field, if any exist. @@ -443,7 +439,7 @@ public bool Remove (string field) } /// - /// Removes all of the headers matching the specified field name. + /// Remove all of the headers matching the specified field name. /// /// /// Removes all of the headers matching the specified field name. @@ -471,7 +467,7 @@ public void RemoveAll (HeaderId id) } /// - /// Removes all of the headers matching the specified field name. + /// Remove all of the headers matching the specified field name. /// /// /// Removes all of the headers matching the specified field name. @@ -499,7 +495,7 @@ public void RemoveAll (string field) } /// - /// Replaces all headers with identical field names with the single specified header. + /// Replace all headers with identical field names with the single specified header. /// /// /// Replaces all headers with identical field names with the single specified header. @@ -522,7 +518,7 @@ public void Replace (HeaderId id, Encoding encoding, string value) } /// - /// Replaces all headers with identical field names with the single specified header. + /// Replace all headers with identical field names with the single specified header. /// /// /// Replaces all headers with identical field names with the single specified header. @@ -542,7 +538,7 @@ public void Replace (HeaderId id, string value) } /// - /// Replaces all headers with identical field names with the single specified header. + /// Replace all headers with identical field names with the single specified header. /// /// /// Replaces all headers with identical field names with the single specified header. @@ -564,7 +560,7 @@ public void Replace (string field, Encoding encoding, string value) } /// - /// Replaces all headers with identical field names with the single specified header. + /// Replace all headers with identical field names with the single specified header. /// /// /// Replaces all headers with identical field names with the single specified header. @@ -586,7 +582,7 @@ public void Replace (string field, string value) } /// - /// Gets or sets the value of the first occurance of a header + /// Get or set the value of the first occurance of a header /// with the specified field name. /// /// @@ -626,7 +622,7 @@ public string this [HeaderId id] { } /// - /// Gets or sets the value of the first occurance of a header + /// Get or set the value of the first occurance of a header /// with the specified field name. /// /// @@ -668,7 +664,7 @@ public string this [string field] { } /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes all of the headers to the output stream. @@ -699,11 +695,14 @@ public string this [string field] { filtered.Add (options.CreateNewLineFilter ()); foreach (var header in headers) { - var rawValue = header.GetRawValue (options); - filtered.Write (header.RawField, 0, header.RawField.Length, cancellationToken); - filtered.Write (Header.Colon, 0, Header.Colon.Length, cancellationToken); - filtered.Write (rawValue, 0, rawValue.Length, cancellationToken); + + if (!header.IsInvalid) { + var rawValue = header.GetRawValue (options); + + filtered.Write (Header.Colon, 0, Header.Colon.Length, cancellationToken); + filtered.Write (rawValue, 0, rawValue.Length, cancellationToken); + } } filtered.Flush (cancellationToken); @@ -720,7 +719,7 @@ public string this [string field] { } /// - /// Asynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// /// Writes all of the headers to the output stream. @@ -752,11 +751,14 @@ public string this [string field] { filtered.Add (options.CreateNewLineFilter ()); foreach (var header in headers) { - var rawValue = header.GetRawValue (options); - await filtered.WriteAsync (header.RawField, 0, header.RawField.Length, cancellationToken).ConfigureAwait (false); - await filtered.WriteAsync (Header.Colon, 0, Header.Colon.Length, cancellationToken).ConfigureAwait (false); - await filtered.WriteAsync (rawValue, 0, rawValue.Length, cancellationToken).ConfigureAwait (false); + + if (!header.IsInvalid) { + var rawValue = header.GetRawValue (options); + + await filtered.WriteAsync (Header.Colon, 0, Header.Colon.Length, cancellationToken).ConfigureAwait (false); + await filtered.WriteAsync (rawValue, 0, rawValue.Length, cancellationToken).ConfigureAwait (false); + } } await filtered.FlushAsync (cancellationToken).ConfigureAwait (false); @@ -766,7 +768,7 @@ public string this [string field] { } /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes all of the headers to the output stream. @@ -788,7 +790,7 @@ public string this [string field] { } /// - /// Asynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// /// Writes all of the headers to the output stream. @@ -813,7 +815,7 @@ public string this [string field] { #region ICollection implementation /// - /// Gets the number of headers in the list. + /// Get the number of headers in the list. /// /// /// Gets the number of headers in the list. @@ -824,7 +826,7 @@ public int Count { } /// - /// Gets whether or not the header list is read only. + /// Get whether or not the header list is read only. /// /// /// A is never read-only. @@ -835,7 +837,7 @@ public bool IsReadOnly { } /// - /// Adds the specified header. + /// Add the specified header. /// /// /// Adds the specified header to the end of the header list. @@ -859,7 +861,7 @@ public void Add (Header header) } /// - /// Clears the header list. + /// Clear the header list. /// /// /// Removes all of the headers from the list. @@ -876,7 +878,7 @@ public void Clear () } /// - /// Checks if the contains the specified header. + /// Check if the contains the specified header. /// /// /// Determines whether or not the header list contains the specified header. @@ -896,7 +898,7 @@ public bool Contains (Header header) } /// - /// Copies all of the headers in the to the specified array. + /// Copy all of the headers in the to the specified array. /// /// /// Copies all of the headers within the into the array, @@ -916,7 +918,7 @@ public void CopyTo (Header[] array, int arrayIndex) } /// - /// Removes the specified header. + /// Remove the specified header. /// /// /// Removes the specified header from the list if it exists. @@ -959,7 +961,7 @@ public bool Remove (Header header) } /// - /// Replaces all headers with identical field names with the single specified header. + /// Replace all headers with identical field names with the single specified header. /// /// /// Replaces all headers with identical field names with the single specified header. @@ -1008,7 +1010,7 @@ public void Replace (Header header) #region IList implementation /// - /// Gets the index of the requested header, if it exists. + /// Get the index of the requested header, if it exists. /// /// /// Finds the index of the specified header, if it exists. @@ -1027,7 +1029,7 @@ public int IndexOf (Header header) } /// - /// Inserts the specified header at the given index. + /// Insert the specified header at the given index. /// /// /// Inserts the header at the specified index in the list. @@ -1066,7 +1068,7 @@ public void Insert (int index, Header header) } /// - /// Removes the header at the specified index. + /// Remove the header at the specified index. /// /// /// Removes the header at the specified index. @@ -1077,7 +1079,7 @@ public void Insert (int index, Header header) /// public void RemoveAt (int index) { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); var header = headers[index]; @@ -1102,10 +1104,10 @@ public void RemoveAt (int index) } /// - /// Gets or sets the at the specified index. + /// Get or set the at the specified index. /// /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// The header at the specified index. /// The index. @@ -1117,13 +1119,13 @@ public void RemoveAt (int index) /// public Header this [int index] { get { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); return headers[index]; } set { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); if (value == null) @@ -1182,7 +1184,7 @@ public Header this [int index] { #region IEnumerable implementation /// - /// Gets an enumerator for the list of headers. + /// Get an enumerator for the list of headers. /// /// /// Gets an enumerator for the list of headers. @@ -1198,7 +1200,7 @@ public IEnumerator
GetEnumerator () #region IEnumerable implementation /// - /// Gets an enumerator for the list of headers. + /// Get an enumerator for the list of headers. /// /// /// Gets an enumerator for the list of headers. @@ -1362,7 +1364,6 @@ internal bool TryGetHeader (string field, out Header header) return LoadAsync (ParserOptions.Default, stream, cancellationToken); } -#if !PORTABLE /// /// Load a from the specified file. /// @@ -1381,8 +1382,7 @@ internal bool TryGetHeader (string field, out Header header) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1432,8 +1432,7 @@ internal bool TryGetHeader (string field, out Header header) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1480,8 +1479,7 @@ internal bool TryGetHeader (string field, out Header header) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1521,8 +1519,7 @@ internal bool TryGetHeader (string field, out Header header) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1546,6 +1543,5 @@ internal bool TryGetHeader (string field, out Header header) { return LoadAsync (ParserOptions.Default, fileName, cancellationToken); } -#endif // !PORTABLE } } diff --git a/MimeKit/HeaderListChangedEventArgs.cs b/MimeKit/HeaderListChangedEventArgs.cs index 8673b917c2..f0da1ea1f8 100644 --- a/MimeKit/HeaderListChangedEventArgs.cs +++ b/MimeKit/HeaderListChangedEventArgs.cs @@ -1,9 +1,9 @@ // -// HeaderChangedEventArgs.cs +// HeaderListChangedEventArgs.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/HeaderListCollection.cs b/MimeKit/HeaderListCollection.cs index 7e66aa7edb..211e113b6f 100644 --- a/MimeKit/HeaderListCollection.cs +++ b/MimeKit/HeaderListCollection.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,7 +42,7 @@ public class HeaderListCollection : ICollection readonly List groups; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -75,10 +75,10 @@ public bool IsReadOnly { } /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// The group of headers at the specified index. /// The index. @@ -90,13 +90,13 @@ public bool IsReadOnly { /// public HeaderList this [int index] { get { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); return groups[index]; } set { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); if (value == null) @@ -167,7 +167,7 @@ public bool Contains (HeaderList group) } /// - /// Copies all of the header groups in the to the specified array. + /// Copies all of the header groups in the to the specified array. /// /// /// Copies all of the header groups within the into the array, diff --git a/MimeKit/IMimeContent.cs b/MimeKit/IMimeContent.cs index 45cb3f22ff..d14331c8b0 100644 --- a/MimeKit/IMimeContent.cs +++ b/MimeKit/IMimeContent.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ namespace MimeKit { /// - /// An interface for content stream encapsulation as used by . + /// An interface for content stream encapsulation as used by . /// /// /// Implemented by . @@ -41,7 +41,7 @@ namespace MimeKit { public interface IMimeContent { /// - /// Gets the content encoding. + /// Get the content encoding. /// /// /// If the is not encoded, this value will be @@ -52,7 +52,18 @@ public interface IMimeContent ContentEncoding Encoding { get; } /// - /// Gets the content stream. + /// Get the new-line format, if known. + /// + /// + /// This property is typically only set by the as it parses + /// the content of a and is only used as a hint when verifying + /// digital signatures. + /// + /// The new-line format, if known. + NewLineFormat? NewLineFormat { get; } + + /// + /// Get the content stream. /// /// /// Gets the content stream. @@ -61,7 +72,7 @@ public interface IMimeContent Stream Stream { get; } /// - /// Opens the decoded content stream. + /// Open the decoded content stream. /// /// /// Provides a means of reading the decoded content without having to first write it to another @@ -71,13 +82,16 @@ public interface IMimeContent Stream Open (); /// - /// Decodes the content stream into another stream. + /// Decode the content stream into another stream. /// /// /// If the content stream is encoded, this method will decode it into the output stream /// using a suitable decoder based on the property, otherwise the /// stream will be copied into the output stream as-is. /// + /// + /// + /// /// The output stream. /// The cancellation token. /// @@ -89,19 +103,20 @@ public interface IMimeContent /// /// An I/O error occurred. /// - /// - /// - /// void DecodeTo (Stream stream, CancellationToken cancellationToken = default (CancellationToken)); /// - /// Asynchronously decodes the content stream into another stream. + /// Asynchronously decode the content stream into another stream. /// /// /// If the content stream is encoded, this method will decode it into the output stream /// using a suitable decoder based on the property, otherwise the /// stream will be copied into the output stream as-is. /// + /// + /// + /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// @@ -113,13 +128,10 @@ public interface IMimeContent /// /// An I/O error occurred. /// - /// - /// - /// Task DecodeToAsync (Stream stream, CancellationToken cancellationToken = default (CancellationToken)); /// - /// Copies the content stream to the specified output stream. + /// Copy the content stream to the specified output stream. /// /// /// This is equivalent to simply using @@ -141,7 +153,7 @@ public interface IMimeContent void WriteTo (Stream stream, CancellationToken cancellationToken = default (CancellationToken)); /// - /// Asynchronously copies the content stream to the specified output stream. + /// Asynchronously copy the content stream to the specified output stream. /// /// /// This is equivalent to simply using @@ -149,6 +161,7 @@ public interface IMimeContent /// If you want the decoded content, use /// instead. /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// diff --git a/MimeKit/IO/BoundStream.cs b/MimeKit/IO/BoundStream.cs index 2adcafbe4a..0bc2c79cd0 100644 --- a/MimeKit/IO/BoundStream.cs +++ b/MimeKit/IO/BoundStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ public class BoundStream : Stream bool eos; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// If the is less than 0, then the end of the stream @@ -123,11 +123,11 @@ public long EndBoundary { /// /// Checks whether or not the underlying stream will remain open after - /// the is disposed. + /// the is disposed. /// /// /// Checks whether or not the underlying stream will remain open after - /// the is disposed. + /// the is disposed. /// /// true if the underlying stream should remain open after the /// is disposed; otherwise, false. diff --git a/MimeKit/IO/ChainedStream.cs b/MimeKit/IO/ChainedStream.cs index 164a25ef23..7561e4c981 100644 --- a/MimeKit/IO/ChainedStream.cs +++ b/MimeKit/IO/ChainedStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ public class ChainedStream : Stream bool eos; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/FilteredStream.cs b/MimeKit/IO/FilteredStream.cs index 9576532d61..604bc8fe44 100644 --- a/MimeKit/IO/FilteredStream.cs +++ b/MimeKit/IO/FilteredStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -58,7 +58,7 @@ enum IOOperation : byte { bool flushed; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a filtered stream using the specified source stream. @@ -522,6 +522,9 @@ public void Write (byte[] buffer, int offset, int count, CancellationToken cance foreach (var filter in filters) filtered = filter.Filter (filtered, filteredIndex, filteredLength, out filteredIndex, out filteredLength); + if (filteredLength == 0) + return; + var cancellable = Source as ICancellableStream; if (cancellable != null) { @@ -690,12 +693,6 @@ public void Flush (CancellationToken cancellationToken) filteredIndex = 0; filteredLength = 0; } - - if (cancellable != null) { - cancellable.Flush (cancellationToken); - } else { - Source.Flush (); - } } /// @@ -767,8 +764,6 @@ public override async Task FlushAsync (CancellationToken cancellationToken) filteredIndex = 0; filteredLength = 0; } - - await Source.FlushAsync (cancellationToken).ConfigureAwait (false); } /// diff --git a/MimeKit/IO/Filters/ArmoredFromFilter.cs b/MimeKit/IO/Filters/ArmoredFromFilter.cs index 86f5731ae0..48237a21d0 100644 --- a/MimeKit/IO/Filters/ArmoredFromFilter.cs +++ b/MimeKit/IO/Filters/ArmoredFromFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,7 +45,7 @@ public class ArmoredFromFilter : MimeFilterBase bool midline; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/Filters/BestEncodingFilter.cs b/MimeKit/IO/Filters/BestEncodingFilter.cs index 9e0e143510..557d851f43 100644 --- a/MimeKit/IO/Filters/BestEncodingFilter.cs +++ b/MimeKit/IO/Filters/BestEncodingFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,9 +42,10 @@ public class BestEncodingFilter : IMimeFilter int markerLength; bool hasMarker; int total; + byte pc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -153,9 +154,13 @@ unsafe void Scan (byte* inptr, byte* inend) marker[markerLength++] = c; linelen++; + pc = c; } if (c == (byte) '\n') { + if (pc == (byte) '\r') + linelen--; + maxline = Math.Max (maxline, linelen); linelen = 0; @@ -259,6 +264,7 @@ public void Reset () count0 = 0; count8 = 0; total = 0; + pc = 0; } #endregion diff --git a/MimeKit/IO/Filters/CharsetFilter.cs b/MimeKit/IO/Filters/CharsetFilter.cs index 8892fe0be4..d673fe366d 100644 --- a/MimeKit/IO/Filters/CharsetFilter.cs +++ b/MimeKit/IO/Filters/CharsetFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,12 +27,6 @@ using System; using System.Text; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - using MimeKit.Utils; namespace MimeKit.IO.Filters { @@ -58,7 +52,7 @@ static Encoding GetEncoding (string paramName, string encodingName) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new to convert text from the specified @@ -83,7 +77,7 @@ public CharsetFilter (string sourceEncodingName, string targetEncodingName) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new to convert text from the specified @@ -107,7 +101,7 @@ public CharsetFilter (int sourceCodePage, int targetCodePage) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new to convert text from the specified diff --git a/MimeKit/IO/Filters/DecoderFilter.cs b/MimeKit/IO/Filters/DecoderFilter.cs index 21821d356e..c85cc491ba 100644 --- a/MimeKit/IO/Filters/DecoderFilter.cs +++ b/MimeKit/IO/Filters/DecoderFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ public ContentEncoding Encoding { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new using the specified decoder. diff --git a/MimeKit/IO/Filters/Dos2UnixFilter.cs b/MimeKit/IO/Filters/Dos2UnixFilter.cs index 48cb550f5f..14978344f7 100644 --- a/MimeKit/IO/Filters/Dos2UnixFilter.cs +++ b/MimeKit/IO/Filters/Dos2UnixFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ public class Dos2UnixFilter : MimeFilterBase byte pc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/Filters/EncoderFilter.cs b/MimeKit/IO/Filters/EncoderFilter.cs index 8345ea6abc..8f261bc31a 100644 --- a/MimeKit/IO/Filters/EncoderFilter.cs +++ b/MimeKit/IO/Filters/EncoderFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -61,7 +61,7 @@ public ContentEncoding Encoding { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new using the specified encoder. diff --git a/MimeKit/IO/Filters/IMimeFilter.cs b/MimeKit/IO/Filters/IMimeFilter.cs index 113976a985..01547422a3 100644 --- a/MimeKit/IO/Filters/IMimeFilter.cs +++ b/MimeKit/IO/Filters/IMimeFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/IO/Filters/MimeFilterBase.cs b/MimeKit/IO/Filters/MimeFilterBase.cs index 887f9a6d85..4f229b92b0 100644 --- a/MimeKit/IO/Filters/MimeFilterBase.cs +++ b/MimeKit/IO/Filters/MimeFilterBase.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ public abstract class MimeFilterBase : IMimeFilter byte[] inbuf; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/Filters/PassThroughFilter.cs b/MimeKit/IO/Filters/PassThroughFilter.cs index 51474769b4..61bc497fe0 100644 --- a/MimeKit/IO/Filters/PassThroughFilter.cs +++ b/MimeKit/IO/Filters/PassThroughFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,7 @@ namespace MimeKit.IO.Filters { public class PassThroughFilter : IMimeFilter { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/Filters/TrailingWhitespaceFilter.cs b/MimeKit/IO/Filters/TrailingWhitespaceFilter.cs index f165651389..08916e5936 100644 --- a/MimeKit/IO/Filters/TrailingWhitespaceFilter.cs +++ b/MimeKit/IO/Filters/TrailingWhitespaceFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ public class TrailingWhitespaceFilter : MimeFilterBase readonly PackedByteArray lwsp = new PackedByteArray (); /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/Filters/Unix2DosFilter.cs b/MimeKit/IO/Filters/Unix2DosFilter.cs index 921bc661ca..d70f31e315 100644 --- a/MimeKit/IO/Filters/Unix2DosFilter.cs +++ b/MimeKit/IO/Filters/Unix2DosFilter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ public class Unix2DosFilter : MimeFilterBase byte pc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/ICancellableStream.cs b/MimeKit/IO/ICancellableStream.cs index 323c6b7112..2fa2c6dd52 100644 --- a/MimeKit/IO/ICancellableStream.cs +++ b/MimeKit/IO/ICancellableStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,9 +32,9 @@ namespace MimeKit.IO { /// /// /// This interface is meant to extend the functionality of a , - /// allowing the to have much finer-grained canellability. + /// allowing the to have much finer-grained canellability. /// When a custom stream implementation also implements this interface, - /// the will opt to use this interface + /// the will opt to use this interface /// instead of the normal /// API to read data from the stream. /// This is really useful when parsing a message or other MIME entity @@ -48,7 +48,7 @@ public interface ICancellableStream /// /// /// When a custom stream implementation also implements this interface, - /// the will opt to use this interface + /// the will opt to use this interface /// instead of the normal /// API to read data from the stream. /// This is really useful when parsing a message or other MIME entity @@ -68,7 +68,7 @@ public interface ICancellableStream ///
/// /// When a custom stream implementation also implements this interface, - /// writing a or + /// writing a or /// to the custom stream will opt to use this interface /// instead of the normal /// API to write data to the stream. diff --git a/MimeKit/IO/MeasuringStream.cs b/MimeKit/IO/MeasuringStream.cs index c6ad01a852..6ce1c70911 100644 --- a/MimeKit/IO/MeasuringStream.cs +++ b/MimeKit/IO/MeasuringStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ public class MeasuringStream : Stream long length; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/IO/MemoryBlockStream.cs b/MimeKit/IO/MemoryBlockStream.cs index f0d81e398e..441f5123b8 100644 --- a/MimeKit/IO/MemoryBlockStream.cs +++ b/MimeKit/IO/MemoryBlockStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,9 +27,13 @@ using System; using System.IO; using System.Threading; +using System.Diagnostics; +using System.Globalization; using System.Threading.Tasks; using System.Collections.Generic; +using MimeKit.Utils; + namespace MimeKit.IO { /// /// An efficient memory stream implementation that sacrifices the ability to @@ -47,12 +51,15 @@ public class MemoryBlockStream : Stream const long MaxCapacity = int.MaxValue * BlockSize; const long BlockSize = 2048; + static readonly BufferPool DefaultPool = new BufferPool ((int) BlockSize, 200); + readonly List blocks = new List (); + readonly BufferPool pool; long position, length; bool disposed; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with an initial memory block @@ -60,7 +67,8 @@ public class MemoryBlockStream : Stream /// public MemoryBlockStream () { - blocks.Add (new byte[BlockSize]); + pool = DefaultPool; + blocks.Add (pool.Rent (Debugger.IsAttached)); } /// @@ -319,7 +327,7 @@ public override void Write (byte[] buffer, int offset, int count) ValidateArguments (buffer, offset, count); if (position + count >= MaxCapacity) - throw new IOException (string.Format ("Cannot exceed {0} bytes", MaxCapacity)); + throw new IOException (string.Format (CultureInfo.InvariantCulture, "Cannot exceed {0} bytes", MaxCapacity)); int startIndex = (int) (position % BlockSize); long capacity = blocks.Count * BlockSize; @@ -327,7 +335,7 @@ public override void Write (byte[] buffer, int offset, int count) int nwritten = 0; while (capacity < position + count) { - blocks.Add (new byte[BlockSize]); + blocks.Add (pool.Rent (Debugger.IsAttached)); capacity += BlockSize; } @@ -426,7 +434,7 @@ public override long Seek (long offset, SeekOrigin origin) throw new IOException ("Cannot seek to a position before the beginning of the stream"); if (real > MaxCapacity) - throw new IOException (string.Format ("Cannot exceed {0} bytes", MaxCapacity)); + throw new IOException (string.Format (CultureInfo.InvariantCulture, "Cannot exceed {0} bytes", MaxCapacity)); // short-cut if we are seeking to our current position if (real == position) @@ -501,12 +509,13 @@ public override void SetLength (long value) if (value > capacity) { do { - blocks.Add (new byte[BlockSize]); + blocks.Add (pool.Rent (Debugger.IsAttached)); capacity += BlockSize; } while (capacity < value); } else if (value < length) { // shed any blocks that are no longer needed while (capacity - value > BlockSize) { + pool.Return (blocks[blocks.Count - 1]); blocks.RemoveAt (blocks.Count - 1); capacity -= BlockSize; } @@ -533,8 +542,17 @@ public override void SetLength (long value) /// false to release only the unmanaged resources. protected override void Dispose (bool disposing) { + if (disposing && !disposed) { + for (int i = 0; i < blocks.Count; i++) { + pool.Return (blocks[i]); + blocks[i] = null; + } + + blocks.Clear (); + disposed = true; + } + base.Dispose (disposing); - disposed = true; } } } diff --git a/MimeKit/InternetAddress.cs b/MimeKit/InternetAddress.cs index b239eb5b22..4836013f26 100644 --- a/MimeKit/InternetAddress.cs +++ b/MimeKit/InternetAddress.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,27 +26,14 @@ using System; using System.Text; +using System.Globalization; using System.Collections.Generic; -#if PORTABLE -using EncoderReplacementFallback = Portable.Text.EncoderReplacementFallback; -using DecoderReplacementFallback = Portable.Text.DecoderReplacementFallback; -using EncoderExceptionFallback = Portable.Text.EncoderExceptionFallback; -using DecoderExceptionFallback = Portable.Text.DecoderExceptionFallback; -using EncoderFallbackException = Portable.Text.EncoderFallbackException; -using DecoderFallbackException = Portable.Text.DecoderFallbackException; -using DecoderFallbackBuffer = Portable.Text.DecoderFallbackBuffer; -using DecoderFallback = Portable.Text.DecoderFallback; -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - using MimeKit.Utils; namespace MimeKit { /// - /// An internet address, as specified by rfc0822. + /// An abstract internet address, as specified by rfc0822. /// /// /// A can be any type of address defined by the @@ -66,7 +53,7 @@ public abstract class InternetAddress : IComparable, IEquatable string name; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Initializes the and properties of the internet address. @@ -86,7 +73,7 @@ protected InternetAddress (Encoding encoding, string name) } /// - /// Gets or sets the character encoding to use when encoding the name of the address. + /// Get or set the character encoding to use when encoding the name of the address. /// /// /// The character encoding is used to convert the property, if it is set, @@ -111,7 +98,7 @@ public Encoding Encoding { } /// - /// Gets or sets the display name of the address. + /// Get or set the display name of the address. /// /// /// A name is optional and is typically set to the name of the person @@ -201,33 +188,58 @@ public int CompareTo (InternetAddress other) #region IEquatable implementation /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// /// Compares two internet addresses to determine if they are identical or not. /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public abstract bool Equals (InternetAddress other); #endregion + /// + /// Determine whether the specified object is equal to the current object. + /// + /// + /// The type of comparison between the current instance and the parameter depends on whether + /// the current instance is a reference type or a value type. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals (object obj) + { + return Equals (obj as InternetAddress); + } + + /// + /// Return the hash code for this instance. + /// + /// + /// Returns the hash code for this instance. + /// + /// A hash code for the current object. + public override int GetHashCode () + { + return ToString ().GetHashCode (); + } + internal static string EncodeInternationalizedPhrase (string phrase) { for (int i = 0; i < phrase.Length; i++) { - if (char.IsControl (phrase[i]) || AtomSpecials.IndexOf (phrase[i]) != -1) + if (AtomSpecials.IndexOf (phrase[i]) != -1) return MimeUtils.Quote (phrase); } return phrase; } - internal abstract void Encode (FormatOptions options, StringBuilder builder, ref int lineLength); + internal abstract void Encode (FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength); /// - /// Returns a string representation of the , - /// optionally encoding it for transport. + /// Serialize an to a string, optionally encoding it for transport. /// /// /// If the parameter is true, then this method will return @@ -244,8 +256,7 @@ internal static string EncodeInternationalizedPhrase (string phrase) public abstract string ToString (FormatOptions options, bool encode); /// - /// Returns a string representation of the , - /// optionally encoding it for transport. + /// Serialize an to a string, optionally encoding it for transport. /// /// /// If the parameter is true, then this method will return @@ -261,7 +272,7 @@ public string ToString (bool encode) } /// - /// Returns a string representation of a suitable for display. + /// Serialize an to a string suitable for display. /// /// /// The string returned by this method is suitable only for display purposes. @@ -275,7 +286,7 @@ public override string ToString () internal event EventHandler Changed; /// - /// Raises the internal changed event used by to keep headers in sync. + /// Raise the internal changed event used by to keep headers in sync. /// /// /// This method is called whenever a property of the internet address is changed. @@ -286,7 +297,7 @@ protected virtual void OnChanged () Changed (this, EventArgs.Empty); } - internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex, bool throwOnError, out string localpart) + internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex, bool skipTrailingCfws, bool throwOnError, out string localpart) { var token = new StringBuilder (); int startIndex = index; @@ -296,7 +307,7 @@ internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex do { if (!text[index].IsAtom () && text[index] != '"' && text[index] != '.') { if (throwOnError) - throw new ParseException (string.Format ("Invalid local-part at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid local-part at offset {0}", startIndex), startIndex, index); return false; } @@ -307,18 +318,26 @@ internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex try { token.Append (CharsetUtils.UTF8.GetString (text, start, index - start)); - } catch (DecoderFallbackException ex) { - if (throwOnError) - throw new ParseException ("Internationalized local-part tokens may only contain UTF-8 characters.", start, start, ex); + } catch (DecoderFallbackException) { + try { + token.Append (CharsetUtils.Latin1.GetString (text, start, index - start)); + } catch (DecoderFallbackException ex) { + if (throwOnError) + throw new ParseException ("Internationalized local-part tokens may only contain UTF-8 characters.", start, start, ex); - return false; + return false; + } } + int cfws = index; if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) return false; - if (index >= endIndex || text[index] != (byte) '.') + if (index >= endIndex || text[index] != (byte) '.') { + if (!skipTrailingCfws) + index = cfws; break; + } token.Append ('.'); index++; @@ -328,7 +347,7 @@ internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete local-part at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete local-part at offset {0}", startIndex), startIndex, index); return false; } @@ -340,6 +359,9 @@ internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex localpart = token.ToString (); + if (ParseUtils.IsIdnEncoded (localpart)) + localpart = ParseUtils.IdnDecode (localpart); + return true; } @@ -348,12 +370,12 @@ internal static bool TryParseLocalPart (byte[] text, ref int index, int endIndex internal static bool TryParseAddrspec (byte[] text, ref int index, int endIndex, byte[] sentinels, bool throwOnError, out string addrspec, out int at) { int startIndex = index; + string localpart; addrspec = null; at = -1; - string localpart; - if (!TryParseLocalPart (text, ref index, endIndex, throwOnError, out localpart)) + if (!TryParseLocalPart (text, ref index, endIndex, true, throwOnError, out localpart)) return false; if (index >= endIndex || ParseUtils.IsSentinel (text[index], sentinels)) { @@ -363,7 +385,7 @@ internal static bool TryParseAddrspec (byte[] text, ref int index, int endIndex, if (text[index] != (byte) '@') { if (throwOnError) - throw new ParseException (string.Format ("Invalid addr-spec token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid addr-spec token at offset {0}", startIndex), startIndex, index); return false; } @@ -371,7 +393,7 @@ internal static bool TryParseAddrspec (byte[] text, ref int index, int endIndex, index++; if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete addr-spec token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete addr-spec token at offset {0}", startIndex), startIndex, index); return false; } @@ -381,7 +403,7 @@ internal static bool TryParseAddrspec (byte[] text, ref int index, int endIndex, if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete addr-spec token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete addr-spec token at offset {0}", startIndex), startIndex, index); return false; } @@ -419,7 +441,7 @@ internal static bool TryParseMailbox (ParserOptions options, byte[] text, int st if (index < endIndex && text[index] == (byte) '<') { if (options.AddressParserComplianceMode == RfcComplianceMode.Strict) { if (throwOnError) - throw new ParseException (string.Format ("Excessive angle brackets at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Excessive angle brackets at offset {0}", index), startIndex, index); return false; } @@ -429,36 +451,44 @@ internal static bool TryParseMailbox (ParserOptions options, byte[] text, int st } while (index < endIndex && text[index] == '<'); } + if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete mailbox at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete mailbox at offset {0}", startIndex), startIndex, index); return false; } - if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) - return false; - if (text[index] == (byte) '@') { // Note: we always pass 'false' as the throwOnError argument here so that we can throw a more informative exception on error if (!DomainList.TryParse (text, ref index, endIndex, false, out route)) { if (throwOnError) - throw new ParseException (string.Format ("Invalid route in mailbox at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid route in mailbox at offset {0}", startIndex), startIndex, index); return false; } - if (index + 1 >= endIndex || text[index] != (byte) ':') { + if (index >= endIndex || text[index] != (byte) ':') { if (throwOnError) - throw new ParseException (string.Format ("Incomplete route in mailbox at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete route in mailbox at offset {0}", startIndex), startIndex, index); return false; } + // skip over ':' index++; if (!ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete mailbox at offset {0}", startIndex), startIndex, index); + + return false; + } } // Note: The only syntactically correct sentinel token here is the '>', but alas... to deal with the first example @@ -478,7 +508,7 @@ internal static bool TryParseMailbox (ParserOptions options, byte[] text, int st if (index >= endIndex || text[index] != (byte) '>') { if (options.AddressParserComplianceMode == RfcComplianceMode.Strict) { if (throwOnError) - throw new ParseException (string.Format ("Unexpected end of mailbox at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected end of mailbox at offset {0}", startIndex), startIndex, index); return false; } @@ -490,7 +520,7 @@ internal static bool TryParseMailbox (ParserOptions options, byte[] text, int st if (index < endIndex && text[index] == (byte) '>') { if (options.AddressParserComplianceMode == RfcComplianceMode.Strict) { if (throwOnError) - throw new ParseException (string.Format ("Excessive angle brackets at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Excessive angle brackets at offset {0}", index), startIndex, index); return false; } @@ -535,7 +565,7 @@ static bool TryParseGroup (ParserOptions options, byte[] text, int startIndex, r if (index >= endIndex || text[index] != (byte) ';') { if (throwOnError && options.AddressParserComplianceMode == RfcComplianceMode.Strict) - throw new ParseException (string.Format ("Expected to find ';' at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Expected to find ';' at offset {0}", index), startIndex, index); while (index < endIndex && text[index] != (byte) ';') index++; @@ -560,7 +590,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index { bool strict = options.AddressParserComplianceMode == RfcComplianceMode.Strict; bool throwOnError = (flags & AddressParserFlags.ThrowOnError) != 0; - int minWordCount = options.AllowAddressesWithoutDomain ? 1 : 0; + int minWordCount = options.AllowUnquotedCommasInAddresses ? 0 : 1; address = null; @@ -592,9 +622,9 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index ParseUtils.SkipWhiteSpace (text, ref index, endIndex); - if (!ParseUtils.SkipAtom (text, ref index, endIndex)) { + if (!ParseUtils.SkipPhraseAtom (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete quoted-string token at offset {0}", qstringIndex), qstringIndex, endIndex); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete quoted-string token at offset {0}", qstringIndex), qstringIndex, endIndex); break; } @@ -603,7 +633,6 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index trimLeadingQuote = true; } } else { - if (!ParseUtils.SkipWordAndPeriod (text, ref index, endIndex, throwOnError)) break; } @@ -646,13 +675,18 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (index >= endIndex || text[index] == (byte) ',' || text[index] == (byte) '>' || text[index] == ';') { // we've completely gobbled up an addr-spec w/o a domain byte sentinel = index < endIndex ? text[index] : (byte) ','; - var sentinels = new byte [] { sentinel }; string name, addrspec; - int at; if ((flags & AddressParserFlags.AllowMailboxAddress) == 0) { if (throwOnError) - throw new ParseException (string.Format ("Addr-spec token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Addr-spec token at offset {0}", startIndex), startIndex, index); + + return false; + } + + if (!options.AllowAddressesWithoutDomain) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete addr-spec token at offset {0}", startIndex), startIndex, index); return false; } @@ -660,24 +694,20 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index // rewind back to the beginning of the local-part index = startIndex; - if (!TryParseAddrspec (text, ref index, endIndex, sentinels, throwOnError, out addrspec, out at)) + if (!TryParseLocalPart (text, ref index, endIndex, false, throwOnError, out addrspec)) return false; ParseUtils.SkipWhiteSpace (text, ref index, endIndex); if (index < endIndex && text[index] == '(') { - int comment = index; - - if (!ParseUtils.SkipComment (text, ref index, endIndex)) { - if (throwOnError) - throw new ParseException (string.Format ("Incomplete comment token at offset {0}", comment), comment, index); - - return false; - } + int comment = index + 1; - comment++; + // Note: this can't fail because it has already been skipped in TryParseLocalPart() above. + ParseUtils.SkipComment (text, ref index, endIndex); name = Rfc2047.DecodePhrase (options, text, comment, (index - 1) - comment).Trim (); + + ParseUtils.SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError); } else { name = string.Empty; } @@ -685,7 +715,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (index < endIndex && text[index] == (byte) '>') { if (strict) { if (throwOnError) - throw new ParseException (string.Format ("Unexpected '>' token at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected '>' token at offset {0}", index), startIndex, index); return false; } @@ -693,7 +723,14 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index index++; } - address = new MailboxAddress (Encoding.UTF8, name, addrspec, at); + if (index < endIndex && text[index] != sentinel) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), startIndex, index); + + return false; + } + + address = new MailboxAddress (Encoding.UTF8, name, addrspec, -1); return true; } @@ -706,14 +743,14 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if ((flags & AddressParserFlags.AllowGroupAddress) == 0) { if (throwOnError) - throw new ParseException (string.Format ("Group address token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Group address token at offset {0}", startIndex), startIndex, index); return false; } if (groupDepth >= options.MaxAddressGroupDepth) { if (throwOnError) - throw new ParseException (string.Format ("Exceeded maximum rfc822 group depth at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Exceeded maximum rfc822 group depth at offset {0}", startIndex), startIndex, index); return false; } @@ -737,7 +774,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if ((flags & AddressParserFlags.AllowMailboxAddress) == 0) { if (throwOnError) - throw new ParseException (string.Format ("Mailbox address token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Mailbox address token at offset {0}", startIndex), startIndex, index); return false; } @@ -760,7 +797,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (!ParseUtils.SkipComment (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete comment token at offset {0}", comment), comment, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete comment token at offset {0}", comment), comment, index); return false; } @@ -784,7 +821,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index // We have an address like "user@example.com "; i.e. the name is an unquoted string with an '@'. if (strict) { if (throwOnError) - throw new ParseException (string.Format ("Unexpected '<' token at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected '<' token at offset {0}", index), startIndex, index); return false; } @@ -802,7 +839,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (text[index] == (byte) '>') { if (strict) { if (throwOnError) - throw new ParseException (string.Format ("Unexpected '>' token at offset {0}", index), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected '>' token at offset {0}", index), startIndex, index); return false; } @@ -840,13 +877,13 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } if (throwOnError) - throw new ParseException (string.Format ("Invalid address token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid address token at offset {0}", startIndex), startIndex, index); return false; } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -891,7 +928,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -915,7 +952,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Inte } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -953,7 +990,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -975,7 +1012,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out InternetAddress } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -1009,7 +1046,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out InternetA } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains @@ -1027,7 +1064,7 @@ public static bool TryParse (byte[] buffer, out InternetAddress address) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single or . If the text contains @@ -1060,7 +1097,7 @@ public static bool TryParse (ParserOptions options, string text, out InternetAdd } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single or . If the text contains @@ -1078,13 +1115,13 @@ public static bool TryParse (string text, out InternetAddress address) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -1115,19 +1152,19 @@ public static InternetAddress Parse (ParserOptions options, byte[] buffer, int s ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return address; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -1147,13 +1184,13 @@ public static InternetAddress Parse (byte[] buffer, int startIndex, int length) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -1182,19 +1219,19 @@ public static InternetAddress Parse (ParserOptions options, byte[] buffer, int s ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return address; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// @@ -1212,13 +1249,13 @@ public static InternetAddress Parse (byte[] buffer, int startIndex) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// @@ -1243,19 +1280,19 @@ public static InternetAddress Parse (ParserOptions options, byte[] buffer) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return address; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single or . If the buffer contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -1269,13 +1306,13 @@ public static InternetAddress Parse (byte[] buffer) } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single or . If the text contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The text. /// @@ -1301,19 +1338,19 @@ public static InternetAddress Parse (ParserOptions options, string text) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return address; } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single or . If the text contains /// more data, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The text. /// /// is null. diff --git a/MimeKit/InternetAddressList.cs b/MimeKit/InternetAddressList.cs index 1c128ab1af..e989bfc786 100644 --- a/MimeKit/InternetAddressList.cs +++ b/MimeKit/InternetAddressList.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -55,7 +55,7 @@ public class InternetAddressList : IList, IEquatable list = new List (); /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new containing the supplied addresses. @@ -76,7 +76,7 @@ public InternetAddressList (IEnumerable addresses) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new, empty, . @@ -86,10 +86,10 @@ public InternetAddressList () } /// - /// Recursively gets all of the mailboxes contained within the . + /// Recursively get all of the mailboxes contained within the . /// /// - /// This API is useful for collecting a flattened list of + /// This API is useful for collecting a flattened list of /// recipients for use with sending via SMTP or for encrypting via S/MIME or PGP/MIME. /// /// The mailboxes. @@ -113,7 +113,7 @@ public IEnumerable Mailboxes { #region IList implementation /// - /// Gets the index of the specified address. + /// Get the index of the specified address. /// /// /// Finds the index of the specified address, if it exists. @@ -132,7 +132,7 @@ public int IndexOf (InternetAddress address) } /// - /// Inserts the address at the specified index. + /// Insert an address at the specified index. /// /// /// Inserts the address at the specified index in the list. @@ -147,6 +147,9 @@ public int IndexOf (InternetAddress address) /// public void Insert (int index, InternetAddress address) { + if (index < 0 || index > list.Count) + throw new ArgumentOutOfRangeException (nameof (index)); + if (address == null) throw new ArgumentNullException (nameof (address)); @@ -156,7 +159,7 @@ public void Insert (int index, InternetAddress address) } /// - /// Removes the address at the specified index. + /// Remove the address at the specified index. /// /// /// Removes the address at the specified index. @@ -176,10 +179,10 @@ public void RemoveAt (int index) } /// - /// Gets or sets the at the specified index. + /// Get or set the at the specified index. /// /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// The internet address at the specified index. /// The index of the address to get or set. @@ -192,12 +195,17 @@ public void RemoveAt (int index) public InternetAddress this [int index] { get { return list[index]; } set { + if (index < 0 || index >= list.Count) + throw new ArgumentOutOfRangeException (nameof (index)); + if (value == null) throw new ArgumentNullException (nameof (value)); if (list[index] == value) return; + list[index].Changed -= AddressChanged; + value.Changed += AddressChanged; list[index] = value; OnChanged (); } @@ -208,7 +216,7 @@ public InternetAddress this [int index] { #region ICollection implementation /// - /// Gets the number of addresses in the . + /// Get the number of addresses in the . /// /// /// Indicates the number of addresses in the list. @@ -219,7 +227,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether the is read only. /// /// /// A is never read-only. @@ -230,7 +238,7 @@ public bool IsReadOnly { } /// - /// Adds the specified address. + /// Add an address to the . /// /// /// Adds the specified address to the end of the address list. @@ -250,7 +258,7 @@ public void Add (InternetAddress address) } /// - /// Adds a collection of addresses. + /// Add a collection of addresses to the . /// /// /// Adds a range of addresses to the end of the address list. @@ -277,7 +285,7 @@ public void AddRange (IEnumerable addresses) } /// - /// Clears the address list. + /// Clear the address list. /// /// /// Removes all of the addresses from the list. @@ -295,7 +303,7 @@ public void Clear () } /// - /// Checks if the contains the specified address. + /// Check if the contains the specified address. /// /// /// Determines whether or not the address list contains the specified address. @@ -315,7 +323,7 @@ public bool Contains (InternetAddress address) } /// - /// Copies all of the addresses in the to the specified array. + /// Copy all of the addresses in the to the specified array. /// /// /// Copies all of the addresses within the into the array, @@ -335,7 +343,7 @@ public void CopyTo (InternetAddress[] array, int arrayIndex) } /// - /// Removes the specified address. + /// Remove the specified address from the . /// /// /// Removes the specified address. @@ -364,7 +372,7 @@ public bool Remove (InternetAddress address) #region IEnumerable implementation /// - /// Gets an enumerator for the list of addresses. + /// Get an enumerator for the list of addresses. /// /// /// Gets an enumerator for the list of addresses. @@ -380,7 +388,7 @@ public IEnumerator GetEnumerator () #region IEnumerable implementation /// - /// Gets an enumerator for the list of addresses. + /// Get an enumerator for the list of addresses. /// /// /// Gets an enumerator for the list of addresses. @@ -396,14 +404,14 @@ IEnumerator IEnumerable.GetEnumerator () #region IEquatable implementation /// - /// Determines whether the specified is equal to the current . + /// Determine whether the specified is equal to the current . /// /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals (InternetAddressList other) { if (other == null) @@ -412,14 +420,8 @@ public bool Equals (InternetAddressList other) if (other.Count != Count) return false; - var otherSorted = new List (other); - otherSorted.Sort (); - - var sorted = new List (this); - sorted.Sort (); - - for (int i = 0; i < sorted.Count; i++) { - if (!sorted[i].Equals (otherSorted[i])) + for (int i = 0; i < Count; i++) { + if (!this[i].Equals (other[i])) return false; } @@ -431,7 +433,7 @@ public bool Equals (InternetAddressList other) #region IComparable implementation /// - /// Compares two internet address lists. + /// Compare two internet address lists. /// /// /// Compares two internet address lists for the purpose of sorting. @@ -458,19 +460,46 @@ public int CompareTo (InternetAddressList other) #endregion - internal void Encode (FormatOptions options, StringBuilder builder, ref int lineLength) + /// + /// Determine whether the specified object is equal to the current object. + /// + /// + /// The type of comparison between the current instance and the parameter depends on whether + /// the current instance is a reference type or a value type. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals (object obj) + { + return Equals (obj as InternetAddressList); + } + + /// + /// Return the hash code for this instance. + /// + /// + /// Returns the hash code for this instance. + /// + /// A hash code for the current object. + public override int GetHashCode () + { + return ToString ().GetHashCode (); + } + + internal void Encode (FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength) { for (int i = 0; i < list.Count; i++) { - if (i > 0) + if (i > 0) { builder.Append (", "); + lineLength += 2; + } - list[i].Encode (options, builder, ref lineLength); + list[i].Encode (options, builder, firstToken && i == 0, ref lineLength); } } /// - /// Returns a string representation of the email addresses in the , - /// optionally encoding them for transport. + /// Serialize an to a string, optionally encoding the list of addresses for transport. /// /// /// If is true, each address in the list will be encoded @@ -487,7 +516,7 @@ public string ToString (FormatOptions options, bool encode) if (encode) { int lineLength = 0; - Encode (options, builder, ref lineLength); + Encode (options, builder, true, ref lineLength); return builder.ToString (); } @@ -503,8 +532,7 @@ public string ToString (FormatOptions options, bool encode) } /// - /// Returns a string representation of the email addresses in the , - /// optionally encoding them for transport. + /// Serialize an to a string, optionally encoding the list of addresses for transport. /// /// /// If is true, each address in the list will be encoded @@ -519,7 +547,7 @@ public string ToString (bool encode) } /// - /// Returns a string representation of the email addresses in the . + /// Serialize an to a string suitable for display. /// /// /// If there are multiple addresses in the list, they will be separated by a comma. @@ -591,7 +619,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the given index @@ -630,7 +658,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the given index @@ -654,7 +682,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Inte } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the specified index. @@ -690,7 +718,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the specified index. @@ -711,7 +739,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out InternetAddressL } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the specified buffer. @@ -743,7 +771,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out InternetA } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the specified buffer. @@ -760,7 +788,7 @@ public static bool TryParse (byte[] buffer, out InternetAddressList addresses) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a list of addresses from the specified text. @@ -793,7 +821,7 @@ public static bool TryParse (ParserOptions options, string text, out InternetAdd } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a list of addresses from the specified text. @@ -810,13 +838,13 @@ public static bool TryParse (string text, out InternetAddressList addresses) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -846,13 +874,13 @@ public static InternetAddressList Parse (ParserOptions options, byte[] buffer, i } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the given index /// and spanning across the specified number of bytes. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -872,12 +900,12 @@ public static InternetAddressList Parse (byte[] buffer, int startIndex, int leng } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -905,12 +933,12 @@ public static InternetAddressList Parse (ParserOptions options, byte[] buffer, i } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the supplied buffer starting at the specified index. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// @@ -928,12 +956,12 @@ public static InternetAddressList Parse (byte[] buffer, int startIndex) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the specified buffer. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// @@ -957,12 +985,12 @@ public static InternetAddressList Parse (ParserOptions options, byte[] buffer) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a list of addresses from the specified buffer. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -976,12 +1004,12 @@ public static InternetAddressList Parse (byte[] buffer) } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a list of addresses from the specified text. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The text. /// @@ -1006,12 +1034,12 @@ public static InternetAddressList Parse (ParserOptions options, string text) } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a list of addresses from the specified text. /// - /// The parsed . + /// The parsed . /// The text. /// /// is null. diff --git a/MimeKit/MailboxAddress.cs b/MimeKit/MailboxAddress.cs index b75a42ece1..652f0acdda 100644 --- a/MimeKit/MailboxAddress.cs +++ b/MimeKit/MailboxAddress.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,12 +26,9 @@ using System; using System.Text; +using System.Globalization; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - #if ENABLE_SNM using System.Net.Mail; #endif @@ -70,7 +67,7 @@ internal MailboxAddress (Encoding encoding, string name, string address, int at) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name, address and route. The @@ -101,7 +98,7 @@ public MailboxAddress (Encoding encoding, string name, IEnumerable route } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name, address and route. @@ -122,7 +119,7 @@ public MailboxAddress (string name, IEnumerable route, string address) : } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified address and route. @@ -137,12 +134,13 @@ public MailboxAddress (string name, IEnumerable route, string address) : /// /// is malformed. /// + [Obsolete ("This constructor will be going away. Use new MailboxAddress(string name, IEnumerable route, string address) instead.")] public MailboxAddress (IEnumerable route, string address) : this (Encoding.UTF8, null, route, address) { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name and address. The @@ -170,7 +168,7 @@ public MailboxAddress (Encoding encoding, string name, string address) : base (e } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified name and address. @@ -188,7 +186,7 @@ public MailboxAddress (string name, string address) : this (Encoding.UTF8, name, } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified address. @@ -206,6 +204,7 @@ public MailboxAddress (string name, string address) : this (Encoding.UTF8, name, /// /// is malformed. /// + [Obsolete("This constructor will be going away due to it causing too much confusion. Use new MailboxAddress(string name, string address) or MailboxAddress.Parse(string) instead.")] public MailboxAddress (string address) : this (Encoding.UTF8, null, address) { } @@ -238,7 +237,7 @@ public DomainList Route { /// Gets or sets the mailbox address. /// /// - /// Represents the actual email address and is in the form of user@example.com. + /// Represents the actual email address and is in the form of user@domain.com. /// /// The mailbox address. /// @@ -258,14 +257,12 @@ public string Address { if (value.Length > 0) { var buffer = CharsetUtils.UTF8.GetBytes (value); - string addrspec; int index = 0; - int atIndex; - TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], true, out addrspec, out atIndex); + TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], true, out string addrspec, out int atIndex); if (index != buffer.Length) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); address = addrspec; at = atIndex; @@ -307,17 +304,19 @@ public bool IsInternational { static string EncodeAddrspec (string addrspec, int at) { -#if !PORTABLE if (at != -1) { var domain = addrspec.Substring (at + 1); var local = addrspec.Substring (0, at); + if (ParseUtils.IsInternational (local)) + local = ParseUtils.IdnEncode (local); + if (ParseUtils.IsInternational (domain)) domain = ParseUtils.IdnEncode (domain); return local + "@" + domain; } -#endif + return addrspec; } @@ -337,36 +336,33 @@ public static string EncodeAddrspec (string addrspec) if (addrspec == null) throw new ArgumentNullException (nameof (addrspec)); -#if !PORTABLE if (addrspec.Length == 0) return addrspec; var buffer = CharsetUtils.UTF8.GetBytes (addrspec); - int at, index = 0; - string address; + int index = 0; - if (!TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], false, out address, out at)) + if (!TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], false, out string address, out int at)) return addrspec; return EncodeAddrspec (address, at); -#else - return addrspec; -#endif } static string DecodeAddrspec (string addrspec, int at) { -#if !PORTABLE if (at != -1) { var domain = addrspec.Substring (at + 1); var local = addrspec.Substring (0, at); + if (ParseUtils.IsIdnEncoded (local)) + local = ParseUtils.IdnDecode (local); + if (ParseUtils.IsIdnEncoded (domain)) domain = ParseUtils.IdnDecode (domain); return local + "@" + domain; } -#endif + return addrspec; } @@ -386,34 +382,41 @@ public static string DecodeAddrspec (string addrspec) if (addrspec == null) throw new ArgumentNullException (nameof (addrspec)); -#if !PORTABLE if (addrspec.Length == 0) return addrspec; var buffer = CharsetUtils.UTF8.GetBytes (addrspec); - int at, index = 0; - string address; + int index = 0; - if (!TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], false, out address, out at)) + if (!TryParseAddrspec (buffer, ref index, buffer.Length, new byte[0], false, out string address, out int at)) return addrspec; return DecodeAddrspec (address, at); -#else - return addrspec; -#endif } - internal override void Encode (FormatOptions options, StringBuilder builder, ref int lineLength) + /// + /// Get the mailbox address, optionally encoded according to IDN encoding rules. + /// + /// + /// If is true, then the returned mailbox address will be encoded according to the IDN encoding rules. + /// + /// true if the address should be encoded according to IDN encoding rules; otherwise, false. + /// The mailbox address. + public string GetAddress (bool idnEncode) + { + if (idnEncode) + return EncodeAddrspec (address, at); + + return DecodeAddrspec (address, at); + } + + internal override void Encode (FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength) { var route = Route.Encode (options); if (!string.IsNullOrEmpty (route)) route += ":"; - string addrspec; - if (options.International) - addrspec = DecodeAddrspec (address, at); - else - addrspec = EncodeAddrspec (address, at); + var addrspec = GetAddress (!options.International); if (!string.IsNullOrEmpty (Name)) { string name; @@ -428,11 +431,11 @@ internal override void Encode (FormatOptions options, StringBuilder builder, ref if (lineLength + name.Length > options.MaxLineLength) { if (name.Length > options.MaxLineLength) { // we need to break up the name... - builder.AppendFolded (options, name, ref lineLength); + builder.AppendFolded (options, firstToken, name, ref lineLength); } else { // the name itself is short enough to fit on a single line, // but only if we write it on a line by itself - if (lineLength > 1) { + if (!firstToken && lineLength > 1) { builder.LineWrap (options); lineLength = 1; } @@ -462,7 +465,7 @@ internal override void Encode (FormatOptions options, StringBuilder builder, ref builder.Append (addrspec); builder.Append ('>'); } else if (!string.IsNullOrEmpty (route)) { - if ((lineLength + route.Length + addrspec.Length + 2) > options.MaxLineLength) { + if (!firstToken && (lineLength + route.Length + addrspec.Length + 2) > options.MaxLineLength) { builder.Append (options.NewLine); builder.Append ("\t<"); lineLength = 2; @@ -478,7 +481,7 @@ internal override void Encode (FormatOptions options, StringBuilder builder, ref builder.Append (addrspec); builder.Append ('>'); } else { - if ((lineLength + addrspec.Length) > options.MaxLineLength) { + if (!firstToken && (lineLength + addrspec.Length) > options.MaxLineLength) { builder.LineWrap (options); lineLength = 1; } @@ -513,7 +516,7 @@ public override string ToString (FormatOptions options, bool encode) var builder = new StringBuilder (); int lineLength = 0; - Encode (options, builder, ref lineLength); + Encode (options, builder, true, ref lineLength); return builder.ToString (); } @@ -534,14 +537,14 @@ public override string ToString (FormatOptions options, bool encode) #region IEquatable implementation /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// /// Compares two mailbox addresses to determine if they are identical or not. /// - /// The to compare with the current . - /// true if the specified is equal to the current - /// ; otherwise, false. + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals (InternetAddress other) { var mailbox = other as MailboxAddress; @@ -567,7 +570,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index if (throwOnError) flags |= AddressParserFlags.ThrowOnError; - if (!InternetAddress.TryParse (options, text, ref index, endIndex, 0, flags, out address)) { + if (!TryParse (options, text, ref index, endIndex, 0, flags, out address)) { mailbox = null; return false; } @@ -578,7 +581,7 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -618,7 +621,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -642,7 +645,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Mail } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -680,7 +683,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, int startInde } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -702,7 +705,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out MailboxAddress m } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -736,7 +739,7 @@ public static bool TryParse (ParserOptions options, byte[] buffer, out MailboxAd } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -754,7 +757,7 @@ public static bool TryParse (byte[] buffer, out MailboxAddress mailbox) } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -791,7 +794,7 @@ public static bool TryParse (ParserOptions options, string text, out MailboxAddr } /// - /// Tries to parse the given text into a new instance. + /// Try to parse the given text into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or @@ -809,13 +812,13 @@ public static bool TryParse (string text, out MailboxAddress mailbox) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -846,19 +849,19 @@ public static bool TryParse (string text, out MailboxAddress mailbox) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return mailbox; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// The number of bytes in the input buffer to parse. @@ -869,7 +872,7 @@ public static bool TryParse (string text, out MailboxAddress mailbox) /// and do not specify /// a valid range in the byte array. /// - /// + /// /// could not be parsed. /// public static new MailboxAddress Parse (byte[] buffer, int startIndex, int length) @@ -878,13 +881,13 @@ public static bool TryParse (string text, out MailboxAddress mailbox) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// The starting index of the input buffer. @@ -896,7 +899,7 @@ public static bool TryParse (string text, out MailboxAddress mailbox) /// /// is out of range. /// - /// + /// /// could not be parsed. /// public static new MailboxAddress Parse (ParserOptions options, byte[] buffer, int startIndex) @@ -913,19 +916,19 @@ public static bool TryParse (string text, out MailboxAddress mailbox) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return mailbox; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// The starting index of the input buffer. /// @@ -943,13 +946,13 @@ public static bool TryParse (string text, out MailboxAddress mailbox) } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The input buffer. /// @@ -974,19 +977,19 @@ public static bool TryParse (string text, out MailboxAddress mailbox) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return mailbox; } /// - /// Parses the given input buffer into a new instance. + /// Parse the given input buffer into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The input buffer. /// /// is null. @@ -1000,13 +1003,13 @@ public static bool TryParse (string text, out MailboxAddress mailbox) } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The parser options to use. /// The text. /// @@ -1036,19 +1039,19 @@ public static bool TryParse (string text, out MailboxAddress mailbox) ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, true); if (index != endIndex) - throw new ParseException (string.Format ("Unexpected token at offset {0}", index), index, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Unexpected token at offset {0}", index), index, index); return mailbox; } /// - /// Parses the given text into a new instance. + /// Parse the given text into a new instance. /// /// /// Parses a single . If the address is not a mailbox address or /// there is more than a single mailbox address, then parsing will fail. /// - /// The parsed . + /// The parsed . /// The text. /// /// is null. diff --git a/MimeKit/MessageDeliveryStatus.cs b/MimeKit/MessageDeliveryStatus.cs index 89764b5aed..3495bdcdc3 100644 --- a/MimeKit/MessageDeliveryStatus.cs +++ b/MimeKit/MessageDeliveryStatus.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,16 +36,20 @@ namespace MimeKit { /// A message delivery status MIME part is a machine readable notification denoting the /// delivery status of a message and has a MIME-type of message/delivery-status. /// For more information, see rfc3464. + /// /// + /// + /// + /// public class MessageDeliveryStatus : MimePart { HeaderListCollection groups; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -56,7 +60,7 @@ public MessageDeliveryStatus (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -79,6 +83,9 @@ public MessageDeliveryStatus () : base ("message", "delivery-status") /// Section 2.3 defines /// the per-recipient fields. /// + /// + /// + /// /// The fields. public HeaderListCollection StatusGroups { get { @@ -123,12 +130,12 @@ void OnGroupsChanged (object sender, EventArgs e) /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/MessageDispositionNotification.cs b/MimeKit/MessageDispositionNotification.cs index 7c71482d0d..975fc2404c 100644 --- a/MimeKit/MessageDispositionNotification.cs +++ b/MimeKit/MessageDispositionNotification.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,16 +36,17 @@ namespace MimeKit { /// A message disposition notification MIME part is a machine readable notification /// denoting the disposition of a message once it has been successfully delivered /// and has a MIME-type of message/disposition-notification. + /// /// public class MessageDispositionNotification : MimePart { HeaderList fields; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -56,7 +57,7 @@ public MessageDispositionNotification (MimeEntityConstructorArgs args) : base (a } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -106,12 +107,12 @@ void OnFieldsChanged (object sender, HeaderListChangedEventArgs e) /// Dispatches to the specific visit method for this MIME entity. ///
/// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/MessageIdList.cs b/MimeKit/MessageIdList.cs index 31bbeadd29..52c435c5cb 100644 --- a/MimeKit/MessageIdList.cs +++ b/MimeKit/MessageIdList.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,10 +29,6 @@ using System.Collections; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.Utils; namespace MimeKit { @@ -47,7 +43,7 @@ public class MessageIdList : IList readonly List references; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new, empty, . @@ -77,7 +73,7 @@ public MessageIdList Clone () #region IList implementation /// - /// Gets the index of the requested Message-Id, if it exists. + /// Get the index of the requested Message-Id, if it exists. /// /// /// Finds the index of the specified Message-Id, if it exists. @@ -127,7 +123,7 @@ public void Insert (int index, string messageId) } /// - /// Removes the Message-Id at the specified index. + /// Remove the Message-Id at the specified index. /// /// /// Removes the Message-Id at the specified index. @@ -143,7 +139,7 @@ public void RemoveAt (int index) } /// - /// Gets or sets the at the specified index. + /// Get or set the Message-Id at the specified index. /// /// /// Gets or sets the Message-Id at the specified index. @@ -215,7 +211,7 @@ public void AddRange (IEnumerable items) } /// - /// Clears the Message-Id list. + /// Clear the Message-Id list. /// /// /// Removes all of the Message-Ids in the list. @@ -227,7 +223,7 @@ public void Clear () } /// - /// Checks if the contains the specified Message-Id. + /// Check if the contains the specified Message-Id. /// /// /// Determines whether or not the list contains the specified Message-Id. @@ -247,7 +243,7 @@ public bool Contains (string messageId) } /// - /// Copies all of the Message-Ids in the to the specified array. + /// Copy all of the Message-Ids in the to the specified array. /// /// /// Copies all of the Message-Ids within the into the array, @@ -267,7 +263,7 @@ public void CopyTo (string[] array, int arrayIndex) } /// - /// Removes the specified Message-Id. + /// Remove a Message-Id from the . /// /// /// Removes the first instance of the specified Message-Id from the list if it exists. @@ -292,7 +288,7 @@ public bool Remove (string messageId) } /// - /// Gets the number of Message-Ids in the . + /// Get the number of Message-Ids in the . /// /// /// Indicates the number of Message-Ids in the list. @@ -303,7 +299,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether the is read only. /// /// /// A is never read-only. @@ -318,7 +314,7 @@ public bool IsReadOnly { #region IEnumerable implementation /// - /// Gets an enumerator for the list of Message-Ids. + /// Get an enumerator for the list of Message-Ids. /// /// /// Gets an enumerator for the list of Message-Ids. @@ -334,7 +330,7 @@ public IEnumerator GetEnumerator () #region IEnumerable implementation /// - /// Gets an enumerator for the list of Message-Ids. + /// Get an enumerator for the list of Message-Ids. /// /// /// Gets an enumerator for the list of Message-Ids. @@ -348,7 +344,7 @@ IEnumerator IEnumerable.GetEnumerator () #endregion /// - /// Returns a string representation of the list of Message-Ids. + /// Serialize a to a string. /// /// /// Each Message-Id will be surrounded by angle brackets. diff --git a/MimeKit/MessageImportance.cs b/MimeKit/MessageImportance.cs index c20404b2b4..24867ca31e 100644 --- a/MimeKit/MessageImportance.cs +++ b/MimeKit/MessageImportance.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/MessagePart.cs b/MimeKit/MessagePart.cs index ae0924aff8..763ad3fadf 100644 --- a/MimeKit/MessagePart.cs +++ b/MimeKit/MessagePart.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,7 +33,7 @@ namespace MimeKit { /// - /// A MIME part containing a as its content. + /// A MIME part containing a as its content. /// /// /// Represents MIME entities such as those with a Content-Type of message/rfc822 or message/news. @@ -41,10 +41,10 @@ namespace MimeKit { public class MessagePart : MimeEntity { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -55,7 +55,7 @@ public MessagePart (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -68,7 +68,7 @@ public MessagePart (MimeEntityConstructorArgs args) : base (args) /// is null. /// /// - /// contains more than one . + /// contains more than one . /// -or- /// contains one or more arguments of an unknown type. /// @@ -83,8 +83,7 @@ public MessagePart (string subtype, params object[] args) : this (subtype) if (obj == null || TryInit (obj)) continue; - var mesg = obj as MimeMessage; - if (mesg != null) { + if (obj is MimeMessage mesg) { if (message != null) throw new ArgumentException ("MimeMessage should not be specified more than once."); @@ -100,7 +99,24 @@ public MessagePart (string subtype, params object[] args) : this (subtype) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. + /// + /// + /// Initializes the based on the provided media type and subtype. + /// + /// The media type. + /// The media subtype. + /// + /// is null. + /// -or- + /// is null. + /// + protected MessagePart (string mediaType, string mediaSubtype) : base (mediaType, mediaSubtype) + { + } + + /// + /// Initialize a new instance of the class. /// /// /// Creates a new MIME message entity with the specified subtype. @@ -109,12 +125,12 @@ public MessagePart (string subtype, params object[] args) : this (subtype) /// /// is null. /// - public MessagePart (string subtype) : base ("message", subtype) + public MessagePart (string subtype) : this ("message", subtype) { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message/rfc822 MIME entity. @@ -138,12 +154,12 @@ public MimeMessage Message { /// Dispatches to the specific visit method for this MIME entity. ///
/// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -180,7 +196,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } /// - /// Writes the to the output stream. + /// Write the to the output stream. /// /// /// Writes the MIME entity and its message to the output stream. @@ -219,15 +235,21 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } } + if (options.EnsureNewLine) { + options = options.Clone (); + options.EnsureNewLine = false; + } + Message.WriteTo (options, stream, cancellationToken); } /// - /// Asynchronously writes the to the output stream. + /// Asynchronously write the to the output stream. /// /// - /// Writes the MIME entity and its message to the output stream. + /// Asynchronously writes the MIME entity and its message to the output stream. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// true if only the content should be written; otherwise, false. @@ -255,6 +277,11 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = await stream.WriteAsync (options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken).ConfigureAwait (false); } + if (options.EnsureNewLine) { + options = options.Clone (); + options.EnsureNewLine = false; + } + await Message.WriteToAsync (options, stream, cancellationToken).ConfigureAwait (false); } } diff --git a/MimeKit/MessagePartial.cs b/MimeKit/MessagePartial.cs index 967eda2ba4..75984864d3 100644 --- a/MimeKit/MessagePartial.cs +++ b/MimeKit/MessagePartial.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -45,10 +45,10 @@ namespace MimeKit { public class MessagePartial : MimePart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -59,7 +59,7 @@ public MessagePartial (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new message/partial entity. @@ -149,12 +149,12 @@ public int? Total { /// Dispatches to the specific visit method for this MIME entity. ///
/// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -203,9 +203,40 @@ public static IEnumerable Split (MimeMessage message, int maxSize) if (maxSize < 1) throw new ArgumentOutOfRangeException (nameof (maxSize)); + var options = FormatOptions.CloneDefault (); + foreach (HeaderId id in Enum.GetValues (typeof (HeaderId))) { + switch (id) { + case HeaderId.Subject: + case HeaderId.MessageId: + case HeaderId.Encrypted: + case HeaderId.MimeVersion: + case HeaderId.ContentAlternative: + case HeaderId.ContentBase: + case HeaderId.ContentClass: + case HeaderId.ContentDescription: + case HeaderId.ContentDisposition: + case HeaderId.ContentDuration: + case HeaderId.ContentFeatures: + case HeaderId.ContentId: + case HeaderId.ContentIdentifier: + case HeaderId.ContentLanguage: + case HeaderId.ContentLength: + case HeaderId.ContentLocation: + case HeaderId.ContentMd5: + case HeaderId.ContentReturn: + case HeaderId.ContentTransferEncoding: + case HeaderId.ContentTranslationType: + case HeaderId.ContentType: + break; + default: + options.HiddenHeaders.Add (id); + break; + } + } + var memory = new MemoryStream (); - message.WriteTo (memory); + message.WriteTo (options, memory); memory.Seek (0, SeekOrigin.Begin); if (memory.Length <= maxSize) { @@ -216,7 +247,7 @@ public static IEnumerable Split (MimeMessage message, int maxSize) } var streams = new List (); -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buf = memory.GetBuffer (); #else var buf = memory.ToArray (); @@ -242,12 +273,13 @@ public static IEnumerable Split (MimeMessage message, int maxSize) startIndex = endIndex; } - var id = message.MessageId ?? MimeUtils.GenerateMessageId (); + var msgid = message.MessageId ?? MimeUtils.GenerateMessageId (); int number = 1; foreach (var stream in streams) { - var part = new MessagePartial (id, number++, streams.Count); - part.Content = new MimeContent (stream); + var part = new MessagePartial (msgid, number++, streams.Count) { + Content = new MimeContent (stream) + }; var submessage = CloneMessage (message); submessage.MessageId = MimeUtils.GenerateMessageId (); @@ -262,38 +294,82 @@ public static IEnumerable Split (MimeMessage message, int maxSize) static int PartialCompare (MessagePartial partial1, MessagePartial partial2) { if (!partial1.Number.HasValue || !partial2.Number.HasValue || partial1.Id != partial2.Id) - throw new ArgumentException ("partial"); + throw new ArgumentException ("Partial messages have mismatching identifiers.", "partials"); return partial1.Number.Value - partial2.Number.Value; } - /// - /// Joins the specified message/partial parts into the complete message. - /// - /// - /// Combines all of the message/partial fragments into its original, - /// complete, message. - /// - /// The re-combined message. - /// The parser options to use. - /// The list of partial message parts. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// The last partial does not have a Total. - /// -or- - /// The number of partials provided does not match the expected count. - /// -or- - /// One or more partials is missing. - /// - public static MimeMessage Join (ParserOptions options, IEnumerable partials) + static void CombineHeaders (MimeMessage message, MimeMessage joined) + { + var headers = new List
(); + int i = 0; + + // RFC2046: Any header fields in the enclosed message which do not start with "Content-" + // (except for the "Subject", "Message-ID", "Encrypted", and "MIME-Version" fields) will + // be ignored and dropped. + while (i < joined.Headers.Count) { + var header = joined.Headers[i]; + + switch (header.Id) { + case HeaderId.Subject: + case HeaderId.MessageId: + case HeaderId.Encrypted: + case HeaderId.MimeVersion: + headers.Add (header); + header.Offset = null; + i++; + break; + default: + joined.Headers.RemoveAt (i); + break; + } + } + + // RFC2046: All of the header fields from the initial enclosing message, except + // those that start with "Content-" and the specific header fields "Subject", + // "Message-ID", "Encrypted", and "MIME-Version", must be copied, in order, + // to the new message. + i = 0; + foreach (var header in message.Headers) { + switch (header.Id) { + case HeaderId.Subject: + case HeaderId.MessageId: + case HeaderId.Encrypted: + case HeaderId.MimeVersion: + for (int j = 0; j < headers.Count; j++) { + if (headers[j].Id == header.Id) { + var original = headers[j]; + + joined.Headers.Remove (original); + joined.Headers.Insert (i++, original); + headers.RemoveAt (j); + break; + } + } + break; + default: + var clone = header.Clone (); + clone.Offset = null; + + joined.Headers.Insert (i++, clone); + break; + } + } + + if (joined.Body != null) { + foreach (var header in joined.Body.Headers) + header.Offset = null; + } + } + + static MimeMessage Join (ParserOptions options, MimeMessage message, IEnumerable partials, bool allowNullMessage) { if (options == null) throw new ArgumentNullException (nameof (options)); + if (!allowNullMessage && message == null) + throw new ArgumentNullException (nameof (message)); + if (partials == null) throw new ArgumentNullException (nameof (partials)); @@ -327,11 +403,93 @@ public static MimeMessage Join (ParserOptions options, IEnumerable + /// Joins the specified message/partial parts into the complete message. + ///
+ /// + /// Combines all of the message/partial fragments into its original, + /// complete, message. + /// + /// The re-combined message. + /// The parser options to use. + /// The message that contains the first `message/partial` part. + /// The list of partial message parts. + /// + /// is null. + /// -or- + /// is null. + /// -or- + /// is null. + /// + /// + /// The last partial does not have a Total. + /// -or- + /// The number of partials provided does not match the expected count. + /// -or- + /// One or more partials is missing. + /// + public static MimeMessage Join (ParserOptions options, MimeMessage message, IEnumerable partials) + { + return Join (options, message, partials, false); + } + + /// + /// Joins the specified message/partial parts into the complete message. + /// + /// + /// Combines all of the message/partial fragments into its original, + /// complete, message. + /// + /// The re-combined message. + /// The message that contains the first `message/partial` part. + /// The list of partial message parts. + /// + /// is null. + /// -or- + /// is null. + /// + public static MimeMessage Join (MimeMessage message, IEnumerable partials) + { + return Join (ParserOptions.Default, message, partials, false); + } + + /// + /// Joins the specified message/partial parts into the complete message. + /// + /// + /// Combines all of the message/partial fragments into its original, + /// complete, message. + /// + /// The re-combined message. + /// The parser options to use. + /// The list of partial message parts. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// The last partial does not have a Total. + /// -or- + /// The number of partials provided does not match the expected count. + /// -or- + /// One or more partials is missing. + /// + [Obsolete ("Use MessagePartial.Join (ParserOptions, MimeMessage, IEnumerable) instead.")] + public static MimeMessage Join (ParserOptions options, IEnumerable partials) + { + return Join (options, null, partials, true); + } + /// /// Joins the specified message/partial parts into the complete message. /// @@ -344,9 +502,10 @@ public static MimeMessage Join (ParserOptions options, IEnumerable /// is null. /// + [Obsolete ("Use MessagePartial.Join (MimeMessage, IEnumerable) instead.")] public static MimeMessage Join (IEnumerable partials) { - return Join (ParserOptions.Default, partials); + return Join (ParserOptions.Default, null, partials, true); } } } diff --git a/MimeKit/MessagePriority.cs b/MimeKit/MessagePriority.cs index 461e4d22c6..e97261fc4d 100644 --- a/MimeKit/MessagePriority.cs +++ b/MimeKit/MessagePriority.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/MimeContent.cs b/MimeKit/MimeContent.cs index b28ce0fa85..fffb6f8f5c 100644 --- a/MimeKit/MimeContent.cs +++ b/MimeKit/MimeContent.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Buffers; using System.Threading; using System.Threading.Tasks; @@ -34,7 +35,7 @@ namespace MimeKit { /// - /// Encapsulates a content stream used by . + /// Encapsulates a content stream used by . /// /// /// A represents the content of a . @@ -44,11 +45,11 @@ namespace MimeKit { public class ContentObject : MimeContent { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// When creating new s, the - /// should typically be unless the + /// When creating new s, the + /// should typically be unless the /// has already been encoded. /// /// The content stream. @@ -66,7 +67,7 @@ public ContentObject (Stream stream, ContentEncoding encoding = ContentEncoding. } /// - /// Encapsulates a content stream used by . + /// Encapsulates a content stream used by . /// /// /// A represents the content of a . @@ -77,12 +78,14 @@ public ContentObject (Stream stream, ContentEncoding encoding = ContentEncoding. /// public class MimeContent : IMimeContent { + const int BufferLength = 4096; + /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// When creating new s, the - /// should typically be unless the + /// When creating new s, the + /// should typically be unless the /// has already been encoded. /// /// The content stream. @@ -113,7 +116,7 @@ public MimeContent (Stream stream, ContentEncoding encoding = ContentEncoding.De #region IContentObject implementation /// - /// Gets or sets the content encoding. + /// Get or set the content encoding. /// /// /// If the was parsed from an existing stream, the @@ -126,7 +129,18 @@ public ContentEncoding Encoding { } /// - /// Gets the content stream. + /// Get the new-line format, if known. + /// + /// + /// This property is typically only set by the as it parses + /// the content of a and is only used as a hint when verifying + /// digital signatures. + /// + /// The new-line format, if known. + public NewLineFormat? NewLineFormat { get; set; } + + /// + /// Get the content stream. /// /// /// Gets the content stream. @@ -137,7 +151,7 @@ public Stream Stream { } /// - /// Opens the decoded content stream. + /// Open the decoded content stream. /// /// /// Provides a means of reading the decoded content without having to first write it to another @@ -155,7 +169,7 @@ public Stream Open () } /// - /// Copies the content stream to the specified output stream. + /// Copy the content stream to the specified output stream. /// /// /// This is equivalent to simply using @@ -179,21 +193,21 @@ public Stream Open () if (stream == null) throw new ArgumentNullException (nameof (stream)); + Stream.Seek (0, SeekOrigin.Begin); + + var buf = ArrayPool.Shared.Rent (BufferLength); var readable = Stream as ICancellableStream; var writable = stream as ICancellableStream; - var buf = new byte[4096]; int nread; - Stream.Seek (0, SeekOrigin.Begin); - try { do { if (readable != null) { - if ((nread = readable.Read (buf, 0, buf.Length, cancellationToken)) <= 0) + if ((nread = readable.Read (buf, 0, BufferLength, cancellationToken)) <= 0) break; } else { cancellationToken.ThrowIfCancellationRequested (); - if ((nread = Stream.Read (buf, 0, buf.Length)) <= 0) + if ((nread = Stream.Read (buf, 0, BufferLength)) <= 0) break; } @@ -214,11 +228,13 @@ public Stream Open () } throw; + } finally { + ArrayPool.Shared.Return (buf); } } /// - /// Asynchronously copies the content stream to the specified output stream. + /// Asynchronously copy the content stream to the specified output stream. /// /// /// This is equivalent to simply using @@ -226,6 +242,7 @@ public Stream Open () /// If you want the decoded content, use /// instead. /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// @@ -242,11 +259,11 @@ public Stream Open () if (stream == null) throw new ArgumentNullException (nameof (stream)); - var buf = new byte[4096]; - int nread; - Stream.Seek (0, SeekOrigin.Begin); + var buf = ArrayPool.Shared.Rent (BufferLength); + int nread; + try { do { if ((nread = await Stream.ReadAsync (buf, 0, buf.Length, cancellationToken).ConfigureAwait (false)) <= 0) @@ -264,17 +281,22 @@ public Stream Open () } throw; + } finally { + ArrayPool.Shared.Return (buf); } } /// - /// Decodes the content stream into another stream. + /// Decode the content stream into another stream. /// /// /// If the content stream is encoded, this method will decode it into the output stream /// using a suitable decoder based on the property, otherwise the /// stream will be copied into the output stream as-is. /// + /// + /// + /// /// The output stream. /// The cancellation token. /// @@ -286,9 +308,6 @@ public Stream Open () /// /// An I/O error occurred. /// - /// - /// - /// public void DecodeTo (Stream stream, CancellationToken cancellationToken = default (CancellationToken)) { if (stream == null) @@ -302,13 +321,17 @@ public Stream Open () } /// - /// Asynchronously decodes the content stream into another stream. + /// Asynchronously decode the content stream into another stream. /// /// /// If the content stream is encoded, this method will decode it into the output stream /// using a suitable decoder based on the property, otherwise the /// stream will be copied into the output stream as-is. /// + /// + /// + /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// @@ -320,9 +343,6 @@ public Stream Open () /// /// An I/O error occurred. /// - /// - /// - /// public async Task DecodeToAsync (Stream stream, CancellationToken cancellationToken = default (CancellationToken)) { if (stream == null) diff --git a/MimeKit/MimeEntity.cs b/MimeKit/MimeEntity.cs index 78881ea05b..de1aef614b 100644 --- a/MimeKit/MimeEntity.cs +++ b/MimeKit/MimeEntity.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,12 +32,8 @@ using System.Threading.Tasks; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - -using MimeKit.Utils; using MimeKit.IO; +using MimeKit.Utils; namespace MimeKit { /// @@ -59,7 +55,7 @@ public abstract class MimeEntity Uri baseUri; /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// based on the . /// /// @@ -90,7 +86,7 @@ protected MimeEntity (MimeEntityConstructorArgs args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Initializes the based on the provided media type and subtype. @@ -107,7 +103,7 @@ protected MimeEntity (string mediaType, string mediaSubtype) : this (new Content } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Initializes the to the one provided. @@ -141,14 +137,12 @@ protected MimeEntity (ContentType contentType) protected bool TryInit (object obj) { // The base MimeEntity class only knows about Headers. - var header = obj as Header; - if (header != null) { + if (obj is Header header) { Headers.Add (header); return true; } - var headers = obj as IEnumerable
; - if (headers != null) { + if (obj is IEnumerable
headers) { foreach (Header h in headers) Headers.Add (h); return true; @@ -294,13 +288,12 @@ public string ContentId { } var buffer = Encoding.UTF8.GetBytes (value); - MailboxAddress mailbox; int index = 0; - if (!MailboxAddress.TryParse (Headers.Options, buffer, ref index, buffer.Length, false, out mailbox)) - throw new ArgumentException ("Invalid Content-Id format."); + if (!ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out string id)) + throw new ArgumentException ("Invalid Content-Id format.", nameof (value)); - contentId = mailbox.Address; + contentId = id; SetHeader ("Content-Id", "<" + contentId + ">"); } @@ -329,19 +322,28 @@ public bool IsAttachment { } } + static readonly byte[] ToStringWarning = Encoding.UTF8.GetBytes ("X-MimeKit-Warning: Do NOT use ToString() to serialize entities! Use one of the WriteTo() methods instead!"); + /// - /// Returns a that represents the current . + /// Returns a that represents the for debugging purposes. /// /// - /// Returns a that represents the current . + /// Returns a that represents the for debugging purposes. + /// In general, the string returned from this method SHOULD NOT be used for serializing + /// the entity to disk. It is recommended that you use instead. + /// If this method is used for serializing the entity to disk, the iso-8859-1 text encoding should be used for + /// conversion. /// - /// A that represents the current . + /// A that represents the for debugging purposes. public override string ToString () { using (var memory = new MemoryStream ()) { + memory.Write (ToStringWarning, 0, ToStringWarning.Length); + memory.Write (FormatOptions.Default.NewLineBytes, 0, FormatOptions.Default.NewLineBytes.Length); + WriteTo (memory); -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buffer = memory.GetBuffer (); #else var buffer = memory.ToArray (); @@ -356,12 +358,12 @@ public override string ToString () /// Dispatches to the specific visit method for this MIME entity. ///
/// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -391,7 +393,7 @@ public virtual void Accept (MimeVisitor visitor) public abstract void Prepare (EncodingConstraint constraint, int maxLineLength = 78); /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the headers to the output stream, followed by a blank line. @@ -425,12 +427,13 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Asynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the headers to the output stream, followed by a blank line. + /// Asynchronously writes the headers to the output stream, followed by a blank line. /// Subclasses should override this method to write the content of the entity. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// true if only the content should be written; otherwise, false. @@ -461,7 +464,7 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the headers to the output stream, followed by a blank line. @@ -487,12 +490,13 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Asynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the headers to the output stream, followed by a blank line. + /// Asynchronously writes the headers to the output stream, followed by a blank line. /// Subclasses should override this method to write the content of the entity. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// The cancellation token. @@ -513,7 +517,7 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the entity to the output stream. @@ -536,11 +540,12 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Adsynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the entity to the output stream. + /// Asynchronously writes the entity to the output stream. /// + /// An awaitable task. /// The output stream. /// true if only the content should be written; otherwise, false. /// The cancellation token. @@ -559,7 +564,7 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Write the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the entity to the output stream. @@ -581,11 +586,12 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Asynchronously write the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the entity to the output stream. + /// Asynchronously writes the entity to the output stream. /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// @@ -602,12 +608,11 @@ public virtual void Accept (MimeVisitor visitor) return WriteToAsync (FormatOptions.Default, stream, false, cancellationToken); } -#if !PORTABLE /// - /// Write the to the specified file. + /// Write the to the specified file. /// /// - /// Writes the to the specified file using the provided formatting options. + /// Writes the entity to the specified file using the provided formatting options. /// /// The formatting options. /// The file. @@ -620,8 +625,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -651,11 +655,12 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Asynchronously write the to the specified file. + /// Asynchronously write the to the specified file. /// /// - /// Writes the to the specified file using the provided formatting options. + /// Asynchronously writes the entity to the specified file using the provided formatting options. /// + /// An awaitable task. /// The formatting options. /// The file. /// true if only the content should be written; otherwise, false. @@ -667,8 +672,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -698,10 +702,10 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Write the to the specified file. + /// Write the to the specified file. /// /// - /// Writes the to the specified file using the provided formatting options. + /// Writes the entity to the specified file using the provided formatting options. /// /// The formatting options. /// The file. @@ -713,8 +717,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -739,16 +742,19 @@ public virtual void Accept (MimeVisitor visitor) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) + using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) { WriteTo (options, stream, false, cancellationToken); + stream.Flush (); + } } /// - /// Asynchronously write the to the specified file. + /// Asynchronously write the to the specified file. /// /// - /// Writes the to the specified file using the provided formatting options. + /// Asynchronously writes the entity to the specified file using the provided formatting options. /// + /// An awaitable task. /// The formatting options. /// The file. /// The cancellation token. @@ -759,8 +765,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -785,15 +790,17 @@ public virtual void Accept (MimeVisitor visitor) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) + using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) { await WriteToAsync (options, stream, false, cancellationToken).ConfigureAwait (false); + await stream.FlushAsync (cancellationToken).ConfigureAwait (false); + } } /// - /// Write the to the specified file. + /// Write the to the specified file. /// /// - /// Writes the to the specified file using the default formatting options. + /// Writes the entity to the specified file using the default formatting options. /// /// The file. /// true if only the content should be written; otherwise, false. @@ -803,8 +810,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -827,11 +833,12 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Asynchronously write the to the specified file. + /// Asynchronously write the to the specified file. /// /// - /// Writes the to the specified file using the default formatting options. + /// Asynchronously writes the entity to the specified file using the default formatting options. /// + /// An awaitable task. /// The file. /// true if only the content should be written; otherwise, false. /// The cancellation token. @@ -840,8 +847,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -864,10 +870,10 @@ public virtual void Accept (MimeVisitor visitor) } /// - /// Writes the to the specified file. + /// Write the to the specified file. /// /// - /// Writes the to the specified file using the default formatting options. + /// Writes the entity to the specified file using the default formatting options. /// /// The file. /// The cancellation token. @@ -876,8 +882,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -896,19 +901,16 @@ public virtual void Accept (MimeVisitor visitor) /// public void WriteTo (string fileName, CancellationToken cancellationToken = default (CancellationToken)) { - if (fileName == null) - throw new ArgumentNullException (nameof (fileName)); - - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) - WriteTo (FormatOptions.Default, stream, false, cancellationToken); + WriteTo (FormatOptions.Default, fileName, cancellationToken); } /// - /// Asynchronously writes the to the specified file. + /// Asynchronously write the to the specified file. /// /// - /// Writes the to the specified file using the default formatting options. + /// Asynchronously writes the entity to the specified file using the default formatting options. /// + /// An awaitable task. /// The file. /// The cancellation token. /// @@ -916,8 +918,7 @@ public virtual void Accept (MimeVisitor visitor) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -934,18 +935,13 @@ public virtual void Accept (MimeVisitor visitor) /// /// An I/O error occurred. /// - public async Task WriteToAsync (string fileName, CancellationToken cancellationToken = default (CancellationToken)) + public Task WriteToAsync (string fileName, CancellationToken cancellationToken = default (CancellationToken)) { - if (fileName == null) - throw new ArgumentNullException (nameof (fileName)); - - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) - await WriteToAsync (FormatOptions.Default, stream, false, cancellationToken).ConfigureAwait (false); + return WriteToAsync (FormatOptions.Default, fileName, cancellationToken); } -#endif // !PORTABLE /// - /// Removes the header. + /// Remove a header by name. /// /// /// Removes all headers matching the specified name without @@ -964,7 +960,7 @@ protected void RemoveHeader (string name) } /// - /// Sets the header. + /// Set the value of a header. /// /// /// Sets the header to the specified value without @@ -984,7 +980,7 @@ protected void SetHeader (string name, string value) } /// - /// Sets the header using the raw value. + /// Set the value of a header using the raw value. /// /// /// Sets the header to the specified value without @@ -1045,7 +1041,6 @@ void ContentTypeChanged (object sender, EventArgs e) /// The header being added, changed or removed. protected virtual void OnHeadersChanged (HeaderListChangedAction action, Header header) { - MailboxAddress mailbox; int index = 0; string text; @@ -1079,8 +1074,8 @@ protected virtual void OnHeadersChanged (HeaderListChangedAction action, Header baseUri = null; break; case HeaderId.ContentId: - if (MailboxAddress.TryParse (Headers.Options, header.RawValue, ref index, header.RawValue.Length, false, out mailbox)) - contentId = mailbox.Address; + if (ParseUtils.TryParseMsgId (header.RawValue, ref index, header.RawValue.Length, false, false, out string msgid)) + contentId = msgid; else contentId = null; break; @@ -1132,7 +1127,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// specified .
/// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. ///
@@ -1176,7 +1171,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// specified . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. ///
@@ -1280,7 +1275,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// default . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. ///
@@ -1313,7 +1308,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// default . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. ///
@@ -1392,7 +1387,6 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) return LoadAsync (ParserOptions.Default, stream, false, cancellationToken); } -#if !PORTABLE /// /// Load a from the specified file. /// @@ -1411,8 +1405,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1440,7 +1433,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Open, FileAccess.Read)) + using (var stream = File.OpenRead (fileName)) return Load (options, stream, cancellationToken); } @@ -1462,8 +1455,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1491,7 +1483,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Open, FileAccess.Read)) + using (var stream = File.OpenRead (fileName)) return await LoadAsync (options, stream, cancellationToken).ConfigureAwait (false); } @@ -1510,8 +1502,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1551,8 +1542,7 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -1576,7 +1566,6 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) { return LoadAsync (ParserOptions.Default, fileName, cancellationToken); } -#endif // !PORTABLE /// /// Load a from the specified content stream. @@ -1689,6 +1678,9 @@ void HeadersChanged (object sender, HeaderListChangedEventArgs e) /// This method is mostly meant for use with APIs such as /// where the headers are parsed separately from the content. /// + /// + /// + /// /// The parsed MIME entity. /// The Content-Type of the stream. /// The content stream. diff --git a/MimeKit/MimeEntityBeginEventArgs.cs b/MimeKit/MimeEntityBeginEventArgs.cs new file mode 100644 index 0000000000..f2ef4ee5b6 --- /dev/null +++ b/MimeKit/MimeEntityBeginEventArgs.cs @@ -0,0 +1,117 @@ +// +// MimeEntityBeginEventArgs.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit { + /// + /// Event args emitted by the when it begins parsing a . + /// + /// + /// Event args emitted by the when it begins parsing a . + /// + public class MimeEntityBeginEventArgs : EventArgs + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The entity that is being parsed. + /// + /// is null. + /// + public MimeEntityBeginEventArgs (MimeEntity entity) + { + if (entity == null) + throw new ArgumentNullException (nameof (entity)); + + Entity = entity; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The entity that is being parsed. + /// The parent multipart. + /// + /// is null. + /// -or- + /// is null. + /// + public MimeEntityBeginEventArgs (MimeEntity entity, Multipart parent) + { + if (entity == null) + throw new ArgumentNullException (nameof (entity)); + + if (parent == null) + throw new ArgumentNullException (nameof (parent)); + + Entity = entity; + Parent = parent; + } + + /// + /// Get the MIME entity. + /// + /// + /// Gets the MIME entity. + /// + /// The MIME entity. + public MimeEntity Entity { get; } + + /// + /// Get the parent if this entity is a child. + /// + /// + /// Gets the parent if this entity is a child. + /// + /// The parent . + public Multipart Parent { get; } + + /// + /// Get or set the stream offset that marks the beginning of the entity. + /// + /// + /// Gets or sets the stream offset that marks the beginning of the entity. + /// + /// The stream offset. + public long BeginOffset { get; set; } + + /// + /// Get or set the line number of the beginning of the entity. + /// + /// + /// Gets or sets the line number of the beginning of the entity. + /// + /// The line number. + internal int LineNumber { get; set; } + } +} diff --git a/MimeKit/MimeEntityConstructorArgs.cs b/MimeKit/MimeEntityConstructorArgs.cs index bcce3d6818..e2896bca85 100644 --- a/MimeKit/MimeEntityConstructorArgs.cs +++ b/MimeKit/MimeEntityConstructorArgs.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/MimeEntityEndEventArgs.cs b/MimeKit/MimeEntityEndEventArgs.cs new file mode 100644 index 0000000000..b0d9810d6b --- /dev/null +++ b/MimeKit/MimeEntityEndEventArgs.cs @@ -0,0 +1,98 @@ +// +// MimeEntityEndEventArgs.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit { + /// + /// Event args emitted by the when a is parsed. + /// + /// + /// Event args emitted by the when a is parsed. + /// + public class MimeEntityEndEventArgs : MimeEntityBeginEventArgs + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The entity that was parsed. + /// + /// is null. + /// + public MimeEntityEndEventArgs (MimeEntity entity) : base (entity) + { + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The entity that was parsed. + /// The parent multipart. + /// + /// is null. + /// -or- + /// is null. + /// + public MimeEntityEndEventArgs (MimeEntity entity, Multipart parent) : base (entity, parent) + { + } + + /// + /// Get or set the stream offset that marks the end of the entity's headers. + /// + /// + /// Gets or sets the stream offset that marks the end of the entity's headers. + /// + /// The stream offset. + public long HeadersEndOffset { get; set; } + + /// + /// Get or set the stream offset that marks the end of the entity. + /// + /// + /// Gets or sets the stream offset that marks the end of the entity. + /// + /// The stream offset. + public long EndOffset { get; set; } + + /// + /// Get or set the content length of the entity as measured in lines. + /// + /// + /// Get or set the content length of the entity as measured in lines. + /// The line count reported by this property is the number of lines in its + /// content transfer encoding and not the resulting line count after any decoding. + /// + /// The length of the content in lines. + public int Lines { get; set; } + } +} diff --git a/MimeKit/MimeFormat.cs b/MimeKit/MimeFormat.cs index 1e9454dbb1..30a169226a 100644 --- a/MimeKit/MimeFormat.cs +++ b/MimeKit/MimeFormat.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/MimeIterator.cs b/MimeKit/MimeIterator.cs index b4ce649cfe..1503d43c99 100644 --- a/MimeKit/MimeIterator.cs +++ b/MimeKit/MimeIterator.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,9 @@ namespace MimeKit { /// /// Walks the MIME tree structure of a in depth-first order. /// + /// + /// + /// public class MimeIterator : IEnumerator { class MimeNode @@ -57,11 +60,14 @@ public MimeNode (MimeEntity entity, bool indexed) int index = -1; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new for the specified message. /// + /// + /// + /// /// The message. /// /// is null. @@ -76,11 +82,11 @@ public MimeIterator (MimeMessage message) /// /// Releases unmanaged resources and performs other cleanup operations before - /// the is reclaimed by garbage collection. + /// the is reclaimed by garbage collection. /// /// /// Releases unmanaged resources and performs other cleanup operations before - /// the is reclaimed by garbage collection. + /// the is reclaimed by garbage collection. /// ~MimeIterator () { @@ -112,6 +118,9 @@ public MimeMessage Message { /// will be null; otherwise the parent will be either be a /// or a . /// + /// + /// + /// /// The parent entity. /// /// Either has not been called or @@ -137,6 +146,9 @@ public MimeEntity Parent { /// also throws a if the last call to /// returned false, which indicates the end of the message. /// + /// + /// + /// /// The current entity. /// /// Either has not been called or @@ -265,6 +277,9 @@ bool Pop () /// When the iterator is at this position, subsequent calls to MoveNext also return /// false until is called. /// + /// + /// + /// /// true if the iterator was successfully advanced to the next entity; otherwise, false. public bool MoveNext () { @@ -374,7 +389,7 @@ public bool MoveTo (string pathSpecifier) } } - if (i == path.Count && indexes[i] < index) + if (!moveFirst && indexes.Length < path.Count) Reset (); if (moveFirst && !MoveNext ()) @@ -411,11 +426,11 @@ public void Reset () } /// - /// Releases the unmanaged resources used by the and + /// Releases the unmanaged resources used by the and /// optionally releases the managed resources. /// /// - /// Releases the unmanaged resources used by the and + /// Releases the unmanaged resources used by the and /// optionally releases the managed resources. /// /// true to release both managed and unmanaged resources; @@ -425,12 +440,12 @@ protected virtual void Dispose (bool disposing) } /// - /// Releases all resources used by the object. + /// Releases all resources used by the object. /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After - /// calling , you must release all references to the so - /// the garbage collector can reclaim the memory that the was occupying. + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After + /// calling , you must release all references to the so + /// the garbage collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); diff --git a/MimeKit/MimeKit.Android.csproj b/MimeKit/MimeKit.Android.csproj deleted file mode 100644 index f9f43a3956..0000000000 --- a/MimeKit/MimeKit.Android.csproj +++ /dev/null @@ -1,275 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {004B4019-62B7-4A15-AF2C-C20968845C46} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - Resources\Resource.designer.cs - Resource - Resources - Assets - false - MimeKit - v4.0.3 - - - - - true - full - false - bin\Debug\MonoAndroid - obj\Debug\MonoAndroid - DEBUG;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__MOBILE__;__ANDROID__ - true - prompt - 4 - - - true - bin\Release\MonoAndroid - obj\Release\MonoAndroid - bin\Release\MonoAndroid\MimeKit.xml - SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__MOBILE__;__ANDROID__ - true - prompt - 4 - - - true - - - mimekit.snk - - - - - - - - - - - - - {A0D302CB-8866-4AB1-98B9-F0772EABF5DF} - BouncyCastle.Android - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.Android.project.json b/MimeKit/MimeKit.Android.project.json deleted file mode 100644 index 22430247f9..0000000000 --- a/MimeKit/MimeKit.Android.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "MonoAndroid,Version=v4.0.3": {} - }, - "runtimes": { - "win-anycpu": {} - } -} diff --git a/MimeKit/MimeKit.Mac.csproj b/MimeKit/MimeKit.Mac.csproj deleted file mode 100644 index 527863b331..0000000000 --- a/MimeKit/MimeKit.Mac.csproj +++ /dev/null @@ -1,253 +0,0 @@ - - - - Debug - AnyCPU - {2CE98315-A444-44D3-8BCE-32389EDDA149} - {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKit - v2.0 - Xamarin.Mac - Resources - - - true - full - false - bin\Debug\Xamarin.Mac - obj\Debug\Xamarin.Mac - DEBUG;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__MAC__ - true - prompt - 4 - - - pdbonly - true - bin\Release\Xamarin.Mac - obj\Release\Xamarin.Mac - bin\Release\Xamarin.Mac\MimeKit.xml - SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__MAC__ - true - true - prompt - 4 - - - true - - - mimekit.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.Mac.project.json b/MimeKit/MimeKit.Mac.project.json deleted file mode 100644 index 49847c4d05..0000000000 --- a/MimeKit/MimeKit.Mac.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "Xamarin.Mac,Version=v2.0": {} - }, - "dependencies": { - "Portable.BouncyCastle": "1.8.1.2" - } -} \ No newline at end of file diff --git a/MimeKit/MimeKit.Net45.csproj b/MimeKit/MimeKit.Net45.csproj deleted file mode 100644 index dcdb130cce..0000000000 --- a/MimeKit/MimeKit.Net45.csproj +++ /dev/null @@ -1,278 +0,0 @@ - - - - Debug - AnyCPU - AnyCPU - {D5F54A4F-D84B-430F-9271-F7861E285B3E} - .NETFramework - v4.5 - Library - Properties - MimeKit - MimeKit - 512 - 8.0.30703 - 2.0 - - - True - full - False - bin\Debug\net45 - obj\Debug\net45 - DEBUG;TRACE;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM; - prompt - 4 - True - - - pdbonly - True - bin\Release\net45 - obj\Release\net45 - TRACE;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM; - prompt - 4 - true - bin\Release\net45\MimeKit.xml - - - true - - - mimekit.snk - - - - - - - - - - - - ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.Net45.project.json b/MimeKit/MimeKit.Net45.project.json deleted file mode 100644 index 8f6b4a8248..0000000000 --- a/MimeKit/MimeKit.Net45.project.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "frameworks": { - ".NETFramework,Version=v4.5": {} - }, - "runtimes": { - "win-anycpu": {}, - "win": {} - }, - "dependencies": { - "BouncyCastle": "1.8.1" - } -} diff --git a/MimeKit/MimeKit.Portable.csproj b/MimeKit/MimeKit.Portable.csproj deleted file mode 100644 index 544f7ee94a..0000000000 --- a/MimeKit/MimeKit.Portable.csproj +++ /dev/null @@ -1,263 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {BE542CE1-F773-467E-8DED-D02B89C5040A} - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKit - Profile7 - v4.5 - 10.0 - - - true - full - false - bin\Debug\portable - obj\Debug\portable - DEBUG;TRACE;PORTABLE;ENABLE_CRYPTO;USE_HTTP_CLIENT - prompt - 4 - false - true - - - true - bin\Release\portable - obj\Release\portable - bin\Release\portable\MimeKit.xml - TRACE;PORTABLE;ENABLE_CRYPTO;USE_HTTP_CLIENT - prompt - 4 - false - true - - - true - - - mimekit.snk - - - - {EEE48C75-11BE-4B50-B759-F85B5052D473} - Portable.Text.Encoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.Portable.project.json b/MimeKit/MimeKit.Portable.project.json deleted file mode 100644 index b5d4cdf842..0000000000 --- a/MimeKit/MimeKit.Portable.project.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "frameworks": { - ".NETPortable,Version=v4.5,Profile=Profile7": {} - }, - "runtimes": { - "win-anycpu": {} - }, - "dependencies": { - "Portable.BouncyCastle": "1.8.1.3" - } -} \ No newline at end of file diff --git a/MimeKit/MimeKit.TvOS.csproj b/MimeKit/MimeKit.TvOS.csproj deleted file mode 100644 index 382e52aa9f..0000000000 --- a/MimeKit/MimeKit.TvOS.csproj +++ /dev/null @@ -1,249 +0,0 @@ - - - - Debug - AnyCPU - {ABEEAB21-341F-43E0-8851-0EDB3CE10AD4} - {06FA79CB-D6CD-4721-BB4B-1BD202089C55};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKit - Resources - - - true - full - false - bin\Debug\Xamarin.TvOS - obj\Debug\Xamarin.TvOS - DEBUG;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__TVOS__ - true - prompt - 4 - - - pdbonly - true - bin\Release\Xamarin.TvOS - obj\Release\Xamarin.TvOS - bin\Release\Xamarin.TvOS\MimeKit.xml - SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__TVOS__ - true - true - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.TvOS.project.json b/MimeKit/MimeKit.TvOS.project.json deleted file mode 100644 index 4a948eec57..0000000000 --- a/MimeKit/MimeKit.TvOS.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "Xamarin.TVOS,Version=v1.0": {} - }, - "dependencies": { - "Portable.BouncyCastle": "1.8.1.2" - } -} diff --git a/MimeKit/MimeKit.WatchOS.csproj b/MimeKit/MimeKit.WatchOS.csproj deleted file mode 100644 index 80ee16910d..0000000000 --- a/MimeKit/MimeKit.WatchOS.csproj +++ /dev/null @@ -1,252 +0,0 @@ - - - - Debug - AnyCPU - {9AD6AE8B-D83D-4511-AA08-2BA8904D2E7C} - {FC940695-DFE0-4552-9F25-99AF4A5619A1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKit - Resources - - - true - full - false - bin\Debug\Xamarin.WatchOS - DEBUG;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__WATCHOS__ - prompt - 4 - NSUrlSessionHandler - - - pdbonly - true - bin\Release\Xamarin.WatchOS - obj\Release\Xamarin.WatchOS - bin\Release\Xamarin.WatchOS\MimeKit.xml - SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__WATCHOS_ - true - true - prompt - 4 - NSUrlSessionHandler - - - true - - - mimekit.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.WatchOS.project.json b/MimeKit/MimeKit.WatchOS.project.json deleted file mode 100644 index 82a2acdacf..0000000000 --- a/MimeKit/MimeKit.WatchOS.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "Xamarin.WatchOS,Version=v1.0": {} - }, - "dependencies": { - "Portable.BouncyCastle": "1.8.1.2" - } -} diff --git a/MimeKit/MimeKit.WindowsUniversal81.csproj b/MimeKit/MimeKit.WindowsUniversal81.csproj deleted file mode 100644 index e140d40f74..0000000000 --- a/MimeKit/MimeKit.WindowsUniversal81.csproj +++ /dev/null @@ -1,271 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - 8.0.30703 - 2.0 - {D9906B8C-7BBD-4CCE-AC7C-E9BCA020D20C} - Library - Properties - MimeKit - MimeKit - v4.5 - Profile111 - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - true - full - false - bin\Debug\wpa81 - obj\Debug\wpa81 - DEBUG;TRACE;PORTABLE;ENABLE_CRYPTO;USE_HTTP_CLIENT - prompt - 4 - false - true - - - - true - bin\Release\wpa81 - obj\Release\wpa81 - bin\Release\wpa81\MimeKit.xml - TRACE;PORTABLE;ENABLE_CRYPTO;USE_HTTP_CLIENT - prompt - 4 - false - true - - - true - - - mimekit.snk - - - - - {B76A64F9-B00E-4243-AE89-5D024CA3B436} - Portable.Text.Encoding.WindowsUniversal81 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.WindowsUniversal81.project.json b/MimeKit/MimeKit.WindowsUniversal81.project.json deleted file mode 100644 index 68db0c76dc..0000000000 --- a/MimeKit/MimeKit.WindowsUniversal81.project.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "frameworks": { - ".NETPortable,Version=v4.5,Profile=Profile111": {} - }, - "runtimes": { - "win-anycpu": {} - }, - "dependencies": { - "Portable.BouncyCastle": "1.8.1.3" - } -} \ No newline at end of file diff --git a/MimeKit/MimeKit.NetStandard.csproj b/MimeKit/MimeKit.csproj similarity index 74% rename from MimeKit/MimeKit.NetStandard.csproj rename to MimeKit/MimeKit.csproj index 36abcb17d6..0c34d35390 100644 --- a/MimeKit/MimeKit.NetStandard.csproj +++ b/MimeKit/MimeKit.csproj @@ -3,14 +3,14 @@ An Open Source library for creating and parsing MIME, S/MIME, PGP messages on desktop and mobile platforms. MimeKit - 2.0.1.1 + 2.10.1.1 Jeffrey Stedfast - netstandard1.3;netstandard1.6;netstandard2.0 + netstandard2.0;netstandard2.1;net45;net46;net47;net48 true false MimeKit MimeKit - mime;encryption;dkim;security;smime;s/mime;openpgp;pgp;mbox;email;parser;tnef;net45;netstandard;netstandard1.3;netstandard1.6;netstandard2.0;xamarin;android;ios;monodroid;monoandroid;win8;wp81 + mime;encryption;dkim;security;smime;s/mime;openpgp;pgp;mbox;email;parser;tnef;net45;net46;net47;net48;netstandard;netstandard1.3;netstandard1.6;netstandard2.0;netstandard2.1 https://github.com/jstedfast/MimeKit https://github.com/jstedfast/MimeKit/blob/master/License.md false @@ -23,23 +23,55 @@ false false MimeKit - $(DefineConstants);ENABLE_CRYPTO;USE_HTTP_CLIENT;NETSTANDARD + $(DefineConstants);ENABLE_CRYPTO true mimekit.snk true - true + true - - - + + full + + + + portable + + + + $(DefineConstants);ENABLE_SNM + + + $(DefineConstants);ENABLE_SNM;SERIALIZABLE + + + + - - - + - - + + + + + + + + + + + + + + + + + + + + + + @@ -47,6 +79,10 @@ + + + + @@ -62,22 +98,28 @@ + + + + + - + + @@ -86,6 +128,10 @@ + + + + @@ -93,8 +139,13 @@ + + + + + @@ -134,6 +185,7 @@ + @@ -148,6 +200,7 @@ + @@ -157,8 +210,10 @@ + + @@ -182,6 +237,7 @@ + @@ -220,10 +276,14 @@ + + + + @@ -239,6 +299,7 @@ + diff --git a/MimeKit/MimeKit.iOS.csproj b/MimeKit/MimeKit.iOS.csproj deleted file mode 100644 index 754bab7a33..0000000000 --- a/MimeKit/MimeKit.iOS.csproj +++ /dev/null @@ -1,271 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {4C1288AD-12C8-4BF7-AED7-6C4DC539C856} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKit - Resources - Xamarin.iOS - - - true - full - false - bin\Debug\Xamarin.iOS - obj\Debug\Xamarin.iOS - DEBUG;SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__IOS__ - true - prompt - 4 - - - pdbonly - true - bin\Release\Xamarin.iOS - obj\Release\Xamarin.iOS - bin\Release\Xamarin.iOS\MimeKit.xml - SERIALIZABLE;ENABLE_CRYPTO;ENABLE_SNM;__UNIFIED__;__MOBILE__;__IOS__ - true - true - prompt - 4 - - - true - - - mimekit.snk - - - - - - - - - - - - - {0249241C-205E-4AC0-828B-90F822359B9E} - BouncyCastle.iOS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKit.iOS.project.json b/MimeKit/MimeKit.iOS.project.json deleted file mode 100644 index 4a7c8a5100..0000000000 --- a/MimeKit/MimeKit.iOS.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "Xamarin.iOS,Version=v1.0": {} - }, - "runtimes": { - "win-anycpu": {} - } -} \ No newline at end of file diff --git a/MimeKit/MimeKitLite.Android.csproj b/MimeKit/MimeKitLite.Android.csproj deleted file mode 100644 index 1529b3ed5e..0000000000 --- a/MimeKit/MimeKitLite.Android.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - Debug - AnyCPU - 10.0.0 - 2.0 - {D95A2734-2A81-4C75-985E-A33B15CC62BC} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - Resources\Resource.designer.cs - Resource - Resources - Assets - False - MimeKitLite - v4.0.3 - - - true - full - false - bin\Debug\MonoAndroid - obj\Debug\MonoAndroid - DEBUG;SERIALIZABLE;ENABLE_SNM;__MOBILE__;__ANDROID__ - prompt - 4 - None - false - true - - - true - bin\Release\MonoAndroid - obj\Release\MonoAndroid - prompt - 4 - false - false - true - SERIALIZABLE;ENABLE_SNM;__MOBILE__;__ANDROID__ - bin\Release\MonoAndroid\MimeKitLite.xml - - - true - - - mimekit.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKitLite.Android.project.json b/MimeKit/MimeKitLite.Android.project.json deleted file mode 100644 index 22430247f9..0000000000 --- a/MimeKit/MimeKitLite.Android.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "MonoAndroid,Version=v4.0.3": {} - }, - "runtimes": { - "win-anycpu": {} - } -} diff --git a/MimeKit/MimeKitLite.Net45.csproj b/MimeKit/MimeKitLite.Net45.csproj deleted file mode 100644 index 0726764d97..0000000000 --- a/MimeKit/MimeKitLite.Net45.csproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - Debug - AnyCPU - 10.0.0 - 2.0 - {B4DA3323-F83C-4731-BE30-B1DA19B8C3E7} - v4.5 - Library - Properties - MimeKit - MimeKitLite - 512 - - - True - full - False - bin\Debug\net45 - obj\Debug\net45 - DEBUG;TRACE;SERIALIZABLE;ENABLE_SNM - prompt - 4 - True - - - True - bin\Release\net45 - obj\Release\net45 - TRACE;SERIALIZABLE;ENABLE_SNM - prompt - 4 - true - bin\Release\net45\MimeKitLite.xml - - - true - - - mimekit.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKitLite.Net45.project.json b/MimeKit/MimeKitLite.Net45.project.json deleted file mode 100644 index 7b2e820fd1..0000000000 --- a/MimeKit/MimeKitLite.Net45.project.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "frameworks": { - "net45": {} - }, - "runtimes": { - "win-anycpu": {}, - "win": {} - } -} diff --git a/MimeKit/MimeKitLite.Portable.csproj b/MimeKit/MimeKitLite.Portable.csproj deleted file mode 100644 index 4d213bc78f..0000000000 --- a/MimeKit/MimeKitLite.Portable.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - Debug - AnyCPU - 10.0.0 - 2.0 - {25C2DD3E-ED14-494F-9BD4-75536911C1BD} - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - MimeKitLite - Profile7 - v4.5 - 10.0 - - - true - full - false - bin\Debug\portable - obj\Debug\portable - DEBUG;TRACE;PORTABLE - prompt - 4 - false - true - - - pdbonly - true - bin\Release\portable - obj\Release\portable - bin\Release\portable\MimeKitLite.xml - TRACE;PORTABLE - prompt - 4 - false - true - - - true - - - mimekit.snk - - - - {EEE48C75-11BE-4B50-B759-F85B5052D473} - Portable.Text.Encoding - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKitLite.Portable.project.json b/MimeKit/MimeKitLite.Portable.project.json deleted file mode 100644 index dbfd9834e6..0000000000 --- a/MimeKit/MimeKitLite.Portable.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - ".NETPortable,Version=v4.5,Profile=Profile7": {} - }, - "runtimes": { - "win-anycpu": {} - }, -} diff --git a/MimeKit/MimeKitLite.WindowsUniversal81.csproj b/MimeKit/MimeKitLite.WindowsUniversal81.csproj deleted file mode 100644 index 88c0fab0d1..0000000000 --- a/MimeKit/MimeKitLite.WindowsUniversal81.csproj +++ /dev/null @@ -1,217 +0,0 @@ - - - - - 11.0 - Debug - AnyCPU - 10.0.0 - 2.0 - {5EB9F403-45B4-4F3A-B64E-0ECC94D14167} - Library - Properties - MimeKit - MimeKitLite - v4.5 - Profile111 - en-US - 512 - {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - true - full - false - bin\Debug\wpa81 - obj\Debug\wpa81 - DEBUG;TRACE;PORTABLE - prompt - 4 - false - true - - - pdbonly - true - bin\Release\wpa81 - obj\Release\wpa81 - bin\Release\wpa81\MimeKitLite.xml - TRACE;PORTABLE - prompt - 4 - false - true - - - true - - - mimekit.snk - - - - - {B76A64F9-B00E-4243-AE89-5D024CA3B436} - Portable.Text.Encoding.WindowsUniversal81 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKitLite.WindowsUniversal81.project.json b/MimeKit/MimeKitLite.WindowsUniversal81.project.json deleted file mode 100644 index e01dcfbe78..0000000000 --- a/MimeKit/MimeKitLite.WindowsUniversal81.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - ".NETPortable,Version=v4.5,Profile=Profile111": {} - }, - "runtimes": { - "win-anycpu": {} - }, -} diff --git a/MimeKit/MimeKitLite.NetStandard.csproj b/MimeKit/MimeKitLite.csproj similarity index 84% rename from MimeKit/MimeKitLite.NetStandard.csproj rename to MimeKit/MimeKitLite.csproj index 903b3362ed..a812b126c2 100644 --- a/MimeKit/MimeKitLite.NetStandard.csproj +++ b/MimeKit/MimeKitLite.csproj @@ -1,16 +1,16 @@ - + An Open Source library for creating and parsing MIME, S/MIME, PGP messages on desktop and mobile platforms. MimeKit Lite - 2.0.1.1 + 2.10.1.1 Jeffrey Stedfast - netstandard1.3;netstandard1.6;netstandard2.0 + netstandard2.0;net45;net46;net47;net48 true false MimeKitLite MimeKitLite - mime;mbox;mail;email;parser;tnef;net45;netstandard;netstandard1.3;netstandard1.6;netstandard2.0;xamarin;android;ios;monodroid;monoandroid;win8;wp81 + mime;mbox;mail;email;parser;tnef;net45;netstandard;netstandard2.0 https://github.com/jstedfast/MimeKit https://github.com/jstedfast/MimeKit/blob/master/License.md false @@ -23,24 +23,38 @@ false false MimeKit - $(DefineConstants);NETSTANDARD true mimekit.snk true - true + true - - - - - - - - + + full + + + + portable + + + + $(DefineConstants);ENABLE_SNM + + + $(DefineConstants);ENABLE_SNM;SERIALIZABLE + + + + + + + + + + @@ -74,6 +88,7 @@ + @@ -88,6 +103,7 @@ + @@ -97,8 +113,10 @@ + + @@ -122,6 +140,7 @@ + @@ -160,10 +179,14 @@ + + + + @@ -179,6 +202,7 @@ + diff --git a/MimeKit/MimeKitLite.iOS.csproj b/MimeKit/MimeKitLite.iOS.csproj deleted file mode 100644 index b3e3386ae0..0000000000 --- a/MimeKit/MimeKitLite.iOS.csproj +++ /dev/null @@ -1,211 +0,0 @@ - - - - Debug - AnyCPU - 10.0.0 - 2.0 - {5F211544-940D-46C9-98EB-4FD8F62506AD} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - MimeKit - Resources - MimeKitLite - Xamarin.iOS - - - true - full - false - bin\Debug\Xamarin.iOS - obj\Debug\Xamarin.iOS - DEBUG;SERIALIZABLE;ENABLE_SNM;__MOBILE__;__IOS__ - prompt - 4 - false - true - - - true - bin\Release\Xamarin.iOS - obj\Release\Xamarin.iOS - prompt - 4 - false - true - SERIALIZABLE;ENABLE_SNM;__MOBILE__;__IOS__ - True - bin\Release\Xamarin.iOS\MimeKitLite.xml - - - true - - - mimekit.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HtmlEntityDecoder.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MimeKit/MimeKitLite.iOS.project.json b/MimeKit/MimeKitLite.iOS.project.json deleted file mode 100644 index 4a7c8a5100..0000000000 --- a/MimeKit/MimeKitLite.iOS.project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "frameworks": { - "Xamarin.iOS,Version=v1.0": {} - }, - "runtimes": { - "win-anycpu": {} - } -} \ No newline at end of file diff --git a/MimeKit/MimeMessage.cs b/MimeKit/MimeMessage.cs index 7922418d33..419f8b561c 100644 --- a/MimeKit/MimeMessage.cs +++ b/MimeKit/MimeMessage.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,13 +29,10 @@ using System.Text; using System.Linq; using System.Threading; +using System.Globalization; using System.Threading.Tasks; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - #if ENABLE_SNM using System.Net.Mail; #endif @@ -45,6 +42,7 @@ using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Crypto.Parameters; using MimeKit.Cryptography; #endif @@ -65,12 +63,12 @@ namespace MimeKit { /// public class MimeMessage { - static readonly string[] StandardAddressHeaders = { - "Resent-From", "Resent-Reply-To", "Resent-To", "Resent-Cc", "Resent-Bcc", - "From", "Reply-To", "To", "Cc", "Bcc" + static readonly HeaderId[] StandardAddressHeaders = { + HeaderId.ResentFrom, HeaderId.ResentReplyTo, HeaderId.ResentTo, HeaderId.ResentCc, HeaderId.ResentBcc, + HeaderId.From, HeaderId.ReplyTo, HeaderId.To, HeaderId.Cc, HeaderId.Bcc }; - readonly Dictionary addresses; + readonly Dictionary addresses; MessageImportance importance = MessageImportance.Normal; XMessagePriority xpriority = XMessagePriority.Normal; MessagePriority priority = MessagePriority.Normal; @@ -88,16 +86,16 @@ public class MimeMessage // Note: this .ctor is used only by the MimeParser and MimeMessage.CreateFromMailMessage() internal MimeMessage (ParserOptions options, IEnumerable
headers, RfcComplianceMode mode) { - addresses = new Dictionary (MimeUtils.OrdinalIgnoreCase); + addresses = new Dictionary (); Headers = new HeaderList (options); compliance = mode; // initialize our address lists - foreach (var name in StandardAddressHeaders) { + foreach (var id in StandardAddressHeaders) { var list = new InternetAddressList (); list.Changed += InternetAddressListChanged; - addresses.Add (name, list); + addresses.Add (id, list); } references = new MessageIdList (); @@ -117,16 +115,16 @@ internal MimeMessage (ParserOptions options, IEnumerable
headers, RfcCom internal MimeMessage (ParserOptions options) { - addresses = new Dictionary (MimeUtils.OrdinalIgnoreCase); + addresses = new Dictionary (); Headers = new HeaderList (options); compliance = RfcComplianceMode.Strict; // initialize our address lists - foreach (var name in StandardAddressHeaders) { + foreach (var id in StandardAddressHeaders) { var list = new InternetAddressList (); list.Changed += InternetAddressListChanged; - addresses.Add (name, list); + addresses.Add (id, list); } references = new MessageIdList (); @@ -137,7 +135,7 @@ internal MimeMessage (ParserOptions options) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -147,7 +145,7 @@ internal MimeMessage (ParserOptions options) /// is null. /// /// - /// contains more than one . + /// contains more than one . /// -or- /// contains one or more arguments of an unknown type. /// @@ -180,7 +178,7 @@ public MimeMessage (params object[] args) : this (ParserOptions.Default.Clone () Headers.Add (h); } - continue; + continue; } var entity = obj as MimeEntity; @@ -212,7 +210,7 @@ public MimeMessage (params object[] args) : this (ParserOptions.Default.Clone () } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new MIME message, specifying details at creation time. @@ -230,7 +228,7 @@ public MimeMessage (IEnumerable from, IEnumerable - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. ///
/// /// Creates a new MIME message. @@ -244,7 +242,7 @@ public MimeMessage () : this (ParserOptions.Default.Clone ()) } /// - /// Gets or sets the mbox marker. + /// Get or set the mbox marker. /// /// /// Set by the when parsing attached message/rfc822 parts @@ -256,17 +254,17 @@ internal byte[] MboxMarker { } /// - /// Gets the list of headers. + /// Get the list of headers. /// /// /// Represents the list of headers for a message. Typically, the headers of /// a message will contain transmission headers such as From and To along /// with metadata headers such as Subject and Date, but may include just /// about anything. - /// To access any MIME headers other than + /// To access any MIME headers other than /// , you will need to access the /// property of the . - /// + /// /// /// The list of headers. public HeaderList Headers { @@ -385,7 +383,7 @@ public XMessagePriority XPriority { } /// - /// Gets or sets the address in the Sender header. + /// Get or set the address in the Sender header. /// /// /// The sender may differ from the addresses in if @@ -408,7 +406,7 @@ public MailboxAddress Sender { var builder = new StringBuilder (" "); int len = "Sender: ".Length; - value.Encode (options, builder, ref len); + value.Encode (options, builder, true, ref len); builder.Append (options.NewLine); var raw = Encoding.UTF8.GetBytes (builder.ToString ()); @@ -420,7 +418,7 @@ public MailboxAddress Sender { } /// - /// Gets or sets the address in the Resent-Sender header. + /// Get or set the address in the Resent-Sender header. /// /// /// The resent sender may differ from the addresses in if @@ -443,7 +441,7 @@ public MailboxAddress ResentSender { var builder = new StringBuilder (" "); int len = "Resent-Sender: ".Length; - value.Encode (options, builder, ref len); + value.Encode (options, builder, true, ref len); builder.Append (options.NewLine); var raw = Encoding.UTF8.GetBytes (builder.ToString ()); @@ -455,7 +453,7 @@ public MailboxAddress ResentSender { } /// - /// Gets the list of addresses in the From header. + /// Get the list of addresses in the From header. /// /// /// The "From" header specifies the author(s) of the message. @@ -466,11 +464,11 @@ public MailboxAddress ResentSender { /// /// The list of addresses in the From header. public InternetAddressList From { - get { return addresses["From"]; } + get { return addresses[HeaderId.From]; } } /// - /// Gets the list of addresses in the Resent-From header. + /// Get the list of addresses in the Resent-From header. /// /// /// The "Resent-From" header specifies the author(s) of the messagebeing @@ -482,11 +480,11 @@ public InternetAddressList From { /// /// The list of addresses in the Resent-From header. public InternetAddressList ResentFrom { - get { return addresses["Resent-From"]; } + get { return addresses[HeaderId.ResentFrom]; } } /// - /// Gets the list of addresses in the Reply-To header. + /// Get the list of addresses in the Reply-To header. /// /// /// When the list of addresses in the Reply-To header is not empty, @@ -498,11 +496,11 @@ public InternetAddressList ResentFrom { /// /// The list of addresses in the Reply-To header. public InternetAddressList ReplyTo { - get { return addresses["Reply-To"]; } + get { return addresses[HeaderId.ReplyTo]; } } /// - /// Gets the list of addresses in the Resent-Reply-To header. + /// Get the list of addresses in the Resent-Reply-To header. /// /// /// When the list of addresses in the Resent-Reply-To header is not empty, @@ -514,11 +512,11 @@ public InternetAddressList ReplyTo { /// /// The list of addresses in the Resent-Reply-To header. public InternetAddressList ResentReplyTo { - get { return addresses["Resent-Reply-To"]; } + get { return addresses[HeaderId.ResentReplyTo]; } } /// - /// Gets the list of addresses in the To header. + /// Get the list of addresses in the To header. /// /// /// The addresses in the To header are the primary recipients of @@ -526,11 +524,11 @@ public InternetAddressList ResentReplyTo { /// /// The list of addresses in the To header. public InternetAddressList To { - get { return addresses["To"]; } + get { return addresses[HeaderId.To]; } } /// - /// Gets the list of addresses in the Resent-To header. + /// Get the list of addresses in the Resent-To header. /// /// /// The addresses in the Resent-To header are the primary recipients of @@ -538,11 +536,11 @@ public InternetAddressList To { /// /// The list of addresses in the Resent-To header. public InternetAddressList ResentTo { - get { return addresses["Resent-To"]; } + get { return addresses[HeaderId.ResentTo]; } } /// - /// Gets the list of addresses in the Cc header. + /// Get the list of addresses in the Cc header. /// /// /// The addresses in the Cc header are secondary recipients of the message @@ -551,11 +549,11 @@ public InternetAddressList ResentTo { /// /// The list of addresses in the Cc header. public InternetAddressList Cc { - get { return addresses["Cc"]; } + get { return addresses[HeaderId.Cc]; } } /// - /// Gets the list of addresses in the Resent-Cc header. + /// Get the list of addresses in the Resent-Cc header. /// /// /// The addresses in the Resent-Cc header are secondary recipients of the message @@ -564,11 +562,11 @@ public InternetAddressList Cc { /// /// The list of addresses in the Resent-Cc header. public InternetAddressList ResentCc { - get { return addresses["Resent-Cc"]; } + get { return addresses[HeaderId.ResentCc]; } } /// - /// Gets the list of addresses in the Bcc header. + /// Get the list of addresses in the Bcc header. /// /// /// Recipients in the Blind-Carpbon-Copy list will not be visible to @@ -576,11 +574,11 @@ public InternetAddressList ResentCc { /// /// The list of addresses in the Bcc header. public InternetAddressList Bcc { - get { return addresses["Bcc"]; } + get { return addresses[HeaderId.Bcc]; } } /// - /// Gets the list of addresses in the Resent-Bcc header. + /// Get the list of addresses in the Resent-Bcc header. /// /// /// Recipients in the Resent-Bcc list will not be visible to @@ -588,11 +586,11 @@ public InternetAddressList Bcc { /// /// The list of addresses in the Resent-Bcc header. public InternetAddressList ResentBcc { - get { return addresses["Resent-Bcc"]; } + get { return addresses[HeaderId.ResentBcc]; } } /// - /// Gets or sets the subject of the message. + /// Get or set the subject of the message. /// /// /// The Subject is typically a short string denoting the topic of the message. @@ -613,7 +611,7 @@ public string Subject { } /// - /// Gets or sets the date of the message. + /// Get or set the date of the message. /// /// /// If the date is not explicitly set before the message is written to a stream, @@ -632,7 +630,7 @@ public DateTimeOffset Date { } /// - /// Gets or sets the Resent-Date of the message. + /// Get or set the Resent-Date of the message. /// /// /// Gets or sets the Resent-Date of the message. @@ -650,7 +648,7 @@ public DateTimeOffset ResentDate { } /// - /// Gets or sets the list of references to other messages. + /// Get the list of references to other messages. /// /// /// The References header contains a chain of Message-Ids back to the @@ -662,7 +660,7 @@ public MessageIdList References { } /// - /// Gets or sets the Message-Id that this message is in reply to. + /// Get or set the Message-Id that this message is replying to. /// /// /// If the message is a reply to another message, it will typically @@ -699,12 +697,12 @@ public string InReplyTo { } /// - /// Gets or sets the message identifier. + /// Get or set the message identifier. /// /// /// The Message-Id is meant to be a globally unique identifier for /// a message. - /// can be used + /// can be used /// to generate this value. /// /// The message identifier. @@ -737,12 +735,12 @@ public string MessageId { } /// - /// Gets or sets the Resent-Message-Id header. + /// Get or set the Resent-Message-Id header. /// /// /// The Resent-Message-Id is meant to be a globally unique identifier for /// a message. - /// can be used + /// can be used /// to generate this value. /// /// The Resent-Message-Id. @@ -775,7 +773,7 @@ public string ResentMessageId { } /// - /// Gets or sets the MIME-Version. + /// Get or set the MIME-Version. /// /// /// The MIME-Version header specifies the version of the MIME specification @@ -800,7 +798,7 @@ public Version MimeVersion { } /// - /// Gets or sets the body of the message. + /// Get or set the body of the message. /// /// /// The body of the message can either be plain text or it can be a @@ -880,7 +878,7 @@ static bool TryGetMultipartBody (Multipart multipart, TextFormat format, out str } /// - /// Gets the text body of the message if it exists. + /// Get the text body of the message if it exists. /// /// /// Gets the text content of the first text/plain body part that is found (in depth-first @@ -892,7 +890,7 @@ public string TextBody { } /// - /// Gets the html body of the message if it exists. + /// Get the html body of the message if it exists. /// /// /// Gets the HTML-formatted body of the message if it exists. @@ -903,7 +901,7 @@ public string HtmlBody { } /// - /// Gets the text body in the specified format. + /// Get the text body in the specified format. /// /// /// Gets the text body in the specified format, if it exists. @@ -949,7 +947,7 @@ static IEnumerable EnumerateMimeParts (MimeEntity entity) } /// - /// Gets the body parts of the message. + /// Get the body parts of the message. /// /// /// Traverses over the MIME tree, enumerating all of the objects, @@ -964,7 +962,7 @@ public IEnumerable BodyParts { } /// - /// Gets the attachments. + /// Get the attachments. /// /// /// Traverses over the MIME tree, enumerating all of the objects that @@ -978,21 +976,28 @@ public IEnumerable Attachments { get { return EnumerateMimeParts (Body).Where (x => x.IsAttachment); } } + static readonly byte[] ToStringWarning = Encoding.UTF8.GetBytes ("X-MimeKit-Warning: Do NOT use ToString() to serialize messages! Use one of the WriteTo() methods instead!"); + /// - /// Returns a that represents the current . + /// Returns a that represents the for debugging purposes. /// /// - /// Returns a that represents the current . - /// Note: In general, the string returned from this method SHOULD NOT be used for serializing - /// the message to disk. It is recommended that you use instead. + /// Returns a that represents the for debugging purposes. + /// In general, the string returned from this method SHOULD NOT be used for serializing + /// the message to disk. It is recommended that you use instead. + /// If this method is used for serializing the message to disk, the iso-8859-1 text encoding should be used for + /// conversion. /// - /// A that represents the current . + /// A that represents the for debugging purposes. public override string ToString () { using (var memory = new MemoryStream ()) { + memory.Write (ToStringWarning, 0, ToStringWarning.Length); + memory.Write (FormatOptions.Default.NewLineBytes, 0, FormatOptions.Default.NewLineBytes.Length); + WriteTo (FormatOptions.Default, memory); -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buffer = memory.GetBuffer (); #else var buffer = memory.ToArray (); @@ -1007,12 +1012,12 @@ public override string ToString () /// Dispatches to the specific visit method for this MIME message. ///
/// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -1044,8 +1049,12 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (maxLineLength < FormatOptions.MinimumLineLength || maxLineLength > FormatOptions.MaximumLineLength) throw new ArgumentOutOfRangeException (nameof (maxLineLength)); - if (Body != null) + if (Body != null) { + if (MimeVersion == null && Body.Headers.Count > 0) + MimeVersion = new Version (1, 0); + Body.Prepare (constraint, maxLineLength); + } } /// @@ -1088,11 +1097,14 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (options.HiddenHeaders.Contains (header.Id)) continue; - var rawValue = header.GetRawValue (options); - filtered.Write (header.RawField, 0, header.RawField.Length, cancellationToken); - filtered.Write (Header.Colon, 0, Header.Colon.Length, cancellationToken); - filtered.Write (rawValue, 0, rawValue.Length, cancellationToken); + + if (!header.IsInvalid) { + var rawValue = header.GetRawValue (options); + + filtered.Write (Header.Colon, 0, Header.Colon.Length, cancellationToken); + filtered.Write (rawValue, 0, rawValue.Length, cancellationToken); + } } filtered.Flush (cancellationToken); @@ -1109,7 +1121,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (!headersOnly) { try { - Body.EnsureNewLine = compliance == RfcComplianceMode.Strict; + Body.EnsureNewLine = compliance == RfcComplianceMode.Strict || options.EnsureNewLine; Body.WriteTo (options, stream, true, cancellationToken); } finally { Body.EnsureNewLine = false; @@ -1124,8 +1136,9 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// Asynchronously write the message to the specified output stream. /// /// - /// Writes the message to the output stream using the provided formatting options. + /// Asynchronously writes the message to the output stream using the provided formatting options. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// true if only the headers should be written; otherwise, false. @@ -1160,11 +1173,14 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (options.HiddenHeaders.Contains (header.Id)) continue; - var rawValue = header.GetRawValue (options); - await filtered.WriteAsync (header.RawField, 0, header.RawField.Length, cancellationToken).ConfigureAwait (false); - await filtered.WriteAsync (Header.Colon, 0, Header.Colon.Length, cancellationToken).ConfigureAwait (false); - await filtered.WriteAsync (rawValue, 0, rawValue.Length, cancellationToken).ConfigureAwait (false); + + if (!header.IsInvalid) { + var rawValue = header.GetRawValue (options); + + await filtered.WriteAsync (Header.Colon, 0, Header.Colon.Length, cancellationToken).ConfigureAwait (false); + await filtered.WriteAsync (rawValue, 0, rawValue.Length, cancellationToken).ConfigureAwait (false); + } } await filtered.FlushAsync (cancellationToken).ConfigureAwait (false); @@ -1174,7 +1190,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (!headersOnly) { try { - Body.EnsureNewLine = compliance == RfcComplianceMode.Strict; + Body.EnsureNewLine = compliance == RfcComplianceMode.Strict || options.EnsureNewLine; await Body.WriteToAsync (options, stream, true, cancellationToken).ConfigureAwait (false); } finally { Body.EnsureNewLine = false; @@ -1214,8 +1230,9 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// Asynchronously write the message to the specified output stream. ///
/// - /// Writes the message to the output stream using the provided formatting options. + /// Asynchronously writes the message to the output stream using the provided formatting options. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// The cancellation token. @@ -1262,8 +1279,9 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// Asynchronously write the message to the specified output stream. ///
/// - /// Writes the message to the output stream using the default formatting options. + /// Asynchronously writes the message to the output stream using the default formatting options. /// + /// An awaitable task. /// The output stream. /// true if only the headers should be written; otherwise, false. /// The cancellation token. @@ -1307,8 +1325,9 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// Asynchronously write the message to the specified output stream. ///
/// - /// Writes the message to the output stream using the default formatting options. + /// Asynchronously writes the message to the output stream using the default formatting options. /// + /// An awaitable task. /// The output stream. /// The cancellation token. /// @@ -1325,7 +1344,6 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = return WriteToAsync (FormatOptions.Default, stream, false, cancellationToken); } -#if !PORTABLE /// /// Write the message to the specified file. /// @@ -1342,8 +1360,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -1368,16 +1385,19 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) + using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) { WriteTo (options, stream, cancellationToken); + stream.Flush (); + } } /// /// Asynchronously write the message to the specified file. /// /// - /// Writes the message to the specified file using the provided formatting options. + /// Asynchronously writes the message to the specified file using the provided formatting options. /// + /// An awaitable task. /// The formatting options. /// The file. /// The cancellation token. @@ -1388,8 +1408,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -1414,8 +1433,10 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) + using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) { await WriteToAsync (options, stream, cancellationToken).ConfigureAwait (false); + await stream.FlushAsync (cancellationToken).ConfigureAwait (false); + } } /// @@ -1431,8 +1452,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -1451,19 +1471,16 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// public void WriteTo (string fileName, CancellationToken cancellationToken = default (CancellationToken)) { - if (fileName == null) - throw new ArgumentNullException (nameof (fileName)); - - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) - WriteTo (FormatOptions.Default, stream, cancellationToken); + WriteTo (FormatOptions.Default, fileName, cancellationToken); } /// /// Asynchronously write the message to the specified file. /// /// - /// Writes the message to the specified file using the default formatting options. + /// Asynchronously writes the message to the specified file using the default formatting options. /// + /// An awaitable task. /// The file. /// The cancellation token. /// @@ -1471,8 +1488,7 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// The operation was canceled via the cancellation token. @@ -1489,15 +1505,10 @@ public virtual void Prepare (EncodingConstraint constraint, int maxLineLength = /// /// An I/O error occurred. /// - public async Task WriteToAsync (string fileName, CancellationToken cancellationToken = default (CancellationToken)) + public Task WriteToAsync (string fileName, CancellationToken cancellationToken = default (CancellationToken)) { - if (fileName == null) - throw new ArgumentNullException (nameof (fileName)); - - using (var stream = File.Open (fileName, FileMode.Create, FileAccess.Write)) - await WriteToAsync (FormatOptions.Default, stream, cancellationToken).ConfigureAwait (false); + return WriteToAsync (FormatOptions.Default, fileName, cancellationToken); } -#endif MailboxAddress GetMessageSigner () { @@ -1560,95 +1571,7 @@ IList GetMessageRecipients (bool includeSenders) } #if ENABLE_CRYPTO - static void DkimWriteHeaderRelaxed (FormatOptions options, Stream stream, Header header, bool isDkimSignature) - { - // o Convert all header field names (not the header field values) to - // lowercase. For example, convert "SUBJect: AbC" to "subject: AbC". - var name = Encoding.ASCII.GetBytes (header.Field.ToLowerInvariant ()); - var rawValue = header.GetRawValue (options); - int index = 0; - - // o Delete any WSP characters remaining before and after the colon - // separating the header field name from the header field value. The - // colon separator MUST be retained. - stream.Write (name, 0, name.Length); - stream.WriteByte ((byte) ':'); - - // trim leading whitespace... - while (index < rawValue.Length && rawValue[index].IsWhitespace ()) - index++; - - while (index < rawValue.Length) { - int startIndex = index; - - // look for the first non-whitespace character - while (index < rawValue.Length && rawValue[index].IsWhitespace ()) - index++; - - // o Delete all WSP characters at the end of each unfolded header field - // value. - if (index >= rawValue.Length) - break; - - // o Convert all sequences of one or more WSP characters to a single SP - // character. WSP characters here include those before and after a - // line folding boundary. - if (index > startIndex) - stream.WriteByte ((byte) ' '); - - startIndex = index; - - while (index < rawValue.Length && !rawValue[index].IsWhitespace ()) - index++; - - if (index > startIndex) - stream.Write (rawValue, startIndex, index - startIndex); - } - - if (!isDkimSignature) - stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length); - } - - static void DkimWriteHeaderSimple (FormatOptions options, Stream stream, Header header, bool isDkimSignature) - { - var rawValue = header.GetRawValue (options); - int rawLength = rawValue.Length; - - if (isDkimSignature && rawLength > 0) { - if (rawValue[rawLength - 1] == (byte) '\n') { - rawLength--; - - if (rawLength > 0 && rawValue[rawLength - 1] == (byte) '\r') - rawLength--; - } - } - - stream.Write (header.RawField, 0, header.RawField.Length); - stream.Write (Header.Colon, 0, Header.Colon.Length); - stream.Write (rawValue, 0, rawLength); - } - - static ISigner DkimGetDigestSigner (DkimSignatureAlgorithm algorithm, AsymmetricKeyParameter key) - { -#if ENABLE_NATIVE_DKIM - return new SystemSecuritySigner (algorithm, key.AsAsymmetricAlgorithm ()); -#else - DerObjectIdentifier id; - - if (algorithm == DkimSignatureAlgorithm.RsaSha256) - id = PkcsObjectIdentifiers.Sha256WithRsaEncryption; - else - id = PkcsObjectIdentifiers.Sha1WithRsaEncryption; - - var signer = SignerUtilities.GetSigner (id); - - signer.Init (key.IsPrivate, key); - - return signer; -#endif - } - - byte[] DkimHashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm, int maxLength) + internal byte[] HashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm, int maxLength) { using (var stream = new DkimHashStream (signatureAlgorithm, maxLength)) { using (var filtered = new FilteredStream (stream)) { @@ -1664,7 +1587,7 @@ byte[] DkimHashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgo if (Body != null) { try { - Body.EnsureNewLine = compliance == RfcComplianceMode.Strict; + Body.EnsureNewLine = compliance == RfcComplianceMode.Strict || options.EnsureNewLine; Body.WriteTo (options, filtered, true, CancellationToken.None); } finally { Body.EnsureNewLine = false; @@ -1681,118 +1604,6 @@ byte[] DkimHashBody (FormatOptions options, DkimSignatureAlgorithm signatureAlgo } } - void DkimWriteHeaders (FormatOptions options, IList fields, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm, Stream stream) - { - var counts = new Dictionary (); - - for (int i = 0; i < fields.Count; i++) { - var headers = fields[i].StartsWith ("Content-", StringComparison.OrdinalIgnoreCase) ? Body.Headers : Headers; - var name = fields[i].ToLowerInvariant (); - int index, count, n = 0; - - if (!counts.TryGetValue (name, out count)) - count = 0; - - // Note: signers choosing to sign an existing header field that occurs more - // than once in the message (such as Received) MUST sign the physically last - // instance of that header field in the header block. Signers wishing to sign - // multiple instances of such a header field MUST include the header field - // name multiple times in the list of header fields and MUST sign such header - // fields in order from the bottom of the header field block to the top. - index = headers.LastIndexOf (name); - - // find the n'th header with this name - while (n < count && --index >= 0) { - if (headers[index].Field.Equals (name, StringComparison.OrdinalIgnoreCase)) - n++; - } - - if (index < 0) - continue; - - var header = headers[index]; - - switch (headerCanonicalizationAlgorithm) { - case DkimCanonicalizationAlgorithm.Relaxed: - DkimWriteHeaderRelaxed (options, stream, header, false); - break; - default: - DkimWriteHeaderSimple (options, stream, header, false); - break; - } - - counts[name] = ++count; - } - } - - static readonly string[] DkimShouldNotInclude = { "return-path", "received", "comments", "keywords", "bcc", "resent-bcc", "dkim-signature" }; - - void DkimSign (FormatOptions options, DkimSigner signer, IList fields, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm) - { - if (version == null && Body != null && Body.Headers.Count > 0) - MimeVersion = new Version (1, 0); - - var t = DateTime.UtcNow - DateUtils.UnixEpoch; - var value = new StringBuilder ("v=1"); - byte[] signature, hash; - Header dkim; - - options = options.Clone (); - options.NewLineFormat = NewLineFormat.Dos; - - switch (signer.SignatureAlgorithm) { - case DkimSignatureAlgorithm.RsaSha256: - value.Append ("; a=rsa-sha256"); - break; - default: - value.Append ("; a=rsa-sha1"); - break; - } - - value.AppendFormat ("; d={0}; s={1}", signer.Domain, signer.Selector); - value.AppendFormat ("; c={0}/{1}", - headerCanonicalizationAlgorithm.ToString ().ToLowerInvariant (), - bodyCanonicalizationAlgorithm.ToString ().ToLowerInvariant ()); - if (!string.IsNullOrEmpty (signer.QueryMethod)) - value.AppendFormat ("; q={0}", signer.QueryMethod); - if (!string.IsNullOrEmpty (signer.AgentOrUserIdentifier)) - value.AppendFormat ("; i={0}", signer.AgentOrUserIdentifier); - value.AppendFormat ("; t={0}", (long) t.TotalSeconds); - - using (var stream = new DkimSignatureStream (signer.DigestSigner)) { - using (var filtered = new FilteredStream (stream)) { - filtered.Add (options.CreateNewLineFilter ()); - - // write the specified message headers - DkimWriteHeaders (options, fields, headerCanonicalizationAlgorithm, filtered); - - value.AppendFormat ("; h={0}", string.Join (":", fields.ToArray ())); - - hash = DkimHashBody (options, signer.SignatureAlgorithm, bodyCanonicalizationAlgorithm, -1); - value.AppendFormat ("; bh={0}", Convert.ToBase64String (hash)); - value.Append ("; b="); - - dkim = new Header (HeaderId.DkimSignature, value.ToString ()); - Headers.Insert (0, dkim); - - switch (headerCanonicalizationAlgorithm) { - case DkimCanonicalizationAlgorithm.Relaxed: - DkimWriteHeaderRelaxed (options, filtered, dkim, true); - break; - default: - DkimWriteHeaderSimple (options, filtered, dkim, true); - break; - } - - filtered.Flush (); - } - - signature = stream.GenerateSignature (); - - dkim.Value += Convert.ToBase64String (signature); - } - } - /// /// Digitally sign the message using a DomainKeys Identified Mail (DKIM) signature. /// @@ -1820,6 +1631,7 @@ void DkimSign (FormatOptions options, DkimSigner signer, IList fields, D /// contains one or more of the following headers: Return-Path, /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. /// + [Obsolete ("Use DkimSigner.Sign() instead.")] public void Sign (FormatOptions options, DkimSigner signer, IList headers, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple) { if (options == null) @@ -1828,32 +1640,10 @@ public void Sign (FormatOptions options, DkimSigner signer, IList header if (signer == null) throw new ArgumentNullException (nameof (signer)); - if (headers == null) - throw new ArgumentNullException (nameof (headers)); - - var fields = new string[headers.Count]; - var containsFrom = false; - - for (int i = 0; i < headers.Count; i++) { - if (headers[i] == null) - throw new ArgumentException ("The list of headers cannot contain null.", nameof (headers)); + signer.HeaderCanonicalizationAlgorithm = headerCanonicalizationAlgorithm; + signer.BodyCanonicalizationAlgorithm = bodyCanonicalizationAlgorithm; - if (headers[i].Length == 0) - throw new ArgumentException ("The list of headers cannot contain empty string.", nameof (headers)); - - fields[i] = headers[i].ToLowerInvariant (); - - if (DkimShouldNotInclude.Contains (fields[i])) - throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i])); - - if (fields[i] == "from") - containsFrom = true; - } - - if (!containsFrom) - throw new ArgumentException ("The list of headers to sign MUST include the 'From' header."); - - DkimSign (options, signer, fields, headerCanonicalizationAlgorithm, bodyCanonicalizationAlgorithm); + signer.Sign (options, this, headers); } /// @@ -1880,6 +1670,7 @@ public void Sign (FormatOptions options, DkimSigner signer, IList header /// contains one or more of the following headers: Return-Path, /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. /// + [Obsolete ("Use DkimSigner.Sign() instead.")] public void Sign (DkimSigner signer, IList headers, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple) { Sign (FormatOptions.Default, signer, headers, headerCanonicalizationAlgorithm, bodyCanonicalizationAlgorithm); @@ -1912,6 +1703,7 @@ public void Sign (DkimSigner signer, IList headers, DkimCanonicalization /// contains one or more of the following headers: Return-Path, /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. /// + [Obsolete ("Use DkimSigner.Sign() instead.")] public void Sign (FormatOptions options, DkimSigner signer, IList headers, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple) { if (options == null) @@ -1920,29 +1712,10 @@ public void Sign (FormatOptions options, DkimSigner signer, IList head if (signer == null) throw new ArgumentNullException (nameof (signer)); - if (headers == null) - throw new ArgumentNullException (nameof (headers)); - - var fields = new string[headers.Count]; - var containsFrom = false; - - for (int i = 0; i < headers.Count; i++) { - if (headers[i] == HeaderId.Unknown) - throw new ArgumentException ("The list of headers to sign cannot include the 'Unknown' header."); + signer.HeaderCanonicalizationAlgorithm = headerCanonicalizationAlgorithm; + signer.BodyCanonicalizationAlgorithm = bodyCanonicalizationAlgorithm; - fields[i] = headers[i].ToHeaderName ().ToLowerInvariant (); - - if (DkimShouldNotInclude.Contains (fields[i])) - throw new ArgumentException (string.Format ("The list of headers to sign SHOULD NOT include the '{0}' header.", headers[i].ToHeaderName ())); - - if (headers[i] == HeaderId.From) - containsFrom = true; - } - - if (!containsFrom) - throw new ArgumentException ("The list of headers to sign MUST include the 'From' header."); - - DkimSign (options, signer, fields, headerCanonicalizationAlgorithm, bodyCanonicalizationAlgorithm); + signer.Sign (options, this, headers); } /// @@ -1969,203 +1742,13 @@ public void Sign (FormatOptions options, DkimSigner signer, IList head /// contains one or more of the following headers: Return-Path, /// Received, Comments, Keywords, Bcc, Resent-Bcc, or DKIM-Signature. /// + [Obsolete ("Use DkimSigner.Sign() instead.")] public void Sign (DkimSigner signer, IList headers, DkimCanonicalizationAlgorithm headerCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm bodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple) { Sign (FormatOptions.Default, signer, headers, headerCanonicalizationAlgorithm, bodyCanonicalizationAlgorithm); } - static bool IsWhiteSpace (char c) - { - return c == ' ' || c == '\t'; - } - - static IDictionary ParseDkimSignature (string signature) - { - var parameters = new Dictionary (); - - foreach (var token in signature.Split (';')) { - var value = new StringBuilder (); - int startIndex, index = 0; - string name; - - while (index < token.Length && IsWhiteSpace (token[index])) - index++; - - startIndex = index; - - while (index < token.Length && token[index] != '=') - index++; - - if (index + 1 >= token.Length) - continue; - - name = token.Substring (startIndex, index - startIndex).Trim (); - index++; - - while (index < token.Length) { - if (!IsWhiteSpace (token[index])) - value.Append (token[index]); - index++; - } - - if (parameters.ContainsKey (name)) - throw new FormatException (string.Format ("Malformed DKIM-Signature value: duplicate parameter '{0}'.", name)); - - parameters.Add (name, value.ToString ()); - } - - return parameters; - } - - static void ValidateDkimSignatureParameters (IDictionary parameters, out DkimSignatureAlgorithm algorithm, out DkimCanonicalizationAlgorithm headerAlgorithm, - out DkimCanonicalizationAlgorithm bodyAlgorithm, out string d, out string s, out string q, out string[] headers, out string bh, out string b, out int maxLength) - { - bool containsFrom = false; - string v, a, c, h, l, id; - - if (!parameters.TryGetValue ("v", out v)) - throw new FormatException ("Malformed DKIM-Signature header: no version parameter detected."); - - if (v != "1") - throw new FormatException (string.Format ("Unrecognized DKIM-Signature version: v={0}", v)); - - if (!parameters.TryGetValue ("a", out a)) - throw new FormatException ("Malformed DKIM-Signature header: no signature algorithm parameter detected."); - - switch (a.ToLowerInvariant ()) { - case "rsa-sha256": algorithm = DkimSignatureAlgorithm.RsaSha256; break; - case "rsa-sha1": algorithm = DkimSignatureAlgorithm.RsaSha1; break; - default: throw new FormatException (string.Format ("Unrecognized DKIM-Signature algorithm parameter: a={0}", a)); - } - - if (!parameters.TryGetValue ("d", out d)) - throw new FormatException ("Malformed DKIM-Signature header: no domain parameter detected."); - - if (parameters.TryGetValue ("i", out id)) { - string ident; - int at; - - if ((at = id.LastIndexOf ('@')) == -1) - throw new FormatException ("Malformed DKIM-Signature header: no @ in the AUID value."); - - ident = id.Substring (at + 1); - - if (!ident.Equals (d, StringComparison.OrdinalIgnoreCase) && !ident.EndsWith ("." + d, StringComparison.OrdinalIgnoreCase)) - throw new FormatException ("Invalid DKIM-Signature header: the domain in the AUID does not match the domain parameter."); - } - - if (!parameters.TryGetValue ("s", out s)) - throw new FormatException ("Malformed DKIM-Signature header: no selector parameter detected."); - - if (!parameters.TryGetValue ("q", out q)) - q = "dns/txt"; - - if (parameters.TryGetValue ("l", out l)) { - if (!int.TryParse (l, out maxLength)) - throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid length parameter: l={0}", l)); - } else { - maxLength = -1; - } - - if (parameters.TryGetValue ("c", out c)) { - var tokens = c.ToLowerInvariant ().Split ('/'); - - if (tokens.Length == 0 || tokens.Length > 2) - throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c)); - - switch (tokens[0]) { - case "relaxed": headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break; - case "simple": headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; break; - default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c)); - } - - if (tokens.Length == 2) { - switch (tokens[1]) { - case "relaxed": bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed; break; - case "simple": bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; break; - default: throw new FormatException (string.Format ("Malformed DKIM-Signature header: invalid canonicalization parameter: c={0}", c)); - } - } else { - bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; - } - } else { - headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; - bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; - } - - if (!parameters.TryGetValue ("h", out h)) - throw new FormatException ("Malformed DKIM-Signature header: no signed header parameter detected."); - - headers = h.Split (':'); - for (int i = 0; i < headers.Length; i++) { - if (headers[i].Equals ("from", StringComparison.OrdinalIgnoreCase)) { - containsFrom = true; - break; - } - } - - if (!containsFrom) - throw new FormatException (string.Format ("Malformed DKIM-Signature header: From header not signed.")); - - if (!parameters.TryGetValue ("bh", out bh)) - throw new FormatException ("Malformed DKIM-Signature header: no body hash parameter detected."); - - if (!parameters.TryGetValue ("b", out b)) - throw new FormatException ("Malformed DKIM-Signature header: no signature parameter detected."); - } - - static Header GetSignedDkimSignatureHeader (Header dkimSignature) - { - // modify the raw DKIM-Signature header value by chopping off the signature value after the "b=" - var rawValue = (byte[]) dkimSignature.RawValue.Clone (); - int length = 0, index = 0; - - do { - while (index < rawValue.Length && rawValue[index].IsWhitespace ()) - index++; - - if (index + 2 < rawValue.Length) { - var param = (char) rawValue[index++]; - - while (index < rawValue.Length && rawValue[index].IsWhitespace ()) - index++; - - if (index < rawValue.Length && rawValue[index] == (byte) '=' && param == 'b') { - length = ++index; - - while (index < rawValue.Length && rawValue[index] != (byte) ';') - index++; - - if (index == rawValue.Length && rawValue[index - 1] == (byte) '\n') { - index--; - - if (rawValue[index - 1] == (byte) '\r') - index--; - } - - break; - } - } - - while (index < rawValue.Length && rawValue[index] != (byte) ';') - index++; - - if (index < rawValue.Length) - index++; - } while (index < rawValue.Length); - - if (index == rawValue.Length) - throw new FormatException ("Malformed DKIM-Signature header: missing signature parameter."); - - while (index < rawValue.Length) - rawValue[length++] = rawValue[index++]; - - Array.Resize (ref rawValue, length); - - return new Header (dkimSignature.Options, dkimSignature.RawField, rawValue); - } - - async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, bool doAsync, CancellationToken cancellationToken) + Task DkimVerifyAsync (FormatOptions options, Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, bool doAsync, CancellationToken cancellationToken) { if (options == null) throw new ArgumentNullException (nameof (options)); @@ -2174,60 +1757,14 @@ async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkim throw new ArgumentNullException (nameof (dkimSignature)); if (dkimSignature.Id != HeaderId.DkimSignature) - throw new ArgumentException ("The dkimSignature parameter MUST be a DKIM-Signature header.", nameof (dkimSignature)); - - if (publicKeyLocator == null) - throw new ArgumentNullException (nameof (publicKeyLocator)); + throw new ArgumentException ("The signature parameter MUST be a DKIM-Signature header.", nameof (dkimSignature)); - var parameters = ParseDkimSignature (dkimSignature.Value); - DkimCanonicalizationAlgorithm headerAlgorithm, bodyAlgorithm; - DkimSignatureAlgorithm signatureAlgorithm; - AsymmetricKeyParameter key; - string d, s, q, bh, b; - string[] headers; - int maxLength; - - ValidateDkimSignatureParameters (parameters, out signatureAlgorithm, out headerAlgorithm, out bodyAlgorithm, - out d, out s, out q, out headers, out bh, out b, out maxLength); + var verifier = new DkimVerifier (publicKeyLocator); if (doAsync) - key = await publicKeyLocator.LocatePublicKeyAsync (q, d, s, cancellationToken).ConfigureAwait (false); - else - key = publicKeyLocator.LocatePublicKey (q, d, s, cancellationToken); - - options = options.Clone (); - options.NewLineFormat = NewLineFormat.Dos; - - // first check the body hash (if that's invalid, then the entire signature is invalid) - var hash = Convert.ToBase64String (DkimHashBody (options, signatureAlgorithm, bodyAlgorithm, maxLength)); - - if (hash != bh) - return false; - - using (var stream = new DkimSignatureStream (DkimGetDigestSigner (signatureAlgorithm, key))) { - using (var filtered = new FilteredStream (stream)) { - filtered.Add (options.CreateNewLineFilter ()); - - DkimWriteHeaders (options, headers, headerAlgorithm, filtered); - - // now include the DKIM-Signature header that we are verifying, - // but only after removing the "b=" signature value. - var header = GetSignedDkimSignatureHeader (dkimSignature); + return verifier.VerifyAsync (options, this, dkimSignature, cancellationToken); - switch (headerAlgorithm) { - case DkimCanonicalizationAlgorithm.Relaxed: - DkimWriteHeaderRelaxed (options, filtered, header, true); - break; - default: - DkimWriteHeaderSimple (options, filtered, header, true); - break; - } - - filtered.Flush (); - } - - return stream.VerifySignature (b); - } + return Task.FromResult (verifier.Verify (options, this, dkimSignature, cancellationToken)); } /// @@ -2260,9 +1797,10 @@ async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkim /// /// The operation was canceled via the cancellation token. /// + [Obsolete ("Use the DkimVerifier class instead.")] public bool Verify (FormatOptions options, Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, CancellationToken cancellationToken = default (CancellationToken)) { - return VerifyAsync (options, dkimSignature, publicKeyLocator, false, cancellationToken).GetAwaiter ().GetResult (); + return DkimVerifyAsync (options, dkimSignature, publicKeyLocator, false, cancellationToken).GetAwaiter ().GetResult (); } /// @@ -2295,9 +1833,10 @@ async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkim /// /// The operation was canceled via the cancellation token. /// + [Obsolete ("Use the DkimVerifier class instead.")] public Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, CancellationToken cancellationToken = default (CancellationToken)) { - return VerifyAsync (options, dkimSignature, publicKeyLocator, true, cancellationToken); + return DkimVerifyAsync (options, dkimSignature, publicKeyLocator, true, cancellationToken); } /// @@ -2327,6 +1866,7 @@ async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkim /// /// The operation was canceled via the cancellation token. /// + [Obsolete ("Use the DkimVerifier class instead.")] public bool Verify (Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, CancellationToken cancellationToken = default (CancellationToken)) { return Verify (FormatOptions.Default, dkimSignature, publicKeyLocator, cancellationToken); @@ -2359,6 +1899,7 @@ async Task VerifyAsync (FormatOptions options, Header dkimSignature, IDkim /// /// The operation was canceled via the cancellation token. /// + [Obsolete ("Use the DkimVerifier class instead.")] public Task VerifyAsync (Header dkimSignature, IDkimPublicKeyLocator publicKeyLocator, CancellationToken cancellationToken = default (CancellationToken)) { return VerifyAsync (FormatOptions.Default, dkimSignature, publicKeyLocator, cancellationToken); @@ -2605,6 +2146,17 @@ IEnumerable
MergeHeaders () { int mesgIndex = 0, bodyIndex = 0; + // write all of the prepended message headers first + while (mesgIndex < Headers.Count) { + var mesgHeader = Headers[mesgIndex]; + if (mesgHeader.Offset.HasValue) + break; + + yield return mesgHeader; + mesgIndex++; + } + + // now merge the message and body headers as they appeared in the raw message while (mesgIndex < Headers.Count && bodyIndex < Body.Headers.Count) { var bodyHeader = Body.Headers[bodyIndex]; if (!bodyHeader.Offset.HasValue) @@ -2663,32 +2215,33 @@ void SetHeader (string name, string value) } } - void SerializeAddressList (string field, InternetAddressList list) + void SerializeAddressList (HeaderId id, InternetAddressList list) { if (list.Count == 0) { - RemoveHeader (field.ToHeaderId ()); + RemoveHeader (id); return; } var builder = new StringBuilder (" "); var options = FormatOptions.Default; + var field = id.ToHeaderName (); int lineLength = field.Length + 2; - list.Encode (options, builder, ref lineLength); + list.Encode (options, builder, true, ref lineLength); builder.Append (options.NewLine); var raw = Encoding.UTF8.GetBytes (builder.ToString ()); - ReplaceHeader (field.ToHeaderId (), field, raw); + ReplaceHeader (id, field, raw); } void InternetAddressListChanged (object addrlist, EventArgs e) { var list = (InternetAddressList) addrlist; - foreach (var name in StandardAddressHeaders) { - if (addresses[name] == list) { - SerializeAddressList (name, list); + foreach (var id in StandardAddressHeaders) { + if (addresses[id] == list) { + SerializeAddressList (id, list); break; } } @@ -2880,7 +2433,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) switch (e.Action) { case HeaderListChangedAction.Added: - if (addresses.TryGetValue (e.Header.Field, out list)) { + if (addresses.TryGetValue (e.Header.Id, out list)) { AddAddresses (e.Header, list); break; } @@ -2945,7 +2498,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) break; case HeaderListChangedAction.Changed: case HeaderListChangedAction.Removed: - if (addresses.TryGetValue (e.Header.Field, out list)) { + if (addresses.TryGetValue (e.Header.Id, out list)) { ReloadAddressList (e.Header.Id, list); break; } @@ -2987,7 +2540,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// specified . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. /// @@ -3031,7 +2584,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// specified . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. /// @@ -3135,7 +2688,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// default . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. /// @@ -3168,7 +2721,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// default . /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save mmeory usage, but also improve /// performance. /// @@ -3247,7 +2800,6 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) return LoadAsync (ParserOptions.Default, stream, false, cancellationToken); } -#if !PORTABLE /// /// Load a from the specified file. /// @@ -3266,8 +2818,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -3295,7 +2846,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Open, FileAccess.Read)) + using (var stream = File.OpenRead (fileName)) return Load (options, stream, cancellationToken); } @@ -3317,8 +2868,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -3346,7 +2896,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - using (var stream = File.Open (fileName, FileMode.Open, FileAccess.Read)) + using (var stream = File.OpenRead (fileName)) return await LoadAsync (options, stream, cancellationToken).ConfigureAwait (false); } @@ -3365,8 +2915,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -3406,8 +2955,7 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) /// /// /// is a zero-length string, contains only white space, or - /// contains one or more invalid characters as defined by - /// . + /// contains one or more invalid characters. /// /// /// is an invalid file path. @@ -3431,7 +2979,6 @@ void HeadersChanged (object o, HeaderListChangedEventArgs e) { return LoadAsync (ParserOptions.Default, fileName, cancellationToken); } -#endif // !PORTABLE #if ENABLE_SNM static MimePart GetMimePart (AttachmentBase item) @@ -3470,6 +3017,8 @@ static MimePart GetMimePart (AttachmentBase item) part.ContentId = item.ContentId; var stream = new MemoryBlockStream (); + if (item.ContentStream.CanSeek) + item.ContentStream.Position = 0; item.ContentStream.CopyTo (stream); stream.Position = 0; @@ -3539,6 +3088,9 @@ public static MimeMessage CreateFromMailMessage (MailMessage message) else msg.Subject = message.Subject ?? string.Empty; + if (!msg.Headers.Contains (HeaderId.Date)) + msg.Date = DateTimeOffset.Now; + switch (message.Priority) { case MailPriority.Normal: msg.Headers.RemoveAll (HeaderId.XMSMailPriority); diff --git a/MimeKit/MimeMessageBeginEventArgs.cs b/MimeKit/MimeMessageBeginEventArgs.cs new file mode 100644 index 0000000000..ce3c283b7f --- /dev/null +++ b/MimeKit/MimeMessageBeginEventArgs.cs @@ -0,0 +1,117 @@ +// +// MimeMessageBeginEventArgs.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit { + /// + /// Event args emitted by the when it begins parsing a . + /// + /// + /// Event args emitted by the when it begins parsing a . + /// + public class MimeMessageBeginEventArgs : EventArgs + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The message that was parsed. + /// + /// is null. + /// + public MimeMessageBeginEventArgs (MimeMessage message) + { + if (message == null) + throw new ArgumentNullException (nameof (message)); + + Message = message; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The message that was parsed. + /// The parent message part. + /// + /// is null. + /// -or- + /// is null. + /// + public MimeMessageBeginEventArgs (MimeMessage message, MessagePart parent) + { + if (message == null) + throw new ArgumentNullException (nameof (message)); + + if (parent == null) + throw new ArgumentNullException (nameof (parent)); + + Message = message; + Parent = parent; + } + + /// + /// Get the message that was parsed. + /// + /// + /// Gets the message that was parsed. + /// + /// The message. + public MimeMessage Message { get; } + + /// + /// Get the parent if this message is an attachment. + /// + /// + /// Gets the parent if this message is an attachment. + /// + /// The parent . + public MessagePart Parent { get; } + + /// + /// Get or set the stream offset that marks the beginning of the message. + /// + /// + /// Gets or sets the stream offset that marks the beginning of the message. + /// + /// The stream offset. + public long BeginOffset { get; set; } + + /// + /// Get or set the line number of the beginning of the message. + /// + /// + /// Gets or sets the line number of the beginning of the message. + /// + /// The line number. + internal int LineNumber { get; set; } + } +} diff --git a/MimeKit/MimeMessageEndEventArgs.cs b/MimeKit/MimeMessageEndEventArgs.cs new file mode 100644 index 0000000000..dfceaaa7b2 --- /dev/null +++ b/MimeKit/MimeMessageEndEventArgs.cs @@ -0,0 +1,87 @@ +// +// MimeMessageEndEventArgs.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit { + /// + /// Event args emitted by the when a is parsed. + /// + /// + /// Event args emitted by the when a is parsed. + /// + public class MimeMessageEndEventArgs : MimeMessageBeginEventArgs + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The message that was parsed. + /// + /// is null. + /// + public MimeMessageEndEventArgs (MimeMessage message) : base (message) + { + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// The message that was parsed. + /// The parent message part. + /// + /// is null. + /// -or- + /// is null. + /// + public MimeMessageEndEventArgs (MimeMessage message, MessagePart parent) : base (message, parent) + { + } + + /// + /// Get or set the stream offset that marks the end of the message headers. + /// + /// + /// Gets or sets the stream offset that marks the end of the message headers. + /// + /// The stream offset. + public long HeadersEndOffset { get; set; } + + /// + /// Get or set the stream offset that marks the end of the message. + /// + /// + /// Gets or sets the stream offset that marks the end of the message. + /// + /// The stream offset. + public long EndOffset { get; set; } + } +} diff --git a/MimeKit/MimeParser.cs b/MimeKit/MimeParser.cs index 8dae1319fd..53374aa77b 100644 --- a/MimeKit/MimeParser.cs +++ b/MimeKit/MimeParser.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,12 +32,8 @@ using System.Collections; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - -using MimeKit.Utils; using MimeKit.IO; +using MimeKit.Utils; namespace MimeKit { enum BoundaryType @@ -58,7 +54,6 @@ class Boundary public int FinalLength { get { return Marker.Length; } } public int Length { get; private set; } public int MaxLength { get; private set; } - public long ContentEnd { get; set; } public Boundary (string boundary, int currentMaxLength) { @@ -66,7 +61,6 @@ public Boundary (string boundary, int currentMaxLength) Length = Marker.Length - 2; MaxLength = Math.Max (currentMaxLength, Marker.Length); - ContentEnd = -1; } Boundary () @@ -77,16 +71,17 @@ public static Boundary CreateMboxBoundary () { var boundary = new Boundary (); boundary.Marker = MboxFrom; - boundary.ContentEnd = -1; boundary.MaxLength = 5; boundary.Length = 5; return boundary; } +#if DEBUG_PARSER public override string ToString () { return Encoding.UTF8.GetString (Marker, 0, Marker.Length); } +#endif } enum MimeParserState : sbyte @@ -97,6 +92,7 @@ enum MimeParserState : sbyte MessageHeaders, Headers, Content, + Boundary, Complete, Eos } @@ -105,8 +101,8 @@ enum MimeParserState : sbyte /// A MIME message and entity parser. ///
/// - /// A MIME parser is used to parse and - /// objects from arbitrary streams. + /// A MIME parser is used to parse and + /// objects from arbitrary streams. /// public partial class MimeParser : IEnumerable { @@ -135,26 +131,36 @@ public partial class MimeParser : IEnumerable long headerOffset; int headerIndex; - readonly List bounds; - readonly List
headers; + readonly List bounds = new List (); + readonly List
headers = new List
(); MimeParserState state; + BoundaryType boundary; MimeFormat format; bool persistent; + bool toplevel; bool eos; - ParserOptions options; + ParserOptions options; // FIXME: might be better if devs passed ParserOptions into the Parse*() methods rather than .ctor and/or SetStream() + long headerBlockBegin; + long headerBlockEnd; + long contentEnd; + + long prevLineBeginOffset; + long lineBeginOffset; + int lineNumber; + Stream stream; - long offset; + long position; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new that will parse the specified stream. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -171,13 +177,13 @@ public MimeParser (Stream stream, MimeFormat format, bool persistent = false) : } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new that will parse the specified stream. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -193,13 +199,13 @@ public MimeParser (Stream stream, bool persistent = false) : this (ParserOptions } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new that will parse the specified stream. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -218,13 +224,13 @@ public MimeParser (ParserOptions options, Stream stream, bool persistent = false } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new that will parse the specified stream. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -241,9 +247,6 @@ public MimeParser (ParserOptions options, Stream stream, bool persistent = false /// public MimeParser (ParserOptions options, Stream stream, MimeFormat format, bool persistent = false) { - bounds = new List (); - headers = new List
(); - SetStream (options, stream, format, persistent); } @@ -267,7 +270,7 @@ public bool IsEndOfStream { /// /// The stream offset. public long Position { - get { return GetOffset (-1); } + get { return GetOffset (inputIndex); } } /// @@ -299,7 +302,7 @@ public string MboxMarker { /// Sets the stream to parse. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -332,11 +335,19 @@ public void SetStream (ParserOptions options, Stream stream, MimeFormat format, mboxMarkerOffset = 0; mboxMarkerLength = 0; - - offset = stream.CanSeek ? stream.Position : 0; + headerBlockBegin = 0; + headerBlockEnd = 0; + lineNumber = 1; + contentEnd = 0; + + position = stream.CanSeek ? stream.Position : 0; + prevLineBeginOffset = position; + lineBeginOffset = position; + preHeaderLength = 0; headers.Clear (); headerOffset = 0; headerIndex = 0; + toplevel = false; eos = false; bounds.Clear (); @@ -348,6 +359,7 @@ public void SetStream (ParserOptions options, Stream stream, MimeFormat format, } state = MimeParserState.Initialized; + boundary = BoundaryType.None; } /// @@ -357,7 +369,7 @@ public void SetStream (ParserOptions options, Stream stream, MimeFormat format, /// Sets the stream to parse. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -383,7 +395,7 @@ public void SetStream (ParserOptions options, Stream stream, bool persistent = f /// Sets the stream to parse. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -407,7 +419,7 @@ public void SetStream (Stream stream, MimeFormat format, bool persistent = false /// Sets the stream to parse. /// If is true and is seekable, then /// the will not copy the content of s into memory. Instead, - /// it will use a to reference a substream of . + /// it will use a to reference a substream of . /// This has the potential to not only save memory usage, but also improve /// performance. /// It should be noted, however, that disposing will make it impossible @@ -423,7 +435,87 @@ public void SetStream (Stream stream, bool persistent = false) SetStream (ParserOptions.Default, stream, MimeFormat.Default, persistent); } -#if DEBUG + /// + /// An event signifying the beginning of a new has been encountered. + /// + /// + /// An event signifying the beginning of a new has been encountered. + /// + public event EventHandler MimeMessageBegin; + + /// + /// Invoked when the parser begins parsing a . + /// + /// + /// Invoked when the parser begins parsing a . + /// + /// The parsed state. + protected virtual void OnMimeMessageBegin (MimeMessageBeginEventArgs args) + { + MimeMessageBegin?.Invoke (this, args); + } + + /// + /// An event signifying the end of a has been encountered. + /// + /// + /// An event signifying the end of a has been encountered. + /// + public event EventHandler MimeMessageEnd; + + /// + /// Invoked when the parser has completed parsing a . + /// + /// + /// Invoked when the parser has completed parsing a . + /// + /// The parsed state. + protected virtual void OnMimeMessageEnd (MimeMessageEndEventArgs args) + { + MimeMessageEnd?.Invoke (this, args); + } + + /// + /// An event signifying the beginning of a new has been encountered. + /// + /// + /// An event signifying the beginning of a new has been encountered. + /// + public event EventHandler MimeEntityBegin; + + /// + /// Invoked when the parser begins parsing a . + /// + /// + /// Invoked when the parser begins parsing a . + /// + /// The parsed state. + protected virtual void OnMimeEntityBegin (MimeEntityBeginEventArgs args) + { + MimeEntityBegin?.Invoke (this, args); + } + + /// + /// An event signifying the end of a has been encountered. + /// + /// + /// An event signifying the end of a has been encountered. + /// + public event EventHandler MimeEntityEnd; + + /// + /// Invoked when the parser has completed parsing a . + /// + /// + /// Invoked when the parser has completed parsing a . + /// + /// The parsed state. + protected virtual void OnMimeEntityEnd (MimeEntityEndEventArgs args) + { + MimeEntityEnd?.Invoke (this, args); + } + +#if DEBUG_PARSER static string ConvertToCString (byte[] buffer, int startIndex, int length) { var cstr = new StringBuilder (); @@ -497,7 +589,7 @@ int ReadAhead (int atleast, int save, CancellationToken cancellationToken) if (nread > 0) { inputEnd += nread; - offset += nread; + position += nread; } else { eos = true; } @@ -507,13 +599,35 @@ int ReadAhead (int atleast, int save, CancellationToken cancellationToken) long GetOffset (int index) { - if (offset == -1) + if (position == -1) return -1; - if (index == -1) - index = inputIndex; + return position - (inputEnd - index); + } + + long GetEndOffset (int index) + { + if (boundary != BoundaryType.Eos && index > 1 && input[index - 1] == (byte) '\n') { + index--; + + if (index > 1 && input[index - 1] == (byte) '\r') + index--; + } + + return GetOffset (index); + } + + int GetLineCount (int beginLineNumber, long beginOffset, long endOffset) + { + var lines = lineNumber - beginLineNumber; - return offset - (inputEnd - index); + if (lineBeginOffset >= beginOffset && endOffset > lineBeginOffset) + lines++; + + if (boundary != BoundaryType.Eos && endOffset == prevLineBeginOffset) + lines--; + + return lines; } static unsafe bool CStringsEqual (byte* str1, byte* str2, int length) @@ -580,7 +694,7 @@ static unsafe bool IsMboxMarker (byte* text, bool allowMunged = false) #endif } - unsafe void StepMboxMarker (byte *inbuf, ref bool needInput, ref bool complete, ref int left) + unsafe bool StepMboxMarker (byte *inbuf, ref int left) { byte* inptr = inbuf + inputIndex; byte* inend = inbuf + inputEnd; @@ -588,53 +702,55 @@ unsafe void StepMboxMarker (byte *inbuf, ref bool needInput, ref bool complete, *inend = (byte) '\n'; while (inptr < inend) { + int startIndex = inputIndex; byte* start = inptr; // scan for the end of the line while (*inptr != (byte) '\n') inptr++; - long length = inptr - start; + var markerLength = (int) (inptr - start); if (inptr > start && *(inptr - 1) == (byte) '\r') - length--; + markerLength--; // consume the '\n' inptr++; + var lineLength = (int) (inptr - start); + if (inptr >= inend) { // we don't have enough input data - inputIndex = (int) (start - inbuf); - left = (int) (inptr - start); - needInput = true; - break; + left = lineLength; + return false; } - if (length >= 5 && IsMboxMarker (start)) { - int startIndex = (int) (start - inbuf); + inputIndex += lineLength; + prevLineBeginOffset = lineBeginOffset; + lineBeginOffset = GetOffset (inputIndex); + lineNumber++; + if (markerLength >= 5 && IsMboxMarker (start)) { mboxMarkerOffset = GetOffset (startIndex); - mboxMarkerLength = (int) length; + mboxMarkerLength = markerLength; if (mboxMarkerBuffer.Length < mboxMarkerLength) Array.Resize (ref mboxMarkerBuffer, mboxMarkerLength); - Buffer.BlockCopy (input, startIndex, mboxMarkerBuffer, 0, (int) length); - complete = true; - break; + Buffer.BlockCopy (input, startIndex, mboxMarkerBuffer, 0, markerLength); + + return true; } } - if (!needInput) { - inputIndex = (int) (inptr - inbuf); - left = 0; - } + left = 0; + + return false; } unsafe void StepMboxMarker (byte* inbuf, CancellationToken cancellationToken) { - bool complete = false; - bool needInput; + bool complete; int left = 0; mboxMarkerLength = 0; @@ -649,9 +765,7 @@ unsafe void StepMboxMarker (byte* inbuf, CancellationToken cancellationToken) return; } - needInput = false; - - StepMboxMarker (inbuf, ref needInput, ref complete, ref left); + complete = StepMboxMarker (inbuf, ref left); } while (!complete); state = MimeParserState.MessageHeaders; @@ -680,19 +794,11 @@ unsafe void ParseAndAppendHeader () return; fixed (byte* buf = headerBuffer) { - Header header; - - if (!Header.TryParse (options, buf, headerIndex, false, out header)) { -#if DEBUG - Debug.WriteLine (string.Format ("Invalid header at offset {0}: {1}", headerOffset, ConvertToCString (headerBuffer, 0, headerIndex))); -#endif + if (Header.TryParse (options, buf, headerIndex, false, out var header)) { + header.Offset = headerOffset; + headers.Add (header); headerIndex = 0; - return; } - - header.Offset = headerOffset; - headers.Add (header); - headerIndex = 0; } } @@ -760,7 +866,7 @@ unsafe bool StepHeaders (byte* inbuf, ref bool scanningFieldName, ref bool check } if (inptr == inend) { - // we don't have enough input data + // we don't have enough input data; restore state back to the beginning of the line left = (int) (inend - start); inputIndex = (int) (start - inbuf); needInput = true; @@ -775,7 +881,7 @@ unsafe bool StepHeaders (byte* inbuf, ref bool scanningFieldName, ref bool check if (!valid) { length = inptr - start; - if (format == MimeFormat.Mbox && length >= 5 && IsMboxMarker (start)) { + if (format == MimeFormat.Mbox && inputIndex >= contentEnd && length >= 5 && IsMboxMarker (start)) { // we've found the start of the next message... inputIndex = (int) (start - inbuf); state = MimeParserState.Complete; @@ -783,10 +889,17 @@ unsafe bool StepHeaders (byte* inbuf, ref bool scanningFieldName, ref bool check return false; } - if (state == MimeParserState.MessageHeaders && headers.Count == 0) { - // ignore From-lines that might appear at the start of a message - if (length < 5 || !IsMboxMarker (start, true)) { - // not a From-line... + if (headers.Count == 0) { + if (state == MimeParserState.MessageHeaders) { + // ignore From-lines that might appear at the start of a message + if (toplevel && (length < 5 || !IsMboxMarker (start, true))) { + // not a From-line... + inputIndex = (int) (start - inbuf); + state = MimeParserState.Error; + headerIndex = 0; + return false; + } + } else if (toplevel && state == MimeParserState.Headers) { inputIndex = (int) (start - inbuf); state = MimeParserState.Error; headerIndex = 0; @@ -825,6 +938,10 @@ unsafe bool StepHeaders (byte* inbuf, ref bool scanningFieldName, ref bool check break; } + prevLineBeginOffset = lineBeginOffset; + lineBeginOffset = GetOffset ((int) (inptr - inbuf) + 1); + lineNumber++; + // check to see if we've reached the end of the headers if (!midline && IsEoln (start)) { inputIndex = (int) (inptr - inbuf) + 1; @@ -836,18 +953,30 @@ unsafe bool StepHeaders (byte* inbuf, ref bool scanningFieldName, ref bool check length = (inptr + 1) - start; - if (!valid && headers.Count == 0 && length > 5 && IsMboxMarker (start, true)) { - if (inptr[-1] == (byte) '\r') + if ((boundary = CheckBoundary ((int) (start - inbuf), start, (int) length)) != BoundaryType.None) { + inputIndex = (int) (start - inbuf); + state = MimeParserState.Boundary; + headerIndex = 0; + return false; + } + + if (!valid && headers.Count == 0) { + if (length > 0 && preHeaderLength == 0) { + if (inptr[-1] == (byte) '\r') + length--; length--; - length--; - preHeaderLength = (int) length; + preHeaderLength = (int) length; - if (preHeaderLength > preHeaderBuffer.Length) - Array.Resize (ref preHeaderBuffer, NextAllocSize (preHeaderLength)); + if (preHeaderLength > preHeaderBuffer.Length) + Array.Resize (ref preHeaderBuffer, NextAllocSize (preHeaderLength)); - Buffer.BlockCopy (input, (int) (start - inbuf), preHeaderBuffer, 0, preHeaderLength); + Buffer.BlockCopy (input, (int) (start - inbuf), preHeaderBuffer, 0, preHeaderLength); + } + scanningFieldName = true; checkFolded = false; + blank = false; + valid = true; } else { AppendRawHeaderData ((int) (start - inbuf), (int) length); checkFolded = true; @@ -874,34 +1003,50 @@ unsafe void StepHeaders (byte* inbuf, CancellationToken cancellationToken) bool valid = true; int left = 0; + headerBlockBegin = GetOffset (inputIndex); + boundary = BoundaryType.None; ResetRawHeaderData (); headers.Clear (); - ReadAhead (Math.Max (ReadAheadSize, left), 0, cancellationToken); + ReadAhead (ReadAheadSize, 0, cancellationToken); do { if (!StepHeaders (inbuf, ref scanningFieldName, ref checkFolded, ref midline, ref blank, ref valid, ref left)) - return; + break; var available = ReadAhead (left + 1, 0, cancellationToken); - if (available == 0) { + if (available == left) { // EOF reached before we reached the end of the headers... - if (left > 0) { - AppendRawHeaderData (inputIndex, left); - inputIndex = inputEnd; - } + if (scanningFieldName && left > 0) { + // EOF reached right in the middle of a header field name. Throw an error. + // + // See private email from Feb 8, 2018 which contained a sample message w/o + // any breaks between the header and message body. The file also did not + // end with a newline sequence. + state = MimeParserState.Error; + } else { + // EOF reached somewhere in the middle of the value. + // + // Append whatever data we've got left and pretend we found the end + // of the header value (and the header block). + // + // For more details, see https://github.com/jstedfast/MimeKit/pull/51 + // and https://github.com/jstedfast/MimeKit/issues/348 + if (left > 0) { + AppendRawHeaderData (inputIndex, left); + inputIndex = inputEnd; + } - ParseAndAppendHeader (); + ParseAndAppendHeader (); - // fail gracefully by pretending we found the end of the headers... - // - // For more details, see https://github.com/jstedfast/MimeKit/pull/51 - // and https://github.com/jstedfast/MimeKit/issues/348 - state = MimeParserState.Content; - return; + state = MimeParserState.Content; + } + break; } } while (true); + + headerBlockEnd = GetOffset (inputIndex); } unsafe bool SkipLine (byte* inbuf, bool consumeNewLine) @@ -919,6 +1064,9 @@ unsafe bool SkipLine (byte* inbuf, bool consumeNewLine) if (consumeNewLine) { inputIndex++; + lineNumber++; + prevLineBeginOffset = lineBeginOffset; + lineBeginOffset = GetOffset (inputIndex); } else if (*(inptr - 1) == (byte) '\r') { inputIndex--; } @@ -959,6 +1107,7 @@ unsafe MimeParserState Step (byte* inbuf, CancellationToken cancellationToken) case MimeParserState.MessageHeaders: case MimeParserState.Headers: StepHeaders (inbuf, cancellationToken); + toplevel = false; break; } @@ -967,8 +1116,6 @@ unsafe MimeParserState Step (byte* inbuf, CancellationToken cancellationToken) ContentType GetContentType (ContentType parent) { - ContentType type; - for (int i = 0; i < headers.Count; i++) { if (!headers[i].Field.Equals ("Content-Type", StringComparison.OrdinalIgnoreCase)) continue; @@ -976,7 +1123,7 @@ ContentType GetContentType (ContentType parent) var rawValue = headers[i].RawValue; int index = 0; - if (!ContentType.TryParse (options, rawValue, ref index, rawValue.Length, false, out type) && type == null) { + if (!ContentType.TryParse (options, rawValue, ref index, rawValue.Length, false, out var type) && type == null) { // if 'type' is null, then it means that even the mime-type was unintelligible type = new ContentType ("application", "octet-stream"); @@ -985,9 +1132,7 @@ ContentType GetContentType (ContentType parent) index++; if (++index < rawValue.Length) { - ParameterList parameters; - - if (ParameterList.TryParse (options, rawValue, ref index, rawValue.Length, false, out parameters)) + if (ParameterList.TryParse (options, rawValue, ref index, rawValue.Length, false, out var parameters)) type.Parameters = parameters; } } @@ -1046,20 +1191,35 @@ static unsafe bool IsBoundary (byte* text, int length, byte[] boundary, int boun unsafe BoundaryType CheckBoundary (int startIndex, byte* start, int length) { + int count = bounds.Count; + if (!IsPossibleBoundary (start, length)) return BoundaryType.None; - long curOffset = GetOffset (startIndex); - for (int i = 0; i < bounds.Count; i++) { + if (contentEnd > 0) { + // We'll need to special-case checking for the mbox From-marker when respecting Content-Length + count--; + } + + for (int i = 0; i < count; i++) { var boundary = bounds[i]; - if (curOffset >= boundary.ContentEnd && IsBoundary (start, length, boundary.Marker, boundary.FinalLength)) + if (IsBoundary (start, length, boundary.Marker, boundary.FinalLength)) return i == 0 ? BoundaryType.ImmediateEndBoundary : BoundaryType.ParentEndBoundary; if (IsBoundary (start, length, boundary.Marker, boundary.Length)) return i == 0 ? BoundaryType.ImmediateBoundary : BoundaryType.ParentBoundary; } + if (contentEnd > 0) { + // now it is time to check the mbox From-marker for the Content-Length case + long curOffset = GetOffset (startIndex); + var boundary = bounds[count]; + + if (curOffset >= contentEnd && IsBoundary (start, length, boundary.Marker, boundary.Length)) + return BoundaryType.ImmediateEndBoundary; + } + return BoundaryType.None; } @@ -1083,7 +1243,7 @@ int GetMaxBoundaryLength () return bounds.Count > 0 ? bounds[0].MaxLength + 2 : 0; } - unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref bool midline, ref BoundaryType found) + unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref bool midline, ref bool[] formats) { int length = inputEnd - inputIndex; byte* inptr = inbuf + inputIndex; @@ -1093,7 +1253,7 @@ unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref b contentIndex = inputIndex; if (midline && length == nleft) - found = BoundaryType.Eos; + boundary = BoundaryType.Eos; *inend = (byte) '\n'; @@ -1111,7 +1271,7 @@ unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref b *aligned = c; if (inptr == aligned && c != (byte) '\n') { - // -funroll-loops, bitches. + // -funroll-loops, yippee ki-yay. uint* dword = (uint*) inptr; do { @@ -1127,23 +1287,30 @@ unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref b length = (int) (inptr - start); if (inptr < inend) { - found = CheckBoundary (startIndex, start, length); - if (found != BoundaryType.None) + if ((boundary = CheckBoundary (startIndex, start, length)) != BoundaryType.None) break; + if (length > 0 && *(inptr - 1) == (byte) '\r') + formats[(int) NewLineFormat.Dos] = true; + else + formats[(int) NewLineFormat.Unix] = true; + + lineNumber++; length++; inptr++; + + prevLineBeginOffset = lineBeginOffset; + lineBeginOffset = GetOffset ((int) (inptr - inbuf)); } else { // didn't find the end of the line... midline = true; - if (found == BoundaryType.None) { + if (boundary == BoundaryType.None) { // not enough to tell if we found a boundary break; } - found = CheckBoundary (startIndex, start, length); - if (found != BoundaryType.None) + if ((boundary = CheckBoundary (startIndex, start, length)) != BoundaryType.None) break; } @@ -1153,11 +1320,30 @@ unsafe void ScanContent (byte* inbuf, ref int contentIndex, ref int nleft, ref b inputIndex = startIndex; } - unsafe BoundaryType ScanContent (byte* inbuf, Stream content, bool trimNewLine, out bool empty, CancellationToken cancellationToken) + class ScanContentResult + { + public readonly NewLineFormat? Format; + public readonly bool IsEmpty; + + public ScanContentResult (bool[] formats, bool isEmpty) + { + if (formats[(int) NewLineFormat.Unix] && formats[(int) NewLineFormat.Dos]) + Format = NewLineFormat.Mixed; + else if (formats[(int) NewLineFormat.Unix]) + Format = NewLineFormat.Unix; + else if (formats[(int) NewLineFormat.Dos]) + Format = NewLineFormat.Dos; + else + Format = null; + IsEmpty = isEmpty; + } + } + + unsafe ScanContentResult ScanContent (byte* inbuf, Stream content, bool trimNewLine, CancellationToken cancellationToken) { int atleast = Math.Max (ReadAheadSize, GetMaxBoundaryLength ()); - BoundaryType found = BoundaryType.None; int contentIndex = inputIndex; + var formats = new bool[2]; bool midline = false; int nleft; @@ -1167,20 +1353,20 @@ unsafe BoundaryType ScanContent (byte* inbuf, Stream content, bool trimNewLine, nleft = inputEnd - inputIndex; if (ReadAhead (atleast, 2, cancellationToken) <= 0) { + boundary = BoundaryType.Eos; contentIndex = inputIndex; - found = BoundaryType.Eos; break; } - ScanContent (inbuf, ref contentIndex, ref nleft, ref midline, ref found); - } while (found == BoundaryType.None); + ScanContent (inbuf, ref contentIndex, ref nleft, ref midline, ref formats); + } while (boundary == BoundaryType.None); if (contentIndex < inputIndex) content.Write (input, contentIndex, inputIndex - contentIndex); - empty = content.Length == 0; + var isEmpty = content.Length == 0; - if (found != BoundaryType.Eos && trimNewLine) { + if (boundary != BoundaryType.Eos && trimNewLine) { // the last \r\n belongs to the boundary if (content.Length > 0) { if (input[inputIndex - 2] == (byte) '\r') @@ -1190,46 +1376,57 @@ unsafe BoundaryType ScanContent (byte* inbuf, Stream content, bool trimNewLine, } } - return found; + return new ScanContentResult (formats, isEmpty); } - unsafe BoundaryType ConstructMimePart (MimePart part, byte* inbuf, CancellationToken cancellationToken) + unsafe void ConstructMimePart (MimePart part, MimeEntityEndEventArgs args, byte* inbuf, CancellationToken cancellationToken) { - BoundaryType found; + long endOffset, beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; + ScanContentResult result; Stream content; - bool empty; if (persistent) { - long begin = GetOffset (inputIndex); - long end; - using (var measured = new MeasuringStream ()) { - found = ScanContent (inbuf, measured, true, out empty, cancellationToken); - end = begin + measured.Length; + result = ScanContent (inbuf, measured, true, cancellationToken); + endOffset = beginOffset + measured.Length; } - content = new BoundStream (stream, begin, end, true); + content = new BoundStream (stream, beginOffset, endOffset, true); } else { content = new MemoryBlockStream (); - found = ScanContent (inbuf, content, true, out empty, cancellationToken); - content.Seek (0, SeekOrigin.Begin); + + try { + result = ScanContent (inbuf, content, true, cancellationToken); + content.Seek (0, SeekOrigin.Begin); + } catch { + content.Dispose (); + throw; + } + + endOffset = beginOffset + content.Length; } - if (!empty) - part.Content = new MimeContent (content, part.ContentTransferEncoding); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); - return found; + if (!result.IsEmpty) + part.Content = new MimeContent (content, part.ContentTransferEncoding) { NewLineFormat = result.Format }; + else + content.Dispose (); } - unsafe BoundaryType ConstructMessagePart (MessagePart part, byte* inbuf, CancellationToken cancellationToken) + unsafe void ConstructMessagePart (MessagePart rfc822, MimeEntityEndEventArgs args, byte* inbuf, int depth, CancellationToken cancellationToken) { - BoundaryType found; + var beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; if (bounds.Count > 0) { int atleast = Math.Max (ReadAheadSize, GetMaxBoundaryLength ()); - if (ReadAhead (atleast, 0, cancellationToken) <= 0) - return BoundaryType.Eos; + if (ReadAhead (atleast, 0, cancellationToken) <= 0) { + boundary = BoundaryType.Eos; + return; + } byte* start = inbuf + inputIndex; byte* inend = inbuf + inputEnd; @@ -1240,106 +1437,168 @@ unsafe BoundaryType ConstructMessagePart (MessagePart part, byte* inbuf, Cancell while (*inptr != (byte) '\n') inptr++; - found = CheckBoundary (inputIndex, start, (int) (inptr - start)); + boundary = CheckBoundary (inputIndex, start, (int) (inptr - start)); - switch (found) { + switch (boundary) { case BoundaryType.ImmediateEndBoundary: case BoundaryType.ImmediateBoundary: case BoundaryType.ParentBoundary: - return found; + return; case BoundaryType.ParentEndBoundary: // ignore "From " boundaries, broken mailers tend to include these... - if (!IsMboxMarker (start)) - return found; + if (!IsMboxMarker (start)) { + return; + } break; } } // parse the headers... - state = MimeParserState.Headers; + state = MimeParserState.MessageHeaders; if (Step (inbuf, cancellationToken) == MimeParserState.Error) { // Note: this either means that StepHeaders() found the end of the stream // or an invalid header field name at the start of the message headers, // which likely means that this is not a valid MIME stream? - return BoundaryType.Eos; + boundary = BoundaryType.Eos; + return; } var message = new MimeMessage (options, headers, RfcComplianceMode.Loose); - var type = GetContentType (null); + var messageArgs = new MimeMessageEndEventArgs (message, rfc822) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeMessageBegin (messageArgs); if (preHeaderBuffer.Length > 0) { message.MboxMarker = new byte[preHeaderLength]; Buffer.BlockCopy (preHeaderBuffer, 0, message.MboxMarker, 0, preHeaderLength); } - var entity = options.CreateEntity (type, headers, true); + var type = GetContentType (null); + var entity = options.CreateEntity (type, headers, true, depth); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + message.Body = entity; if (entity is Multipart) - found = ConstructMultipart ((Multipart) entity, inbuf, cancellationToken); + ConstructMultipart ((Multipart) entity, entityArgs, inbuf, depth + 1, cancellationToken); else if (entity is MessagePart) - found = ConstructMessagePart ((MessagePart) entity, inbuf, cancellationToken); + ConstructMessagePart ((MessagePart) entity, entityArgs, inbuf, depth + 1, cancellationToken); else - found = ConstructMimePart ((MimePart) entity, inbuf, cancellationToken); + ConstructMimePart ((MimePart) entity, entityArgs, inbuf, cancellationToken); - part.Message = message; + rfc822.Message = message; - return found; + var endOffset = GetEndOffset (inputIndex); + messageArgs.HeadersEndOffset = entityArgs.HeadersEndOffset = Math.Min(entityArgs.HeadersEndOffset, endOffset); + messageArgs.EndOffset = entityArgs.EndOffset = endOffset; + + OnMimeEntityEnd (entityArgs); + OnMimeMessageEnd (messageArgs); + + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); } - unsafe BoundaryType MultipartScanPreamble (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) + unsafe void MultipartScanPreamble (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) { using (var memory = new MemoryStream ()) { - bool empty; + long offset = GetOffset (inputIndex); - var found = ScanContent (inbuf, memory, false, out empty, cancellationToken); + //OnMultipartPreambleBegin (multipart, offset); + ScanContent (inbuf, memory, false, cancellationToken); multipart.RawPreamble = memory.ToArray (); - return found; + //OnMultipartPreambleEnd (multipart, offset + memory.Length); } } - unsafe BoundaryType MultipartScanEpilogue (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) + unsafe void MultipartScanEpilogue (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) { using (var memory = new MemoryStream ()) { - bool empty; + long offset = GetOffset (inputIndex); - var found = ScanContent (inbuf, memory, true, out empty, cancellationToken); - multipart.RawEpilogue = empty ? null : memory.ToArray (); - return found; + //OnMultipartEpilogueBegin (multipart, offset); + var result = ScanContent (inbuf, memory, true, cancellationToken); + multipart.RawEpilogue = result.IsEmpty ? null : memory.ToArray (); + //OnMultipartEpilogueEnd (multipart, offset + memory.Length); } } - unsafe BoundaryType MultipartScanSubparts (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) + unsafe void MultipartScanSubparts (Multipart multipart, byte* inbuf, int depth, CancellationToken cancellationToken) { - BoundaryType found; + //var beginOffset = GetOffset (inputIndex); do { + //OnMultipartBoundaryBegin (multipart, beginOffset); + // skip over the boundary marker - if (!SkipLine (inbuf, true, cancellationToken)) - return BoundaryType.Eos; + if (!SkipLine (inbuf, true, cancellationToken)) { + //OnMultipartBoundaryEnd (multipart, GetOffset (inputIndex)); + boundary = BoundaryType.Eos; + return; + } + + //OnMultipartBoundaryEnd (multipart, GetOffset (inputIndex)); + + var beginLineNumber = lineNumber; // parse the headers state = MimeParserState.Headers; - if (Step (inbuf, cancellationToken) == MimeParserState.Error) - return BoundaryType.Eos; + if (Step (inbuf, cancellationToken) == MimeParserState.Error) { + boundary = BoundaryType.Eos; + return; + } + + if (state == MimeParserState.Boundary) { + if (headers.Count == 0) { + if (boundary == BoundaryType.ImmediateBoundary) { + //beginOffset = GetOffset (inputIndex); + continue; + } + return; + } + + // This part has no content, but that will be handled in ConstructMultipart() + // or ConstructMimePart(). + } //if (state == ParserState.Complete && headers.Count == 0) // return BoundaryType.EndBoundary; var type = GetContentType (multipart.ContentType); - var entity = options.CreateEntity (type, headers, false); + var entity = options.CreateEntity (type, headers, false, depth); + var entityArgs = new MimeEntityEndEventArgs (entity, multipart) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); if (entity is Multipart) - found = ConstructMultipart ((Multipart) entity, inbuf, cancellationToken); + ConstructMultipart ((Multipart) entity, entityArgs, inbuf, depth + 1, cancellationToken); else if (entity is MessagePart) - found = ConstructMessagePart ((MessagePart) entity, inbuf, cancellationToken); + ConstructMessagePart ((MessagePart) entity, entityArgs, inbuf, depth + 1, cancellationToken); else - found = ConstructMimePart ((MimePart) entity, inbuf, cancellationToken); + ConstructMimePart ((MimePart) entity, entityArgs, inbuf, cancellationToken); - multipart.Add (entity); - } while (found == BoundaryType.ImmediateBoundary); + var endOffset = GetEndOffset (inputIndex); + entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + entityArgs.EndOffset = endOffset; + + OnMimeEntityEnd (entityArgs); - return found; + //beginOffset = endOffset; + multipart.Add (entity); + } while (boundary == BoundaryType.ImmediateBoundary); } void PushBoundary (string boundary) @@ -1355,46 +1614,61 @@ void PopBoundary () bounds.RemoveAt (0); } - unsafe BoundaryType ConstructMultipart (Multipart multipart, byte* inbuf, CancellationToken cancellationToken) + unsafe void ConstructMultipart (Multipart multipart, MimeEntityEndEventArgs args, byte* inbuf, int depth, CancellationToken cancellationToken) { - var boundary = multipart.Boundary; + var beginOffset = GetOffset (inputIndex); + var beginLineNumber = lineNumber; + var marker = multipart.Boundary; + long endOffset; - if (boundary == null) { + if (marker == null) { #if DEBUG Debug.WriteLine ("Multipart without a boundary encountered!"); #endif // Note: this will scan all content into the preamble... - return MultipartScanPreamble (multipart, inbuf, cancellationToken); + MultipartScanPreamble (multipart, inbuf, cancellationToken); + + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + return; } - PushBoundary (boundary); + PushBoundary (marker); + + MultipartScanPreamble (multipart, inbuf, cancellationToken); + if (boundary == BoundaryType.ImmediateBoundary) + MultipartScanSubparts (multipart, inbuf, depth, cancellationToken); - var found = MultipartScanPreamble (multipart, inbuf, cancellationToken); - if (found == BoundaryType.ImmediateBoundary) - found = MultipartScanSubparts (multipart, inbuf, cancellationToken); + if (boundary == BoundaryType.ImmediateEndBoundary) { + //OnMultipartEndBoundaryBegin (multipart, GetEndOffset (inputIndex)); - if (found == BoundaryType.ImmediateEndBoundary) { // consume the end boundary and read the epilogue (if there is one) multipart.WriteEndBoundary = true; SkipLine (inbuf, false, cancellationToken); PopBoundary (); - return MultipartScanEpilogue (multipart, inbuf, cancellationToken); + //OnMultipartEndBoundaryEnd (multipart, GetOffset (inputIndex)); + + MultipartScanEpilogue (multipart, inbuf, cancellationToken); + + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + return; } + endOffset = GetEndOffset (inputIndex); + args.Lines = GetLineCount (beginLineNumber, beginOffset, endOffset); + multipart.WriteEndBoundary = false; // We either found the end of the stream or we found a parent's boundary PopBoundary (); - if (found == BoundaryType.ParentEndBoundary && FoundImmediateBoundary (inbuf, true)) - return BoundaryType.ImmediateEndBoundary; - - if (found == BoundaryType.ParentBoundary && FoundImmediateBoundary (inbuf, false)) - return BoundaryType.ImmediateBoundary; - - return found; + if (boundary == BoundaryType.ParentEndBoundary && FoundImmediateBoundary (inbuf, true)) + boundary = BoundaryType.ImmediateEndBoundary; + else if (boundary == BoundaryType.ParentBoundary && FoundImmediateBoundary (inbuf, false)) + boundary = BoundaryType.ImmediateBoundary; } unsafe HeaderList ParseHeaders (byte* inbuf, CancellationToken cancellationToken) @@ -1443,31 +1717,48 @@ unsafe MimeEntity ParseEntity (byte* inbuf, CancellationToken cancellationToken) // Note: if a previously parsed MimePart's content has been read, // then the stream position will have moved and will need to be // reset. - if (persistent && stream.Position != offset) - stream.Seek (offset, SeekOrigin.Begin); + if (persistent && stream.Position != position) + stream.Seek (position, SeekOrigin.Begin); + + var beginLineNumber = lineNumber; state = MimeParserState.Headers; + toplevel = true; + if (Step (inbuf, cancellationToken) == MimeParserState.Error) throw new FormatException ("Failed to parse entity headers."); var type = GetContentType (null); - BoundaryType found; // Note: we pass 'false' as the 'toplevel' argument here because // we want the entity to consume all of the headers. - var entity = options.CreateEntity (type, headers, false); + var entity = options.CreateEntity (type, headers, false, 0); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + if (entity is Multipart) - found = ConstructMultipart ((Multipart) entity, inbuf, cancellationToken); + ConstructMultipart ((Multipart) entity, entityArgs, inbuf, 0, cancellationToken); else if (entity is MessagePart) - found = ConstructMessagePart ((MessagePart) entity, inbuf, cancellationToken); + ConstructMessagePart ((MessagePart) entity, entityArgs, inbuf, 0, cancellationToken); else - found = ConstructMimePart ((MimePart) entity, inbuf, cancellationToken); + ConstructMimePart ((MimePart) entity, entityArgs, inbuf, cancellationToken); + + var endOffset = GetEndOffset (inputIndex); + entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + entityArgs.EndOffset = endOffset; - if (found != BoundaryType.Eos) + if (boundary != BoundaryType.Eos) state = MimeParserState.Complete; else state = MimeParserState.Eos; + OnMimeEntityEnd (entityArgs); + return entity; } @@ -1499,13 +1790,11 @@ unsafe MimeEntity ParseEntity (byte* inbuf, CancellationToken cancellationToken) unsafe MimeMessage ParseMessage (byte* inbuf, CancellationToken cancellationToken) { - BoundaryType found; - // Note: if a previously parsed MimePart's content has been read, // then the stream position will have moved and will need to be // reset. - if (persistent && stream.Position != offset) - stream.Seek (offset, SeekOrigin.Begin); + if (persistent && stream.Position != position) + stream.Seek (position, SeekOrigin.Begin); // scan the from-line if we are parsing an mbox while (state != MimeParserState.MessageHeaders) { @@ -1517,44 +1806,66 @@ unsafe MimeMessage ParseMessage (byte* inbuf, CancellationToken cancellationToke } } + toplevel = true; + // parse the headers + var beginLineNumber = lineNumber; if (state < MimeParserState.Content && Step (inbuf, cancellationToken) == MimeParserState.Error) throw new FormatException ("Failed to parse message headers."); var message = new MimeMessage (options, headers, RfcComplianceMode.Loose); + var messageArgs = new MimeMessageEndEventArgs (message) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; - if (format == MimeFormat.Mbox && options.RespectContentLength) { - bounds[0].ContentEnd = -1; + OnMimeMessageBegin (messageArgs); + contentEnd = 0; + if (format == MimeFormat.Mbox && options.RespectContentLength) { for (int i = 0; i < headers.Count; i++) { - if (!headers[i].Field.Equals ("Content-Length", StringComparison.OrdinalIgnoreCase)) + if (headers[i].Id != HeaderId.ContentLength) continue; var value = headers[i].RawValue; - int length, index = 0; + int index = 0; - if (!ParseUtils.TryParseInt32 (value, ref index, value.Length, out length)) + if (!ParseUtils.SkipWhiteSpace (value, ref index, value.Length)) continue; - long endOffset = GetOffset (inputIndex) + length; + if (!ParseUtils.TryParseInt32 (value, ref index, value.Length, out int length)) + continue; - bounds[0].ContentEnd = endOffset; + contentEnd = GetOffset (inputIndex) + length; break; } } var type = GetContentType (null); - var entity = options.CreateEntity (type, headers, true); + var entity = options.CreateEntity (type, headers, true, 0); + var entityArgs = new MimeEntityEndEventArgs (entity) { + HeadersEndOffset = headerBlockEnd, + BeginOffset = headerBlockBegin, + LineNumber = beginLineNumber + }; + + OnMimeEntityBegin (entityArgs); + message.Body = entity; - if (entity is Multipart) - found = ConstructMultipart ((Multipart) entity, inbuf, cancellationToken); - else if (entity is MessagePart) - found = ConstructMessagePart ((MessagePart) entity, inbuf, cancellationToken); + if (entity is Multipart multipart) + ConstructMultipart (multipart, entityArgs, inbuf, 0, cancellationToken); + else if (entity is MessagePart rfc822) + ConstructMessagePart (rfc822, entityArgs, inbuf, 0, cancellationToken); else - found = ConstructMimePart ((MimePart) entity, inbuf, cancellationToken); + ConstructMimePart ((MimePart) entity, entityArgs, inbuf, cancellationToken); - if (found != BoundaryType.Eos) { + var endOffset = GetEndOffset (inputIndex); + messageArgs.HeadersEndOffset = entityArgs.HeadersEndOffset = Math.Min (entityArgs.HeadersEndOffset, endOffset); + messageArgs.EndOffset = entityArgs.EndOffset = endOffset; + + if (boundary != BoundaryType.Eos) { if (format == MimeFormat.Mbox) state = MimeParserState.MboxMarker; else @@ -1563,6 +1874,9 @@ unsafe MimeMessage ParseMessage (byte* inbuf, CancellationToken cancellationToke state = MimeParserState.Eos; } + OnMimeEntityEnd (entityArgs); + OnMimeMessageEnd (messageArgs); + return message; } diff --git a/MimeKit/MimePart.cs b/MimeKit/MimePart.cs index 7a7617f231..a8a9450bda 100644 --- a/MimeKit/MimePart.cs +++ b/MimeKit/MimePart.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -30,17 +30,12 @@ using System.Threading; using System.Threading.Tasks; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -using MD5 = MimeKit.Cryptography.MD5; -#else using MD5 = System.Security.Cryptography.MD5; -#endif -using MimeKit.IO.Filters; -using MimeKit.Encodings; -using MimeKit.Utils; using MimeKit.IO; +using MimeKit.Utils; +using MimeKit.Encodings; +using MimeKit.IO.Filters; namespace MimeKit { /// @@ -62,11 +57,11 @@ public class MimePart : MimeEntity int? duration; /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// based on the . /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -77,7 +72,7 @@ public MimePart (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// with the specified media type and subtype. /// /// @@ -94,7 +89,7 @@ public MimePart (MimeEntityConstructorArgs args) : base (args) /// is null. /// /// - /// contains more than one or + /// contains more than one or /// . /// -or- /// contains one or more arguments of an unknown type. @@ -110,17 +105,15 @@ public MimePart (string mediaType, string mediaSubtype, params object[] args) : if (obj == null || TryInit (obj)) continue; - var co = obj as IMimeContent; - if (co != null) { + if (obj is IMimeContent co) { if (content != null) - throw new ArgumentException ("ContentObject should not be specified more than once."); + throw new ArgumentException ("IMimeContent should not be specified more than once."); content = co; continue; } - var stream = obj as Stream; - if (stream != null) { + if (obj is Stream stream) { if (content != null) throw new ArgumentException ("Stream (used as content) should not be specified more than once."); @@ -137,7 +130,7 @@ public MimePart (string mediaType, string mediaSubtype, params object[] args) : } /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// with the specified media type and subtype. /// /// @@ -155,7 +148,7 @@ public MimePart (string mediaType, string mediaSubtype) : base (mediaType, media } /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// with the specified content type. /// /// @@ -170,7 +163,7 @@ public MimePart (ContentType contentType) : base (contentType) } /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// with the specified content type. /// /// @@ -188,7 +181,7 @@ public MimePart (string contentType) : base (ContentType.Parse (contentType)) } /// - /// Initializes a new instance of the class + /// Initialize a new instance of the class /// with the default Content-Type of application/octet-stream. /// /// @@ -358,12 +351,12 @@ public IMimeContent ContentObject { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -423,20 +416,24 @@ public override void Accept (MimeVisitor visitor) /// public ContentEncoding GetBestEncoding (EncodingConstraint constraint, int maxLineLength, CancellationToken cancellationToken = default (CancellationToken)) { - if (Content == null) - return ContentEncoding.SevenBit; + if (ContentType.IsMimeType ("text", "*") || ContentType.IsMimeType ("message", "*")) { + if (Content == null) + return ContentEncoding.SevenBit; - using (var measure = new MeasuringStream ()) { - using (var filtered = new FilteredStream (measure)) { - var filter = new BestEncodingFilter (); + using (var measure = new MeasuringStream ()) { + using (var filtered = new FilteredStream (measure)) { + var filter = new BestEncodingFilter (); - filtered.Add (filter); - Content.DecodeTo (filtered, cancellationToken); - filtered.Flush (); + filtered.Add (filter); + Content.DecodeTo (filtered, cancellationToken); + filtered.Flush (); - return filter.GetBestEncoding (constraint, maxLineLength); + return filter.GetBestEncoding (constraint, maxLineLength); + } } } + + return constraint == EncodingConstraint.None ? ContentEncoding.Binary : ContentEncoding.Base64; } /// @@ -504,18 +501,6 @@ public bool VerifyContentMd5 () return md5sum == ComputeContentMd5 (); } - static bool NeedsEncoding (ContentEncoding encoding) - { - switch (encoding) { - case ContentEncoding.EightBit: - case ContentEncoding.Binary: - case ContentEncoding.Default: - return true; - default: - return false; - } - } - /// /// Prepare the MIME entity for transport using the specified encoding constraints. /// @@ -557,7 +542,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } /// - /// Writes the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the MIME part to the output stream. @@ -624,7 +609,16 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length); } } - } else if (encoding != ContentEncoding.Binary) { + } else if (encoding == ContentEncoding.Binary) { + // Do not alter binary content. + Content.WriteTo (stream, cancellationToken); + } else if (options.VerifyingSignature && Content.NewLineFormat.HasValue && Content.NewLineFormat.Value == NewLineFormat.Mixed) { + // Allow pass-through of the original parsed content without canonicalization when verifying signatures + // if the content contains a mix of line-endings. + // + // See https://github.com/jstedfast/MimeKit/issues/569 for details. + Content.WriteTo (stream, cancellationToken); + } else { using (var filtered = new FilteredStream (stream)) { // Note: if we are writing the top-level MimePart, make sure it ends with a new-line so that // MimeMessage.WriteTo() *always* ends with a new-line. @@ -632,17 +626,16 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = Content.WriteTo (filtered, cancellationToken); filtered.Flush (cancellationToken); } - } else { - Content.WriteTo (stream, cancellationToken); } } /// - /// Asynchronously writes the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the MIME part to the output stream. + /// Asynchronously writes the MIME part to the output stream. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// true if only the content should be written; otherwise, false. @@ -665,6 +658,8 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = if (Content == null) return; + var isText = ContentType.IsMimeType ("text", "*") || ContentType.IsMimeType ("message", "*"); + if (Content.Encoding != encoding) { if (encoding == ContentEncoding.UUEncode) { var begin = string.Format ("begin 0644 {0}", FileName ?? "unknown"); @@ -691,7 +686,16 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = await stream.WriteAsync (buffer, 0, buffer.Length, cancellationToken).ConfigureAwait (false); await stream.WriteAsync (options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken).ConfigureAwait (false); } - } else if (encoding != ContentEncoding.Binary) { + } else if (encoding == ContentEncoding.Binary) { + // Do not alter binary content. + await Content.WriteToAsync (stream, cancellationToken).ConfigureAwait (false); + } else if (options.VerifyingSignature && Content.NewLineFormat.HasValue && Content.NewLineFormat.Value == NewLineFormat.Mixed) { + // Allow pass-through of the original parsed content without canonicalization when verifying signatures + // if the content contains a mix of line-endings. + // + // See https://github.com/jstedfast/MimeKit/issues/569 for details. + await Content.WriteToAsync (stream, cancellationToken).ConfigureAwait (false); + } else { using (var filtered = new FilteredStream (stream)) { // Note: if we are writing the top-level MimePart, make sure it ends with a new-line so that // MimeMessage.WriteTo() *always* ends with a new-line. @@ -699,8 +703,6 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = await Content.WriteToAsync (filtered, cancellationToken).ConfigureAwait (false); await filtered.FlushAsync (cancellationToken).ConfigureAwait (false); } - } else { - await Content.WriteToAsync (stream, cancellationToken).ConfigureAwait (false); } } diff --git a/MimeKit/MimeTypes.cs b/MimeKit/MimeTypes.cs index 6fbcb584e8..957248b831 100644 --- a/MimeKit/MimeTypes.cs +++ b/MimeKit/MimeTypes.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ // using System; +using System.IO; using System.Collections.Generic; using MimeKit.Utils; @@ -38,570 +39,959 @@ namespace MimeKit { /// public static class MimeTypes { + static readonly Dictionary extensions; static readonly Dictionary mimeTypes; static MimeTypes () { - mimeTypes = new Dictionary (MimeUtils.OrdinalIgnoreCase); - mimeTypes.Add ("323", "text/h323"); - mimeTypes.Add ("3dmf", "x-world/x-3dmf"); - mimeTypes.Add ("3dm", "x-world/x-3dmf"); - mimeTypes.Add ("3g2", "video/3gpp2"); - mimeTypes.Add ("3gp", "video/3gpp"); - mimeTypes.Add ("7z", "application/x-7z-compressed"); - mimeTypes.Add ("aab", "application/x-authorware-bin"); - mimeTypes.Add ("aac", "audio/aac"); - mimeTypes.Add ("aam", "application/x-authorware-map"); - mimeTypes.Add ("aas", "application/x-authorware-seg"); - mimeTypes.Add ("abc", "text/vnd.abc"); - mimeTypes.Add ("acgi", "text/html"); - mimeTypes.Add ("acx", "application/internet-property-stream"); - mimeTypes.Add ("afl", "video/animaflex"); - mimeTypes.Add ("ai", "application/postscript"); - mimeTypes.Add ("aif", "audio/aiff"); - mimeTypes.Add ("aifc", "audio/aiff"); - mimeTypes.Add ("aiff", "audio/aiff"); - mimeTypes.Add ("aim", "application/x-aim"); - mimeTypes.Add ("aip", "text/x-audiosoft-intra"); - mimeTypes.Add ("ani", "application/x-navi-animation"); - mimeTypes.Add ("aos", "application/x-nokia-9000-communicator-add-on-software"); - mimeTypes.Add ("appcache", "text/cache-manifest"); - mimeTypes.Add ("application", "application/x-ms-application"); - mimeTypes.Add ("aps", "application/mime"); - mimeTypes.Add ("art", "image/x-jg"); - mimeTypes.Add ("asf", "video/x-ms-asf"); - mimeTypes.Add ("asm", "text/x-asm"); - mimeTypes.Add ("asp", "text/asp"); - mimeTypes.Add ("asr", "video/x-ms-asf"); - mimeTypes.Add ("asx", "application/x-mplayer2"); - mimeTypes.Add ("atom", "application/atom+xml"); - mimeTypes.Add ("au", "audio/x-au"); - mimeTypes.Add ("avi", "video/avi"); - mimeTypes.Add ("avs", "video/avs-video"); - mimeTypes.Add ("axs", "application/olescript"); - mimeTypes.Add ("bas", "text/plain"); - mimeTypes.Add ("bcpio", "application/x-bcpio"); - mimeTypes.Add ("bin", "application/octet-stream"); - mimeTypes.Add ("bm", "image/bmp"); - mimeTypes.Add ("bmp", "image/bmp"); - mimeTypes.Add ("boo", "application/book"); - mimeTypes.Add ("book", "application/book"); - mimeTypes.Add ("boz", "application/x-bzip2"); - mimeTypes.Add ("bsh", "application/x-bsh"); - mimeTypes.Add ("bz2", "application/x-bzip2"); - mimeTypes.Add ("bz", "application/x-bzip"); - mimeTypes.Add ("cat", "application/vnd.ms-pki.seccat"); - mimeTypes.Add ("ccad", "application/clariscad"); - mimeTypes.Add ("cco", "application/x-cocoa"); - mimeTypes.Add ("cc", "text/plain"); - mimeTypes.Add ("cdf", "application/cdf"); - mimeTypes.Add ("cer", "application/pkix-cert"); - mimeTypes.Add ("cha", "application/x-chat"); - mimeTypes.Add ("chat", "application/x-chat"); - mimeTypes.Add ("class", "application/x-java-applet"); - mimeTypes.Add ("clp", "application/x-msclip"); - mimeTypes.Add ("cmx", "image/x-cmx"); - mimeTypes.Add ("cod", "image/cis-cod"); - mimeTypes.Add ("coffee", "text/x-coffeescript"); - mimeTypes.Add ("conf", "text/plain"); - mimeTypes.Add ("cpio", "application/x-cpio"); - mimeTypes.Add ("cpp", "text/plain"); - mimeTypes.Add ("cpt", "application/x-cpt"); - mimeTypes.Add ("crd", "application/x-mscardfile"); - mimeTypes.Add ("crl", "application/pkix-crl"); - mimeTypes.Add ("crt", "application/pkix-cert"); - mimeTypes.Add ("csh", "application/x-csh"); - mimeTypes.Add ("css", "text/css"); - mimeTypes.Add ("c", "text/plain"); - mimeTypes.Add ("c++", "text/plain"); - mimeTypes.Add ("cxx", "text/plain"); - mimeTypes.Add ("dart", "application/dart"); - mimeTypes.Add ("dcr", "application/x-director"); - mimeTypes.Add ("deb", "application/x-deb"); - mimeTypes.Add ("deepv", "application/x-deepv"); - mimeTypes.Add ("def", "text/plain"); - mimeTypes.Add ("deploy", "application/octet-stream"); - mimeTypes.Add ("der", "application/x-x509-ca-cert"); - mimeTypes.Add ("dib", "image/bmp"); - mimeTypes.Add ("dif", "video/x-dv"); - mimeTypes.Add ("dir", "application/x-director"); - mimeTypes.Add ("disco", "text/xml"); - mimeTypes.Add ("dll", "application/x-msdownload"); - mimeTypes.Add ("dl", "video/dl"); - mimeTypes.Add ("doc", "application/msword"); - mimeTypes.Add ("docm", "application/vnd.ms-word.document.macroEnabled.12"); - mimeTypes.Add ("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); - mimeTypes.Add ("dot", "application/msword"); - mimeTypes.Add ("dotm", "application/vnd.ms-word.template.macroEnabled.12"); - mimeTypes.Add ("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"); - mimeTypes.Add ("dp", "application/commonground"); - mimeTypes.Add ("drw", "application/drafting"); - mimeTypes.Add ("dtd", "application/xml-dtd"); - mimeTypes.Add ("dvi", "application/x-dvi"); - mimeTypes.Add ("dv", "video/x-dv"); - mimeTypes.Add ("dwf", "drawing/x-dwf (old)"); - mimeTypes.Add ("dwg", "application/acad"); - mimeTypes.Add ("dxf", "application/dxf"); - mimeTypes.Add ("dxr", "application/x-director"); - mimeTypes.Add ("elc", "application/x-elc"); - mimeTypes.Add ("el", "text/x-script.elisp"); - mimeTypes.Add ("eml", "message/rfc822"); - mimeTypes.Add ("eot", "application/vnd.bw-fontobject"); - mimeTypes.Add ("eps", "application/postscript"); - mimeTypes.Add ("es", "application/x-esrehber"); - mimeTypes.Add ("etx", "text/x-setext"); - mimeTypes.Add ("evy", "application/envoy"); - mimeTypes.Add ("exe", "application/octet-stream"); - mimeTypes.Add ("f77", "text/plain"); - mimeTypes.Add ("f90", "text/plain"); - mimeTypes.Add ("fdf", "application/vnd.fdf"); - mimeTypes.Add ("fif", "image/fif"); - mimeTypes.Add ("flac", "audio/x-flac"); - mimeTypes.Add ("fli", "video/fli"); - mimeTypes.Add ("flo", "image/florian"); - mimeTypes.Add ("flr", "x-world/x-vrml"); - mimeTypes.Add ("flx", "text/vnd.fmi.flexstor"); - mimeTypes.Add ("fmf", "video/x-atomic3d-feature"); - mimeTypes.Add ("for", "text/plain"); - mimeTypes.Add ("fpx", "image/vnd.fpx"); - mimeTypes.Add ("frl", "application/freeloader"); - mimeTypes.Add ("f", "text/plain"); - mimeTypes.Add ("funk", "audio/make"); - mimeTypes.Add ("g3", "image/g3fax"); - mimeTypes.Add ("gif", "image/gif"); - mimeTypes.Add ("gl", "video/gl"); - mimeTypes.Add ("gsd", "audio/x-gsm"); - mimeTypes.Add ("gsm", "audio/x-gsm"); - mimeTypes.Add ("gsp", "application/x-gsp"); - mimeTypes.Add ("gss", "application/x-gss"); - mimeTypes.Add ("gtar", "application/x-gtar"); - mimeTypes.Add ("g", "text/plain"); - mimeTypes.Add ("gz", "application/x-gzip"); - mimeTypes.Add ("gzip", "application/x-gzip"); - mimeTypes.Add ("hdf", "application/x-hdf"); - mimeTypes.Add ("help", "application/x-helpfile"); - mimeTypes.Add ("hgl", "application/vnd.hp-HPGL"); - mimeTypes.Add ("hh", "text/plain"); - mimeTypes.Add ("hlb", "text/x-script"); - mimeTypes.Add ("hlp", "application/x-helpfile"); - mimeTypes.Add ("hpg", "application/vnd.hp-HPGL"); - mimeTypes.Add ("hpgl", "application/vnd.hp-HPGL"); - mimeTypes.Add ("hqx", "application/binhex"); - mimeTypes.Add ("hta", "application/hta"); - mimeTypes.Add ("htc", "text/x-component"); - mimeTypes.Add ("h", "text/plain"); - mimeTypes.Add ("htmls", "text/html"); - mimeTypes.Add ("html", "text/html"); - mimeTypes.Add ("htm", "text/html"); - mimeTypes.Add ("htt", "text/webviewhtml"); - mimeTypes.Add ("htx", "text/html"); - mimeTypes.Add ("ice", "x-conference/x-cooltalk"); - mimeTypes.Add ("ico", "image/x-icon"); - mimeTypes.Add ("ics", "text/calendar"); - mimeTypes.Add ("idc", "text/plain"); - mimeTypes.Add ("ief", "image/ief"); - mimeTypes.Add ("iefs", "image/ief"); - mimeTypes.Add ("iges", "application/iges"); - mimeTypes.Add ("igs", "application/iges"); - mimeTypes.Add ("iii", "application/x-iphone"); - mimeTypes.Add ("ima", "application/x-ima"); - mimeTypes.Add ("imap", "application/x-httpd-imap"); - mimeTypes.Add ("inf", "application/inf"); - mimeTypes.Add ("ins", "application/x-internett-signup"); - mimeTypes.Add ("ip", "application/x-ip2"); - mimeTypes.Add ("isp", "application/x-internet-signup"); - mimeTypes.Add ("isu", "video/x-isvideo"); - mimeTypes.Add ("it", "audio/it"); - mimeTypes.Add ("iv", "application/x-inventor"); - mimeTypes.Add ("ivf", "video/x-ivf"); - mimeTypes.Add ("ivr", "i-world/i-vrml"); - mimeTypes.Add ("ivy", "application/x-livescreen"); - mimeTypes.Add ("jam", "audio/x-jam"); - mimeTypes.Add ("jar", "application/java-archive"); - mimeTypes.Add ("java", "text/plain"); - mimeTypes.Add ("jav", "text/plain"); - mimeTypes.Add ("jcm", "application/x-java-commerce"); - mimeTypes.Add ("jfif", "image/jpeg"); - mimeTypes.Add ("jfif-tbnl", "image/jpeg"); - mimeTypes.Add ("jpeg", "image/jpeg"); - mimeTypes.Add ("jpe", "image/jpeg"); - mimeTypes.Add ("jpg", "image/jpeg"); - mimeTypes.Add ("jps", "image/x-jps"); - mimeTypes.Add ("js", "application/javascript"); - mimeTypes.Add ("json", "application/json"); - mimeTypes.Add ("jut", "image/jutvision"); - mimeTypes.Add ("kar", "audio/midi"); - mimeTypes.Add ("ksh", "text/x-script.ksh"); - mimeTypes.Add ("la", "audio/nspaudio"); - mimeTypes.Add ("lam", "audio/x-liveaudio"); - mimeTypes.Add ("latex", "application/x-latex"); - mimeTypes.Add ("list", "text/plain"); - mimeTypes.Add ("lma", "audio/nspaudio"); - mimeTypes.Add ("log", "text/plain"); - mimeTypes.Add ("lsp", "application/x-lisp"); - mimeTypes.Add ("lst", "text/plain"); - mimeTypes.Add ("lsx", "text/x-la-asf"); - mimeTypes.Add ("ltx", "application/x-latex"); - mimeTypes.Add ("m13", "application/x-msmediaview"); - mimeTypes.Add ("m14", "application/x-msmediaview"); - mimeTypes.Add ("m1v", "video/mpeg"); - mimeTypes.Add ("m2a", "audio/mpeg"); - mimeTypes.Add ("m2v", "video/mpeg"); - mimeTypes.Add ("m3u", "audio/x-mpequrl"); - mimeTypes.Add ("m4a", "audio/mp4"); - mimeTypes.Add ("m4v", "video/mp4"); - mimeTypes.Add ("man", "application/x-troff-man"); - mimeTypes.Add ("manifest", "application/x-ms-manifest"); - mimeTypes.Add ("map", "application/x-navimap"); - mimeTypes.Add ("mar", "text/plain"); - mimeTypes.Add ("mbd", "application/mbedlet"); - mimeTypes.Add ("mc$", "application/x-magic-cap-package-1.0"); - mimeTypes.Add ("mcd", "application/mcad"); - mimeTypes.Add ("mcf", "image/vasa"); - mimeTypes.Add ("mcp", "application/netmc"); - mimeTypes.Add ("mdb", "application/x-msaccess"); - mimeTypes.Add ("mesh", "model/mesh"); - mimeTypes.Add ("me", "application/x-troff-me"); - mimeTypes.Add ("mid", "audio/midi"); - mimeTypes.Add ("midi", "audio/midi"); - mimeTypes.Add ("mif", "application/x-mif"); - mimeTypes.Add ("mjf", "audio/x-vnd.AudioExplosion.MjuiceMediaFile"); - mimeTypes.Add ("mjpg", "video/x-motion-jpeg"); - mimeTypes.Add ("mm", "application/base64"); - mimeTypes.Add ("mme", "application/base64"); - mimeTypes.Add ("mny", "application/x-msmoney"); - mimeTypes.Add ("mod", "audio/mod"); - mimeTypes.Add ("mov", "video/quicktime"); - mimeTypes.Add ("movie", "video/x-sgi-movie"); - mimeTypes.Add ("mp2", "video/mpeg"); - mimeTypes.Add ("mp3", "audio/mpeg"); - mimeTypes.Add ("mp4", "video/mp4"); - mimeTypes.Add ("mp4a", "audio/mp4"); - mimeTypes.Add ("mp4v", "video/mp4"); - mimeTypes.Add ("mpa", "audio/mpeg"); - mimeTypes.Add ("mpc", "application/x-project"); - mimeTypes.Add ("mpeg", "video/mpeg"); - mimeTypes.Add ("mpe", "video/mpeg"); - mimeTypes.Add ("mpga", "audio/mpeg"); - mimeTypes.Add ("mpg", "video/mpeg"); - mimeTypes.Add ("mpp", "application/vnd.ms-project"); - mimeTypes.Add ("mpt", "application/x-project"); - mimeTypes.Add ("mpv2", "video/mpeg"); - mimeTypes.Add ("mpv", "application/x-project"); - mimeTypes.Add ("mpx", "application/x-project"); - mimeTypes.Add ("mrc", "application/marc"); - mimeTypes.Add ("ms", "application/x-troff-ms"); - mimeTypes.Add ("msh", "model/mesh"); - mimeTypes.Add ("m", "text/plain"); - mimeTypes.Add ("mvb", "application/x-msmediaview"); - mimeTypes.Add ("mv", "video/x-sgi-movie"); - mimeTypes.Add ("my", "audio/make"); - mimeTypes.Add ("mzz", "application/x-vnd.AudioExplosion.mzz"); - mimeTypes.Add ("nap", "image/naplps"); - mimeTypes.Add ("naplps", "image/naplps"); - mimeTypes.Add ("nc", "application/x-netcdf"); - mimeTypes.Add ("ncm", "application/vnd.nokia.configuration-message"); - mimeTypes.Add ("niff", "image/x-niff"); - mimeTypes.Add ("nif", "image/x-niff"); - mimeTypes.Add ("nix", "application/x-mix-transfer"); - mimeTypes.Add ("nsc", "application/x-conference"); - mimeTypes.Add ("nvd", "application/x-navidoc"); - mimeTypes.Add ("nws", "message/rfc822"); - mimeTypes.Add ("oda", "application/oda"); - mimeTypes.Add ("ods", "application/oleobject"); - mimeTypes.Add ("oga", "audio/ogg"); - mimeTypes.Add ("ogg", "audio/ogg"); - mimeTypes.Add ("ogv", "video/ogg"); - mimeTypes.Add ("ogx", "application/ogg"); - mimeTypes.Add ("omc", "application/x-omc"); - mimeTypes.Add ("omcd", "application/x-omcdatamaker"); - mimeTypes.Add ("omcr", "application/x-omcregerator"); - mimeTypes.Add ("opus", "audio/ogg"); - mimeTypes.Add ("oxps", "application/oxps"); - mimeTypes.Add ("p10", "application/pkcs10"); - mimeTypes.Add ("p12", "application/pkcs-12"); - mimeTypes.Add ("p7a", "application/x-pkcs7-signature"); - mimeTypes.Add ("p7b", "application/x-pkcs7-certificates"); - mimeTypes.Add ("p7c", "application/pkcs7-mime"); - mimeTypes.Add ("p7m", "application/pkcs7-mime"); - mimeTypes.Add ("p7r", "application/x-pkcs7-certreqresp"); - mimeTypes.Add ("p7s", "application/pkcs7-signature"); - mimeTypes.Add ("part", "application/pro_eng"); - mimeTypes.Add ("pas", "text/pascal"); - mimeTypes.Add ("pbm", "image/x-portable-bitmap"); - mimeTypes.Add ("pcl", "application/x-pcl"); - mimeTypes.Add ("pct", "image/x-pict"); - mimeTypes.Add ("pcx", "image/x-pcx"); - mimeTypes.Add ("pdb", "chemical/x-pdb"); - mimeTypes.Add ("pdf", "application/pdf"); - mimeTypes.Add ("pfunk", "audio/make"); - mimeTypes.Add ("pfx", "application/x-pkcs12"); - mimeTypes.Add ("pgm", "image/x-portable-graymap"); - mimeTypes.Add ("pic", "image/pict"); - mimeTypes.Add ("pict", "image/pict"); - mimeTypes.Add ("pkg", "application/x-newton-compatible-pkg"); - mimeTypes.Add ("pko", "application/vnd.ms-pki.pko"); - mimeTypes.Add ("pl", "text/plain"); - mimeTypes.Add ("plx", "application/x-PiXCLscript"); - mimeTypes.Add ("pm4", "application/x-pagemaker"); - mimeTypes.Add ("pm5", "application/x-pagemaker"); - mimeTypes.Add ("pma", "application/x-perfmon"); - mimeTypes.Add ("pmc", "application/x-perfmon"); - mimeTypes.Add ("pm", "image/x-xpixmap"); - mimeTypes.Add ("pml", "application/x-perfmon"); - mimeTypes.Add ("pmr", "application/x-perfmon"); - mimeTypes.Add ("pmw", "application/x-perfmon"); - mimeTypes.Add ("png", "image/png"); - mimeTypes.Add ("pnm", "application/x-portable-anymap"); - mimeTypes.Add ("pot", "application/vnd.ms-powerpoint"); - mimeTypes.Add ("potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"); - mimeTypes.Add ("potx", "application/vnd.openxmlformats-officedocument.presentationml.template"); - mimeTypes.Add ("pov", "model/x-pov"); - mimeTypes.Add ("ppa", "application/vnd.ms-powerpoint"); - mimeTypes.Add ("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"); - mimeTypes.Add ("ppm", "image/x-portable-pixmap"); - mimeTypes.Add ("pps", "application/vnd.ms-powerpoint"); - mimeTypes.Add ("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"); - mimeTypes.Add ("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"); - mimeTypes.Add ("ppt", "application/vnd.ms-powerpoint"); - mimeTypes.Add ("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"); - mimeTypes.Add ("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); - mimeTypes.Add ("ppz", "application/mspowerpoint"); - mimeTypes.Add ("pre", "application/x-freelance"); - mimeTypes.Add ("prf", "application/pics-rules"); - mimeTypes.Add ("prt", "application/pro_eng"); - mimeTypes.Add ("ps", "application/postscript"); - mimeTypes.Add ("p", "text/x-pascal"); - mimeTypes.Add ("pub", "application/x-mspublisher"); - mimeTypes.Add ("pvu", "paleovu/x-pv"); - mimeTypes.Add ("pwz", "application/vnd.ms-powerpoint"); - mimeTypes.Add ("pyc", "applicaiton/x-bytecode.python"); - mimeTypes.Add ("py", "text/x-script.phyton"); - mimeTypes.Add ("qcp", "audio/vnd.qcelp"); - mimeTypes.Add ("qd3d", "x-world/x-3dmf"); - mimeTypes.Add ("qd3", "x-world/x-3dmf"); - mimeTypes.Add ("qif", "image/x-quicktime"); - mimeTypes.Add ("qtc", "video/x-qtc"); - mimeTypes.Add ("qtif", "image/x-quicktime"); - mimeTypes.Add ("qti", "image/x-quicktime"); - mimeTypes.Add ("qt", "video/quicktime"); - mimeTypes.Add ("ra", "audio/x-pn-realaudio"); - mimeTypes.Add ("ram", "audio/x-pn-realaudio"); - mimeTypes.Add ("ras", "application/x-cmu-raster"); - mimeTypes.Add ("rast", "image/cmu-raster"); - mimeTypes.Add ("rexx", "text/x-script.rexx"); - mimeTypes.Add ("rf", "image/vnd.rn-realflash"); - mimeTypes.Add ("rgb", "image/x-rgb"); - mimeTypes.Add ("rm", "application/vnd.rn-realmedia"); - mimeTypes.Add ("rmi", "audio/mid"); - mimeTypes.Add ("rmm", "audio/x-pn-realaudio"); - mimeTypes.Add ("rmp", "audio/x-pn-realaudio"); - mimeTypes.Add ("rng", "application/ringing-tones"); - mimeTypes.Add ("rnx", "application/vnd.rn-realplayer"); - mimeTypes.Add ("roff", "application/x-troff"); - mimeTypes.Add ("rp", "image/vnd.rn-realpix"); - mimeTypes.Add ("rpm", "audio/x-pn-realaudio-plugin"); - mimeTypes.Add ("rss", "application/rss+xml"); - mimeTypes.Add ("rtf", "text/richtext"); - mimeTypes.Add ("rt", "text/richtext"); - mimeTypes.Add ("rtx", "text/richtext"); - mimeTypes.Add ("rv", "video/vnd.rn-realvideo"); - mimeTypes.Add ("s3m", "audio/s3m"); - mimeTypes.Add ("sbk", "application/x-tbook"); - mimeTypes.Add ("scd", "application/x-msschedule"); - mimeTypes.Add ("scm", "application/x-lotusscreencam"); - mimeTypes.Add ("sct", "text/scriptlet"); - mimeTypes.Add ("sdml", "text/plain"); - mimeTypes.Add ("sdp", "application/sdp"); - mimeTypes.Add ("sdr", "application/sounder"); - mimeTypes.Add ("sea", "application/sea"); - mimeTypes.Add ("set", "application/set"); - mimeTypes.Add ("setpay", "application/set-payment-initiation"); - mimeTypes.Add ("setreg", "application/set-registration-initiation"); - mimeTypes.Add ("sgml", "text/sgml"); - mimeTypes.Add ("sgm", "text/sgml"); - mimeTypes.Add ("shar", "application/x-bsh"); - mimeTypes.Add ("sh", "text/x-script.sh"); - mimeTypes.Add ("shtml", "text/html"); - mimeTypes.Add ("sid", "audio/x-psid"); - mimeTypes.Add ("silo", "model/mesh"); - mimeTypes.Add ("sit", "application/x-sit"); - mimeTypes.Add ("skd", "application/x-koan"); - mimeTypes.Add ("skm", "application/x-koan"); - mimeTypes.Add ("skp", "application/x-koan"); - mimeTypes.Add ("skt", "application/x-koan"); - mimeTypes.Add ("sl", "application/x-seelogo"); - mimeTypes.Add ("smi", "application/smil"); - mimeTypes.Add ("smil", "application/smil"); - mimeTypes.Add ("snd", "audio/basic"); - mimeTypes.Add ("sol", "application/solids"); - mimeTypes.Add ("spc", "application/x-pkcs7-certificates"); - mimeTypes.Add ("spl", "application/futuresplash"); - mimeTypes.Add ("spr", "application/x-sprite"); - mimeTypes.Add ("sprite", "application/x-sprite"); - mimeTypes.Add ("spx", "audio/ogg"); - mimeTypes.Add ("src", "application/x-wais-source"); - mimeTypes.Add ("ssi", "text/x-server-parsed-html"); - mimeTypes.Add ("ssm", "application/streamingmedia"); - mimeTypes.Add ("sst", "application/vnd.ms-pki.certstore"); - mimeTypes.Add ("step", "application/step"); - mimeTypes.Add ("s", "text/x-asm"); - mimeTypes.Add ("stl", "application/sla"); - mimeTypes.Add ("stm", "text/html"); - mimeTypes.Add ("stp", "application/step"); - mimeTypes.Add ("sv4cpio", "application/x-sv4cpio"); - mimeTypes.Add ("sv4crc", "application/x-sv4crc"); - mimeTypes.Add ("svf", "image/x-dwg"); - mimeTypes.Add ("svg", "image/svg+xml"); - mimeTypes.Add ("svr", "application/x-world"); - mimeTypes.Add ("swf", "application/x-shockwave-flash"); - mimeTypes.Add ("talk", "text/x-speech"); - mimeTypes.Add ("t", "application/x-troff"); - mimeTypes.Add ("tar", "application/x-tar"); - mimeTypes.Add ("tbk", "application/toolbook"); - mimeTypes.Add ("tcl", "text/x-script.tcl"); - mimeTypes.Add ("tcsh", "text/x-script.tcsh"); - mimeTypes.Add ("tex", "application/x-tex"); - mimeTypes.Add ("texi", "application/x-texinfo"); - mimeTypes.Add ("texinfo", "application/x-texinfo"); - mimeTypes.Add ("text", "text/plain"); - mimeTypes.Add ("tgz", "application/x-compressed"); - mimeTypes.Add ("tiff", "image/tiff"); - mimeTypes.Add ("tif", "image/tiff"); - mimeTypes.Add ("tr", "application/x-troff"); - mimeTypes.Add ("trm", "application/x-msterminal"); - mimeTypes.Add ("ts", "text/x-typescript"); - mimeTypes.Add ("tsi", "audio/tsp-audio"); - mimeTypes.Add ("tsp", "audio/tsplayer"); - mimeTypes.Add ("tsv", "text/tab-separated-values"); - mimeTypes.Add ("ttf", "application/x-font-ttf"); - mimeTypes.Add ("turbot", "image/florian"); - mimeTypes.Add ("txt", "text/plain"); - mimeTypes.Add ("uil", "text/x-uil"); - mimeTypes.Add ("uls", "text/iuls"); - mimeTypes.Add ("unis", "text/uri-list"); - mimeTypes.Add ("uni", "text/uri-list"); - mimeTypes.Add ("unv", "application/i-deas"); - mimeTypes.Add ("uris", "text/uri-list"); - mimeTypes.Add ("uri", "text/uri-list"); - mimeTypes.Add ("ustar", "multipart/x-ustar"); - mimeTypes.Add ("uue", "text/x-uuencode"); - mimeTypes.Add ("uu", "text/x-uuencode"); - mimeTypes.Add ("vcd", "application/x-cdlink"); - mimeTypes.Add ("vcf", "text/vcard"); - mimeTypes.Add ("vcard", "text/vcard"); - mimeTypes.Add ("vcs", "text/x-vCalendar"); - mimeTypes.Add ("vda", "application/vda"); - mimeTypes.Add ("vdo", "video/vdo"); - mimeTypes.Add ("vew", "application/groupwise"); - mimeTypes.Add ("vivo", "video/vivo"); - mimeTypes.Add ("viv", "video/vivo"); - mimeTypes.Add ("vmd", "application/vocaltec-media-desc"); - mimeTypes.Add ("vmf", "application/vocaltec-media-file"); - mimeTypes.Add ("voc", "audio/voc"); - mimeTypes.Add ("vos", "video/vosaic"); - mimeTypes.Add ("vox", "audio/voxware"); - mimeTypes.Add ("vqe", "audio/x-twinvq-plugin"); - mimeTypes.Add ("vqf", "audio/x-twinvq"); - mimeTypes.Add ("vql", "audio/x-twinvq-plugin"); - mimeTypes.Add ("vrml", "application/x-vrml"); - mimeTypes.Add ("vrt", "x-world/x-vrt"); - mimeTypes.Add ("vsd", "application/x-visio"); - mimeTypes.Add ("vst", "application/x-visio"); - mimeTypes.Add ("vsw", "application/x-visio"); - mimeTypes.Add ("w60", "application/wordperfect6.0"); - mimeTypes.Add ("w61", "application/wordperfect6.1"); - mimeTypes.Add ("w6w", "application/msword"); - mimeTypes.Add ("wav", "audio/wav"); - mimeTypes.Add ("wb1", "application/x-qpro"); - mimeTypes.Add ("wbmp", "image/vnd.wap.wbmp"); - mimeTypes.Add ("wcm", "application/vnd.ms-works"); - mimeTypes.Add ("wdb", "application/vnd.ms-works"); - mimeTypes.Add ("web", "application/vnd.xara"); - mimeTypes.Add ("webm", "video/webm"); - mimeTypes.Add ("wiz", "application/msword"); - mimeTypes.Add ("wk1", "application/x-123"); - mimeTypes.Add ("wks", "application/vnd.ms-works"); - mimeTypes.Add ("wmf", "windows/metafile"); - mimeTypes.Add ("wmlc", "application/vnd.wap.wmlc"); - mimeTypes.Add ("wmlsc", "application/vnd.wap.wmlscriptc"); - mimeTypes.Add ("wmls", "text/vnd.wap.wmlscript"); - mimeTypes.Add ("wml", "text/vnd.wap.wml"); - mimeTypes.Add ("wmp", "video/x-ms-wmp"); - mimeTypes.Add ("wmv", "video/x-ms-wmv"); - mimeTypes.Add ("wmx", "video/x-ms-wmx"); - mimeTypes.Add ("woff", "application/x-woff"); - mimeTypes.Add ("word", "application/msword"); - mimeTypes.Add ("wp5", "application/wordperfect"); - mimeTypes.Add ("wp6", "application/wordperfect"); - mimeTypes.Add ("wp", "application/wordperfect"); - mimeTypes.Add ("wpd", "application/wordperfect"); - mimeTypes.Add ("wps", "application/vnd.ms-works"); - mimeTypes.Add ("wq1", "application/x-lotus"); - mimeTypes.Add ("wri", "application/mswrite"); - mimeTypes.Add ("wrl", "application/x-world"); - mimeTypes.Add ("wrz", "model/vrml"); - mimeTypes.Add ("wsc", "text/scriplet"); - mimeTypes.Add ("wsdl", "text/xml"); - mimeTypes.Add ("wsrc", "application/x-wais-source"); - mimeTypes.Add ("wtk", "application/x-wintalk"); - mimeTypes.Add ("wvx", "video/x-ms-wvx"); - mimeTypes.Add ("x3d", "model/x3d+xml"); - mimeTypes.Add ("x3db", "model/x3d+fastinfoset"); - mimeTypes.Add ("x3dv", "model/x3d-vrml"); - mimeTypes.Add ("xaf", "x-world/x-vrml"); - mimeTypes.Add ("xaml", "application/xaml+xml"); - mimeTypes.Add ("xap", "application/x-silverlight-app"); - mimeTypes.Add ("xbap", "application/x-ms-xbap"); - mimeTypes.Add ("xbm", "image/x-xbitmap"); - mimeTypes.Add ("xdr", "video/x-amt-demorun"); - mimeTypes.Add ("xgz", "xgl/drawing"); - mimeTypes.Add ("xht", "application/xhtml+xml"); - mimeTypes.Add ("xhtml", "application/xhtml+xml"); - mimeTypes.Add ("xif", "image/vnd.xiff"); - mimeTypes.Add ("xla", "application/vnd.ms-excel"); - mimeTypes.Add ("xlam", "application/vnd.ms-excel.addin.macroEnabled.12"); - mimeTypes.Add ("xl", "application/excel"); - mimeTypes.Add ("xlb", "application/excel"); - mimeTypes.Add ("xlc", "application/excel"); - mimeTypes.Add ("xld", "application/excel"); - mimeTypes.Add ("xlk", "application/excel"); - mimeTypes.Add ("xll", "application/excel"); - mimeTypes.Add ("xlm", "application/excel"); - mimeTypes.Add ("xls", "application/vnd.ms-excel"); - mimeTypes.Add ("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"); - mimeTypes.Add ("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"); - mimeTypes.Add ("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); - mimeTypes.Add ("xlt", "application/vnd.ms-excel"); - mimeTypes.Add ("xltm", "application/vnd.ms-excel.template.macroEnabled.12"); - mimeTypes.Add ("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"); - mimeTypes.Add ("xlv", "application/excel"); - mimeTypes.Add ("xlw", "application/excel"); - mimeTypes.Add ("xm", "audio/xm"); - mimeTypes.Add ("xml", "text/xml"); - mimeTypes.Add ("xmz", "xgl/movie"); - mimeTypes.Add ("xof", "x-world/x-vrml"); - mimeTypes.Add ("xpi", "application/x-xpinstall"); - mimeTypes.Add ("xpix", "application/x-vnd.ls-xpix"); - mimeTypes.Add ("xpm", "image/xpm"); - mimeTypes.Add ("xps", "application/vnd.ms-xpsdocument"); - mimeTypes.Add ("x-png", "image/png"); - mimeTypes.Add ("xsd", "text/xml"); - mimeTypes.Add ("xsl", "text/xml"); - mimeTypes.Add ("xslt", "text/xml"); - mimeTypes.Add ("xsr", "video/x-amt-showrun"); - mimeTypes.Add ("xwd", "image/x-xwd"); - mimeTypes.Add ("xyz", "chemical/x-pdb"); - mimeTypes.Add ("z", "application/x-compressed"); - mimeTypes.Add ("zip", "application/zip"); - mimeTypes.Add ("zsh", "text/x-script.zsh"); + extensions = LoadExtensions (); + mimeTypes = LoadMimeTypes (); + } + + static Dictionary LoadMimeTypes () + { + return new Dictionary (MimeUtils.OrdinalIgnoreCase) { + { ".323", "text/h323" }, + { ".3g2", "video/3gpp2" }, + { ".3gp", "video/3gpp" }, + { ".7z", "application/x-7z-compressed" }, + { ".aab", "application/x-authorware-bin" }, + { ".aac", "audio/aac" }, + { ".aam", "application/x-authorware-map" }, + { ".aas", "application/x-authorware-seg" }, + { ".abc", "text/vnd.abc" }, + { ".acgi", "text/html" }, + { ".acx", "application/internet-property-stream" }, + { ".afl", "video/animaflex" }, + { ".ai", "application/postscript" }, + { ".aif", "audio/aiff" }, + { ".aifc", "audio/aiff" }, + { ".aiff", "audio/aiff" }, + { ".aim", "application/x-aim" }, + { ".aip", "text/x-audiosoft-intra" }, + { ".ani", "application/x-navi-animation" }, + { ".aos", "application/x-nokia-9000-communicator-add-on-software" }, + { ".appcache", "text/cache-manifest" }, + { ".application", "application/x-ms-application" }, + { ".aps", "application/mime" }, + { ".art", "image/x-jg" }, + { ".asf", "video/x-ms-asf" }, + { ".asm", "text/x-asm" }, + { ".asp", "text/asp" }, + { ".asr", "video/x-ms-asf" }, + { ".asx", "application/x-mplayer2" }, + { ".atom", "application/atom+xml" }, + { ".au", "audio/x-au" }, + { ".avi", "video/avi" }, + { ".avs", "video/avs-video" }, + { ".axs", "application/olescript" }, + { ".bas", "text/plain" }, + { ".bcpio", "application/x-bcpio" }, + { ".bin", "application/octet-stream" }, + { ".bm", "image/bmp" }, + { ".bmp", "image/bmp" }, + { ".boo", "application/book" }, + { ".book", "application/book" }, + { ".boz", "application/x-bzip2" }, + { ".bsh", "application/x-bsh" }, + { ".bz2", "application/x-bzip2" }, + { ".bz", "application/x-bzip" }, + { ".cat", "application/vnd.ms-pki.seccat" }, + { ".ccad", "application/clariscad" }, + { ".cco", "application/x-cocoa" }, + { ".cc", "text/plain" }, + { ".cdf", "application/cdf" }, + { ".cer", "application/pkix-cert" }, + { ".cha", "application/x-chat" }, + { ".chat", "application/x-chat" }, + { ".chm", "application/vnd.ms-htmlhelp" }, + { ".class", "application/x-java-applet" }, + { ".clp", "application/x-msclip" }, + { ".cmx", "image/x-cmx" }, + { ".cod", "image/cis-cod" }, + { ".coffee", "text/x-coffeescript" }, + { ".conf", "text/plain" }, + { ".cpio", "application/x-cpio" }, + { ".cpp", "text/plain" }, + { ".cpt", "application/x-cpt" }, + { ".crd", "application/x-mscardfile" }, + { ".crl", "application/pkix-crl" }, + { ".crt", "application/pkix-cert" }, + { ".csh", "application/x-csh" }, + { ".css", "text/css" }, + { ".csv", "text/csv" }, + { ".cs", "text/plain" }, + { ".c", "text/plain" }, + { ".c++", "text/plain" }, + { ".cxx", "text/plain" }, + { ".dart", "application/dart" }, + { ".dcr", "application/x-director" }, + { ".deb", "application/x-deb" }, + { ".deepv", "application/x-deepv" }, + { ".def", "text/plain" }, + { ".deploy", "application/octet-stream" }, + { ".der", "application/x-x509-ca-cert" }, + { ".dib", "image/bmp" }, + { ".dif", "video/x-dv" }, + { ".dir", "application/x-director" }, + { ".disco", "text/xml" }, + { ".dll", "application/x-msdownload" }, + { ".dl", "video/dl" }, + { ".doc", "application/msword" }, + { ".docm", "application/vnd.ms-word.document.macroEnabled.12" }, + { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, + { ".dot", "application/msword" }, + { ".dotm", "application/vnd.ms-word.template.macroEnabled.12" }, + { ".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" }, + { ".dp", "application/commonground" }, + { ".drw", "application/drafting" }, + { ".dtd", "application/xml-dtd" }, + { ".dvi", "application/x-dvi" }, + { ".dv", "video/x-dv" }, + { ".dwg", "application/acad" }, + { ".dxf", "application/dxf" }, + { ".dxr", "application/x-director" }, + { ".el", "text/x-script.elisp" }, + { ".elc", "application/x-elc" }, + { ".eml", "message/rfc822" }, + { ".eot", "application/vnd.bw-fontobject" }, + { ".eps", "application/postscript" }, + { ".epub", "application/epub+zip" }, + { ".es", "application/x-esrehber" }, + { ".etx", "text/x-setext" }, + { ".evy", "application/envoy" }, + { ".exe", "application/octet-stream" }, + { ".f77", "text/plain" }, + { ".f90", "text/plain" }, + { ".fdf", "application/vnd.fdf" }, + { ".fif", "image/fif" }, + { ".flac", "audio/x-flac" }, + { ".fli", "video/fli" }, + { ".flx", "text/vnd.fmi.flexstor" }, + { ".fmf", "video/x-atomic3d-feature" }, + { ".for", "text/plain" }, + { ".fpx", "image/vnd.fpx" }, + { ".frl", "application/freeloader" }, + { ".fsx", "application/fsharp-script" }, + { ".g3", "image/g3fax" }, + { ".gif", "image/gif" }, + { ".gl", "video/gl" }, + { ".gsd", "audio/x-gsm" }, + { ".gsm", "audio/x-gsm" }, + { ".gsp", "application/x-gsp" }, + { ".gss", "application/x-gss" }, + { ".gtar", "application/x-gtar" }, + { ".g", "text/plain" }, + { ".gz", "application/x-gzip" }, + { ".gzip", "application/x-gzip" }, + { ".hdf", "application/x-hdf" }, + { ".help", "application/x-helpfile" }, + { ".hgl", "application/vnd.hp-HPGL" }, + { ".hh", "text/plain" }, + { ".hlb", "text/x-script" }, + { ".hlp", "application/x-helpfile" }, + { ".hpg", "application/vnd.hp-HPGL" }, + { ".hpgl", "application/vnd.hp-HPGL" }, + { ".hqx", "application/binhex" }, + { ".hta", "application/hta" }, + { ".htc", "text/x-component" }, + { ".h", "text/plain" }, + { ".htmls", "text/html" }, + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".htt", "text/webviewhtml" }, + { ".htx", "text/html" }, + { ".ico", "image/x-icon" }, + { ".ics", "text/calendar" }, + { ".idc", "text/plain" }, + { ".ief", "image/ief" }, + { ".iefs", "image/ief" }, + { ".iges", "model/iges" }, + { ".igs", "model/iges" }, + { ".iii", "application/x-iphone" }, + { ".ima", "application/x-ima" }, + { ".imap", "application/x-httpd-imap" }, + { ".inf", "application/inf" }, + { ".ins", "application/x-internett-signup" }, + { ".ip", "application/x-ip2" }, + { ".isp", "application/x-internet-signup" }, + { ".isu", "video/x-isvideo" }, + { ".it", "audio/it" }, + { ".iv", "application/x-inventor" }, + { ".ivf", "video/x-ivf" }, + { ".ivy", "application/x-livescreen" }, + { ".jam", "audio/x-jam" }, + { ".jar", "application/java-archive" }, + { ".java", "text/plain" }, + { ".jav", "text/plain" }, + { ".jcm", "application/x-java-commerce" }, + { ".jfif", "image/jpeg" }, + { ".jfif-tbnl", "image/jpeg" }, + { ".jpeg", "image/jpeg" }, + { ".jpe", "image/jpeg" }, + { ".jpg", "image/jpeg" }, + { ".jps", "image/x-jps" }, + { ".js", "application/javascript" }, + { ".json", "application/json" }, + { ".jut", "image/jutvision" }, + { ".kar", "audio/midi" }, + { ".ksh", "text/x-script.ksh" }, + { ".la", "audio/nspaudio" }, + { ".lam", "audio/x-liveaudio" }, + { ".latex", "application/x-latex" }, + { ".list", "text/plain" }, + { ".lma", "audio/nspaudio" }, + { ".log", "text/plain" }, + { ".lsp", "application/x-lisp" }, + { ".lst", "text/plain" }, + { ".lsx", "text/x-la-asf" }, + { ".ltx", "application/x-latex" }, + { ".m13", "application/x-msmediaview" }, + { ".m14", "application/x-msmediaview" }, + { ".m1v", "video/mpeg" }, + { ".m2a", "audio/mpeg" }, + { ".m2v", "video/mpeg" }, + { ".m3u", "audio/x-mpequrl" }, + { ".m4a", "audio/mp4" }, + { ".m4v", "video/mp4" }, + { ".man", "application/x-troff-man" }, + { ".manifest", "application/x-ms-manifest" }, + { ".map", "application/x-navimap" }, + { ".mar", "text/plain" }, + { ".markdown", "text/markdown" }, + { ".mbd", "application/mbedlet" }, + { ".mc$", "application/x-magic-cap-package-1.0" }, + { ".mcd", "application/mcad" }, + { ".mcf", "image/vasa" }, + { ".mcp", "application/netmc" }, + { ".md", "text/markdown" }, + { ".mdb", "application/x-msaccess" }, + { ".mesh", "model/mesh" }, + { ".me", "application/x-troff-me" }, + { ".mid", "audio/midi" }, + { ".midi", "audio/midi" }, + { ".mif", "application/x-mif" }, + { ".mjf", "audio/x-vnd.AudioExplosion.MjuiceMediaFile" }, + { ".mjpg", "video/x-motion-jpeg" }, + { ".mm", "application/base64" }, + { ".mme", "application/base64" }, + { ".mny", "application/x-msmoney" }, + { ".mod", "audio/mod" }, + { ".mov", "video/quicktime" }, + { ".movie", "video/x-sgi-movie" }, + { ".mp2", "video/mpeg" }, + { ".mp3", "audio/mpeg" }, + { ".mp4", "video/mp4" }, + { ".mp4a", "audio/mp4" }, + { ".mp4v", "video/mp4" }, + { ".mpa", "audio/mpeg" }, + { ".mpc", "application/x-project" }, + { ".mpeg", "video/mpeg" }, + { ".mpe", "video/mpeg" }, + { ".mpga", "audio/mpeg" }, + { ".mpg", "video/mpeg" }, + { ".mpp", "application/vnd.ms-project" }, + { ".mpt", "application/x-project" }, + { ".mpv2", "video/mpeg" }, + { ".mpv", "application/x-project" }, + { ".mpx", "application/x-project" }, + { ".mrc", "application/marc" }, + { ".ms", "application/x-troff-ms" }, + { ".msh", "model/mesh" }, + { ".m", "text/plain" }, + { ".mvb", "application/x-msmediaview" }, + { ".mv", "video/x-sgi-movie" }, + { ".mzz", "application/x-vnd.AudioExplosion.mzz" }, + { ".nap", "image/naplps" }, + { ".naplps", "image/naplps" }, + { ".nc", "application/x-netcdf" }, + { ".ncm", "application/vnd.nokia.configuration-message" }, + { ".niff", "image/x-niff" }, + { ".nif", "image/x-niff" }, + { ".nix", "application/x-mix-transfer" }, + { ".nsc", "application/x-conference" }, + { ".nvd", "application/x-navidoc" }, + { ".nws", "message/rfc822" }, + { ".oda", "application/oda" }, + { ".ods", "application/oleobject" }, + { ".oga", "audio/ogg" }, + { ".ogg", "audio/ogg" }, + { ".ogv", "video/ogg" }, + { ".ogx", "application/ogg" }, + { ".omc", "application/x-omc" }, + { ".omcd", "application/x-omcdatamaker" }, + { ".omcr", "application/x-omcregerator" }, + { ".opus", "audio/ogg" }, + { ".otf", "font/otf" }, + { ".oxps", "application/oxps" }, + { ".p10", "application/pkcs10" }, + { ".p12", "application/pkcs-12" }, + { ".p7a", "application/x-pkcs7-signature" }, + { ".p7b", "application/x-pkcs7-certificates" }, + { ".p7c", "application/pkcs7-mime" }, + { ".p7m", "application/pkcs7-mime" }, + { ".p7r", "application/x-pkcs7-certreqresp" }, + { ".p7s", "application/pkcs7-signature" }, + { ".part", "application/pro_eng" }, + { ".pas", "text/pascal" }, + { ".pbm", "image/x-portable-bitmap" }, + { ".pcl", "application/x-pcl" }, + { ".pct", "image/x-pict" }, + { ".pcx", "image/x-pcx" }, + { ".pdf", "application/pdf" }, + { ".pfx", "application/x-pkcs12" }, + { ".pgm", "image/x-portable-graymap" }, + { ".pic", "image/pict" }, + { ".pict", "image/pict" }, + { ".pkg", "application/x-newton-compatible-pkg" }, + { ".pko", "application/vnd.ms-pki.pko" }, + { ".pl", "text/plain" }, + { ".plx", "application/x-PiXCLscript" }, + { ".pm4", "application/x-pagemaker" }, + { ".pm5", "application/x-pagemaker" }, + { ".pma", "application/x-perfmon" }, + { ".pmc", "application/x-perfmon" }, + { ".pm", "image/x-xpixmap" }, + { ".pml", "application/x-perfmon" }, + { ".pmr", "application/x-perfmon" }, + { ".pmw", "application/x-perfmon" }, + { ".png", "image/png" }, + { ".pnm", "application/x-portable-anymap" }, + { ".pot", "application/vnd.ms-powerpoint" }, + { ".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12" }, + { ".potx", "application/vnd.openxmlformats-officedocument.presentationml.template" }, + { ".pov", "model/x-pov" }, + { ".ppa", "application/vnd.ms-powerpoint" }, + { ".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12" }, + { ".ppm", "image/x-portable-pixmap" }, + { ".pps", "application/vnd.ms-powerpoint" }, + { ".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" }, + { ".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" }, + { ".ppt", "application/vnd.ms-powerpoint" }, + { ".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12" }, + { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, + { ".ppz", "application/mspowerpoint" }, + { ".pre", "application/x-freelance" }, + { ".prf", "application/pics-rules" }, + { ".prt", "application/pro_eng" }, + { ".ps", "application/postscript" }, + { ".p", "text/x-pascal" }, + { ".pub", "application/x-mspublisher" }, + { ".pwz", "application/vnd.ms-powerpoint" }, + { ".pyc", "application/x-bytecode.python" }, + { ".py", "text/x-script.phyton" }, + { ".qcp", "audio/vnd.qcelp" }, + { ".qif", "image/x-quicktime" }, + { ".qtc", "video/x-qtc" }, + { ".qtif", "image/x-quicktime" }, + { ".qti", "image/x-quicktime" }, + { ".qt", "video/quicktime" }, + { ".ra", "audio/x-pn-realaudio" }, + { ".ram", "audio/x-pn-realaudio" }, + { ".ras", "application/x-cmu-raster" }, + { ".rast", "image/cmu-raster" }, + { ".rexx", "text/x-script.rexx" }, + { ".rf", "image/vnd.rn-realflash" }, + { ".rgb", "image/x-rgb" }, + { ".rm", "application/vnd.rn-realmedia" }, + { ".rmi", "audio/mid" }, + { ".rmm", "audio/x-pn-realaudio" }, + { ".rmp", "audio/x-pn-realaudio" }, + { ".rng", "application/ringing-tones" }, + { ".rnx", "application/vnd.rn-realplayer" }, + { ".roff", "application/x-troff" }, + { ".rp", "image/vnd.rn-realpix" }, + { ".rpm", "audio/x-pn-realaudio-plugin" }, + { ".rss", "application/rss+xml" }, + { ".rtf", "text/rtf" }, + { ".rt", "text/richtext" }, + { ".rtx", "text/richtext" }, + { ".rv", "video/vnd.rn-realvideo" }, + { ".s3m", "audio/s3m" }, + { ".sbk", "application/x-tbook" }, + { ".scd", "application/x-msschedule" }, + { ".scm", "application/x-lotusscreencam" }, + { ".sct", "text/scriptlet" }, + { ".sdml", "text/plain" }, + { ".sdp", "application/sdp" }, + { ".sdr", "application/sounder" }, + { ".sea", "application/sea" }, + { ".set", "application/set" }, + { ".setpay", "application/set-payment-initiation" }, + { ".setreg", "application/set-registration-initiation" }, + { ".sgml", "text/sgml" }, + { ".sgm", "text/sgml" }, + { ".shar", "application/x-bsh" }, + { ".sh", "text/x-script.sh" }, + { ".shtml", "text/html" }, + { ".sid", "audio/x-psid" }, + { ".silo", "model/mesh" }, + { ".sit", "application/x-sit" }, + { ".skd", "application/x-koan" }, + { ".skm", "application/x-koan" }, + { ".skp", "application/x-koan" }, + { ".skt", "application/x-koan" }, + { ".sl", "application/x-seelogo" }, + { ".smi", "application/smil" }, + { ".smil", "application/smil" }, + { ".snd", "audio/basic" }, + { ".sol", "application/solids" }, + { ".spc", "application/x-pkcs7-certificates" }, + { ".spl", "application/futuresplash" }, + { ".spr", "application/x-sprite" }, + { ".sprite", "application/x-sprite" }, + { ".spx", "audio/ogg" }, + { ".src", "application/x-wais-source" }, + { ".ssi", "text/x-server-parsed-html" }, + { ".ssm", "application/streamingmedia" }, + { ".sst", "application/vnd.ms-pki.certstore" }, + { ".step", "application/step" }, + { ".s", "text/x-asm" }, + { ".stl", "application/sla" }, + { ".stm", "text/html" }, + { ".stp", "application/step" }, + { ".sv4cpio", "application/x-sv4cpio" }, + { ".sv4crc", "application/x-sv4crc" }, + { ".svf", "image/x-dwg" }, + { ".svg", "image/svg+xml" }, + { ".svr", "application/x-world" }, + { ".swf", "application/x-shockwave-flash" }, + { ".talk", "text/x-speech" }, + { ".t", "application/x-troff" }, + { ".tar", "application/x-tar" }, + { ".tbk", "application/toolbook" }, + { ".tcl", "text/x-script.tcl" }, + { ".tcsh", "text/x-script.tcsh" }, + { ".tex", "application/x-tex" }, + { ".texi", "application/x-texinfo" }, + { ".texinfo", "application/x-texinfo" }, + { ".text", "text/plain" }, + { ".tgz", "application/x-compressed" }, + { ".tiff", "image/tiff" }, + { ".tif", "image/tiff" }, + { ".tr", "application/x-troff" }, + { ".trm", "application/x-msterminal" }, + { ".ts", "application/typescript" }, + { ".tsi", "audio/tsp-audio" }, + { ".tsp", "audio/tsplayer" }, + { ".tsv", "text/tab-separated-values" }, + { ".ttc", "font/collection" }, + { ".ttf", "font/ttf" }, + { ".txt", "text/plain" }, + { ".uil", "text/x-uil" }, + { ".uls", "text/iuls" }, + { ".unis", "text/uri-list" }, + { ".uni", "text/uri-list" }, + { ".unv", "application/i-deas" }, + { ".uris", "text/uri-list" }, + { ".uri", "text/uri-list" }, + { ".ustar", "multipart/x-ustar" }, + { ".uue", "text/x-uuencode" }, + { ".uu", "text/x-uuencode" }, + { ".vcd", "application/x-cdlink" }, + { ".vcf", "text/vcard" }, + { ".vcard", "text/vcard" }, + { ".vcs", "text/x-vcalendar" }, + { ".vda", "application/vda" }, + { ".vdo", "video/vdo" }, + { ".vew", "application/groupwise" }, + { ".vivo", "video/vnd.vivo" }, + { ".viv", "video/vnd.vivo" }, + { ".vmd", "application/vocaltec-media-desc" }, + { ".vmf", "application/vocaltec-media-file" }, + { ".voc", "audio/voc" }, + { ".vos", "video/vosaic" }, + { ".vox", "audio/voxware" }, + { ".vqe", "audio/x-twinvq-plugin" }, + { ".vqf", "audio/x-twinvq" }, + { ".vql", "audio/x-twinvq-plugin" }, + { ".vrml", "application/x-vrml" }, + { ".vsd", "application/x-visio" }, + { ".vst", "application/x-visio" }, + { ".vsw", "application/x-visio" }, + { ".w60", "application/wordperfect6.0" }, + { ".w61", "application/wordperfect6.1" }, + { ".w6w", "application/msword" }, + { ".wav", "audio/wav" }, + { ".wb1", "application/x-qpro" }, + { ".wbmp", "image/vnd.wap.wbmp" }, + { ".wcm", "application/vnd.ms-works" }, + { ".wdb", "application/vnd.ms-works" }, + { ".web", "application/vnd.xara" }, + { ".weba", "audio/webm" }, + { ".webm", "video/webm" }, + { ".webp", "image/webp" }, + { ".wiz", "application/msword" }, + { ".wk1", "application/x-123" }, + { ".wks", "application/vnd.ms-works" }, + { ".wmf", "image/wmf" }, + { ".wmlc", "application/vnd.wap.wmlc" }, + { ".wmlsc", "application/vnd.wap.wmlscriptc" }, + { ".wmls", "text/vnd.wap.wmlscript" }, + { ".wml", "text/vnd.wap.wml" }, + { ".wmp", "video/x-ms-wmp" }, + { ".wmv", "video/x-ms-wmv" }, + { ".wmx", "video/x-ms-wmx" }, + { ".woff", "font/woff" }, + { ".woff2", "font/woff2" }, + { ".word", "application/msword" }, + { ".wp5", "application/wordperfect" }, + { ".wp6", "application/wordperfect" }, + { ".wp", "application/wordperfect" }, + { ".wpd", "application/wordperfect" }, + { ".wps", "application/vnd.ms-works" }, + { ".wq1", "application/x-lotus" }, + { ".wri", "application/mswrite" }, + { ".wrl", "application/x-world" }, + { ".wrz", "model/vrml" }, + { ".wsc", "text/scriplet" }, + { ".wsdl", "text/xml" }, + { ".wsrc", "application/x-wais-source" }, + { ".wtk", "application/x-wintalk" }, + { ".wvx", "video/x-ms-wvx" }, + { ".x3d", "model/x3d+xml" }, + { ".x3db", "model/x3d+fastinfoset" }, + { ".x3dv", "model/x3d-vrml" }, + { ".xaml", "application/xaml+xml" }, + { ".xap", "application/x-silverlight-app" }, + { ".xbap", "application/x-ms-xbap" }, + { ".xbm", "image/x-xbitmap" }, + { ".xdr", "video/x-amt-demorun" }, + { ".xht", "application/xhtml+xml" }, + { ".xhtml", "application/xhtml+xml" }, + { ".xif", "image/vnd.xiff" }, + { ".xla", "application/vnd.ms-excel" }, + { ".xlam", "application/vnd.ms-excel.addin.macroEnabled.12" }, + { ".xl", "application/excel" }, + { ".xlb", "application/excel" }, + { ".xlc", "application/excel" }, + { ".xld", "application/excel" }, + { ".xlk", "application/excel" }, + { ".xll", "application/excel" }, + { ".xlm", "application/excel" }, + { ".xls", "application/vnd.ms-excel" }, + { ".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" }, + { ".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" }, + { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, + { ".xlt", "application/vnd.ms-excel" }, + { ".xltm", "application/vnd.ms-excel.template.macroEnabled.12" }, + { ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" }, + { ".xlv", "application/excel" }, + { ".xlw", "application/excel" }, + { ".xm", "audio/xm" }, + { ".xml", "text/xml" }, + { ".xpi", "application/x-xpinstall" }, + { ".xpix", "application/x-vnd.ls-xpix" }, + { ".xpm", "image/xpm" }, + { ".xps", "application/vnd.ms-xpsdocument" }, + { ".x-png", "image/png" }, + { ".xsd", "text/xml" }, + { ".xsl", "text/xml" }, + { ".xslt", "text/xml" }, + { ".xsr", "video/x-amt-showrun" }, + { ".xwd", "image/x-xwd" }, + { ".z", "application/x-compressed" }, + { ".zip", "application/zip" }, + { ".zsh", "text/x-script.zsh" } + }; + } + + static Dictionary LoadExtensions () + { + return new Dictionary (MimeUtils.OrdinalIgnoreCase) { + { "application/acad", ".dwg" }, + { "application/atom+xml", ".atom" }, + { "application/base64", ".mm" }, + { "application/binhex", ".hqx" }, + { "application/book", ".boo" }, + { "application/cdf", ".cdf" }, + { "application/clariscad", ".ccad" }, + { "application/commonground", ".dp" }, + { "application/dart", ".dart" }, + { "application/drafting", ".drw" }, + { "application/dxf", ".dxf" }, + { "application/envoy", ".evy" }, + { "application/epub+zip", ".epub" }, + { "application/excel", ".xls" }, + { "application/freeloader", ".frl" }, + { "application/fsharp-script", ".fsx" }, + { "application/futuresplash", ".spl" }, + { "application/groupwise", ".vew" }, + { "application/hta", ".hta" }, + { "application/i-deas", ".unv" }, + { "application/inf", ".inf" }, + { "application/internet-property-stream", ".acx" }, + { "application/java-archive", ".jar" }, + { "application/javascript", ".js" }, + { "application/json", ".json" }, + { "application/marc", ".mrc" }, + { "application/mbedlet", ".mbd" }, + { "application/mcad", ".mcd" }, + { "application/mime", ".aps" }, + { "application/mspowerpoint", ".ppz" }, + { "application/msword", ".doc" }, + { "application/mswrite", ".wri" }, + { "application/netmc", ".mcp" }, + { "application/octet-stream", ".bin" }, + { "application/oda", ".oda" }, + { "application/ogg", ".ogx" }, + { "application/oleobject", ".ods" }, + { "application/olescript", ".axs" }, + { "application/oxps", ".oxps" }, + { "application/pdf", ".pdf" }, + { "application/pics-rules", ".prf" }, + { "application/pkcs-12", ".p12" }, + { "application/pkcs10", ".p10" }, + { "application/pkcs7-mime", ".p7m" }, + { "application/pkcs7-signature", ".p7s" }, + { "application/pkix-cert", ".cer" }, + { "application/pkix-crl", ".crl" }, + { "application/postscript", ".ps" }, + { "application/pro_eng", ".part" }, + { "application/ringing-tones", ".rng" }, + { "application/rss+xml", ".rss" }, + { "application/sdp", ".sdp" }, + { "application/sea", ".sea" }, + { "application/set", ".set" }, + { "application/set-payment-initiation", ".setpay" }, + { "application/set-registration-initiation", ".setreg" }, + { "application/sla", ".stl" }, + { "application/smil", ".smi" }, + { "application/solids", ".sol" }, + { "application/sounder", ".sdr" }, + { "application/step", ".step" }, + { "application/streamingmedia", ".ssm" }, + { "application/toolbook", ".tbk" }, + { "application/typescript", ".ts" }, + { "application/vda", ".vda" }, + { "application/vnd.bw-fontobject", ".eot" }, + { "application/vnd.fdf", ".fdf" }, + { "application/vnd.hp-HPGL", ".hgl" }, + { "application/vnd.ms-excel", ".xls" }, + { "application/vnd.ms-excel.addin.macroEnabled.12", ".xlam" }, + { "application/vnd.ms-excel.sheet.binary.macroEnabled.12", ".xlsb" }, + { "application/vnd.ms-excel.sheet.macroEnabled.12", ".xlsm" }, + { "application/vnd.ms-excel.template.macroEnabled.12", ".xltm" }, + { "application/vnd.ms-htmlhelp", ".chm" }, + { "application/vnd.ms-pki.certstore", ".sst" }, + { "application/vnd.ms-pki.pko", ".pko" }, + { "application/vnd.ms-pki.seccat", ".cat" }, + { "application/vnd.ms-powerpoint", ".ppt" }, + { "application/vnd.ms-powerpoint.addin.macroEnabled.12", ".ppam" }, + { "application/vnd.ms-powerpoint.presentation.macroEnabled.12", ".pptm" }, + { "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", ".ppsm" }, + { "application/vnd.ms-powerpoint.template.macroEnabled.12", ".potm" }, + { "application/vnd.ms-project", ".mpp" }, + { "application/vnd.ms-word.document.macroEnabled.12", ".docm" }, + { "application/vnd.ms-word.template.macroEnabled.12", ".dotm" }, + { "application/vnd.ms-works", ".wcm" }, + { "application/vnd.ms-xpsdocument", ".xps" }, + { "application/vnd.nokia.configuration-message", ".ncm" }, + { "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx" }, + { "application/vnd.openxmlformats-officedocument.presentationml.slideshow", ".ppsx" }, + { "application/vnd.openxmlformats-officedocument.presentationml.template", ".potx" }, + { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsx" }, + { "application/vnd.openxmlformats-officedocument.spreadsheetml.template", ".xltx" }, + { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".docx" }, + { "application/vnd.openxmlformats-officedocument.wordprocessingml.template", ".dotx" }, + { "application/vnd.rn-realmedia", ".rm" }, + { "application/vnd.rn-realplayer", ".rnx" }, + { "application/vnd.wap.wmlc", ".wmlc" }, + { "application/vnd.wap.wmlscriptc", ".wmlsc" }, + { "application/vnd.xara", ".web" }, + { "application/vocaltec-media-desc", ".vmd" }, + { "application/vocaltec-media-file", ".vmf" }, + { "application/wordperfect", ".wp5" }, + { "application/wordperfect6.0", ".w60" }, + { "application/wordperfect6.1", ".w61" }, + { "application/x-123", ".wk1" }, + { "application/x-7z-compressed", ".7z" }, + { "application/x-aim", ".aim" }, + { "application/x-authorware-bin", ".aab" }, + { "application/x-authorware-map", ".aam" }, + { "application/x-authorware-seg", ".aas" }, + { "application/x-bcpio", ".bcpio" }, + { "application/x-bsh", ".bsh" }, + { "application/x-bytecode.python", ".pyc" }, + { "application/x-bzip", ".bz" }, + { "application/x-bzip2", ".bz2" }, + { "application/x-cdlink", ".vcd" }, + { "application/x-chat", ".cha" }, + { "application/x-cmu-raster", ".ras" }, + { "application/x-cocoa", ".cco" }, + { "application/x-compressed", ".z" }, + { "application/x-conference", ".nsc" }, + { "application/x-cpio", ".cpio" }, + { "application/x-cpt", ".cpt" }, + { "application/x-csh", ".csh" }, + { "application/x-deb", ".deb" }, + { "application/x-deepv", ".deepv" }, + { "application/x-director", ".dcr" }, + { "application/x-dvi", ".dvi" }, + { "application/x-elc", ".elc" }, + { "application/x-esrehber", ".es" }, + { "application/x-font-ttf", ".ttf" }, + { "application/x-freelance", ".pre" }, + { "application/x-gsp", ".gsp" }, + { "application/x-gss", ".gss" }, + { "application/x-gtar", ".gtar" }, + { "application/x-gzip", ".gz" }, + { "application/x-hdf", ".hdf" }, + { "application/x-helpfile", ".help" }, + { "application/x-httpd-imap", ".imap" }, + { "application/x-ima", ".ima" }, + { "application/x-internet-signup", ".isp" }, + { "application/x-internett-signup", ".ins" }, + { "application/x-inventor", ".iv" }, + { "application/x-ip2", ".ip" }, + { "application/x-iphone", ".iii" }, + { "application/x-java-applet", ".class" }, + { "application/x-java-commerce", ".jcm" }, + { "application/x-koan", ".skd" }, + { "application/x-latex", ".latex" }, + { "application/x-lisp", ".lsp" }, + { "application/x-livescreen", ".ivy" }, + { "application/x-lotus", ".wq1" }, + { "application/x-lotusscreencam", ".scm" }, + { "application/x-magic-cap-package-1.0", ".mc$" }, + { "application/x-mif", ".mif" }, + { "application/x-mix-transfer", ".nix" }, + { "application/x-mplayer2", ".asx" }, + { "application/x-ms-application", ".application" }, + { "application/x-ms-manifest", ".manifest" }, + { "application/x-ms-xbap", ".xbap" }, + { "application/x-msaccess", ".mdb" }, + { "application/x-mscardfile", ".crd" }, + { "application/x-msclip", ".clp" }, + { "application/x-msdownload", ".dll" }, + { "application/x-msmediaview", ".m13" }, + { "application/x-msmoney", ".mny" }, + { "application/x-mspublisher", ".pub" }, + { "application/x-msschedule", ".scd" }, + { "application/x-msterminal", ".trm" }, + { "application/x-navi-animation", ".ani" }, + { "application/x-navidoc", ".nvd" }, + { "application/x-navimap", ".map" }, + { "application/x-netcdf", ".nc" }, + { "application/x-newton-compatible-pkg", ".pkg" }, + { "application/x-nokia-9000-communicator-add-on-software", ".aos" }, + { "application/x-omc", ".omc" }, + { "application/x-omcdatamaker", ".omcd" }, + { "application/x-omcregerator", ".omcr" }, + { "application/x-pagemaker", ".pm4" }, + { "application/x-pcl", ".pcl" }, + { "application/x-perfmon", ".pma" }, + { "application/x-PiXCLscript", ".plx" }, + { "application/x-pkcs12", ".pfx" }, + { "application/x-pkcs7-certificates", ".p7b" }, + { "application/x-pkcs7-certreqresp", ".p7r" }, + { "application/x-pkcs7-signature", ".p7a" }, + { "application/x-portable-anymap", ".pnm" }, + { "application/x-project", ".mpc" }, + { "application/x-qpro", ".wb1" }, + { "application/x-seelogo", ".sl" }, + { "application/x-shockwave-flash", ".swf" }, + { "application/x-silverlight-app", ".xap" }, + { "application/x-sit", ".sit" }, + { "application/x-sprite", ".spr" }, + { "application/x-sv4cpio", ".sv4cpio" }, + { "application/x-sv4crc", ".sv4crc" }, + { "application/x-tar", ".tar" }, + { "application/x-tbook", ".sbk" }, + { "application/x-tex", ".tex" }, + { "application/x-texinfo", ".texi" }, + { "application/x-troff", ".roff" }, + { "application/x-troff-man", ".man" }, + { "application/x-troff-me", ".me" }, + { "application/x-troff-ms", ".ms" }, + { "application/x-visio", ".vsd" }, + { "application/x-vnd.AudioExplosion.mzz", ".mzz" }, + { "application/x-vnd.ls-xpix", ".xpix" }, + { "application/x-vrml", ".vrml" }, + { "application/x-wais-source", ".src" }, + { "application/x-wintalk", ".wtk" }, + { "application/x-woff", ".woff" }, + { "application/x-world", ".svr" }, + { "application/x-x509-ca-cert", ".der" }, + { "application/x-xpinstall", ".xpi" }, + { "application/xaml+xml", ".xaml" }, + { "application/xhtml+xml", ".xhtml" }, + { "application/xml", ".xml" }, + { "application/xml-dtd", ".dtd" }, + { "application/zip", ".zip" }, + { "audio/aac", ".aac" }, + { "audio/aiff", ".aiff" }, + { "audio/basic", ".snd" }, + { "audio/it", ".it" }, + { "audio/mid", ".rmi" }, + { "audio/midi", ".mid" }, + { "audio/mod", ".mod" }, + { "audio/mp4", ".mp4" }, + { "audio/mpeg", ".mp3" }, + { "audio/nspaudio", ".la" }, + { "audio/ogg", ".ogg" }, + { "audio/s3m", ".s3m" }, + { "audio/tsp-audio", ".tsi" }, + { "audio/tsplayer", ".tsp" }, + { "audio/vnd.qcelp", ".qcp" }, + { "audio/voc", ".voc" }, + { "audio/vorbis", ".ogg" }, + { "audio/voxware", ".vox" }, + { "audio/wav", ".wav" }, + { "audio/webm", ".weba" }, + { "audio/x-au", ".au" }, + { "audio/x-flac", ".flac" }, + { "audio/x-gsm", ".gsd" }, + { "audio/x-jam", ".jam" }, + { "audio/x-liveaudio", ".lam" }, + { "audio/x-mpequrl", ".m3u" }, + { "audio/x-pn-realaudio", ".ra" }, + { "audio/x-pn-realaudio-plugin", ".rpm" }, + { "audio/x-psid", ".sid" }, + { "audio/x-twinvq", ".vqf" }, + { "audio/x-twinvq-plugin", ".vqe" }, + { "audio/x-vnd.AudioExplosion.MjuiceMediaFile", ".mjf" }, + { "audio/xm", ".xm" }, + { "font/collection", ".ttc" }, + { "font/otf", ".otf" }, + { "font/sfnt", ".ttf" }, + { "font/ttf", ".ttf" }, + { "font/woff", ".woff" }, + { "font/woff2", ".woff2" }, + { "image/bmp", ".bmp" }, + { "image/cis-cod", ".cod" }, + { "image/cmu-raster", ".rast" }, + { "image/fif", ".fif" }, + { "image/g3fax", ".g3" }, + { "image/gif", ".gif" }, + { "image/ief", ".ief" }, + { "image/jpeg", ".jpg" }, + { "image/jutvision", ".jut" }, + { "image/naplps", ".nap" }, + { "image/pict", ".pic" }, + { "image/png", ".png" }, + { "image/svg+xml", ".svg" }, + { "image/tiff", ".tif" }, + { "image/vasa", ".mcf" }, + { "image/vnd.fpx", ".fpx" }, + { "image/vnd.rn-realflash", ".rf" }, + { "image/vnd.rn-realpix", ".rp" }, + { "image/vnd.wap.wbmp", ".wbmp" }, + { "image/vnd.xiff", ".xif" }, + { "image/webp", ".webp" }, + { "image/wmf", ".wmf" }, + { "image/x-cmx", ".cmx" }, + { "image/x-dwg", ".svf" }, + { "image/x-icon", ".ico" }, + { "image/x-jg", ".art" }, + { "image/x-jps", ".jps" }, + { "image/x-niff", ".niff" }, + { "image/x-pcx", ".pcx" }, + { "image/x-pict", ".pct" }, + { "image/x-png", ".png" }, + { "image/x-portable-bitmap", ".pbm" }, + { "image/x-portable-graymap", ".pgm" }, + { "image/x-portable-pixmap", ".ppm" }, + { "image/x-quicktime", ".qif" }, + { "image/x-rgb", ".rgb" }, + { "image/x-xbitmap", ".xbm" }, + { "image/x-xpixmap", ".pm" }, + { "image/x-xwd", ".xwd" }, + { "image/xpm", ".xpm" }, + { "message/rfc822", ".eml" }, + { "model/iges", ".iges" }, + { "model/mesh", ".mesh" }, + { "model/vrml", ".wrz" }, + { "model/x-pov", ".pov" }, + { "model/x3d+fastinfoset", ".x3db" }, + { "model/x3d+xml", ".x3d" }, + { "model/x3d-vrml", ".x3dv" }, + { "multipart/x-ustar", ".ustar" }, + { "text/asp", ".asp" }, + { "text/cache-manifest", ".appcache" }, + { "text/calendar", ".ics" }, + { "text/css", ".css" }, + { "text/csv", ".csv" }, + { "text/h323", ".323" }, + { "text/html", ".html" }, + { "text/iuls", ".uls" }, + { "text/markdown", ".md" }, + { "text/pascal", ".pas" }, + { "text/plain", ".txt" }, + { "text/richtext", ".rtx" }, + { "text/rtf", ".rtf" }, + { "text/scriplet", ".wsc" }, + { "text/scriptlet", ".sct" }, + { "text/sgml", ".sgml" }, + { "text/tab-separated-values", ".tsv" }, + { "text/uri-list", ".uri" }, + { "text/vcard", ".vcf" }, + { "text/vnd.abc", ".abc" }, + { "text/vnd.fmi.flexstor", ".flx" }, + { "text/vnd.wap.wml", ".wml" }, + { "text/vnd.wap.wmlscript", ".wmls" }, + { "text/webviewhtml", ".htt" }, + { "text/x-asm", ".asm" }, + { "text/x-audiosoft-intra", ".aip" }, + { "text/x-coffeescript", ".coffee" }, + { "text/x-component", ".htc" }, + { "text/x-la-asf", ".lsx" }, + { "text/x-pascal", ".p" }, + { "text/x-script", ".hlb" }, + { "text/x-script.elisp", ".el" }, + { "text/x-script.ksh", ".ksh" }, + { "text/x-script.phyton", ".py" }, + { "text/x-script.rexx", ".rexx" }, + { "text/x-script.sh", ".sh" }, + { "text/x-script.tcl", ".tcl" }, + { "text/x-script.tcsh", ".tcsh" }, + { "text/x-script.zsh", ".zsh" }, + { "text/x-server-parsed-html", ".ssi" }, + { "text/x-setext", ".etx" }, + { "text/x-speech", ".talk" }, + { "text/x-uil", ".uil" }, + { "text/x-uuencode", ".uu" }, + { "text/x-vcalendar", ".vcs" }, + { "text/xml", ".xml" }, + { "video/3gpp", ".3gp" }, + { "video/3gpp2", ".3g2" }, + { "video/animaflex", ".afl" }, + { "video/avi", ".avi" }, + { "video/avs-video", ".avs" }, + { "video/dl", ".dl" }, + { "video/fli", ".fli" }, + { "video/gl", ".gl" }, + { "video/mp4", ".mp4" }, + { "video/mpeg", ".mpg" }, + { "video/ogg", ".ogv" }, + { "video/quicktime", ".mov" }, + { "video/vdo", ".vdo" }, + { "video/vnd.rn-realvideo", ".rv" }, + { "video/vnd.vivo", ".vivo" }, + { "video/vosaic", ".vos" }, + { "video/webm", ".webm" }, + { "video/x-amt-demorun", ".xdr" }, + { "video/x-amt-showrun", ".xsr" }, + { "video/x-atomic3d-feature", ".fmf" }, + { "video/x-dv", ".dif" }, + { "video/x-isvideo", ".isu" }, + { "video/x-ivf", ".ivf" }, + { "video/x-motion-jpeg", ".mjpg" }, + { "video/x-ms-asf", ".asf" }, + { "video/x-ms-wmp", ".wmp" }, + { "video/x-ms-wmv", ".wmv" }, + { "video/x-ms-wmx", ".wmx" }, + { "video/x-ms-wvx", ".wvx" }, + { "video/x-qtc", ".qtc" }, + { "video/x-sgi-movie", ".movie" } + }; } /// - /// Gets the MIME-type of the file. + /// Get the MIME-type of a file. /// /// - /// Gets the MIME-type of the file based on the file extension. + /// Gets the MIME-type of a file based on the file extension. /// /// The MIME-type. /// The file name. @@ -613,16 +1003,72 @@ public static string GetMimeType (string fileName) if (fileName == null) throw new ArgumentNullException (nameof (fileName)); - int dot = fileName.LastIndexOf ('.'); - string mimeType = null; + var extension = Path.GetExtension (fileName); - if (dot != -1 && fileName.Length > dot + 1) - mimeTypes.TryGetValue (fileName.Substring (dot + 1), out mimeType); + mimeTypes.TryGetValue (extension, out var mimeType); + + return mimeType ?? "application/octet-stream"; + } + /// + /// Get the standard file extension for a MIME-type. + /// + /// + /// Gets the standard file extension for a MIME-type. + /// + /// true if the extension is known for the specified MIME-type; otherwise, false. + /// The MIME-type. + /// The file name extension for the specified MIME-type. + /// + /// is null. + /// + public static bool TryGetExtension (string mimeType, out string extension) + { if (mimeType == null) - mimeType = "application/octet-stream"; + throw new ArgumentNullException (nameof (mimeType)); + + return extensions.TryGetValue (mimeType, out extension); + } + + /// + /// Register a MIME-type to file extension mapping. + /// + /// + /// Registers a MIME-type to file extension mapping. + /// If the mapping for the MIME-type and/or file extension already exists, + /// then it is overridden by the new mapping. + /// + /// The MIME-type to register. + /// The file extension to register. + /// + /// is null. + /// -or- + /// is null. + /// + /// + /// is empty. + /// -or- + /// is empty. + /// + public static void Register (string mimeType, string extension) + { + if (mimeType == null) + throw new ArgumentNullException (nameof (mimeType)); + + if (mimeType.Length == 0) + throw new ArgumentException ("Cannot register an empty MIME-type.", nameof (mimeType)); + + if (extension == null) + throw new ArgumentNullException (nameof (extension)); + + if (extension.Length == 0) + throw new ArgumentException ("Cannot register an empty file extension.", nameof (extension)); + + if (extension[0] != '.') + extension = "." + extension; - return mimeType; + mimeTypes[extension] = mimeType; + extensions[mimeType] = extension; } } } diff --git a/MimeKit/MimeVisitor.cs b/MimeKit/MimeVisitor.cs index aa21c044ac..39b2cad4be 100644 --- a/MimeKit/MimeVisitor.cs +++ b/MimeKit/MimeVisitor.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -239,10 +239,10 @@ protected internal virtual void VisitMimePart (MimePart entity) } /// - /// Visit the children of a . + /// Visit the children of a . /// /// - /// Visits the children of a . + /// Visits the children of a . /// /// Multipart. protected virtual void VisitChildren (Multipart multipart) @@ -352,6 +352,21 @@ protected internal virtual void VisitTextPart (TextPart entity) VisitMimePart (entity); } + /// + /// Visit the text/rfc822-headers MIME entity. + /// + /// + /// Visits the text/rfc822-headers MIME entity. + /// + /// + /// + /// + /// The text/rfc822-headers MIME entity. + protected internal virtual void VisitTextRfc822Headers (TextRfc822Headers entity) + { + VisitMessagePart (entity); + } + /// /// Visit the Microsoft TNEF MIME part entity. /// diff --git a/MimeKit/Multipart.cs b/MimeKit/Multipart.cs index e827ab8a5e..3a8f7db2fa 100644 --- a/MimeKit/Multipart.cs +++ b/MimeKit/Multipart.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,13 +32,9 @@ using System.Threading.Tasks; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - -using MimeKit.Encodings; -using MimeKit.Utils; using MimeKit.IO; +using MimeKit.Utils; +using MimeKit.Encodings; namespace MimeKit { /// @@ -71,10 +67,10 @@ public class Multipart : MimeEntity, ICollection, IList string preamble, epilogue; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -86,7 +82,7 @@ public Multipart (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified subtype. @@ -110,8 +106,7 @@ public Multipart (string subtype, params object[] args) : this (subtype) if (obj == null || TryInit (obj)) continue; - var entity = obj as MimeEntity; - if (entity != null) { + if (obj is MimeEntity entity) { Add (entity); continue; } @@ -121,7 +116,7 @@ public Multipart (string subtype, params object[] args) : this (subtype) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with the specified subtype. @@ -132,13 +127,13 @@ public Multipart (string subtype, params object[] args) : this (subtype) /// public Multipart (string subtype) : base ("multipart", subtype) { - ContentType.Parameters["boundary"] = GenerateBoundary (); + ContentType.Boundary = GenerateBoundary (); children = new List (); WriteEndBoundary = true; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with a ContentType of multipart/mixed. @@ -162,7 +157,7 @@ static string GenerateBoundary () } /// - /// Gets or sets the boundary. + /// Get or set the boundary. /// /// /// Gets or sets the boundary parameter on the Content-Type header. @@ -189,7 +184,7 @@ internal byte[] RawPreamble { } /// - /// Gets or sets the preamble. + /// Get or set the preamble. /// /// /// A multipart preamble appears before the first child entity of the @@ -228,7 +223,7 @@ internal byte[] RawEpilogue { } /// - /// Gets or sets the epilogue. + /// Get or set the epilogue. /// /// /// A multipart epiloque is the text that appears after the closing boundary @@ -271,7 +266,7 @@ public string Epilogue { } /// - /// Gets or sets whether the end boundary should be written. + /// Get or set whether the end boundary should be written. /// /// /// Gets or sets whether the end boundary should be written. @@ -285,12 +280,12 @@ internal bool WriteEndBoundary { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -356,10 +351,10 @@ internal static string FoldPreambleOrEpilogue (FormatOptions options, string tex return builder.ToString (); } - static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, CancellationToken cancellationToken) + static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, bool ensureNewLine, CancellationToken cancellationToken) { var cancellable = stream as ICancellableStream; - var filter = options.CreateNewLineFilter (); + var filter = options.CreateNewLineFilter (ensureNewLine); int index, length; var output = filter.Flush (bytes, 0, bytes.Length, out index, out length); @@ -372,9 +367,9 @@ static void WriteBytes (FormatOptions options, Stream stream, byte[] bytes, Canc } } - static Task WriteBytesAsync (FormatOptions options, Stream stream, byte[] bytes, CancellationToken cancellationToken) + static Task WriteBytesAsync (FormatOptions options, Stream stream, byte[] bytes, bool ensureNewLine, CancellationToken cancellationToken) { - var filter = options.CreateNewLineFilter (); + var filter = options.CreateNewLineFilter (ensureNewLine); int index, length; var output = filter.Flush (bytes, 0, bytes.Length, out index, out length); @@ -405,7 +400,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } /// - /// Writes the to the specified output stream. + /// Write the to the specified output stream. /// /// /// Writes the multipart MIME entity and its subparts to the output stream. @@ -427,9 +422,6 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = /// public override void WriteTo (FormatOptions options, Stream stream, bool contentOnly, CancellationToken cancellationToken = default (CancellationToken)) { - if (Boundary == null) - Boundary = GenerateBoundary (); - base.WriteTo (options, stream, contentOnly, cancellationToken); if (ContentType.IsMimeType ("multipart", "signed")) { @@ -444,7 +436,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = var cancellable = stream as ICancellableStream; if (RawPreamble != null && RawPreamble.Length > 0) - WriteBytes (options, stream, RawPreamble, cancellationToken); + WriteBytes (options, stream, RawPreamble, children.Count > 0 || EnsureNewLine, cancellationToken); var boundary = Encoding.ASCII.GetBytes ("--" + Boundary + "--"); @@ -479,7 +471,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = cancellable.Write (options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken); } else { for (int i = 0; i < children.Count; i++) { - var msg = children[i] as MessagePart; + var rfc822 = children[i] as MessagePart; var multi = children[i] as Multipart; var part = children[i] as MimePart; @@ -488,15 +480,16 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length); children[i].WriteTo (options, stream, false, cancellationToken); - if (msg != null && msg.Message != null && msg.Message.Body != null) { - multi = msg.Message.Body as Multipart; - part = msg.Message.Body as MimePart; + if (rfc822 != null && rfc822.Message != null && rfc822.Message.Body != null) { + multi = rfc822.Message.Body as Multipart; + part = rfc822.Message.Body as MimePart; } if ((part != null && part.Content == null) || (multi != null && !multi.WriteEndBoundary)) continue; + cancellationToken.ThrowIfCancellationRequested (); stream.Write (options.NewLineBytes, 0, options.NewLineBytes.Length); } @@ -513,15 +506,16 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } if (RawEpilogue != null && RawEpilogue.Length > 0) - WriteBytes (options, stream, RawEpilogue, cancellationToken); + WriteBytes (options, stream, RawEpilogue, EnsureNewLine, cancellationToken); } /// - /// Asynchronously writes the to the specified output stream. + /// Asynchronously write the to the specified output stream. /// /// - /// Writes the multipart MIME entity and its subparts to the output stream. + /// Asynchronously writes the multipart MIME entity and its subparts to the output stream. /// + /// An awaitable task. /// The formatting options. /// The output stream. /// true if only the content should be written; otherwise, false. @@ -539,9 +533,6 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = /// public override async Task WriteToAsync (FormatOptions options, Stream stream, bool contentOnly, CancellationToken cancellationToken = default (CancellationToken)) { - if (Boundary == null) - Boundary = GenerateBoundary (); - await base.WriteToAsync (options, stream, contentOnly, cancellationToken).ConfigureAwait (false); if (ContentType.IsMimeType ("multipart", "signed")) { @@ -554,7 +545,7 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = } if (RawPreamble != null && RawPreamble.Length > 0) - await WriteBytesAsync (options, stream, RawPreamble, cancellationToken).ConfigureAwait (false); + await WriteBytesAsync (options, stream, RawPreamble, children.Count > 0 || EnsureNewLine, cancellationToken).ConfigureAwait (false); var boundary = Encoding.ASCII.GetBytes ("--" + Boundary + "--"); @@ -588,13 +579,13 @@ public override void Prepare (EncodingConstraint constraint, int maxLineLength = await stream.WriteAsync (options.NewLineBytes, 0, options.NewLineBytes.Length, cancellationToken).ConfigureAwait (false); if (RawEpilogue != null && RawEpilogue.Length > 0) - await WriteBytesAsync (options, stream, RawEpilogue, cancellationToken).ConfigureAwait (false); + await WriteBytesAsync (options, stream, RawEpilogue, EnsureNewLine, cancellationToken).ConfigureAwait (false); } #region ICollection implementation /// - /// Gets the number of parts in the multipart. + /// Get the number of parts in the multipart. /// /// /// Indicates the number of parts in the multipart. @@ -605,7 +596,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether this instance is read only. /// /// /// A is never read-only. @@ -616,7 +607,7 @@ public bool IsReadOnly { } /// - /// Adds the specified part. + /// Add an entity to the multipart. /// /// /// Adds the specified part to the multipart. @@ -635,7 +626,7 @@ public void Add (MimeEntity part) } /// - /// Clears the multipart. + /// Clear a multipart. /// /// /// Removes all of the parts within the multipart. @@ -647,7 +638,7 @@ public void Clear () } /// - /// Checks if the contains the specified part. + /// Check if the contains the specified part. /// /// /// Determines whether or not the multipart contains the specified part. @@ -667,7 +658,7 @@ public bool Contains (MimeEntity part) } /// - /// Copies all of the entities in the to the specified array. + /// Copy all of the entities in the to the specified array. /// /// /// Copies all of the entities within the into the array, @@ -687,7 +678,7 @@ public void CopyTo (MimeEntity[] array, int arrayIndex) } /// - /// Removes the specified part. + /// Remove an entity from the multipart. /// /// /// Removes the specified part, if it exists within the multipart. @@ -715,7 +706,7 @@ public bool Remove (MimeEntity part) #region IList implementation /// - /// Gets the index of the specified part. + /// Get the index of an entity. /// /// /// Finds the index of the specified part, if it exists. @@ -734,7 +725,7 @@ public int IndexOf (MimeEntity part) } /// - /// Inserts the part at the specified index. + /// Insert an entity into the at the specified index. /// /// /// Inserts the part into the multipart at the specified index. @@ -760,10 +751,10 @@ public void Insert (int index, MimeEntity part) } /// - /// Removes the part at the specified index. + /// Remove an entity from the at the specified index. /// /// - /// Removes the part at the specified index. + /// Removes the entity at the specified index. /// /// The index. /// @@ -776,7 +767,7 @@ public void RemoveAt (int index) } /// - /// Gets or sets the at the specified index. + /// Get or set the at the specified index. /// /// /// Gets or sets the at the specified index. @@ -805,7 +796,7 @@ public MimeEntity this[int index] { #region IEnumerable implementation /// - /// Gets the enumerator for the children of the . + /// Get the enumerator for the children of the . /// /// /// Gets the enumerator for the children of the . @@ -821,7 +812,7 @@ public IEnumerator GetEnumerator () #region IEnumerable implementation /// - /// Gets the enumerator for the children of the . + /// Get the enumerator for the children of the . /// /// /// Gets the enumerator for the children of the . diff --git a/MimeKit/MultipartAlternative.cs b/MimeKit/MultipartAlternative.cs index f42e950c4a..1fd29ff23c 100644 --- a/MimeKit/MultipartAlternative.cs +++ b/MimeKit/MultipartAlternative.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,10 +42,10 @@ namespace MimeKit { public class MultipartAlternative : Multipart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -56,7 +56,7 @@ public MultipartAlternative (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -73,7 +73,7 @@ public MultipartAlternative (params object[] args) : base ("alternative", args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -108,12 +108,12 @@ public string HtmlBody { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/MultipartRelated.cs b/MimeKit/MultipartRelated.cs index de002e59ba..cefed06494 100644 --- a/MimeKit/MultipartRelated.cs +++ b/MimeKit/MultipartRelated.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,13 +38,16 @@ namespace MimeKit { /// A multipart/related MIME entity contains, as one might expect, inter-related MIME parts which /// typically reference each other via URIs based on the Content-Id and/or Content-Location headers. /// + /// + /// + /// public class MultipartRelated : Multipart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -55,7 +58,7 @@ public MultipartRelated (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -72,7 +75,7 @@ public MultipartRelated (params object[] args) : base ("related", args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -83,19 +86,32 @@ public MultipartRelated () : base ("related") int GetRootIndex () { - string start = ContentType.Parameters["start"]; + var start = ContentType.Parameters["start"]; - if (start == null) - return -1; + if (start != null) { + string contentId; + + if ((contentId = MimeUtils.EnumerateReferences (start).FirstOrDefault ()) == null) + contentId = start; + + var cid = new Uri (string.Format ("cid:{0}", contentId)); + + return IndexOf (cid); + } - string contentId; + var type = ContentType.Parameters["type"]; - if ((contentId = MimeUtils.EnumerateReferences (start).FirstOrDefault ()) == null) - contentId = start; + if (type == null) + return -1; - var cid = new Uri (string.Format ("cid:{0}", contentId)); + for (int index = 0; index < Count; index++) { + var mimeType = this[index].ContentType.MimeType; - return IndexOf (cid); + if (mimeType.Equals (type, StringComparison.OrdinalIgnoreCase)) + return index; + } + + return -1; } /// @@ -109,6 +125,9 @@ int GetRootIndex () /// When setting the root document MIME part, the Content-Type header of the multipart/related part is also /// updated with a appropriate "start" and "type" parameters. /// + /// + /// + /// /// The root MIME part. /// /// is null. @@ -140,17 +159,18 @@ public MimeEntity Root { index = 0; } - if (string.IsNullOrEmpty (value.ContentId)) - value.ContentId = MimeUtils.GenerateMessageId (); - ContentType.Parameters["type"] = value.ContentType.MediaType + "/" + value.ContentType.MediaSubtype; // Note: we only use a "start" parameter if the index of the root entity is not at index 0 in order // to work around the following Thunderbird bug: https://bugzilla.mozilla.org/show_bug.cgi?id=471402 - if (index > 0) + if (index > 0) { + if (string.IsNullOrEmpty (value.ContentId)) + value.ContentId = MimeUtils.GenerateMessageId (); + ContentType.Parameters["start"] = "<" + value.ContentId + ">"; - else + } else { ContentType.Parameters.Remove ("start"); + } } } @@ -158,12 +178,12 @@ public MimeEntity Root { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -205,6 +225,9 @@ public bool Contains (Uri uri) /// multipart/related part's Content-Base header in order to produce an absolute URI that can be /// compared with the provided absolute URI. /// + /// + /// + /// /// The index of the part matching the specified URI if found; otherwise -1. /// The URI of the MIME part. /// diff --git a/MimeKit/MultipartReport.cs b/MimeKit/MultipartReport.cs index 142b7a344d..5754f098c7 100644 --- a/MimeKit/MultipartReport.cs +++ b/MimeKit/MultipartReport.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,14 +33,19 @@ namespace MimeKit { /// /// A multipart/related MIME entity is a general container part for electronic mail /// reports of any kind. + /// + /// /// + /// + /// + /// public class MultipartReport : Multipart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -51,7 +56,7 @@ public MultipartReport (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -75,7 +80,7 @@ public MultipartReport (string reportType, params object[] args) : base ("report } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new part. @@ -100,6 +105,9 @@ public MultipartReport (string reportType) : base ("report") /// The report type should be the subtype of the second /// of the multipart/report. /// + /// + /// + /// /// The type of the report. /// /// is null. @@ -121,12 +129,12 @@ public string ReportType { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// diff --git a/MimeKit/Parameter.cs b/MimeKit/Parameter.cs index d27220fd2f..d773e86326 100644 --- a/MimeKit/Parameter.cs +++ b/MimeKit/Parameter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,11 +27,6 @@ using System; using System.Text; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -#endif - using MimeKit.Encodings; using MimeKit.Utils; @@ -50,7 +45,7 @@ public class Parameter string text; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new parameter with the specified name and value. @@ -86,7 +81,7 @@ public Parameter (string name, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new parameter with the specified name and value. @@ -129,7 +124,7 @@ public Parameter (Encoding encoding, string name, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new parameter with the specified name and value. @@ -216,6 +211,9 @@ public Encoding Encoding { /// If set to , the encoding /// method used will default to the value set on the . /// + /// + /// + /// /// The encoding method. /// /// is not a valid value. diff --git a/MimeKit/ParameterEncodingMethod.cs b/MimeKit/ParameterEncodingMethod.cs index 7a35db6d75..3670f6e8cc 100644 --- a/MimeKit/ParameterEncodingMethod.cs +++ b/MimeKit/ParameterEncodingMethod.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -35,6 +35,9 @@ namespace MimeKit { /// some older email clients to improperly encode using the method described in /// rfc2047 instead. /// + /// + /// + /// public enum ParameterEncodingMethod { /// /// Use the default encoding method set on the . diff --git a/MimeKit/ParameterList.cs b/MimeKit/ParameterList.cs index 9adb4a5fc5..3178b458bb 100644 --- a/MimeKit/ParameterList.cs +++ b/MimeKit/ParameterList.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,14 +28,9 @@ using System.IO; using System.Text; using System.Collections; +using System.Globalization; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - using MimeKit.Encodings; using MimeKit.Utils; @@ -52,7 +47,7 @@ public class ParameterList : IList readonly List parameters; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new parameter list. @@ -64,7 +59,7 @@ public ParameterList () } /// - /// Adds a parameter with the specified name and value. + /// Add a parameter with the specified name and value. /// /// /// Adds a new parameter to the list with the specified name and value. @@ -85,7 +80,7 @@ public void Add (string name, string value) } /// - /// Adds a parameter with the specified name and value. + /// Add a parameter with the specified name and value. /// /// /// Adds a new parameter to the list with the specified name and value. @@ -109,7 +104,7 @@ public void Add (Encoding encoding, string name, string value) } /// - /// Adds a parameter with the specified name and value. + /// Add a parameter with the specified name and value. /// /// /// Adds a new parameter to the list with the specified name and value. @@ -138,7 +133,7 @@ public void Add (string charset, string name, string value) } /// - /// Checks if the contains a parameter with the specified name. + /// Check if the contains a parameter with the specified name. /// /// /// Determines whether or not the parameter list contains a parameter with the specified name. @@ -158,7 +153,7 @@ public bool Contains (string name) } /// - /// Gets the index of the requested parameter, if it exists. + /// Get the index of the requested parameter, if it exists. /// /// /// Finds the index of the parameter with the specified name, if it exists. @@ -182,7 +177,7 @@ public int IndexOf (string name) } /// - /// Inserts a parameter with the specified name and value at the given index. + /// Insert a parameter with the specified name and value at the given index. /// /// /// Inserts a new parameter with the given name and value at the specified index. @@ -210,7 +205,7 @@ public void Insert (int index, string name, string value) } /// - /// Removes the specified parameter. + /// Remove the specified parameter. /// /// /// Removes the parameter with the specified name from the list, if it exists. @@ -234,7 +229,7 @@ public bool Remove (string name) } /// - /// Gets or sets the value of a parameter with the specified name. + /// Get or set the value of a parameter with the specified name. /// /// /// Gets or sets the value of a parameter with the specified name. @@ -277,11 +272,14 @@ public string this [string name] { } /// - /// Gets the parameter with the specified name. + /// Get the parameter with the specified name. /// /// /// Gets the parameter with the specified name. /// + /// + /// + /// /// true if the parameter exists; otherwise, false. /// The parameter name. /// The parameter. @@ -297,7 +295,7 @@ public bool TryGetValue (string name, out Parameter param) } /// - /// Gets the value of the parameter with the specified name. + /// Get the value of the parameter with the specified name. /// /// /// Gets the value of the parameter with the specified name. @@ -328,7 +326,7 @@ public bool TryGetValue (string name, out string value) #region ICollection implementation /// - /// Gets the number of parameters in the . + /// Get the number of parameters in the . /// /// /// Indicates the number of parameters in the list. @@ -339,7 +337,7 @@ public int Count { } /// - /// Gets a value indicating whether this instance is read only. + /// Get a value indicating whether this instance is read only. /// /// /// A is never read-only. @@ -350,7 +348,7 @@ public bool IsReadOnly { } /// - /// Adds the specified parameter. + /// Add a to a . /// /// /// Adds the specified parameter to the end of the list. @@ -369,7 +367,7 @@ public void Add (Parameter param) throw new ArgumentNullException (nameof (param)); if (table.ContainsKey (param.Name)) - throw new ArgumentException ("A parameter of that name already exists."); + throw new ArgumentException ("A parameter of that name already exists.", nameof (param)); param.Changed += OnParamChanged; table.Add (param.Name, param); @@ -379,7 +377,7 @@ public void Add (Parameter param) } /// - /// Clears the parameter list. + /// Clear the parameter list. /// /// /// Removes all of the parameters from the list. @@ -396,7 +394,7 @@ public void Clear () } /// - /// Checks if the contains the specified parameter. + /// Check if the contains the specified parameter. /// /// /// Determines whether or not the parameter list contains the specified parameter. @@ -416,7 +414,7 @@ public bool Contains (Parameter param) } /// - /// Copies all of the contained parameters to the specified array. + /// Copy all of the parameters in the list to the specified array. /// /// /// Copies all of the parameters within the into the array, @@ -430,7 +428,7 @@ public void CopyTo (Parameter[] array, int arrayIndex) } /// - /// Removes the specified parameter. + /// Remove a from a . /// /// /// Removes the specified parameter from the list. @@ -462,7 +460,7 @@ public bool Remove (Parameter param) #region IList implementation /// - /// Gets the index of the requested parameter, if it exists. + /// Ges the index of the requested parameter, if it exists. /// /// /// Finds the index of the specified parameter, if it exists. @@ -481,7 +479,7 @@ public int IndexOf (Parameter param) } /// - /// Inserts the specified parameter at the given index. + /// Insert a at the specified index. /// /// /// Inserts the parameter at the specified index in the list. @@ -507,7 +505,7 @@ public void Insert (int index, Parameter param) throw new ArgumentNullException (nameof (param)); if (table.ContainsKey (param.Name)) - throw new ArgumentException ("A parameter of that name already exists."); + throw new ArgumentException ("A parameter of that name already exists.", nameof (param)); parameters.Insert (index, param); table.Add (param.Name, param); @@ -517,7 +515,7 @@ public void Insert (int index, Parameter param) } /// - /// Removes the parameter at the specified index. + /// Remove the parameter at the specified index. /// /// /// Removes the parameter at the specified index. @@ -541,10 +539,10 @@ public void RemoveAt (int index) } /// - /// Gets or sets the at the specified index. + /// Get or set the at the specified index. /// /// - /// Gets or sets the at the specified index. + /// Gets or sets the at the specified index. /// /// The parameter at the specified index. /// The index. @@ -563,7 +561,7 @@ public Parameter this [int index] { return parameters[index]; } set { - if (index < 0 || index > Count) + if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException (nameof (index)); if (value == null) @@ -579,7 +577,7 @@ public Parameter this [int index] { if (table[param.Name] == param) table[param.Name] = value; } else if (table.ContainsKey (value.Name)) { - throw new ArgumentException ("A parameter of that name already exists."); + throw new ArgumentException ("A parameter of that name already exists.", nameof (value)); } else { table.Add (value.Name, value); table.Remove (param.Name); @@ -598,7 +596,7 @@ public Parameter this [int index] { #region IEnumerable implementation /// - /// Gets an enumerator for the list of parameters. + /// Get an enumerator for the list of parameters. /// /// /// Gets an enumerator for the list of parameters. @@ -614,7 +612,7 @@ public IEnumerator GetEnumerator () #region IEnumerable implementation /// - /// Gets an enumerator for the list of parameters. + /// Get an enumerator for the list of parameters. /// /// /// Gets an enumerator for the list of parameters. @@ -634,7 +632,7 @@ internal void Encode (FormatOptions options, StringBuilder builder, ref int line } /// - /// Returns a string representation of the parameters in the . + /// Serialize a to a string. /// /// /// If there are multiple parameters in the list, they will be separated by a semicolon. @@ -714,7 +712,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i startIndex = index; if (!SkipParamName (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Invalid parameter name token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid parameter name token at offset {0}", startIndex), startIndex, index); return false; } @@ -726,7 +724,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); return false; } @@ -740,7 +738,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); return false; } @@ -752,7 +750,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); return false; } @@ -766,7 +764,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); return false; } @@ -779,12 +777,10 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i } if (text[index] != (byte) '=') { - if (index >= endIndex) { - if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); - return false; - } + return false; } index++; @@ -794,7 +790,7 @@ static bool TryParseNameValuePair (ParserOptions options, byte[] text, ref int i if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete parameter at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete parameter at offset {0}", startIndex), startIndex, index); return false; } @@ -977,13 +973,16 @@ internal static bool TryParse (ParserOptions options, byte[] text, ref int index break; if (text[index] != (byte) ';') { - if (throwOnError) - throw new ParseException (string.Format ("Invalid parameter list token at offset {0}", index), index, index); + if (options.ParameterComplianceMode == RfcComplianceMode.Strict) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid parameter list token at offset {0}", index), index, index); - return false; + return false; + } + } else { + // Skip over ';' + index++; } - - index++; } while (true); paramList = new ParameterList (); diff --git a/MimeKit/ParseException.cs b/MimeKit/ParseException.cs index a461816c8d..1e87e66534 100644 --- a/MimeKit/ParseException.cs +++ b/MimeKit/ParseException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ public class ParseException : FormatException { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -67,7 +67,7 @@ protected ParseException (SerializationInfo info, StreamingContext context) : ba #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -83,7 +83,7 @@ public ParseException (string message, int tokenIndex, int errorIndex, Exception } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -114,13 +114,10 @@ public ParseException (string message, int tokenIndex, int errorIndex) : base (m [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("TokenIndex", TokenIndex); info.AddValue ("ErrorIndex", ErrorIndex); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/ParserOptions.cs b/MimeKit/ParserOptions.cs index 45032de409..e851f11f92 100644 --- a/MimeKit/ParserOptions.cs +++ b/MimeKit/ParserOptions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,10 +29,6 @@ using System.Reflection; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - #if ENABLE_CRYPTO using MimeKit.Cryptography; #endif @@ -50,7 +46,7 @@ namespace MimeKit { /// public class ParserOptions { - readonly Dictionary mimeTypes = new Dictionary (); + readonly Dictionary mimeTypes = new Dictionary (StringComparer.Ordinal); static readonly Type[] ConstructorArgTypes = { typeof (MimeEntityConstructorArgs) }; /// @@ -69,21 +65,31 @@ public class ParserOptions /// In general, you'll probably want this value to be /// (the default) as it allows maximum interoperability with existing (broken) mail clients /// and other mail software such as sloppily written perl scripts (aka spambots). - /// Even in mode, the address - /// parser is fairly liberal in what it accepts. Setting it to - /// just makes it try harder to deal with garbage input. + /// Even in mode, the address parser + /// is fairly liberal in what it accepts. Setting it to + /// just makes it try harder to deal with garbage input. /// /// The RFC compliance mode. public RfcComplianceMode AddressParserComplianceMode { get; set; } /// - /// Gets or sets whether the rfc822 address parser should allow addresses without a domain. + /// Gets or sets whether the rfc822 address parser should ignore unquoted commas in address names. /// /// - /// In general, you'll probably want this value to be false (the default) as it allows + /// In general, you'll probably want this value to be true (the default) as it allows /// maximum interoperability with existing (broken) mail clients and other mail software such as /// sloppily written perl scripts (aka spambots) that do not properly quote the name when it /// contains a comma. + /// + /// true if the address parser should ignore unquoted commas in address names; otherwise, false. + public bool AllowUnquotedCommasInAddresses { get; set; } + + /// + /// Gets or sets whether the rfc822 address parser should allow addresses without a domain. + /// + /// + /// In general, you'll probably want this value to be true (the default) as it allows + /// maximum interoperability with older email messages that may contain local UNIX addresses. /// This option exists in order to allow parsing of mailbox addresses that do not have an /// @domain component. These types of addresses are rare and were typically only used when sending /// mail to other users on the same UNIX system. @@ -100,9 +106,21 @@ public class ParserOptions /// formed. If the value is set too large, then it is possible that a maliciously formed set of /// recursive group addresses could cause a stack overflow. /// - /// The max address group depth. + /// The maximum address group depth. public int MaxAddressGroupDepth { get; set; } + /// + /// Gets or sets the maximum MIME nesting depth the parser should accept. + /// + /// + /// This option exists in order to define the maximum recursive depth of MIME parts that the parser + /// should accept before treating further nesting as a leaf-node MIME part and not recursing any further. + /// If the value is set too large, then it is possible that a maliciously formed set of rdeeply nested + /// multipart MIME parts could cause a stack overflow. + /// + /// The maximum MIME nesting depth. + public int MaxMimeDepth { get; set; } + /// /// Gets or sets the compliance mode that should be used when parsing Content-Type and Content-Disposition parameters. /// @@ -110,9 +128,9 @@ public class ParserOptions /// In general, you'll probably want this value to be /// (the default) as it allows maximum interoperability with existing (broken) mail clients /// and other mail software such as sloppily written perl scripts (aka spambots). - /// Even in mode, the parameter - /// parser is fairly liberal in what it accepts. Setting it to - /// just makes it try harder to deal with garbage input. + /// Even in mode, the parameter parser + /// is fairly liberal in what it accepts. Setting it to + /// just makes it try harder to deal with garbage input. /// /// The RFC compliance mode. public RfcComplianceMode ParameterComplianceMode { get; set; } @@ -145,8 +163,8 @@ public class ParserOptions /// Gets or sets the charset encoding to use as a fallback for 8bit headers. /// /// - /// and - /// + /// and + /// /// use this charset encoding as a fallback when decoding 8bit text into unicode. The first /// charset encoding attempted is UTF-8, followed by this charset encoding, before finally /// falling back to iso-8859-1. @@ -155,7 +173,7 @@ public class ParserOptions public Encoding CharsetEncoding { get; set; } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// By default, new instances of enable rfc2047 work-arounds @@ -168,13 +186,15 @@ public ParserOptions () ParameterComplianceMode = RfcComplianceMode.Loose; Rfc2047ComplianceMode = RfcComplianceMode.Loose; CharsetEncoding = CharsetUtils.UTF8; - AllowAddressesWithoutDomain = false; + AllowUnquotedCommasInAddresses = true; + AllowAddressesWithoutDomain = true; RespectContentLength = false; MaxAddressGroupDepth = 3; + MaxMimeDepth = 1024; } /// - /// Clones an instance of . + /// Clones an instance of . /// /// /// Clones a set of options, allowing you to change a specific option @@ -185,12 +205,14 @@ public ParserOptions Clone () { var options = new ParserOptions (); options.AddressParserComplianceMode = AddressParserComplianceMode; + options.AllowUnquotedCommasInAddresses = AllowUnquotedCommasInAddresses; options.AllowAddressesWithoutDomain = AllowAddressesWithoutDomain; options.ParameterComplianceMode = ParameterComplianceMode; options.Rfc2047ComplianceMode = Rfc2047ComplianceMode; options.MaxAddressGroupDepth = MaxAddressGroupDepth; options.RespectContentLength = RespectContentLength; options.CharsetEncoding = CharsetEncoding; + options.MaxMimeDepth = MaxMimeDepth; foreach (var mimeType in mimeTypes) options.mimeTypes.Add (mimeType.Key, mimeType.Value); @@ -198,27 +220,6 @@ public ParserOptions Clone () return options; } -#if PORTABLE - static ConstructorInfo GetConstructor (TypeInfo type, Type[] argTypes) - { - foreach (var ctor in type.DeclaredConstructors) { - var args = ctor.GetParameters (); - - if (args.Length != ConstructorArgTypes.Length) - continue; - - bool matched = true; - for (int i = 0; i < argTypes.Length && matched; i++) - matched = matched && args[i].ParameterType == argTypes[i]; - - if (matched) - return ctor; - } - - return null; - } -#endif - /// /// Registers the subclass for the specified mime-type. /// @@ -252,7 +253,7 @@ public void RegisterMimeType (string mimeType, Type type) mimeType = mimeType.ToLowerInvariant (); -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 var info = type.GetTypeInfo (); #else var info = type; @@ -263,11 +264,7 @@ public void RegisterMimeType (string mimeType, Type type) !info.IsSubclassOf (typeof (MimePart))) throw new ArgumentException ("The specified type must be a subclass of MessagePart, Multipart, or MimePart.", nameof (type)); -#if PORTABLE - var ctor = GetConstructor (info, ConstructorArgTypes); -#else var ctor = type.GetConstructor (ConstructorArgTypes); -#endif if (ctor == null) throw new ArgumentException ("The specified type must have a constructor that takes a MimeEntityConstructorArgs argument.", nameof (type)); @@ -298,9 +295,13 @@ static bool IsEncoded (IList
headers) return false; } - internal MimeEntity CreateEntity (ContentType contentType, IList
headers, bool toplevel) + internal MimeEntity CreateEntity (ContentType contentType, IList
headers, bool toplevel, int depth) { var args = new MimeEntityConstructorArgs (this, contentType, headers, toplevel); + + if (depth >= MaxMimeDepth) + return new MimePart (args); + var subtype = contentType.MediaSubtype.ToLowerInvariant (); var type = contentType.MediaType.ToLowerInvariant (); @@ -323,17 +324,24 @@ internal MimeEntity CreateEntity (ContentType contentType, IList
headers // actually handle that w/o any problems. if (type == "message") { switch (subtype) { + case "global-disposition-notification": case "disposition-notification": return new MessageDispositionNotification (args); + case "global-delivery-status": case "delivery-status": return new MessageDeliveryStatus (args); case "partial": if (!IsEncoded (headers)) return new MessagePartial (args); break; + case "global-headers": + if (!IsEncoded (headers)) + return new TextRfc822Headers (args); + break; case "external-body": case "rfc2822": case "rfc822": + case "global": case "news": if (!IsEncoded (headers)) return new MessagePart (args); @@ -384,8 +392,12 @@ internal MimeEntity CreateEntity (ContentType contentType, IList
headers } } - if (type == "text") + if (type == "text") { + if (subtype == "rfc822-headers" && !IsEncoded (headers)) + return new TextRfc822Headers (args); + return new TextPart (args); + } return new MimePart (args); } diff --git a/MimeKit/Properties/AssemblyInfo.cs b/MimeKit/Properties/AssemblyInfo.cs index 058e1482b9..873dfdc746 100644 --- a/MimeKit/Properties/AssemblyInfo.cs +++ b/MimeKit/Properties/AssemblyInfo.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,10 +33,10 @@ [assembly: AssemblyTitle ("MimeKit")] [assembly: AssemblyDescription ("A complete MIME library with support for S/MIME, PGP, DKIM and Unix mbox spools.")] [assembly: AssemblyConfiguration ("")] -[assembly: AssemblyCompany ("Xamarin Inc.")] +[assembly: AssemblyCompany (".NET Foundation")] [assembly: AssemblyProduct ("MimeKit")] -[assembly: AssemblyCopyright ("Copyright © 2013-2018 Xamarin Inc. (www.xamarin.com)")] -[assembly: AssemblyTrademark ("Xamarin Inc.")] +[assembly: AssemblyCopyright ("Copyright © 2013-2020 .NET Foundation and Contributors")] +[assembly: AssemblyTrademark (".NET Foundation")] [assembly: AssemblyCulture ("")] // Setting ComVisible to false makes the types in this assembly not visible @@ -44,7 +44,6 @@ // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible (true)] -#if !PORTABLE // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid ("2fe79b66-d107-45da-9493-175f59c4a53c")] [assembly: InternalsVisibleTo ("UnitTests, PublicKey=002400000480000094000000060200" + @@ -52,7 +51,6 @@ "4656c5bfe4c47803453a91ae525f723f4316fd90a3f87366f4d948593277e950f6d2df6ee26068" + "1877a6d9e71c3ea77e87e61f3878af1d69bf10dce8debe92c54ca8a10afc44dc08674f3db6594e" + "f545d67d31cc3e18b8f90d8f220c4b67d7e87f5b7e8df410ac8faeb3")] -#endif // Version information for an assembly consists of the following four values: // @@ -80,6 +78,6 @@ // // If there have only been bug fixes, bump the Micro Version and/or the Build Number // in the AssemblyFileVersion attribute. -[assembly: AssemblyInformationalVersion ("2.0.1.1.0")] -[assembly: AssemblyFileVersion ("2.0.1.1.0")] -[assembly: AssemblyVersion ("2.0.0.0")] +[assembly: AssemblyInformationalVersion ("2.10.1.1.0")] +[assembly: AssemblyFileVersion ("2.10.1.1.0")] +[assembly: AssemblyVersion ("2.10.0.0")] diff --git a/MimeKit/RfcComplianceMode.cs b/MimeKit/RfcComplianceMode.cs index 8009ac8540..2522f2fb25 100644 --- a/MimeKit/RfcComplianceMode.cs +++ b/MimeKit/RfcComplianceMode.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/CharBuffer.cs b/MimeKit/Text/CharBuffer.cs new file mode 100644 index 0000000000..6afdac1e7e --- /dev/null +++ b/MimeKit/Text/CharBuffer.cs @@ -0,0 +1,93 @@ +// +// CharBuffer.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Runtime.CompilerServices; + +namespace MimeKit.Text { + class CharBuffer + { + char[] buffer; + + public CharBuffer (int capacity) + { + buffer = new char[capacity]; + } + + public int Length { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl (MethodImplOptions.AggressiveInlining)] + set; + } + + public char this[int index] { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get { return buffer[index]; } + [MethodImpl (MethodImplOptions.AggressiveInlining)] + set { buffer[index] = value; } + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + void EnsureCapacity (int length) + { + if (length < buffer.Length) + return; + + int capacity = buffer.Length << 1; + while (capacity <= length) + capacity <<= 1; + + Array.Resize (ref buffer, capacity); + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public void Append (char c) + { + EnsureCapacity (Length + 1); + buffer[Length++] = c; + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public void Append (string str) + { + EnsureCapacity (Length + str.Length); + str.CopyTo (0, buffer, Length, str.Length); + Length += str.Length; + } + + [MethodImpl (MethodImplOptions.AggressiveInlining)] + public override string ToString () + { + return new string (buffer, 0, Length); + } + + public static implicit operator string (CharBuffer buffer) + { + return buffer.ToString (); + } + } +} diff --git a/MimeKit/Text/FlowedToHtml.cs b/MimeKit/Text/FlowedToHtml.cs index 79cc06e71f..22f77dccec 100644 --- a/MimeKit/Text/FlowedToHtml.cs +++ b/MimeKit/Text/FlowedToHtml.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,7 +44,7 @@ public class FlowedToHtml : TextConverter readonly UrlScanner scanner; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new flowed text to HTML converter. @@ -87,7 +87,7 @@ public override TextFormat OutputFormat { /// The flowed text format defines a Content-Type parameter called "delsp" which can /// have a value of "yes" or "no". If the parameter exists and the value is "yes", then /// should be set to true, otherwise - /// should be set to false. + /// should be set to false. /// /// /// @@ -97,18 +97,6 @@ public bool DeleteSpace { get; set; } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - /// /// Get or set the footer format. /// @@ -120,18 +108,6 @@ public HeaderFooterFormat FooterFormat { get; set; } - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - /// /// Get or set the header format. /// diff --git a/MimeKit/Text/FlowedToText.cs b/MimeKit/Text/FlowedToText.cs index 234b7b26fb..3b0092fc64 100644 --- a/MimeKit/Text/FlowedToText.cs +++ b/MimeKit/Text/FlowedToText.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ namespace MimeKit.Text { public class FlowedToText : TextConverter { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new flowed text to text converter. @@ -77,37 +77,13 @@ public override TextFormat OutputFormat { /// The flowed text format defines a Content-Type parameter called "delsp" which can /// have a value of "yes" or "no". If the parameter exists and the value is "yes", then /// should be set to true, otherwise - /// should be set to false. + /// should be set to false. /// /// true if the trailing space on a wrapped line should be deleted; otherwise, false. public bool DeleteSpace { get; set; } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - static string Unquote (string line, out int quoteDepth) { int index = 0; diff --git a/MimeKit/Text/HeaderFooterFormat.cs b/MimeKit/Text/HeaderFooterFormat.cs index 3225c107f8..a5bd0ebdbd 100644 --- a/MimeKit/Text/HeaderFooterFormat.cs +++ b/MimeKit/Text/HeaderFooterFormat.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/HtmlAttribute.cs b/MimeKit/Text/HtmlAttribute.cs index 8618c3dad9..3586c5942f 100644 --- a/MimeKit/Text/HtmlAttribute.cs +++ b/MimeKit/Text/HtmlAttribute.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,7 @@ namespace MimeKit.Text { public class HtmlAttribute { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new HTML attribute with the given id and value. @@ -60,7 +60,7 @@ public HtmlAttribute (HtmlAttributeId id, string value) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new HTML attribute with the given name and value. diff --git a/MimeKit/Text/HtmlAttributeCollection.cs b/MimeKit/Text/HtmlAttributeCollection.cs index 736a774150..e805c2fbec 100644 --- a/MimeKit/Text/HtmlAttributeCollection.cs +++ b/MimeKit/Text/HtmlAttributeCollection.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ public class HtmlAttributeCollection : IEnumerable readonly List attributes = new List (); /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Text/HtmlAttributeId.cs b/MimeKit/Text/HtmlAttributeId.cs index 9f08a0afa4..7c61ead19a 100644 --- a/MimeKit/Text/HtmlAttributeId.cs +++ b/MimeKit/Text/HtmlAttributeId.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -621,7 +621,7 @@ public static string ToAttributeName (this HtmlAttributeId value) { var name = value.ToString (); -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 var field = typeof (HtmlAttributeId).GetTypeInfo ().GetDeclaredField (name); var attrs = field.GetCustomAttributes (typeof (HtmlAttributeNameAttribute), false).ToArray (); #else diff --git a/MimeKit/Text/HtmlEntityDecoder.cs b/MimeKit/Text/HtmlEntityDecoder.cs index 44bd1ba4fb..3838bdcd19 100644 --- a/MimeKit/Text/HtmlEntityDecoder.cs +++ b/MimeKit/Text/HtmlEntityDecoder.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,13 +37,14 @@ public partial class HtmlEntityDecoder { readonly char[] pushed; readonly int[] states; + bool semicolon; bool numeric; byte digits; byte xbase; int index; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -122,6 +123,9 @@ bool PushNumericEntity (char c) /// public bool Push (char c) { + if (semicolon) + return false; + if (index == 0) { if (c != '&') throw new ArgumentOutOfRangeException (nameof (c), "The first character that is pushed MUST be the '&' character."); @@ -135,9 +139,6 @@ public bool Push (char c) if (index + 1 > MaxEntityLength) return false; - if (c == ';') - return false; - if (index == 1 && c == '#') { pushed[index] = '#'; states[index] = 0; @@ -146,12 +147,25 @@ public bool Push (char c) return true; } - return numeric ? PushNumericEntity (c) : PushNamedEntity (c); + semicolon = c == ';'; + + if (numeric) { + if (c == ';') { + states[index] = states[index - 1]; + pushed[index] = ';'; + index++; + return true; + } + + return PushNumericEntity (c); + } + + return PushNamedEntity (c); } string GetNumericEntityValue () { - if (digits == 0) + if (digits == 0 || !semicolon) return new string (pushed, 0, index); int state = states[index - 1]; @@ -234,6 +248,7 @@ internal string GetPushedInput () /// public void Reset () { + semicolon = false; numeric = false; digits = 0; xbase = 0; diff --git a/MimeKit/Text/HtmlEntityDecoder.g.cs b/MimeKit/Text/HtmlEntityDecoder.g.cs index 14fa119eaa..f9cc9c908c 100644 --- a/MimeKit/Text/HtmlEntityDecoder.g.cs +++ b/MimeKit/Text/HtmlEntityDecoder.g.cs @@ -1,9 +1,9 @@ -// +// // HtmlEntityDecoder.g.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,10192 +26,12408 @@ // WARNING: This file is auto-generated. DO NOT EDIT! +using System.Collections.Generic; + namespace MimeKit.Text { - public partial class HtmlEntityDecoder { - const int MaxEntityLength = 32; + public partial class HtmlEntityDecoder + { + const int MaxEntityLength = 33; + + static readonly Dictionary NamedEntities; + + struct Transition + { + public readonly int From; + public readonly int To; + + public Transition (int from, int to) + { + From = from; + To = to; + } + } + + static readonly Transition[] TransitionTable_1; + static readonly Transition[] TransitionTable_2; + static readonly Transition[] TransitionTable_3; + static readonly Transition[] TransitionTable_4; + static readonly Transition[] TransitionTable_5; + static readonly Transition[] TransitionTable_6; + static readonly Transition[] TransitionTable_7; + static readonly Transition[] TransitionTable_8; + static readonly Transition[] TransitionTable_semicolon; + static readonly Transition[] TransitionTable_A; + static readonly Transition[] TransitionTable_B; + static readonly Transition[] TransitionTable_C; + static readonly Transition[] TransitionTable_D; + static readonly Transition[] TransitionTable_E; + static readonly Transition[] TransitionTable_F; + static readonly Transition[] TransitionTable_G; + static readonly Transition[] TransitionTable_H; + static readonly Transition[] TransitionTable_I; + static readonly Transition[] TransitionTable_J; + static readonly Transition[] TransitionTable_K; + static readonly Transition[] TransitionTable_L; + static readonly Transition[] TransitionTable_M; + static readonly Transition[] TransitionTable_N; + static readonly Transition[] TransitionTable_O; + static readonly Transition[] TransitionTable_P; + static readonly Transition[] TransitionTable_Q; + static readonly Transition[] TransitionTable_R; + static readonly Transition[] TransitionTable_S; + static readonly Transition[] TransitionTable_T; + static readonly Transition[] TransitionTable_U; + static readonly Transition[] TransitionTable_V; + static readonly Transition[] TransitionTable_W; + static readonly Transition[] TransitionTable_X; + static readonly Transition[] TransitionTable_Y; + static readonly Transition[] TransitionTable_Z; + static readonly Transition[] TransitionTable_a; + static readonly Transition[] TransitionTable_b; + static readonly Transition[] TransitionTable_c; + static readonly Transition[] TransitionTable_d; + static readonly Transition[] TransitionTable_e; + static readonly Transition[] TransitionTable_f; + static readonly Transition[] TransitionTable_g; + static readonly Transition[] TransitionTable_h; + static readonly Transition[] TransitionTable_i; + static readonly Transition[] TransitionTable_j; + static readonly Transition[] TransitionTable_k; + static readonly Transition[] TransitionTable_l; + static readonly Transition[] TransitionTable_m; + static readonly Transition[] TransitionTable_n; + static readonly Transition[] TransitionTable_o; + static readonly Transition[] TransitionTable_p; + static readonly Transition[] TransitionTable_q; + static readonly Transition[] TransitionTable_r; + static readonly Transition[] TransitionTable_s; + static readonly Transition[] TransitionTable_t; + static readonly Transition[] TransitionTable_u; + static readonly Transition[] TransitionTable_v; + static readonly Transition[] TransitionTable_w; + static readonly Transition[] TransitionTable_x; + static readonly Transition[] TransitionTable_y; + static readonly Transition[] TransitionTable_z; + + static HtmlEntityDecoder () + { + TransitionTable_1 = new Transition[4] { + new Transition (566, 567), // &blk -> &blk1 + new Transition (2280, 2282), // &emsp -> &emsp1 + new Transition (2649, 2650), // &frac -> &frac1 + new Transition (8284, 8286) // &sup -> ¹ + }; + TransitionTable_2 = new Transition[4] { + new Transition (567, 568), // &blk1 -> &blk12 + new Transition (2649, 2663), // &frac -> &frac2 + new Transition (2650, 2651), // &frac1 -> ½ + new Transition (8284, 8288) // &sup -> ² + }; + TransitionTable_3 = new Transition[6] { + new Transition (566, 572), // &blk -> &blk3 + new Transition (2282, 2283), // &emsp1 -> &emsp13 + new Transition (2649, 2668), // &frac -> &frac3 + new Transition (2650, 2653), // &frac1 -> &frac13 + new Transition (2663, 2664), // &frac2 -> &frac23 + new Transition (8284, 8290) // &sup -> ³ + }; + TransitionTable_4 = new Transition[7] { + new Transition (567, 570), // &blk1 -> &blk14 + new Transition (572, 573), // &blk3 -> &blk34 + new Transition (2282, 2285), // &emsp1 -> &emsp14 + new Transition (2649, 2675), // &frac -> &frac4 + new Transition (2650, 2655), // &frac1 -> ¼ + new Transition (2668, 2669), // &frac3 -> ¾ + new Transition (8464, 8465) // &there -> &there4 + }; + TransitionTable_5 = new Transition[5] { + new Transition (2649, 2678), // &frac -> &frac5 + new Transition (2650, 2657), // &frac1 -> &frac15 + new Transition (2663, 2666), // &frac2 -> &frac25 + new Transition (2668, 2671), // &frac3 -> &frac35 + new Transition (2675, 2676) // &frac4 -> &frac45 + }; + TransitionTable_6 = new Transition[2] { + new Transition (2650, 2659), // &frac1 -> &frac16 + new Transition (2678, 2679) // &frac5 -> &frac56 + }; + TransitionTable_7 = new Transition[1] { + new Transition (2649, 2683) // &frac -> &frac7 + }; + TransitionTable_8 = new Transition[4] { + new Transition (2650, 2661), // &frac1 -> &frac18 + new Transition (2668, 2673), // &frac3 -> &frac38 + new Transition (2678, 2681), // &frac5 -> &frac58 + new Transition (2683, 2684) // &frac7 -> &frac78 + }; + TransitionTable_semicolon = new Transition[2125] { + new Transition (6, 7), // Á -> Á + new Transition (13, 14), // á -> á + new Transition (19, 20), // &Abreve -> Ă + new Transition (25, 26), // &abreve -> ă + new Transition (27, 28), // &ac -> ∾ + new Transition (29, 30), // &acd -> ∿ + new Transition (31, 32), // &acE -> ∾̳ + new Transition (36, 37), //  ->  + new Transition (40, 41), // â -> â + new Transition (44, 45), // ´ -> ´ + new Transition (46, 47), // &Acy -> А + new Transition (48, 49), // &acy -> а + new Transition (53, 54), // Æ -> Æ + new Transition (58, 59), // æ -> æ + new Transition (60, 61), // &af -> ⁡ + new Transition (63, 64), // &Afr -> 𝔄 + new Transition (65, 66), // &afr -> 𝔞 + new Transition (71, 72), // À -> À + new Transition (77, 78), // à -> à + new Transition (84, 85), // &alefsym -> ℵ + new Transition (87, 88), // &aleph -> ℵ + new Transition (92, 93), // &Alpha -> Α + new Transition (96, 97), // &alpha -> α + new Transition (101, 102), // &Amacr -> Ā + new Transition (106, 107), // &amacr -> ā + new Transition (109, 110), // &amalg -> ⨿ + new Transition (112, 113), // & -> & + new Transition (114, 115), // & -> & + new Transition (117, 118), // &And -> ⩓ + new Transition (120, 121), // &and -> ∧ + new Transition (124, 125), // &andand -> ⩕ + new Transition (126, 127), // &andd -> ⩜ + new Transition (132, 133), // &andslope -> ⩘ + new Transition (134, 135), // &andv -> ⩚ + new Transition (136, 137), // &ang -> ∠ + new Transition (138, 139), // &ange -> ⦤ + new Transition (141, 142), // &angle -> ∠ + new Transition (145, 146), // &angmsd -> ∡ + new Transition (148, 149), // &angmsdaa -> ⦨ + new Transition (150, 151), // &angmsdab -> ⦩ + new Transition (152, 153), // &angmsdac -> ⦪ + new Transition (154, 155), // &angmsdad -> ⦫ + new Transition (156, 157), // &angmsdae -> ⦬ + new Transition (158, 159), // &angmsdaf -> ⦭ + new Transition (160, 161), // &angmsdag -> ⦮ + new Transition (162, 163), // &angmsdah -> ⦯ + new Transition (165, 166), // &angrt -> ∟ + new Transition (168, 169), // &angrtvb -> ⊾ + new Transition (170, 171), // &angrtvbd -> ⦝ + new Transition (174, 175), // &angsph -> ∢ + new Transition (176, 177), // &angst -> Å + new Transition (181, 182), // &angzarr -> ⍼ + new Transition (186, 187), // &Aogon -> Ą + new Transition (191, 192), // &aogon -> ą + new Transition (194, 195), // &Aopf -> 𝔸 + new Transition (197, 198), // &aopf -> 𝕒 + new Transition (199, 200), // &ap -> ≈ + new Transition (204, 205), // &apacir -> ⩯ + new Transition (206, 207), // &apE -> ⩰ + new Transition (208, 209), // &ape -> ≊ + new Transition (211, 212), // &apid -> ≋ + new Transition (214, 215), // &apos -> ' + new Transition (227, 228), // &ApplyFunction -> ⁡ + new Transition (232, 233), // &approx -> ≈ + new Transition (235, 236), // &approxeq -> ≊ + new Transition (240, 241), // Å -> Å + new Transition (245, 246), // å -> å + new Transition (249, 250), // &Ascr -> 𝒜 + new Transition (253, 254), // &ascr -> 𝒶 + new Transition (258, 259), // &Assign -> ≔ + new Transition (260, 261), // &ast -> * + new Transition (264, 265), // &asymp -> ≈ + new Transition (267, 268), // &asympeq -> ≍ + new Transition (273, 274), // à -> à + new Transition (279, 280), // ã -> ã + new Transition (283, 284), // Ä -> Ä + new Transition (287, 288), // ä -> ä + new Transition (295, 296), // &awconint -> ∳ + new Transition (299, 300), // &awint -> ⨑ + new Transition (308, 309), // &backcong -> ≌ + new Transition (316, 317), // &backepsilon -> ϶ + new Transition (322, 323), // &backprime -> ‵ + new Transition (326, 327), // &backsim -> ∽ + new Transition (329, 330), // &backsimeq -> ⋍ + new Transition (339, 340), // &Backslash -> ∖ + new Transition (342, 343), // &Barv -> ⫧ + new Transition (347, 348), // &barvee -> ⊽ + new Transition (351, 352), // &Barwed -> ⌆ + new Transition (355, 356), // &barwed -> ⌅ + new Transition (358, 359), // &barwedge -> ⌅ + new Transition (362, 363), // &bbrk -> ⎵ + new Transition (367, 368), // &bbrktbrk -> ⎶ + new Transition (372, 373), // &bcong -> ≌ + new Transition (375, 376), // &Bcy -> Б + new Transition (377, 378), // &bcy -> б + new Transition (382, 383), // &bdquo -> „ + new Transition (388, 389), // &becaus -> ∵ + new Transition (395, 396), // &Because -> ∵ + new Transition (397, 398), // &because -> ∵ + new Transition (403, 404), // &bemptyv -> ⦰ + new Transition (407, 408), // &bepsi -> ϶ + new Transition (412, 413), // &bernou -> ℬ + new Transition (421, 422), // &Bernoullis -> ℬ + new Transition (424, 425), // &Beta -> Β + new Transition (427, 428), // &beta -> β + new Transition (429, 430), // &beth -> ℶ + new Transition (434, 435), // &between -> ≬ + new Transition (437, 438), // &Bfr -> 𝔅 + new Transition (440, 441), // &bfr -> 𝔟 + new Transition (446, 447), // &bigcap -> ⋂ + new Transition (450, 451), // &bigcirc -> ◯ + new Transition (453, 454), // &bigcup -> ⋃ + new Transition (458, 459), // &bigodot -> ⨀ + new Transition (463, 464), // &bigoplus -> ⨁ + new Transition (469, 470), // &bigotimes -> ⨂ + new Transition (475, 476), // &bigsqcup -> ⨆ + new Transition (479, 480), // &bigstar -> ★ + new Transition (492, 493), // &bigtriangledown -> ▽ + new Transition (495, 496), // &bigtriangleup -> △ + new Transition (501, 502), // &biguplus -> ⨄ + new Transition (505, 506), // &bigvee -> ⋁ + new Transition (511, 512), // &bigwedge -> ⋀ + new Transition (517, 518), // &bkarow -> ⤍ + new Transition (529, 530), // &blacklozenge -> ⧫ + new Transition (536, 537), // &blacksquare -> ▪ + new Transition (545, 546), // &blacktriangle -> ▴ + new Transition (550, 551), // &blacktriangledown -> ▾ + new Transition (555, 556), // &blacktriangleleft -> ◂ + new Transition (561, 562), // &blacktriangleright -> ▸ + new Transition (564, 565), // &blank -> ␣ + new Transition (568, 569), // &blk12 -> ▒ + new Transition (570, 571), // &blk14 -> ░ + new Transition (573, 574), // &blk34 -> ▓ + new Transition (577, 578), // &block -> █ + new Transition (580, 581), // &bne -> =⃥ + new Transition (585, 586), // &bnequiv -> ≡⃥ + new Transition (589, 590), // &bNot -> ⫭ + new Transition (592, 593), // &bnot -> ⌐ + new Transition (596, 597), // &Bopf -> 𝔹 + new Transition (600, 601), // &bopf -> 𝕓 + new Transition (602, 603), // &bot -> ⊥ + new Transition (606, 607), // &bottom -> ⊥ + new Transition (611, 612), // &bowtie -> ⋈ + new Transition (616, 617), // &boxbox -> ⧉ + new Transition (619, 620), // &boxDL -> ╗ + new Transition (621, 622), // &boxDl -> ╖ + new Transition (624, 625), // &boxdL -> ╕ + new Transition (626, 627), // &boxdl -> ┐ + new Transition (628, 629), // &boxDR -> ╔ + new Transition (630, 631), // &boxDr -> ╓ + new Transition (632, 633), // &boxdR -> ╒ + new Transition (634, 635), // &boxdr -> ┌ + new Transition (636, 637), // &boxH -> ═ + new Transition (638, 639), // &boxh -> ─ + new Transition (640, 641), // &boxHD -> ╦ + new Transition (642, 643), // &boxHd -> ╤ + new Transition (644, 645), // &boxhD -> ╥ + new Transition (646, 647), // &boxhd -> ┬ + new Transition (648, 649), // &boxHU -> ╩ + new Transition (650, 651), // &boxHu -> ╧ + new Transition (652, 653), // &boxhU -> ╨ + new Transition (654, 655), // &boxhu -> ┴ + new Transition (660, 661), // &boxminus -> ⊟ + new Transition (665, 666), // &boxplus -> ⊞ + new Transition (671, 672), // &boxtimes -> ⊠ + new Transition (674, 675), // &boxUL -> ╝ + new Transition (676, 677), // &boxUl -> ╜ + new Transition (679, 680), // &boxuL -> ╛ + new Transition (681, 682), // &boxul -> ┘ + new Transition (683, 684), // &boxUR -> ╚ + new Transition (685, 686), // &boxUr -> ╙ + new Transition (687, 688), // &boxuR -> ╘ + new Transition (689, 690), // &boxur -> └ + new Transition (691, 692), // &boxV -> ║ + new Transition (693, 694), // &boxv -> │ + new Transition (695, 696), // &boxVH -> ╬ + new Transition (697, 698), // &boxVh -> ╫ + new Transition (699, 700), // &boxvH -> ╪ + new Transition (701, 702), // &boxvh -> ┼ + new Transition (703, 704), // &boxVL -> ╣ + new Transition (705, 706), // &boxVl -> ╢ + new Transition (707, 708), // &boxvL -> ╡ + new Transition (709, 710), // &boxvl -> ┤ + new Transition (711, 712), // &boxVR -> ╠ + new Transition (713, 714), // &boxVr -> ╟ + new Transition (715, 716), // &boxvR -> ╞ + new Transition (717, 718), // &boxvr -> ├ + new Transition (723, 724), // &bprime -> ‵ + new Transition (728, 729), // &Breve -> ˘ + new Transition (733, 734), // &breve -> ˘ + new Transition (738, 739), // ¦ -> ¦ + new Transition (742, 743), // &Bscr -> ℬ + new Transition (746, 747), // &bscr -> 𝒷 + new Transition (750, 751), // &bsemi -> ⁏ + new Transition (753, 754), // &bsim -> ∽ + new Transition (755, 756), // &bsime -> ⋍ + new Transition (758, 759), // &bsol -> \ + new Transition (760, 761), // &bsolb -> ⧅ + new Transition (765, 766), // &bsolhsub -> ⟈ + new Transition (769, 770), // &bull -> • + new Transition (772, 773), // &bullet -> • + new Transition (775, 776), // &bump -> ≎ + new Transition (777, 778), // &bumpE -> ⪮ + new Transition (779, 780), // &bumpe -> ≏ + new Transition (785, 786), // &Bumpeq -> ≎ + new Transition (787, 788), // &bumpeq -> ≏ + new Transition (794, 795), // &Cacute -> Ć + new Transition (801, 802), // &cacute -> ć + new Transition (803, 804), // &Cap -> ⋒ + new Transition (805, 806), // &cap -> ∩ + new Transition (809, 810), // &capand -> ⩄ + new Transition (815, 816), // &capbrcup -> ⩉ + new Transition (819, 820), // &capcap -> ⩋ + new Transition (822, 823), // &capcup -> ⩇ + new Transition (826, 827), // &capdot -> ⩀ + new Transition (844, 845), // &CapitalDifferentialD -> ⅅ + new Transition (846, 847), // &caps -> ∩︀ + new Transition (850, 851), // &caret -> ⁁ + new Transition (853, 854), // &caron -> ˇ + new Transition (859, 860), // &Cayleys -> ℭ + new Transition (864, 865), // &ccaps -> ⩍ + new Transition (870, 871), // &Ccaron -> Č + new Transition (874, 875), // &ccaron -> č + new Transition (879, 880), // Ç -> Ç + new Transition (884, 885), // ç -> ç + new Transition (888, 889), // &Ccirc -> Ĉ + new Transition (892, 893), // &ccirc -> ĉ + new Transition (898, 899), // &Cconint -> ∰ + new Transition (902, 903), // &ccups -> ⩌ + new Transition (905, 906), // &ccupssm -> ⩐ + new Transition (909, 910), // &Cdot -> Ċ + new Transition (913, 914), // &cdot -> ċ + new Transition (918, 919), // ¸ -> ¸ + new Transition (925, 926), // &Cedilla -> ¸ + new Transition (931, 932), // &cemptyv -> ⦲ + new Transition (934, 935), // ¢ -> ¢ + new Transition (942, 943), // &CenterDot -> · + new Transition (948, 949), // ¢erdot -> · + new Transition (951, 952), // &Cfr -> ℭ + new Transition (954, 955), // &cfr -> 𝔠 + new Transition (958, 959), // &CHcy -> Ч + new Transition (962, 963), // &chcy -> ч + new Transition (966, 967), // &check -> ✓ + new Transition (971, 972), // &checkmark -> ✓ + new Transition (974, 975), // &Chi -> Χ + new Transition (976, 977), // &chi -> χ + new Transition (979, 980), // &cir -> ○ + new Transition (981, 982), // &circ -> ˆ + new Transition (984, 985), // &circeq -> ≗ + new Transition (996, 997), // &circlearrowleft -> ↺ + new Transition (1002, 1003), // &circlearrowright -> ↻ + new Transition (1007, 1008), // &circledast -> ⊛ + new Transition (1012, 1013), // &circledcirc -> ⊚ + new Transition (1017, 1018), // &circleddash -> ⊝ + new Transition (1026, 1027), // &CircleDot -> ⊙ + new Transition (1028, 1029), // &circledR -> ® + new Transition (1030, 1031), // &circledS -> Ⓢ + new Transition (1036, 1037), // &CircleMinus -> ⊖ + new Transition (1041, 1042), // &CirclePlus -> ⊕ + new Transition (1047, 1048), // &CircleTimes -> ⊗ + new Transition (1049, 1050), // &cirE -> ⧃ + new Transition (1051, 1052), // &cire -> ≗ + new Transition (1057, 1058), // &cirfnint -> ⨐ + new Transition (1061, 1062), // &cirmid -> ⫯ + new Transition (1066, 1067), // &cirscir -> ⧂ + new Transition (1090, 1091), // &ClockwiseContourIntegral -> ∲ + new Transition (1109, 1110), // &CloseCurlyDoubleQuote -> ” + new Transition (1115, 1116), // &CloseCurlyQuote -> ’ + new Transition (1120, 1121), // &clubs -> ♣ + new Transition (1124, 1125), // &clubsuit -> ♣ + new Transition (1129, 1130), // &Colon -> ∷ + new Transition (1134, 1135), // &colon -> : + new Transition (1136, 1137), // &Colone -> ⩴ + new Transition (1138, 1139), // &colone -> ≔ + new Transition (1140, 1141), // &coloneq -> ≔ + new Transition (1144, 1145), // &comma -> , + new Transition (1146, 1147), // &commat -> @ + new Transition (1148, 1149), // &comp -> ∁ + new Transition (1151, 1152), // &compfn -> ∘ + new Transition (1158, 1159), // &complement -> ∁ + new Transition (1162, 1163), // &complexes -> ℂ + new Transition (1165, 1166), // &cong -> ≅ + new Transition (1169, 1170), // &congdot -> ⩭ + new Transition (1177, 1178), // &Congruent -> ≡ + new Transition (1181, 1182), // &Conint -> ∯ + new Transition (1185, 1186), // &conint -> ∮ + new Transition (1198, 1199), // &ContourIntegral -> ∮ + new Transition (1201, 1202), // &Copf -> ℂ + new Transition (1204, 1205), // &copf -> 𝕔 + new Transition (1208, 1209), // &coprod -> ∐ + new Transition (1215, 1216), // &Coproduct -> ∐ + new Transition (1219, 1220), // © -> © + new Transition (1221, 1222), // © -> © + new Transition (1224, 1225), // ©sr -> ℗ + new Transition (1254, 1255), // &CounterClockwiseContourIntegral -> ∳ + new Transition (1259, 1260), // &crarr -> ↵ + new Transition (1264, 1265), // &Cross -> ⨯ + new Transition (1268, 1269), // &cross -> ✗ + new Transition (1272, 1273), // &Cscr -> 𝒞 + new Transition (1276, 1277), // &cscr -> 𝒸 + new Transition (1279, 1280), // &csub -> ⫏ + new Transition (1281, 1282), // &csube -> ⫑ + new Transition (1283, 1284), // &csup -> ⫐ + new Transition (1285, 1286), // &csupe -> ⫒ + new Transition (1290, 1291), // &ctdot -> ⋯ + new Transition (1297, 1298), // &cudarrl -> ⤸ + new Transition (1299, 1300), // &cudarrr -> ⤵ + new Transition (1303, 1304), // &cuepr -> ⋞ + new Transition (1306, 1307), // &cuesc -> ⋟ + new Transition (1311, 1312), // &cularr -> ↶ + new Transition (1313, 1314), // &cularrp -> ⤽ + new Transition (1316, 1317), // &Cup -> ⋓ + new Transition (1318, 1319), // &cup -> ∪ + new Transition (1324, 1325), // &cupbrcap -> ⩈ + new Transition (1328, 1329), // &CupCap -> ≍ + new Transition (1332, 1333), // &cupcap -> ⩆ + new Transition (1335, 1336), // &cupcup -> ⩊ + new Transition (1339, 1340), // &cupdot -> ⊍ + new Transition (1342, 1343), // &cupor -> ⩅ + new Transition (1344, 1345), // &cups -> ∪︀ + new Transition (1349, 1350), // &curarr -> ↷ + new Transition (1351, 1352), // &curarrm -> ⤼ + new Transition (1360, 1361), // &curlyeqprec -> ⋞ + new Transition (1365, 1366), // &curlyeqsucc -> ⋟ + new Transition (1369, 1370), // &curlyvee -> ⋎ + new Transition (1375, 1376), // &curlywedge -> ⋏ + new Transition (1379, 1380), // ¤ -> ¤ + new Transition (1391, 1392), // &curvearrowleft -> ↶ + new Transition (1397, 1398), // &curvearrowright -> ↷ + new Transition (1401, 1402), // &cuvee -> ⋎ + new Transition (1405, 1406), // &cuwed -> ⋏ + new Transition (1413, 1414), // &cwconint -> ∲ + new Transition (1417, 1418), // &cwint -> ∱ + new Transition (1423, 1424), // &cylcty -> ⌭ + new Transition (1430, 1431), // &Dagger -> ‡ + new Transition (1437, 1438), // &dagger -> † + new Transition (1442, 1443), // &daleth -> ℸ + new Transition (1445, 1446), // &Darr -> ↡ + new Transition (1449, 1450), // &dArr -> ⇓ + new Transition (1452, 1453), // &darr -> ↓ + new Transition (1455, 1456), // &dash -> ‐ + new Transition (1459, 1460), // &Dashv -> ⫤ + new Transition (1461, 1462), // &dashv -> ⊣ + new Transition (1468, 1469), // &dbkarow -> ⤏ + new Transition (1472, 1473), // &dblac -> ˝ + new Transition (1478, 1479), // &Dcaron -> Ď + new Transition (1484, 1485), // &dcaron -> ď + new Transition (1486, 1487), // &Dcy -> Д + new Transition (1488, 1489), // &dcy -> д + new Transition (1490, 1491), // &DD -> ⅅ + new Transition (1492, 1493), // &dd -> ⅆ + new Transition (1498, 1499), // &ddagger -> ‡ + new Transition (1501, 1502), // &ddarr -> ⇊ + new Transition (1508, 1509), // &DDotrahd -> ⤑ + new Transition (1514, 1515), // &ddotseq -> ⩷ + new Transition (1517, 1518), // ° -> ° + new Transition (1520, 1521), // &Del -> ∇ + new Transition (1523, 1524), // &Delta -> Δ + new Transition (1527, 1528), // &delta -> δ + new Transition (1533, 1534), // &demptyv -> ⦱ + new Transition (1539, 1540), // &dfisht -> ⥿ + new Transition (1542, 1543), // &Dfr -> 𝔇 + new Transition (1544, 1545), // &dfr -> 𝔡 + new Transition (1548, 1549), // &dHar -> ⥥ + new Transition (1553, 1554), // &dharl -> ⇃ + new Transition (1555, 1556), // &dharr -> ⇂ + new Transition (1571, 1572), // &DiacriticalAcute -> ´ + new Transition (1575, 1576), // &DiacriticalDot -> ˙ + new Transition (1585, 1586), // &DiacriticalDoubleAcute -> ˝ + new Transition (1591, 1592), // &DiacriticalGrave -> ` + new Transition (1597, 1598), // &DiacriticalTilde -> ˜ + new Transition (1601, 1602), // &diam -> ⋄ + new Transition (1606, 1607), // &Diamond -> ⋄ + new Transition (1610, 1611), // &diamond -> ⋄ + new Transition (1615, 1616), // &diamondsuit -> ♦ + new Transition (1617, 1618), // &diams -> ♦ + new Transition (1619, 1620), // &die -> ¨ + new Transition (1631, 1632), // &DifferentialD -> ⅆ + new Transition (1637, 1638), // &digamma -> ϝ + new Transition (1641, 1642), // &disin -> ⋲ + new Transition (1643, 1644), // &div -> ÷ + new Transition (1647, 1648), // ÷ -> ÷ + new Transition (1655, 1656), // ÷ontimes -> ⋇ + new Transition (1659, 1660), // &divonx -> ⋇ + new Transition (1663, 1664), // &DJcy -> Ђ + new Transition (1667, 1668), // &djcy -> ђ + new Transition (1673, 1674), // &dlcorn -> ⌞ + new Transition (1677, 1678), // &dlcrop -> ⌍ + new Transition (1683, 1684), // &dollar -> $ + new Transition (1687, 1688), // &Dopf -> 𝔻 + new Transition (1690, 1691), // &dopf -> 𝕕 + new Transition (1692, 1693), // &Dot -> ¨ + new Transition (1694, 1695), // &dot -> ˙ + new Transition (1698, 1699), // &DotDot -> ⃜ + new Transition (1701, 1702), // &doteq -> ≐ + new Transition (1705, 1706), // &doteqdot -> ≑ + new Transition (1711, 1712), // &DotEqual -> ≐ + new Transition (1717, 1718), // &dotminus -> ∸ + new Transition (1722, 1723), // &dotplus -> ∔ + new Transition (1729, 1730), // &dotsquare -> ⊡ + new Transition (1742, 1743), // &doublebarwedge -> ⌆ + new Transition (1762, 1763), // &DoubleContourIntegral -> ∯ + new Transition (1766, 1767), // &DoubleDot -> ¨ + new Transition (1774, 1775), // &DoubleDownArrow -> ⇓ + new Transition (1784, 1785), // &DoubleLeftArrow -> ⇐ + new Transition (1795, 1796), // &DoubleLeftRightArrow -> ⇔ + new Transition (1799, 1800), // &DoubleLeftTee -> ⫤ + new Transition (1812, 1813), // &DoubleLongLeftArrow -> ⟸ + new Transition (1823, 1824), // &DoubleLongLeftRightArrow -> ⟺ + new Transition (1834, 1835), // &DoubleLongRightArrow -> ⟹ + new Transition (1845, 1846), // &DoubleRightArrow -> ⇒ + new Transition (1849, 1850), // &DoubleRightTee -> ⊨ + new Transition (1857, 1858), // &DoubleUpArrow -> ⇑ + new Transition (1867, 1868), // &DoubleUpDownArrow -> ⇕ + new Transition (1879, 1880), // &DoubleVerticalBar -> ∥ + new Transition (1887, 1888), // &DownArrow -> ↓ + new Transition (1893, 1894), // &Downarrow -> ⇓ + new Transition (1901, 1902), // &downarrow -> ↓ + new Transition (1905, 1906), // &DownArrowBar -> ⤓ + new Transition (1913, 1914), // &DownArrowUpArrow -> ⇵ + new Transition (1919, 1920), // &DownBreve -> ̑ + new Transition (1930, 1931), // &downdownarrows -> ⇊ + new Transition (1942, 1943), // &downharpoonleft -> ⇃ + new Transition (1948, 1949), // &downharpoonright -> ⇂ + new Transition (1964, 1965), // &DownLeftRightVector -> ⥐ + new Transition (1974, 1975), // &DownLeftTeeVector -> ⥞ + new Transition (1981, 1982), // &DownLeftVector -> ↽ + new Transition (1985, 1986), // &DownLeftVectorBar -> ⥖ + new Transition (2000, 2001), // &DownRightTeeVector -> ⥟ + new Transition (2007, 2008), // &DownRightVector -> ⇁ + new Transition (2011, 2012), // &DownRightVectorBar -> ⥗ + new Transition (2015, 2016), // &DownTee -> ⊤ + new Transition (2021, 2022), // &DownTeeArrow -> ↧ + new Transition (2029, 2030), // &drbkarow -> ⤐ + new Transition (2034, 2035), // &drcorn -> ⌟ + new Transition (2038, 2039), // &drcrop -> ⌌ + new Transition (2042, 2043), // &Dscr -> 𝒟 + new Transition (2046, 2047), // &dscr -> 𝒹 + new Transition (2050, 2051), // &DScy -> Ѕ + new Transition (2052, 2053), // &dscy -> ѕ + new Transition (2055, 2056), // &dsol -> ⧶ + new Transition (2060, 2061), // &Dstrok -> Đ + new Transition (2065, 2066), // &dstrok -> đ + new Transition (2070, 2071), // &dtdot -> ⋱ + new Transition (2073, 2074), // &dtri -> ▿ + new Transition (2075, 2076), // &dtrif -> ▾ + new Transition (2080, 2081), // &duarr -> ⇵ + new Transition (2084, 2085), // &duhar -> ⥯ + new Transition (2091, 2092), // &dwangle -> ⦦ + new Transition (2095, 2096), // &DZcy -> Џ + new Transition (2099, 2100), // &dzcy -> џ + new Transition (2106, 2107), // &dzigrarr -> ⟿ + new Transition (2113, 2114), // É -> É + new Transition (2120, 2121), // é -> é + new Transition (2125, 2126), // &easter -> ⩮ + new Transition (2131, 2132), // &Ecaron -> Ě + new Transition (2137, 2138), // &ecaron -> ě + new Transition (2140, 2141), // &ecir -> ≖ + new Transition (2144, 2145), // Ê -> Ê + new Transition (2146, 2147), // ê -> ê + new Transition (2151, 2152), // &ecolon -> ≕ + new Transition (2153, 2154), // &Ecy -> Э + new Transition (2155, 2156), // &ecy -> э + new Transition (2160, 2161), // &eDDot -> ⩷ + new Transition (2164, 2165), // &Edot -> Ė + new Transition (2167, 2168), // &eDot -> ≑ + new Transition (2171, 2172), // &edot -> ė + new Transition (2173, 2174), // &ee -> ⅇ + new Transition (2178, 2179), // &efDot -> ≒ + new Transition (2181, 2182), // &Efr -> 𝔈 + new Transition (2183, 2184), // &efr -> 𝔢 + new Transition (2185, 2186), // &eg -> ⪚ + new Transition (2191, 2192), // È -> È + new Transition (2196, 2197), // è -> è + new Transition (2198, 2199), // &egs -> ⪖ + new Transition (2202, 2203), // &egsdot -> ⪘ + new Transition (2204, 2205), // &el -> ⪙ + new Transition (2211, 2212), // &Element -> ∈ + new Transition (2218, 2219), // &elinters -> ⏧ + new Transition (2220, 2221), // &ell -> ℓ + new Transition (2222, 2223), // &els -> ⪕ + new Transition (2226, 2227), // &elsdot -> ⪗ + new Transition (2231, 2232), // &Emacr -> Ē + new Transition (2236, 2237), // &emacr -> ē + new Transition (2240, 2241), // &empty -> ∅ + new Transition (2244, 2245), // &emptyset -> ∅ + new Transition (2259, 2260), // &EmptySmallSquare -> ◻ + new Transition (2261, 2262), // &emptyv -> ∅ + new Transition (2277, 2278), // &EmptyVerySmallSquare -> ▫ + new Transition (2280, 2281), // &emsp ->   + new Transition (2283, 2284), // &emsp13 ->   + new Transition (2285, 2286), // &emsp14 ->   + new Transition (2288, 2289), // &ENG -> Ŋ + new Transition (2291, 2292), // &eng -> ŋ + new Transition (2294, 2295), // &ensp ->   + new Transition (2299, 2300), // &Eogon -> Ę + new Transition (2304, 2305), // &eogon -> ę + new Transition (2307, 2308), // &Eopf -> 𝔼 + new Transition (2310, 2311), // &eopf -> 𝕖 + new Transition (2314, 2315), // &epar -> ⋕ + new Transition (2317, 2318), // &eparsl -> ⧣ + new Transition (2321, 2322), // &eplus -> ⩱ + new Transition (2324, 2325), // &epsi -> ε + new Transition (2331, 2332), // &Epsilon -> Ε + new Transition (2335, 2336), // &epsilon -> ε + new Transition (2337, 2338), // &epsiv -> ϵ + new Transition (2343, 2344), // &eqcirc -> ≖ + new Transition (2348, 2349), // &eqcolon -> ≕ + new Transition (2352, 2353), // &eqsim -> ≂ + new Transition (2360, 2361), // &eqslantgtr -> ⪖ + new Transition (2365, 2366), // &eqslantless -> ⪕ + new Transition (2370, 2371), // &Equal -> ⩵ + new Transition (2375, 2376), // &equals -> = + new Transition (2381, 2382), // &EqualTilde -> ≂ + new Transition (2385, 2386), // &equest -> ≟ + new Transition (2394, 2395), // &Equilibrium -> ⇌ + new Transition (2397, 2398), // &equiv -> ≡ + new Transition (2400, 2401), // &equivDD -> ⩸ + new Transition (2407, 2408), // &eqvparsl -> ⧥ + new Transition (2412, 2413), // &erarr -> ⥱ + new Transition (2416, 2417), // &erDot -> ≓ + new Transition (2420, 2421), // &Escr -> ℰ + new Transition (2424, 2425), // &escr -> ℯ + new Transition (2428, 2429), // &esdot -> ≐ + new Transition (2431, 2432), // &Esim -> ⩳ + new Transition (2434, 2435), // &esim -> ≂ + new Transition (2437, 2438), // &Eta -> Η + new Transition (2440, 2441), // &eta -> η + new Transition (2443, 2444), // Ð -> Ð + new Transition (2445, 2446), // ð -> ð + new Transition (2449, 2450), // Ë -> Ë + new Transition (2453, 2454), // ë -> ë + new Transition (2456, 2457), // &euro -> € + new Transition (2460, 2461), // &excl -> ! + new Transition (2464, 2465), // &exist -> ∃ + new Transition (2470, 2471), // &Exists -> ∃ + new Transition (2480, 2481), // &expectation -> ℰ + new Transition (2491, 2492), // &ExponentialE -> ⅇ + new Transition (2501, 2502), // &exponentiale -> ⅇ + new Transition (2515, 2516), // &fallingdotseq -> ≒ + new Transition (2519, 2520), // &Fcy -> Ф + new Transition (2522, 2523), // &fcy -> ф + new Transition (2528, 2529), // &female -> ♀ + new Transition (2534, 2535), // &ffilig -> ffi + new Transition (2538, 2539), // &fflig -> ff + new Transition (2542, 2543), // &ffllig -> ffl + new Transition (2545, 2546), // &Ffr -> 𝔉 + new Transition (2547, 2548), // &ffr -> 𝔣 + new Transition (2552, 2553), // &filig -> fi + new Transition (2569, 2570), // &FilledSmallSquare -> ◼ + new Transition (2585, 2586), // &FilledVerySmallSquare -> ▪ + new Transition (2590, 2591), // &fjlig -> fj + new Transition (2594, 2595), // &flat -> ♭ + new Transition (2598, 2599), // &fllig -> fl + new Transition (2602, 2603), // &fltns -> ▱ + new Transition (2606, 2607), // &fnof -> ƒ + new Transition (2610, 2611), // &Fopf -> 𝔽 + new Transition (2614, 2615), // &fopf -> 𝕗 + new Transition (2619, 2620), // &ForAll -> ∀ + new Transition (2624, 2625), // &forall -> ∀ + new Transition (2626, 2627), // &fork -> ⋔ + new Transition (2628, 2629), // &forkv -> ⫙ + new Transition (2637, 2638), // &Fouriertrf -> ℱ + new Transition (2645, 2646), // &fpartint -> ⨍ + new Transition (2651, 2652), // ½ -> ½ + new Transition (2653, 2654), // &frac13 -> ⅓ + new Transition (2655, 2656), // ¼ -> ¼ + new Transition (2657, 2658), // &frac15 -> ⅕ + new Transition (2659, 2660), // &frac16 -> ⅙ + new Transition (2661, 2662), // &frac18 -> ⅛ + new Transition (2664, 2665), // &frac23 -> ⅔ + new Transition (2666, 2667), // &frac25 -> ⅖ + new Transition (2669, 2670), // ¾ -> ¾ + new Transition (2671, 2672), // &frac35 -> ⅗ + new Transition (2673, 2674), // &frac38 -> ⅜ + new Transition (2676, 2677), // &frac45 -> ⅘ + new Transition (2679, 2680), // &frac56 -> ⅚ + new Transition (2681, 2682), // &frac58 -> ⅝ + new Transition (2684, 2685), // &frac78 -> ⅞ + new Transition (2687, 2688), // &frasl -> ⁄ + new Transition (2691, 2692), // &frown -> ⌢ + new Transition (2695, 2696), // &Fscr -> ℱ + new Transition (2699, 2700), // &fscr -> 𝒻 + new Transition (2706, 2707), // &gacute -> ǵ + new Transition (2712, 2713), // &Gamma -> Γ + new Transition (2716, 2717), // &gamma -> γ + new Transition (2718, 2719), // &Gammad -> Ϝ + new Transition (2720, 2721), // &gammad -> ϝ + new Transition (2722, 2723), // &gap -> ⪆ + new Transition (2728, 2729), // &Gbreve -> Ğ + new Transition (2734, 2735), // &gbreve -> ğ + new Transition (2740, 2741), // &Gcedil -> Ģ + new Transition (2744, 2745), // &Gcirc -> Ĝ + new Transition (2749, 2750), // &gcirc -> ĝ + new Transition (2751, 2752), // &Gcy -> Г + new Transition (2753, 2754), // &gcy -> г + new Transition (2757, 2758), // &Gdot -> Ġ + new Transition (2761, 2762), // &gdot -> ġ + new Transition (2763, 2764), // &gE -> ≧ + new Transition (2765, 2766), // &ge -> ≥ + new Transition (2767, 2768), // &gEl -> ⪌ + new Transition (2769, 2770), // &gel -> ⋛ + new Transition (2771, 2772), // &geq -> ≥ + new Transition (2773, 2774), // &geqq -> ≧ + new Transition (2779, 2780), // &geqslant -> ⩾ + new Transition (2781, 2782), // &ges -> ⩾ + new Transition (2784, 2785), // &gescc -> ⪩ + new Transition (2788, 2789), // &gesdot -> ⪀ + new Transition (2790, 2791), // &gesdoto -> ⪂ + new Transition (2792, 2793), // &gesdotol -> ⪄ + new Transition (2794, 2795), // &gesl -> ⋛︀ + new Transition (2797, 2798), // &gesles -> ⪔ + new Transition (2800, 2801), // &Gfr -> 𝔊 + new Transition (2803, 2804), // &gfr -> 𝔤 + new Transition (2805, 2806), // &Gg -> ⋙ + new Transition (2807, 2808), // &gg -> ≫ + new Transition (2809, 2810), // &ggg -> ⋙ + new Transition (2814, 2815), // &gimel -> ℷ + new Transition (2818, 2819), // &GJcy -> Ѓ + new Transition (2822, 2823), // &gjcy -> ѓ + new Transition (2824, 2825), // &gl -> ≷ + new Transition (2826, 2827), // &gla -> ⪥ + new Transition (2828, 2829), // &glE -> ⪒ + new Transition (2830, 2831), // &glj -> ⪤ + new Transition (2834, 2835), // &gnap -> ⪊ + new Transition (2839, 2840), // &gnapprox -> ⪊ + new Transition (2841, 2842), // &gnE -> ≩ + new Transition (2843, 2844), // &gne -> ⪈ + new Transition (2845, 2846), // &gneq -> ⪈ + new Transition (2847, 2848), // &gneqq -> ≩ + new Transition (2851, 2852), // &gnsim -> ⋧ + new Transition (2855, 2856), // &Gopf -> 𝔾 + new Transition (2859, 2860), // &gopf -> 𝕘 + new Transition (2864, 2865), // &grave -> ` + new Transition (2876, 2877), // &GreaterEqual -> ≥ + new Transition (2881, 2882), // &GreaterEqualLess -> ⋛ + new Transition (2891, 2892), // &GreaterFullEqual -> ≧ + new Transition (2899, 2900), // &GreaterGreater -> ⪢ + new Transition (2904, 2905), // &GreaterLess -> ≷ + new Transition (2915, 2916), // &GreaterSlantEqual -> ⩾ + new Transition (2921, 2922), // &GreaterTilde -> ≳ + new Transition (2925, 2926), // &Gscr -> 𝒢 + new Transition (2929, 2930), // &gscr -> ℊ + new Transition (2932, 2933), // &gsim -> ≳ + new Transition (2934, 2935), // &gsime -> ⪎ + new Transition (2936, 2937), // &gsiml -> ⪐ + new Transition (2938, 2939), // > -> > + new Transition (2940, 2941), // &Gt -> ≫ + new Transition (2942, 2943), // > -> > + new Transition (2945, 2946), // >cc -> ⪧ + new Transition (2948, 2949), // >cir -> ⩺ + new Transition (2952, 2953), // >dot -> ⋗ + new Transition (2957, 2958), // >lPar -> ⦕ + new Transition (2963, 2964), // >quest -> ⩼ + new Transition (2971, 2972), // >rapprox -> ⪆ + new Transition (2974, 2975), // >rarr -> ⥸ + new Transition (2978, 2979), // >rdot -> ⋗ + new Transition (2985, 2986), // >reqless -> ⋛ + new Transition (2991, 2992), // >reqqless -> ⪌ + new Transition (2996, 2997), // >rless -> ≷ + new Transition (3000, 3001), // >rsim -> ≳ + new Transition (3009, 3010), // &gvertneqq -> ≩︀ + new Transition (3012, 3013), // &gvnE -> ≩︀ + new Transition (3018, 3019), // &Hacek -> ˇ + new Transition (3025, 3026), // &hairsp ->   + new Transition (3028, 3029), // &half -> ½ + new Transition (3033, 3034), // &hamilt -> ℋ + new Transition (3039, 3040), // &HARDcy -> Ъ + new Transition (3044, 3045), // &hardcy -> ъ + new Transition (3048, 3049), // &hArr -> ⇔ + new Transition (3050, 3051), // &harr -> ↔ + new Transition (3054, 3055), // &harrcir -> ⥈ + new Transition (3056, 3057), // &harrw -> ↭ + new Transition (3058, 3059), // &Hat -> ^ + new Transition (3062, 3063), // &hbar -> ℏ + new Transition (3067, 3068), // &Hcirc -> Ĥ + new Transition (3072, 3073), // &hcirc -> ĥ + new Transition (3078, 3079), // &hearts -> ♥ + new Transition (3082, 3083), // &heartsuit -> ♥ + new Transition (3087, 3088), // &hellip -> … + new Transition (3092, 3093), // &hercon -> ⊹ + new Transition (3095, 3096), // &Hfr -> ℌ + new Transition (3098, 3099), // &hfr -> 𝔥 + new Transition (3110, 3111), // &HilbertSpace -> ℋ + new Transition (3118, 3119), // &hksearow -> ⤥ + new Transition (3124, 3125), // &hkswarow -> ⤦ + new Transition (3129, 3130), // &hoarr -> ⇿ + new Transition (3134, 3135), // &homtht -> ∻ + new Transition (3146, 3147), // &hookleftarrow -> ↩ + new Transition (3157, 3158), // &hookrightarrow -> ↪ + new Transition (3161, 3162), // &Hopf -> ℍ + new Transition (3164, 3165), // &hopf -> 𝕙 + new Transition (3169, 3170), // &horbar -> ― + new Transition (3182, 3183), // &HorizontalLine -> ─ + new Transition (3186, 3187), // &Hscr -> ℋ + new Transition (3190, 3191), // &hscr -> 𝒽 + new Transition (3195, 3196), // &hslash -> ℏ + new Transition (3200, 3201), // &Hstrok -> Ħ + new Transition (3205, 3206), // &hstrok -> ħ + new Transition (3217, 3218), // &HumpDownHump -> ≎ + new Transition (3223, 3224), // &HumpEqual -> ≏ + new Transition (3229, 3230), // &hybull -> ⁃ + new Transition (3234, 3235), // &hyphen -> ‐ + new Transition (3241, 3242), // Í -> Í + new Transition (3248, 3249), // í -> í + new Transition (3250, 3251), // &ic -> ⁣ + new Transition (3255, 3256), // Î -> Î + new Transition (3259, 3260), // î -> î + new Transition (3261, 3262), // &Icy -> И + new Transition (3263, 3264), // &icy -> и + new Transition (3267, 3268), // &Idot -> İ + new Transition (3271, 3272), // &IEcy -> Е + new Transition (3275, 3276), // &iecy -> е + new Transition (3279, 3280), // ¡ -> ¡ + new Transition (3282, 3283), // &iff -> ⇔ + new Transition (3285, 3286), // &Ifr -> ℑ + new Transition (3287, 3288), // &ifr -> 𝔦 + new Transition (3293, 3294), // Ì -> Ì + new Transition (3299, 3300), // ì -> ì + new Transition (3301, 3302), // &ii -> ⅈ + new Transition (3306, 3307), // &iiiint -> ⨌ + new Transition (3309, 3310), // &iiint -> ∭ + new Transition (3314, 3315), // &iinfin -> ⧜ + new Transition (3318, 3319), // &iiota -> ℩ + new Transition (3323, 3324), // &IJlig -> IJ + new Transition (3328, 3329), // &ijlig -> ij + new Transition (3330, 3331), // &Im -> ℑ + new Transition (3334, 3335), // &Imacr -> Ī + new Transition (3339, 3340), // &imacr -> ī + new Transition (3342, 3343), // &image -> ℑ + new Transition (3350, 3351), // &ImaginaryI -> ⅈ + new Transition (3355, 3356), // &imagline -> ℐ + new Transition (3360, 3361), // &imagpart -> ℑ + new Transition (3363, 3364), // &imath -> ı + new Transition (3366, 3367), // &imof -> ⊷ + new Transition (3370, 3371), // &imped -> Ƶ + new Transition (3376, 3377), // &Implies -> ⇒ + new Transition (3378, 3379), // &in -> ∈ + new Transition (3383, 3384), // &incare -> ℅ + new Transition (3387, 3388), // &infin -> ∞ + new Transition (3391, 3392), // &infintie -> ⧝ + new Transition (3396, 3397), // &inodot -> ı + new Transition (3399, 3400), // &Int -> ∬ + new Transition (3401, 3402), // &int -> ∫ + new Transition (3405, 3406), // &intcal -> ⊺ + new Transition (3411, 3412), // &integers -> ℤ + new Transition (3417, 3418), // &Integral -> ∫ + new Transition (3422, 3423), // &intercal -> ⊺ + new Transition (3431, 3432), // &Intersection -> ⋂ + new Transition (3437, 3438), // &intlarhk -> ⨗ + new Transition (3442, 3443), // &intprod -> ⨼ + new Transition (3455, 3456), // &InvisibleComma -> ⁣ + new Transition (3461, 3462), // &InvisibleTimes -> ⁢ + new Transition (3465, 3466), // &IOcy -> Ё + new Transition (3469, 3470), // &iocy -> ё + new Transition (3474, 3475), // &Iogon -> Į + new Transition (3478, 3479), // &iogon -> į + new Transition (3481, 3482), // &Iopf -> 𝕀 + new Transition (3484, 3485), // &iopf -> 𝕚 + new Transition (3487, 3488), // &Iota -> Ι + new Transition (3490, 3491), // &iota -> ι + new Transition (3495, 3496), // &iprod -> ⨼ + new Transition (3501, 3502), // ¿ -> ¿ + new Transition (3505, 3506), // &Iscr -> ℐ + new Transition (3509, 3510), // &iscr -> 𝒾 + new Transition (3512, 3513), // &isin -> ∈ + new Transition (3516, 3517), // &isindot -> ⋵ + new Transition (3518, 3519), // &isinE -> ⋹ + new Transition (3520, 3521), // &isins -> ⋴ + new Transition (3522, 3523), // &isinsv -> ⋳ + new Transition (3524, 3525), // &isinv -> ∈ + new Transition (3526, 3527), // &it -> ⁢ + new Transition (3532, 3533), // &Itilde -> Ĩ + new Transition (3537, 3538), // &itilde -> ĩ + new Transition (3542, 3543), // &Iukcy -> І + new Transition (3547, 3548), // &iukcy -> і + new Transition (3550, 3551), // Ï -> Ï + new Transition (3553, 3554), // ï -> ï + new Transition (3559, 3560), // &Jcirc -> Ĵ + new Transition (3565, 3566), // &jcirc -> ĵ + new Transition (3567, 3568), // &Jcy -> Й + new Transition (3569, 3570), // &jcy -> й + new Transition (3572, 3573), // &Jfr -> 𝔍 + new Transition (3575, 3576), // &jfr -> 𝔧 + new Transition (3580, 3581), // &jmath -> ȷ + new Transition (3584, 3585), // &Jopf -> 𝕁 + new Transition (3588, 3589), // &jopf -> 𝕛 + new Transition (3592, 3593), // &Jscr -> 𝒥 + new Transition (3596, 3597), // &jscr -> 𝒿 + new Transition (3601, 3602), // &Jsercy -> Ј + new Transition (3606, 3607), // &jsercy -> ј + new Transition (3611, 3612), // &Jukcy -> Є + new Transition (3616, 3617), // &jukcy -> є + new Transition (3622, 3623), // &Kappa -> Κ + new Transition (3628, 3629), // &kappa -> κ + new Transition (3630, 3631), // &kappav -> ϰ + new Transition (3636, 3637), // &Kcedil -> Ķ + new Transition (3642, 3643), // &kcedil -> ķ + new Transition (3644, 3645), // &Kcy -> К + new Transition (3646, 3647), // &kcy -> к + new Transition (3649, 3650), // &Kfr -> 𝔎 + new Transition (3652, 3653), // &kfr -> 𝔨 + new Transition (3658, 3659), // &kgreen -> ĸ + new Transition (3662, 3663), // &KHcy -> Х + new Transition (3666, 3667), // &khcy -> х + new Transition (3670, 3671), // &KJcy -> Ќ + new Transition (3674, 3675), // &kjcy -> ќ + new Transition (3678, 3679), // &Kopf -> 𝕂 + new Transition (3682, 3683), // &kopf -> 𝕜 + new Transition (3686, 3687), // &Kscr -> 𝒦 + new Transition (3690, 3691), // &kscr -> 𝓀 + new Transition (3696, 3697), // &lAarr -> ⇚ + new Transition (3703, 3704), // &Lacute -> Ĺ + new Transition (3709, 3710), // &lacute -> ĺ + new Transition (3716, 3717), // &laemptyv -> ⦴ + new Transition (3721, 3722), // &lagran -> ℒ + new Transition (3726, 3727), // &Lambda -> Λ + new Transition (3731, 3732), // &lambda -> λ + new Transition (3734, 3735), // &Lang -> ⟪ + new Transition (3737, 3738), // &lang -> ⟨ + new Transition (3739, 3740), // &langd -> ⦑ + new Transition (3742, 3743), // &langle -> ⟨ + new Transition (3744, 3745), // &lap -> ⪅ + new Transition (3753, 3754), // &Laplacetrf -> ℒ + new Transition (3757, 3758), // « -> « + new Transition (3760, 3761), // &Larr -> ↞ + new Transition (3763, 3764), // &lArr -> ⇐ + new Transition (3766, 3767), // &larr -> ← + new Transition (3768, 3769), // &larrb -> ⇤ + new Transition (3771, 3772), // &larrbfs -> ⤟ + new Transition (3774, 3775), // &larrfs -> ⤝ + new Transition (3777, 3778), // &larrhk -> ↩ + new Transition (3780, 3781), // &larrlp -> ↫ + new Transition (3783, 3784), // &larrpl -> ⤹ + new Transition (3787, 3788), // &larrsim -> ⥳ + new Transition (3790, 3791), // &larrtl -> ↢ + new Transition (3792, 3793), // &lat -> ⪫ + new Transition (3797, 3798), // &lAtail -> ⤛ + new Transition (3801, 3802), // &latail -> ⤙ + new Transition (3803, 3804), // &late -> ⪭ + new Transition (3805, 3806), // &lates -> ⪭︀ + new Transition (3810, 3811), // &lBarr -> ⤎ + new Transition (3815, 3816), // &lbarr -> ⤌ + new Transition (3819, 3820), // &lbbrk -> ❲ + new Transition (3824, 3825), // &lbrace -> { + new Transition (3826, 3827), // &lbrack -> [ + new Transition (3829, 3830), // &lbrke -> ⦋ + new Transition (3833, 3834), // &lbrksld -> ⦏ + new Transition (3835, 3836), // &lbrkslu -> ⦍ + new Transition (3841, 3842), // &Lcaron -> Ľ + new Transition (3847, 3848), // &lcaron -> ľ + new Transition (3852, 3853), // &Lcedil -> Ļ + new Transition (3857, 3858), // &lcedil -> ļ + new Transition (3860, 3861), // &lceil -> ⌈ + new Transition (3863, 3864), // &lcub -> { + new Transition (3865, 3866), // &Lcy -> Л + new Transition (3867, 3868), // &lcy -> л + new Transition (3871, 3872), // &ldca -> ⤶ + new Transition (3875, 3876), // &ldquo -> “ + new Transition (3877, 3878), // &ldquor -> „ + new Transition (3883, 3884), // &ldrdhar -> ⥧ + new Transition (3889, 3890), // &ldrushar -> ⥋ + new Transition (3892, 3893), // &ldsh -> ↲ + new Transition (3894, 3895), // &lE -> ≦ + new Transition (3896, 3897), // &le -> ≤ + new Transition (3912, 3913), // &LeftAngleBracket -> ⟨ + new Transition (3917, 3918), // &LeftArrow -> ← + new Transition (3923, 3924), // &Leftarrow -> ⇐ + new Transition (3931, 3932), // &leftarrow -> ← + new Transition (3935, 3936), // &LeftArrowBar -> ⇤ + new Transition (3946, 3947), // &LeftArrowRightArrow -> ⇆ + new Transition (3951, 3952), // &leftarrowtail -> ↢ + new Transition (3959, 3960), // &LeftCeiling -> ⌈ + new Transition (3973, 3974), // &LeftDoubleBracket -> ⟦ + new Transition (3985, 3986), // &LeftDownTeeVector -> ⥡ + new Transition (3992, 3993), // &LeftDownVector -> ⇃ + new Transition (3996, 3997), // &LeftDownVectorBar -> ⥙ + new Transition (4002, 4003), // &LeftFloor -> ⌊ + new Transition (4014, 4015), // &leftharpoondown -> ↽ + new Transition (4017, 4018), // &leftharpoonup -> ↼ + new Transition (4028, 4029), // &leftleftarrows -> ⇇ + new Transition (4039, 4040), // &LeftRightArrow -> ↔ + new Transition (4050, 4051), // &Leftrightarrow -> ⇔ + new Transition (4061, 4062), // &leftrightarrow -> ↔ + new Transition (4063, 4064), // &leftrightarrows -> ⇆ + new Transition (4072, 4073), // &leftrightharpoons -> ⇋ + new Transition (4083, 4084), // &leftrightsquigarrow -> ↭ + new Transition (4090, 4091), // &LeftRightVector -> ⥎ + new Transition (4094, 4095), // &LeftTee -> ⊣ + new Transition (4100, 4101), // &LeftTeeArrow -> ↤ + new Transition (4107, 4108), // &LeftTeeVector -> ⥚ + new Transition (4118, 4119), // &leftthreetimes -> ⋋ + new Transition (4126, 4127), // &LeftTriangle -> ⊲ + new Transition (4130, 4131), // &LeftTriangleBar -> ⧏ + new Transition (4136, 4137), // &LeftTriangleEqual -> ⊴ + new Transition (4149, 4150), // &LeftUpDownVector -> ⥑ + new Transition (4159, 4160), // &LeftUpTeeVector -> ⥠ + new Transition (4166, 4167), // &LeftUpVector -> ↿ + new Transition (4170, 4171), // &LeftUpVectorBar -> ⥘ + new Transition (4177, 4178), // &LeftVector -> ↼ + new Transition (4181, 4182), // &LeftVectorBar -> ⥒ + new Transition (4183, 4184), // &lEg -> ⪋ + new Transition (4185, 4186), // &leg -> ⋚ + new Transition (4187, 4188), // &leq -> ≤ + new Transition (4189, 4190), // &leqq -> ≦ + new Transition (4195, 4196), // &leqslant -> ⩽ + new Transition (4197, 4198), // &les -> ⩽ + new Transition (4200, 4201), // &lescc -> ⪨ + new Transition (4204, 4205), // &lesdot -> ⩿ + new Transition (4206, 4207), // &lesdoto -> ⪁ + new Transition (4208, 4209), // &lesdotor -> ⪃ + new Transition (4210, 4211), // &lesg -> ⋚︀ + new Transition (4213, 4214), // &lesges -> ⪓ + new Transition (4221, 4222), // &lessapprox -> ⪅ + new Transition (4225, 4226), // &lessdot -> ⋖ + new Transition (4231, 4232), // &lesseqgtr -> ⋚ + new Transition (4236, 4237), // &lesseqqgtr -> ⪋ + new Transition (4251, 4252), // &LessEqualGreater -> ⋚ + new Transition (4261, 4262), // &LessFullEqual -> ≦ + new Transition (4269, 4270), // &LessGreater -> ≶ + new Transition (4273, 4274), // &lessgtr -> ≶ + new Transition (4278, 4279), // &LessLess -> ⪡ + new Transition (4282, 4283), // &lesssim -> ≲ + new Transition (4293, 4294), // &LessSlantEqual -> ⩽ + new Transition (4299, 4300), // &LessTilde -> ≲ + new Transition (4305, 4306), // &lfisht -> ⥼ + new Transition (4310, 4311), // &lfloor -> ⌊ + new Transition (4313, 4314), // &Lfr -> 𝔏 + new Transition (4315, 4316), // &lfr -> 𝔩 + new Transition (4317, 4318), // &lg -> ≶ + new Transition (4319, 4320), // &lgE -> ⪑ + new Transition (4323, 4324), // &lHar -> ⥢ + new Transition (4328, 4329), // &lhard -> ↽ + new Transition (4330, 4331), // &lharu -> ↼ + new Transition (4332, 4333), // &lharul -> ⥪ + new Transition (4336, 4337), // &lhblk -> ▄ + new Transition (4340, 4341), // &LJcy -> Љ + new Transition (4344, 4345), // &ljcy -> љ + new Transition (4346, 4347), // &Ll -> ⋘ + new Transition (4348, 4349), // &ll -> ≪ + new Transition (4352, 4353), // &llarr -> ⇇ + new Transition (4359, 4360), // &llcorner -> ⌞ + new Transition (4368, 4369), // &Lleftarrow -> ⇚ + new Transition (4373, 4374), // &llhard -> ⥫ + new Transition (4377, 4378), // &lltri -> ◺ + new Transition (4383, 4384), // &Lmidot -> Ŀ + new Transition (4389, 4390), // &lmidot -> ŀ + new Transition (4394, 4395), // &lmoust -> ⎰ + new Transition (4399, 4400), // &lmoustache -> ⎰ + new Transition (4403, 4404), // &lnap -> ⪉ + new Transition (4408, 4409), // &lnapprox -> ⪉ + new Transition (4410, 4411), // &lnE -> ≨ + new Transition (4412, 4413), // &lne -> ⪇ + new Transition (4414, 4415), // &lneq -> ⪇ + new Transition (4416, 4417), // &lneqq -> ≨ + new Transition (4420, 4421), // &lnsim -> ⋦ + new Transition (4425, 4426), // &loang -> ⟬ + new Transition (4428, 4429), // &loarr -> ⇽ + new Transition (4432, 4433), // &lobrk -> ⟦ + new Transition (4445, 4446), // &LongLeftArrow -> ⟵ + new Transition (4455, 4456), // &Longleftarrow -> ⟸ + new Transition (4467, 4468), // &longleftarrow -> ⟵ + new Transition (4478, 4479), // &LongLeftRightArrow -> ⟷ + new Transition (4489, 4490), // &Longleftrightarrow -> ⟺ + new Transition (4500, 4501), // &longleftrightarrow -> ⟷ + new Transition (4507, 4508), // &longmapsto -> ⟼ + new Transition (4518, 4519), // &LongRightArrow -> ⟶ + new Transition (4529, 4530), // &Longrightarrow -> ⟹ + new Transition (4540, 4541), // &longrightarrow -> ⟶ + new Transition (4552, 4553), // &looparrowleft -> ↫ + new Transition (4558, 4559), // &looparrowright -> ↬ + new Transition (4562, 4563), // &lopar -> ⦅ + new Transition (4565, 4566), // &Lopf -> 𝕃 + new Transition (4567, 4568), // &lopf -> 𝕝 + new Transition (4571, 4572), // &loplus -> ⨭ + new Transition (4577, 4578), // &lotimes -> ⨴ + new Transition (4582, 4583), // &lowast -> ∗ + new Transition (4586, 4587), // &lowbar -> _ + new Transition (4599, 4600), // &LowerLeftArrow -> ↙ + new Transition (4610, 4611), // &LowerRightArrow -> ↘ + new Transition (4612, 4613), // &loz -> ◊ + new Transition (4617, 4618), // &lozenge -> ◊ + new Transition (4619, 4620), // &lozf -> ⧫ + new Transition (4623, 4624), // &lpar -> ( + new Transition (4626, 4627), // &lparlt -> ⦓ + new Transition (4631, 4632), // &lrarr -> ⇆ + new Transition (4638, 4639), // &lrcorner -> ⌟ + new Transition (4642, 4643), // &lrhar -> ⇋ + new Transition (4644, 4645), // &lrhard -> ⥭ + new Transition (4646, 4647), // &lrm -> ‎ + new Transition (4650, 4651), // &lrtri -> ⊿ + new Transition (4656, 4657), // &lsaquo -> ‹ + new Transition (4660, 4661), // &Lscr -> ℒ + new Transition (4663, 4664), // &lscr -> 𝓁 + new Transition (4665, 4666), // &Lsh -> ↰ + new Transition (4667, 4668), // &lsh -> ↰ + new Transition (4670, 4671), // &lsim -> ≲ + new Transition (4672, 4673), // &lsime -> ⪍ + new Transition (4674, 4675), // &lsimg -> ⪏ + new Transition (4677, 4678), // &lsqb -> [ + new Transition (4680, 4681), // &lsquo -> ‘ + new Transition (4682, 4683), // &lsquor -> ‚ + new Transition (4687, 4688), // &Lstrok -> Ł + new Transition (4692, 4693), // &lstrok -> ł + new Transition (4694, 4695), // < -> < + new Transition (4696, 4697), // &Lt -> ≪ + new Transition (4698, 4699), // < -> < + new Transition (4701, 4702), // <cc -> ⪦ + new Transition (4704, 4705), // <cir -> ⩹ + new Transition (4708, 4709), // <dot -> ⋖ + new Transition (4713, 4714), // <hree -> ⋋ + new Transition (4718, 4719), // <imes -> ⋉ + new Transition (4723, 4724), // <larr -> ⥶ + new Transition (4729, 4730), // <quest -> ⩻ + new Transition (4732, 4733), // <ri -> ◃ + new Transition (4734, 4735), // <rie -> ⊴ + new Transition (4736, 4737), // <rif -> ◂ + new Transition (4740, 4741), // <rPar -> ⦖ + new Transition (4748, 4749), // &lurdshar -> ⥊ + new Transition (4753, 4754), // &luruhar -> ⥦ + new Transition (4762, 4763), // &lvertneqq -> ≨︀ + new Transition (4765, 4766), // &lvnE -> ≨︀ + new Transition (4770, 4771), // ¯ -> ¯ + new Transition (4773, 4774), // &male -> ♂ + new Transition (4775, 4776), // &malt -> ✠ + new Transition (4779, 4780), // &maltese -> ✠ + new Transition (4783, 4784), // &Map -> ⤅ + new Transition (4785, 4786), // &map -> ↦ + new Transition (4789, 4790), // &mapsto -> ↦ + new Transition (4794, 4795), // &mapstodown -> ↧ + new Transition (4799, 4800), // &mapstoleft -> ↤ + new Transition (4802, 4803), // &mapstoup -> ↥ + new Transition (4807, 4808), // &marker -> ▮ + new Transition (4813, 4814), // &mcomma -> ⨩ + new Transition (4816, 4817), // &Mcy -> М + new Transition (4818, 4819), // &mcy -> м + new Transition (4823, 4824), // &mdash -> — + new Transition (4828, 4829), // &mDDot -> ∺ + new Transition (4841, 4842), // &measuredangle -> ∡ + new Transition (4852, 4853), // &MediumSpace ->   + new Transition (4860, 4861), // &Mellintrf -> ℳ + new Transition (4863, 4864), // &Mfr -> 𝔐 + new Transition (4866, 4867), // &mfr -> 𝔪 + new Transition (4869, 4870), // &mho -> ℧ + new Transition (4874, 4875), // µ -> µ + new Transition (4876, 4877), // &mid -> ∣ + new Transition (4880, 4881), // &midast -> * + new Transition (4884, 4885), // &midcir -> ⫰ + new Transition (4888, 4889), // · -> · + new Transition (4892, 4893), // &minus -> − + new Transition (4894, 4895), // &minusb -> ⊟ + new Transition (4896, 4897), // &minusd -> ∸ + new Transition (4898, 4899), // &minusdu -> ⨪ + new Transition (4907, 4908), // &MinusPlus -> ∓ + new Transition (4911, 4912), // &mlcp -> ⫛ + new Transition (4914, 4915), // &mldr -> … + new Transition (4920, 4921), // &mnplus -> ∓ + new Transition (4926, 4927), // &models -> ⊧ + new Transition (4930, 4931), // &Mopf -> 𝕄 + new Transition (4933, 4934), // &mopf -> 𝕞 + new Transition (4935, 4936), // &mp -> ∓ + new Transition (4939, 4940), // &Mscr -> ℳ + new Transition (4943, 4944), // &mscr -> 𝓂 + new Transition (4948, 4949), // &mstpos -> ∾ + new Transition (4950, 4951), // &Mu -> Μ + new Transition (4952, 4953), // &mu -> μ + new Transition (4959, 4960), // &multimap -> ⊸ + new Transition (4963, 4964), // &mumap -> ⊸ + new Transition (4969, 4970), // &nabla -> ∇ + new Transition (4976, 4977), // &Nacute -> Ń + new Transition (4981, 4982), // &nacute -> ń + new Transition (4984, 4985), // &nang -> ∠⃒ + new Transition (4986, 4987), // &nap -> ≉ + new Transition (4988, 4989), // &napE -> ⩰̸ + new Transition (4991, 4992), // &napid -> ≋̸ + new Transition (4994, 4995), // &napos -> ʼn + new Transition (4999, 5000), // &napprox -> ≉ + new Transition (5003, 5004), // &natur -> ♮ + new Transition (5006, 5007), // &natural -> ♮ + new Transition (5008, 5009), // &naturals -> ℕ + new Transition (5012, 5013), //   ->   + new Transition (5016, 5017), // &nbump -> ≎̸ + new Transition (5018, 5019), // &nbumpe -> ≏̸ + new Transition (5022, 5023), // &ncap -> ⩃ + new Transition (5028, 5029), // &Ncaron -> Ň + new Transition (5032, 5033), // &ncaron -> ň + new Transition (5037, 5038), // &Ncedil -> Ņ + new Transition (5042, 5043), // &ncedil -> ņ + new Transition (5046, 5047), // &ncong -> ≇ + new Transition (5050, 5051), // &ncongdot -> ⩭̸ + new Transition (5053, 5054), // &ncup -> ⩂ + new Transition (5055, 5056), // &Ncy -> Н + new Transition (5057, 5058), // &ncy -> н + new Transition (5062, 5063), // &ndash -> – + new Transition (5064, 5065), // &ne -> ≠ + new Transition (5069, 5070), // &nearhk -> ⤤ + new Transition (5073, 5074), // &neArr -> ⇗ + new Transition (5075, 5076), // &nearr -> ↗ + new Transition (5078, 5079), // &nearrow -> ↗ + new Transition (5082, 5083), // &nedot -> ≐̸ + new Transition (5101, 5102), // &NegativeMediumSpace -> ​ + new Transition (5112, 5113), // &NegativeThickSpace -> ​ + new Transition (5119, 5120), // &NegativeThinSpace -> ​ + new Transition (5133, 5134), // &NegativeVeryThinSpace -> ​ + new Transition (5138, 5139), // &nequiv -> ≢ + new Transition (5143, 5144), // &nesear -> ⤨ + new Transition (5146, 5147), // &nesim -> ≂̸ + new Transition (5165, 5166), // &NestedGreaterGreater -> ≫ + new Transition (5174, 5175), // &NestedLessLess -> ≪ + new Transition (5180, 5181), // &NewLine -> + new Transition (5185, 5186), // &nexist -> ∄ + new Transition (5187, 5188), // &nexists -> ∄ + new Transition (5190, 5191), // &Nfr -> 𝔑 + new Transition (5193, 5194), // &nfr -> 𝔫 + new Transition (5196, 5197), // &ngE -> ≧̸ + new Transition (5198, 5199), // &nge -> ≱ + new Transition (5200, 5201), // &ngeq -> ≱ + new Transition (5202, 5203), // &ngeqq -> ≧̸ + new Transition (5208, 5209), // &ngeqslant -> ⩾̸ + new Transition (5210, 5211), // &nges -> ⩾̸ + new Transition (5213, 5214), // &nGg -> ⋙̸ + new Transition (5217, 5218), // &ngsim -> ≵ + new Transition (5219, 5220), // &nGt -> ≫⃒ + new Transition (5221, 5222), // &ngt -> ≯ + new Transition (5223, 5224), // &ngtr -> ≯ + new Transition (5225, 5226), // &nGtv -> ≫̸ + new Transition (5230, 5231), // &nhArr -> ⇎ + new Transition (5234, 5235), // &nharr -> ↮ + new Transition (5238, 5239), // &nhpar -> ⫲ + new Transition (5240, 5241), // &ni -> ∋ + new Transition (5242, 5243), // &nis -> ⋼ + new Transition (5244, 5245), // &nisd -> ⋺ + new Transition (5246, 5247), // &niv -> ∋ + new Transition (5250, 5251), // &NJcy -> Њ + new Transition (5254, 5255), // &njcy -> њ + new Transition (5259, 5260), // &nlArr -> ⇍ + new Transition (5263, 5264), // &nlarr -> ↚ + new Transition (5266, 5267), // &nldr -> ‥ + new Transition (5268, 5269), // &nlE -> ≦̸ + new Transition (5270, 5271), // &nle -> ≰ + new Transition (5280, 5281), // &nLeftarrow -> ⇍ + new Transition (5288, 5289), // &nleftarrow -> ↚ + new Transition (5299, 5300), // &nLeftrightarrow -> ⇎ + new Transition (5310, 5311), // &nleftrightarrow -> ↮ + new Transition (5312, 5313), // &nleq -> ≰ + new Transition (5314, 5315), // &nleqq -> ≦̸ + new Transition (5320, 5321), // &nleqslant -> ⩽̸ + new Transition (5322, 5323), // &nles -> ⩽̸ + new Transition (5324, 5325), // &nless -> ≮ + new Transition (5326, 5327), // &nLl -> ⋘̸ + new Transition (5330, 5331), // &nlsim -> ≴ + new Transition (5332, 5333), // &nLt -> ≪⃒ + new Transition (5334, 5335), // &nlt -> ≮ + new Transition (5337, 5338), // &nltri -> ⋪ + new Transition (5339, 5340), // &nltrie -> ⋬ + new Transition (5341, 5342), // &nLtv -> ≪̸ + new Transition (5345, 5346), // &nmid -> ∤ + new Transition (5352, 5353), // &NoBreak -> ⁠ + new Transition (5367, 5368), // &NonBreakingSpace ->   + new Transition (5370, 5371), // &Nopf -> ℕ + new Transition (5374, 5375), // &nopf -> 𝕟 + new Transition (5376, 5377), // &Not -> ⫬ + new Transition (5378, 5379), // ¬ -> ¬ + new Transition (5388, 5389), // &NotCongruent -> ≢ + new Transition (5394, 5395), // &NotCupCap -> ≭ + new Transition (5412, 5413), // &NotDoubleVerticalBar -> ∦ + new Transition (5420, 5421), // &NotElement -> ∉ + new Transition (5425, 5426), // &NotEqual -> ≠ + new Transition (5431, 5432), // &NotEqualTilde -> ≂̸ + new Transition (5437, 5438), // &NotExists -> ∄ + new Transition (5445, 5446), // &NotGreater -> ≯ + new Transition (5451, 5452), // &NotGreaterEqual -> ≱ + new Transition (5461, 5462), // &NotGreaterFullEqual -> ≧̸ + new Transition (5469, 5470), // &NotGreaterGreater -> ≫̸ + new Transition (5474, 5475), // &NotGreaterLess -> ≹ + new Transition (5485, 5486), // &NotGreaterSlantEqual -> ⩾̸ + new Transition (5491, 5492), // &NotGreaterTilde -> ≵ + new Transition (5504, 5505), // &NotHumpDownHump -> ≎̸ + new Transition (5510, 5511), // &NotHumpEqual -> ≏̸ + new Transition (5513, 5514), // ¬in -> ∉ + new Transition (5517, 5518), // ¬indot -> ⋵̸ + new Transition (5519, 5520), // ¬inE -> ⋹̸ + new Transition (5522, 5523), // ¬inva -> ∉ + new Transition (5524, 5525), // ¬invb -> ⋷ + new Transition (5526, 5527), // ¬invc -> ⋶ + new Transition (5539, 5540), // &NotLeftTriangle -> ⋪ + new Transition (5543, 5544), // &NotLeftTriangleBar -> ⧏̸ + new Transition (5549, 5550), // &NotLeftTriangleEqual -> ⋬ + new Transition (5552, 5553), // &NotLess -> ≮ + new Transition (5558, 5559), // &NotLessEqual -> ≰ + new Transition (5566, 5567), // &NotLessGreater -> ≸ + new Transition (5571, 5572), // &NotLessLess -> ≪̸ + new Transition (5582, 5583), // &NotLessSlantEqual -> ⩽̸ + new Transition (5588, 5589), // &NotLessTilde -> ≴ + new Transition (5609, 5610), // &NotNestedGreaterGreater -> ⪢̸ + new Transition (5618, 5619), // &NotNestedLessLess -> ⪡̸ + new Transition (5621, 5622), // ¬ni -> ∌ + new Transition (5624, 5625), // ¬niva -> ∌ + new Transition (5626, 5627), // ¬nivb -> ⋾ + new Transition (5628, 5629), // ¬nivc -> ⋽ + new Transition (5637, 5638), // &NotPrecedes -> ⊀ + new Transition (5643, 5644), // &NotPrecedesEqual -> ⪯̸ + new Transition (5654, 5655), // &NotPrecedesSlantEqual -> ⋠ + new Transition (5669, 5670), // &NotReverseElement -> ∌ + new Transition (5682, 5683), // &NotRightTriangle -> ⋫ + new Transition (5686, 5687), // &NotRightTriangleBar -> ⧐̸ + new Transition (5692, 5693), // &NotRightTriangleEqual -> ⋭ + new Transition (5705, 5706), // &NotSquareSubset -> ⊏̸ + new Transition (5711, 5712), // &NotSquareSubsetEqual -> ⋢ + new Transition (5718, 5719), // &NotSquareSuperset -> ⊐̸ + new Transition (5724, 5725), // &NotSquareSupersetEqual -> ⋣ + new Transition (5730, 5731), // &NotSubset -> ⊂⃒ + new Transition (5736, 5737), // &NotSubsetEqual -> ⊈ + new Transition (5743, 5744), // &NotSucceeds -> ⊁ + new Transition (5749, 5750), // &NotSucceedsEqual -> ⪰̸ + new Transition (5760, 5761), // &NotSucceedsSlantEqual -> ⋡ + new Transition (5766, 5767), // &NotSucceedsTilde -> ≿̸ + new Transition (5773, 5774), // &NotSuperset -> ⊃⃒ + new Transition (5779, 5780), // &NotSupersetEqual -> ⊉ + new Transition (5785, 5786), // &NotTilde -> ≁ + new Transition (5791, 5792), // &NotTildeEqual -> ≄ + new Transition (5801, 5802), // &NotTildeFullEqual -> ≇ + new Transition (5807, 5808), // &NotTildeTilde -> ≉ + new Transition (5819, 5820), // &NotVerticalBar -> ∤ + new Transition (5823, 5824), // &npar -> ∦ + new Transition (5829, 5830), // &nparallel -> ∦ + new Transition (5832, 5833), // &nparsl -> ⫽⃥ + new Transition (5834, 5835), // &npart -> ∂̸ + new Transition (5840, 5841), // &npolint -> ⨔ + new Transition (5842, 5843), // &npr -> ⊀ + new Transition (5846, 5847), // &nprcue -> ⋠ + new Transition (5848, 5849), // &npre -> ⪯̸ + new Transition (5850, 5851), // &nprec -> ⊀ + new Transition (5853, 5854), // &npreceq -> ⪯̸ + new Transition (5858, 5859), // &nrArr -> ⇏ + new Transition (5862, 5863), // &nrarr -> ↛ + new Transition (5864, 5865), // &nrarrc -> ⤳̸ + new Transition (5866, 5867), // &nrarrw -> ↝̸ + new Transition (5877, 5878), // &nRightarrow -> ⇏ + new Transition (5887, 5888), // &nrightarrow -> ↛ + new Transition (5891, 5892), // &nrtri -> ⋫ + new Transition (5893, 5894), // &nrtrie -> ⋭ + new Transition (5896, 5897), // &nsc -> ⊁ + new Transition (5900, 5901), // &nsccue -> ⋡ + new Transition (5902, 5903), // &nsce -> ⪰̸ + new Transition (5906, 5907), // &Nscr -> 𝒩 + new Transition (5908, 5909), // &nscr -> 𝓃 + new Transition (5916, 5917), // &nshortmid -> ∤ + new Transition (5925, 5926), // &nshortparallel -> ∦ + new Transition (5928, 5929), // &nsim -> ≁ + new Transition (5930, 5931), // &nsime -> ≄ + new Transition (5932, 5933), // &nsimeq -> ≄ + new Transition (5936, 5937), // &nsmid -> ∤ + new Transition (5940, 5941), // &nspar -> ∦ + new Transition (5946, 5947), // &nsqsube -> ⋢ + new Transition (5949, 5950), // &nsqsupe -> ⋣ + new Transition (5952, 5953), // &nsub -> ⊄ + new Transition (5954, 5955), // &nsubE -> ⫅̸ + new Transition (5956, 5957), // &nsube -> ⊈ + new Transition (5960, 5961), // &nsubset -> ⊂⃒ + new Transition (5963, 5964), // &nsubseteq -> ⊈ + new Transition (5965, 5966), // &nsubseteqq -> ⫅̸ + new Transition (5968, 5969), // &nsucc -> ⊁ + new Transition (5971, 5972), // &nsucceq -> ⪰̸ + new Transition (5973, 5974), // &nsup -> ⊅ + new Transition (5975, 5976), // &nsupE -> ⫆̸ + new Transition (5977, 5978), // &nsupe -> ⊉ + new Transition (5981, 5982), // &nsupset -> ⊃⃒ + new Transition (5984, 5985), // &nsupseteq -> ⊉ + new Transition (5986, 5987), // &nsupseteqq -> ⫆̸ + new Transition (5990, 5991), // &ntgl -> ≹ + new Transition (5996, 5997), // Ñ -> Ñ + new Transition (6001, 6002), // ñ -> ñ + new Transition (6004, 6005), // &ntlg -> ≸ + new Transition (6016, 6017), // &ntriangleleft -> ⋪ + new Transition (6019, 6020), // &ntrianglelefteq -> ⋬ + new Transition (6025, 6026), // &ntriangleright -> ⋫ + new Transition (6028, 6029), // &ntrianglerighteq -> ⋭ + new Transition (6030, 6031), // &Nu -> Ν + new Transition (6032, 6033), // &nu -> ν + new Transition (6034, 6035), // &num -> # + new Transition (6038, 6039), // &numero -> № + new Transition (6041, 6042), // &numsp ->   + new Transition (6045, 6046), // &nvap -> ≍⃒ + new Transition (6051, 6052), // &nVDash -> ⊯ + new Transition (6056, 6057), // &nVdash -> ⊮ + new Transition (6061, 6062), // &nvDash -> ⊭ + new Transition (6066, 6067), // &nvdash -> ⊬ + new Transition (6069, 6070), // &nvge -> ≥⃒ + new Transition (6071, 6072), // &nvgt -> >⃒ + new Transition (6076, 6077), // &nvHarr -> ⤄ + new Transition (6082, 6083), // &nvinfin -> ⧞ + new Transition (6087, 6088), // &nvlArr -> ⤂ + new Transition (6089, 6090), // &nvle -> ≤⃒ + new Transition (6091, 6092), // &nvlt -> <⃒ + new Transition (6095, 6096), // &nvltrie -> ⊴⃒ + new Transition (6100, 6101), // &nvrArr -> ⤃ + new Transition (6105, 6106), // &nvrtrie -> ⊵⃒ + new Transition (6109, 6110), // &nvsim -> ∼⃒ + new Transition (6115, 6116), // &nwarhk -> ⤣ + new Transition (6119, 6120), // &nwArr -> ⇖ + new Transition (6121, 6122), // &nwarr -> ↖ + new Transition (6124, 6125), // &nwarrow -> ↖ + new Transition (6129, 6130), // &nwnear -> ⤧ + new Transition (6136, 6137), // Ó -> Ó + new Transition (6143, 6144), // ó -> ó + new Transition (6146, 6147), // &oast -> ⊛ + new Transition (6150, 6151), // &ocir -> ⊚ + new Transition (6155, 6156), // Ô -> Ô + new Transition (6157, 6158), // ô -> ô + new Transition (6159, 6160), // &Ocy -> О + new Transition (6161, 6162), // &ocy -> о + new Transition (6166, 6167), // &odash -> ⊝ + new Transition (6172, 6173), // &Odblac -> Ő + new Transition (6177, 6178), // &odblac -> ő + new Transition (6180, 6181), // &odiv -> ⨸ + new Transition (6183, 6184), // &odot -> ⊙ + new Transition (6188, 6189), // &odsold -> ⦼ + new Transition (6193, 6194), // &OElig -> Œ + new Transition (6198, 6199), // &oelig -> œ + new Transition (6203, 6204), // &ofcir -> ⦿ + new Transition (6206, 6207), // &Ofr -> 𝔒 + new Transition (6208, 6209), // &ofr -> 𝔬 + new Transition (6212, 6213), // &ogon -> ˛ + new Transition (6218, 6219), // Ò -> Ò + new Transition (6223, 6224), // ò -> ò + new Transition (6225, 6226), // &ogt -> ⧁ + new Transition (6230, 6231), // &ohbar -> ⦵ + new Transition (6232, 6233), // &ohm -> Ω + new Transition (6236, 6237), // &oint -> ∮ + new Transition (6241, 6242), // &olarr -> ↺ + new Transition (6245, 6246), // &olcir -> ⦾ + new Transition (6250, 6251), // &olcross -> ⦻ + new Transition (6254, 6255), // &oline -> ‾ + new Transition (6256, 6257), // &olt -> ⧀ + new Transition (6261, 6262), // &Omacr -> Ō + new Transition (6266, 6267), // &omacr -> ō + new Transition (6270, 6271), // &Omega -> Ω + new Transition (6274, 6275), // &omega -> ω + new Transition (6280, 6281), // &Omicron -> Ο + new Transition (6286, 6287), // &omicron -> ο + new Transition (6288, 6289), // &omid -> ⦶ + new Transition (6292, 6293), // &ominus -> ⊖ + new Transition (6296, 6297), // &Oopf -> 𝕆 + new Transition (6300, 6301), // &oopf -> 𝕠 + new Transition (6304, 6305), // &opar -> ⦷ + new Transition (6324, 6325), // &OpenCurlyDoubleQuote -> “ + new Transition (6330, 6331), // &OpenCurlyQuote -> ‘ + new Transition (6334, 6335), // &operp -> ⦹ + new Transition (6338, 6339), // &oplus -> ⊕ + new Transition (6340, 6341), // &Or -> ⩔ + new Transition (6342, 6343), // &or -> ∨ + new Transition (6346, 6347), // &orarr -> ↻ + new Transition (6348, 6349), // &ord -> ⩝ + new Transition (6351, 6352), // &order -> ℴ + new Transition (6354, 6355), // &orderof -> ℴ + new Transition (6356, 6357), // ª -> ª + new Transition (6358, 6359), // º -> º + new Transition (6363, 6364), // &origof -> ⊶ + new Transition (6366, 6367), // &oror -> ⩖ + new Transition (6372, 6373), // &orslope -> ⩗ + new Transition (6374, 6375), // &orv -> ⩛ + new Transition (6376, 6377), // &oS -> Ⓢ + new Transition (6380, 6381), // &Oscr -> 𝒪 + new Transition (6384, 6385), // &oscr -> ℴ + new Transition (6389, 6390), // Ø -> Ø + new Transition (6394, 6395), // ø -> ø + new Transition (6397, 6398), // &osol -> ⊘ + new Transition (6403, 6404), // Õ -> Õ + new Transition (6409, 6410), // õ -> õ + new Transition (6413, 6414), // &Otimes -> ⨷ + new Transition (6417, 6418), // &otimes -> ⊗ + new Transition (6420, 6421), // &otimesas -> ⨶ + new Transition (6424, 6425), // Ö -> Ö + new Transition (6428, 6429), // ö -> ö + new Transition (6433, 6434), // &ovbar -> ⌽ + new Transition (6440, 6441), // &OverBar -> ‾ + new Transition (6445, 6446), // &OverBrace -> ⏞ + new Transition (6449, 6450), // &OverBracket -> ⎴ + new Transition (6461, 6462), // &OverParenthesis -> ⏜ + new Transition (6465, 6466), // &par -> ∥ + new Transition (6467, 6468), // ¶ -> ¶ + new Transition (6472, 6473), // ¶llel -> ∥ + new Transition (6476, 6477), // &parsim -> ⫳ + new Transition (6478, 6479), // &parsl -> ⫽ + new Transition (6480, 6481), // &part -> ∂ + new Transition (6489, 6490), // &PartialD -> ∂ + new Transition (6492, 6493), // &Pcy -> П + new Transition (6495, 6496), // &pcy -> п + new Transition (6501, 6502), // &percnt -> % + new Transition (6505, 6506), // &period -> . + new Transition (6509, 6510), // &permil -> ‰ + new Transition (6511, 6512), // &perp -> ⊥ + new Transition (6516, 6517), // &pertenk -> ‱ + new Transition (6519, 6520), // &Pfr -> 𝔓 + new Transition (6522, 6523), // &pfr -> 𝔭 + new Transition (6525, 6526), // &Phi -> Φ + new Transition (6528, 6529), // &phi -> φ + new Transition (6530, 6531), // &phiv -> ϕ + new Transition (6535, 6536), // &phmmat -> ℳ + new Transition (6539, 6540), // &phone -> ☎ + new Transition (6541, 6542), // &Pi -> Π + new Transition (6543, 6544), // &pi -> π + new Transition (6551, 6552), // &pitchfork -> ⋔ + new Transition (6553, 6554), // &piv -> ϖ + new Transition (6559, 6560), // &planck -> ℏ + new Transition (6561, 6562), // &planckh -> ℎ + new Transition (6564, 6565), // &plankv -> ℏ + new Transition (6567, 6568), // &plus -> + + new Transition (6572, 6573), // &plusacir -> ⨣ + new Transition (6574, 6575), // &plusb -> ⊞ + new Transition (6578, 6579), // &pluscir -> ⨢ + new Transition (6581, 6582), // &plusdo -> ∔ + new Transition (6583, 6584), // &plusdu -> ⨥ + new Transition (6585, 6586), // &pluse -> ⩲ + new Transition (6594, 6595), // &PlusMinus -> ± + new Transition (6597, 6598), // ± -> ± + new Transition (6601, 6602), // &plussim -> ⨦ + new Transition (6605, 6606), // &plustwo -> ⨧ + new Transition (6607, 6608), // &pm -> ± + new Transition (6620, 6621), // &Poincareplane -> ℌ + new Transition (6628, 6629), // &pointint -> ⨕ + new Transition (6631, 6632), // &Popf -> ℙ + new Transition (6634, 6635), // &popf -> 𝕡 + new Transition (6638, 6639), // £ -> £ + new Transition (6640, 6641), // &Pr -> ⪻ + new Transition (6642, 6643), // &pr -> ≺ + new Transition (6645, 6646), // &prap -> ⪷ + new Transition (6649, 6650), // &prcue -> ≼ + new Transition (6651, 6652), // &prE -> ⪳ + new Transition (6653, 6654), // &pre -> ⪯ + new Transition (6655, 6656), // &prec -> ≺ + new Transition (6662, 6663), // &precapprox -> ⪷ + new Transition (6670, 6671), // &preccurlyeq -> ≼ + new Transition (6677, 6678), // &Precedes -> ≺ + new Transition (6683, 6684), // &PrecedesEqual -> ⪯ + new Transition (6694, 6695), // &PrecedesSlantEqual -> ≼ + new Transition (6700, 6701), // &PrecedesTilde -> ≾ + new Transition (6703, 6704), // &preceq -> ⪯ + new Transition (6711, 6712), // &precnapprox -> ⪹ + new Transition (6715, 6716), // &precneqq -> ⪵ + new Transition (6719, 6720), // &precnsim -> ⋨ + new Transition (6723, 6724), // &precsim -> ≾ + new Transition (6727, 6728), // &Prime -> ″ + new Transition (6731, 6732), // &prime -> ′ + new Transition (6733, 6734), // &primes -> ℙ + new Transition (6737, 6738), // &prnap -> ⪹ + new Transition (6739, 6740), // &prnE -> ⪵ + new Transition (6743, 6744), // &prnsim -> ⋨ + new Transition (6746, 6747), // &prod -> ∏ + new Transition (6752, 6753), // &Product -> ∏ + new Transition (6758, 6759), // &profalar -> ⌮ + new Transition (6763, 6764), // &profline -> ⌒ + new Transition (6768, 6769), // &profsurf -> ⌓ + new Transition (6770, 6771), // &prop -> ∝ + new Transition (6778, 6779), // &Proportion -> ∷ + new Transition (6781, 6782), // &Proportional -> ∝ + new Transition (6784, 6785), // &propto -> ∝ + new Transition (6788, 6789), // &prsim -> ≾ + new Transition (6793, 6794), // &prurel -> ⊰ + new Transition (6797, 6798), // &Pscr -> 𝒫 + new Transition (6801, 6802), // &pscr -> 𝓅 + new Transition (6803, 6804), // &Psi -> Ψ + new Transition (6805, 6806), // &psi -> ψ + new Transition (6811, 6812), // &puncsp ->   + new Transition (6815, 6816), // &Qfr -> 𝔔 + new Transition (6819, 6820), // &qfr -> 𝔮 + new Transition (6823, 6824), // &qint -> ⨌ + new Transition (6827, 6828), // &Qopf -> ℚ + new Transition (6831, 6832), // &qopf -> 𝕢 + new Transition (6837, 6838), // &qprime -> ⁗ + new Transition (6841, 6842), // &Qscr -> 𝒬 + new Transition (6845, 6846), // &qscr -> 𝓆 + new Transition (6856, 6857), // &quaternions -> ℍ + new Transition (6860, 6861), // &quatint -> ⨖ + new Transition (6864, 6865), // &quest -> ? + new Transition (6867, 6868), // &questeq -> ≟ + new Transition (6871, 6872), // " -> " + new Transition (6874, 6875), // " -> " + new Transition (6880, 6881), // &rAarr -> ⇛ + new Transition (6884, 6885), // &race -> ∽̱ + new Transition (6891, 6892), // &Racute -> Ŕ + new Transition (6895, 6896), // &racute -> ŕ + new Transition (6899, 6900), // &radic -> √ + new Transition (6906, 6907), // &raemptyv -> ⦳ + new Transition (6909, 6910), // &Rang -> ⟫ + new Transition (6912, 6913), // &rang -> ⟩ + new Transition (6914, 6915), // &rangd -> ⦒ + new Transition (6916, 6917), // &range -> ⦥ + new Transition (6919, 6920), // &rangle -> ⟩ + new Transition (6923, 6924), // » -> » + new Transition (6926, 6927), // &Rarr -> ↠ + new Transition (6929, 6930), // &rArr -> ⇒ + new Transition (6932, 6933), // &rarr -> → + new Transition (6935, 6936), // &rarrap -> ⥵ + new Transition (6937, 6938), // &rarrb -> ⇥ + new Transition (6940, 6941), // &rarrbfs -> ⤠ + new Transition (6942, 6943), // &rarrc -> ⤳ + new Transition (6945, 6946), // &rarrfs -> ⤞ + new Transition (6948, 6949), // &rarrhk -> ↪ + new Transition (6951, 6952), // &rarrlp -> ↬ + new Transition (6954, 6955), // &rarrpl -> ⥅ + new Transition (6958, 6959), // &rarrsim -> ⥴ + new Transition (6961, 6962), // &Rarrtl -> ⤖ + new Transition (6964, 6965), // &rarrtl -> ↣ + new Transition (6966, 6967), // &rarrw -> ↝ + new Transition (6971, 6972), // &rAtail -> ⤜ + new Transition (6976, 6977), // &ratail -> ⤚ + new Transition (6979, 6980), // &ratio -> ∶ + new Transition (6984, 6985), // &rationals -> ℚ + new Transition (6989, 6990), // &RBarr -> ⤐ + new Transition (6994, 6995), // &rBarr -> ⤏ + new Transition (6999, 7000), // &rbarr -> ⤍ + new Transition (7003, 7004), // &rbbrk -> ❳ + new Transition (7008, 7009), // &rbrace -> } + new Transition (7010, 7011), // &rbrack -> ] + new Transition (7013, 7014), // &rbrke -> ⦌ + new Transition (7017, 7018), // &rbrksld -> ⦎ + new Transition (7019, 7020), // &rbrkslu -> ⦐ + new Transition (7025, 7026), // &Rcaron -> Ř + new Transition (7031, 7032), // &rcaron -> ř + new Transition (7036, 7037), // &Rcedil -> Ŗ + new Transition (7041, 7042), // &rcedil -> ŗ + new Transition (7044, 7045), // &rceil -> ⌉ + new Transition (7047, 7048), // &rcub -> } + new Transition (7049, 7050), // &Rcy -> Р + new Transition (7051, 7052), // &rcy -> р + new Transition (7055, 7056), // &rdca -> ⤷ + new Transition (7061, 7062), // &rdldhar -> ⥩ + new Transition (7065, 7066), // &rdquo -> ” + new Transition (7067, 7068), // &rdquor -> ” + new Transition (7070, 7071), // &rdsh -> ↳ + new Transition (7072, 7073), // &Re -> ℜ + new Transition (7076, 7077), // &real -> ℜ + new Transition (7080, 7081), // &realine -> ℛ + new Transition (7085, 7086), // &realpart -> ℜ + new Transition (7087, 7088), // &reals -> ℝ + new Transition (7090, 7091), // &rect -> ▭ + new Transition (7093, 7094), // ® -> ® + new Transition (7095, 7096), // ® -> ® + new Transition (7108, 7109), // &ReverseElement -> ∋ + new Transition (7119, 7120), // &ReverseEquilibrium -> ⇋ + new Transition (7133, 7134), // &ReverseUpEquilibrium -> ⥯ + new Transition (7139, 7140), // &rfisht -> ⥽ + new Transition (7144, 7145), // &rfloor -> ⌋ + new Transition (7147, 7148), // &Rfr -> ℜ + new Transition (7149, 7150), // &rfr -> 𝔯 + new Transition (7153, 7154), // &rHar -> ⥤ + new Transition (7158, 7159), // &rhard -> ⇁ + new Transition (7160, 7161), // &rharu -> ⇀ + new Transition (7162, 7163), // &rharul -> ⥬ + new Transition (7165, 7166), // &Rho -> Ρ + new Transition (7167, 7168), // &rho -> ρ + new Transition (7169, 7170), // &rhov -> ϱ + new Transition (7186, 7187), // &RightAngleBracket -> ⟩ + new Transition (7191, 7192), // &RightArrow -> → + new Transition (7197, 7198), // &Rightarrow -> ⇒ + new Transition (7207, 7208), // &rightarrow -> → + new Transition (7211, 7212), // &RightArrowBar -> ⇥ + new Transition (7221, 7222), // &RightArrowLeftArrow -> ⇄ + new Transition (7226, 7227), // &rightarrowtail -> ↣ + new Transition (7234, 7235), // &RightCeiling -> ⌉ + new Transition (7248, 7249), // &RightDoubleBracket -> ⟧ + new Transition (7260, 7261), // &RightDownTeeVector -> ⥝ + new Transition (7267, 7268), // &RightDownVector -> ⇂ + new Transition (7271, 7272), // &RightDownVectorBar -> ⥕ + new Transition (7277, 7278), // &RightFloor -> ⌋ + new Transition (7289, 7290), // &rightharpoondown -> ⇁ + new Transition (7292, 7293), // &rightharpoonup -> ⇀ + new Transition (7303, 7304), // &rightleftarrows -> ⇄ + new Transition (7312, 7313), // &rightleftharpoons -> ⇌ + new Transition (7324, 7325), // &rightrightarrows -> ⇉ + new Transition (7335, 7336), // &rightsquigarrow -> ↝ + new Transition (7339, 7340), // &RightTee -> ⊢ + new Transition (7345, 7346), // &RightTeeArrow -> ↦ + new Transition (7352, 7353), // &RightTeeVector -> ⥛ + new Transition (7363, 7364), // &rightthreetimes -> ⋌ + new Transition (7371, 7372), // &RightTriangle -> ⊳ + new Transition (7375, 7376), // &RightTriangleBar -> ⧐ + new Transition (7381, 7382), // &RightTriangleEqual -> ⊵ + new Transition (7394, 7395), // &RightUpDownVector -> ⥏ + new Transition (7404, 7405), // &RightUpTeeVector -> ⥜ + new Transition (7411, 7412), // &RightUpVector -> ↾ + new Transition (7415, 7416), // &RightUpVectorBar -> ⥔ + new Transition (7422, 7423), // &RightVector -> ⇀ + new Transition (7426, 7427), // &RightVectorBar -> ⥓ + new Transition (7429, 7430), // &ring -> ˚ + new Transition (7440, 7441), // &risingdotseq -> ≓ + new Transition (7445, 7446), // &rlarr -> ⇄ + new Transition (7449, 7450), // &rlhar -> ⇌ + new Transition (7451, 7452), // &rlm -> ‏ + new Transition (7457, 7458), // &rmoust -> ⎱ + new Transition (7462, 7463), // &rmoustache -> ⎱ + new Transition (7467, 7468), // &rnmid -> ⫮ + new Transition (7472, 7473), // &roang -> ⟭ + new Transition (7475, 7476), // &roarr -> ⇾ + new Transition (7479, 7480), // &robrk -> ⟧ + new Transition (7483, 7484), // &ropar -> ⦆ + new Transition (7487, 7488), // &Ropf -> ℝ + new Transition (7489, 7490), // &ropf -> 𝕣 + new Transition (7493, 7494), // &roplus -> ⨮ + new Transition (7499, 7500), // &rotimes -> ⨵ + new Transition (7510, 7511), // &RoundImplies -> ⥰ + new Transition (7514, 7515), // &rpar -> ) + new Transition (7517, 7518), // &rpargt -> ⦔ + new Transition (7524, 7525), // &rppolint -> ⨒ + new Transition (7529, 7530), // &rrarr -> ⇉ + new Transition (7540, 7541), // &Rrightarrow -> ⇛ + new Transition (7546, 7547), // &rsaquo -> › + new Transition (7550, 7551), // &Rscr -> ℛ + new Transition (7553, 7554), // &rscr -> 𝓇 + new Transition (7555, 7556), // &Rsh -> ↱ + new Transition (7557, 7558), // &rsh -> ↱ + new Transition (7560, 7561), // &rsqb -> ] + new Transition (7563, 7564), // &rsquo -> ’ + new Transition (7565, 7566), // &rsquor -> ’ + new Transition (7571, 7572), // &rthree -> ⋌ + new Transition (7576, 7577), // &rtimes -> ⋊ + new Transition (7579, 7580), // &rtri -> ▹ + new Transition (7581, 7582), // &rtrie -> ⊵ + new Transition (7583, 7584), // &rtrif -> ▸ + new Transition (7588, 7589), // &rtriltri -> ⧎ + new Transition (7599, 7600), // &RuleDelayed -> ⧴ + new Transition (7606, 7607), // &ruluhar -> ⥨ + new Transition (7608, 7609), // &rx -> ℞ + new Transition (7615, 7616), // &Sacute -> Ś + new Transition (7622, 7623), // &sacute -> ś + new Transition (7627, 7628), // &sbquo -> ‚ + new Transition (7629, 7630), // &Sc -> ⪼ + new Transition (7631, 7632), // &sc -> ≻ + new Transition (7634, 7635), // &scap -> ⪸ + new Transition (7639, 7640), // &Scaron -> Š + new Transition (7643, 7644), // &scaron -> š + new Transition (7647, 7648), // &sccue -> ≽ + new Transition (7649, 7650), // &scE -> ⪴ + new Transition (7651, 7652), // &sce -> ⪰ + new Transition (7656, 7657), // &Scedil -> Ş + new Transition (7660, 7661), // &scedil -> ş + new Transition (7664, 7665), // &Scirc -> Ŝ + new Transition (7668, 7669), // &scirc -> ŝ + new Transition (7672, 7673), // &scnap -> ⪺ + new Transition (7674, 7675), // &scnE -> ⪶ + new Transition (7678, 7679), // &scnsim -> ⋩ + new Transition (7685, 7686), // &scpolint -> ⨓ + new Transition (7689, 7690), // &scsim -> ≿ + new Transition (7691, 7692), // &Scy -> С + new Transition (7693, 7694), // &scy -> с + new Transition (7697, 7698), // &sdot -> ⋅ + new Transition (7699, 7700), // &sdotb -> ⊡ + new Transition (7701, 7702), // &sdote -> ⩦ + new Transition (7707, 7708), // &searhk -> ⤥ + new Transition (7711, 7712), // &seArr -> ⇘ + new Transition (7713, 7714), // &searr -> ↘ + new Transition (7716, 7717), // &searrow -> ↘ + new Transition (7719, 7720), // § -> § + new Transition (7722, 7723), // &semi -> ; + new Transition (7727, 7728), // &seswar -> ⤩ + new Transition (7734, 7735), // &setminus -> ∖ + new Transition (7736, 7737), // &setmn -> ∖ + new Transition (7739, 7740), // &sext -> ✶ + new Transition (7742, 7743), // &Sfr -> 𝔖 + new Transition (7745, 7746), // &sfr -> 𝔰 + new Transition (7749, 7750), // &sfrown -> ⌢ + new Transition (7754, 7755), // &sharp -> ♯ + new Transition (7760, 7761), // &SHCHcy -> Щ + new Transition (7765, 7766), // &shchcy -> щ + new Transition (7768, 7769), // &SHcy -> Ш + new Transition (7770, 7771), // &shcy -> ш + new Transition (7784, 7785), // &ShortDownArrow -> ↓ + new Transition (7794, 7795), // &ShortLeftArrow -> ← + new Transition (7801, 7802), // &shortmid -> ∣ + new Transition (7810, 7811), // &shortparallel -> ∥ + new Transition (7821, 7822), // &ShortRightArrow -> → + new Transition (7829, 7830), // &ShortUpArrow -> ↑ + new Transition (7831, 7832), // ­ -> ­ + new Transition (7836, 7837), // &Sigma -> Σ + new Transition (7841, 7842), // &sigma -> σ + new Transition (7843, 7844), // &sigmaf -> ς + new Transition (7845, 7846), // &sigmav -> ς + new Transition (7847, 7848), // &sim -> ∼ + new Transition (7851, 7852), // &simdot -> ⩪ + new Transition (7853, 7854), // &sime -> ≃ + new Transition (7855, 7856), // &simeq -> ≃ + new Transition (7857, 7858), // &simg -> ⪞ + new Transition (7859, 7860), // &simgE -> ⪠ + new Transition (7861, 7862), // &siml -> ⪝ + new Transition (7863, 7864), // &simlE -> ⪟ + new Transition (7866, 7867), // &simne -> ≆ + new Transition (7871, 7872), // &simplus -> ⨤ + new Transition (7876, 7877), // &simrarr -> ⥲ + new Transition (7881, 7882), // &slarr -> ← + new Transition (7892, 7893), // &SmallCircle -> ∘ + new Transition (7905, 7906), // &smallsetminus -> ∖ + new Transition (7909, 7910), // &smashp -> ⨳ + new Transition (7916, 7917), // &smeparsl -> ⧤ + new Transition (7919, 7920), // &smid -> ∣ + new Transition (7922, 7923), // &smile -> ⌣ + new Transition (7924, 7925), // &smt -> ⪪ + new Transition (7926, 7927), // &smte -> ⪬ + new Transition (7928, 7929), // &smtes -> ⪬︀ + new Transition (7934, 7935), // &SOFTcy -> Ь + new Transition (7940, 7941), // &softcy -> ь + new Transition (7942, 7943), // &sol -> / + new Transition (7944, 7945), // &solb -> ⧄ + new Transition (7947, 7948), // &solbar -> ⌿ + new Transition (7951, 7952), // &Sopf -> 𝕊 + new Transition (7954, 7955), // &sopf -> 𝕤 + new Transition (7960, 7961), // &spades -> ♠ + new Transition (7964, 7965), // &spadesuit -> ♠ + new Transition (7966, 7967), // &spar -> ∥ + new Transition (7971, 7972), // &sqcap -> ⊓ + new Transition (7973, 7974), // &sqcaps -> ⊓︀ + new Transition (7976, 7977), // &sqcup -> ⊔ + new Transition (7978, 7979), // &sqcups -> ⊔︀ + new Transition (7982, 7983), // &Sqrt -> √ + new Transition (7986, 7987), // &sqsub -> ⊏ + new Transition (7988, 7989), // &sqsube -> ⊑ + new Transition (7992, 7993), // &sqsubset -> ⊏ + new Transition (7995, 7996), // &sqsubseteq -> ⊑ + new Transition (7997, 7998), // &sqsup -> ⊐ + new Transition (7999, 8000), // &sqsupe -> ⊒ + new Transition (8003, 8004), // &sqsupset -> ⊐ + new Transition (8006, 8007), // &sqsupseteq -> ⊒ + new Transition (8008, 8009), // &squ -> □ + new Transition (8013, 8014), // &Square -> □ + new Transition (8017, 8018), // &square -> □ + new Transition (8030, 8031), // &SquareIntersection -> ⊓ + new Transition (8037, 8038), // &SquareSubset -> ⊏ + new Transition (8043, 8044), // &SquareSubsetEqual -> ⊑ + new Transition (8050, 8051), // &SquareSuperset -> ⊐ + new Transition (8056, 8057), // &SquareSupersetEqual -> ⊒ + new Transition (8062, 8063), // &SquareUnion -> ⊔ + new Transition (8064, 8065), // &squarf -> ▪ + new Transition (8066, 8067), // &squf -> ▪ + new Transition (8071, 8072), // &srarr -> → + new Transition (8075, 8076), // &Sscr -> 𝒮 + new Transition (8079, 8080), // &sscr -> 𝓈 + new Transition (8084, 8085), // &ssetmn -> ∖ + new Transition (8089, 8090), // &ssmile -> ⌣ + new Transition (8094, 8095), // &sstarf -> ⋆ + new Transition (8098, 8099), // &Star -> ⋆ + new Transition (8102, 8103), // &star -> ☆ + new Transition (8104, 8105), // &starf -> ★ + new Transition (8118, 8119), // &straightepsilon -> ϵ + new Transition (8122, 8123), // &straightphi -> ϕ + new Transition (8125, 8126), // &strns -> ¯ + new Transition (8128, 8129), // &Sub -> ⋐ + new Transition (8131, 8132), // &sub -> ⊂ + new Transition (8135, 8136), // &subdot -> ⪽ + new Transition (8137, 8138), // &subE -> ⫅ + new Transition (8139, 8140), // &sube -> ⊆ + new Transition (8143, 8144), // &subedot -> ⫃ + new Transition (8148, 8149), // &submult -> ⫁ + new Transition (8151, 8152), // &subnE -> ⫋ + new Transition (8153, 8154), // &subne -> ⊊ + new Transition (8158, 8159), // &subplus -> ⪿ + new Transition (8163, 8164), // &subrarr -> ⥹ + new Transition (8167, 8168), // &Subset -> ⋐ + new Transition (8171, 8172), // &subset -> ⊂ + new Transition (8174, 8175), // &subseteq -> ⊆ + new Transition (8176, 8177), // &subseteqq -> ⫅ + new Transition (8182, 8183), // &SubsetEqual -> ⊆ + new Transition (8186, 8187), // &subsetneq -> ⊊ + new Transition (8188, 8189), // &subsetneqq -> ⫋ + new Transition (8191, 8192), // &subsim -> ⫇ + new Transition (8194, 8195), // &subsub -> ⫕ + new Transition (8196, 8197), // &subsup -> ⫓ + new Transition (8199, 8200), // &succ -> ≻ + new Transition (8206, 8207), // &succapprox -> ⪸ + new Transition (8214, 8215), // &succcurlyeq -> ≽ + new Transition (8221, 8222), // &Succeeds -> ≻ + new Transition (8227, 8228), // &SucceedsEqual -> ⪰ + new Transition (8238, 8239), // &SucceedsSlantEqual -> ≽ + new Transition (8244, 8245), // &SucceedsTilde -> ≿ + new Transition (8247, 8248), // &succeq -> ⪰ + new Transition (8255, 8256), // &succnapprox -> ⪺ + new Transition (8259, 8260), // &succneqq -> ⪶ + new Transition (8263, 8264), // &succnsim -> ⋩ + new Transition (8267, 8268), // &succsim -> ≿ + new Transition (8273, 8274), // &SuchThat -> ∋ + new Transition (8275, 8276), // &Sum -> ∑ + new Transition (8277, 8278), // &sum -> ∑ + new Transition (8280, 8281), // &sung -> ♪ + new Transition (8282, 8283), // &Sup -> ⋑ + new Transition (8284, 8285), // &sup -> ⊃ + new Transition (8286, 8287), // ¹ -> ¹ + new Transition (8288, 8289), // ² -> ² + new Transition (8290, 8291), // ³ -> ³ + new Transition (8294, 8295), // &supdot -> ⪾ + new Transition (8298, 8299), // &supdsub -> ⫘ + new Transition (8300, 8301), // &supE -> ⫆ + new Transition (8302, 8303), // &supe -> ⊇ + new Transition (8306, 8307), // &supedot -> ⫄ + new Transition (8312, 8313), // &Superset -> ⊃ + new Transition (8318, 8319), // &SupersetEqual -> ⊇ + new Transition (8323, 8324), // &suphsol -> ⟉ + new Transition (8326, 8327), // &suphsub -> ⫗ + new Transition (8331, 8332), // &suplarr -> ⥻ + new Transition (8336, 8337), // &supmult -> ⫂ + new Transition (8339, 8340), // &supnE -> ⫌ + new Transition (8341, 8342), // &supne -> ⊋ + new Transition (8346, 8347), // &supplus -> ⫀ + new Transition (8350, 8351), // &Supset -> ⋑ + new Transition (8354, 8355), // &supset -> ⊃ + new Transition (8357, 8358), // &supseteq -> ⊇ + new Transition (8359, 8360), // &supseteqq -> ⫆ + new Transition (8363, 8364), // &supsetneq -> ⊋ + new Transition (8365, 8366), // &supsetneqq -> ⫌ + new Transition (8368, 8369), // &supsim -> ⫈ + new Transition (8371, 8372), // &supsub -> ⫔ + new Transition (8373, 8374), // &supsup -> ⫖ + new Transition (8379, 8380), // &swarhk -> ⤦ + new Transition (8383, 8384), // &swArr -> ⇙ + new Transition (8385, 8386), // &swarr -> ↙ + new Transition (8388, 8389), // &swarrow -> ↙ + new Transition (8393, 8394), // &swnwar -> ⤪ + new Transition (8398, 8399), // ß -> ß + new Transition (8402, 8403), // &Tab -> + new Transition (8409, 8410), // &target -> ⌖ + new Transition (8411, 8412), // &Tau -> Τ + new Transition (8413, 8414), // &tau -> τ + new Transition (8417, 8418), // &tbrk -> ⎴ + new Transition (8423, 8424), // &Tcaron -> Ť + new Transition (8429, 8430), // &tcaron -> ť + new Transition (8434, 8435), // &Tcedil -> Ţ + new Transition (8439, 8440), // &tcedil -> ţ + new Transition (8441, 8442), // &Tcy -> Т + new Transition (8443, 8444), // &tcy -> т + new Transition (8447, 8448), // &tdot -> ⃛ + new Transition (8453, 8454), // &telrec -> ⌕ + new Transition (8456, 8457), // &Tfr -> 𝔗 + new Transition (8459, 8460), // &tfr -> 𝔱 + new Transition (8465, 8466), // &there4 -> ∴ + new Transition (8474, 8475), // &Therefore -> ∴ + new Transition (8479, 8480), // &therefore -> ∴ + new Transition (8482, 8483), // &Theta -> Θ + new Transition (8485, 8486), // &theta -> θ + new Transition (8489, 8490), // &thetasym -> ϑ + new Transition (8491, 8492), // &thetav -> ϑ + new Transition (8501, 8502), // &thickapprox -> ≈ + new Transition (8505, 8506), // &thicksim -> ∼ + new Transition (8514, 8515), // &ThickSpace ->    + new Transition (8518, 8519), // &thinsp ->   + new Transition (8525, 8526), // &ThinSpace ->   + new Transition (8529, 8530), // &thkap -> ≈ + new Transition (8533, 8534), // &thksim -> ∼ + new Transition (8538, 8539), // Þ -> Þ + new Transition (8542, 8543), // þ -> þ + new Transition (8547, 8548), // &Tilde -> ∼ + new Transition (8552, 8553), // &tilde -> ˜ + new Transition (8558, 8559), // &TildeEqual -> ≃ + new Transition (8568, 8569), // &TildeFullEqual -> ≅ + new Transition (8574, 8575), // &TildeTilde -> ≈ + new Transition (8578, 8579), // × -> × + new Transition (8580, 8581), // ×b -> ⊠ + new Transition (8583, 8584), // ×bar -> ⨱ + new Transition (8585, 8586), // ×d -> ⨰ + new Transition (8588, 8589), // &tint -> ∭ + new Transition (8592, 8593), // &toea -> ⤨ + new Transition (8594, 8595), // &top -> ⊤ + new Transition (8598, 8599), // &topbot -> ⌶ + new Transition (8602, 8603), // &topcir -> ⫱ + new Transition (8606, 8607), // &Topf -> 𝕋 + new Transition (8608, 8609), // &topf -> 𝕥 + new Transition (8612, 8613), // &topfork -> ⫚ + new Transition (8615, 8616), // &tosa -> ⤩ + new Transition (8621, 8622), // &tprime -> ‴ + new Transition (8626, 8627), // &TRADE -> ™ + new Transition (8631, 8632), // &trade -> ™ + new Transition (8638, 8639), // &triangle -> ▵ + new Transition (8643, 8644), // &triangledown -> ▿ + new Transition (8648, 8649), // &triangleleft -> ◃ + new Transition (8651, 8652), // &trianglelefteq -> ⊴ + new Transition (8653, 8654), // &triangleq -> ≜ + new Transition (8659, 8660), // &triangleright -> ▹ + new Transition (8662, 8663), // &trianglerighteq -> ⊵ + new Transition (8666, 8667), // &tridot -> ◬ + new Transition (8668, 8669), // &trie -> ≜ + new Transition (8674, 8675), // &triminus -> ⨺ + new Transition (8683, 8684), // &TripleDot -> ⃛ + new Transition (8688, 8689), // &triplus -> ⨹ + new Transition (8691, 8692), // &trisb -> ⧍ + new Transition (8696, 8697), // &tritime -> ⨻ + new Transition (8703, 8704), // &trpezium -> ⏢ + new Transition (8707, 8708), // &Tscr -> 𝒯 + new Transition (8711, 8712), // &tscr -> 𝓉 + new Transition (8715, 8716), // &TScy -> Ц + new Transition (8717, 8718), // &tscy -> ц + new Transition (8721, 8722), // &TSHcy -> Ћ + new Transition (8725, 8726), // &tshcy -> ћ + new Transition (8730, 8731), // &Tstrok -> Ŧ + new Transition (8735, 8736), // &tstrok -> ŧ + new Transition (8740, 8741), // &twixt -> ≬ + new Transition (8755, 8756), // &twoheadleftarrow -> ↞ + new Transition (8766, 8767), // &twoheadrightarrow -> ↠ + new Transition (8773, 8774), // Ú -> Ú + new Transition (8780, 8781), // ú -> ú + new Transition (8783, 8784), // &Uarr -> ↟ + new Transition (8787, 8788), // &uArr -> ⇑ + new Transition (8790, 8791), // &uarr -> ↑ + new Transition (8795, 8796), // &Uarrocir -> ⥉ + new Transition (8800, 8801), // &Ubrcy -> Ў + new Transition (8805, 8806), // &ubrcy -> ў + new Transition (8809, 8810), // &Ubreve -> Ŭ + new Transition (8813, 8814), // &ubreve -> ŭ + new Transition (8818, 8819), // Û -> Û + new Transition (8823, 8824), // û -> û + new Transition (8825, 8826), // &Ucy -> У + new Transition (8827, 8828), // &ucy -> у + new Transition (8832, 8833), // &udarr -> ⇅ + new Transition (8838, 8839), // &Udblac -> Ű + new Transition (8843, 8844), // &udblac -> ű + new Transition (8847, 8848), // &udhar -> ⥮ + new Transition (8853, 8854), // &ufisht -> ⥾ + new Transition (8856, 8857), // &Ufr -> 𝔘 + new Transition (8858, 8859), // &ufr -> 𝔲 + new Transition (8864, 8865), // Ù -> Ù + new Transition (8870, 8871), // ù -> ù + new Transition (8874, 8875), // &uHar -> ⥣ + new Transition (8879, 8880), // &uharl -> ↿ + new Transition (8881, 8882), // &uharr -> ↾ + new Transition (8885, 8886), // &uhblk -> ▀ + new Transition (8891, 8892), // &ulcorn -> ⌜ + new Transition (8894, 8895), // &ulcorner -> ⌜ + new Transition (8898, 8899), // &ulcrop -> ⌏ + new Transition (8902, 8903), // &ultri -> ◸ + new Transition (8907, 8908), // &Umacr -> Ū + new Transition (8912, 8913), // &umacr -> ū + new Transition (8914, 8915), // ¨ -> ¨ + new Transition (8922, 8923), // &UnderBar -> _ + new Transition (8927, 8928), // &UnderBrace -> ⏟ + new Transition (8931, 8932), // &UnderBracket -> ⎵ + new Transition (8943, 8944), // &UnderParenthesis -> ⏝ + new Transition (8947, 8948), // &Union -> ⋃ + new Transition (8952, 8953), // &UnionPlus -> ⊎ + new Transition (8957, 8958), // &Uogon -> Ų + new Transition (8962, 8963), // &uogon -> ų + new Transition (8965, 8966), // &Uopf -> 𝕌 + new Transition (8968, 8969), // &uopf -> 𝕦 + new Transition (8975, 8976), // &UpArrow -> ↑ + new Transition (8981, 8982), // &Uparrow -> ⇑ + new Transition (8988, 8989), // &uparrow -> ↑ + new Transition (8992, 8993), // &UpArrowBar -> ⤒ + new Transition (9002, 9003), // &UpArrowDownArrow -> ⇅ + new Transition (9012, 9013), // &UpDownArrow -> ↕ + new Transition (9022, 9023), // &Updownarrow -> ⇕ + new Transition (9032, 9033), // &updownarrow -> ↕ + new Transition (9044, 9045), // &UpEquilibrium -> ⥮ + new Transition (9056, 9057), // &upharpoonleft -> ↿ + new Transition (9062, 9063), // &upharpoonright -> ↾ + new Transition (9066, 9067), // &uplus -> ⊎ + new Transition (9079, 9080), // &UpperLeftArrow -> ↖ + new Transition (9090, 9091), // &UpperRightArrow -> ↗ + new Transition (9093, 9094), // &Upsi -> ϒ + new Transition (9096, 9097), // &upsi -> υ + new Transition (9098, 9099), // &upsih -> ϒ + new Transition (9102, 9103), // &Upsilon -> Υ + new Transition (9106, 9107), // &upsilon -> υ + new Transition (9110, 9111), // &UpTee -> ⊥ + new Transition (9116, 9117), // &UpTeeArrow -> ↥ + new Transition (9125, 9126), // &upuparrows -> ⇈ + new Transition (9131, 9132), // &urcorn -> ⌝ + new Transition (9134, 9135), // &urcorner -> ⌝ + new Transition (9138, 9139), // &urcrop -> ⌎ + new Transition (9143, 9144), // &Uring -> Ů + new Transition (9147, 9148), // &uring -> ů + new Transition (9151, 9152), // &urtri -> ◹ + new Transition (9155, 9156), // &Uscr -> 𝒰 + new Transition (9159, 9160), // &uscr -> 𝓊 + new Transition (9164, 9165), // &utdot -> ⋰ + new Transition (9170, 9171), // &Utilde -> Ũ + new Transition (9175, 9176), // &utilde -> ũ + new Transition (9178, 9179), // &utri -> ▵ + new Transition (9180, 9181), // &utrif -> ▴ + new Transition (9185, 9186), // &uuarr -> ⇈ + new Transition (9189, 9190), // Ü -> Ü + new Transition (9192, 9193), // ü -> ü + new Transition (9199, 9200), // &uwangle -> ⦧ + new Transition (9206, 9207), // &vangrt -> ⦜ + new Transition (9215, 9216), // &varepsilon -> ϵ + new Transition (9221, 9222), // &varkappa -> ϰ + new Transition (9229, 9230), // &varnothing -> ∅ + new Transition (9233, 9234), // &varphi -> ϕ + new Transition (9235, 9236), // &varpi -> ϖ + new Transition (9241, 9242), // &varpropto -> ∝ + new Transition (9245, 9246), // &vArr -> ⇕ + new Transition (9247, 9248), // &varr -> ↕ + new Transition (9250, 9251), // &varrho -> ϱ + new Transition (9256, 9257), // &varsigma -> ς + new Transition (9265, 9266), // &varsubsetneq -> ⊊︀ + new Transition (9267, 9268), // &varsubsetneqq -> ⫋︀ + new Transition (9275, 9276), // &varsupsetneq -> ⊋︀ + new Transition (9277, 9278), // &varsupsetneqq -> ⫌︀ + new Transition (9283, 9284), // &vartheta -> ϑ + new Transition (9295, 9296), // &vartriangleleft -> ⊲ + new Transition (9301, 9302), // &vartriangleright -> ⊳ + new Transition (9306, 9307), // &Vbar -> ⫫ + new Transition (9310, 9311), // &vBar -> ⫨ + new Transition (9312, 9313), // &vBarv -> ⫩ + new Transition (9315, 9316), // &Vcy -> В + new Transition (9318, 9319), // &vcy -> в + new Transition (9323, 9324), // &VDash -> ⊫ + new Transition (9328, 9329), // &Vdash -> ⊩ + new Transition (9333, 9334), // &vDash -> ⊨ + new Transition (9338, 9339), // &vdash -> ⊢ + new Transition (9340, 9341), // &Vdashl -> ⫦ + new Transition (9343, 9344), // &Vee -> ⋁ + new Transition (9346, 9347), // &vee -> ∨ + new Transition (9350, 9351), // &veebar -> ⊻ + new Transition (9353, 9354), // &veeeq -> ≚ + new Transition (9358, 9359), // &vellip -> ⋮ + new Transition (9363, 9364), // &Verbar -> ‖ + new Transition (9368, 9369), // &verbar -> | + new Transition (9370, 9371), // &Vert -> ‖ + new Transition (9372, 9373), // &vert -> | + new Transition (9380, 9381), // &VerticalBar -> ∣ + new Transition (9385, 9386), // &VerticalLine -> | + new Transition (9395, 9396), // &VerticalSeparator -> ❘ + new Transition (9401, 9402), // &VerticalTilde -> ≀ + new Transition (9412, 9413), // &VeryThinSpace ->   + new Transition (9415, 9416), // &Vfr -> 𝔙 + new Transition (9418, 9419), // &vfr -> 𝔳 + new Transition (9423, 9424), // &vltri -> ⊲ + new Transition (9428, 9429), // &vnsub -> ⊂⃒ + new Transition (9430, 9431), // &vnsup -> ⊃⃒ + new Transition (9434, 9435), // &Vopf -> 𝕍 + new Transition (9438, 9439), // &vopf -> 𝕧 + new Transition (9443, 9444), // &vprop -> ∝ + new Transition (9448, 9449), // &vrtri -> ⊳ + new Transition (9452, 9453), // &Vscr -> 𝒱 + new Transition (9456, 9457), // &vscr -> 𝓋 + new Transition (9461, 9462), // &vsubnE -> ⫋︀ + new Transition (9463, 9464), // &vsubne -> ⊊︀ + new Transition (9467, 9468), // &vsupnE -> ⫌︀ + new Transition (9469, 9470), // &vsupne -> ⊋︀ + new Transition (9475, 9476), // &Vvdash -> ⊪ + new Transition (9482, 9483), // &vzigzag -> ⦚ + new Transition (9488, 9489), // &Wcirc -> Ŵ + new Transition (9494, 9495), // &wcirc -> ŵ + new Transition (9500, 9501), // &wedbar -> ⩟ + new Transition (9505, 9506), // &Wedge -> ⋀ + new Transition (9508, 9509), // &wedge -> ∧ + new Transition (9510, 9511), // &wedgeq -> ≙ + new Transition (9515, 9516), // &weierp -> ℘ + new Transition (9518, 9519), // &Wfr -> 𝔚 + new Transition (9521, 9522), // &wfr -> 𝔴 + new Transition (9525, 9526), // &Wopf -> 𝕎 + new Transition (9529, 9530), // &wopf -> 𝕨 + new Transition (9531, 9532), // &wp -> ℘ + new Transition (9533, 9534), // &wr -> ≀ + new Transition (9538, 9539), // &wreath -> ≀ + new Transition (9542, 9543), // &Wscr -> 𝒲 + new Transition (9546, 9547), // &wscr -> 𝓌 + new Transition (9551, 9552), // &xcap -> ⋂ + new Transition (9555, 9556), // &xcirc -> ◯ + new Transition (9558, 9559), // &xcup -> ⋃ + new Transition (9563, 9564), // &xdtri -> ▽ + new Transition (9567, 9568), // &Xfr -> 𝔛 + new Transition (9570, 9571), // &xfr -> 𝔵 + new Transition (9575, 9576), // &xhArr -> ⟺ + new Transition (9579, 9580), // &xharr -> ⟷ + new Transition (9581, 9582), // &Xi -> Ξ + new Transition (9583, 9584), // &xi -> ξ + new Transition (9588, 9589), // &xlArr -> ⟸ + new Transition (9592, 9593), // &xlarr -> ⟵ + new Transition (9596, 9597), // &xmap -> ⟼ + new Transition (9600, 9601), // &xnis -> ⋻ + new Transition (9605, 9606), // &xodot -> ⨀ + new Transition (9609, 9610), // &Xopf -> 𝕏 + new Transition (9612, 9613), // &xopf -> 𝕩 + new Transition (9616, 9617), // &xoplus -> ⨁ + new Transition (9621, 9622), // &xotime -> ⨂ + new Transition (9626, 9627), // &xrArr -> ⟹ + new Transition (9630, 9631), // &xrarr -> ⟶ + new Transition (9634, 9635), // &Xscr -> 𝒳 + new Transition (9638, 9639), // &xscr -> 𝓍 + new Transition (9643, 9644), // &xsqcup -> ⨆ + new Transition (9649, 9650), // &xuplus -> ⨄ + new Transition (9653, 9654), // &xutri -> △ + new Transition (9657, 9658), // &xvee -> ⋁ + new Transition (9663, 9664), // &xwedge -> ⋀ + new Transition (9670, 9671), // Ý -> Ý + new Transition (9677, 9678), // ý -> ý + new Transition (9681, 9682), // &YAcy -> Я + new Transition (9683, 9684), // &yacy -> я + new Transition (9688, 9689), // &Ycirc -> Ŷ + new Transition (9693, 9694), // &ycirc -> ŷ + new Transition (9695, 9696), // &Ycy -> Ы + new Transition (9697, 9698), // &ycy -> ы + new Transition (9700, 9701), // ¥ -> ¥ + new Transition (9703, 9704), // &Yfr -> 𝔜 + new Transition (9706, 9707), // &yfr -> 𝔶 + new Transition (9710, 9711), // &YIcy -> Ї + new Transition (9714, 9715), // &yicy -> ї + new Transition (9718, 9719), // &Yopf -> 𝕐 + new Transition (9722, 9723), // &yopf -> 𝕪 + new Transition (9726, 9727), // &Yscr -> 𝒴 + new Transition (9730, 9731), // &yscr -> 𝓎 + new Transition (9734, 9735), // &YUcy -> Ю + new Transition (9738, 9739), // &yucy -> ю + new Transition (9742, 9743), // &Yuml -> Ÿ + new Transition (9745, 9746), // ÿ -> ÿ + new Transition (9752, 9753), // &Zacute -> Ź + new Transition (9759, 9760), // &zacute -> ź + new Transition (9765, 9766), // &Zcaron -> Ž + new Transition (9771, 9772), // &zcaron -> ž + new Transition (9773, 9774), // &Zcy -> З + new Transition (9775, 9776), // &zcy -> з + new Transition (9779, 9780), // &Zdot -> Ż + new Transition (9783, 9784), // &zdot -> ż + new Transition (9789, 9790), // &zeetrf -> ℨ + new Transition (9803, 9804), // &ZeroWidthSpace -> ​ + new Transition (9806, 9807), // &Zeta -> Ζ + new Transition (9809, 9810), // &zeta -> ζ + new Transition (9812, 9813), // &Zfr -> ℨ + new Transition (9815, 9816), // &zfr -> 𝔷 + new Transition (9819, 9820), // &ZHcy -> Ж + new Transition (9823, 9824), // &zhcy -> ж + new Transition (9830, 9831), // &zigrarr -> ⇝ + new Transition (9834, 9835), // &Zopf -> ℤ + new Transition (9838, 9839), // &zopf -> 𝕫 + new Transition (9842, 9843), // &Zscr -> 𝒵 + new Transition (9846, 9847), // &zscr -> 𝓏 + new Transition (9849, 9850), // &zwj -> ‍ + new Transition (9852, 9853) // &zwnj -> ‌ + }; + TransitionTable_A = new Transition[59] { + new Transition (0, 1), // & -> &A + new Transition (1432, 1447), // &d -> &dA + new Transition (1566, 1567), // &Diacritical -> &DiacriticalA + new Transition (1580, 1581), // &DiacriticalDouble -> &DiacriticalDoubleA + new Transition (1769, 1770), // &DoubleDown -> &DoubleDownA + new Transition (1779, 1780), // &DoubleLeft -> &DoubleLeftA + new Transition (1790, 1791), // &DoubleLeftRight -> &DoubleLeftRightA + new Transition (1807, 1808), // &DoubleLongLeft -> &DoubleLongLeftA + new Transition (1818, 1819), // &DoubleLongLeftRight -> &DoubleLongLeftRightA + new Transition (1829, 1830), // &DoubleLongRight -> &DoubleLongRightA + new Transition (1840, 1841), // &DoubleRight -> &DoubleRightA + new Transition (1852, 1853), // &DoubleUp -> &DoubleUpA + new Transition (1862, 1863), // &DoubleUpDown -> &DoubleUpDownA + new Transition (1882, 1883), // &Down -> &DownA + new Transition (1908, 1909), // &DownArrowUp -> &DownArrowUpA + new Transition (2015, 2017), // &DownTee -> &DownTeeA + new Transition (2616, 2617), // &For -> &ForA + new Transition (3014, 3035), // &H -> &HA + new Transition (3020, 3046), // &h -> &hA + new Transition (3692, 3693), // &l -> &lA + new Transition (3900, 3901), // &Left -> &LeftA + new Transition (3941, 3942), // &LeftArrowRight -> &LeftArrowRightA + new Transition (4034, 4035), // &LeftRight -> &LeftRightA + new Transition (4094, 4096), // &LeftTee -> &LeftTeeA + new Transition (4440, 4441), // &LongLeft -> &LongLeftA + new Transition (4473, 4474), // &LongLeftRight -> &LongLeftRightA + new Transition (4513, 4514), // &LongRight -> &LongRightA + new Transition (4594, 4595), // &LowerLeft -> &LowerLeftA + new Transition (4605, 4606), // &LowerRight -> &LowerRightA + new Transition (5064, 5071), // &ne -> &neA + new Transition (5227, 5228), // &nh -> &nhA + new Transition (5256, 5257), // &nl -> &nlA + new Transition (5855, 5856), // &nr -> &nrA + new Transition (6084, 6085), // &nvl -> &nvlA + new Transition (6097, 6098), // &nvr -> &nvrA + new Transition (6111, 6117), // &nw -> &nwA + new Transition (6876, 6877), // &r -> &rA + new Transition (7174, 7175), // &Right -> &RightA + new Transition (7216, 7217), // &RightArrowLeft -> &RightArrowLeftA + new Transition (7339, 7341), // &RightTee -> &RightTeeA + new Transition (7703, 7709), // &se -> &seA + new Transition (7779, 7780), // &ShortDown -> &ShortDownA + new Transition (7789, 7790), // &ShortLeft -> &ShortLeftA + new Transition (7816, 7817), // &ShortRight -> &ShortRightA + new Transition (7824, 7825), // &ShortUp -> &ShortUpA + new Transition (8375, 8381), // &sw -> &swA + new Transition (8623, 8624), // &TR -> &TRA + new Transition (8775, 8785), // &u -> &uA + new Transition (8970, 8971), // &Up -> &UpA + new Transition (8997, 8998), // &UpArrowDown -> &UpArrowDownA + new Transition (9007, 9008), // &UpDown -> &UpDownA + new Transition (9074, 9075), // &UpperLeft -> &UpperLeftA + new Transition (9085, 9086), // &UpperRight -> &UpperRightA + new Transition (9110, 9112), // &UpTee -> &UpTeeA + new Transition (9201, 9243), // &v -> &vA + new Transition (9572, 9573), // &xh -> &xhA + new Transition (9585, 9586), // &xl -> &xlA + new Transition (9623, 9624), // &xr -> &xrA + new Transition (9665, 9679) // &Y -> &YA + }; + TransitionTable_B = new Transition[34] { + new Transition (0, 331), // & -> &B + new Transition (1876, 1877), // &DoubleVertical -> &DoubleVerticalB + new Transition (1882, 1915), // &Down -> &DownB + new Transition (1887, 1903), // &DownArrow -> &DownArrowB + new Transition (1981, 1983), // &DownLeftVector -> &DownLeftVectorB + new Transition (2007, 2009), // &DownRightVector -> &DownRightVectorB + new Transition (3692, 3807), // &l -> &lB + new Transition (3905, 3906), // &LeftAngle -> &LeftAngleB + new Transition (3917, 3933), // &LeftArrow -> &LeftArrowB + new Transition (3966, 3967), // &LeftDouble -> &LeftDoubleB + new Transition (3992, 3994), // &LeftDownVector -> &LeftDownVectorB + new Transition (4126, 4128), // &LeftTriangle -> &LeftTriangleB + new Transition (4166, 4168), // &LeftUpVector -> &LeftUpVectorB + new Transition (4177, 4179), // &LeftVector -> &LeftVectorB + new Transition (5347, 5348), // &No -> &NoB + new Transition (5354, 5355), // &Non -> &NonB + new Transition (5409, 5410), // &NotDoubleVertical -> &NotDoubleVerticalB + new Transition (5539, 5541), // &NotLeftTriangle -> &NotLeftTriangleB + new Transition (5682, 5684), // &NotRightTriangle -> &NotRightTriangleB + new Transition (5816, 5817), // &NotVertical -> &NotVerticalB + new Transition (6437, 6438), // &Over -> &OverB + new Transition (6876, 6991), // &r -> &rB + new Transition (6886, 6986), // &R -> &RB + new Transition (7179, 7180), // &RightAngle -> &RightAngleB + new Transition (7191, 7209), // &RightArrow -> &RightArrowB + new Transition (7241, 7242), // &RightDouble -> &RightDoubleB + new Transition (7267, 7269), // &RightDownVector -> &RightDownVectorB + new Transition (7371, 7373), // &RightTriangle -> &RightTriangleB + new Transition (7411, 7413), // &RightUpVector -> &RightUpVectorB + new Transition (7422, 7424), // &RightVector -> &RightVectorB + new Transition (8919, 8920), // &Under -> &UnderB + new Transition (8975, 8990), // &UpArrow -> &UpArrowB + new Transition (9201, 9308), // &v -> &vB + new Transition (9377, 9378) // &Vertical -> &VerticalB + }; + TransitionTable_C = new Transition[15] { + new Transition (0, 789), // & -> &C + new Transition (1075, 1076), // &Clockwise -> &ClockwiseC + new Transition (1093, 1094), // &Close -> &CloseC + new Transition (1230, 1231), // &Counter -> &CounterC + new Transition (1239, 1240), // &CounterClockwise -> &CounterClockwiseC + new Transition (1316, 1326), // &Cup -> &CupC + new Transition (1747, 1748), // &Double -> &DoubleC + new Transition (3450, 3451), // &Invisible -> &InvisibleC + new Transition (3900, 3953), // &Left -> &LeftC + new Transition (5376, 5380), // &Not -> &NotC + new Transition (5391, 5392), // &NotCup -> &NotCupC + new Transition (6308, 6309), // &Open -> &OpenC + new Transition (7174, 7228), // &Right -> &RightC + new Transition (7756, 7757), // &SH -> &SHC + new Transition (7886, 7887) // &Small -> &SmallC + }; + TransitionTable_D = new Transition[43] { + new Transition (0, 1425), // & -> &D + new Transition (613, 618), // &box -> &boxD + new Transition (636, 640), // &boxH -> &boxHD + new Transition (638, 644), // &boxh -> &boxhD + new Transition (831, 832), // &Capital -> &CapitalD + new Transition (843, 844), // &CapitalDifferential -> &CapitalDifferentialD + new Transition (939, 940), // &Center -> &CenterD + new Transition (1023, 1024), // &Circle -> &CircleD + new Transition (1098, 1099), // &CloseCurly -> &CloseCurlyD + new Transition (1425, 1490), // &D -> &DD + new Transition (1566, 1573), // &Diacritical -> &DiacriticalD + new Transition (1630, 1631), // &Differential -> &DifferentialD + new Transition (1692, 1696), // &Dot -> &DotD + new Transition (1747, 1764), // &Double -> &DoubleD + new Transition (1852, 1859), // &DoubleUp -> &DoubleUpD + new Transition (2115, 2157), // &e -> &eD + new Transition (2157, 2158), // &eD -> &eDD + new Transition (2175, 2176), // &ef -> &efD + new Transition (2397, 2399), // &equiv -> &equivD + new Transition (2399, 2400), // &equivD -> &equivDD + new Transition (2409, 2414), // &er -> &erD + new Transition (3036, 3037), // &HAR -> &HARD + new Transition (3209, 3210), // &Hump -> &HumpD + new Transition (3900, 3961), // &Left -> &LeftD + new Transition (4139, 4140), // &LeftUp -> &LeftUpD + new Transition (4767, 4825), // &m -> &mD + new Transition (4825, 4826), // &mD -> &mDD + new Transition (5376, 5396), // &Not -> &NotD + new Transition (5496, 5497), // &NotHump -> &NotHumpD + new Transition (6043, 6058), // &nv -> &nvD + new Transition (6047, 6048), // &nV -> &nVD + new Transition (6313, 6314), // &OpenCurly -> &OpenCurlyD + new Transition (6488, 6489), // &Partial -> &PartialD + new Transition (7174, 7236), // &Right -> &RightD + new Transition (7384, 7385), // &RightUp -> &RightUpD + new Transition (7592, 7593), // &Rule -> &RuleD + new Transition (7775, 7776), // &Short -> &ShortD + new Transition (8624, 8625), // &TRA -> &TRAD + new Transition (8680, 8681), // &Triple -> &TripleD + new Transition (8970, 9004), // &Up -> &UpD + new Transition (8975, 8994), // &UpArrow -> &UpArrowD + new Transition (9201, 9330), // &v -> &vD + new Transition (9303, 9320) // &V -> &VD + }; + TransitionTable_E = new Transition[81] { + new Transition (0, 2108), // & -> &E + new Transition (1, 50), // &A -> &AE + new Transition (27, 31), // &ac -> &acE + new Transition (199, 206), // &ap -> &apE + new Transition (775, 777), // &bump -> &bumpE + new Transition (979, 1049), // &cir -> &cirE + new Transition (1692, 1707), // &Dot -> &DotE + new Transition (2490, 2491), // &Exponential -> &ExponentialE + new Transition (2701, 2763), // &g -> &gE + new Transition (2824, 2828), // &gl -> &glE + new Transition (2832, 2841), // &gn -> &gnE + new Transition (2871, 2872), // &Greater -> &GreaterE + new Transition (2886, 2887), // &GreaterFull -> &GreaterFullE + new Transition (2910, 2911), // &GreaterSlant -> &GreaterSlantE + new Transition (3011, 3012), // &gvn -> &gvnE + new Transition (3209, 3219), // &Hump -> &HumpE + new Transition (3236, 3269), // &I -> &IE + new Transition (3512, 3518), // &isin -> &isinE + new Transition (3692, 3894), // &l -> &lE + new Transition (4126, 4132), // &LeftTriangle -> &LeftTriangleE + new Transition (4239, 4240), // &Less -> &LessE + new Transition (4256, 4257), // &LessFull -> &LessFullE + new Transition (4288, 4289), // &LessSlant -> &LessSlantE + new Transition (4317, 4319), // &lg -> &lgE + new Transition (4401, 4410), // &ln -> &lnE + new Transition (4764, 4765), // &lvn -> &lvnE + new Transition (4986, 4988), // &nap -> &napE + new Transition (5195, 5196), // &ng -> &ngE + new Transition (5256, 5268), // &nl -> &nlE + new Transition (5376, 5414), // &Not -> &NotE + new Transition (5445, 5447), // &NotGreater -> &NotGreaterE + new Transition (5456, 5457), // &NotGreaterFull -> &NotGreaterFullE + new Transition (5480, 5481), // &NotGreaterSlant -> &NotGreaterSlantE + new Transition (5496, 5506), // &NotHump -> &NotHumpE + new Transition (5513, 5519), // ¬in -> ¬inE + new Transition (5539, 5545), // &NotLeftTriangle -> &NotLeftTriangleE + new Transition (5552, 5554), // &NotLess -> &NotLessE + new Transition (5577, 5578), // &NotLessSlant -> &NotLessSlantE + new Transition (5637, 5639), // &NotPrecedes -> &NotPrecedesE + new Transition (5649, 5650), // &NotPrecedesSlant -> &NotPrecedesSlantE + new Transition (5662, 5663), // &NotReverse -> &NotReverseE + new Transition (5682, 5688), // &NotRightTriangle -> &NotRightTriangleE + new Transition (5705, 5707), // &NotSquareSubset -> &NotSquareSubsetE + new Transition (5718, 5720), // &NotSquareSuperset -> &NotSquareSupersetE + new Transition (5730, 5732), // &NotSubset -> &NotSubsetE + new Transition (5743, 5745), // &NotSucceeds -> &NotSucceedsE + new Transition (5755, 5756), // &NotSucceedsSlant -> &NotSucceedsSlantE + new Transition (5773, 5775), // &NotSuperset -> &NotSupersetE + new Transition (5785, 5787), // &NotTilde -> &NotTildeE + new Transition (5796, 5797), // &NotTildeFull -> &NotTildeFullE + new Transition (5952, 5954), // &nsub -> &nsubE + new Transition (5973, 5975), // &nsup -> &nsupE + new Transition (6131, 6190), // &O -> &OE + new Transition (6642, 6651), // &pr -> &prE + new Transition (6677, 6679), // &Precedes -> &PrecedesE + new Transition (6689, 6690), // &PrecedesSlant -> &PrecedesSlantE + new Transition (6735, 6739), // &prn -> &prnE + new Transition (6886, 7092), // &R -> &RE + new Transition (7101, 7102), // &Reverse -> &ReverseE + new Transition (7122, 7123), // &ReverseUp -> &ReverseUpE + new Transition (7371, 7377), // &RightTriangle -> &RightTriangleE + new Transition (7631, 7649), // &sc -> &scE + new Transition (7670, 7674), // &scn -> &scnE + new Transition (7857, 7859), // &simg -> &simgE + new Transition (7861, 7863), // &siml -> &simlE + new Transition (8037, 8039), // &SquareSubset -> &SquareSubsetE + new Transition (8050, 8052), // &SquareSuperset -> &SquareSupersetE + new Transition (8131, 8137), // &sub -> &subE + new Transition (8150, 8151), // &subn -> &subnE + new Transition (8167, 8178), // &Subset -> &SubsetE + new Transition (8221, 8223), // &Succeeds -> &SucceedsE + new Transition (8233, 8234), // &SucceedsSlant -> &SucceedsSlantE + new Transition (8284, 8300), // &sup -> &supE + new Transition (8312, 8314), // &Superset -> &SupersetE + new Transition (8338, 8339), // &supn -> &supnE + new Transition (8547, 8554), // &Tilde -> &TildeE + new Transition (8563, 8564), // &TildeFull -> &TildeFullE + new Transition (8625, 8626), // &TRAD -> &TRADE + new Transition (8970, 9034), // &Up -> &UpE + new Transition (9460, 9461), // &vsubn -> &vsubnE + new Transition (9466, 9467) // &vsupn -> &vsupnE + }; + TransitionTable_F = new Transition[10] { + new Transition (0, 2517), // & -> &F + new Transition (219, 220), // &Apply -> &ApplyF + new Transition (2871, 2883), // &Greater -> &GreaterF + new Transition (3900, 3998), // &Left -> &LeftF + new Transition (4239, 4253), // &Less -> &LessF + new Transition (5445, 5453), // &NotGreater -> &NotGreaterF + new Transition (5785, 5793), // &NotTilde -> &NotTildeF + new Transition (7174, 7273), // &Right -> &RightF + new Transition (7930, 7931), // &SO -> &SOF + new Transition (8547, 8560) // &Tilde -> &TildeF + }; + TransitionTable_G = new Transition[15] { + new Transition (0, 2708), // & -> &G + new Transition (1566, 1587), // &Diacritical -> &DiacriticalG + new Transition (2287, 2288), // &EN -> &ENG + new Transition (2871, 2893), // &Greater -> &GreaterG + new Transition (4239, 4263), // &Less -> &LessG + new Transition (4244, 4245), // &LessEqual -> &LessEqualG + new Transition (4965, 5212), // &n -> &nG + new Transition (5151, 5152), // &Nested -> &NestedG + new Transition (5158, 5159), // &NestedGreater -> &NestedGreaterG + new Transition (5376, 5439), // &Not -> &NotG + new Transition (5445, 5463), // &NotGreater -> &NotGreaterG + new Transition (5552, 5560), // &NotLess -> &NotLessG + new Transition (5595, 5596), // &NotNested -> &NotNestedG + new Transition (5602, 5603), // &NotNestedGreater -> &NotNestedGreaterG + new Transition (7092, 7093) // &RE -> ® + }; + TransitionTable_H = new Transition[20] { + new Transition (0, 3014), // & -> &H + new Transition (613, 636), // &box -> &boxH + new Transition (691, 695), // &boxV -> &boxVH + new Transition (693, 699), // &boxv -> &boxvH + new Transition (789, 956), // &C -> &CH + new Transition (1432, 1546), // &d -> &dH + new Transition (2442, 2443), // &ET -> Ð + new Transition (3213, 3214), // &HumpDown -> &HumpDownH + new Transition (3618, 3660), // &K -> &KH + new Transition (3692, 4321), // &l -> &lH + new Transition (5376, 5493), // &Not -> &NotH + new Transition (5500, 5501), // &NotHumpDown -> &NotHumpDownH + new Transition (6043, 6073), // &nv -> &nvH + new Transition (6876, 7151), // &r -> &rH + new Transition (7610, 7756), // &S -> &SH + new Transition (7757, 7758), // &SHC -> &SHCH + new Transition (8400, 8535), // &T -> &TH + new Transition (8713, 8719), // &TS -> &TSH + new Transition (8775, 8872), // &u -> &uH + new Transition (9747, 9817) // &Z -> &ZH + }; + TransitionTable_I = new Transition[9] { + new Transition (0, 3236), // & -> &I + new Transition (1082, 1083), // &ClockwiseContour -> &ClockwiseContourI + new Transition (1190, 1191), // &Contour -> &ContourI + new Transition (1246, 1247), // &CounterClockwiseContour -> &CounterClockwiseContourI + new Transition (1754, 1755), // &DoubleContour -> &DoubleContourI + new Transition (3349, 3350), // &Imaginary -> &ImaginaryI + new Transition (7503, 7504), // &Round -> &RoundI + new Transition (8013, 8019), // &Square -> &SquareI + new Transition (9665, 9708) // &Y -> &YI + }; + TransitionTable_J = new Transition[7] { + new Transition (0, 3555), // & -> &J + new Transition (1425, 1661), // &D -> &DJ + new Transition (2708, 2816), // &G -> &GJ + new Transition (3236, 3320), // &I -> &IJ + new Transition (3618, 3668), // &K -> &KJ + new Transition (3698, 4338), // &L -> &LJ + new Transition (4971, 5248) // &N -> &NJ + }; + TransitionTable_K = new Transition[1] { + new Transition (0, 3618) // & -> &K + }; + TransitionTable_L = new Transition[29] { + new Transition (0, 3698), // & -> &L + new Transition (618, 619), // &boxD -> &boxDL + new Transition (623, 624), // &boxd -> &boxdL + new Transition (673, 674), // &boxU -> &boxUL + new Transition (678, 679), // &boxu -> &boxuL + new Transition (691, 703), // &boxV -> &boxVL + new Transition (693, 707), // &boxv -> &boxvL + new Transition (1747, 1776), // &Double -> &DoubleL + new Transition (1803, 1804), // &DoubleLong -> &DoubleLongL + new Transition (1882, 1950), // &Down -> &DownL + new Transition (2871, 2901), // &Greater -> &GreaterL + new Transition (2876, 2878), // &GreaterEqual -> &GreaterEqualL + new Transition (3178, 3179), // &Horizontal -> &HorizontalL + new Transition (4239, 4275), // &Less -> &LessL + new Transition (4436, 4437), // &Long -> &LongL + new Transition (4590, 4591), // &Lower -> &LowerL + new Transition (4965, 5272), // &n -> &nL + new Transition (5151, 5167), // &Nested -> &NestedL + new Transition (5170, 5171), // &NestedLess -> &NestedLessL + new Transition (5176, 5177), // &New -> &NewL + new Transition (5376, 5528), // &Not -> &NotL + new Transition (5445, 5471), // &NotGreater -> &NotGreaterL + new Transition (5552, 5568), // &NotLess -> &NotLessL + new Transition (5595, 5611), // &NotNested -> &NotNestedL + new Transition (5614, 5615), // &NotNestedLess -> &NotNestedLessL + new Transition (7191, 7213), // &RightArrow -> &RightArrowL + new Transition (7775, 7786), // &Short -> &ShortL + new Transition (9070, 9071), // &Upper -> &UpperL + new Transition (9377, 9382) // &Vertical -> &VerticalL + }; + TransitionTable_M = new Transition[5] { + new Transition (0, 4781), // & -> &M + new Transition (1, 111), // &A -> &AM + new Transition (1023, 1032), // &Circle -> &CircleM + new Transition (5090, 5091), // &Negative -> &NegativeM + new Transition (6589, 6590) // &Plus -> &PlusM + }; + TransitionTable_N = new Transition[5] { + new Transition (0, 4971), // & -> &N + new Transition (301, 587), // &b -> &bN + new Transition (2108, 2287), // &E -> &EN + new Transition (5376, 5590), // &Not -> &NotN + new Transition (8537, 8538) // &THOR -> Þ + }; + TransitionTable_O = new Transition[6] { + new Transition (0, 6131), // & -> &O + new Transition (789, 1217), // &C -> &CO + new Transition (3236, 3463), // &I -> &IO + new Transition (6869, 6870), // &QU -> &QUO + new Transition (7610, 7930), // &S -> &SO + new Transition (8535, 8536) // &TH -> &THO + }; + TransitionTable_P = new Transition[11] { + new Transition (0, 6482), // & -> &P + new Transition (111, 112), // &AM -> & + new Transition (1023, 1038), // &Circle -> &CircleP + new Transition (1217, 1218), // &CO -> &COP + new Transition (2954, 2955), // >l -> >lP + new Transition (4731, 4738), // <r -> <rP + new Transition (4903, 4904), // &Minus -> &MinusP + new Transition (5376, 5630), // &Not -> &NotP + new Transition (6437, 6451), // &Over -> &OverP + new Transition (8919, 8933), // &Under -> &UnderP + new Transition (8947, 8949) // &Union -> &UnionP + }; + TransitionTable_Q = new Transition[5] { + new Transition (0, 6813), // & -> &Q + new Transition (1098, 1111), // &CloseCurly -> &CloseCurlyQ + new Transition (1104, 1105), // &CloseCurlyDouble -> &CloseCurlyDoubleQ + new Transition (6313, 6326), // &OpenCurly -> &OpenCurlyQ + new Transition (6319, 6320) // &OpenCurlyDouble -> &OpenCurlyDoubleQ + }; + TransitionTable_R = new Transition[26] { + new Transition (0, 6886), // & -> &R + new Transition (618, 628), // &boxD -> &boxDR + new Transition (623, 632), // &boxd -> &boxdR + new Transition (673, 683), // &boxU -> &boxUR + new Transition (678, 687), // &boxu -> &boxuR + new Transition (691, 711), // &boxV -> &boxVR + new Transition (693, 715), // &boxv -> &boxvR + new Transition (1004, 1028), // &circled -> &circledR + new Transition (1747, 1836), // &Double -> &DoubleR + new Transition (1779, 1786), // &DoubleLeft -> &DoubleLeftR + new Transition (1803, 1825), // &DoubleLong -> &DoubleLongR + new Transition (1807, 1814), // &DoubleLongLeft -> &DoubleLongLeftR + new Transition (1882, 1987), // &Down -> &DownR + new Transition (1953, 1954), // &DownLeft -> &DownLeftR + new Transition (3035, 3036), // &HA -> &HAR + new Transition (3900, 4030), // &Left -> &LeftR + new Transition (3917, 3937), // &LeftArrow -> &LeftArrowR + new Transition (4436, 4509), // &Long -> &LongR + new Transition (4440, 4469), // &LongLeft -> &LongLeftR + new Transition (4590, 4601), // &Lower -> &LowerR + new Transition (4965, 5868), // &n -> &nR + new Transition (5376, 5656), // &Not -> &NotR + new Transition (7775, 7812), // &Short -> &ShortR + new Transition (8400, 8623), // &T -> &TR + new Transition (8536, 8537), // &THO -> &THOR + new Transition (9070, 9081) // &Upper -> &UpperR + }; + TransitionTable_S = new Transition[36] { + new Transition (0, 7610), // & -> &S + new Transition (1004, 1030), // &circled -> &circledS + new Transition (1425, 2048), // &D -> &DS + new Transition (2248, 2249), // &Empty -> &EmptyS + new Transition (2253, 2254), // &EmptySmall -> &EmptySmallS + new Transition (2266, 2267), // &EmptyVery -> &EmptyVeryS + new Transition (2271, 2272), // &EmptyVerySmall -> &EmptyVerySmallS + new Transition (2558, 2559), // &Filled -> &FilledS + new Transition (2563, 2564), // &FilledSmall -> &FilledSmallS + new Transition (2574, 2575), // &FilledVery -> &FilledVeryS + new Transition (2579, 2580), // &FilledVerySmall -> &FilledVerySmallS + new Transition (2871, 2906), // &Greater -> &GreaterS + new Transition (3105, 3106), // &Hilbert -> &HilbertS + new Transition (4239, 4284), // &Less -> &LessS + new Transition (4847, 4848), // &Medium -> &MediumS + new Transition (5096, 5097), // &NegativeMedium -> &NegativeMediumS + new Transition (5107, 5108), // &NegativeThick -> &NegativeThickS + new Transition (5114, 5115), // &NegativeThin -> &NegativeThinS + new Transition (5128, 5129), // &NegativeVeryThin -> &NegativeVeryThinS + new Transition (5362, 5363), // &NonBreaking -> &NonBreakingS + new Transition (5376, 5694), // &Not -> &NotS + new Transition (5445, 5476), // &NotGreater -> &NotGreaterS + new Transition (5552, 5573), // &NotLess -> &NotLessS + new Transition (5637, 5645), // &NotPrecedes -> &NotPrecedesS + new Transition (5699, 5700), // &NotSquare -> &NotSquareS + new Transition (5743, 5751), // &NotSucceeds -> &NotSucceedsS + new Transition (6138, 6376), // &o -> &oS + new Transition (6677, 6685), // &Precedes -> &PrecedesS + new Transition (8013, 8032), // &Square -> &SquareS + new Transition (8221, 8229), // &Succeeds -> &SucceedsS + new Transition (8400, 8713), // &T -> &TS + new Transition (8509, 8510), // &Thick -> &ThickS + new Transition (8520, 8521), // &Thin -> &ThinS + new Transition (9377, 9387), // &Vertical -> &VerticalS + new Transition (9407, 9408), // &VeryThin -> &VeryThinS + new Transition (9798, 9799) // &ZeroWidth -> &ZeroWidthS + }; + TransitionTable_T = new Transition[40] { + new Transition (0, 8400), // & -> &T + new Transition (1023, 1043), // &Circle -> &CircleT + new Transition (1566, 1593), // &Diacritical -> &DiacriticalT + new Transition (1779, 1797), // &DoubleLeft -> &DoubleLeftT + new Transition (1840, 1847), // &DoubleRight -> &DoubleRightT + new Transition (1882, 2013), // &Down -> &DownT + new Transition (1953, 1966), // &DownLeft -> &DownLeftT + new Transition (1991, 1992), // &DownRight -> &DownRightT + new Transition (2108, 2442), // &E -> &ET + new Transition (2370, 2377), // &Equal -> &EqualT + new Transition (2708, 2938), // &G -> > + new Transition (2871, 2917), // &Greater -> &GreaterT + new Transition (3450, 3457), // &Invisible -> &InvisibleT + new Transition (3698, 4694), // &L -> < + new Transition (3900, 4092), // &Left -> &LeftT + new Transition (3976, 3977), // &LeftDown -> &LeftDownT + new Transition (4139, 4151), // &LeftUp -> &LeftUpT + new Transition (4239, 4295), // &Less -> &LessT + new Transition (5090, 5103), // &Negative -> &NegativeT + new Transition (5124, 5125), // &NegativeVery -> &NegativeVeryT + new Transition (5376, 5781), // &Not -> &NotT + new Transition (5425, 5427), // &NotEqual -> &NotEqualT + new Transition (5445, 5487), // &NotGreater -> &NotGreaterT + new Transition (5531, 5532), // &NotLeft -> &NotLeftT + new Transition (5552, 5584), // &NotLess -> &NotLessT + new Transition (5674, 5675), // &NotRight -> &NotRightT + new Transition (5743, 5762), // &NotSucceeds -> &NotSucceedsT + new Transition (5785, 5803), // &NotTilde -> &NotTildeT + new Transition (6677, 6696), // &Precedes -> &PrecedesT + new Transition (6870, 6871), // &QUO -> " + new Transition (7174, 7337), // &Right -> &RightT + new Transition (7251, 7252), // &RightDown -> &RightDownT + new Transition (7384, 7396), // &RightUp -> &RightUpT + new Transition (7931, 7932), // &SOF -> &SOFT + new Transition (8221, 8240), // &Succeeds -> &SucceedsT + new Transition (8269, 8270), // &Such -> &SuchT + new Transition (8547, 8570), // &Tilde -> &TildeT + new Transition (8970, 9108), // &Up -> &UpT + new Transition (9377, 9397), // &Vertical -> &VerticalT + new Transition (9403, 9404) // &Very -> &VeryT + }; + TransitionTable_U = new Transition[13] { + new Transition (0, 8768), // & -> &U + new Transition (613, 673), // &box -> &boxU + new Transition (636, 648), // &boxH -> &boxHU + new Transition (638, 652), // &boxh -> &boxhU + new Transition (1747, 1851), // &Double -> &DoubleU + new Transition (1887, 1907), // &DownArrow -> &DownArrowU + new Transition (3900, 4138), // &Left -> &LeftU + new Transition (6813, 6869), // &Q -> &QU + new Transition (7101, 7121), // &Reverse -> &ReverseU + new Transition (7174, 7383), // &Right -> &RightU + new Transition (7775, 7823), // &Short -> &ShortU + new Transition (8013, 8058), // &Square -> &SquareU + new Transition (9665, 9732) // &Y -> &YU + }; + TransitionTable_V = new Transition[29] { + new Transition (0, 9303), // & -> &V + new Transition (613, 691), // &box -> &boxV + new Transition (1747, 1869), // &Double -> &DoubleV + new Transition (1953, 1976), // &DownLeft -> &DownLeftV + new Transition (1958, 1959), // &DownLeftRight -> &DownLeftRightV + new Transition (1968, 1969), // &DownLeftTee -> &DownLeftTeeV + new Transition (1991, 2002), // &DownRight -> &DownRightV + new Transition (1994, 1995), // &DownRightTee -> &DownRightTeeV + new Transition (2248, 2263), // &Empty -> &EmptyV + new Transition (2558, 2571), // &Filled -> &FilledV + new Transition (3900, 4172), // &Left -> &LeftV + new Transition (3976, 3987), // &LeftDown -> &LeftDownV + new Transition (3979, 3980), // &LeftDownTee -> &LeftDownTeeV + new Transition (4034, 4085), // &LeftRight -> &LeftRightV + new Transition (4094, 4102), // &LeftTee -> &LeftTeeV + new Transition (4139, 4161), // &LeftUp -> &LeftUpV + new Transition (4143, 4144), // &LeftUpDown -> &LeftUpDownV + new Transition (4153, 4154), // &LeftUpTee -> &LeftUpTeeV + new Transition (4965, 6047), // &n -> &nV + new Transition (5090, 5121), // &Negative -> &NegativeV + new Transition (5376, 5809), // &Not -> &NotV + new Transition (5401, 5402), // &NotDouble -> &NotDoubleV + new Transition (7174, 7417), // &Right -> &RightV + new Transition (7251, 7262), // &RightDown -> &RightDownV + new Transition (7254, 7255), // &RightDownTee -> &RightDownTeeV + new Transition (7339, 7347), // &RightTee -> &RightTeeV + new Transition (7384, 7406), // &RightUp -> &RightUpV + new Transition (7388, 7389), // &RightUpDown -> &RightUpDownV + new Transition (7398, 7399) // &RightUpTee -> &RightUpTeeV + }; + TransitionTable_W = new Transition[2] { + new Transition (0, 9484), // & -> &W + new Transition (9793, 9794) // &Zero -> &ZeroW + }; + TransitionTable_X = new Transition[1] { + new Transition (0, 9565) // & -> &X + }; + TransitionTable_Y = new Transition[2] { + new Transition (0, 9665), // & -> &Y + new Transition (1218, 1219) // &COP -> © + }; + TransitionTable_Z = new Transition[2] { + new Transition (0, 9747), // & -> &Z + new Transition (1425, 2093) // &D -> &DZ + }; + TransitionTable_a = new Transition[555] { + new Transition (0, 8), // & -> &a + new Transition (1, 2), // &A -> &Aa + new Transition (8, 9), // &a -> &aa + new Transition (68, 69), // &Agr -> &Agra + new Transition (74, 75), // &agr -> &agra + new Transition (91, 92), // &Alph -> &Alpha + new Transition (95, 96), // &alph -> &alpha + new Transition (98, 99), // &Am -> &Ama + new Transition (103, 104), // &am -> &ama + new Transition (120, 122), // &and -> &anda + new Transition (145, 147), // &angmsd -> &angmsda + new Transition (147, 148), // &angmsda -> &angmsdaa + new Transition (178, 179), // &angz -> &angza + new Transition (199, 201), // &ap -> &apa + new Transition (301, 302), // &b -> &ba + new Transition (331, 332), // &B -> &Ba + new Transition (336, 337), // &Backsl -> &Backsla + new Transition (385, 386), // &bec -> &beca + new Transition (391, 392), // &Bec -> &Beca + new Transition (423, 424), // &Bet -> &Beta + new Transition (426, 427), // &bet -> &beta + new Transition (444, 445), // &bigc -> &bigca + new Transition (477, 478), // &bigst -> &bigsta + new Transition (483, 484), // &bigtri -> &bigtria + new Transition (513, 514), // &bk -> &bka + new Transition (519, 520), // &bl -> &bla + new Transition (533, 534), // &blacksqu -> &blacksqua + new Transition (540, 541), // &blacktri -> &blacktria + new Transition (736, 737), // &brvb -> &brvba + new Transition (789, 790), // &C -> &Ca + new Transition (796, 797), // &c -> &ca + new Transition (805, 807), // &cap -> &capa + new Transition (817, 818), // &capc -> &capca + new Transition (829, 830), // &Capit -> &Capita + new Transition (841, 842), // &CapitalDifferenti -> &CapitalDifferentia + new Transition (861, 862), // &cc -> &cca + new Transition (866, 867), // &Cc -> &Cca + new Transition (924, 925), // &Cedill -> &Cedilla + new Transition (968, 969), // &checkm -> &checkma + new Transition (987, 988), // &circle -> &circlea + new Transition (1004, 1005), // &circled -> &circleda + new Transition (1014, 1015), // &circledd -> &circledda + new Transition (1088, 1089), // &ClockwiseContourIntegr -> &ClockwiseContourIntegra + new Transition (1143, 1144), // &comm -> &comma + new Transition (1196, 1197), // &ContourIntegr -> &ContourIntegra + new Transition (1252, 1253), // &CounterClockwiseContourIntegr -> &CounterClockwiseContourIntegra + new Transition (1256, 1257), // &cr -> &cra + new Transition (1293, 1294), // &cud -> &cuda + new Transition (1308, 1309), // &cul -> &cula + new Transition (1322, 1323), // &cupbrc -> &cupbrca + new Transition (1326, 1327), // &CupC -> &CupCa + new Transition (1330, 1331), // &cupc -> &cupca + new Transition (1346, 1347), // &cur -> &cura + new Transition (1382, 1383), // &curve -> &curvea + new Transition (1425, 1426), // &D -> &Da + new Transition (1432, 1433), // &d -> &da + new Transition (1464, 1465), // &dbk -> &dbka + new Transition (1470, 1471), // &dbl -> &dbla + new Transition (1474, 1475), // &Dc -> &Dca + new Transition (1480, 1481), // &dc -> &dca + new Transition (1492, 1494), // &dd -> &dda + new Transition (1505, 1506), // &DDotr -> &DDotra + new Transition (1522, 1523), // &Delt -> &Delta + new Transition (1526, 1527), // &delt -> &delta + new Transition (1546, 1547), // &dH -> &dHa + new Transition (1550, 1551), // &dh -> &dha + new Transition (1557, 1558), // &Di -> &Dia + new Transition (1564, 1565), // &Diacritic -> &Diacritica + new Transition (1588, 1589), // &DiacriticalGr -> &DiacriticalGra + new Transition (1599, 1600), // &di -> &dia + new Transition (1628, 1629), // &Differenti -> &Differentia + new Transition (1633, 1634), // &dig -> &diga + new Transition (1636, 1637), // &digamm -> &digamma + new Transition (1681, 1682), // &doll -> &dolla + new Transition (1709, 1710), // &DotEqu -> &DotEqua + new Transition (1726, 1727), // &dotsqu -> &dotsqua + new Transition (1735, 1736), // &doubleb -> &doubleba + new Transition (1760, 1761), // &DoubleContourIntegr -> &DoubleContourIntegra + new Transition (1874, 1875), // &DoubleVertic -> &DoubleVertica + new Transition (1877, 1878), // &DoubleVerticalB -> &DoubleVerticalBa + new Transition (1882, 1889), // &Down -> &Downa + new Transition (1896, 1897), // &down -> &downa + new Transition (1903, 1904), // &DownArrowB -> &DownArrowBa + new Transition (1924, 1925), // &downdown -> &downdowna + new Transition (1932, 1933), // &downh -> &downha + new Transition (1983, 1984), // &DownLeftVectorB -> &DownLeftVectorBa + new Transition (2009, 2010), // &DownRightVectorB -> &DownRightVectorBa + new Transition (2025, 2026), // &drbk -> &drbka + new Transition (2077, 2078), // &du -> &dua + new Transition (2082, 2083), // &duh -> &duha + new Transition (2086, 2087), // &dw -> &dwa + new Transition (2103, 2104), // &dzigr -> &dzigra + new Transition (2108, 2109), // &E -> &Ea + new Transition (2115, 2116), // &e -> &ea + new Transition (2127, 2128), // &Ec -> &Eca + new Transition (2133, 2134), // &ec -> &eca + new Transition (2188, 2189), // &Egr -> &Egra + new Transition (2193, 2194), // &egr -> &egra + new Transition (2228, 2229), // &Em -> &Ema + new Transition (2233, 2234), // &em -> &ema + new Transition (2250, 2251), // &EmptySm -> &EmptySma + new Transition (2256, 2257), // &EmptySmallSqu -> &EmptySmallSqua + new Transition (2268, 2269), // &EmptyVerySm -> &EmptyVerySma + new Transition (2274, 2275), // &EmptyVerySmallSqu -> &EmptyVerySmallSqua + new Transition (2312, 2313), // &ep -> &epa + new Transition (2354, 2355), // &eqsl -> &eqsla + new Transition (2368, 2369), // &Equ -> &Equa + new Transition (2372, 2373), // &equ -> &equa + new Transition (2403, 2404), // &eqvp -> &eqvpa + new Transition (2409, 2410), // &er -> &era + new Transition (2436, 2437), // &Et -> &Eta + new Transition (2439, 2440), // &et -> &eta + new Transition (2475, 2476), // &expect -> &expecta + new Transition (2488, 2489), // &Exponenti -> &Exponentia + new Transition (2498, 2499), // &exponenti -> &exponentia + new Transition (2503, 2504), // &f -> &fa + new Transition (2525, 2526), // &fem -> &fema + new Transition (2560, 2561), // &FilledSm -> &FilledSma + new Transition (2566, 2567), // &FilledSmallSqu -> &FilledSmallSqua + new Transition (2576, 2577), // &FilledVerySm -> &FilledVerySma + new Transition (2582, 2583), // &FilledVerySmallSqu -> &FilledVerySmallSqua + new Transition (2592, 2593), // &fl -> &fla + new Transition (2621, 2622), // &for -> &fora + new Transition (2639, 2640), // &fp -> &fpa + new Transition (2647, 2648), // &fr -> &fra + new Transition (2701, 2702), // &g -> &ga + new Transition (2708, 2709), // &G -> &Ga + new Transition (2711, 2712), // &Gamm -> &Gamma + new Transition (2715, 2716), // &gamm -> &gamma + new Transition (2776, 2777), // &geqsl -> &geqsla + new Transition (2824, 2826), // &gl -> &gla + new Transition (2832, 2833), // &gn -> &gna + new Transition (2861, 2862), // &gr -> &gra + new Transition (2867, 2868), // &Gre -> &Grea + new Transition (2874, 2875), // &GreaterEqu -> &GreaterEqua + new Transition (2889, 2890), // &GreaterFullEqu -> &GreaterFullEqua + new Transition (2895, 2896), // &GreaterGre -> &GreaterGrea + new Transition (2907, 2908), // &GreaterSl -> &GreaterSla + new Transition (2913, 2914), // &GreaterSlantEqu -> &GreaterSlantEqua + new Transition (2955, 2956), // >lP -> >lPa + new Transition (2965, 2966), // >r -> >ra + new Transition (3014, 3015), // &H -> &Ha + new Transition (3020, 3021), // &h -> &ha + new Transition (3060, 3061), // &hb -> &hba + new Transition (3074, 3075), // &he -> &hea + new Transition (3107, 3108), // &HilbertSp -> &HilbertSpa + new Transition (3114, 3115), // &hkse -> &hksea + new Transition (3120, 3121), // &hksw -> &hkswa + new Transition (3126, 3127), // &ho -> &hoa + new Transition (3141, 3142), // &hookleft -> &hooklefta + new Transition (3152, 3153), // &hookright -> &hookrighta + new Transition (3167, 3168), // &horb -> &horba + new Transition (3176, 3177), // &Horizont -> &Horizonta + new Transition (3192, 3193), // &hsl -> &hsla + new Transition (3221, 3222), // &HumpEqu -> &HumpEqua + new Transition (3236, 3237), // &I -> &Ia + new Transition (3243, 3244), // &i -> &ia + new Transition (3290, 3291), // &Igr -> &Igra + new Transition (3296, 3297), // &igr -> &igra + new Transition (3317, 3318), // &iiot -> &iiota + new Transition (3330, 3332), // &Im -> &Ima + new Transition (3336, 3337), // &im -> &ima + new Transition (3346, 3347), // &Imagin -> &Imagina + new Transition (3357, 3358), // &imagp -> &imagpa + new Transition (3380, 3381), // &inc -> &inca + new Transition (3403, 3404), // &intc -> &intca + new Transition (3415, 3416), // &Integr -> &Integra + new Transition (3420, 3421), // &interc -> &interca + new Transition (3433, 3434), // &intl -> &intla + new Transition (3454, 3455), // &InvisibleComm -> &InvisibleComma + new Transition (3486, 3487), // &Iot -> &Iota + new Transition (3489, 3490), // &iot -> &iota + new Transition (3577, 3578), // &jm -> &jma + new Transition (3618, 3619), // &K -> &Ka + new Transition (3621, 3622), // &Kapp -> &Kappa + new Transition (3624, 3625), // &k -> &ka + new Transition (3627, 3628), // &kapp -> &kappa + new Transition (3692, 3705), // &l -> &la + new Transition (3693, 3694), // &lA -> &lAa + new Transition (3698, 3699), // &L -> &La + new Transition (3719, 3720), // &lagr -> &lagra + new Transition (3725, 3726), // &Lambd -> &Lambda + new Transition (3730, 3731), // &lambd -> &lambda + new Transition (3747, 3748), // &Lapl -> &Lapla + new Transition (3792, 3799), // &lat -> &lata + new Transition (3794, 3795), // &lAt -> &lAta + new Transition (3807, 3808), // &lB -> &lBa + new Transition (3812, 3813), // &lb -> &lba + new Transition (3821, 3822), // &lbr -> &lbra + new Transition (3837, 3838), // &Lc -> &Lca + new Transition (3843, 3844), // &lc -> &lca + new Transition (3870, 3871), // &ldc -> &ldca + new Transition (3881, 3882), // &ldrdh -> &ldrdha + new Transition (3887, 3888), // &ldrush -> &ldrusha + new Transition (3900, 3919), // &Left -> &Lefta + new Transition (3907, 3908), // &LeftAngleBr -> &LeftAngleBra + new Transition (3926, 3927), // &left -> &lefta + new Transition (3933, 3934), // &LeftArrowB -> &LeftArrowBa + new Transition (3948, 3949), // &leftarrowt -> &leftarrowta + new Transition (3968, 3969), // &LeftDoubleBr -> &LeftDoubleBra + new Transition (3994, 3995), // &LeftDownVectorB -> &LeftDownVectorBa + new Transition (4004, 4005), // &lefth -> &leftha + new Transition (4022, 4023), // &leftleft -> &leftlefta + new Transition (4045, 4046), // &Leftright -> &Leftrighta + new Transition (4056, 4057), // &leftright -> &leftrighta + new Transition (4065, 4066), // &leftrighth -> &leftrightha + new Transition (4078, 4079), // &leftrightsquig -> &leftrightsquiga + new Transition (4121, 4122), // &LeftTri -> &LeftTria + new Transition (4128, 4129), // &LeftTriangleB -> &LeftTriangleBa + new Transition (4134, 4135), // &LeftTriangleEqu -> &LeftTriangleEqua + new Transition (4168, 4169), // &LeftUpVectorB -> &LeftUpVectorBa + new Transition (4179, 4180), // &LeftVectorB -> &LeftVectorBa + new Transition (4192, 4193), // &leqsl -> &leqsla + new Transition (4215, 4216), // &less -> &lessa + new Transition (4242, 4243), // &LessEqu -> &LessEqua + new Transition (4247, 4248), // &LessEqualGre -> &LessEqualGrea + new Transition (4259, 4260), // &LessFullEqu -> &LessFullEqua + new Transition (4265, 4266), // &LessGre -> &LessGrea + new Transition (4285, 4286), // &LessSl -> &LessSla + new Transition (4291, 4292), // &LessSlantEqu -> &LessSlantEqua + new Transition (4321, 4322), // &lH -> &lHa + new Transition (4325, 4326), // &lh -> &lha + new Transition (4348, 4350), // &ll -> &lla + new Transition (4363, 4364), // &Lleft -> &Llefta + new Transition (4370, 4371), // &llh -> &llha + new Transition (4394, 4396), // &lmoust -> &lmousta + new Transition (4401, 4402), // &ln -> &lna + new Transition (4422, 4423), // &lo -> &loa + new Transition (4450, 4451), // &Longleft -> &Longlefta + new Transition (4462, 4463), // &longleft -> &longlefta + new Transition (4484, 4485), // &Longleftright -> &Longleftrighta + new Transition (4495, 4496), // &longleftright -> &longleftrighta + new Transition (4502, 4503), // &longm -> &longma + new Transition (4524, 4525), // &Longright -> &Longrighta + new Transition (4535, 4536), // &longright -> &longrighta + new Transition (4543, 4544), // &loop -> &loopa + new Transition (4560, 4561), // &lop -> &lopa + new Transition (4579, 4580), // &low -> &lowa + new Transition (4584, 4585), // &lowb -> &lowba + new Transition (4621, 4622), // &lp -> &lpa + new Transition (4628, 4629), // &lr -> &lra + new Transition (4640, 4641), // &lrh -> &lrha + new Transition (4652, 4653), // &ls -> &lsa + new Transition (4720, 4721), // <l -> <la + new Transition (4738, 4739), // <rP -> <rPa + new Transition (4746, 4747), // &lurdsh -> &lurdsha + new Transition (4751, 4752), // &luruh -> &luruha + new Transition (4767, 4768), // &m -> &ma + new Transition (4781, 4782), // &M -> &Ma + new Transition (4812, 4813), // &mcomm -> &mcomma + new Transition (4820, 4821), // &md -> &mda + new Transition (4830, 4831), // &me -> &mea + new Transition (4836, 4837), // &measured -> &measureda + new Transition (4849, 4850), // &MediumSp -> &MediumSpa + new Transition (4876, 4878), // &mid -> &mida + new Transition (4957, 4958), // &multim -> &multima + new Transition (4961, 4962), // &mum -> &muma + new Transition (4965, 4966), // &n -> &na + new Transition (4968, 4969), // &nabl -> &nabla + new Transition (4971, 4972), // &N -> &Na + new Transition (5003, 5005), // &natur -> &natura + new Transition (5020, 5021), // &nc -> &nca + new Transition (5024, 5025), // &Nc -> &Nca + new Transition (5059, 5060), // &nd -> &nda + new Transition (5064, 5066), // &ne -> &nea + new Transition (5085, 5086), // &Neg -> &Nega + new Transition (5098, 5099), // &NegativeMediumSp -> &NegativeMediumSpa + new Transition (5109, 5110), // &NegativeThickSp -> &NegativeThickSpa + new Transition (5116, 5117), // &NegativeThinSp -> &NegativeThinSpa + new Transition (5130, 5131), // &NegativeVeryThinSp -> &NegativeVeryThinSpa + new Transition (5141, 5142), // &nese -> &nesea + new Transition (5154, 5155), // &NestedGre -> &NestedGrea + new Transition (5161, 5162), // &NestedGreaterGre -> &NestedGreaterGrea + new Transition (5205, 5206), // &ngeqsl -> &ngeqsla + new Transition (5227, 5232), // &nh -> &nha + new Transition (5236, 5237), // &nhp -> &nhpa + new Transition (5256, 5261), // &nl -> &nla + new Transition (5275, 5276), // &nLeft -> &nLefta + new Transition (5283, 5284), // &nleft -> &nlefta + new Transition (5294, 5295), // &nLeftright -> &nLeftrighta + new Transition (5305, 5306), // &nleftright -> &nleftrighta + new Transition (5317, 5318), // &nleqsl -> &nleqsla + new Transition (5350, 5351), // &NoBre -> &NoBrea + new Transition (5357, 5358), // &NonBre -> &NonBrea + new Transition (5364, 5365), // &NonBreakingSp -> &NonBreakingSpa + new Transition (5392, 5393), // &NotCupC -> &NotCupCa + new Transition (5407, 5408), // &NotDoubleVertic -> &NotDoubleVertica + new Transition (5410, 5411), // &NotDoubleVerticalB -> &NotDoubleVerticalBa + new Transition (5423, 5424), // &NotEqu -> &NotEqua + new Transition (5441, 5442), // &NotGre -> &NotGrea + new Transition (5449, 5450), // &NotGreaterEqu -> &NotGreaterEqua + new Transition (5459, 5460), // &NotGreaterFullEqu -> &NotGreaterFullEqua + new Transition (5465, 5466), // &NotGreaterGre -> &NotGreaterGrea + new Transition (5477, 5478), // &NotGreaterSl -> &NotGreaterSla + new Transition (5483, 5484), // &NotGreaterSlantEqu -> &NotGreaterSlantEqua + new Transition (5508, 5509), // &NotHumpEqu -> &NotHumpEqua + new Transition (5521, 5522), // ¬inv -> ¬inva + new Transition (5534, 5535), // &NotLeftTri -> &NotLeftTria + new Transition (5541, 5542), // &NotLeftTriangleB -> &NotLeftTriangleBa + new Transition (5547, 5548), // &NotLeftTriangleEqu -> &NotLeftTriangleEqua + new Transition (5556, 5557), // &NotLessEqu -> &NotLessEqua + new Transition (5562, 5563), // &NotLessGre -> &NotLessGrea + new Transition (5574, 5575), // &NotLessSl -> &NotLessSla + new Transition (5580, 5581), // &NotLessSlantEqu -> &NotLessSlantEqua + new Transition (5598, 5599), // &NotNestedGre -> &NotNestedGrea + new Transition (5605, 5606), // &NotNestedGreaterGre -> &NotNestedGreaterGrea + new Transition (5623, 5624), // ¬niv -> ¬niva + new Transition (5641, 5642), // &NotPrecedesEqu -> &NotPrecedesEqua + new Transition (5646, 5647), // &NotPrecedesSl -> &NotPrecedesSla + new Transition (5652, 5653), // &NotPrecedesSlantEqu -> &NotPrecedesSlantEqua + new Transition (5677, 5678), // &NotRightTri -> &NotRightTria + new Transition (5684, 5685), // &NotRightTriangleB -> &NotRightTriangleBa + new Transition (5690, 5691), // &NotRightTriangleEqu -> &NotRightTriangleEqua + new Transition (5696, 5697), // &NotSqu -> &NotSqua + new Transition (5709, 5710), // &NotSquareSubsetEqu -> &NotSquareSubsetEqua + new Transition (5722, 5723), // &NotSquareSupersetEqu -> &NotSquareSupersetEqua + new Transition (5734, 5735), // &NotSubsetEqu -> &NotSubsetEqua + new Transition (5747, 5748), // &NotSucceedsEqu -> &NotSucceedsEqua + new Transition (5752, 5753), // &NotSucceedsSl -> &NotSucceedsSla + new Transition (5758, 5759), // &NotSucceedsSlantEqu -> &NotSucceedsSlantEqua + new Transition (5777, 5778), // &NotSupersetEqu -> &NotSupersetEqua + new Transition (5789, 5790), // &NotTildeEqu -> &NotTildeEqua + new Transition (5799, 5800), // &NotTildeFullEqu -> &NotTildeFullEqua + new Transition (5814, 5815), // &NotVertic -> &NotVertica + new Transition (5817, 5818), // &NotVerticalB -> &NotVerticalBa + new Transition (5821, 5822), // &np -> &npa + new Transition (5823, 5825), // &npar -> &npara + new Transition (5855, 5860), // &nr -> &nra + new Transition (5872, 5873), // &nRight -> &nRighta + new Transition (5882, 5883), // &nright -> &nrighta + new Transition (5918, 5919), // &nshortp -> &nshortpa + new Transition (5920, 5921), // &nshortpar -> &nshortpara + new Transition (5938, 5939), // &nsp -> &nspa + new Transition (6007, 6008), // &ntri -> &ntria + new Transition (6043, 6044), // &nv -> &nva + new Transition (6048, 6049), // &nVD -> &nVDa + new Transition (6053, 6054), // &nVd -> &nVda + new Transition (6058, 6059), // &nvD -> &nvDa + new Transition (6063, 6064), // &nvd -> &nvda + new Transition (6073, 6074), // &nvH -> &nvHa + new Transition (6111, 6112), // &nw -> &nwa + new Transition (6127, 6128), // &nwne -> &nwnea + new Transition (6131, 6132), // &O -> &Oa + new Transition (6138, 6139), // &o -> &oa + new Transition (6163, 6164), // &od -> &oda + new Transition (6170, 6171), // &Odbl -> &Odbla + new Transition (6175, 6176), // &odbl -> &odbla + new Transition (6215, 6216), // &Ogr -> &Ogra + new Transition (6220, 6221), // &ogr -> &ogra + new Transition (6228, 6229), // &ohb -> &ohba + new Transition (6238, 6239), // &ol -> &ola + new Transition (6258, 6259), // &Om -> &Oma + new Transition (6263, 6264), // &om -> &oma + new Transition (6269, 6270), // &Omeg -> &Omega + new Transition (6273, 6274), // &omeg -> &omega + new Transition (6302, 6303), // &op -> &opa + new Transition (6342, 6344), // &or -> &ora + new Transition (6386, 6387), // &Osl -> &Osla + new Transition (6391, 6392), // &osl -> &osla + new Transition (6417, 6419), // &otimes -> &otimesa + new Transition (6431, 6432), // &ovb -> &ovba + new Transition (6438, 6439), // &OverB -> &OverBa + new Transition (6442, 6443), // &OverBr -> &OverBra + new Transition (6451, 6452), // &OverP -> &OverPa + new Transition (6463, 6464), // &p -> &pa + new Transition (6465, 6467), // &par -> ¶ + new Transition (6482, 6483), // &P -> &Pa + new Transition (6486, 6487), // &Parti -> &Partia + new Transition (6533, 6534), // &phmm -> &phmma + new Transition (6555, 6556), // &pl -> &pla + new Transition (6567, 6569), // &plus -> &plusa + new Transition (6612, 6613), // &Poinc -> &Poinca + new Transition (6617, 6618), // &Poincarepl -> &Poincarepla + new Transition (6642, 6644), // &pr -> &pra + new Transition (6655, 6657), // &prec -> &preca + new Transition (6681, 6682), // &PrecedesEqu -> &PrecedesEqua + new Transition (6686, 6687), // &PrecedesSl -> &PrecedesSla + new Transition (6692, 6693), // &PrecedesSlantEqu -> &PrecedesSlantEqua + new Transition (6705, 6706), // &precn -> &precna + new Transition (6735, 6736), // &prn -> &prna + new Transition (6754, 6755), // &prof -> &profa + new Transition (6756, 6757), // &profal -> &profala + new Transition (6778, 6780), // &Proportion -> &Proportiona + new Transition (6847, 6848), // &qu -> &qua + new Transition (6876, 6882), // &r -> &ra + new Transition (6877, 6878), // &rA -> &rAa + new Transition (6886, 6887), // &R -> &Ra + new Transition (6932, 6934), // &rarr -> &rarra + new Transition (6968, 6969), // &rAt -> &rAta + new Transition (6973, 6974), // &rat -> &rata + new Transition (6981, 6982), // &ration -> &rationa + new Transition (6986, 6987), // &RB -> &RBa + new Transition (6991, 6992), // &rB -> &rBa + new Transition (6996, 6997), // &rb -> &rba + new Transition (7005, 7006), // &rbr -> &rbra + new Transition (7021, 7022), // &Rc -> &Rca + new Transition (7027, 7028), // &rc -> &rca + new Transition (7054, 7055), // &rdc -> &rdca + new Transition (7059, 7060), // &rdldh -> &rdldha + new Transition (7074, 7075), // &re -> &rea + new Transition (7082, 7083), // &realp -> &realpa + new Transition (7151, 7152), // &rH -> &rHa + new Transition (7155, 7156), // &rh -> &rha + new Transition (7174, 7193), // &Right -> &Righta + new Transition (7181, 7182), // &RightAngleBr -> &RightAngleBra + new Transition (7202, 7203), // &right -> &righta + new Transition (7209, 7210), // &RightArrowB -> &RightArrowBa + new Transition (7223, 7224), // &rightarrowt -> &rightarrowta + new Transition (7243, 7244), // &RightDoubleBr -> &RightDoubleBra + new Transition (7269, 7270), // &RightDownVectorB -> &RightDownVectorBa + new Transition (7279, 7280), // &righth -> &rightha + new Transition (7297, 7298), // &rightleft -> &rightlefta + new Transition (7305, 7306), // &rightlefth -> &rightleftha + new Transition (7318, 7319), // &rightright -> &rightrighta + new Transition (7330, 7331), // &rightsquig -> &rightsquiga + new Transition (7366, 7367), // &RightTri -> &RightTria + new Transition (7373, 7374), // &RightTriangleB -> &RightTriangleBa + new Transition (7379, 7380), // &RightTriangleEqu -> &RightTriangleEqua + new Transition (7413, 7414), // &RightUpVectorB -> &RightUpVectorBa + new Transition (7424, 7425), // &RightVectorB -> &RightVectorBa + new Transition (7442, 7443), // &rl -> &rla + new Transition (7447, 7448), // &rlh -> &rlha + new Transition (7457, 7459), // &rmoust -> &rmousta + new Transition (7469, 7470), // &ro -> &roa + new Transition (7481, 7482), // &rop -> &ropa + new Transition (7512, 7513), // &rp -> &rpa + new Transition (7526, 7527), // &rr -> &rra + new Transition (7535, 7536), // &Rright -> &Rrighta + new Transition (7542, 7543), // &rs -> &rsa + new Transition (7595, 7596), // &RuleDel -> &RuleDela + new Transition (7604, 7605), // &ruluh -> &ruluha + new Transition (7610, 7611), // &S -> &Sa + new Transition (7617, 7618), // &s -> &sa + new Transition (7629, 7636), // &Sc -> &Sca + new Transition (7631, 7633), // &sc -> &sca + new Transition (7670, 7671), // &scn -> &scna + new Transition (7703, 7704), // &se -> &sea + new Transition (7725, 7726), // &sesw -> &seswa + new Transition (7751, 7752), // &sh -> &sha + new Transition (7803, 7804), // &shortp -> &shortpa + new Transition (7805, 7806), // &shortpar -> &shortpara + new Transition (7835, 7836), // &Sigm -> &Sigma + new Transition (7840, 7841), // &sigm -> &sigma + new Transition (7873, 7874), // &simr -> &simra + new Transition (7878, 7879), // &sl -> &sla + new Transition (7883, 7884), // &Sm -> &Sma + new Transition (7894, 7895), // &sm -> &sma + new Transition (7912, 7913), // &smep -> &smepa + new Transition (7944, 7946), // &solb -> &solba + new Transition (7956, 7957), // &sp -> &spa + new Transition (7969, 7970), // &sqc -> &sqca + new Transition (8008, 8015), // &squ -> &squa + new Transition (8010, 8011), // &Squ -> &Squa + new Transition (8041, 8042), // &SquareSubsetEqu -> &SquareSubsetEqua + new Transition (8054, 8055), // &SquareSupersetEqu -> &SquareSupersetEqua + new Transition (8068, 8069), // &sr -> &sra + new Transition (8091, 8092), // &sst -> &ssta + new Transition (8096, 8097), // &St -> &Sta + new Transition (8100, 8101), // &st -> &sta + new Transition (8106, 8107), // &str -> &stra + new Transition (8160, 8161), // &subr -> &subra + new Transition (8180, 8181), // &SubsetEqu -> &SubsetEqua + new Transition (8199, 8201), // &succ -> &succa + new Transition (8225, 8226), // &SucceedsEqu -> &SucceedsEqua + new Transition (8230, 8231), // &SucceedsSl -> &SucceedsSla + new Transition (8236, 8237), // &SucceedsSlantEqu -> &SucceedsSlantEqua + new Transition (8249, 8250), // &succn -> &succna + new Transition (8271, 8272), // &SuchTh -> &SuchTha + new Transition (8316, 8317), // &SupersetEqu -> &SupersetEqua + new Transition (8328, 8329), // &supl -> &supla + new Transition (8375, 8376), // &sw -> &swa + new Transition (8391, 8392), // &swnw -> &swnwa + new Transition (8400, 8401), // &T -> &Ta + new Transition (8404, 8405), // &t -> &ta + new Transition (8419, 8420), // &Tc -> &Tca + new Transition (8425, 8426), // &tc -> &tca + new Transition (8481, 8482), // &Thet -> &Theta + new Transition (8484, 8485), // &thet -> &theta + new Transition (8495, 8496), // &thick -> &thicka + new Transition (8511, 8512), // &ThickSp -> &ThickSpa + new Transition (8522, 8523), // &ThinSp -> &ThinSpa + new Transition (8527, 8528), // &thk -> &thka + new Transition (8556, 8557), // &TildeEqu -> &TildeEqua + new Transition (8566, 8567), // &TildeFullEqu -> &TildeFullEqua + new Transition (8580, 8582), // ×b -> ×ba + new Transition (8591, 8592), // &toe -> &toea + new Transition (8614, 8615), // &tos -> &tosa + new Transition (8628, 8629), // &tr -> &tra + new Transition (8633, 8634), // &tri -> &tria + new Transition (8744, 8745), // &twohe -> &twohea + new Transition (8750, 8751), // &twoheadleft -> &twoheadlefta + new Transition (8761, 8762), // &twoheadright -> &twoheadrighta + new Transition (8768, 8769), // &U -> &Ua + new Transition (8775, 8776), // &u -> &ua + new Transition (8829, 8830), // &ud -> &uda + new Transition (8836, 8837), // &Udbl -> &Udbla + new Transition (8841, 8842), // &udbl -> &udbla + new Transition (8845, 8846), // &udh -> &udha + new Transition (8861, 8862), // &Ugr -> &Ugra + new Transition (8867, 8868), // &ugr -> &ugra + new Transition (8872, 8873), // &uH -> &uHa + new Transition (8876, 8877), // &uh -> &uha + new Transition (8904, 8905), // &Um -> &Uma + new Transition (8909, 8910), // &um -> &uma + new Transition (8920, 8921), // &UnderB -> &UnderBa + new Transition (8924, 8925), // &UnderBr -> &UnderBra + new Transition (8933, 8934), // &UnderP -> &UnderPa + new Transition (8970, 8977), // &Up -> &Upa + new Transition (8983, 8984), // &up -> &upa + new Transition (8990, 8991), // &UpArrowB -> &UpArrowBa + new Transition (9017, 9018), // &Updown -> &Updowna + new Transition (9027, 9028), // &updown -> &updowna + new Transition (9046, 9047), // &uph -> &upha + new Transition (9119, 9120), // &upup -> &upupa + new Transition (9182, 9183), // &uu -> &uua + new Transition (9194, 9195), // &uw -> &uwa + new Transition (9201, 9202), // &v -> &va + new Transition (9217, 9218), // &vark -> &varka + new Transition (9220, 9221), // &varkapp -> &varkappa + new Transition (9255, 9256), // &varsigm -> &varsigma + new Transition (9282, 9283), // &varthet -> &vartheta + new Transition (9286, 9287), // &vartri -> &vartria + new Transition (9304, 9305), // &Vb -> &Vba + new Transition (9308, 9309), // &vB -> &vBa + new Transition (9320, 9321), // &VD -> &VDa + new Transition (9325, 9326), // &Vd -> &Vda + new Transition (9330, 9331), // &vD -> &vDa + new Transition (9335, 9336), // &vd -> &vda + new Transition (9348, 9349), // &veeb -> &veeba + new Transition (9361, 9362), // &Verb -> &Verba + new Transition (9366, 9367), // &verb -> &verba + new Transition (9375, 9376), // &Vertic -> &Vertica + new Transition (9378, 9379), // &VerticalB -> &VerticalBa + new Transition (9389, 9390), // &VerticalSep -> &VerticalSepa + new Transition (9391, 9392), // &VerticalSepar -> &VerticalSepara + new Transition (9409, 9410), // &VeryThinSp -> &VeryThinSpa + new Transition (9472, 9473), // &Vvd -> &Vvda + new Transition (9480, 9481), // &vzigz -> &vzigza + new Transition (9498, 9499), // &wedb -> &wedba + new Transition (9535, 9536), // &wre -> &wrea + new Transition (9549, 9550), // &xc -> &xca + new Transition (9572, 9577), // &xh -> &xha + new Transition (9585, 9590), // &xl -> &xla + new Transition (9594, 9595), // &xm -> &xma + new Transition (9623, 9628), // &xr -> &xra + new Transition (9665, 9666), // &Y -> &Ya + new Transition (9672, 9673), // &y -> &ya + new Transition (9747, 9748), // &Z -> &Za + new Transition (9754, 9755), // &z -> &za + new Transition (9761, 9762), // &Zc -> &Zca + new Transition (9767, 9768), // &zc -> &zca + new Transition (9800, 9801), // &ZeroWidthSp -> &ZeroWidthSpa + new Transition (9805, 9806), // &Zet -> &Zeta + new Transition (9808, 9809), // &zet -> &zeta + new Transition (9827, 9828) // &zigr -> &zigra + }; + TransitionTable_b = new Transition[96] { + new Transition (0, 301), // & -> &b + new Transition (1, 15), // &A -> &Ab + new Transition (8, 21), // &a -> &ab + new Transition (147, 150), // &angmsda -> &angmsdab + new Transition (167, 168), // &angrtv -> &angrtvb + new Transition (301, 360), // &b -> &bb + new Transition (364, 365), // &bbrkt -> &bbrktb + new Transition (613, 614), // &box -> &boxb + new Transition (735, 736), // &brv -> &brvb + new Transition (758, 760), // &bsol -> &bsolb + new Transition (764, 765), // &bsolhsu -> &bsolhsub + new Transition (805, 811), // &cap -> &capb + new Transition (1101, 1102), // &CloseCurlyDou -> &CloseCurlyDoub + new Transition (1118, 1119), // &clu -> &club + new Transition (1278, 1279), // &csu -> &csub + new Transition (1318, 1320), // &cup -> &cupb + new Transition (1432, 1463), // &d -> &db + new Transition (1577, 1578), // &DiacriticalDou -> &DiacriticalDoub + new Transition (1731, 1732), // &dou -> &doub + new Transition (1734, 1735), // &double -> &doubleb + new Transition (1744, 1745), // &Dou -> &Doub + new Transition (2023, 2024), // &dr -> &drb + new Transition (2389, 2390), // &Equili -> &Equilib + new Transition (2701, 2730), // &g -> &gb + new Transition (2708, 2724), // &G -> &Gb + new Transition (3020, 3060), // &h -> &hb + new Transition (3101, 3102), // &Hil -> &Hilb + new Transition (3166, 3167), // &hor -> &horb + new Transition (3225, 3226), // &hy -> &hyb + new Transition (3447, 3448), // &Invisi -> &Invisib + new Transition (3692, 3812), // &l -> &lb + new Transition (3723, 3724), // &Lam -> &Lamb + new Transition (3728, 3729), // &lam -> &lamb + new Transition (3766, 3768), // &larr -> &larrb + new Transition (3812, 3817), // &lb -> &lbb + new Transition (3862, 3863), // &lcu -> &lcub + new Transition (3963, 3964), // &LeftDou -> &LeftDoub + new Transition (4325, 4334), // &lh -> &lhb + new Transition (4422, 4430), // &lo -> &lob + new Transition (4579, 4584), // &low -> &lowb + new Transition (4676, 4677), // &lsq -> &lsqb + new Transition (4892, 4894), // &minus -> &minusb + new Transition (4965, 5010), // &n -> &nb + new Transition (4966, 4967), // &na -> &nab + new Transition (5398, 5399), // &NotDou -> &NotDoub + new Transition (5521, 5524), // ¬inv -> ¬invb + new Transition (5623, 5626), // ¬niv -> ¬nivb + new Transition (5701, 5702), // &NotSquareSu -> &NotSquareSub + new Transition (5726, 5727), // &NotSu -> &NotSub + new Transition (5944, 5945), // &nsqsu -> &nsqsub + new Transition (5951, 5952), // &nsu -> &nsub + new Transition (6163, 6174), // &od -> &odb + new Transition (6168, 6169), // &Od -> &Odb + new Transition (6227, 6228), // &oh -> &ohb + new Transition (6316, 6317), // &OpenCurlyDou -> &OpenCurlyDoub + new Transition (6430, 6431), // &ov -> &ovb + new Transition (6567, 6574), // &plus -> &plusb + new Transition (6876, 6996), // &r -> &rb + new Transition (6932, 6937), // &rarr -> &rarrb + new Transition (6996, 7001), // &rb -> &rbb + new Transition (7046, 7047), // &rcu -> &rcub + new Transition (7114, 7115), // &ReverseEquili -> &ReverseEquilib + new Transition (7128, 7129), // &ReverseUpEquili -> &ReverseUpEquilib + new Transition (7238, 7239), // &RightDou -> &RightDoub + new Transition (7469, 7477), // &ro -> &rob + new Transition (7559, 7560), // &rsq -> &rsqb + new Transition (7617, 7624), // &s -> &sb + new Transition (7697, 7699), // &sdot -> &sdotb + new Transition (7942, 7944), // &sol -> &solb + new Transition (7985, 7986), // &sqsu -> &sqsub + new Transition (8033, 8034), // &SquareSu -> &SquareSub + new Transition (8127, 8128), // &Su -> &Sub + new Transition (8130, 8131), // &su -> &sub + new Transition (8193, 8194), // &subsu -> &subsub + new Transition (8297, 8298), // &supdsu -> &supdsub + new Transition (8325, 8326), // &suphsu -> &suphsub + new Transition (8370, 8371), // &supsu -> &supsub + new Transition (8401, 8402), // &Ta -> &Tab + new Transition (8404, 8415), // &t -> &tb + new Transition (8578, 8580), // × -> ×b + new Transition (8594, 8596), // &top -> &topb + new Transition (8690, 8691), // &tris -> &trisb + new Transition (8768, 8797), // &U -> &Ub + new Transition (8775, 8802), // &u -> &ub + new Transition (8829, 8840), // &ud -> &udb + new Transition (8834, 8835), // &Ud -> &Udb + new Transition (8876, 8883), // &uh -> &uhb + new Transition (9039, 9040), // &UpEquili -> &UpEquilib + new Transition (9258, 9259), // &varsu -> &varsub + new Transition (9303, 9304), // &V -> &Vb + new Transition (9346, 9348), // &vee -> &veeb + new Transition (9360, 9361), // &Ver -> &Verb + new Transition (9365, 9366), // &ver -> &verb + new Transition (9427, 9428), // &vnsu -> &vnsub + new Transition (9458, 9459), // &vsu -> &vsub + new Transition (9497, 9498) // &wed -> &wedb + }; + TransitionTable_c = new Transition[377] { + new Transition (0, 796), // & -> &c + new Transition (1, 33), // &A -> &Ac + new Transition (2, 3), // &Aa -> &Aac + new Transition (8, 27), // &a -> &ac + new Transition (9, 10), // &aa -> &aac + new Transition (35, 36), // &Acir ->  + new Transition (39, 40), // &acir -> â + new Transition (99, 100), // &Ama -> &Amac + new Transition (104, 105), // &ama -> &amac + new Transition (147, 152), // &angmsda -> &angmsdac + new Transition (201, 202), // &apa -> &apac + new Transition (222, 223), // &ApplyFun -> &ApplyFunc + new Transition (247, 248), // &As -> &Asc + new Transition (251, 252), // &as -> &asc + new Transition (289, 290), // &aw -> &awc + new Transition (301, 369), // &b -> &bc + new Transition (302, 303), // &ba -> &bac + new Transition (304, 305), // &back -> &backc + new Transition (331, 374), // &B -> &Bc + new Transition (332, 333), // &Ba -> &Bac + new Transition (384, 385), // &be -> &bec + new Transition (390, 391), // &Be -> &Bec + new Transition (443, 444), // &big -> &bigc + new Transition (449, 450), // &bigcir -> &bigcirc + new Transition (472, 473), // &bigsq -> &bigsqc + new Transition (520, 521), // &bla -> &blac + new Transition (575, 576), // &blo -> &bloc + new Transition (740, 741), // &Bs -> &Bsc + new Transition (744, 745), // &bs -> &bsc + new Transition (789, 866), // &C -> &Cc + new Transition (790, 791), // &Ca -> &Cac + new Transition (796, 861), // &c -> &cc + new Transition (797, 798), // &ca -> &cac + new Transition (805, 817), // &cap -> &capc + new Transition (812, 813), // &capbr -> &capbrc + new Transition (887, 888), // &Ccir -> &Ccirc + new Transition (891, 892), // &ccir -> &ccirc + new Transition (956, 957), // &CH -> &CHc + new Transition (960, 961), // &ch -> &chc + new Transition (964, 965), // &che -> &chec + new Transition (979, 981), // &cir -> &circ + new Transition (1004, 1009), // &circled -> &circledc + new Transition (1011, 1012), // &circledcir -> &circledcirc + new Transition (1020, 1021), // &Cir -> &Circ + new Transition (1063, 1064), // &cirs -> &cirsc + new Transition (1069, 1070), // &Clo -> &Cloc + new Transition (1213, 1214), // &Coprodu -> &Coproduc + new Transition (1233, 1234), // &CounterClo -> &CounterCloc + new Transition (1270, 1271), // &Cs -> &Csc + new Transition (1274, 1275), // &cs -> &csc + new Transition (1305, 1306), // &cues -> &cuesc + new Transition (1318, 1330), // &cup -> &cupc + new Transition (1321, 1322), // &cupbr -> &cupbrc + new Transition (1359, 1360), // &curlyeqpre -> &curlyeqprec + new Transition (1363, 1364), // &curlyeqsu -> &curlyeqsuc + new Transition (1364, 1365), // &curlyeqsuc -> &curlyeqsucc + new Transition (1407, 1408), // &cw -> &cwc + new Transition (1420, 1421), // &cyl -> &cylc + new Transition (1425, 1474), // &D -> &Dc + new Transition (1432, 1480), // &d -> &dc + new Transition (1471, 1472), // &dbla -> &dblac + new Transition (1558, 1559), // &Dia -> &Diac + new Transition (1563, 1564), // &Diacriti -> &Diacritic + new Transition (1567, 1568), // &DiacriticalA -> &DiacriticalAc + new Transition (1581, 1582), // &DiacriticalDoubleA -> &DiacriticalDoubleAc + new Transition (1661, 1662), // &DJ -> &DJc + new Transition (1665, 1666), // &dj -> &djc + new Transition (1669, 1670), // &dl -> &dlc + new Transition (1873, 1874), // &DoubleVerti -> &DoubleVertic + new Transition (1960, 1961), // &DownLeftRightVe -> &DownLeftRightVec + new Transition (1970, 1971), // &DownLeftTeeVe -> &DownLeftTeeVec + new Transition (1977, 1978), // &DownLeftVe -> &DownLeftVec + new Transition (1996, 1997), // &DownRightTeeVe -> &DownRightTeeVec + new Transition (2003, 2004), // &DownRightVe -> &DownRightVec + new Transition (2023, 2031), // &dr -> &drc + new Transition (2040, 2041), // &Ds -> &Dsc + new Transition (2044, 2045), // &ds -> &dsc + new Transition (2048, 2049), // &DS -> &DSc + new Transition (2093, 2094), // &DZ -> &DZc + new Transition (2097, 2098), // &dz -> &dzc + new Transition (2108, 2127), // &E -> &Ec + new Transition (2109, 2110), // &Ea -> &Eac + new Transition (2115, 2133), // &e -> &ec + new Transition (2116, 2117), // &ea -> &eac + new Transition (2140, 2146), // &ecir -> ê + new Transition (2143, 2144), // &Ecir -> Ê + new Transition (2229, 2230), // &Ema -> &Emac + new Transition (2234, 2235), // &ema -> &emac + new Transition (2339, 2340), // &eq -> &eqc + new Transition (2342, 2343), // &eqcir -> &eqcirc + new Transition (2418, 2419), // &Es -> &Esc + new Transition (2422, 2423), // &es -> &esc + new Transition (2458, 2459), // &ex -> &exc + new Transition (2473, 2474), // &expe -> &expec + new Transition (2503, 2521), // &f -> &fc + new Transition (2517, 2518), // &F -> &Fc + new Transition (2648, 2649), // &fra -> &frac + new Transition (2693, 2694), // &Fs -> &Fsc + new Transition (2697, 2698), // &fs -> &fsc + new Transition (2701, 2746), // &g -> &gc + new Transition (2702, 2703), // &ga -> &gac + new Transition (2708, 2736), // &G -> &Gc + new Transition (2743, 2744), // &Gcir -> &Gcirc + new Transition (2748, 2749), // &gcir -> &gcirc + new Transition (2781, 2783), // &ges -> &gesc + new Transition (2783, 2784), // &gesc -> &gescc + new Transition (2816, 2817), // &GJ -> &GJc + new Transition (2820, 2821), // &gj -> &gjc + new Transition (2923, 2924), // &Gs -> &Gsc + new Transition (2927, 2928), // &gs -> &gsc + new Transition (2942, 2944), // > -> >c + new Transition (2944, 2945), // >c -> >cc + new Transition (3014, 3064), // &H -> &Hc + new Transition (3015, 3016), // &Ha -> &Hac + new Transition (3020, 3069), // &h -> &hc + new Transition (3037, 3038), // &HARD -> &HARDc + new Transition (3042, 3043), // &hard -> &hardc + new Transition (3050, 3052), // &harr -> &harrc + new Transition (3066, 3067), // &Hcir -> &Hcirc + new Transition (3071, 3072), // &hcir -> &hcirc + new Transition (3089, 3090), // &her -> &herc + new Transition (3108, 3109), // &HilbertSpa -> &HilbertSpac + new Transition (3184, 3185), // &Hs -> &Hsc + new Transition (3188, 3189), // &hs -> &hsc + new Transition (3236, 3252), // &I -> &Ic + new Transition (3237, 3238), // &Ia -> &Iac + new Transition (3243, 3250), // &i -> &ic + new Transition (3244, 3245), // &ia -> &iac + new Transition (3254, 3255), // &Icir -> Î + new Transition (3258, 3259), // &icir -> î + new Transition (3269, 3270), // &IE -> &IEc + new Transition (3273, 3274), // &ie -> &iec + new Transition (3277, 3278), // &iex -> &iexc + new Transition (3332, 3333), // &Ima -> &Imac + new Transition (3337, 3338), // &ima -> &imac + new Transition (3378, 3380), // &in -> &inc + new Transition (3401, 3403), // &int -> &intc + new Transition (3419, 3420), // &inter -> &interc + new Transition (3426, 3427), // &Interse -> &Intersec + new Transition (3463, 3464), // &IO -> &IOc + new Transition (3467, 3468), // &io -> &ioc + new Transition (3503, 3504), // &Is -> &Isc + new Transition (3507, 3508), // &is -> &isc + new Transition (3540, 3541), // &Iuk -> &Iukc + new Transition (3545, 3546), // &iuk -> &iukc + new Transition (3555, 3556), // &J -> &Jc + new Transition (3558, 3559), // &Jcir -> &Jcirc + new Transition (3561, 3562), // &j -> &jc + new Transition (3564, 3565), // &jcir -> &jcirc + new Transition (3590, 3591), // &Js -> &Jsc + new Transition (3594, 3595), // &js -> &jsc + new Transition (3599, 3600), // &Jser -> &Jserc + new Transition (3604, 3605), // &jser -> &jserc + new Transition (3609, 3610), // &Juk -> &Jukc + new Transition (3614, 3615), // &juk -> &jukc + new Transition (3618, 3632), // &K -> &Kc + new Transition (3624, 3638), // &k -> &kc + new Transition (3660, 3661), // &KH -> &KHc + new Transition (3664, 3665), // &kh -> &khc + new Transition (3668, 3669), // &KJ -> &KJc + new Transition (3672, 3673), // &kj -> &kjc + new Transition (3684, 3685), // &Ks -> &Ksc + new Transition (3688, 3689), // &ks -> &ksc + new Transition (3692, 3843), // &l -> &lc + new Transition (3698, 3837), // &L -> &Lc + new Transition (3699, 3700), // &La -> &Lac + new Transition (3705, 3706), // &la -> &lac + new Transition (3748, 3749), // &Lapla -> &Laplac + new Transition (3822, 3823), // &lbra -> &lbrac + new Transition (3869, 3870), // &ld -> &ldc + new Transition (3908, 3909), // &LeftAngleBra -> &LeftAngleBrac + new Transition (3969, 3970), // &LeftDoubleBra -> &LeftDoubleBrac + new Transition (3981, 3982), // &LeftDownTeeVe -> &LeftDownTeeVec + new Transition (3988, 3989), // &LeftDownVe -> &LeftDownVec + new Transition (4086, 4087), // &LeftRightVe -> &LeftRightVec + new Transition (4103, 4104), // &LeftTeeVe -> &LeftTeeVec + new Transition (4145, 4146), // &LeftUpDownVe -> &LeftUpDownVec + new Transition (4155, 4156), // &LeftUpTeeVe -> &LeftUpTeeVec + new Transition (4162, 4163), // &LeftUpVe -> &LeftUpVec + new Transition (4173, 4174), // &LeftVe -> &LeftVec + new Transition (4197, 4199), // &les -> &lesc + new Transition (4199, 4200), // &lesc -> &lescc + new Transition (4338, 4339), // &LJ -> &LJc + new Transition (4342, 4343), // &lj -> &ljc + new Transition (4348, 4354), // &ll -> &llc + new Transition (4396, 4397), // &lmousta -> &lmoustac + new Transition (4628, 4633), // &lr -> &lrc + new Transition (4652, 4662), // &ls -> &lsc + new Transition (4658, 4659), // &Ls -> &Lsc + new Transition (4698, 4700), // < -> <c + new Transition (4700, 4701), // <c -> <cc + new Transition (4767, 4809), // &m -> &mc + new Transition (4768, 4769), // &ma -> &mac + new Transition (4781, 4815), // &M -> &Mc + new Transition (4850, 4851), // &MediumSpa -> &MediumSpac + new Transition (4871, 4872), // &mi -> &mic + new Transition (4876, 4882), // &mid -> &midc + new Transition (4909, 4910), // &ml -> &mlc + new Transition (4937, 4938), // &Ms -> &Msc + new Transition (4941, 4942), // &ms -> &msc + new Transition (4965, 5020), // &n -> &nc + new Transition (4966, 4978), // &na -> &nac + new Transition (4971, 5024), // &N -> &Nc + new Transition (4972, 4973), // &Na -> &Nac + new Transition (5099, 5100), // &NegativeMediumSpa -> &NegativeMediumSpac + new Transition (5105, 5106), // &NegativeThi -> &NegativeThic + new Transition (5110, 5111), // &NegativeThickSpa -> &NegativeThickSpac + new Transition (5117, 5118), // &NegativeThinSpa -> &NegativeThinSpac + new Transition (5131, 5132), // &NegativeVeryThinSpa -> &NegativeVeryThinSpac + new Transition (5248, 5249), // &NJ -> &NJc + new Transition (5252, 5253), // &nj -> &njc + new Transition (5365, 5366), // &NonBreakingSpa -> &NonBreakingSpac + new Transition (5406, 5407), // &NotDoubleVerti -> &NotDoubleVertic + new Transition (5521, 5526), // ¬inv -> ¬invc + new Transition (5623, 5628), // ¬niv -> ¬nivc + new Transition (5632, 5633), // &NotPre -> &NotPrec + new Transition (5726, 5738), // &NotSu -> &NotSuc + new Transition (5738, 5739), // &NotSuc -> &NotSucc + new Transition (5813, 5814), // &NotVerti -> &NotVertic + new Transition (5842, 5844), // &npr -> &nprc + new Transition (5848, 5850), // &npre -> &nprec + new Transition (5862, 5864), // &nrarr -> &nrarrc + new Transition (5895, 5896), // &ns -> &nsc + new Transition (5896, 5898), // &nsc -> &nscc + new Transition (5904, 5905), // &Ns -> &Nsc + new Transition (5951, 5967), // &nsu -> &nsuc + new Transition (5967, 5968), // &nsuc -> &nsucc + new Transition (6131, 6152), // &O -> &Oc + new Transition (6132, 6133), // &Oa -> &Oac + new Transition (6138, 6148), // &o -> &oc + new Transition (6139, 6140), // &oa -> &oac + new Transition (6150, 6157), // &ocir -> ô + new Transition (6154, 6155), // &Ocir -> Ô + new Transition (6171, 6172), // &Odbla -> &Odblac + new Transition (6176, 6177), // &odbla -> &odblac + new Transition (6200, 6201), // &of -> &ofc + new Transition (6238, 6243), // &ol -> &olc + new Transition (6259, 6260), // &Oma -> &Omac + new Transition (6264, 6265), // &oma -> &omac + new Transition (6276, 6277), // &Omi -> &Omic + new Transition (6282, 6283), // &omi -> &omic + new Transition (6378, 6379), // &Os -> &Osc + new Transition (6382, 6383), // &os -> &osc + new Transition (6443, 6444), // &OverBra -> &OverBrac + new Transition (6463, 6494), // &p -> &pc + new Transition (6482, 6491), // &P -> &Pc + new Transition (6498, 6499), // &per -> &perc + new Transition (6545, 6546), // &pit -> &pitc + new Transition (6557, 6558), // &plan -> &planc + new Transition (6567, 6576), // &plus -> &plusc + new Transition (6569, 6570), // &plusa -> &plusac + new Transition (6611, 6612), // &Poin -> &Poinc + new Transition (6642, 6647), // &pr -> &prc + new Transition (6653, 6655), // &pre -> &prec + new Transition (6655, 6664), // &prec -> &precc + new Transition (6672, 6673), // &Pre -> &Prec + new Transition (6750, 6751), // &Produ -> &Produc + new Transition (6795, 6796), // &Ps -> &Psc + new Transition (6799, 6800), // &ps -> &psc + new Transition (6808, 6809), // &pun -> &punc + new Transition (6839, 6840), // &Qs -> &Qsc + new Transition (6843, 6844), // &qs -> &qsc + new Transition (6876, 7027), // &r -> &rc + new Transition (6882, 6883), // &ra -> &rac + new Transition (6886, 7021), // &R -> &Rc + new Transition (6887, 6888), // &Ra -> &Rac + new Transition (6898, 6899), // &radi -> &radic + new Transition (6932, 6942), // &rarr -> &rarrc + new Transition (7006, 7007), // &rbra -> &rbrac + new Transition (7053, 7054), // &rd -> &rdc + new Transition (7074, 7089), // &re -> &rec + new Transition (7182, 7183), // &RightAngleBra -> &RightAngleBrac + new Transition (7244, 7245), // &RightDoubleBra -> &RightDoubleBrac + new Transition (7256, 7257), // &RightDownTeeVe -> &RightDownTeeVec + new Transition (7263, 7264), // &RightDownVe -> &RightDownVec + new Transition (7348, 7349), // &RightTeeVe -> &RightTeeVec + new Transition (7390, 7391), // &RightUpDownVe -> &RightUpDownVec + new Transition (7400, 7401), // &RightUpTeeVe -> &RightUpTeeVec + new Transition (7407, 7408), // &RightUpVe -> &RightUpVec + new Transition (7418, 7419), // &RightVe -> &RightVec + new Transition (7459, 7460), // &rmousta -> &rmoustac + new Transition (7542, 7552), // &rs -> &rsc + new Transition (7548, 7549), // &Rs -> &Rsc + new Transition (7610, 7629), // &S -> &Sc + new Transition (7611, 7612), // &Sa -> &Sac + new Transition (7617, 7631), // &s -> &sc + new Transition (7618, 7619), // &sa -> &sac + new Transition (7631, 7645), // &sc -> &scc + new Transition (7663, 7664), // &Scir -> &Scirc + new Transition (7667, 7668), // &scir -> &scirc + new Transition (7703, 7718), // &se -> &sec + new Transition (7751, 7762), // &sh -> &shc + new Transition (7756, 7767), // &SH -> &SHc + new Transition (7758, 7759), // &SHCH -> &SHCHc + new Transition (7763, 7764), // &shch -> &shchc + new Transition (7889, 7890), // &SmallCir -> &SmallCirc + new Transition (7932, 7933), // &SOFT -> &SOFTc + new Transition (7938, 7939), // &soft -> &softc + new Transition (7968, 7969), // &sq -> &sqc + new Transition (8025, 8026), // &SquareInterse -> &SquareIntersec + new Transition (8073, 8074), // &Ss -> &Ssc + new Transition (8077, 8078), // &ss -> &ssc + new Transition (8127, 8216), // &Su -> &Suc + new Transition (8130, 8198), // &su -> &suc + new Transition (8198, 8199), // &suc -> &succ + new Transition (8199, 8208), // &succ -> &succc + new Transition (8216, 8217), // &Suc -> &Succ + new Transition (8400, 8419), // &T -> &Tc + new Transition (8404, 8425), // &t -> &tc + new Transition (8452, 8453), // &telre -> &telrec + new Transition (8493, 8494), // &thi -> &thic + new Transition (8507, 8508), // &Thi -> &Thic + new Transition (8512, 8513), // &ThickSpa -> &ThickSpac + new Transition (8523, 8524), // &ThinSpa -> &ThinSpac + new Transition (8594, 8600), // &top -> &topc + new Transition (8705, 8706), // &Ts -> &Tsc + new Transition (8709, 8710), // &ts -> &tsc + new Transition (8713, 8714), // &TS -> &TSc + new Transition (8719, 8720), // &TSH -> &TSHc + new Transition (8723, 8724), // &tsh -> &tshc + new Transition (8768, 8815), // &U -> &Uc + new Transition (8769, 8770), // &Ua -> &Uac + new Transition (8775, 8820), // &u -> &uc + new Transition (8776, 8777), // &ua -> &uac + new Transition (8792, 8793), // &Uarro -> &Uarroc + new Transition (8798, 8799), // &Ubr -> &Ubrc + new Transition (8803, 8804), // &ubr -> &ubrc + new Transition (8817, 8818), // &Ucir -> Û + new Transition (8822, 8823), // &ucir -> û + new Transition (8837, 8838), // &Udbla -> &Udblac + new Transition (8842, 8843), // &udbla -> &udblac + new Transition (8887, 8888), // &ul -> &ulc + new Transition (8905, 8906), // &Uma -> &Umac + new Transition (8910, 8911), // &uma -> &umac + new Transition (8925, 8926), // &UnderBra -> &UnderBrac + new Transition (9127, 9128), // &ur -> &urc + new Transition (9153, 9154), // &Us -> &Usc + new Transition (9157, 9158), // &us -> &usc + new Transition (9201, 9317), // &v -> &vc + new Transition (9303, 9314), // &V -> &Vc + new Transition (9374, 9375), // &Verti -> &Vertic + new Transition (9410, 9411), // &VeryThinSpa -> &VeryThinSpac + new Transition (9450, 9451), // &Vs -> &Vsc + new Transition (9454, 9455), // &vs -> &vsc + new Transition (9484, 9485), // &W -> &Wc + new Transition (9487, 9488), // &Wcir -> &Wcirc + new Transition (9490, 9491), // &w -> &wc + new Transition (9493, 9494), // &wcir -> &wcirc + new Transition (9540, 9541), // &Ws -> &Wsc + new Transition (9544, 9545), // &ws -> &wsc + new Transition (9548, 9549), // &x -> &xc + new Transition (9554, 9555), // &xcir -> &xcirc + new Transition (9632, 9633), // &Xs -> &Xsc + new Transition (9636, 9637), // &xs -> &xsc + new Transition (9640, 9641), // &xsq -> &xsqc + new Transition (9665, 9685), // &Y -> &Yc + new Transition (9666, 9667), // &Ya -> &Yac + new Transition (9672, 9690), // &y -> &yc + new Transition (9673, 9674), // &ya -> &yac + new Transition (9679, 9680), // &YA -> &YAc + new Transition (9687, 9688), // &Ycir -> &Ycirc + new Transition (9692, 9693), // &ycir -> &ycirc + new Transition (9708, 9709), // &YI -> &YIc + new Transition (9712, 9713), // &yi -> &yic + new Transition (9724, 9725), // &Ys -> &Ysc + new Transition (9728, 9729), // &ys -> &ysc + new Transition (9732, 9733), // &YU -> &YUc + new Transition (9736, 9737), // &yu -> &yuc + new Transition (9747, 9761), // &Z -> &Zc + new Transition (9748, 9749), // &Za -> &Zac + new Transition (9754, 9767), // &z -> &zc + new Transition (9755, 9756), // &za -> &zac + new Transition (9801, 9802), // &ZeroWidthSpa -> &ZeroWidthSpac + new Transition (9817, 9818), // &ZH -> &ZHc + new Transition (9821, 9822), // &zh -> &zhc + new Transition (9840, 9841), // &Zs -> &Zsc + new Transition (9844, 9845) // &zs -> &zsc + }; + TransitionTable_d = new Transition[206] { + new Transition (0, 1432), // & -> &d + new Transition (27, 29), // &ac -> &acd + new Transition (116, 117), // &An -> &And + new Transition (119, 120), // &an -> &and + new Transition (120, 126), // &and -> &andd + new Transition (123, 124), // &andan -> &andand + new Transition (144, 145), // &angms -> &angmsd + new Transition (147, 154), // &angmsda -> &angmsdad + new Transition (168, 170), // &angrtvb -> &angrtvbd + new Transition (210, 211), // &api -> &apid + new Transition (271, 272), // &Atil -> &Atild + new Transition (277, 278), // &atil -> &atild + new Transition (301, 379), // &b -> &bd + new Transition (350, 351), // &Barwe -> &Barwed + new Transition (354, 355), // &barwe -> &barwed + new Transition (455, 456), // &bigo -> &bigod + new Transition (488, 489), // &bigtriangle -> &bigtriangled + new Transition (508, 509), // &bigwe -> &bigwed + new Transition (545, 547), // &blacktriangle -> &blacktriangled + new Transition (613, 623), // &box -> &boxd + new Transition (636, 642), // &boxH -> &boxHd + new Transition (638, 646), // &boxh -> &boxhd + new Transition (789, 907), // &C -> &Cd + new Transition (796, 911), // &c -> &cd + new Transition (805, 824), // &cap -> &capd + new Transition (808, 809), // &capan -> &capand + new Transition (876, 877), // &Cce -> &Cced + new Transition (881, 882), // &cce -> &cced + new Transition (915, 916), // &ce -> &ced + new Transition (920, 921), // &Ce -> &Ced + new Transition (945, 946), // ¢er -> ¢erd + new Transition (987, 1004), // &circle -> &circled + new Transition (1004, 1014), // &circled -> &circledd + new Transition (1060, 1061), // &cirmi -> &cirmid + new Transition (1165, 1167), // &cong -> &congd + new Transition (1207, 1208), // &copro -> &coprod + new Transition (1211, 1212), // &Copro -> &Coprod + new Transition (1287, 1288), // &ct -> &ctd + new Transition (1292, 1293), // &cu -> &cud + new Transition (1318, 1337), // &cup -> &cupd + new Transition (1372, 1373), // &curlywe -> &curlywed + new Transition (1404, 1405), // &cuwe -> &cuwed + new Transition (1432, 1492), // &d -> &dd + new Transition (1507, 1508), // &DDotrah -> &DDotrahd + new Transition (1595, 1596), // &DiacriticalTil -> &DiacriticalTild + new Transition (1605, 1606), // &Diamon -> &Diamond + new Transition (1609, 1610), // &diamon -> &diamond + new Transition (1645, 1646), // &divi -> &divid + new Transition (1701, 1703), // &doteq -> &doteqd + new Transition (1739, 1740), // &doublebarwe -> &doublebarwed + new Transition (1896, 1921), // &down -> &downd + new Transition (2067, 2068), // &dt -> &dtd + new Transition (2108, 2162), // &E -> &Ed + new Transition (2115, 2169), // &e -> &ed + new Transition (2198, 2200), // &egs -> &egsd + new Transition (2222, 2224), // &els -> &elsd + new Transition (2379, 2380), // &EqualTil -> &EqualTild + new Transition (2422, 2426), // &es -> &esd + new Transition (2509, 2510), // &falling -> &fallingd + new Transition (2557, 2558), // &Fille -> &Filled + new Transition (2701, 2759), // &g -> &gd + new Transition (2708, 2755), // &G -> &Gd + new Transition (2712, 2718), // &Gamma -> &Gammad + new Transition (2716, 2720), // &gamma -> &gammad + new Transition (2737, 2738), // &Gce -> &Gced + new Transition (2781, 2786), // &ges -> &gesd + new Transition (2919, 2920), // &GreaterTil -> &GreaterTild + new Transition (2942, 2950), // > -> >d + new Transition (2965, 2976), // >r -> >rd + new Transition (3041, 3042), // &har -> &hard + new Transition (3236, 3265), // &I -> &Id + new Transition (3369, 3370), // &impe -> &imped + new Transition (3393, 3394), // &ino -> &inod + new Transition (3441, 3442), // &intpro -> &intprod + new Transition (3494, 3495), // &ipro -> &iprod + new Transition (3512, 3514), // &isin -> &isind + new Transition (3530, 3531), // &Itil -> &Itild + new Transition (3535, 3536), // &itil -> &itild + new Transition (3633, 3634), // &Kce -> &Kced + new Transition (3639, 3640), // &kce -> &kced + new Transition (3692, 3869), // &l -> &ld + new Transition (3724, 3725), // &Lamb -> &Lambd + new Transition (3729, 3730), // &lamb -> &lambd + new Transition (3737, 3739), // &lang -> &langd + new Transition (3832, 3833), // &lbrksl -> &lbrksld + new Transition (3849, 3850), // &Lce -> &Lced + new Transition (3854, 3855), // &lce -> &lced + new Transition (3879, 3880), // &ldr -> &ldrd + new Transition (4010, 4011), // &leftharpoon -> &leftharpoond + new Transition (4197, 4202), // &les -> &lesd + new Transition (4215, 4223), // &less -> &lessd + new Transition (4297, 4298), // &LessTil -> &LessTild + new Transition (4327, 4328), // &lhar -> &lhard + new Transition (4372, 4373), // &llhar -> &llhard + new Transition (4380, 4381), // &Lmi -> &Lmid + new Transition (4386, 4387), // &lmi -> &lmid + new Transition (4642, 4644), // &lrhar -> &lrhard + new Transition (4698, 4706), // < -> <d + new Transition (4743, 4744), // &lur -> &lurd + new Transition (4767, 4820), // &m -> &md + new Transition (4789, 4791), // &mapsto -> &mapstod + new Transition (4835, 4836), // &measure -> &measured + new Transition (4843, 4844), // &Me -> &Med + new Transition (4871, 4876), // &mi -> &mid + new Transition (4876, 4886), // &mid -> &midd + new Transition (4892, 4896), // &minus -> &minusd + new Transition (4909, 4913), // &ml -> &mld + new Transition (4922, 4923), // &mo -> &mod + new Transition (4965, 5059), // &n -> &nd + new Transition (4990, 4991), // &napi -> &napid + new Transition (5034, 5035), // &Nce -> &Nced + new Transition (5039, 5040), // &nce -> &nced + new Transition (5046, 5048), // &ncong -> &ncongd + new Transition (5064, 5080), // &ne -> &ned + new Transition (5092, 5093), // &NegativeMe -> &NegativeMed + new Transition (5150, 5151), // &Neste -> &Nested + new Transition (5242, 5244), // &nis -> &nisd + new Transition (5256, 5265), // &nl -> &nld + new Transition (5344, 5345), // &nmi -> &nmid + new Transition (5429, 5430), // &NotEqualTil -> &NotEqualTild + new Transition (5489, 5490), // &NotGreaterTil -> &NotGreaterTild + new Transition (5513, 5515), // ¬in -> ¬ind + new Transition (5586, 5587), // &NotLessTil -> &NotLessTild + new Transition (5594, 5595), // &NotNeste -> &NotNested + new Transition (5634, 5635), // &NotPrece -> &NotPreced + new Transition (5741, 5742), // &NotSuccee -> &NotSucceed + new Transition (5764, 5765), // &NotSucceedsTil -> &NotSucceedsTild + new Transition (5783, 5784), // &NotTil -> &NotTild + new Transition (5805, 5806), // &NotTildeTil -> &NotTildeTild + new Transition (5915, 5916), // &nshortmi -> &nshortmid + new Transition (5935, 5936), // &nsmi -> &nsmid + new Transition (5994, 5995), // &Ntil -> &Ntild + new Transition (5999, 6000), // &ntil -> &ntild + new Transition (6043, 6063), // &nv -> &nvd + new Transition (6047, 6053), // &nV -> &nVd + new Transition (6131, 6168), // &O -> &Od + new Transition (6138, 6163), // &o -> &od + new Transition (6187, 6188), // &odsol -> &odsold + new Transition (6282, 6288), // &omi -> &omid + new Transition (6342, 6348), // &or -> &ord + new Transition (6401, 6402), // &Otil -> &Otild + new Transition (6407, 6408), // &otil -> &otild + new Transition (6504, 6505), // &perio -> &period + new Transition (6567, 6580), // &plus -> &plusd + new Transition (6637, 6638), // &poun -> £ + new Transition (6674, 6675), // &Prece -> &Preced + new Transition (6698, 6699), // &PrecedesTil -> &PrecedesTild + new Transition (6745, 6746), // &pro -> &prod + new Transition (6748, 6749), // &Pro -> &Prod + new Transition (6876, 7053), // &r -> &rd + new Transition (6882, 6897), // &ra -> &rad + new Transition (6912, 6914), // &rang -> &rangd + new Transition (7016, 7017), // &rbrksl -> &rbrksld + new Transition (7033, 7034), // &Rce -> &Rced + new Transition (7038, 7039), // &rce -> &rced + new Transition (7057, 7058), // &rdl -> &rdld + new Transition (7157, 7158), // &rhar -> &rhard + new Transition (7285, 7286), // &rightharpoon -> &rightharpoond + new Transition (7434, 7435), // &rising -> &risingd + new Transition (7466, 7467), // &rnmi -> &rnmid + new Transition (7502, 7503), // &Roun -> &Round + new Transition (7598, 7599), // &RuleDelaye -> &RuleDelayed + new Transition (7617, 7695), // &s -> &sd + new Transition (7651, 7658), // &sce -> &sced + new Transition (7653, 7654), // &Sce -> &Sced + new Transition (7800, 7801), // &shortmi -> &shortmid + new Transition (7847, 7849), // &sim -> &simd + new Transition (7918, 7919), // &smi -> &smid + new Transition (7957, 7958), // &spa -> &spad + new Transition (8131, 8133), // &sub -> &subd + new Transition (8139, 8141), // &sube -> &subed + new Transition (8219, 8220), // &Succee -> &Succeed + new Transition (8242, 8243), // &SucceedsTil -> &SucceedsTild + new Transition (8284, 8292), // &sup -> &supd + new Transition (8302, 8304), // &supe -> &suped + new Transition (8404, 8445), // &t -> &td + new Transition (8431, 8432), // &Tce -> &Tced + new Transition (8436, 8437), // &tce -> &tced + new Transition (8545, 8546), // &Til -> &Tild + new Transition (8550, 8551), // &til -> &tild + new Transition (8572, 8573), // &TildeTil -> &TildeTild + new Transition (8578, 8585), // × -> ×d + new Transition (8629, 8630), // &tra -> &trad + new Transition (8633, 8664), // &tri -> &trid + new Transition (8638, 8640), // &triangle -> &triangled + new Transition (8745, 8746), // &twohea -> &twohead + new Transition (8768, 8834), // &U -> &Ud + new Transition (8775, 8829), // &u -> &ud + new Transition (8916, 8917), // &Un -> &Und + new Transition (8970, 9014), // &Up -> &Upd + new Transition (8983, 9024), // &up -> &upd + new Transition (9161, 9162), // &ut -> &utd + new Transition (9168, 9169), // &Util -> &Utild + new Transition (9173, 9174), // &util -> &utild + new Transition (9201, 9335), // &v -> &vd + new Transition (9303, 9325), // &V -> &Vd + new Transition (9399, 9400), // &VerticalTil -> &VerticalTild + new Transition (9471, 9472), // &Vv -> &Vvd + new Transition (9496, 9497), // &we -> &wed + new Transition (9502, 9503), // &We -> &Wed + new Transition (9548, 9560), // &x -> &xd + new Transition (9602, 9603), // &xo -> &xod + new Transition (9660, 9661), // &xwe -> &xwed + new Transition (9747, 9777), // &Z -> &Zd + new Transition (9754, 9781), // &z -> &zd + new Transition (9795, 9796) // &ZeroWi -> &ZeroWid + }; + TransitionTable_e = new Transition[674] { + new Transition (0, 2115), // & -> &e + new Transition (5, 6), // &Aacut -> Á + new Transition (8, 55), // &a -> &ae + new Transition (12, 13), // &aacut -> á + new Transition (16, 17), // &Abr -> &Abre + new Transition (18, 19), // &Abrev -> &Abreve + new Transition (22, 23), // &abr -> &abre + new Transition (24, 25), // &abrev -> &abreve + new Transition (43, 44), // &acut -> ´ + new Transition (70, 71), // &Agrav -> À + new Transition (76, 77), // &agrav -> à + new Transition (79, 80), // &al -> &ale + new Transition (131, 132), // &andslop -> &andslope + new Transition (136, 138), // &ang -> &ange + new Transition (140, 141), // &angl -> &angle + new Transition (147, 156), // &angmsda -> &angmsdae + new Transition (199, 208), // &ap -> &ape + new Transition (232, 234), // &approx -> &approxe + new Transition (264, 266), // &asymp -> &asympe + new Transition (272, 273), // &Atild -> à + new Transition (278, 279), // &atild -> ã + new Transition (301, 384), // &b -> &be + new Transition (304, 310), // &back -> &backe + new Transition (321, 322), // &backprim -> &backprime + new Transition (326, 328), // &backsim -> &backsime + new Transition (331, 390), // &B -> &Be + new Transition (345, 346), // &barv -> &barve + new Transition (346, 347), // &barve -> &barvee + new Transition (349, 350), // &Barw -> &Barwe + new Transition (353, 354), // &barw -> &barwe + new Transition (357, 358), // &barwedg -> &barwedge + new Transition (388, 397), // &becaus -> &because + new Transition (394, 395), // &Becaus -> &Because + new Transition (431, 432), // &betw -> &betwe + new Transition (432, 433), // &betwe -> &betwee + new Transition (467, 468), // &bigotim -> &bigotime + new Transition (487, 488), // &bigtriangl -> &bigtriangle + new Transition (503, 504), // &bigv -> &bigve + new Transition (504, 505), // &bigve -> &bigvee + new Transition (507, 508), // &bigw -> &bigwe + new Transition (510, 511), // &bigwedg -> &bigwedge + new Transition (525, 526), // &blackloz -> &blackloze + new Transition (528, 529), // &blacklozeng -> &blacklozenge + new Transition (535, 536), // &blacksquar -> &blacksquare + new Transition (544, 545), // &blacktriangl -> &blacktriangle + new Transition (552, 553), // &blacktrianglel -> &blacktrianglele + new Transition (579, 580), // &bn -> &bne + new Transition (610, 611), // &bowti -> &bowtie + new Transition (669, 670), // &boxtim -> &boxtime + new Transition (722, 723), // &bprim -> &bprime + new Transition (725, 726), // &Br -> &Bre + new Transition (727, 728), // &Brev -> &Breve + new Transition (730, 731), // &br -> &bre + new Transition (732, 733), // &brev -> &breve + new Transition (744, 748), // &bs -> &bse + new Transition (753, 755), // &bsim -> &bsime + new Transition (769, 771), // &bull -> &bulle + new Transition (775, 779), // &bump -> &bumpe + new Transition (783, 784), // &Bump -> &Bumpe + new Transition (789, 920), // &C -> &Ce + new Transition (793, 794), // &Cacut -> &Cacute + new Transition (796, 915), // &c -> &ce + new Transition (800, 801), // &cacut -> &cacute + new Transition (835, 836), // &CapitalDiff -> &CapitalDiffe + new Transition (837, 838), // &CapitalDiffer -> &CapitalDiffere + new Transition (848, 849), // &car -> &care + new Transition (856, 857), // &Cayl -> &Cayle + new Transition (861, 881), // &cc -> &cce + new Transition (866, 876), // &Cc -> &Cce + new Transition (934, 944), // ¢ -> ¢e + new Transition (937, 938), // &Cent -> &Cente + new Transition (960, 964), // &ch -> &che + new Transition (979, 1051), // &cir -> &cire + new Transition (981, 983), // &circ -> &circe + new Transition (986, 987), // &circl -> &circle + new Transition (993, 994), // &circlearrowl -> &circlearrowle + new Transition (1022, 1023), // &Circl -> &Circle + new Transition (1045, 1046), // &CircleTim -> &CircleTime + new Transition (1074, 1075), // &Clockwis -> &Clockwise + new Transition (1085, 1086), // &ClockwiseContourInt -> &ClockwiseContourInte + new Transition (1092, 1093), // &Clos -> &Close + new Transition (1103, 1104), // &CloseCurlyDoubl -> &CloseCurlyDouble + new Transition (1108, 1109), // &CloseCurlyDoubleQuot -> &CloseCurlyDoubleQuote + new Transition (1114, 1115), // &CloseCurlyQuot -> &CloseCurlyQuote + new Transition (1129, 1136), // &Colon -> &Colone + new Transition (1134, 1138), // &colon -> &colone + new Transition (1153, 1154), // &compl -> &comple + new Transition (1155, 1156), // &complem -> &compleme + new Transition (1160, 1161), // &complex -> &complexe + new Transition (1174, 1175), // &Congru -> &Congrue + new Transition (1193, 1194), // &ContourInt -> &ContourInte + new Transition (1228, 1229), // &Count -> &Counte + new Transition (1238, 1239), // &CounterClockwis -> &CounterClockwise + new Transition (1249, 1250), // &CounterClockwiseContourInt -> &CounterClockwiseContourInte + new Transition (1279, 1281), // &csub -> &csube + new Transition (1283, 1285), // &csup -> &csupe + new Transition (1292, 1301), // &cu -> &cue + new Transition (1354, 1355), // &curly -> &curlye + new Transition (1358, 1359), // &curlyeqpr -> &curlyeqpre + new Transition (1367, 1368), // &curlyv -> &curlyve + new Transition (1368, 1369), // &curlyve -> &curlyvee + new Transition (1371, 1372), // &curlyw -> &curlywe + new Transition (1374, 1375), // &curlywedg -> &curlywedge + new Transition (1377, 1378), // &curr -> &curre + new Transition (1381, 1382), // &curv -> &curve + new Transition (1388, 1389), // &curvearrowl -> &curvearrowle + new Transition (1399, 1400), // &cuv -> &cuve + new Transition (1400, 1401), // &cuve -> &cuvee + new Transition (1403, 1404), // &cuw -> &cuwe + new Transition (1425, 1519), // &D -> &De + new Transition (1428, 1429), // &Dagg -> &Dagge + new Transition (1432, 1516), // &d -> &de + new Transition (1435, 1436), // &dagg -> &dagge + new Transition (1439, 1440), // &dal -> &dale + new Transition (1496, 1497), // &ddagg -> &ddagge + new Transition (1512, 1513), // &ddots -> &ddotse + new Transition (1570, 1571), // &DiacriticalAcut -> &DiacriticalAcute + new Transition (1579, 1580), // &DiacriticalDoubl -> &DiacriticalDouble + new Transition (1584, 1585), // &DiacriticalDoubleAcut -> &DiacriticalDoubleAcute + new Transition (1590, 1591), // &DiacriticalGrav -> &DiacriticalGrave + new Transition (1596, 1597), // &DiacriticalTild -> &DiacriticalTilde + new Transition (1599, 1619), // &di -> &die + new Transition (1622, 1623), // &Diff -> &Diffe + new Transition (1624, 1625), // &Differ -> &Differe + new Transition (1646, 1647), // &divid -> ÷ + new Transition (1653, 1654), // ÷ontim -> ÷ontime + new Transition (1694, 1700), // &dot -> &dote + new Transition (1728, 1729), // &dotsquar -> &dotsquare + new Transition (1733, 1734), // &doubl -> &double + new Transition (1738, 1739), // &doublebarw -> &doublebarwe + new Transition (1741, 1742), // &doublebarwedg -> &doublebarwedge + new Transition (1746, 1747), // &Doubl -> &Double + new Transition (1757, 1758), // &DoubleContourInt -> &DoubleContourInte + new Transition (1776, 1777), // &DoubleL -> &DoubleLe + new Transition (1797, 1798), // &DoubleLeftT -> &DoubleLeftTe + new Transition (1798, 1799), // &DoubleLeftTe -> &DoubleLeftTee + new Transition (1804, 1805), // &DoubleLongL -> &DoubleLongLe + new Transition (1847, 1848), // &DoubleRightT -> &DoubleRightTe + new Transition (1848, 1849), // &DoubleRightTe -> &DoubleRightTee + new Transition (1869, 1870), // &DoubleV -> &DoubleVe + new Transition (1916, 1917), // &DownBr -> &DownBre + new Transition (1918, 1919), // &DownBrev -> &DownBreve + new Transition (1939, 1940), // &downharpoonl -> &downharpoonle + new Transition (1950, 1951), // &DownL -> &DownLe + new Transition (1959, 1960), // &DownLeftRightV -> &DownLeftRightVe + new Transition (1966, 1967), // &DownLeftT -> &DownLeftTe + new Transition (1967, 1968), // &DownLeftTe -> &DownLeftTee + new Transition (1969, 1970), // &DownLeftTeeV -> &DownLeftTeeVe + new Transition (1976, 1977), // &DownLeftV -> &DownLeftVe + new Transition (1992, 1993), // &DownRightT -> &DownRightTe + new Transition (1993, 1994), // &DownRightTe -> &DownRightTee + new Transition (1995, 1996), // &DownRightTeeV -> &DownRightTeeVe + new Transition (2002, 2003), // &DownRightV -> &DownRightVe + new Transition (2013, 2014), // &DownT -> &DownTe + new Transition (2014, 2015), // &DownTe -> &DownTee + new Transition (2090, 2091), // &dwangl -> &dwangle + new Transition (2112, 2113), // &Eacut -> É + new Transition (2115, 2173), // &e -> &ee + new Transition (2119, 2120), // &eacut -> é + new Transition (2123, 2124), // &east -> &easte + new Transition (2190, 2191), // &Egrav -> È + new Transition (2195, 2196), // &egrav -> è + new Transition (2206, 2207), // &El -> &Ele + new Transition (2208, 2209), // &Elem -> &Eleme + new Transition (2215, 2216), // &elint -> &elinte + new Transition (2242, 2243), // &emptys -> &emptyse + new Transition (2258, 2259), // &EmptySmallSquar -> &EmptySmallSquare + new Transition (2263, 2264), // &EmptyV -> &EmptyVe + new Transition (2276, 2277), // &EmptyVerySmallSquar -> &EmptyVerySmallSquare + new Transition (2362, 2363), // &eqslantl -> &eqslantle + new Transition (2372, 2383), // &equ -> &eque + new Transition (2380, 2381), // &EqualTild -> &EqualTilde + new Transition (2472, 2473), // &exp -> &expe + new Transition (2484, 2485), // &Expon -> &Expone + new Transition (2494, 2495), // &expon -> &expone + new Transition (2500, 2501), // &exponential -> &exponentiale + new Transition (2503, 2524), // &f -> &fe + new Transition (2513, 2514), // &fallingdots -> &fallingdotse + new Transition (2527, 2528), // &femal -> &female + new Transition (2556, 2557), // &Fill -> &Fille + new Transition (2568, 2569), // &FilledSmallSquar -> &FilledSmallSquare + new Transition (2571, 2572), // &FilledV -> &FilledVe + new Transition (2584, 2585), // &FilledVerySmallSquar -> &FilledVerySmallSquare + new Transition (2632, 2633), // &Fouri -> &Fourie + new Transition (2701, 2765), // &g -> &ge + new Transition (2705, 2706), // &gacut -> &gacute + new Transition (2725, 2726), // &Gbr -> &Gbre + new Transition (2727, 2728), // &Gbrev -> &Gbreve + new Transition (2731, 2732), // &gbr -> &gbre + new Transition (2733, 2734), // &gbrev -> &gbreve + new Transition (2736, 2737), // &Gc -> &Gce + new Transition (2794, 2796), // &gesl -> &gesle + new Transition (2812, 2813), // &gim -> &gime + new Transition (2832, 2843), // &gn -> &gne + new Transition (2863, 2864), // &grav -> &grave + new Transition (2866, 2867), // &Gr -> &Gre + new Transition (2869, 2870), // &Great -> &Greate + new Transition (2878, 2879), // &GreaterEqualL -> &GreaterEqualLe + new Transition (2894, 2895), // &GreaterGr -> &GreaterGre + new Transition (2897, 2898), // &GreaterGreat -> &GreaterGreate + new Transition (2901, 2902), // &GreaterL -> &GreaterLe + new Transition (2920, 2921), // &GreaterTild -> &GreaterTilde + new Transition (2932, 2934), // &gsim -> &gsime + new Transition (2960, 2961), // >qu -> >que + new Transition (2965, 2980), // >r -> >re + new Transition (2982, 2983), // >reql -> >reqle + new Transition (2988, 2989), // >reqql -> >reqqle + new Transition (2993, 2994), // >rl -> >rle + new Transition (3002, 3003), // &gv -> &gve + new Transition (3006, 3007), // &gvertn -> &gvertne + new Transition (3016, 3017), // &Hac -> &Hace + new Transition (3020, 3074), // &h -> &he + new Transition (3102, 3103), // &Hilb -> &Hilbe + new Transition (3109, 3110), // &HilbertSpac -> &HilbertSpace + new Transition (3113, 3114), // &hks -> &hkse + new Transition (3138, 3139), // &hookl -> &hookle + new Transition (3181, 3182), // &HorizontalLin -> &HorizontalLine + new Transition (3232, 3233), // &hyph -> &hyphe + new Transition (3240, 3241), // &Iacut -> Í + new Transition (3243, 3273), // &i -> &ie + new Transition (3247, 3248), // &iacut -> í + new Transition (3292, 3293), // &Igrav -> Ì + new Transition (3298, 3299), // &igrav -> ì + new Transition (3341, 3342), // &imag -> &image + new Transition (3354, 3355), // &imaglin -> &imagline + new Transition (3368, 3369), // &imp -> &impe + new Transition (3374, 3375), // &Impli -> &Implie + new Transition (3382, 3383), // &incar -> &incare + new Transition (3390, 3391), // &infinti -> &infintie + new Transition (3399, 3413), // &Int -> &Inte + new Transition (3401, 3407), // &int -> &inte + new Transition (3408, 3409), // &integ -> &intege + new Transition (3425, 3426), // &Inters -> &Interse + new Transition (3449, 3450), // &Invisibl -> &Invisible + new Transition (3459, 3460), // &InvisibleTim -> &InvisibleTime + new Transition (3498, 3499), // &iqu -> &ique + new Transition (3531, 3532), // &Itild -> &Itilde + new Transition (3536, 3537), // &itild -> &itilde + new Transition (3590, 3598), // &Js -> &Jse + new Transition (3594, 3603), // &js -> &jse + new Transition (3632, 3633), // &Kc -> &Kce + new Transition (3638, 3639), // &kc -> &kce + new Transition (3655, 3656), // &kgr -> &kgre + new Transition (3656, 3657), // &kgre -> &kgree + new Transition (3692, 3896), // &l -> &le + new Transition (3698, 3898), // &L -> &Le + new Transition (3702, 3703), // &Lacut -> &Lacute + new Transition (3705, 3711), // &la -> &lae + new Transition (3708, 3709), // &lacut -> &lacute + new Transition (3741, 3742), // &langl -> &langle + new Transition (3749, 3750), // &Laplac -> &Laplace + new Transition (3792, 3803), // &lat -> &late + new Transition (3823, 3824), // &lbrac -> &lbrace + new Transition (3828, 3829), // &lbrk -> &lbrke + new Transition (3837, 3849), // &Lc -> &Lce + new Transition (3843, 3854), // &lc -> &lce + new Transition (3904, 3905), // &LeftAngl -> &LeftAngle + new Transition (3910, 3911), // &LeftAngleBrack -> &LeftAngleBracke + new Transition (3953, 3954), // &LeftC -> &LeftCe + new Transition (3965, 3966), // &LeftDoubl -> &LeftDouble + new Transition (3971, 3972), // &LeftDoubleBrack -> &LeftDoubleBracke + new Transition (3977, 3978), // &LeftDownT -> &LeftDownTe + new Transition (3978, 3979), // &LeftDownTe -> &LeftDownTee + new Transition (3980, 3981), // &LeftDownTeeV -> &LeftDownTeeVe + new Transition (3987, 3988), // &LeftDownV -> &LeftDownVe + new Transition (4019, 4020), // &leftl -> &leftle + new Transition (4085, 4086), // &LeftRightV -> &LeftRightVe + new Transition (4092, 4093), // &LeftT -> &LeftTe + new Transition (4093, 4094), // &LeftTe -> &LeftTee + new Transition (4102, 4103), // &LeftTeeV -> &LeftTeeVe + new Transition (4111, 4112), // &leftthr -> &leftthre + new Transition (4112, 4113), // &leftthre -> &leftthree + new Transition (4116, 4117), // &leftthreetim -> &leftthreetime + new Transition (4125, 4126), // &LeftTriangl -> &LeftTriangle + new Transition (4144, 4145), // &LeftUpDownV -> &LeftUpDownVe + new Transition (4151, 4152), // &LeftUpT -> &LeftUpTe + new Transition (4152, 4153), // &LeftUpTe -> &LeftUpTee + new Transition (4154, 4155), // &LeftUpTeeV -> &LeftUpTeeVe + new Transition (4161, 4162), // &LeftUpV -> &LeftUpVe + new Transition (4172, 4173), // &LeftV -> &LeftVe + new Transition (4210, 4212), // &lesg -> &lesge + new Transition (4215, 4227), // &less -> &lesse + new Transition (4246, 4247), // &LessEqualGr -> &LessEqualGre + new Transition (4249, 4250), // &LessEqualGreat -> &LessEqualGreate + new Transition (4264, 4265), // &LessGr -> &LessGre + new Transition (4267, 4268), // &LessGreat -> &LessGreate + new Transition (4275, 4276), // &LessL -> &LessLe + new Transition (4298, 4299), // &LessTild -> &LessTilde + new Transition (4346, 4361), // &Ll -> &Lle + new Transition (4357, 4358), // &llcorn -> &llcorne + new Transition (4398, 4399), // &lmoustach -> &lmoustache + new Transition (4401, 4412), // &ln -> &lne + new Transition (4437, 4438), // &LongL -> &LongLe + new Transition (4447, 4448), // &Longl -> &Longle + new Transition (4459, 4460), // &longl -> &longle + new Transition (4549, 4550), // &looparrowl -> &looparrowle + new Transition (4575, 4576), // &lotim -> &lotime + new Transition (4588, 4589), // &Low -> &Lowe + new Transition (4591, 4592), // &LowerL -> &LowerLe + new Transition (4612, 4614), // &loz -> &loze + new Transition (4616, 4617), // &lozeng -> &lozenge + new Transition (4636, 4637), // &lrcorn -> &lrcorne + new Transition (4670, 4672), // &lsim -> &lsime + new Transition (4711, 4712), // <hr -> <hre + new Transition (4712, 4713), // <hre -> <hree + new Transition (4716, 4717), // <im -> <ime + new Transition (4726, 4727), // <qu -> <que + new Transition (4732, 4734), // <ri -> <rie + new Transition (4755, 4756), // &lv -> &lve + new Transition (4759, 4760), // &lvertn -> &lvertne + new Transition (4767, 4830), // &m -> &me + new Transition (4772, 4773), // &mal -> &male + new Transition (4775, 4777), // &malt -> &malte + new Transition (4778, 4779), // &maltes -> &maltese + new Transition (4781, 4843), // &M -> &Me + new Transition (4796, 4797), // &mapstol -> &mapstole + new Transition (4805, 4806), // &mark -> &marke + new Transition (4834, 4835), // &measur -> &measure + new Transition (4840, 4841), // &measuredangl -> &measuredangle + new Transition (4851, 4852), // &MediumSpac -> &MediumSpace + new Transition (4923, 4924), // &mod -> &mode + new Transition (4965, 5064), // &n -> &ne + new Transition (4971, 5084), // &N -> &Ne + new Transition (4975, 4976), // &Nacut -> &Nacute + new Transition (4980, 4981), // &nacut -> &nacute + new Transition (5016, 5018), // &nbump -> &nbumpe + new Transition (5020, 5039), // &nc -> &nce + new Transition (5024, 5034), // &Nc -> &Nce + new Transition (5089, 5090), // &Negativ -> &Negative + new Transition (5091, 5092), // &NegativeM -> &NegativeMe + new Transition (5100, 5101), // &NegativeMediumSpac -> &NegativeMediumSpace + new Transition (5111, 5112), // &NegativeThickSpac -> &NegativeThickSpace + new Transition (5118, 5119), // &NegativeThinSpac -> &NegativeThinSpace + new Transition (5121, 5122), // &NegativeV -> &NegativeVe + new Transition (5132, 5133), // &NegativeVeryThinSpac -> &NegativeVeryThinSpace + new Transition (5140, 5141), // &nes -> &nese + new Transition (5149, 5150), // &Nest -> &Neste + new Transition (5153, 5154), // &NestedGr -> &NestedGre + new Transition (5156, 5157), // &NestedGreat -> &NestedGreate + new Transition (5160, 5161), // &NestedGreaterGr -> &NestedGreaterGre + new Transition (5163, 5164), // &NestedGreaterGreat -> &NestedGreaterGreate + new Transition (5167, 5168), // &NestedL -> &NestedLe + new Transition (5171, 5172), // &NestedLessL -> &NestedLessLe + new Transition (5179, 5180), // &NewLin -> &NewLine + new Transition (5195, 5198), // &ng -> &nge + new Transition (5256, 5270), // &nl -> &nle + new Transition (5272, 5273), // &nL -> &nLe + new Transition (5337, 5339), // &nltri -> &nltrie + new Transition (5349, 5350), // &NoBr -> &NoBre + new Transition (5356, 5357), // &NonBr -> &NonBre + new Transition (5366, 5367), // &NonBreakingSpac -> &NonBreakingSpace + new Transition (5385, 5386), // &NotCongru -> &NotCongrue + new Transition (5400, 5401), // &NotDoubl -> &NotDouble + new Transition (5402, 5403), // &NotDoubleV -> &NotDoubleVe + new Transition (5415, 5416), // &NotEl -> &NotEle + new Transition (5417, 5418), // &NotElem -> &NotEleme + new Transition (5430, 5431), // &NotEqualTild -> &NotEqualTilde + new Transition (5440, 5441), // &NotGr -> &NotGre + new Transition (5443, 5444), // &NotGreat -> &NotGreate + new Transition (5464, 5465), // &NotGreaterGr -> &NotGreaterGre + new Transition (5467, 5468), // &NotGreaterGreat -> &NotGreaterGreate + new Transition (5471, 5472), // &NotGreaterL -> &NotGreaterLe + new Transition (5490, 5491), // &NotGreaterTild -> &NotGreaterTilde + new Transition (5528, 5529), // &NotL -> &NotLe + new Transition (5538, 5539), // &NotLeftTriangl -> &NotLeftTriangle + new Transition (5561, 5562), // &NotLessGr -> &NotLessGre + new Transition (5564, 5565), // &NotLessGreat -> &NotLessGreate + new Transition (5568, 5569), // &NotLessL -> &NotLessLe + new Transition (5587, 5588), // &NotLessTild -> &NotLessTilde + new Transition (5590, 5591), // &NotN -> &NotNe + new Transition (5593, 5594), // &NotNest -> &NotNeste + new Transition (5597, 5598), // &NotNestedGr -> &NotNestedGre + new Transition (5600, 5601), // &NotNestedGreat -> &NotNestedGreate + new Transition (5604, 5605), // &NotNestedGreaterGr -> &NotNestedGreaterGre + new Transition (5607, 5608), // &NotNestedGreaterGreat -> &NotNestedGreaterGreate + new Transition (5611, 5612), // &NotNestedL -> &NotNestedLe + new Transition (5615, 5616), // &NotNestedLessL -> &NotNestedLessLe + new Transition (5631, 5632), // &NotPr -> &NotPre + new Transition (5633, 5634), // &NotPrec -> &NotPrece + new Transition (5635, 5636), // &NotPreced -> &NotPrecede + new Transition (5656, 5657), // &NotR -> &NotRe + new Transition (5658, 5659), // &NotRev -> &NotReve + new Transition (5661, 5662), // &NotRevers -> &NotReverse + new Transition (5664, 5665), // &NotReverseEl -> &NotReverseEle + new Transition (5666, 5667), // &NotReverseElem -> &NotReverseEleme + new Transition (5681, 5682), // &NotRightTriangl -> &NotRightTriangle + new Transition (5698, 5699), // &NotSquar -> &NotSquare + new Transition (5703, 5704), // &NotSquareSubs -> &NotSquareSubse + new Transition (5713, 5714), // &NotSquareSup -> &NotSquareSupe + new Transition (5716, 5717), // &NotSquareSupers -> &NotSquareSuperse + new Transition (5728, 5729), // &NotSubs -> &NotSubse + new Transition (5739, 5740), // &NotSucc -> &NotSucce + new Transition (5740, 5741), // &NotSucce -> &NotSuccee + new Transition (5765, 5766), // &NotSucceedsTild -> &NotSucceedsTilde + new Transition (5768, 5769), // &NotSup -> &NotSupe + new Transition (5771, 5772), // &NotSupers -> &NotSuperse + new Transition (5784, 5785), // &NotTild -> &NotTilde + new Transition (5806, 5807), // &NotTildeTild -> &NotTildeTilde + new Transition (5809, 5810), // &NotV -> &NotVe + new Transition (5827, 5828), // &nparall -> &nparalle + new Transition (5842, 5848), // &npr -> &npre + new Transition (5845, 5846), // &nprcu -> &nprcue + new Transition (5850, 5852), // &nprec -> &nprece + new Transition (5891, 5893), // &nrtri -> &nrtrie + new Transition (5896, 5902), // &nsc -> &nsce + new Transition (5899, 5900), // &nsccu -> &nsccue + new Transition (5923, 5924), // &nshortparall -> &nshortparalle + new Transition (5928, 5930), // &nsim -> &nsime + new Transition (5945, 5946), // &nsqsub -> &nsqsube + new Transition (5948, 5949), // &nsqsup -> &nsqsupe + new Transition (5952, 5956), // &nsub -> &nsube + new Transition (5958, 5959), // &nsubs -> &nsubse + new Transition (5960, 5962), // &nsubset -> &nsubsete + new Transition (5968, 5970), // &nsucc -> &nsucce + new Transition (5973, 5977), // &nsup -> &nsupe + new Transition (5979, 5980), // &nsups -> &nsupse + new Transition (5981, 5983), // &nsupset -> &nsupsete + new Transition (5995, 5996), // &Ntild -> Ñ + new Transition (6000, 6001), // &ntild -> ñ + new Transition (6011, 6012), // &ntriangl -> &ntriangle + new Transition (6013, 6014), // &ntrianglel -> &ntrianglele + new Transition (6016, 6018), // &ntriangleleft -> &ntrianglelefte + new Transition (6025, 6027), // &ntriangleright -> &ntrianglerighte + new Transition (6034, 6036), // &num -> &nume + new Transition (6068, 6069), // &nvg -> &nvge + new Transition (6084, 6089), // &nvl -> &nvle + new Transition (6094, 6095), // &nvltri -> &nvltrie + new Transition (6104, 6105), // &nvrtri -> &nvrtrie + new Transition (6126, 6127), // &nwn -> &nwne + new Transition (6135, 6136), // &Oacut -> Ó + new Transition (6138, 6195), // &o -> &oe + new Transition (6142, 6143), // &oacut -> ó + new Transition (6217, 6218), // &Ograv -> Ò + new Transition (6222, 6223), // &ograv -> ò + new Transition (6253, 6254), // &olin -> &oline + new Transition (6258, 6268), // &Om -> &Ome + new Transition (6263, 6272), // &om -> &ome + new Transition (6302, 6332), // &op -> &ope + new Transition (6306, 6307), // &Op -> &Ope + new Transition (6318, 6319), // &OpenCurlyDoubl -> &OpenCurlyDouble + new Transition (6323, 6324), // &OpenCurlyDoubleQuot -> &OpenCurlyDoubleQuote + new Transition (6329, 6330), // &OpenCurlyQuot -> &OpenCurlyQuote + new Transition (6348, 6350), // &ord -> &orde + new Transition (6371, 6372), // &orslop -> &orslope + new Transition (6402, 6403), // &Otild -> Õ + new Transition (6408, 6409), // &otild -> õ + new Transition (6411, 6412), // &Otim -> &Otime + new Transition (6415, 6416), // &otim -> &otime + new Transition (6435, 6436), // &Ov -> &Ove + new Transition (6444, 6445), // &OverBrac -> &OverBrace + new Transition (6447, 6448), // &OverBrack -> &OverBracke + new Transition (6453, 6454), // &OverPar -> &OverPare + new Transition (6457, 6458), // &OverParenth -> &OverParenthe + new Transition (6463, 6497), // &p -> &pe + new Transition (6470, 6471), // ¶ll -> ¶lle + new Transition (6513, 6514), // &pert -> &perte + new Transition (6538, 6539), // &phon -> &phone + new Transition (6567, 6585), // &plus -> &pluse + new Transition (6614, 6615), // &Poincar -> &Poincare + new Transition (6619, 6620), // &Poincareplan -> &Poincareplane + new Transition (6640, 6672), // &Pr -> &Pre + new Transition (6642, 6653), // &pr -> &pre + new Transition (6648, 6649), // &prcu -> &prcue + new Transition (6655, 6702), // &prec -> &prece + new Transition (6668, 6669), // &preccurly -> &preccurlye + new Transition (6673, 6674), // &Prec -> &Prece + new Transition (6675, 6676), // &Preced -> &Precede + new Transition (6699, 6700), // &PrecedesTild -> &PrecedesTilde + new Transition (6705, 6713), // &precn -> &precne + new Transition (6726, 6727), // &Prim -> &Prime + new Transition (6730, 6731), // &prim -> &prime + new Transition (6762, 6763), // &proflin -> &profline + new Transition (6791, 6792), // &prur -> &prure + new Transition (6836, 6837), // &qprim -> &qprime + new Transition (6847, 6862), // &qu -> &que + new Transition (6849, 6850), // &quat -> &quate + new Transition (6864, 6866), // &quest -> &queste + new Transition (6876, 7074), // &r -> &re + new Transition (6882, 6901), // &ra -> &rae + new Transition (6883, 6884), // &rac -> &race + new Transition (6886, 7072), // &R -> &Re + new Transition (6890, 6891), // &Racut -> &Racute + new Transition (6894, 6895), // &racut -> &racute + new Transition (6912, 6916), // &rang -> &range + new Transition (6918, 6919), // &rangl -> &rangle + new Transition (7007, 7008), // &rbrac -> &rbrace + new Transition (7012, 7013), // &rbrk -> &rbrke + new Transition (7021, 7033), // &Rc -> &Rce + new Transition (7027, 7038), // &rc -> &rce + new Transition (7079, 7080), // &realin -> &realine + new Transition (7097, 7098), // &Rev -> &Reve + new Transition (7100, 7101), // &Revers -> &Reverse + new Transition (7103, 7104), // &ReverseEl -> &ReverseEle + new Transition (7105, 7106), // &ReverseElem -> &ReverseEleme + new Transition (7178, 7179), // &RightAngl -> &RightAngle + new Transition (7184, 7185), // &RightAngleBrack -> &RightAngleBracke + new Transition (7213, 7214), // &RightArrowL -> &RightArrowLe + new Transition (7228, 7229), // &RightC -> &RightCe + new Transition (7240, 7241), // &RightDoubl -> &RightDouble + new Transition (7246, 7247), // &RightDoubleBrack -> &RightDoubleBracke + new Transition (7252, 7253), // &RightDownT -> &RightDownTe + new Transition (7253, 7254), // &RightDownTe -> &RightDownTee + new Transition (7255, 7256), // &RightDownTeeV -> &RightDownTeeVe + new Transition (7262, 7263), // &RightDownV -> &RightDownVe + new Transition (7294, 7295), // &rightl -> &rightle + new Transition (7337, 7338), // &RightT -> &RightTe + new Transition (7338, 7339), // &RightTe -> &RightTee + new Transition (7347, 7348), // &RightTeeV -> &RightTeeVe + new Transition (7356, 7357), // &rightthr -> &rightthre + new Transition (7357, 7358), // &rightthre -> &rightthree + new Transition (7361, 7362), // &rightthreetim -> &rightthreetime + new Transition (7370, 7371), // &RightTriangl -> &RightTriangle + new Transition (7389, 7390), // &RightUpDownV -> &RightUpDownVe + new Transition (7396, 7397), // &RightUpT -> &RightUpTe + new Transition (7397, 7398), // &RightUpTe -> &RightUpTee + new Transition (7399, 7400), // &RightUpTeeV -> &RightUpTeeVe + new Transition (7406, 7407), // &RightUpV -> &RightUpVe + new Transition (7417, 7418), // &RightV -> &RightVe + new Transition (7438, 7439), // &risingdots -> &risingdotse + new Transition (7461, 7462), // &rmoustach -> &rmoustache + new Transition (7497, 7498), // &rotim -> &rotime + new Transition (7508, 7509), // &RoundImpli -> &RoundImplie + new Transition (7569, 7570), // &rthr -> &rthre + new Transition (7570, 7571), // &rthre -> &rthree + new Transition (7574, 7575), // &rtim -> &rtime + new Transition (7579, 7581), // &rtri -> &rtrie + new Transition (7591, 7592), // &Rul -> &Rule + new Transition (7593, 7594), // &RuleD -> &RuleDe + new Transition (7597, 7598), // &RuleDelay -> &RuleDelaye + new Transition (7614, 7615), // &Sacut -> &Sacute + new Transition (7617, 7703), // &s -> &se + new Transition (7621, 7622), // &sacut -> &sacute + new Transition (7629, 7653), // &Sc -> &Sce + new Transition (7631, 7651), // &sc -> &sce + new Transition (7646, 7647), // &sccu -> &sccue + new Transition (7697, 7701), // &sdot -> &sdote + new Transition (7786, 7787), // &ShortL -> &ShortLe + new Transition (7808, 7809), // &shortparall -> &shortparalle + new Transition (7847, 7853), // &sim -> &sime + new Transition (7865, 7866), // &simn -> &simne + new Transition (7891, 7892), // &SmallCircl -> &SmallCircle + new Transition (7894, 7911), // &sm -> &sme + new Transition (7898, 7899), // &smalls -> &smallse + new Transition (7921, 7922), // &smil -> &smile + new Transition (7924, 7926), // &smt -> &smte + new Transition (7958, 7959), // &spad -> &spade + new Transition (7986, 7988), // &sqsub -> &sqsube + new Transition (7990, 7991), // &sqsubs -> &sqsubse + new Transition (7992, 7994), // &sqsubset -> &sqsubsete + new Transition (7997, 7999), // &sqsup -> &sqsupe + new Transition (8001, 8002), // &sqsups -> &sqsupse + new Transition (8003, 8005), // &sqsupset -> &sqsupsete + new Transition (8012, 8013), // &Squar -> &Square + new Transition (8016, 8017), // &squar -> &square + new Transition (8021, 8022), // &SquareInt -> &SquareInte + new Transition (8024, 8025), // &SquareInters -> &SquareInterse + new Transition (8035, 8036), // &SquareSubs -> &SquareSubse + new Transition (8045, 8046), // &SquareSup -> &SquareSupe + new Transition (8048, 8049), // &SquareSupers -> &SquareSuperse + new Transition (8077, 8081), // &ss -> &sse + new Transition (8088, 8089), // &ssmil -> &ssmile + new Transition (8111, 8112), // &straight -> &straighte + new Transition (8131, 8139), // &sub -> &sube + new Transition (8150, 8153), // &subn -> &subne + new Transition (8165, 8166), // &Subs -> &Subse + new Transition (8169, 8170), // &subs -> &subse + new Transition (8171, 8173), // &subset -> &subsete + new Transition (8184, 8185), // &subsetn -> &subsetne + new Transition (8199, 8246), // &succ -> &succe + new Transition (8212, 8213), // &succcurly -> &succcurlye + new Transition (8217, 8218), // &Succ -> &Succe + new Transition (8218, 8219), // &Succe -> &Succee + new Transition (8243, 8244), // &SucceedsTild -> &SucceedsTilde + new Transition (8249, 8257), // &succn -> &succne + new Transition (8282, 8308), // &Sup -> &Supe + new Transition (8284, 8302), // &sup -> &supe + new Transition (8310, 8311), // &Supers -> &Superse + new Transition (8338, 8341), // &supn -> &supne + new Transition (8348, 8349), // &Sups -> &Supse + new Transition (8352, 8353), // &sups -> &supse + new Transition (8354, 8356), // &supset -> &supsete + new Transition (8361, 8362), // &supsetn -> &supsetne + new Transition (8404, 8449), // &t -> &te + new Transition (8407, 8408), // &targ -> &targe + new Transition (8419, 8431), // &Tc -> &Tce + new Transition (8425, 8436), // &tc -> &tce + new Transition (8451, 8452), // &telr -> &telre + new Transition (8461, 8462), // &th -> &the + new Transition (8463, 8464), // &ther -> &there + new Transition (8467, 8468), // &Th -> &The + new Transition (8469, 8470), // &Ther -> &There + new Transition (8473, 8474), // &Therefor -> &Therefore + new Transition (8478, 8479), // &therefor -> &therefore + new Transition (8513, 8514), // &ThickSpac -> &ThickSpace + new Transition (8524, 8525), // &ThinSpac -> &ThinSpace + new Transition (8546, 8547), // &Tild -> &Tilde + new Transition (8551, 8552), // &tild -> &tilde + new Transition (8573, 8574), // &TildeTild -> &TildeTilde + new Transition (8576, 8577), // &tim -> &time + new Transition (8590, 8591), // &to -> &toe + new Transition (8620, 8621), // &tprim -> &tprime + new Transition (8630, 8631), // &trad -> &trade + new Transition (8633, 8668), // &tri -> &trie + new Transition (8637, 8638), // &triangl -> &triangle + new Transition (8645, 8646), // &trianglel -> &trianglele + new Transition (8648, 8650), // &triangleleft -> &trianglelefte + new Transition (8659, 8661), // &triangleright -> &trianglerighte + new Transition (8679, 8680), // &Tripl -> &Triple + new Transition (8695, 8696), // &tritim -> &tritime + new Transition (8698, 8699), // &trp -> &trpe + new Transition (8743, 8744), // &twoh -> &twohe + new Transition (8747, 8748), // &twoheadl -> &twoheadle + new Transition (8772, 8773), // &Uacut -> Ú + new Transition (8779, 8780), // &uacut -> ú + new Transition (8798, 8807), // &Ubr -> &Ubre + new Transition (8803, 8811), // &ubr -> &ubre + new Transition (8808, 8809), // &Ubrev -> &Ubreve + new Transition (8812, 8813), // &ubrev -> &ubreve + new Transition (8863, 8864), // &Ugrav -> Ù + new Transition (8869, 8870), // &ugrav -> ù + new Transition (8891, 8893), // &ulcorn -> &ulcorne + new Transition (8917, 8918), // &Und -> &Unde + new Transition (8926, 8927), // &UnderBrac -> &UnderBrace + new Transition (8929, 8930), // &UnderBrack -> &UnderBracke + new Transition (8935, 8936), // &UnderPar -> &UnderPare + new Transition (8939, 8940), // &UnderParenth -> &UnderParenthe + new Transition (9053, 9054), // &upharpoonl -> &upharpoonle + new Transition (9068, 9069), // &Upp -> &Uppe + new Transition (9071, 9072), // &UpperL -> &UpperLe + new Transition (9108, 9109), // &UpT -> &UpTe + new Transition (9109, 9110), // &UpTe -> &UpTee + new Transition (9131, 9133), // &urcorn -> &urcorne + new Transition (9169, 9170), // &Utild -> &Utilde + new Transition (9174, 9175), // &utild -> &utilde + new Transition (9198, 9199), // &uwangl -> &uwangle + new Transition (9201, 9345), // &v -> &ve + new Transition (9208, 9209), // &var -> &vare + new Transition (9260, 9261), // &varsubs -> &varsubse + new Transition (9263, 9264), // &varsubsetn -> &varsubsetne + new Transition (9270, 9271), // &varsups -> &varsupse + new Transition (9273, 9274), // &varsupsetn -> &varsupsetne + new Transition (9280, 9281), // &varth -> &varthe + new Transition (9290, 9291), // &vartriangl -> &vartriangle + new Transition (9292, 9293), // &vartrianglel -> &vartrianglele + new Transition (9303, 9342), // &V -> &Ve + new Transition (9342, 9343), // &Ve -> &Vee + new Transition (9345, 9346), // &ve -> &vee + new Transition (9346, 9352), // &vee -> &veee + new Transition (9384, 9385), // &VerticalLin -> &VerticalLine + new Transition (9387, 9388), // &VerticalS -> &VerticalSe + new Transition (9400, 9401), // &VerticalTild -> &VerticalTilde + new Transition (9411, 9412), // &VeryThinSpac -> &VeryThinSpace + new Transition (9460, 9463), // &vsubn -> &vsubne + new Transition (9466, 9469), // &vsupn -> &vsupne + new Transition (9484, 9502), // &W -> &We + new Transition (9490, 9496), // &w -> &we + new Transition (9504, 9505), // &Wedg -> &Wedge + new Transition (9507, 9508), // &wedg -> &wedge + new Transition (9512, 9513), // &wei -> &weie + new Transition (9533, 9535), // &wr -> &wre + new Transition (9620, 9621), // &xotim -> &xotime + new Transition (9655, 9656), // &xv -> &xve + new Transition (9656, 9657), // &xve -> &xvee + new Transition (9659, 9660), // &xw -> &xwe + new Transition (9662, 9663), // &xwedg -> &xwedge + new Transition (9669, 9670), // &Yacut -> Ý + new Transition (9672, 9699), // &y -> &ye + new Transition (9676, 9677), // &yacut -> ý + new Transition (9747, 9791), // &Z -> &Ze + new Transition (9751, 9752), // &Zacut -> &Zacute + new Transition (9754, 9785), // &z -> &ze + new Transition (9758, 9759), // &zacut -> &zacute + new Transition (9785, 9786), // &ze -> &zee + new Transition (9802, 9803) // &ZeroWidthSpac -> &ZeroWidthSpace + }; + TransitionTable_f = new Transition[177] { + new Transition (0, 2503), // & -> &f + new Transition (1, 62), // &A -> &Af + new Transition (8, 60), // &a -> &af + new Transition (80, 81), // &ale -> &alef + new Transition (147, 158), // &angmsda -> &angmsdaf + new Transition (193, 194), // &Aop -> &Aopf + new Transition (196, 197), // &aop -> &aopf + new Transition (301, 439), // &b -> &bf + new Transition (331, 436), // &B -> &Bf + new Transition (553, 554), // &blacktrianglele -> &blacktrianglelef + new Transition (595, 596), // &Bop -> &Bopf + new Transition (599, 600), // &bop -> &bopf + new Transition (789, 950), // &C -> &Cf + new Transition (796, 953), // &c -> &cf + new Transition (833, 834), // &CapitalDi -> &CapitalDif + new Transition (834, 835), // &CapitalDif -> &CapitalDiff + new Transition (979, 1053), // &cir -> &cirf + new Transition (994, 995), // &circlearrowle -> &circlearrowlef + new Transition (1148, 1150), // &comp -> &compf + new Transition (1200, 1201), // &Cop -> &Copf + new Transition (1203, 1204), // &cop -> &copf + new Transition (1389, 1390), // &curvearrowle -> &curvearrowlef + new Transition (1425, 1541), // &D -> &Df + new Transition (1432, 1535), // &d -> &df + new Transition (1557, 1621), // &Di -> &Dif + new Transition (1621, 1622), // &Dif -> &Diff + new Transition (1686, 1687), // &Dop -> &Dopf + new Transition (1689, 1690), // &dop -> &dopf + new Transition (1777, 1778), // &DoubleLe -> &DoubleLef + new Transition (1805, 1806), // &DoubleLongLe -> &DoubleLongLef + new Transition (1940, 1941), // &downharpoonle -> &downharpoonlef + new Transition (1951, 1952), // &DownLe -> &DownLef + new Transition (2073, 2075), // &dtri -> &dtrif + new Transition (2108, 2180), // &E -> &Ef + new Transition (2115, 2175), // &e -> &ef + new Transition (2306, 2307), // &Eop -> &Eopf + new Transition (2309, 2310), // &eop -> &eopf + new Transition (2503, 2530), // &f -> &ff + new Transition (2517, 2544), // &F -> &Ff + new Transition (2605, 2606), // &fno -> &fnof + new Transition (2609, 2610), // &Fop -> &Fopf + new Transition (2613, 2614), // &fop -> &fopf + new Transition (2636, 2637), // &Fouriertr -> &Fouriertrf + new Transition (2701, 2802), // &g -> &gf + new Transition (2708, 2799), // &G -> &Gf + new Transition (2854, 2855), // &Gop -> &Gopf + new Transition (2858, 2859), // &gop -> &gopf + new Transition (3014, 3094), // &H -> &Hf + new Transition (3020, 3097), // &h -> &hf + new Transition (3027, 3028), // &hal -> &half + new Transition (3139, 3140), // &hookle -> &hooklef + new Transition (3160, 3161), // &Hop -> &Hopf + new Transition (3163, 3164), // &hop -> &hopf + new Transition (3236, 3284), // &I -> &If + new Transition (3243, 3281), // &i -> &if + new Transition (3281, 3282), // &if -> &iff + new Transition (3311, 3312), // &iin -> &iinf + new Transition (3365, 3366), // &imo -> &imof + new Transition (3378, 3385), // &in -> &inf + new Transition (3480, 3481), // &Iop -> &Iopf + new Transition (3483, 3484), // &iop -> &iopf + new Transition (3555, 3571), // &J -> &Jf + new Transition (3561, 3574), // &j -> &jf + new Transition (3583, 3584), // &Jop -> &Jopf + new Transition (3587, 3588), // &jop -> &jopf + new Transition (3618, 3648), // &K -> &Kf + new Transition (3624, 3651), // &k -> &kf + new Transition (3677, 3678), // &Kop -> &Kopf + new Transition (3681, 3682), // &kop -> &kopf + new Transition (3692, 4301), // &l -> &lf + new Transition (3698, 4312), // &L -> &Lf + new Transition (3752, 3753), // &Laplacetr -> &Laplacetrf + new Transition (3766, 3773), // &larr -> &larrf + new Transition (3768, 3770), // &larrb -> &larrbf + new Transition (3896, 3925), // &le -> &lef + new Transition (3898, 3899), // &Le -> &Lef + new Transition (4020, 4021), // &leftle -> &leftlef + new Transition (4361, 4362), // &Lle -> &Llef + new Transition (4438, 4439), // &LongLe -> &LongLef + new Transition (4448, 4449), // &Longle -> &Longlef + new Transition (4460, 4461), // &longle -> &longlef + new Transition (4550, 4551), // &looparrowle -> &looparrowlef + new Transition (4560, 4567), // &lop -> &lopf + new Transition (4564, 4565), // &Lop -> &Lopf + new Transition (4592, 4593), // &LowerLe -> &LowerLef + new Transition (4612, 4619), // &loz -> &lozf + new Transition (4732, 4736), // <ri -> <rif + new Transition (4767, 4865), // &m -> &mf + new Transition (4781, 4862), // &M -> &Mf + new Transition (4797, 4798), // &mapstole -> &mapstolef + new Transition (4859, 4860), // &Mellintr -> &Mellintrf + new Transition (4929, 4930), // &Mop -> &Mopf + new Transition (4932, 4933), // &mop -> &mopf + new Transition (4965, 5192), // &n -> &nf + new Transition (4971, 5189), // &N -> &Nf + new Transition (5270, 5282), // &nle -> &nlef + new Transition (5273, 5274), // &nLe -> &nLef + new Transition (5369, 5370), // &Nop -> &Nopf + new Transition (5373, 5374), // &nop -> &nopf + new Transition (5529, 5530), // &NotLe -> &NotLef + new Transition (6014, 6015), // &ntrianglele -> &ntrianglelef + new Transition (6079, 6080), // &nvin -> &nvinf + new Transition (6131, 6205), // &O -> &Of + new Transition (6138, 6200), // &o -> &of + new Transition (6295, 6296), // &Oop -> &Oopf + new Transition (6299, 6300), // &oop -> &oopf + new Transition (6348, 6356), // &ord -> ª + new Transition (6353, 6354), // &ordero -> &orderof + new Transition (6362, 6363), // &origo -> &origof + new Transition (6463, 6521), // &p -> &pf + new Transition (6482, 6518), // &P -> &Pf + new Transition (6547, 6548), // &pitch -> &pitchf + new Transition (6630, 6631), // &Pop -> &Popf + new Transition (6633, 6634), // &pop -> &popf + new Transition (6745, 6754), // &pro -> &prof + new Transition (6767, 6768), // &profsur -> &profsurf + new Transition (6813, 6814), // &Q -> &Qf + new Transition (6817, 6818), // &q -> &qf + new Transition (6826, 6827), // &Qop -> &Qopf + new Transition (6830, 6831), // &qop -> &qopf + new Transition (6876, 7135), // &r -> &rf + new Transition (6886, 7146), // &R -> &Rf + new Transition (6932, 6944), // &rarr -> &rarrf + new Transition (6937, 6939), // &rarrb -> &rarrbf + new Transition (7214, 7215), // &RightArrowLe -> &RightArrowLef + new Transition (7295, 7296), // &rightle -> &rightlef + new Transition (7481, 7489), // &rop -> &ropf + new Transition (7486, 7487), // &Rop -> &Ropf + new Transition (7579, 7583), // &rtri -> &rtrif + new Transition (7610, 7741), // &S -> &Sf + new Transition (7617, 7744), // &s -> &sf + new Transition (7787, 7788), // &ShortLe -> &ShortLef + new Transition (7841, 7843), // &sigma -> &sigmaf + new Transition (7936, 7937), // &so -> &sof + new Transition (7950, 7951), // &Sop -> &Sopf + new Transition (7953, 7954), // &sop -> &sopf + new Transition (8008, 8066), // &squ -> &squf + new Transition (8016, 8064), // &squar -> &squarf + new Transition (8093, 8094), // &sstar -> &sstarf + new Transition (8102, 8104), // &star -> &starf + new Transition (8400, 8455), // &T -> &Tf + new Transition (8404, 8458), // &t -> &tf + new Transition (8464, 8476), // &there -> &theref + new Transition (8470, 8471), // &There -> &Theref + new Transition (8594, 8608), // &top -> &topf + new Transition (8605, 8606), // &Top -> &Topf + new Transition (8646, 8647), // &trianglele -> &trianglelef + new Transition (8748, 8749), // &twoheadle -> &twoheadlef + new Transition (8768, 8855), // &U -> &Uf + new Transition (8775, 8849), // &u -> &uf + new Transition (8964, 8965), // &Uop -> &Uopf + new Transition (8967, 8968), // &uop -> &uopf + new Transition (9054, 9055), // &upharpoonle -> &upharpoonlef + new Transition (9072, 9073), // &UpperLe -> &UpperLef + new Transition (9178, 9180), // &utri -> &utrif + new Transition (9201, 9417), // &v -> &vf + new Transition (9293, 9294), // &vartrianglele -> &vartrianglelef + new Transition (9303, 9414), // &V -> &Vf + new Transition (9433, 9434), // &Vop -> &Vopf + new Transition (9437, 9438), // &vop -> &vopf + new Transition (9484, 9517), // &W -> &Wf + new Transition (9490, 9520), // &w -> &wf + new Transition (9524, 9525), // &Wop -> &Wopf + new Transition (9528, 9529), // &wop -> &wopf + new Transition (9548, 9569), // &x -> &xf + new Transition (9565, 9566), // &X -> &Xf + new Transition (9608, 9609), // &Xop -> &Xopf + new Transition (9611, 9612), // &xop -> &xopf + new Transition (9665, 9702), // &Y -> &Yf + new Transition (9672, 9705), // &y -> &yf + new Transition (9717, 9718), // &Yop -> &Yopf + new Transition (9721, 9722), // &yop -> &yopf + new Transition (9747, 9811), // &Z -> &Zf + new Transition (9754, 9814), // &z -> &zf + new Transition (9788, 9789), // &zeetr -> &zeetrf + new Transition (9833, 9834), // &Zop -> &Zopf + new Transition (9837, 9838) // &zop -> &zopf + }; + TransitionTable_g = new Transition[182] { + new Transition (0, 2701), // & -> &g + new Transition (1, 67), // &A -> &Ag + new Transition (8, 73), // &a -> &ag + new Transition (52, 53), // &AEli -> Æ + new Transition (57, 58), // &aeli -> æ + new Transition (108, 109), // &amal -> &amalg + new Transition (119, 136), // &an -> &ang + new Transition (147, 160), // &angmsda -> &angmsdag + new Transition (183, 184), // &Ao -> &Aog + new Transition (188, 189), // &ao -> &aog + new Transition (239, 240), // &Arin -> Å + new Transition (244, 245), // &arin -> å + new Transition (256, 257), // &Assi -> &Assig + new Transition (307, 308), // &backcon -> &backcong + new Transition (355, 357), // &barwed -> &barwedg + new Transition (371, 372), // &bcon -> &bcong + new Transition (442, 443), // &bi -> &big + new Transition (485, 486), // &bigtrian -> &bigtriang + new Transition (509, 510), // &bigwed -> &bigwedg + new Transition (527, 528), // &blacklozen -> &blacklozeng + new Transition (542, 543), // &blacktrian -> &blacktriang + new Transition (558, 559), // &blacktriangleri -> &blacktrianglerig + new Transition (999, 1000), // &circlearrowri -> &circlearrowrig + new Transition (1086, 1087), // &ClockwiseContourInte -> &ClockwiseContourInteg + new Transition (1164, 1165), // &con -> &cong + new Transition (1171, 1172), // &Con -> &Cong + new Transition (1194, 1195), // &ContourInte -> &ContourInteg + new Transition (1250, 1251), // &CounterClockwiseContourInte -> &CounterClockwiseContourInteg + new Transition (1373, 1374), // &curlywed -> &curlywedg + new Transition (1394, 1395), // &curvearrowri -> &curvearrowrig + new Transition (1426, 1427), // &Da -> &Dag + new Transition (1427, 1428), // &Dag -> &Dagg + new Transition (1433, 1434), // &da -> &dag + new Transition (1434, 1435), // &dag -> &dagg + new Transition (1494, 1495), // &dda -> &ddag + new Transition (1495, 1496), // &ddag -> &ddagg + new Transition (1516, 1517), // &de -> ° + new Transition (1599, 1633), // &di -> &dig + new Transition (1740, 1741), // &doublebarwed -> &doublebarwedg + new Transition (1758, 1759), // &DoubleContourInte -> &DoubleContourInteg + new Transition (1787, 1788), // &DoubleLeftRi -> &DoubleLeftRig + new Transition (1802, 1803), // &DoubleLon -> &DoubleLong + new Transition (1815, 1816), // &DoubleLongLeftRi -> &DoubleLongLeftRig + new Transition (1826, 1827), // &DoubleLongRi -> &DoubleLongRig + new Transition (1837, 1838), // &DoubleRi -> &DoubleRig + new Transition (1945, 1946), // &downharpoonri -> &downharpoonrig + new Transition (1955, 1956), // &DownLeftRi -> &DownLeftRig + new Transition (1988, 1989), // &DownRi -> &DownRig + new Transition (2088, 2089), // &dwan -> &dwang + new Transition (2101, 2102), // &dzi -> &dzig + new Transition (2108, 2187), // &E -> &Eg + new Transition (2115, 2185), // &e -> &eg + new Transition (2290, 2291), // &en -> &eng + new Transition (2296, 2297), // &Eo -> &Eog + new Transition (2301, 2302), // &eo -> &eog + new Transition (2357, 2358), // &eqslant -> &eqslantg + new Transition (2508, 2509), // &fallin -> &falling + new Transition (2533, 2534), // &ffili -> &ffilig + new Transition (2537, 2538), // &ffli -> &fflig + new Transition (2541, 2542), // &fflli -> &ffllig + new Transition (2551, 2552), // &fili -> &filig + new Transition (2589, 2590), // &fjli -> &fjlig + new Transition (2597, 2598), // &flli -> &fllig + new Transition (2701, 2807), // &g -> &gg + new Transition (2708, 2805), // &G -> &Gg + new Transition (2807, 2809), // &gg -> &ggg + new Transition (3149, 3150), // &hookri -> &hookrig + new Transition (3236, 3289), // &I -> &Ig + new Transition (3243, 3295), // &i -> &ig + new Transition (3322, 3323), // &IJli -> &IJlig + new Transition (3327, 3328), // &ijli -> &ijlig + new Transition (3332, 3344), // &Ima -> &Imag + new Transition (3337, 3341), // &ima -> &imag + new Transition (3407, 3408), // &inte -> &integ + new Transition (3413, 3414), // &Inte -> &Integ + new Transition (3467, 3476), // &io -> &iog + new Transition (3471, 3472), // &Io -> &Iog + new Transition (3624, 3654), // &k -> &kg + new Transition (3692, 4317), // &l -> &lg + new Transition (3705, 3718), // &la -> &lag + new Transition (3733, 3734), // &Lan -> &Lang + new Transition (3736, 3737), // &lan -> &lang + new Transition (3894, 4183), // &lE -> &lEg + new Transition (3896, 4185), // &le -> &leg + new Transition (3902, 3903), // &LeftAn -> &LeftAng + new Transition (3938, 3939), // &LeftArrowRi -> &LeftArrowRig + new Transition (3958, 3959), // &LeftCeilin -> &LeftCeiling + new Transition (4031, 4032), // &LeftRi -> &LeftRig + new Transition (4042, 4043), // &Leftri -> &Leftrig + new Transition (4053, 4054), // &leftri -> &leftrig + new Transition (4077, 4078), // &leftrightsqui -> &leftrightsquig + new Transition (4123, 4124), // &LeftTrian -> &LeftTriang + new Transition (4197, 4210), // &les -> &lesg + new Transition (4215, 4271), // &less -> &lessg + new Transition (4228, 4229), // &lesseq -> &lesseqg + new Transition (4233, 4234), // &lesseqq -> &lesseqqg + new Transition (4424, 4425), // &loan -> &loang + new Transition (4435, 4436), // &Lon -> &Long + new Transition (4457, 4458), // &lon -> &long + new Transition (4470, 4471), // &LongLeftRi -> &LongLeftRig + new Transition (4481, 4482), // &Longleftri -> &Longleftrig + new Transition (4492, 4493), // &longleftri -> &longleftrig + new Transition (4510, 4511), // &LongRi -> &LongRig + new Transition (4521, 4522), // &Longri -> &Longrig + new Transition (4532, 4533), // &longri -> &longrig + new Transition (4555, 4556), // &looparrowri -> &looparrowrig + new Transition (4602, 4603), // &LowerRi -> &LowerRig + new Transition (4615, 4616), // &lozen -> &lozeng + new Transition (4670, 4674), // &lsim -> &lsimg + new Transition (4838, 4839), // &measuredan -> &measuredang + new Transition (4965, 5195), // &n -> &ng + new Transition (4983, 4984), // &nan -> &nang + new Transition (5045, 5046), // &ncon -> &ncong + new Transition (5084, 5085), // &Ne -> &Neg + new Transition (5212, 5213), // &nG -> &nGg + new Transition (5291, 5292), // &nLeftri -> &nLeftrig + new Transition (5302, 5303), // &nleftri -> &nleftrig + new Transition (5361, 5362), // &NonBreakin -> &NonBreaking + new Transition (5382, 5383), // &NotCon -> &NotCong + new Transition (5536, 5537), // &NotLeftTrian -> &NotLeftTriang + new Transition (5671, 5672), // &NotRi -> &NotRig + new Transition (5679, 5680), // &NotRightTrian -> &NotRightTriang + new Transition (5869, 5870), // &nRi -> &nRig + new Transition (5879, 5880), // &nri -> &nrig + new Transition (5988, 5989), // &nt -> &ntg + new Transition (6003, 6004), // &ntl -> &ntlg + new Transition (6009, 6010), // &ntrian -> &ntriang + new Transition (6022, 6023), // &ntriangleri -> &ntrianglerig + new Transition (6043, 6068), // &nv -> &nvg + new Transition (6131, 6214), // &O -> &Og + new Transition (6138, 6210), // &o -> &og + new Transition (6192, 6193), // &OEli -> &OElig + new Transition (6197, 6198), // &oeli -> &oelig + new Transition (6268, 6269), // &Ome -> &Omeg + new Transition (6272, 6273), // &ome -> &omeg + new Transition (6360, 6361), // &ori -> &orig + new Transition (6908, 6909), // &Ran -> &Rang + new Transition (6911, 6912), // &ran -> &rang + new Transition (7074, 7095), // &re -> ® + new Transition (7171, 7172), // &Ri -> &Rig + new Transition (7176, 7177), // &RightAn -> &RightAng + new Transition (7199, 7200), // &ri -> &rig + new Transition (7233, 7234), // &RightCeilin -> &RightCeiling + new Transition (7315, 7316), // &rightri -> &rightrig + new Transition (7329, 7330), // &rightsqui -> &rightsquig + new Transition (7368, 7369), // &RightTrian -> &RightTriang + new Transition (7428, 7429), // &rin -> &ring + new Transition (7433, 7434), // &risin -> &rising + new Transition (7471, 7472), // &roan -> &roang + new Transition (7514, 7516), // &rpar -> &rparg + new Transition (7532, 7533), // &Rri -> &Rrig + new Transition (7813, 7814), // &ShortRi -> &ShortRig + new Transition (7833, 7834), // &Si -> &Sig + new Transition (7838, 7839), // &si -> &sig + new Transition (7847, 7857), // &sim -> &simg + new Transition (8108, 8109), // &strai -> &straig + new Transition (8279, 8280), // &sun -> &sung + new Transition (8397, 8398), // &szli -> ß + new Transition (8406, 8407), // &tar -> &targ + new Transition (8635, 8636), // &trian -> &triang + new Transition (8656, 8657), // &triangleri -> &trianglerig + new Transition (8758, 8759), // &twoheadri -> &twoheadrig + new Transition (8768, 8860), // &U -> &Ug + new Transition (8775, 8866), // &u -> &ug + new Transition (8954, 8955), // &Uo -> &Uog + new Transition (8959, 8960), // &uo -> &uog + new Transition (9059, 9060), // &upharpoonri -> &upharpoonrig + new Transition (9082, 9083), // &UpperRi -> &UpperRig + new Transition (9142, 9143), // &Urin -> &Uring + new Transition (9146, 9147), // &urin -> &uring + new Transition (9196, 9197), // &uwan -> &uwang + new Transition (9203, 9204), // &van -> &vang + new Transition (9228, 9229), // &varnothin -> &varnothing + new Transition (9253, 9254), // &varsi -> &varsig + new Transition (9288, 9289), // &vartrian -> &vartriang + new Transition (9298, 9299), // &vartriangleri -> &vartrianglerig + new Transition (9478, 9479), // &vzi -> &vzig + new Transition (9481, 9482), // &vzigza -> &vzigzag + new Transition (9497, 9507), // &wed -> &wedg + new Transition (9503, 9504), // &Wed -> &Wedg + new Transition (9661, 9662), // &xwed -> &xwedg + new Transition (9825, 9826) // &zi -> &zig + }; + TransitionTable_h = new Transition[159] { + new Transition (0, 3020), // & -> &h + new Transition (86, 87), // &alep -> &aleph + new Transition (90, 91), // &Alp -> &Alph + new Transition (94, 95), // &alp -> &alph + new Transition (147, 162), // &angmsda -> &angmsdah + new Transition (173, 174), // &angsp -> &angsph + new Transition (338, 339), // &Backslas -> &Backslash + new Transition (426, 429), // &bet -> &beth + new Transition (559, 560), // &blacktrianglerig -> &blacktrianglerigh + new Transition (613, 638), // &box -> &boxh + new Transition (691, 697), // &boxV -> &boxVh + new Transition (693, 701), // &boxv -> &boxvh + new Transition (758, 762), // &bsol -> &bsolh + new Transition (789, 973), // &C -> &Ch + new Transition (796, 960), // &c -> &ch + new Transition (1000, 1001), // &circlearrowrig -> &circlearrowrigh + new Transition (1016, 1017), // &circleddas -> &circleddash + new Transition (1395, 1396), // &curvearrowrig -> &curvearrowrigh + new Transition (1432, 1550), // &d -> &dh + new Transition (1441, 1442), // &dalet -> &daleth + new Transition (1454, 1455), // &das -> &dash + new Transition (1457, 1458), // &Das -> &Dash + new Transition (1506, 1507), // &DDotra -> &DDotrah + new Transition (1537, 1538), // &dfis -> &dfish + new Transition (1788, 1789), // &DoubleLeftRig -> &DoubleLeftRigh + new Transition (1816, 1817), // &DoubleLongLeftRig -> &DoubleLongLeftRigh + new Transition (1827, 1828), // &DoubleLongRig -> &DoubleLongRigh + new Transition (1838, 1839), // &DoubleRig -> &DoubleRigh + new Transition (1896, 1932), // &down -> &downh + new Transition (1946, 1947), // &downharpoonrig -> &downharpoonrigh + new Transition (1956, 1957), // &DownLeftRig -> &DownLeftRigh + new Transition (1989, 1990), // &DownRig -> &DownRigh + new Transition (2077, 2082), // &du -> &duh + new Transition (2439, 2445), // &et -> ð + new Transition (3132, 3133), // &homt -> &homth + new Transition (3150, 3151), // &hookrig -> &hookrigh + new Transition (3194, 3195), // &hslas -> &hslash + new Transition (3231, 3232), // &hyp -> &hyph + new Transition (3362, 3363), // &imat -> &imath + new Transition (3435, 3436), // &intlar -> &intlarh + new Transition (3579, 3580), // &jmat -> &jmath + new Transition (3624, 3664), // &k -> &kh + new Transition (3692, 4325), // &l -> &lh + new Transition (3766, 3776), // &larr -> &larrh + new Transition (3880, 3881), // &ldrd -> &ldrdh + new Transition (3886, 3887), // &ldrus -> &ldrush + new Transition (3891, 3892), // &lds -> &ldsh + new Transition (3926, 4004), // &left -> &lefth + new Transition (3939, 3940), // &LeftArrowRig -> &LeftArrowRigh + new Transition (4032, 4033), // &LeftRig -> &LeftRigh + new Transition (4043, 4044), // &Leftrig -> &Leftrigh + new Transition (4054, 4055), // &leftrig -> &leftrigh + new Transition (4056, 4065), // &leftright -> &leftrighth + new Transition (4109, 4110), // &leftt -> &leftth + new Transition (4303, 4304), // &lfis -> &lfish + new Transition (4348, 4370), // &ll -> &llh + new Transition (4397, 4398), // &lmoustac -> &lmoustach + new Transition (4471, 4472), // &LongLeftRig -> &LongLeftRigh + new Transition (4482, 4483), // &Longleftrig -> &Longleftrigh + new Transition (4493, 4494), // &longleftrig -> &longleftrigh + new Transition (4511, 4512), // &LongRig -> &LongRigh + new Transition (4522, 4523), // &Longrig -> &Longrigh + new Transition (4533, 4534), // &longrig -> &longrigh + new Transition (4556, 4557), // &looparrowrig -> &looparrowrigh + new Transition (4603, 4604), // &LowerRig -> &LowerRigh + new Transition (4628, 4640), // &lr -> &lrh + new Transition (4652, 4667), // &ls -> &lsh + new Transition (4658, 4665), // &Ls -> &Lsh + new Transition (4698, 4710), // < -> <h + new Transition (4745, 4746), // &lurds -> &lurdsh + new Transition (4750, 4751), // &luru -> &luruh + new Transition (4767, 4868), // &m -> &mh + new Transition (4822, 4823), // &mdas -> &mdash + new Transition (4965, 5227), // &n -> &nh + new Transition (5061, 5062), // &ndas -> &ndash + new Transition (5067, 5068), // &near -> &nearh + new Transition (5103, 5104), // &NegativeT -> &NegativeTh + new Transition (5125, 5126), // &NegativeVeryT -> &NegativeVeryTh + new Transition (5292, 5293), // &nLeftrig -> &nLeftrigh + new Transition (5303, 5304), // &nleftrig -> &nleftrigh + new Transition (5672, 5673), // &NotRig -> &NotRigh + new Transition (5870, 5871), // &nRig -> &nRigh + new Transition (5880, 5881), // &nrig -> &nrigh + new Transition (5895, 5910), // &ns -> &nsh + new Transition (6023, 6024), // &ntrianglerig -> &ntrianglerigh + new Transition (6050, 6051), // &nVDas -> &nVDash + new Transition (6055, 6056), // &nVdas -> &nVdash + new Transition (6060, 6061), // &nvDas -> &nvDash + new Transition (6065, 6066), // &nvdas -> &nvdash + new Transition (6113, 6114), // &nwar -> &nwarh + new Transition (6138, 6227), // &o -> &oh + new Transition (6165, 6166), // &odas -> &odash + new Transition (6388, 6389), // &Oslas -> Ø + new Transition (6393, 6394), // &oslas -> ø + new Transition (6456, 6457), // &OverParent -> &OverParenth + new Transition (6463, 6527), // &p -> &ph + new Transition (6482, 6524), // &P -> &Ph + new Transition (6546, 6547), // &pitc -> &pitch + new Transition (6559, 6561), // &planck -> &planckh + new Transition (6876, 7155), // &r -> &rh + new Transition (6886, 7164), // &R -> &Rh + new Transition (6932, 6947), // &rarr -> &rarrh + new Transition (7058, 7059), // &rdld -> &rdldh + new Transition (7069, 7070), // &rds -> &rdsh + new Transition (7137, 7138), // &rfis -> &rfish + new Transition (7172, 7173), // &Rig -> &Righ + new Transition (7200, 7201), // &rig -> &righ + new Transition (7202, 7279), // &right -> &righth + new Transition (7297, 7305), // &rightleft -> &rightlefth + new Transition (7316, 7317), // &rightrig -> &rightrigh + new Transition (7354, 7355), // &rightt -> &rightth + new Transition (7442, 7447), // &rl -> &rlh + new Transition (7460, 7461), // &rmoustac -> &rmoustach + new Transition (7533, 7534), // &Rrig -> &Rrigh + new Transition (7542, 7557), // &rs -> &rsh + new Transition (7548, 7555), // &Rs -> &Rsh + new Transition (7567, 7568), // &rt -> &rth + new Transition (7603, 7604), // &rulu -> &ruluh + new Transition (7610, 7772), // &S -> &Sh + new Transition (7617, 7751), // &s -> &sh + new Transition (7705, 7706), // &sear -> &searh + new Transition (7762, 7763), // &shc -> &shch + new Transition (7814, 7815), // &ShortRig -> &ShortRigh + new Transition (7907, 7908), // &smas -> &smash + new Transition (8109, 8110), // &straig -> &straigh + new Transition (8120, 8121), // &straightp -> &straightph + new Transition (8216, 8269), // &Suc -> &Such + new Transition (8270, 8271), // &SuchT -> &SuchTh + new Transition (8284, 8320), // &sup -> &suph + new Transition (8377, 8378), // &swar -> &swarh + new Transition (8400, 8467), // &T -> &Th + new Transition (8404, 8461), // &t -> &th + new Transition (8657, 8658), // &trianglerig -> &trianglerigh + new Transition (8709, 8723), // &ts -> &tsh + new Transition (8742, 8743), // &two -> &twoh + new Transition (8759, 8760), // &twoheadrig -> &twoheadrigh + new Transition (8775, 8876), // &u -> &uh + new Transition (8829, 8845), // &ud -> &udh + new Transition (8851, 8852), // &ufis -> &ufish + new Transition (8938, 8939), // &UnderParent -> &UnderParenth + new Transition (8983, 9046), // &up -> &uph + new Transition (9060, 9061), // &upharpoonrig -> &upharpoonrigh + new Transition (9083, 9084), // &UpperRig -> &UpperRigh + new Transition (9096, 9098), // &upsi -> &upsih + new Transition (9225, 9226), // &varnot -> &varnoth + new Transition (9231, 9232), // &varp -> &varph + new Transition (9247, 9249), // &varr -> &varrh + new Transition (9279, 9280), // &vart -> &varth + new Transition (9299, 9300), // &vartrianglerig -> &vartrianglerigh + new Transition (9322, 9323), // &VDas -> &VDash + new Transition (9327, 9328), // &Vdas -> &Vdash + new Transition (9332, 9333), // &vDas -> &vDash + new Transition (9337, 9338), // &vdas -> &vdash + new Transition (9404, 9405), // &VeryT -> &VeryTh + new Transition (9474, 9475), // &Vvdas -> &Vvdash + new Transition (9537, 9538), // &wreat -> &wreath + new Transition (9548, 9572), // &x -> &xh + new Transition (9754, 9821), // &z -> &zh + new Transition (9797, 9798) // &ZeroWidt -> &ZeroWidth + }; + TransitionTable_i = new Transition[428] { + new Transition (0, 3243), // & -> &i + new Transition (27, 38), // &ac -> &aci + new Transition (33, 34), // &Ac -> &Aci + new Transition (51, 52), // &AEl -> &AEli + new Transition (56, 57), // &ael -> &aeli + new Transition (199, 210), // &ap -> &api + new Transition (202, 203), // &apac -> &apaci + new Transition (224, 225), // &ApplyFunct -> &ApplyFuncti + new Transition (237, 238), // &Ar -> &Ari + new Transition (242, 243), // &ar -> &ari + new Transition (255, 256), // &Ass -> &Assi + new Transition (269, 270), // &At -> &Ati + new Transition (275, 276), // &at -> &ati + new Transition (289, 297), // &aw -> &awi + new Transition (292, 293), // &awcon -> &awconi + new Transition (301, 442), // &b -> &bi + new Transition (312, 313), // &backeps -> &backepsi + new Transition (319, 320), // &backpr -> &backpri + new Transition (324, 325), // &backs -> &backsi + new Transition (406, 407), // &beps -> &bepsi + new Transition (419, 420), // &Bernoull -> &Bernoulli + new Transition (444, 448), // &bigc -> &bigci + new Transition (465, 466), // &bigot -> &bigoti + new Transition (482, 483), // &bigtr -> &bigtri + new Transition (539, 540), // &blacktr -> &blacktri + new Transition (557, 558), // &blacktriangler -> &blacktriangleri + new Transition (583, 584), // &bnequ -> &bnequi + new Transition (609, 610), // &bowt -> &bowti + new Transition (656, 657), // &boxm -> &boxmi + new Transition (667, 668), // &boxt -> &boxti + new Transition (720, 721), // &bpr -> &bpri + new Transition (744, 752), // &bs -> &bsi + new Transition (749, 750), // &bsem -> &bsemi + new Transition (789, 1019), // &C -> &Ci + new Transition (796, 978), // &c -> &ci + new Transition (803, 828), // &Cap -> &Capi + new Transition (832, 833), // &CapitalD -> &CapitalDi + new Transition (840, 841), // &CapitalDifferent -> &CapitalDifferenti + new Transition (861, 890), // &cc -> &cci + new Transition (866, 886), // &Cc -> &Cci + new Transition (877, 878), // &Cced -> &Ccedi + new Transition (882, 883), // &cced -> &ccedi + new Transition (895, 896), // &Ccon -> &Cconi + new Transition (916, 917), // &ced -> &cedi + new Transition (921, 922), // &Ced -> &Cedi + new Transition (960, 976), // &ch -> &chi + new Transition (973, 974), // &Ch -> &Chi + new Transition (998, 999), // &circlearrowr -> &circlearrowri + new Transition (1009, 1010), // &circledc -> &circledci + new Transition (1032, 1033), // &CircleM -> &CircleMi + new Transition (1043, 1044), // &CircleT -> &CircleTi + new Transition (1054, 1055), // &cirfn -> &cirfni + new Transition (1059, 1060), // &cirm -> &cirmi + new Transition (1064, 1065), // &cirsc -> &cirsci + new Transition (1072, 1073), // &Clockw -> &Clockwi + new Transition (1122, 1123), // &clubsu -> &clubsui + new Transition (1164, 1183), // &con -> &coni + new Transition (1171, 1179), // &Con -> &Coni + new Transition (1236, 1237), // &CounterClockw -> &CounterClockwi + new Transition (1393, 1394), // &curvearrowr -> &curvearrowri + new Transition (1407, 1415), // &cw -> &cwi + new Transition (1410, 1411), // &cwcon -> &cwconi + new Transition (1425, 1557), // &D -> &Di + new Transition (1432, 1599), // &d -> &di + new Transition (1535, 1536), // &df -> &dfi + new Transition (1560, 1561), // &Diacr -> &Diacri + new Transition (1562, 1563), // &Diacrit -> &Diacriti + new Transition (1593, 1594), // &DiacriticalT -> &DiacriticalTi + new Transition (1613, 1614), // &diamondsu -> &diamondsui + new Transition (1627, 1628), // &Different -> &Differenti + new Transition (1639, 1640), // &dis -> &disi + new Transition (1643, 1645), // &div -> &divi + new Transition (1651, 1652), // ÷ont -> ÷onti + new Transition (1713, 1714), // &dotm -> &dotmi + new Transition (1786, 1787), // &DoubleLeftR -> &DoubleLeftRi + new Transition (1814, 1815), // &DoubleLongLeftR -> &DoubleLongLeftRi + new Transition (1825, 1826), // &DoubleLongR -> &DoubleLongRi + new Transition (1836, 1837), // &DoubleR -> &DoubleRi + new Transition (1872, 1873), // &DoubleVert -> &DoubleVerti + new Transition (1944, 1945), // &downharpoonr -> &downharpoonri + new Transition (1954, 1955), // &DownLeftR -> &DownLeftRi + new Transition (1987, 1988), // &DownR -> &DownRi + new Transition (2072, 2073), // &dtr -> &dtri + new Transition (2097, 2101), // &dz -> &dzi + new Transition (2127, 2142), // &Ec -> &Eci + new Transition (2133, 2139), // &ec -> &eci + new Transition (2204, 2213), // &el -> &eli + new Transition (2323, 2324), // &eps -> &epsi + new Transition (2327, 2328), // &Eps -> &Epsi + new Transition (2340, 2341), // &eqc -> &eqci + new Transition (2350, 2351), // &eqs -> &eqsi + new Transition (2368, 2387), // &Equ -> &Equi + new Transition (2372, 2396), // &equ -> &equi + new Transition (2377, 2378), // &EqualT -> &EqualTi + new Transition (2388, 2389), // &Equil -> &Equili + new Transition (2391, 2392), // &Equilibr -> &Equilibri + new Transition (2418, 2430), // &Es -> &Esi + new Transition (2422, 2433), // &es -> &esi + new Transition (2458, 2462), // &ex -> &exi + new Transition (2466, 2467), // &Ex -> &Exi + new Transition (2477, 2478), // &expectat -> &expectati + new Transition (2487, 2488), // &Exponent -> &Exponenti + new Transition (2497, 2498), // &exponent -> &exponenti + new Transition (2503, 2549), // &f -> &fi + new Transition (2506, 2507), // &fall -> &falli + new Transition (2517, 2554), // &F -> &Fi + new Transition (2530, 2531), // &ff -> &ffi + new Transition (2532, 2533), // &ffil -> &ffili + new Transition (2536, 2537), // &ffl -> &ffli + new Transition (2540, 2541), // &ffll -> &fflli + new Transition (2550, 2551), // &fil -> &fili + new Transition (2588, 2589), // &fjl -> &fjli + new Transition (2596, 2597), // &fll -> &flli + new Transition (2631, 2632), // &Four -> &Fouri + new Transition (2642, 2643), // &fpart -> &fparti + new Transition (2701, 2811), // &g -> &gi + new Transition (2736, 2742), // &Gc -> &Gci + new Transition (2738, 2739), // &Gced -> &Gcedi + new Transition (2746, 2747), // &gc -> &gci + new Transition (2849, 2850), // &gns -> &gnsi + new Transition (2917, 2918), // &GreaterT -> &GreaterTi + new Transition (2927, 2931), // &gs -> &gsi + new Transition (2944, 2947), // >c -> >ci + new Transition (2998, 2999), // >rs -> >rsi + new Transition (3014, 3100), // &H -> &Hi + new Transition (3021, 3022), // &ha -> &hai + new Transition (3030, 3031), // &ham -> &hami + new Transition (3052, 3053), // &harrc -> &harrci + new Transition (3064, 3065), // &Hc -> &Hci + new Transition (3069, 3070), // &hc -> &hci + new Transition (3080, 3081), // &heartsu -> &heartsui + new Transition (3085, 3086), // &hell -> &helli + new Transition (3148, 3149), // &hookr -> &hookri + new Transition (3171, 3172), // &Hor -> &Hori + new Transition (3179, 3180), // &HorizontalL -> &HorizontalLi + new Transition (3243, 3301), // &i -> &ii + new Transition (3250, 3257), // &ic -> &ici + new Transition (3252, 3253), // &Ic -> &Ici + new Transition (3301, 3303), // &ii -> &iii + new Transition (3303, 3304), // &iii -> &iiii + new Transition (3312, 3313), // &iinf -> &iinfi + new Transition (3321, 3322), // &IJl -> &IJli + new Transition (3326, 3327), // &ijl -> &ijli + new Transition (3344, 3345), // &Imag -> &Imagi + new Transition (3352, 3353), // &imagl -> &imagli + new Transition (3373, 3374), // &Impl -> &Impli + new Transition (3385, 3386), // &inf -> &infi + new Transition (3389, 3390), // &infint -> &infinti + new Transition (3428, 3429), // &Intersect -> &Intersecti + new Transition (3444, 3445), // &Inv -> &Invi + new Transition (3446, 3447), // &Invis -> &Invisi + new Transition (3457, 3458), // &InvisibleT -> &InvisibleTi + new Transition (3507, 3511), // &is -> &isi + new Transition (3526, 3534), // &it -> &iti + new Transition (3528, 3529), // &It -> &Iti + new Transition (3556, 3557), // &Jc -> &Jci + new Transition (3562, 3563), // &jc -> &jci + new Transition (3634, 3635), // &Kced -> &Kcedi + new Transition (3640, 3641), // &kced -> &kcedi + new Transition (3785, 3786), // &larrs -> &larrsi + new Transition (3795, 3796), // &lAta -> &lAtai + new Transition (3799, 3800), // &lata -> &latai + new Transition (3850, 3851), // &Lced -> &Lcedi + new Transition (3854, 3859), // &lce -> &lcei + new Transition (3855, 3856), // &lced -> &lcedi + new Transition (3937, 3938), // &LeftArrowR -> &LeftArrowRi + new Transition (3949, 3950), // &leftarrowta -> &leftarrowtai + new Transition (3954, 3955), // &LeftCe -> &LeftCei + new Transition (3956, 3957), // &LeftCeil -> &LeftCeili + new Transition (4030, 4031), // &LeftR -> &LeftRi + new Transition (4041, 4042), // &Leftr -> &Leftri + new Transition (4052, 4053), // &leftr -> &leftri + new Transition (4076, 4077), // &leftrightsqu -> &leftrightsqui + new Transition (4114, 4115), // &leftthreet -> &leftthreeti + new Transition (4120, 4121), // &LeftTr -> &LeftTri + new Transition (4280, 4281), // &lesss -> &lesssi + new Transition (4295, 4296), // &LessT -> &LessTi + new Transition (4301, 4302), // &lf -> &lfi + new Transition (4376, 4377), // &lltr -> &lltri + new Transition (4379, 4380), // &Lm -> &Lmi + new Transition (4385, 4386), // &lm -> &lmi + new Transition (4418, 4419), // &lns -> &lnsi + new Transition (4469, 4470), // &LongLeftR -> &LongLeftRi + new Transition (4480, 4481), // &Longleftr -> &Longleftri + new Transition (4491, 4492), // &longleftr -> &longleftri + new Transition (4509, 4510), // &LongR -> &LongRi + new Transition (4520, 4521), // &Longr -> &Longri + new Transition (4531, 4532), // &longr -> &longri + new Transition (4554, 4555), // &looparrowr -> &looparrowri + new Transition (4573, 4574), // &lot -> &loti + new Transition (4601, 4602), // &LowerR -> &LowerRi + new Transition (4649, 4650), // &lrtr -> &lrtri + new Transition (4652, 4669), // &ls -> &lsi + new Transition (4698, 4715), // < -> <i + new Transition (4700, 4703), // <c -> <ci + new Transition (4731, 4732), // <r -> <ri + new Transition (4767, 4871), // &m -> &mi + new Transition (4781, 4900), // &M -> &Mi + new Transition (4844, 4845), // &Med -> &Medi + new Transition (4855, 4856), // &Mell -> &Melli + new Transition (4882, 4883), // &midc -> &midci + new Transition (4955, 4956), // &mult -> &multi + new Transition (4965, 5240), // &n -> &ni + new Transition (4986, 4990), // &nap -> &napi + new Transition (5035, 5036), // &Nced -> &Ncedi + new Transition (5040, 5041), // &nced -> &ncedi + new Transition (5087, 5088), // &Negat -> &Negati + new Transition (5093, 5094), // &NegativeMed -> &NegativeMedi + new Transition (5104, 5105), // &NegativeTh -> &NegativeThi + new Transition (5126, 5127), // &NegativeVeryTh -> &NegativeVeryThi + new Transition (5136, 5137), // &nequ -> &nequi + new Transition (5140, 5145), // &nes -> &nesi + new Transition (5177, 5178), // &NewL -> &NewLi + new Transition (5182, 5183), // &nex -> &nexi + new Transition (5215, 5216), // &ngs -> &ngsi + new Transition (5290, 5291), // &nLeftr -> &nLeftri + new Transition (5301, 5302), // &nleftr -> &nleftri + new Transition (5328, 5329), // &nls -> &nlsi + new Transition (5336, 5337), // &nltr -> &nltri + new Transition (5343, 5344), // &nm -> &nmi + new Transition (5359, 5360), // &NonBreak -> &NonBreaki + new Transition (5378, 5512), // ¬ -> ¬i + new Transition (5405, 5406), // &NotDoubleVert -> &NotDoubleVerti + new Transition (5427, 5428), // &NotEqualT -> &NotEqualTi + new Transition (5433, 5434), // &NotEx -> &NotExi + new Transition (5487, 5488), // &NotGreaterT -> &NotGreaterTi + new Transition (5533, 5534), // &NotLeftTr -> &NotLeftTri + new Transition (5584, 5585), // &NotLessT -> &NotLessTi + new Transition (5620, 5621), // ¬n -> ¬ni + new Transition (5656, 5671), // &NotR -> &NotRi + new Transition (5676, 5677), // &NotRightTr -> &NotRightTri + new Transition (5762, 5763), // &NotSucceedsT -> &NotSucceedsTi + new Transition (5781, 5782), // &NotT -> &NotTi + new Transition (5803, 5804), // &NotTildeT -> &NotTildeTi + new Transition (5812, 5813), // &NotVert -> &NotVerti + new Transition (5837, 5838), // &npol -> &npoli + new Transition (5855, 5879), // &nr -> &nri + new Transition (5868, 5869), // &nR -> &nRi + new Transition (5890, 5891), // &nrtr -> &nrtri + new Transition (5895, 5927), // &ns -> &nsi + new Transition (5914, 5915), // &nshortm -> &nshortmi + new Transition (5934, 5935), // &nsm -> &nsmi + new Transition (5988, 5998), // &nt -> &nti + new Transition (5992, 5993), // &Nt -> &Nti + new Transition (6006, 6007), // &ntr -> &ntri + new Transition (6021, 6022), // &ntriangler -> &ntriangleri + new Transition (6043, 6078), // &nv -> &nvi + new Transition (6080, 6081), // &nvinf -> &nvinfi + new Transition (6093, 6094), // &nvltr -> &nvltri + new Transition (6103, 6104), // &nvrtr -> &nvrtri + new Transition (6107, 6108), // &nvs -> &nvsi + new Transition (6138, 6234), // &o -> &oi + new Transition (6148, 6149), // &oc -> &oci + new Transition (6152, 6153), // &Oc -> &Oci + new Transition (6163, 6179), // &od -> &odi + new Transition (6191, 6192), // &OEl -> &OEli + new Transition (6196, 6197), // &oel -> &oeli + new Transition (6201, 6202), // &ofc -> &ofci + new Transition (6238, 6252), // &ol -> &oli + new Transition (6243, 6244), // &olc -> &olci + new Transition (6258, 6276), // &Om -> &Omi + new Transition (6263, 6282), // &om -> &omi + new Transition (6342, 6360), // &or -> &ori + new Transition (6399, 6400), // &Ot -> &Oti + new Transition (6405, 6406), // &ot -> &oti + new Transition (6459, 6460), // &OverParenthes -> &OverParenthesi + new Transition (6463, 6543), // &p -> &pi + new Transition (6474, 6475), // &pars -> &parsi + new Transition (6482, 6541), // &P -> &Pi + new Transition (6485, 6486), // &Part -> &Parti + new Transition (6498, 6503), // &per -> &peri + new Transition (6507, 6508), // &perm -> &permi + new Transition (6524, 6525), // &Ph -> &Phi + new Transition (6527, 6528), // &ph -> &phi + new Transition (6570, 6571), // &plusac -> &plusaci + new Transition (6576, 6577), // &plusc -> &plusci + new Transition (6590, 6591), // &PlusM -> &PlusMi + new Transition (6599, 6600), // &pluss -> &plussi + new Transition (6609, 6610), // &Po -> &Poi + new Transition (6622, 6623), // &po -> &poi + new Transition (6625, 6626), // &point -> &pointi + new Transition (6640, 6725), // &Pr -> &Pri + new Transition (6642, 6729), // &pr -> &pri + new Transition (6696, 6697), // &PrecedesT -> &PrecedesTi + new Transition (6717, 6718), // &precns -> &precnsi + new Transition (6721, 6722), // &precs -> &precsi + new Transition (6741, 6742), // &prns -> &prnsi + new Transition (6760, 6761), // &profl -> &profli + new Transition (6775, 6776), // &Proport -> &Proporti + new Transition (6786, 6787), // &prs -> &prsi + new Transition (6795, 6803), // &Ps -> &Psi + new Transition (6799, 6805), // &ps -> &psi + new Transition (6817, 6821), // &q -> &qi + new Transition (6834, 6835), // &qpr -> &qpri + new Transition (6849, 6858), // &quat -> &quati + new Transition (6852, 6853), // &quatern -> &quaterni + new Transition (6876, 7199), // &r -> &ri + new Transition (6886, 7171), // &R -> &Ri + new Transition (6897, 6898), // &rad -> &radi + new Transition (6956, 6957), // &rarrs -> &rarrsi + new Transition (6969, 6970), // &rAta -> &rAtai + new Transition (6973, 6978), // &rat -> &rati + new Transition (6974, 6975), // &rata -> &ratai + new Transition (7034, 7035), // &Rced -> &Rcedi + new Transition (7038, 7043), // &rce -> &rcei + new Transition (7039, 7040), // &rced -> &rcedi + new Transition (7076, 7078), // &real -> &reali + new Transition (7111, 7112), // &ReverseEqu -> &ReverseEqui + new Transition (7113, 7114), // &ReverseEquil -> &ReverseEquili + new Transition (7116, 7117), // &ReverseEquilibr -> &ReverseEquilibri + new Transition (7125, 7126), // &ReverseUpEqu -> &ReverseUpEqui + new Transition (7127, 7128), // &ReverseUpEquil -> &ReverseUpEquili + new Transition (7130, 7131), // &ReverseUpEquilibr -> &ReverseUpEquilibri + new Transition (7135, 7136), // &rf -> &rfi + new Transition (7224, 7225), // &rightarrowta -> &rightarrowtai + new Transition (7229, 7230), // &RightCe -> &RightCei + new Transition (7231, 7232), // &RightCeil -> &RightCeili + new Transition (7314, 7315), // &rightr -> &rightri + new Transition (7328, 7329), // &rightsqu -> &rightsqui + new Transition (7359, 7360), // &rightthreet -> &rightthreeti + new Transition (7365, 7366), // &RightTr -> &RightTri + new Transition (7431, 7432), // &ris -> &risi + new Transition (7465, 7466), // &rnm -> &rnmi + new Transition (7495, 7496), // &rot -> &roti + new Transition (7507, 7508), // &RoundImpl -> &RoundImpli + new Transition (7521, 7522), // &rppol -> &rppoli + new Transition (7531, 7532), // &Rr -> &Rri + new Transition (7567, 7573), // &rt -> &rti + new Transition (7578, 7579), // &rtr -> &rtri + new Transition (7587, 7588), // &rtriltr -> &rtriltri + new Transition (7610, 7833), // &S -> &Si + new Transition (7617, 7838), // &s -> &si + new Transition (7629, 7662), // &Sc -> &Sci + new Transition (7631, 7666), // &sc -> &sci + new Transition (7654, 7655), // &Sced -> &Scedi + new Transition (7658, 7659), // &sced -> &scedi + new Transition (7676, 7677), // &scns -> &scnsi + new Transition (7682, 7683), // &scpol -> &scpoli + new Transition (7687, 7688), // &scs -> &scsi + new Transition (7721, 7722), // &sem -> &semi + new Transition (7730, 7731), // &setm -> &setmi + new Transition (7799, 7800), // &shortm -> &shortmi + new Transition (7812, 7813), // &ShortR -> &ShortRi + new Transition (7887, 7888), // &SmallC -> &SmallCi + new Transition (7894, 7918), // &sm -> &smi + new Transition (7901, 7902), // &smallsetm -> &smallsetmi + new Transition (7962, 7963), // &spadesu -> &spadesui + new Transition (8027, 8028), // &SquareIntersect -> &SquareIntersecti + new Transition (8059, 8060), // &SquareUn -> &SquareUni + new Transition (8086, 8087), // &ssm -> &ssmi + new Transition (8107, 8108), // &stra -> &strai + new Transition (8114, 8115), // &straighteps -> &straightepsi + new Transition (8121, 8122), // &straightph -> &straightphi + new Transition (8169, 8190), // &subs -> &subsi + new Transition (8240, 8241), // &SucceedsT -> &SucceedsTi + new Transition (8261, 8262), // &succns -> &succnsi + new Transition (8265, 8266), // &succs -> &succsi + new Transition (8352, 8367), // &sups -> &supsi + new Transition (8396, 8397), // &szl -> &szli + new Transition (8400, 8544), // &T -> &Ti + new Transition (8404, 8549), // &t -> &ti + new Transition (8432, 8433), // &Tced -> &Tcedi + new Transition (8437, 8438), // &tced -> &tcedi + new Transition (8461, 8493), // &th -> &thi + new Transition (8467, 8507), // &Th -> &Thi + new Transition (8503, 8504), // &thicks -> &thicksi + new Transition (8531, 8532), // &thks -> &thksi + new Transition (8570, 8571), // &TildeT -> &TildeTi + new Transition (8600, 8601), // &topc -> &topci + new Transition (8618, 8619), // &tpr -> &tpri + new Transition (8628, 8633), // &tr -> &tri + new Transition (8655, 8656), // &triangler -> &triangleri + new Transition (8670, 8671), // &trim -> &trimi + new Transition (8676, 8677), // &Tr -> &Tri + new Transition (8693, 8694), // &trit -> &triti + new Transition (8700, 8701), // &trpez -> &trpezi + new Transition (8737, 8738), // &tw -> &twi + new Transition (8757, 8758), // &twoheadr -> &twoheadri + new Transition (8793, 8794), // &Uarroc -> &Uarroci + new Transition (8815, 8816), // &Uc -> &Uci + new Transition (8820, 8821), // &uc -> &uci + new Transition (8849, 8850), // &uf -> &ufi + new Transition (8901, 8902), // &ultr -> &ultri + new Transition (8916, 8945), // &Un -> &Uni + new Transition (8941, 8942), // &UnderParenthes -> &UnderParenthesi + new Transition (9036, 9037), // &UpEqu -> &UpEqui + new Transition (9038, 9039), // &UpEquil -> &UpEquili + new Transition (9041, 9042), // &UpEquilibr -> &UpEquilibri + new Transition (9058, 9059), // &upharpoonr -> &upharpoonri + new Transition (9081, 9082), // &UpperR -> &UpperRi + new Transition (9092, 9093), // &Ups -> &Upsi + new Transition (9095, 9096), // &ups -> &upsi + new Transition (9127, 9145), // &ur -> &uri + new Transition (9140, 9141), // &Ur -> &Uri + new Transition (9150, 9151), // &urtr -> &urtri + new Transition (9161, 9172), // &ut -> &uti + new Transition (9166, 9167), // &Ut -> &Uti + new Transition (9177, 9178), // &utr -> &utri + new Transition (9211, 9212), // &vareps -> &varepsi + new Transition (9226, 9227), // &varnoth -> &varnothi + new Transition (9231, 9235), // &varp -> &varpi + new Transition (9232, 9233), // &varph -> &varphi + new Transition (9252, 9253), // &vars -> &varsi + new Transition (9285, 9286), // &vartr -> &vartri + new Transition (9297, 9298), // &vartriangler -> &vartriangleri + new Transition (9356, 9357), // &vell -> &velli + new Transition (9370, 9374), // &Vert -> &Verti + new Transition (9382, 9383), // &VerticalL -> &VerticalLi + new Transition (9397, 9398), // &VerticalT -> &VerticalTi + new Transition (9405, 9406), // &VeryTh -> &VeryThi + new Transition (9422, 9423), // &vltr -> &vltri + new Transition (9447, 9448), // &vrtr -> &vrtri + new Transition (9477, 9478), // &vz -> &vzi + new Transition (9485, 9486), // &Wc -> &Wci + new Transition (9491, 9492), // &wc -> &wci + new Transition (9496, 9512), // &we -> &wei + new Transition (9548, 9583), // &x -> &xi + new Transition (9549, 9553), // &xc -> &xci + new Transition (9562, 9563), // &xdtr -> &xdtri + new Transition (9565, 9581), // &X -> &Xi + new Transition (9598, 9599), // &xn -> &xni + new Transition (9618, 9619), // &xot -> &xoti + new Transition (9652, 9653), // &xutr -> &xutri + new Transition (9672, 9712), // &y -> &yi + new Transition (9685, 9686), // &Yc -> &Yci + new Transition (9690, 9691), // &yc -> &yci + new Transition (9754, 9825), // &z -> &zi + new Transition (9794, 9795) // &ZeroW -> &ZeroWi + }; + TransitionTable_j = new Transition[11] { + new Transition (0, 3561), // & -> &j + new Transition (1432, 1665), // &d -> &dj + new Transition (2503, 2587), // &f -> &fj + new Transition (2701, 2820), // &g -> &gj + new Transition (2824, 2830), // &gl -> &glj + new Transition (3243, 3325), // &i -> &ij + new Transition (3624, 3672), // &k -> &kj + new Transition (3692, 4342), // &l -> &lj + new Transition (4965, 5252), // &n -> &nj + new Transition (9848, 9849), // &zw -> &zwj + new Transition (9851, 9852) // &zwn -> &zwnj + }; + TransitionTable_k = new Transition[69] { + new Transition (0, 3624), // & -> &k + new Transition (301, 513), // &b -> &bk + new Transition (303, 304), // &bac -> &back + new Transition (333, 334), // &Bac -> &Back + new Transition (361, 362), // &bbr -> &bbrk + new Transition (366, 367), // &bbrktbr -> &bbrktbrk + new Transition (519, 566), // &bl -> &blk + new Transition (521, 522), // &blac -> &black + new Transition (563, 564), // &blan -> &blank + new Transition (576, 577), // &bloc -> &block + new Transition (965, 966), // &chec -> &check + new Transition (970, 971), // &checkmar -> &checkmark + new Transition (1070, 1071), // &Cloc -> &Clock + new Transition (1234, 1235), // &CounterCloc -> &CounterClock + new Transition (1463, 1464), // &db -> &dbk + new Transition (2024, 2025), // &drb -> &drbk + new Transition (2059, 2060), // &Dstro -> &Dstrok + new Transition (2064, 2065), // &dstro -> &dstrok + new Transition (2621, 2626), // &for -> &fork + new Transition (3017, 3018), // &Hace -> &Hacek + new Transition (3020, 3112), // &h -> &hk + new Transition (3136, 3137), // &hoo -> &hook + new Transition (3199, 3200), // &Hstro -> &Hstrok + new Transition (3204, 3205), // &hstro -> &hstrok + new Transition (3436, 3437), // &intlarh -> &intlarhk + new Transition (3539, 3540), // &Iu -> &Iuk + new Transition (3544, 3545), // &iu -> &iuk + new Transition (3608, 3609), // &Ju -> &Juk + new Transition (3613, 3614), // &ju -> &juk + new Transition (3776, 3777), // &larrh -> &larrhk + new Transition (3818, 3819), // &lbbr -> &lbbrk + new Transition (3821, 3828), // &lbr -> &lbrk + new Transition (3823, 3826), // &lbrac -> &lbrack + new Transition (3909, 3910), // &LeftAngleBrac -> &LeftAngleBrack + new Transition (3970, 3971), // &LeftDoubleBrac -> &LeftDoubleBrack + new Transition (4335, 4336), // &lhbl -> &lhblk + new Transition (4431, 4432), // &lobr -> &lobrk + new Transition (4686, 4687), // &Lstro -> &Lstrok + new Transition (4691, 4692), // &lstro -> &lstrok + new Transition (4804, 4805), // &mar -> &mark + new Transition (5068, 5069), // &nearh -> &nearhk + new Transition (5106, 5107), // &NegativeThic -> &NegativeThick + new Transition (5351, 5352), // &NoBrea -> &NoBreak + new Transition (5358, 5359), // &NonBrea -> &NonBreak + new Transition (6114, 6115), // &nwarh -> &nwarhk + new Transition (6444, 6447), // &OverBrac -> &OverBrack + new Transition (6515, 6516), // &perten -> &pertenk + new Transition (6550, 6551), // &pitchfor -> &pitchfork + new Transition (6557, 6563), // &plan -> &plank + new Transition (6558, 6559), // &planc -> &planck + new Transition (6947, 6948), // &rarrh -> &rarrhk + new Transition (7002, 7003), // &rbbr -> &rbbrk + new Transition (7005, 7012), // &rbr -> &rbrk + new Transition (7007, 7010), // &rbrac -> &rbrack + new Transition (7183, 7184), // &RightAngleBrac -> &RightAngleBrack + new Transition (7245, 7246), // &RightDoubleBrac -> &RightDoubleBrack + new Transition (7478, 7479), // &robr -> &robrk + new Transition (7706, 7707), // &searh -> &searhk + new Transition (8378, 8379), // &swarh -> &swarhk + new Transition (8416, 8417), // &tbr -> &tbrk + new Transition (8461, 8527), // &th -> &thk + new Transition (8494, 8495), // &thic -> &thick + new Transition (8508, 8509), // &Thic -> &Thick + new Transition (8611, 8612), // &topfor -> &topfork + new Transition (8729, 8730), // &Tstro -> &Tstrok + new Transition (8734, 8735), // &tstro -> &tstrok + new Transition (8884, 8885), // &uhbl -> &uhblk + new Transition (8926, 8929), // &UnderBrac -> &UnderBrack + new Transition (9208, 9217) // &var -> &vark + }; + TransitionTable_l = new Transition[438] { + new Transition (0, 3692), // & -> &l + new Transition (1, 89), // &A -> &Al + new Transition (8, 79), // &a -> &al + new Transition (50, 51), // &AE -> &AEl + new Transition (55, 56), // &ae -> &ael + new Transition (104, 108), // &ama -> &amal + new Transition (128, 129), // &ands -> &andsl + new Transition (136, 140), // &ang -> &angl + new Transition (217, 218), // &App -> &Appl + new Transition (270, 271), // &Ati -> &Atil + new Transition (276, 277), // &ati -> &atil + new Transition (282, 283), // &Aum -> Ä + new Transition (286, 287), // &aum -> ä + new Transition (301, 519), // &b -> &bl + new Transition (313, 314), // &backepsi -> &backepsil + new Transition (335, 336), // &Backs -> &Backsl + new Transition (417, 418), // &Bernou -> &Bernoul + new Transition (418, 419), // &Bernoul -> &Bernoull + new Transition (460, 461), // &bigop -> &bigopl + new Transition (486, 487), // &bigtriang -> &bigtriangl + new Transition (498, 499), // &bigup -> &bigupl + new Transition (522, 523), // &black -> &blackl + new Transition (543, 544), // &blacktriang -> &blacktriangl + new Transition (545, 552), // &blacktriangle -> &blacktrianglel + new Transition (618, 621), // &boxD -> &boxDl + new Transition (623, 626), // &boxd -> &boxdl + new Transition (662, 663), // &boxp -> &boxpl + new Transition (673, 676), // &boxU -> &boxUl + new Transition (678, 681), // &boxu -> &boxul + new Transition (691, 705), // &boxV -> &boxVl + new Transition (693, 709), // &boxv -> &boxvl + new Transition (757, 758), // &bso -> &bsol + new Transition (767, 768), // &bu -> &bul + new Transition (768, 769), // &bul -> &bull + new Transition (789, 1068), // &C -> &Cl + new Transition (796, 1117), // &c -> &cl + new Transition (830, 831), // &Capita -> &Capital + new Transition (842, 843), // &CapitalDifferentia -> &CapitalDifferential + new Transition (855, 856), // &Cay -> &Cayl + new Transition (878, 879), // &Ccedi -> Ç + new Transition (883, 884), // &ccedi -> ç + new Transition (917, 918), // &cedi -> ¸ + new Transition (922, 923), // &Cedi -> &Cedil + new Transition (923, 924), // &Cedil -> &Cedill + new Transition (981, 986), // &circ -> &circl + new Transition (992, 993), // &circlearrow -> &circlearrowl + new Transition (1021, 1022), // &Circ -> &Circl + new Transition (1038, 1039), // &CircleP -> &CirclePl + new Transition (1089, 1090), // &ClockwiseContourIntegra -> &ClockwiseContourIntegral + new Transition (1096, 1097), // &CloseCur -> &CloseCurl + new Transition (1102, 1103), // &CloseCurlyDoub -> &CloseCurlyDoubl + new Transition (1126, 1127), // &Co -> &Col + new Transition (1131, 1132), // &co -> &col + new Transition (1148, 1153), // &comp -> &compl + new Transition (1197, 1198), // &ContourIntegra -> &ContourIntegral + new Transition (1231, 1232), // &CounterC -> &CounterCl + new Transition (1253, 1254), // &CounterClockwiseContourIntegra -> &CounterClockwiseContourIntegral + new Transition (1292, 1308), // &cu -> &cul + new Transition (1296, 1297), // &cudarr -> &cudarrl + new Transition (1346, 1353), // &cur -> &curl + new Transition (1387, 1388), // &curvearrow -> &curvearrowl + new Transition (1419, 1420), // &cy -> &cyl + new Transition (1432, 1669), // &d -> &dl + new Transition (1433, 1439), // &da -> &dal + new Transition (1463, 1470), // &db -> &dbl + new Transition (1516, 1525), // &de -> &del + new Transition (1519, 1520), // &De -> &Del + new Transition (1552, 1553), // &dhar -> &dharl + new Transition (1565, 1566), // &Diacritica -> &Diacritical + new Transition (1578, 1579), // &DiacriticalDoub -> &DiacriticalDoubl + new Transition (1594, 1595), // &DiacriticalTi -> &DiacriticalTil + new Transition (1629, 1630), // &Differentia -> &Differential + new Transition (1679, 1680), // &do -> &dol + new Transition (1680, 1681), // &dol -> &doll + new Transition (1710, 1711), // &DotEqua -> &DotEqual + new Transition (1719, 1720), // &dotp -> &dotpl + new Transition (1732, 1733), // &doub -> &doubl + new Transition (1745, 1746), // &Doub -> &Doubl + new Transition (1761, 1762), // &DoubleContourIntegra -> &DoubleContourIntegral + new Transition (1875, 1876), // &DoubleVertica -> &DoubleVertical + new Transition (1938, 1939), // &downharpoon -> &downharpoonl + new Transition (2054, 2055), // &dso -> &dsol + new Transition (2089, 2090), // &dwang -> &dwangl + new Transition (2108, 2206), // &E -> &El + new Transition (2115, 2204), // &e -> &el + new Transition (2148, 2149), // &eco -> &ecol + new Transition (2204, 2220), // &el -> &ell + new Transition (2251, 2252), // &EmptySma -> &EmptySmal + new Transition (2252, 2253), // &EmptySmal -> &EmptySmall + new Transition (2269, 2270), // &EmptyVerySma -> &EmptyVerySmal + new Transition (2270, 2271), // &EmptyVerySmal -> &EmptyVerySmall + new Transition (2312, 2319), // &ep -> &epl + new Transition (2316, 2317), // &epars -> &eparsl + new Transition (2324, 2333), // &epsi -> &epsil + new Transition (2328, 2329), // &Epsi -> &Epsil + new Transition (2345, 2346), // &eqco -> &eqcol + new Transition (2350, 2354), // &eqs -> &eqsl + new Transition (2357, 2362), // &eqslant -> &eqslantl + new Transition (2369, 2370), // &Equa -> &Equal + new Transition (2373, 2374), // &equa -> &equal + new Transition (2378, 2379), // &EqualTi -> &EqualTil + new Transition (2387, 2388), // &Equi -> &Equil + new Transition (2406, 2407), // &eqvpars -> &eqvparsl + new Transition (2448, 2449), // &Eum -> Ë + new Transition (2452, 2453), // &eum -> ë + new Transition (2459, 2460), // &exc -> &excl + new Transition (2489, 2490), // &Exponentia -> &Exponential + new Transition (2499, 2500), // &exponentia -> &exponential + new Transition (2503, 2592), // &f -> &fl + new Transition (2504, 2505), // &fa -> &fal + new Transition (2505, 2506), // &fal -> &fall + new Transition (2526, 2527), // &fema -> &femal + new Transition (2530, 2536), // &ff -> &ffl + new Transition (2531, 2532), // &ffi -> &ffil + new Transition (2536, 2540), // &ffl -> &ffll + new Transition (2549, 2550), // &fi -> &fil + new Transition (2554, 2555), // &Fi -> &Fil + new Transition (2555, 2556), // &Fil -> &Fill + new Transition (2561, 2562), // &FilledSma -> &FilledSmal + new Transition (2562, 2563), // &FilledSmal -> &FilledSmall + new Transition (2577, 2578), // &FilledVerySma -> &FilledVerySmal + new Transition (2578, 2579), // &FilledVerySmal -> &FilledVerySmall + new Transition (2587, 2588), // &fj -> &fjl + new Transition (2592, 2596), // &fl -> &fll + new Transition (2617, 2618), // &ForA -> &ForAl + new Transition (2618, 2619), // &ForAl -> &ForAll + new Transition (2622, 2623), // &fora -> &foral + new Transition (2623, 2624), // &foral -> &forall + new Transition (2686, 2687), // &fras -> &frasl + new Transition (2701, 2824), // &g -> &gl + new Transition (2739, 2740), // &Gcedi -> &Gcedil + new Transition (2763, 2767), // &gE -> &gEl + new Transition (2765, 2769), // &ge -> &gel + new Transition (2775, 2776), // &geqs -> &geqsl + new Transition (2781, 2794), // &ges -> &gesl + new Transition (2790, 2792), // &gesdoto -> &gesdotol + new Transition (2813, 2814), // &gime -> &gimel + new Transition (2875, 2876), // &GreaterEqua -> &GreaterEqual + new Transition (2884, 2885), // &GreaterFu -> &GreaterFul + new Transition (2885, 2886), // &GreaterFul -> &GreaterFull + new Transition (2890, 2891), // &GreaterFullEqua -> &GreaterFullEqual + new Transition (2906, 2907), // &GreaterS -> &GreaterSl + new Transition (2914, 2915), // &GreaterSlantEqua -> &GreaterSlantEqual + new Transition (2918, 2919), // &GreaterTi -> &GreaterTil + new Transition (2932, 2936), // &gsim -> &gsiml + new Transition (2942, 2954), // > -> >l + new Transition (2965, 2993), // >r -> >rl + new Transition (2981, 2982), // >req -> >reql + new Transition (2987, 2988), // >reqq -> >reqql + new Transition (3021, 3027), // &ha -> &hal + new Transition (3031, 3032), // &hami -> &hamil + new Transition (3074, 3084), // &he -> &hel + new Transition (3084, 3085), // &hel -> &hell + new Transition (3100, 3101), // &Hi -> &Hil + new Transition (3137, 3138), // &hook -> &hookl + new Transition (3177, 3178), // &Horizonta -> &Horizontal + new Transition (3188, 3192), // &hs -> &hsl + new Transition (3222, 3223), // &HumpEqua -> &HumpEqual + new Transition (3227, 3228), // &hybu -> &hybul + new Transition (3228, 3229), // &hybul -> &hybull + new Transition (3278, 3279), // &iexc -> ¡ + new Transition (3320, 3321), // &IJ -> &IJl + new Transition (3325, 3326), // &ij -> &ijl + new Transition (3341, 3352), // &imag -> &imagl + new Transition (3372, 3373), // &Imp -> &Impl + new Transition (3401, 3433), // &int -> &intl + new Transition (3404, 3405), // &intca -> &intcal + new Transition (3416, 3417), // &Integra -> &Integral + new Transition (3421, 3422), // &interca -> &intercal + new Transition (3448, 3449), // &Invisib -> &Invisibl + new Transition (3529, 3530), // &Iti -> &Itil + new Transition (3534, 3535), // &iti -> &itil + new Transition (3549, 3550), // &Ium -> Ï + new Transition (3552, 3553), // &ium -> ï + new Transition (3635, 3636), // &Kcedi -> &Kcedil + new Transition (3641, 3642), // &kcedi -> &kcedil + new Transition (3692, 4348), // &l -> &ll + new Transition (3698, 4346), // &L -> &Ll + new Transition (3737, 3741), // &lang -> &langl + new Transition (3746, 3747), // &Lap -> &Lapl + new Transition (3766, 3779), // &larr -> &larrl + new Transition (3782, 3783), // &larrp -> &larrpl + new Transition (3789, 3790), // &larrt -> &larrtl + new Transition (3796, 3797), // &lAtai -> &lAtail + new Transition (3800, 3801), // &latai -> &latail + new Transition (3831, 3832), // &lbrks -> &lbrksl + new Transition (3851, 3852), // &Lcedi -> &Lcedil + new Transition (3856, 3857), // &lcedi -> &lcedil + new Transition (3859, 3860), // &lcei -> &lceil + new Transition (3903, 3904), // &LeftAng -> &LeftAngl + new Transition (3926, 4019), // &left -> &leftl + new Transition (3950, 3951), // &leftarrowtai -> &leftarrowtail + new Transition (3955, 3956), // &LeftCei -> &LeftCeil + new Transition (3964, 3965), // &LeftDoub -> &LeftDoubl + new Transition (3998, 3999), // &LeftF -> &LeftFl + new Transition (4124, 4125), // &LeftTriang -> &LeftTriangl + new Transition (4135, 4136), // &LeftTriangleEqua -> &LeftTriangleEqual + new Transition (4191, 4192), // &leqs -> &leqsl + new Transition (4243, 4244), // &LessEqua -> &LessEqual + new Transition (4254, 4255), // &LessFu -> &LessFul + new Transition (4255, 4256), // &LessFul -> &LessFull + new Transition (4260, 4261), // &LessFullEqua -> &LessFullEqual + new Transition (4284, 4285), // &LessS -> &LessSl + new Transition (4292, 4293), // &LessSlantEqua -> &LessSlantEqual + new Transition (4296, 4297), // &LessTi -> &LessTil + new Transition (4301, 4307), // &lf -> &lfl + new Transition (4330, 4332), // &lharu -> &lharul + new Transition (4334, 4335), // &lhb -> &lhbl + new Transition (4436, 4447), // &Long -> &Longl + new Transition (4458, 4459), // &long -> &longl + new Transition (4548, 4549), // &looparrow -> &looparrowl + new Transition (4560, 4569), // &lop -> &lopl + new Transition (4623, 4625), // &lpar -> &lparl + new Transition (4698, 4720), // < -> <l + new Transition (4767, 4909), // &m -> &ml + new Transition (4768, 4772), // &ma -> &mal + new Transition (4789, 4796), // &mapsto -> &mapstol + new Transition (4839, 4840), // &measuredang -> &measuredangl + new Transition (4843, 4854), // &Me -> &Mel + new Transition (4854, 4855), // &Mel -> &Mell + new Transition (4904, 4905), // &MinusP -> &MinusPl + new Transition (4917, 4918), // &mnp -> &mnpl + new Transition (4924, 4925), // &mode -> &model + new Transition (4952, 4954), // &mu -> &mul + new Transition (4965, 5256), // &n -> &nl + new Transition (4967, 4968), // &nab -> &nabl + new Transition (5005, 5006), // &natura -> &natural + new Transition (5036, 5037), // &Ncedi -> &Ncedil + new Transition (5041, 5042), // &ncedi -> &ncedil + new Transition (5204, 5205), // &ngeqs -> &ngeqsl + new Transition (5272, 5326), // &nL -> &nLl + new Transition (5316, 5317), // &nleqs -> &nleqsl + new Transition (5399, 5400), // &NotDoub -> &NotDoubl + new Transition (5408, 5409), // &NotDoubleVertica -> &NotDoubleVertical + new Transition (5414, 5415), // &NotE -> &NotEl + new Transition (5424, 5425), // &NotEqua -> &NotEqual + new Transition (5428, 5429), // &NotEqualTi -> &NotEqualTil + new Transition (5450, 5451), // &NotGreaterEqua -> &NotGreaterEqual + new Transition (5454, 5455), // &NotGreaterFu -> &NotGreaterFul + new Transition (5455, 5456), // &NotGreaterFul -> &NotGreaterFull + new Transition (5460, 5461), // &NotGreaterFullEqua -> &NotGreaterFullEqual + new Transition (5476, 5477), // &NotGreaterS -> &NotGreaterSl + new Transition (5484, 5485), // &NotGreaterSlantEqua -> &NotGreaterSlantEqual + new Transition (5488, 5489), // &NotGreaterTi -> &NotGreaterTil + new Transition (5509, 5510), // &NotHumpEqua -> &NotHumpEqual + new Transition (5537, 5538), // &NotLeftTriang -> &NotLeftTriangl + new Transition (5548, 5549), // &NotLeftTriangleEqua -> &NotLeftTriangleEqual + new Transition (5557, 5558), // &NotLessEqua -> &NotLessEqual + new Transition (5573, 5574), // &NotLessS -> &NotLessSl + new Transition (5581, 5582), // &NotLessSlantEqua -> &NotLessSlantEqual + new Transition (5585, 5586), // &NotLessTi -> &NotLessTil + new Transition (5642, 5643), // &NotPrecedesEqua -> &NotPrecedesEqual + new Transition (5645, 5646), // &NotPrecedesS -> &NotPrecedesSl + new Transition (5653, 5654), // &NotPrecedesSlantEqua -> &NotPrecedesSlantEqual + new Transition (5663, 5664), // &NotReverseE -> &NotReverseEl + new Transition (5680, 5681), // &NotRightTriang -> &NotRightTriangl + new Transition (5691, 5692), // &NotRightTriangleEqua -> &NotRightTriangleEqual + new Transition (5710, 5711), // &NotSquareSubsetEqua -> &NotSquareSubsetEqual + new Transition (5723, 5724), // &NotSquareSupersetEqua -> &NotSquareSupersetEqual + new Transition (5735, 5736), // &NotSubsetEqua -> &NotSubsetEqual + new Transition (5748, 5749), // &NotSucceedsEqua -> &NotSucceedsEqual + new Transition (5751, 5752), // &NotSucceedsS -> &NotSucceedsSl + new Transition (5759, 5760), // &NotSucceedsSlantEqua -> &NotSucceedsSlantEqual + new Transition (5763, 5764), // &NotSucceedsTi -> &NotSucceedsTil + new Transition (5778, 5779), // &NotSupersetEqua -> &NotSupersetEqual + new Transition (5782, 5783), // &NotTi -> &NotTil + new Transition (5790, 5791), // &NotTildeEqua -> &NotTildeEqual + new Transition (5794, 5795), // &NotTildeFu -> &NotTildeFul + new Transition (5795, 5796), // &NotTildeFul -> &NotTildeFull + new Transition (5800, 5801), // &NotTildeFullEqua -> &NotTildeFullEqual + new Transition (5804, 5805), // &NotTildeTi -> &NotTildeTil + new Transition (5815, 5816), // &NotVertica -> &NotVertical + new Transition (5825, 5826), // &npara -> &nparal + new Transition (5826, 5827), // &nparal -> &nparall + new Transition (5828, 5829), // &nparalle -> &nparallel + new Transition (5831, 5832), // &npars -> &nparsl + new Transition (5836, 5837), // &npo -> &npol + new Transition (5921, 5922), // &nshortpara -> &nshortparal + new Transition (5922, 5923), // &nshortparal -> &nshortparall + new Transition (5924, 5925), // &nshortparalle -> &nshortparallel + new Transition (5988, 6003), // &nt -> &ntl + new Transition (5989, 5990), // &ntg -> &ntgl + new Transition (5993, 5994), // &Nti -> &Ntil + new Transition (5998, 5999), // &nti -> &ntil + new Transition (6010, 6011), // &ntriang -> &ntriangl + new Transition (6012, 6013), // &ntriangle -> &ntrianglel + new Transition (6043, 6084), // &nv -> &nvl + new Transition (6138, 6238), // &o -> &ol + new Transition (6169, 6170), // &Odb -> &Odbl + new Transition (6174, 6175), // &odb -> &odbl + new Transition (6186, 6187), // &odso -> &odsol + new Transition (6190, 6191), // &OE -> &OEl + new Transition (6195, 6196), // &oe -> &oel + new Transition (6302, 6336), // &op -> &opl + new Transition (6311, 6312), // &OpenCur -> &OpenCurl + new Transition (6317, 6318), // &OpenCurlyDoub -> &OpenCurlyDoubl + new Transition (6368, 6369), // &ors -> &orsl + new Transition (6378, 6386), // &Os -> &Osl + new Transition (6382, 6391), // &os -> &osl + new Transition (6396, 6397), // &oso -> &osol + new Transition (6400, 6401), // &Oti -> &Otil + new Transition (6406, 6407), // &oti -> &otil + new Transition (6423, 6424), // &Oum -> Ö + new Transition (6427, 6428), // &oum -> ö + new Transition (6463, 6555), // &p -> &pl + new Transition (6467, 6469), // ¶ -> ¶l + new Transition (6469, 6470), // ¶l -> ¶ll + new Transition (6471, 6472), // ¶lle -> ¶llel + new Transition (6474, 6478), // &pars -> &parsl + new Transition (6482, 6587), // &P -> &Pl + new Transition (6487, 6488), // &Partia -> &Partial + new Transition (6508, 6509), // &permi -> &permil + new Transition (6616, 6617), // &Poincarep -> &Poincarepl + new Transition (6666, 6667), // &preccur -> &preccurl + new Transition (6682, 6683), // &PrecedesEqua -> &PrecedesEqual + new Transition (6685, 6686), // &PrecedesS -> &PrecedesSl + new Transition (6693, 6694), // &PrecedesSlantEqua -> &PrecedesSlantEqual + new Transition (6697, 6698), // &PrecedesTi -> &PrecedesTil + new Transition (6754, 6760), // &prof -> &profl + new Transition (6755, 6756), // &profa -> &profal + new Transition (6780, 6781), // &Proportiona -> &Proportional + new Transition (6792, 6793), // &prure -> &prurel + new Transition (6876, 7442), // &r -> &rl + new Transition (6912, 6918), // &rang -> &rangl + new Transition (6932, 6950), // &rarr -> &rarrl + new Transition (6953, 6954), // &rarrp -> &rarrpl + new Transition (6960, 6961), // &Rarrt -> &Rarrtl + new Transition (6963, 6964), // &rarrt -> &rarrtl + new Transition (6970, 6971), // &rAtai -> &rAtail + new Transition (6975, 6976), // &ratai -> &ratail + new Transition (6982, 6983), // &rationa -> &rational + new Transition (7015, 7016), // &rbrks -> &rbrksl + new Transition (7035, 7036), // &Rcedi -> &Rcedil + new Transition (7040, 7041), // &rcedi -> &rcedil + new Transition (7043, 7044), // &rcei -> &rceil + new Transition (7053, 7057), // &rd -> &rdl + new Transition (7075, 7076), // &rea -> &real + new Transition (7102, 7103), // &ReverseE -> &ReverseEl + new Transition (7112, 7113), // &ReverseEqui -> &ReverseEquil + new Transition (7126, 7127), // &ReverseUpEqui -> &ReverseUpEquil + new Transition (7135, 7141), // &rf -> &rfl + new Transition (7160, 7162), // &rharu -> &rharul + new Transition (7177, 7178), // &RightAng -> &RightAngl + new Transition (7202, 7294), // &right -> &rightl + new Transition (7225, 7226), // &rightarrowtai -> &rightarrowtail + new Transition (7230, 7231), // &RightCei -> &RightCeil + new Transition (7239, 7240), // &RightDoub -> &RightDoubl + new Transition (7273, 7274), // &RightF -> &RightFl + new Transition (7369, 7370), // &RightTriang -> &RightTriangl + new Transition (7380, 7381), // &RightTriangleEqua -> &RightTriangleEqual + new Transition (7481, 7491), // &rop -> &ropl + new Transition (7506, 7507), // &RoundImp -> &RoundImpl + new Transition (7520, 7521), // &rppo -> &rppol + new Transition (7579, 7585), // &rtri -> &rtril + new Transition (7590, 7591), // &Ru -> &Rul + new Transition (7594, 7595), // &RuleDe -> &RuleDel + new Transition (7601, 7602), // &ru -> &rul + new Transition (7617, 7878), // &s -> &sl + new Transition (7655, 7656), // &Scedi -> &Scedil + new Transition (7659, 7660), // &scedi -> &scedil + new Transition (7681, 7682), // &scpo -> &scpol + new Transition (7806, 7807), // &shortpara -> &shortparal + new Transition (7807, 7808), // &shortparal -> &shortparall + new Transition (7809, 7810), // &shortparalle -> &shortparallel + new Transition (7847, 7861), // &sim -> &siml + new Transition (7868, 7869), // &simp -> &simpl + new Transition (7884, 7885), // &Sma -> &Smal + new Transition (7885, 7886), // &Smal -> &Small + new Transition (7890, 7891), // &SmallCirc -> &SmallCircl + new Transition (7895, 7896), // &sma -> &smal + new Transition (7896, 7897), // &smal -> &small + new Transition (7915, 7916), // &smepars -> &smeparsl + new Transition (7918, 7921), // &smi -> &smil + new Transition (7936, 7942), // &so -> &sol + new Transition (8042, 8043), // &SquareSubsetEqua -> &SquareSubsetEqual + new Transition (8055, 8056), // &SquareSupersetEqua -> &SquareSupersetEqual + new Transition (8087, 8088), // &ssmi -> &ssmil + new Transition (8115, 8116), // &straightepsi -> &straightepsil + new Transition (8146, 8147), // &submu -> &submul + new Transition (8155, 8156), // &subp -> &subpl + new Transition (8181, 8182), // &SubsetEqua -> &SubsetEqual + new Transition (8210, 8211), // &succcur -> &succcurl + new Transition (8226, 8227), // &SucceedsEqua -> &SucceedsEqual + new Transition (8229, 8230), // &SucceedsS -> &SucceedsSl + new Transition (8237, 8238), // &SucceedsSlantEqua -> &SucceedsSlantEqual + new Transition (8241, 8242), // &SucceedsTi -> &SucceedsTil + new Transition (8284, 8328), // &sup -> &supl + new Transition (8317, 8318), // &SupersetEqua -> &SupersetEqual + new Transition (8322, 8323), // &suphso -> &suphsol + new Transition (8334, 8335), // &supmu -> &supmul + new Transition (8343, 8344), // &supp -> &suppl + new Transition (8395, 8396), // &sz -> &szl + new Transition (8433, 8434), // &Tcedi -> &Tcedil + new Transition (8438, 8439), // &tcedi -> &tcedil + new Transition (8449, 8450), // &te -> &tel + new Transition (8544, 8545), // &Ti -> &Til + new Transition (8549, 8550), // &ti -> &til + new Transition (8557, 8558), // &TildeEqua -> &TildeEqual + new Transition (8561, 8562), // &TildeFu -> &TildeFul + new Transition (8562, 8563), // &TildeFul -> &TildeFull + new Transition (8567, 8568), // &TildeFullEqua -> &TildeFullEqual + new Transition (8571, 8572), // &TildeTi -> &TildeTil + new Transition (8636, 8637), // &triang -> &triangl + new Transition (8638, 8645), // &triangle -> &trianglel + new Transition (8678, 8679), // &Trip -> &Tripl + new Transition (8685, 8686), // &trip -> &tripl + new Transition (8746, 8747), // &twohead -> &twoheadl + new Transition (8775, 8887), // &u -> &ul + new Transition (8835, 8836), // &Udb -> &Udbl + new Transition (8840, 8841), // &udb -> &udbl + new Transition (8878, 8879), // &uhar -> &uharl + new Transition (8883, 8884), // &uhb -> &uhbl + new Transition (8909, 8914), // &um -> ¨ + new Transition (8949, 8950), // &UnionP -> &UnionPl + new Transition (8983, 9064), // &up -> &upl + new Transition (9037, 9038), // &UpEqui -> &UpEquil + new Transition (9052, 9053), // &upharpoon -> &upharpoonl + new Transition (9093, 9100), // &Upsi -> &Upsil + new Transition (9096, 9104), // &upsi -> &upsil + new Transition (9167, 9168), // &Uti -> &Util + new Transition (9172, 9173), // &uti -> &util + new Transition (9188, 9189), // &Uum -> Ü + new Transition (9191, 9192), // &uum -> ü + new Transition (9197, 9198), // &uwang -> &uwangl + new Transition (9201, 9420), // &v -> &vl + new Transition (9212, 9213), // &varepsi -> &varepsil + new Transition (9289, 9290), // &vartriang -> &vartriangl + new Transition (9291, 9292), // &vartriangle -> &vartrianglel + new Transition (9328, 9340), // &Vdash -> &Vdashl + new Transition (9345, 9355), // &ve -> &vel + new Transition (9355, 9356), // &vel -> &vell + new Transition (9376, 9377), // &Vertica -> &Vertical + new Transition (9398, 9399), // &VerticalTi -> &VerticalTil + new Transition (9548, 9585), // &x -> &xl + new Transition (9611, 9614), // &xop -> &xopl + new Transition (9646, 9647), // &xup -> &xupl + new Transition (9741, 9742), // &Yum -> &Yuml + new Transition (9744, 9745) // &yum -> ÿ + }; + TransitionTable_m = new Transition[177] { + new Transition (0, 4767), // & -> &m + new Transition (1, 98), // &A -> &Am + new Transition (8, 103), // &a -> &am + new Transition (83, 84), // &alefsy -> &alefsym + new Transition (136, 143), // &ang -> &angm + new Transition (262, 263), // &asy -> &asym + new Transition (281, 282), // &Au -> &Aum + new Transition (285, 286), // &au -> &aum + new Transition (320, 321), // &backpri -> &backprim + new Transition (325, 326), // &backsi -> &backsim + new Transition (384, 399), // &be -> &bem + new Transition (466, 467), // &bigoti -> &bigotim + new Transition (605, 606), // &botto -> &bottom + new Transition (613, 656), // &box -> &boxm + new Transition (668, 669), // &boxti -> &boxtim + new Transition (721, 722), // &bpri -> &bprim + new Transition (748, 749), // &bse -> &bsem + new Transition (752, 753), // &bsi -> &bsim + new Transition (767, 774), // &bu -> &bum + new Transition (781, 782), // &Bu -> &Bum + new Transition (904, 905), // &ccupss -> &ccupssm + new Transition (915, 927), // &ce -> &cem + new Transition (966, 968), // &check -> &checkm + new Transition (979, 1059), // &cir -> &cirm + new Transition (1044, 1045), // &CircleTi -> &CircleTim + new Transition (1131, 1142), // &co -> &com + new Transition (1142, 1143), // &com -> &comm + new Transition (1154, 1155), // &comple -> &complem + new Transition (1349, 1351), // &curarr -> &curarrm + new Transition (1516, 1529), // &de -> &dem + new Transition (1558, 1603), // &Dia -> &Diam + new Transition (1600, 1601), // &dia -> &diam + new Transition (1634, 1635), // &diga -> &digam + new Transition (1635, 1636), // &digam -> &digamm + new Transition (1652, 1653), // ÷onti -> ÷ontim + new Transition (1694, 1713), // &dot -> &dotm + new Transition (2108, 2228), // &E -> &Em + new Transition (2115, 2233), // &e -> &em + new Transition (2207, 2208), // &Ele -> &Elem + new Transition (2249, 2250), // &EmptyS -> &EmptySm + new Transition (2267, 2268), // &EmptyVeryS -> &EmptyVerySm + new Transition (2351, 2352), // &eqsi -> &eqsim + new Transition (2393, 2394), // &Equilibriu -> &Equilibrium + new Transition (2430, 2431), // &Esi -> &Esim + new Transition (2433, 2434), // &esi -> &esim + new Transition (2447, 2448), // &Eu -> &Eum + new Transition (2451, 2452), // &eu -> &eum + new Transition (2524, 2525), // &fe -> &fem + new Transition (2559, 2560), // &FilledS -> &FilledSm + new Transition (2575, 2576), // &FilledVeryS -> &FilledVerySm + new Transition (2702, 2714), // &ga -> &gam + new Transition (2709, 2710), // &Ga -> &Gam + new Transition (2710, 2711), // &Gam -> &Gamm + new Transition (2714, 2715), // &gam -> &gamm + new Transition (2811, 2812), // &gi -> &gim + new Transition (2850, 2851), // &gnsi -> &gnsim + new Transition (2931, 2932), // &gsi -> &gsim + new Transition (2999, 3000), // >rsi -> >rsim + new Transition (3021, 3030), // &ha -> &ham + new Transition (3126, 3131), // &ho -> &hom + new Transition (3207, 3208), // &Hu -> &Hum + new Transition (3215, 3216), // &HumpDownHu -> &HumpDownHum + new Transition (3236, 3330), // &I -> &Im + new Transition (3243, 3336), // &i -> &im + new Transition (3452, 3453), // &InvisibleCo -> &InvisibleCom + new Transition (3453, 3454), // &InvisibleCom -> &InvisibleComm + new Transition (3458, 3459), // &InvisibleTi -> &InvisibleTim + new Transition (3539, 3549), // &Iu -> &Ium + new Transition (3544, 3552), // &iu -> &ium + new Transition (3561, 3577), // &j -> &jm + new Transition (3692, 4385), // &l -> &lm + new Transition (3698, 4379), // &L -> &Lm + new Transition (3699, 3723), // &La -> &Lam + new Transition (3705, 3728), // &la -> &lam + new Transition (3711, 3712), // &lae -> &laem + new Transition (3786, 3787), // &larrsi -> &larrsim + new Transition (4115, 4116), // &leftthreeti -> &leftthreetim + new Transition (4281, 4282), // &lesssi -> &lesssim + new Transition (4419, 4420), // &lnsi -> &lnsim + new Transition (4458, 4502), // &long -> &longm + new Transition (4574, 4575), // &loti -> &lotim + new Transition (4628, 4646), // &lr -> &lrm + new Transition (4669, 4670), // &lsi -> &lsim + new Transition (4715, 4716), // <i -> <im + new Transition (4810, 4811), // &mco -> &mcom + new Transition (4811, 4812), // &mcom -> &mcomm + new Transition (4846, 4847), // &Mediu -> &Medium + new Transition (4952, 4961), // &mu -> &mum + new Transition (4956, 4957), // &multi -> &multim + new Transition (4965, 5343), // &n -> &nm + new Transition (5014, 5015), // &nbu -> &nbum + new Transition (5095, 5096), // &NegativeMediu -> &NegativeMedium + new Transition (5145, 5146), // &nesi -> &nesim + new Transition (5216, 5217), // &ngsi -> &ngsim + new Transition (5329, 5330), // &nlsi -> &nlsim + new Transition (5416, 5417), // &NotEle -> &NotElem + new Transition (5494, 5495), // &NotHu -> &NotHum + new Transition (5502, 5503), // &NotHumpDownHu -> &NotHumpDownHum + new Transition (5665, 5666), // &NotReverseEle -> &NotReverseElem + new Transition (5895, 5934), // &ns -> &nsm + new Transition (5913, 5914), // &nshort -> &nshortm + new Transition (5927, 5928), // &nsi -> &nsim + new Transition (6032, 6034), // &nu -> &num + new Transition (6108, 6109), // &nvsi -> &nvsim + new Transition (6131, 6258), // &O -> &Om + new Transition (6138, 6263), // &o -> &om + new Transition (6227, 6232), // &oh -> &ohm + new Transition (6348, 6358), // &ord -> º + new Transition (6400, 6411), // &Oti -> &Otim + new Transition (6406, 6415), // &oti -> &otim + new Transition (6422, 6423), // &Ou -> &Oum + new Transition (6426, 6427), // &ou -> &oum + new Transition (6463, 6607), // &p -> &pm + new Transition (6475, 6476), // &parsi -> &parsim + new Transition (6498, 6507), // &per -> &perm + new Transition (6527, 6532), // &ph -> &phm + new Transition (6532, 6533), // &phm -> &phmm + new Transition (6567, 6596), // &plus -> &plusm + new Transition (6600, 6601), // &plussi -> &plussim + new Transition (6718, 6719), // &precnsi -> &precnsim + new Transition (6722, 6723), // &precsi -> &precsim + new Transition (6725, 6726), // &Pri -> &Prim + new Transition (6729, 6730), // &pri -> &prim + new Transition (6742, 6743), // &prnsi -> &prnsim + new Transition (6787, 6788), // &prsi -> &prsim + new Transition (6835, 6836), // &qpri -> &qprim + new Transition (6876, 7453), // &r -> &rm + new Transition (6901, 6902), // &rae -> &raem + new Transition (6957, 6958), // &rarrsi -> &rarrsim + new Transition (7104, 7105), // &ReverseEle -> &ReverseElem + new Transition (7118, 7119), // &ReverseEquilibriu -> &ReverseEquilibrium + new Transition (7132, 7133), // &ReverseUpEquilibriu -> &ReverseUpEquilibrium + new Transition (7360, 7361), // &rightthreeti -> &rightthreetim + new Transition (7442, 7451), // &rl -> &rlm + new Transition (7464, 7465), // &rn -> &rnm + new Transition (7496, 7497), // &roti -> &rotim + new Transition (7504, 7505), // &RoundI -> &RoundIm + new Transition (7573, 7574), // &rti -> &rtim + new Transition (7610, 7883), // &S -> &Sm + new Transition (7617, 7894), // &s -> &sm + new Transition (7677, 7678), // &scnsi -> &scnsim + new Transition (7688, 7689), // &scsi -> &scsim + new Transition (7703, 7721), // &se -> &sem + new Transition (7729, 7730), // &set -> &setm + new Transition (7798, 7799), // &short -> &shortm + new Transition (7834, 7835), // &Sig -> &Sigm + new Transition (7838, 7847), // &si -> &sim + new Transition (7839, 7840), // &sig -> &sigm + new Transition (7900, 7901), // &smallset -> &smallsetm + new Transition (8077, 8086), // &ss -> &ssm + new Transition (8082, 8083), // &sset -> &ssetm + new Transition (8127, 8275), // &Su -> &Sum + new Transition (8130, 8277), // &su -> &sum + new Transition (8131, 8145), // &sub -> &subm + new Transition (8190, 8191), // &subsi -> &subsim + new Transition (8262, 8263), // &succnsi -> &succnsim + new Transition (8266, 8267), // &succsi -> &succsim + new Transition (8284, 8333), // &sup -> &supm + new Transition (8367, 8368), // &supsi -> &supsim + new Transition (8488, 8489), // &thetasy -> &thetasym + new Transition (8504, 8505), // &thicksi -> &thicksim + new Transition (8532, 8533), // &thksi -> &thksim + new Transition (8549, 8576), // &ti -> &tim + new Transition (8619, 8620), // &tpri -> &tprim + new Transition (8633, 8670), // &tri -> &trim + new Transition (8694, 8695), // &triti -> &tritim + new Transition (8702, 8703), // &trpeziu -> &trpezium + new Transition (8768, 8904), // &U -> &Um + new Transition (8775, 8909), // &u -> &um + new Transition (9043, 9044), // &UpEquilibriu -> &UpEquilibrium + new Transition (9182, 9191), // &uu -> &uum + new Transition (9187, 9188), // &Uu -> &Uum + new Transition (9254, 9255), // &varsig -> &varsigm + new Transition (9548, 9594), // &x -> &xm + new Transition (9619, 9620), // &xoti -> &xotim + new Transition (9736, 9744), // &yu -> &yum + new Transition (9740, 9741) // &Yu -> &Yum + }; + TransitionTable_n = new Transition[303] { + new Transition (0, 4965), // & -> &n + new Transition (1, 116), // &A -> &An + new Transition (8, 119), // &a -> &an + new Transition (122, 123), // &anda -> &andan + new Transition (185, 186), // &Aogo -> &Aogon + new Transition (190, 191), // &aogo -> &aogon + new Transition (221, 222), // &ApplyFu -> &ApplyFun + new Transition (226, 227), // &ApplyFunctio -> &ApplyFunction + new Transition (238, 239), // &Ari -> &Arin + new Transition (243, 244), // &ari -> &arin + new Transition (257, 258), // &Assig -> &Assign + new Transition (291, 292), // &awco -> &awcon + new Transition (293, 294), // &awconi -> &awconin + new Transition (297, 298), // &awi -> &awin + new Transition (301, 579), // &b -> &bn + new Transition (306, 307), // &backco -> &backcon + new Transition (315, 316), // &backepsilo -> &backepsilon + new Transition (370, 371), // &bco -> &bcon + new Transition (409, 410), // &ber -> &bern + new Transition (414, 415), // &Ber -> &Bern + new Transition (433, 434), // &betwee -> &between + new Transition (484, 485), // &bigtria -> &bigtrian + new Transition (491, 492), // &bigtriangledow -> &bigtriangledown + new Transition (520, 563), // &bla -> &blan + new Transition (526, 527), // &blackloze -> &blacklozen + new Transition (541, 542), // &blacktria -> &blacktrian + new Transition (549, 550), // &blacktriangledow -> &blacktriangledown + new Transition (657, 658), // &boxmi -> &boxmin + new Transition (807, 808), // &capa -> &capan + new Transition (838, 839), // &CapitalDiffere -> &CapitalDifferen + new Transition (852, 853), // &caro -> &caron + new Transition (869, 870), // &Ccaro -> &Ccaron + new Transition (873, 874), // &ccaro -> &ccaron + new Transition (894, 895), // &Cco -> &Ccon + new Transition (896, 897), // &Cconi -> &Cconin + new Transition (915, 933), // &ce -> &cen + new Transition (920, 936), // &Ce -> &Cen + new Transition (1033, 1034), // &CircleMi -> &CircleMin + new Transition (1053, 1054), // &cirf -> &cirfn + new Transition (1055, 1056), // &cirfni -> &cirfnin + new Transition (1077, 1078), // &ClockwiseCo -> &ClockwiseCon + new Transition (1083, 1084), // &ClockwiseContourI -> &ClockwiseContourIn + new Transition (1126, 1171), // &Co -> &Con + new Transition (1128, 1129), // &Colo -> &Colon + new Transition (1131, 1164), // &co -> &con + new Transition (1133, 1134), // &colo -> &colon + new Transition (1150, 1151), // &compf -> &compfn + new Transition (1156, 1157), // &compleme -> &complemen + new Transition (1175, 1176), // &Congrue -> &Congruen + new Transition (1179, 1180), // &Coni -> &Conin + new Transition (1183, 1184), // &coni -> &conin + new Transition (1191, 1192), // &ContourI -> &ContourIn + new Transition (1226, 1227), // &Cou -> &Coun + new Transition (1241, 1242), // &CounterClockwiseCo -> &CounterClockwiseCon + new Transition (1247, 1248), // &CounterClockwiseContourI -> &CounterClockwiseContourIn + new Transition (1378, 1379), // &curre -> ¤ + new Transition (1409, 1410), // &cwco -> &cwcon + new Transition (1411, 1412), // &cwconi -> &cwconin + new Transition (1415, 1416), // &cwi -> &cwin + new Transition (1477, 1478), // &Dcaro -> &Dcaron + new Transition (1483, 1484), // &dcaro -> &dcaron + new Transition (1604, 1605), // &Diamo -> &Diamon + new Transition (1608, 1609), // &diamo -> &diamon + new Transition (1625, 1626), // &Differe -> &Differen + new Transition (1640, 1641), // &disi -> &disin + new Transition (1649, 1650), // ÷o -> ÷on + new Transition (1657, 1658), // &divo -> &divon + new Transition (1672, 1673), // &dlcor -> &dlcorn + new Transition (1714, 1715), // &dotmi -> &dotmin + new Transition (1749, 1750), // &DoubleCo -> &DoubleCon + new Transition (1755, 1756), // &DoubleContourI -> &DoubleContourIn + new Transition (1768, 1769), // &DoubleDow -> &DoubleDown + new Transition (1801, 1802), // &DoubleLo -> &DoubleLon + new Transition (1861, 1862), // &DoubleUpDow -> &DoubleUpDown + new Transition (1881, 1882), // &Dow -> &Down + new Transition (1895, 1896), // &dow -> &down + new Transition (1923, 1924), // &downdow -> &downdown + new Transition (1937, 1938), // &downharpoo -> &downharpoon + new Transition (2033, 2034), // &drcor -> &drcorn + new Transition (2087, 2088), // &dwa -> &dwan + new Transition (2115, 2290), // &e -> &en + new Transition (2130, 2131), // &Ecaro -> &Ecaron + new Transition (2136, 2137), // &ecaro -> &ecaron + new Transition (2150, 2151), // &ecolo -> &ecolon + new Transition (2209, 2210), // &Eleme -> &Elemen + new Transition (2213, 2214), // &eli -> &elin + new Transition (2298, 2299), // &Eogo -> &Eogon + new Transition (2303, 2304), // &eogo -> &eogon + new Transition (2330, 2331), // &Epsilo -> &Epsilon + new Transition (2334, 2335), // &epsilo -> &epsilon + new Transition (2347, 2348), // &eqcolo -> &eqcolon + new Transition (2355, 2356), // &eqsla -> &eqslan + new Transition (2479, 2480), // &expectatio -> &expectation + new Transition (2483, 2484), // &Expo -> &Expon + new Transition (2485, 2486), // &Expone -> &Exponen + new Transition (2493, 2494), // &expo -> &expon + new Transition (2495, 2496), // &expone -> &exponen + new Transition (2503, 2604), // &f -> &fn + new Transition (2507, 2508), // &falli -> &fallin + new Transition (2600, 2601), // &flt -> &fltn + new Transition (2643, 2644), // &fparti -> &fpartin + new Transition (2690, 2691), // &frow -> &frown + new Transition (2701, 2832), // &g -> &gn + new Transition (2777, 2778), // &geqsla -> &geqslan + new Transition (2908, 2909), // &GreaterSla -> &GreaterSlan + new Transition (3002, 3011), // &gv -> &gvn + new Transition (3005, 3006), // &gvert -> &gvertn + new Transition (3091, 3092), // &herco -> &hercon + new Transition (3174, 3175), // &Horizo -> &Horizon + new Transition (3180, 3181), // &HorizontalLi -> &HorizontalLin + new Transition (3212, 3213), // &HumpDow -> &HumpDown + new Transition (3233, 3234), // &hyphe -> &hyphen + new Transition (3236, 3398), // &I -> &In + new Transition (3243, 3378), // &i -> &in + new Transition (3301, 3311), // &ii -> &iin + new Transition (3303, 3308), // &iii -> &iiin + new Transition (3304, 3305), // &iiii -> &iiiin + new Transition (3313, 3314), // &iinfi -> &iinfin + new Transition (3345, 3346), // &Imagi -> &Imagin + new Transition (3353, 3354), // &imagli -> &imaglin + new Transition (3386, 3387), // &infi -> &infin + new Transition (3430, 3431), // &Intersectio -> &Intersection + new Transition (3473, 3474), // &Iogo -> &Iogon + new Transition (3477, 3478), // &iogo -> &iogon + new Transition (3511, 3512), // &isi -> &isin + new Transition (3657, 3658), // &kgree -> &kgreen + new Transition (3692, 4401), // &l -> &ln + new Transition (3699, 3733), // &La -> &Lan + new Transition (3705, 3736), // &la -> &lan + new Transition (3720, 3721), // &lagra -> &lagran + new Transition (3840, 3841), // &Lcaro -> &Lcaron + new Transition (3846, 3847), // &lcaro -> &lcaron + new Transition (3901, 3902), // &LeftA -> &LeftAn + new Transition (3957, 3958), // &LeftCeili -> &LeftCeilin + new Transition (3975, 3976), // &LeftDow -> &LeftDown + new Transition (4009, 4010), // &leftharpoo -> &leftharpoon + new Transition (4013, 4014), // &leftharpoondow -> &leftharpoondown + new Transition (4070, 4071), // &leftrightharpoo -> &leftrightharpoon + new Transition (4122, 4123), // &LeftTria -> &LeftTrian + new Transition (4142, 4143), // &LeftUpDow -> &LeftUpDown + new Transition (4193, 4194), // &leqsla -> &leqslan + new Transition (4286, 4287), // &LessSla -> &LessSlan + new Transition (4356, 4357), // &llcor -> &llcorn + new Transition (4422, 4457), // &lo -> &lon + new Transition (4423, 4424), // &loa -> &loan + new Transition (4434, 4435), // &Lo -> &Lon + new Transition (4614, 4615), // &loze -> &lozen + new Transition (4635, 4636), // &lrcor -> &lrcorn + new Transition (4755, 4764), // &lv -> &lvn + new Transition (4758, 4759), // &lvert -> &lvertn + new Transition (4767, 4916), // &m -> &mn + new Transition (4793, 4794), // &mapstodow -> &mapstodown + new Transition (4837, 4838), // &measureda -> &measuredan + new Transition (4856, 4857), // &Melli -> &Mellin + new Transition (4871, 4890), // &mi -> &min + new Transition (4900, 4901), // &Mi -> &Min + new Transition (4966, 4983), // &na -> &nan + new Transition (5027, 5028), // &Ncaro -> &Ncaron + new Transition (5031, 5032), // &ncaro -> &ncaron + new Transition (5044, 5045), // &nco -> &ncon + new Transition (5105, 5114), // &NegativeThi -> &NegativeThin + new Transition (5127, 5128), // &NegativeVeryThi -> &NegativeVeryThin + new Transition (5178, 5179), // &NewLi -> &NewLin + new Transition (5206, 5207), // &ngeqsla -> &ngeqslan + new Transition (5318, 5319), // &nleqsla -> &nleqslan + new Transition (5347, 5354), // &No -> &Non + new Transition (5360, 5361), // &NonBreaki -> &NonBreakin + new Transition (5378, 5620), // ¬ -> ¬n + new Transition (5381, 5382), // &NotCo -> &NotCon + new Transition (5386, 5387), // &NotCongrue -> &NotCongruen + new Transition (5418, 5419), // &NotEleme -> &NotElemen + new Transition (5478, 5479), // &NotGreaterSla -> &NotGreaterSlan + new Transition (5499, 5500), // &NotHumpDow -> &NotHumpDown + new Transition (5512, 5513), // ¬i -> ¬in + new Transition (5535, 5536), // &NotLeftTria -> &NotLeftTrian + new Transition (5575, 5576), // &NotLessSla -> &NotLessSlan + new Transition (5647, 5648), // &NotPrecedesSla -> &NotPrecedesSlan + new Transition (5667, 5668), // &NotReverseEleme -> &NotReverseElemen + new Transition (5678, 5679), // &NotRightTria -> &NotRightTrian + new Transition (5753, 5754), // &NotSucceedsSla -> &NotSucceedsSlan + new Transition (5838, 5839), // &npoli -> &npolin + new Transition (6008, 6009), // &ntria -> &ntrian + new Transition (6078, 6079), // &nvi -> &nvin + new Transition (6081, 6082), // &nvinfi -> &nvinfin + new Transition (6111, 6126), // &nw -> &nwn + new Transition (6211, 6212), // &ogo -> &ogon + new Transition (6234, 6235), // &oi -> &oin + new Transition (6252, 6253), // &oli -> &olin + new Transition (6279, 6280), // &Omicro -> &Omicron + new Transition (6282, 6290), // &omi -> &omin + new Transition (6285, 6286), // &omicro -> &omicron + new Transition (6307, 6308), // &Ope -> &Open + new Transition (6454, 6455), // &OverPare -> &OverParen + new Transition (6499, 6500), // &perc -> &percn + new Transition (6514, 6515), // &perte -> &perten + new Transition (6537, 6538), // &pho -> &phon + new Transition (6556, 6557), // &pla -> &plan + new Transition (6591, 6592), // &PlusMi -> &PlusMin + new Transition (6596, 6597), // &plusm -> ± + new Transition (6610, 6611), // &Poi -> &Poin + new Transition (6618, 6619), // &Poincarepla -> &Poincareplan + new Transition (6623, 6624), // &poi -> &poin + new Transition (6626, 6627), // &pointi -> &pointin + new Transition (6636, 6637), // &pou -> &poun + new Transition (6642, 6735), // &pr -> &prn + new Transition (6655, 6705), // &prec -> &precn + new Transition (6687, 6688), // &PrecedesSla -> &PrecedesSlan + new Transition (6761, 6762), // &profli -> &proflin + new Transition (6777, 6778), // &Proportio -> &Proportion + new Transition (6807, 6808), // &pu -> &pun + new Transition (6821, 6822), // &qi -> &qin + new Transition (6851, 6852), // &quater -> &quatern + new Transition (6854, 6855), // &quaternio -> &quaternion + new Transition (6858, 6859), // &quati -> &quatin + new Transition (6876, 7464), // &r -> &rn + new Transition (6882, 6911), // &ra -> &ran + new Transition (6887, 6908), // &Ra -> &Ran + new Transition (6979, 6981), // &ratio -> &ration + new Transition (7024, 7025), // &Rcaro -> &Rcaron + new Transition (7030, 7031), // &rcaro -> &rcaron + new Transition (7078, 7079), // &reali -> &realin + new Transition (7106, 7107), // &ReverseEleme -> &ReverseElemen + new Transition (7175, 7176), // &RightA -> &RightAn + new Transition (7199, 7428), // &ri -> &rin + new Transition (7232, 7233), // &RightCeili -> &RightCeilin + new Transition (7250, 7251), // &RightDow -> &RightDown + new Transition (7284, 7285), // &rightharpoo -> &rightharpoon + new Transition (7288, 7289), // &rightharpoondow -> &rightharpoondown + new Transition (7310, 7311), // &rightleftharpoo -> &rightleftharpoon + new Transition (7367, 7368), // &RightTria -> &RightTrian + new Transition (7387, 7388), // &RightUpDow -> &RightUpDown + new Transition (7432, 7433), // &risi -> &risin + new Transition (7470, 7471), // &roa -> &roan + new Transition (7501, 7502), // &Rou -> &Roun + new Transition (7522, 7523), // &rppoli -> &rppolin + new Transition (7631, 7670), // &sc -> &scn + new Transition (7638, 7639), // &Scaro -> &Scaron + new Transition (7642, 7643), // &scaro -> &scaron + new Transition (7683, 7684), // &scpoli -> &scpolin + new Transition (7730, 7736), // &setm -> &setmn + new Transition (7731, 7732), // &setmi -> &setmin + new Transition (7748, 7749), // &sfrow -> &sfrown + new Transition (7778, 7779), // &ShortDow -> &ShortDown + new Transition (7847, 7865), // &sim -> &simn + new Transition (7902, 7903), // &smallsetmi -> &smallsetmin + new Transition (8019, 8020), // &SquareI -> &SquareIn + new Transition (8029, 8030), // &SquareIntersectio -> &SquareIntersection + new Transition (8058, 8059), // &SquareU -> &SquareUn + new Transition (8061, 8062), // &SquareUnio -> &SquareUnion + new Transition (8083, 8084), // &ssetm -> &ssetmn + new Transition (8106, 8124), // &str -> &strn + new Transition (8117, 8118), // &straightepsilo -> &straightepsilon + new Transition (8130, 8279), // &su -> &sun + new Transition (8131, 8150), // &sub -> &subn + new Transition (8171, 8184), // &subset -> &subsetn + new Transition (8199, 8249), // &succ -> &succn + new Transition (8231, 8232), // &SucceedsSla -> &SucceedsSlan + new Transition (8284, 8338), // &sup -> &supn + new Transition (8354, 8361), // &supset -> &supsetn + new Transition (8375, 8390), // &sw -> &swn + new Transition (8422, 8423), // &Tcaro -> &Tcaron + new Transition (8428, 8429), // &tcaro -> &tcaron + new Transition (8493, 8516), // &thi -> &thin + new Transition (8507, 8520), // &Thi -> &Thin + new Transition (8541, 8542), // &thor -> þ + new Transition (8549, 8587), // &ti -> &tin + new Transition (8634, 8635), // &tria -> &trian + new Transition (8642, 8643), // &triangledow -> &triangledown + new Transition (8671, 8672), // &trimi -> &trimin + new Transition (8768, 8916), // &U -> &Un + new Transition (8890, 8891), // &ulcor -> &ulcorn + new Transition (8936, 8937), // &UnderPare -> &UnderParen + new Transition (8946, 8947), // &Unio -> &Union + new Transition (8956, 8957), // &Uogo -> &Uogon + new Transition (8961, 8962), // &uogo -> &uogon + new Transition (8996, 8997), // &UpArrowDow -> &UpArrowDown + new Transition (9006, 9007), // &UpDow -> &UpDown + new Transition (9016, 9017), // &Updow -> &Updown + new Transition (9026, 9027), // &updow -> &updown + new Transition (9051, 9052), // &upharpoo -> &upharpoon + new Transition (9101, 9102), // &Upsilo -> &Upsilon + new Transition (9105, 9106), // &upsilo -> &upsilon + new Transition (9130, 9131), // &urcor -> &urcorn + new Transition (9141, 9142), // &Uri -> &Urin + new Transition (9145, 9146), // &uri -> &urin + new Transition (9195, 9196), // &uwa -> &uwan + new Transition (9201, 9425), // &v -> &vn + new Transition (9202, 9203), // &va -> &van + new Transition (9208, 9223), // &var -> &varn + new Transition (9214, 9215), // &varepsilo -> &varepsilon + new Transition (9227, 9228), // &varnothi -> &varnothin + new Transition (9262, 9263), // &varsubset -> &varsubsetn + new Transition (9272, 9273), // &varsupset -> &varsupsetn + new Transition (9287, 9288), // &vartria -> &vartrian + new Transition (9383, 9384), // &VerticalLi -> &VerticalLin + new Transition (9406, 9407), // &VeryThi -> &VeryThin + new Transition (9459, 9460), // &vsub -> &vsubn + new Transition (9465, 9466), // &vsup -> &vsupn + new Transition (9548, 9598), // &x -> &xn + new Transition (9699, 9700), // &ye -> ¥ + new Transition (9764, 9765), // &Zcaro -> &Zcaron + new Transition (9770, 9771), // &zcaro -> &zcaron + new Transition (9848, 9851) // &zw -> &zwn + }; + TransitionTable_o = new Transition[460] { + new Transition (0, 6138), // & -> &o + new Transition (1, 183), // &A -> &Ao + new Transition (8, 188), // &a -> &ao + new Transition (129, 130), // &andsl -> &andslo + new Transition (184, 185), // &Aog -> &Aogo + new Transition (189, 190), // &aog -> &aogo + new Transition (199, 213), // &ap -> &apo + new Transition (225, 226), // &ApplyFuncti -> &ApplyFunctio + new Transition (230, 231), // &appr -> &appro + new Transition (290, 291), // &awc -> &awco + new Transition (301, 598), // &b -> &bo + new Transition (305, 306), // &backc -> &backco + new Transition (314, 315), // &backepsil -> &backepsilo + new Transition (331, 594), // &B -> &Bo + new Transition (369, 370), // &bc -> &bco + new Transition (381, 382), // &bdqu -> &bdquo + new Transition (410, 411), // &bern -> &berno + new Transition (415, 416), // &Bern -> &Berno + new Transition (443, 455), // &big -> &bigo + new Transition (456, 457), // &bigod -> &bigodo + new Transition (489, 490), // &bigtriangled -> &bigtriangledo + new Transition (515, 516), // &bkar -> &bkaro + new Transition (519, 575), // &bl -> &blo + new Transition (523, 524), // &blackl -> &blacklo + new Transition (547, 548), // &blacktriangled -> &blacktriangledo + new Transition (579, 591), // &bn -> &bno + new Transition (587, 588), // &bN -> &bNo + new Transition (604, 605), // &bott -> &botto + new Transition (614, 615), // &boxb -> &boxbo + new Transition (744, 757), // &bs -> &bso + new Transition (789, 1126), // &C -> &Co + new Transition (796, 1131), // &c -> &co + new Transition (824, 825), // &capd -> &capdo + new Transition (848, 852), // &car -> &caro + new Transition (866, 894), // &Cc -> &Cco + new Transition (868, 869), // &Ccar -> &Ccaro + new Transition (872, 873), // &ccar -> &ccaro + new Transition (907, 908), // &Cd -> &Cdo + new Transition (911, 912), // &cd -> &cdo + new Transition (940, 941), // &CenterD -> &CenterDo + new Transition (946, 947), // ¢erd -> ¢erdo + new Transition (990, 991), // &circlearr -> &circlearro + new Transition (1024, 1025), // &CircleD -> &CircleDo + new Transition (1068, 1069), // &Cl -> &Clo + new Transition (1076, 1077), // &ClockwiseC -> &ClockwiseCo + new Transition (1079, 1080), // &ClockwiseCont -> &ClockwiseConto + new Transition (1099, 1100), // &CloseCurlyD -> &CloseCurlyDo + new Transition (1106, 1107), // &CloseCurlyDoubleQu -> &CloseCurlyDoubleQuo + new Transition (1112, 1113), // &CloseCurlyQu -> &CloseCurlyQuo + new Transition (1127, 1128), // &Col -> &Colo + new Transition (1132, 1133), // &col -> &colo + new Transition (1167, 1168), // &congd -> &congdo + new Transition (1187, 1188), // &Cont -> &Conto + new Transition (1206, 1207), // &copr -> &copro + new Transition (1210, 1211), // &Copr -> &Copro + new Transition (1232, 1233), // &CounterCl -> &CounterClo + new Transition (1240, 1241), // &CounterClockwiseC -> &CounterClockwiseCo + new Transition (1243, 1244), // &CounterClockwiseCont -> &CounterClockwiseConto + new Transition (1256, 1266), // &cr -> &cro + new Transition (1261, 1262), // &Cr -> &Cro + new Transition (1288, 1289), // &ctd -> &ctdo + new Transition (1318, 1341), // &cup -> &cupo + new Transition (1337, 1338), // &cupd -> &cupdo + new Transition (1385, 1386), // &curvearr -> &curvearro + new Transition (1408, 1409), // &cwc -> &cwco + new Transition (1425, 1685), // &D -> &Do + new Transition (1432, 1679), // &d -> &do + new Transition (1466, 1467), // &dbkar -> &dbkaro + new Transition (1476, 1477), // &Dcar -> &Dcaro + new Transition (1482, 1483), // &dcar -> &dcaro + new Transition (1490, 1503), // &DD -> &DDo + new Transition (1492, 1510), // &dd -> &ddo + new Transition (1573, 1574), // &DiacriticalD -> &DiacriticalDo + new Transition (1601, 1608), // &diam -> &diamo + new Transition (1603, 1604), // &Diam -> &Diamo + new Transition (1643, 1657), // &div -> &divo + new Transition (1647, 1649), // ÷ -> ÷o + new Transition (1670, 1671), // &dlc -> &dlco + new Transition (1675, 1676), // &dlcr -> &dlcro + new Transition (1696, 1697), // &DotD -> &DotDo + new Transition (1703, 1704), // &doteqd -> &doteqdo + new Transition (1748, 1749), // &DoubleC -> &DoubleCo + new Transition (1751, 1752), // &DoubleCont -> &DoubleConto + new Transition (1764, 1765), // &DoubleD -> &DoubleDo + new Transition (1772, 1773), // &DoubleDownArr -> &DoubleDownArro + new Transition (1776, 1801), // &DoubleL -> &DoubleLo + new Transition (1782, 1783), // &DoubleLeftArr -> &DoubleLeftArro + new Transition (1793, 1794), // &DoubleLeftRightArr -> &DoubleLeftRightArro + new Transition (1810, 1811), // &DoubleLongLeftArr -> &DoubleLongLeftArro + new Transition (1821, 1822), // &DoubleLongLeftRightArr -> &DoubleLongLeftRightArro + new Transition (1832, 1833), // &DoubleLongRightArr -> &DoubleLongRightArro + new Transition (1843, 1844), // &DoubleRightArr -> &DoubleRightArro + new Transition (1855, 1856), // &DoubleUpArr -> &DoubleUpArro + new Transition (1859, 1860), // &DoubleUpD -> &DoubleUpDo + new Transition (1865, 1866), // &DoubleUpDownArr -> &DoubleUpDownArro + new Transition (1885, 1886), // &DownArr -> &DownArro + new Transition (1891, 1892), // &Downarr -> &Downarro + new Transition (1899, 1900), // &downarr -> &downarro + new Transition (1911, 1912), // &DownArrowUpArr -> &DownArrowUpArro + new Transition (1921, 1922), // &downd -> &downdo + new Transition (1927, 1928), // &downdownarr -> &downdownarro + new Transition (1935, 1936), // &downharp -> &downharpo + new Transition (1936, 1937), // &downharpo -> &downharpoo + new Transition (1962, 1963), // &DownLeftRightVect -> &DownLeftRightVecto + new Transition (1972, 1973), // &DownLeftTeeVect -> &DownLeftTeeVecto + new Transition (1979, 1980), // &DownLeftVect -> &DownLeftVecto + new Transition (1998, 1999), // &DownRightTeeVect -> &DownRightTeeVecto + new Transition (2005, 2006), // &DownRightVect -> &DownRightVecto + new Transition (2019, 2020), // &DownTeeArr -> &DownTeeArro + new Transition (2027, 2028), // &drbkar -> &drbkaro + new Transition (2031, 2032), // &drc -> &drco + new Transition (2036, 2037), // &drcr -> &drcro + new Transition (2044, 2054), // &ds -> &dso + new Transition (2058, 2059), // &Dstr -> &Dstro + new Transition (2063, 2064), // &dstr -> &dstro + new Transition (2068, 2069), // &dtd -> &dtdo + new Transition (2108, 2296), // &E -> &Eo + new Transition (2115, 2301), // &e -> &eo + new Transition (2129, 2130), // &Ecar -> &Ecaro + new Transition (2133, 2148), // &ec -> &eco + new Transition (2135, 2136), // &ecar -> &ecaro + new Transition (2149, 2150), // &ecol -> &ecolo + new Transition (2157, 2166), // &eD -> &eDo + new Transition (2158, 2159), // &eDD -> &eDDo + new Transition (2162, 2163), // &Ed -> &Edo + new Transition (2169, 2170), // &ed -> &edo + new Transition (2176, 2177), // &efD -> &efDo + new Transition (2200, 2201), // &egsd -> &egsdo + new Transition (2224, 2225), // &elsd -> &elsdo + new Transition (2297, 2298), // &Eog -> &Eogo + new Transition (2302, 2303), // &eog -> &eogo + new Transition (2329, 2330), // &Epsil -> &Epsilo + new Transition (2333, 2334), // &epsil -> &epsilo + new Transition (2340, 2345), // &eqc -> &eqco + new Transition (2346, 2347), // &eqcol -> &eqcolo + new Transition (2414, 2415), // &erD -> &erDo + new Transition (2426, 2427), // &esd -> &esdo + new Transition (2455, 2456), // &eur -> &euro + new Transition (2472, 2493), // &exp -> &expo + new Transition (2478, 2479), // &expectati -> &expectatio + new Transition (2482, 2483), // &Exp -> &Expo + new Transition (2503, 2612), // &f -> &fo + new Transition (2510, 2511), // &fallingd -> &fallingdo + new Transition (2517, 2608), // &F -> &Fo + new Transition (2604, 2605), // &fn -> &fno + new Transition (2647, 2689), // &fr -> &fro + new Transition (2701, 2857), // &g -> &go + new Transition (2708, 2853), // &G -> &Go + new Transition (2755, 2756), // &Gd -> &Gdo + new Transition (2759, 2760), // &gd -> &gdo + new Transition (2786, 2787), // &gesd -> &gesdo + new Transition (2788, 2790), // &gesdot -> &gesdoto + new Transition (2837, 2838), // &gnappr -> &gnappro + new Transition (2950, 2951), // >d -> >do + new Transition (2969, 2970), // >rappr -> >rappro + new Transition (2976, 2977), // >rd -> >rdo + new Transition (3014, 3159), // &H -> &Ho + new Transition (3020, 3126), // &h -> &ho + new Transition (3090, 3091), // &herc -> &herco + new Transition (3116, 3117), // &hksear -> &hksearo + new Transition (3122, 3123), // &hkswar -> &hkswaro + new Transition (3126, 3136), // &ho -> &hoo + new Transition (3144, 3145), // &hookleftarr -> &hookleftarro + new Transition (3155, 3156), // &hookrightarr -> &hookrightarro + new Transition (3173, 3174), // &Horiz -> &Horizo + new Transition (3198, 3199), // &Hstr -> &Hstro + new Transition (3203, 3204), // &hstr -> &hstro + new Transition (3210, 3211), // &HumpD -> &HumpDo + new Transition (3236, 3471), // &I -> &Io + new Transition (3243, 3467), // &i -> &io + new Transition (3265, 3266), // &Id -> &Ido + new Transition (3301, 3316), // &ii -> &iio + new Transition (3336, 3365), // &im -> &imo + new Transition (3378, 3393), // &in -> &ino + new Transition (3394, 3395), // &inod -> &inodo + new Transition (3429, 3430), // &Intersecti -> &Intersectio + new Transition (3440, 3441), // &intpr -> &intpro + new Transition (3451, 3452), // &InvisibleC -> &InvisibleCo + new Transition (3472, 3473), // &Iog -> &Iogo + new Transition (3476, 3477), // &iog -> &iogo + new Transition (3493, 3494), // &ipr -> &ipro + new Transition (3514, 3515), // &isind -> &isindo + new Transition (3555, 3582), // &J -> &Jo + new Transition (3561, 3586), // &j -> &jo + new Transition (3618, 3676), // &K -> &Ko + new Transition (3624, 3680), // &k -> &ko + new Transition (3692, 4422), // &l -> &lo + new Transition (3698, 4434), // &L -> &Lo + new Transition (3756, 3757), // &laqu -> « + new Transition (3839, 3840), // &Lcar -> &Lcaro + new Transition (3845, 3846), // &lcar -> &lcaro + new Transition (3874, 3875), // &ldqu -> &ldquo + new Transition (3915, 3916), // &LeftArr -> &LeftArro + new Transition (3921, 3922), // &Leftarr -> &Leftarro + new Transition (3929, 3930), // &leftarr -> &leftarro + new Transition (3944, 3945), // &LeftArrowRightArr -> &LeftArrowRightArro + new Transition (3961, 3962), // &LeftD -> &LeftDo + new Transition (3983, 3984), // &LeftDownTeeVect -> &LeftDownTeeVecto + new Transition (3990, 3991), // &LeftDownVect -> &LeftDownVecto + new Transition (3999, 4000), // &LeftFl -> &LeftFlo + new Transition (4000, 4001), // &LeftFlo -> &LeftFloo + new Transition (4007, 4008), // &leftharp -> &leftharpo + new Transition (4008, 4009), // &leftharpo -> &leftharpoo + new Transition (4011, 4012), // &leftharpoond -> &leftharpoondo + new Transition (4025, 4026), // &leftleftarr -> &leftleftarro + new Transition (4037, 4038), // &LeftRightArr -> &LeftRightArro + new Transition (4048, 4049), // &Leftrightarr -> &Leftrightarro + new Transition (4059, 4060), // &leftrightarr -> &leftrightarro + new Transition (4068, 4069), // &leftrightharp -> &leftrightharpo + new Transition (4069, 4070), // &leftrightharpo -> &leftrightharpoo + new Transition (4081, 4082), // &leftrightsquigarr -> &leftrightsquigarro + new Transition (4088, 4089), // &LeftRightVect -> &LeftRightVecto + new Transition (4098, 4099), // &LeftTeeArr -> &LeftTeeArro + new Transition (4105, 4106), // &LeftTeeVect -> &LeftTeeVecto + new Transition (4140, 4141), // &LeftUpD -> &LeftUpDo + new Transition (4147, 4148), // &LeftUpDownVect -> &LeftUpDownVecto + new Transition (4157, 4158), // &LeftUpTeeVect -> &LeftUpTeeVecto + new Transition (4164, 4165), // &LeftUpVect -> &LeftUpVecto + new Transition (4175, 4176), // &LeftVect -> &LeftVecto + new Transition (4202, 4203), // &lesd -> &lesdo + new Transition (4204, 4206), // &lesdot -> &lesdoto + new Transition (4219, 4220), // &lessappr -> &lessappro + new Transition (4223, 4224), // &lessd -> &lessdo + new Transition (4307, 4308), // &lfl -> &lflo + new Transition (4308, 4309), // &lflo -> &lfloo + new Transition (4354, 4355), // &llc -> &llco + new Transition (4366, 4367), // &Lleftarr -> &Lleftarro + new Transition (4381, 4382), // &Lmid -> &Lmido + new Transition (4385, 4391), // &lm -> &lmo + new Transition (4387, 4388), // &lmid -> &lmido + new Transition (4406, 4407), // &lnappr -> &lnappro + new Transition (4422, 4542), // &lo -> &loo + new Transition (4443, 4444), // &LongLeftArr -> &LongLeftArro + new Transition (4453, 4454), // &Longleftarr -> &Longleftarro + new Transition (4465, 4466), // &longleftarr -> &longleftarro + new Transition (4476, 4477), // &LongLeftRightArr -> &LongLeftRightArro + new Transition (4487, 4488), // &Longleftrightarr -> &Longleftrightarro + new Transition (4498, 4499), // &longleftrightarr -> &longleftrightarro + new Transition (4506, 4507), // &longmapst -> &longmapsto + new Transition (4516, 4517), // &LongRightArr -> &LongRightArro + new Transition (4527, 4528), // &Longrightarr -> &Longrightarro + new Transition (4538, 4539), // &longrightarr -> &longrightarro + new Transition (4546, 4547), // &looparr -> &looparro + new Transition (4597, 4598), // &LowerLeftArr -> &LowerLeftArro + new Transition (4608, 4609), // &LowerRightArr -> &LowerRightArro + new Transition (4633, 4634), // &lrc -> &lrco + new Transition (4655, 4656), // &lsaqu -> &lsaquo + new Transition (4679, 4680), // &lsqu -> &lsquo + new Transition (4685, 4686), // &Lstr -> &Lstro + new Transition (4690, 4691), // &lstr -> &lstro + new Transition (4706, 4707), // <d -> <do + new Transition (4767, 4922), // &m -> &mo + new Transition (4781, 4928), // &M -> &Mo + new Transition (4788, 4789), // &mapst -> &mapsto + new Transition (4791, 4792), // &mapstod -> &mapstodo + new Transition (4809, 4810), // &mc -> &mco + new Transition (4826, 4827), // &mDD -> &mDDo + new Transition (4868, 4869), // &mh -> &mho + new Transition (4873, 4874), // &micr -> µ + new Transition (4886, 4887), // &midd -> &middo + new Transition (4946, 4947), // &mstp -> &mstpo + new Transition (4965, 5372), // &n -> &no + new Transition (4971, 5347), // &N -> &No + new Transition (4986, 4993), // &nap -> &napo + new Transition (4997, 4998), // &nappr -> &nappro + new Transition (5020, 5044), // &nc -> &nco + new Transition (5026, 5027), // &Ncar -> &Ncaro + new Transition (5030, 5031), // &ncar -> &ncaro + new Transition (5048, 5049), // &ncongd -> &ncongdo + new Transition (5075, 5077), // &nearr -> &nearro + new Transition (5080, 5081), // &ned -> &nedo + new Transition (5278, 5279), // &nLeftarr -> &nLeftarro + new Transition (5286, 5287), // &nleftarr -> &nleftarro + new Transition (5297, 5298), // &nLeftrightarr -> &nLeftrightarro + new Transition (5308, 5309), // &nleftrightarr -> &nleftrightarro + new Transition (5380, 5381), // &NotC -> &NotCo + new Transition (5396, 5397), // &NotD -> &NotDo + new Transition (5497, 5498), // &NotHumpD -> &NotHumpDo + new Transition (5515, 5516), // ¬ind -> ¬indo + new Transition (5821, 5836), // &np -> &npo + new Transition (5875, 5876), // &nRightarr -> &nRightarro + new Transition (5885, 5886), // &nrightarr -> &nrightarro + new Transition (5910, 5911), // &nsh -> &nsho + new Transition (6037, 6038), // &numer -> &numero + new Transition (6121, 6123), // &nwarr -> &nwarro + new Transition (6131, 6294), // &O -> &Oo + new Transition (6138, 6298), // &o -> &oo + new Transition (6163, 6182), // &od -> &odo + new Transition (6185, 6186), // &ods -> &odso + new Transition (6210, 6211), // &og -> &ogo + new Transition (6247, 6248), // &olcr -> &olcro + new Transition (6278, 6279), // &Omicr -> &Omicro + new Transition (6284, 6285), // &omicr -> &omicro + new Transition (6314, 6315), // &OpenCurlyD -> &OpenCurlyDo + new Transition (6321, 6322), // &OpenCurlyDoubleQu -> &OpenCurlyDoubleQuo + new Transition (6327, 6328), // &OpenCurlyQu -> &OpenCurlyQuo + new Transition (6342, 6365), // &or -> &oro + new Transition (6351, 6353), // &order -> &ordero + new Transition (6361, 6362), // &orig -> &origo + new Transition (6369, 6370), // &orsl -> &orslo + new Transition (6382, 6396), // &os -> &oso + new Transition (6463, 6622), // &p -> &po + new Transition (6482, 6609), // &P -> &Po + new Transition (6503, 6504), // &peri -> &perio + new Transition (6527, 6537), // &ph -> &pho + new Transition (6548, 6549), // &pitchf -> &pitchfo + new Transition (6580, 6581), // &plusd -> &plusdo + new Transition (6604, 6605), // &plustw -> &plustwo + new Transition (6640, 6748), // &Pr -> &Pro + new Transition (6642, 6745), // &pr -> &pro + new Transition (6660, 6661), // &precappr -> &precappro + new Transition (6709, 6710), // &precnappr -> &precnappro + new Transition (6772, 6773), // &Prop -> &Propo + new Transition (6776, 6777), // &Proporti -> &Proportio + new Transition (6783, 6784), // &propt -> &propto + new Transition (6813, 6825), // &Q -> &Qo + new Transition (6817, 6829), // &q -> &qo + new Transition (6847, 6873), // &qu -> &quo + new Transition (6853, 6854), // &quaterni -> &quaternio + new Transition (6876, 7469), // &r -> &ro + new Transition (6886, 7485), // &R -> &Ro + new Transition (6922, 6923), // &raqu -> » + new Transition (6978, 6979), // &rati -> &ratio + new Transition (7023, 7024), // &Rcar -> &Rcaro + new Transition (7029, 7030), // &rcar -> &rcaro + new Transition (7064, 7065), // &rdqu -> &rdquo + new Transition (7141, 7142), // &rfl -> &rflo + new Transition (7142, 7143), // &rflo -> &rfloo + new Transition (7155, 7167), // &rh -> &rho + new Transition (7164, 7165), // &Rh -> &Rho + new Transition (7189, 7190), // &RightArr -> &RightArro + new Transition (7195, 7196), // &Rightarr -> &Rightarro + new Transition (7205, 7206), // &rightarr -> &rightarro + new Transition (7219, 7220), // &RightArrowLeftArr -> &RightArrowLeftArro + new Transition (7236, 7237), // &RightD -> &RightDo + new Transition (7258, 7259), // &RightDownTeeVect -> &RightDownTeeVecto + new Transition (7265, 7266), // &RightDownVect -> &RightDownVecto + new Transition (7274, 7275), // &RightFl -> &RightFlo + new Transition (7275, 7276), // &RightFlo -> &RightFloo + new Transition (7282, 7283), // &rightharp -> &rightharpo + new Transition (7283, 7284), // &rightharpo -> &rightharpoo + new Transition (7286, 7287), // &rightharpoond -> &rightharpoondo + new Transition (7300, 7301), // &rightleftarr -> &rightleftarro + new Transition (7308, 7309), // &rightleftharp -> &rightleftharpo + new Transition (7309, 7310), // &rightleftharpo -> &rightleftharpoo + new Transition (7321, 7322), // &rightrightarr -> &rightrightarro + new Transition (7333, 7334), // &rightsquigarr -> &rightsquigarro + new Transition (7343, 7344), // &RightTeeArr -> &RightTeeArro + new Transition (7350, 7351), // &RightTeeVect -> &RightTeeVecto + new Transition (7385, 7386), // &RightUpD -> &RightUpDo + new Transition (7392, 7393), // &RightUpDownVect -> &RightUpDownVecto + new Transition (7402, 7403), // &RightUpTeeVect -> &RightUpTeeVecto + new Transition (7409, 7410), // &RightUpVect -> &RightUpVecto + new Transition (7420, 7421), // &RightVect -> &RightVecto + new Transition (7435, 7436), // &risingd -> &risingdo + new Transition (7453, 7454), // &rm -> &rmo + new Transition (7519, 7520), // &rpp -> &rppo + new Transition (7538, 7539), // &Rrightarr -> &Rrightarro + new Transition (7545, 7546), // &rsaqu -> &rsaquo + new Transition (7562, 7563), // &rsqu -> &rsquo + new Transition (7610, 7949), // &S -> &So + new Transition (7617, 7936), // &s -> &so + new Transition (7626, 7627), // &sbqu -> &sbquo + new Transition (7637, 7638), // &Scar -> &Scaro + new Transition (7641, 7642), // &scar -> &scaro + new Transition (7680, 7681), // &scp -> &scpo + new Transition (7695, 7696), // &sd -> &sdo + new Transition (7713, 7715), // &searr -> &searro + new Transition (7745, 7747), // &sfr -> &sfro + new Transition (7751, 7796), // &sh -> &sho + new Transition (7772, 7773), // &Sh -> &Sho + new Transition (7776, 7777), // &ShortD -> &ShortDo + new Transition (7782, 7783), // &ShortDownArr -> &ShortDownArro + new Transition (7792, 7793), // &ShortLeftArr -> &ShortLeftArro + new Transition (7819, 7820), // &ShortRightArr -> &ShortRightArro + new Transition (7827, 7828), // &ShortUpArr -> &ShortUpArro + new Transition (7849, 7850), // &simd -> &simdo + new Transition (8028, 8029), // &SquareIntersecti -> &SquareIntersectio + new Transition (8060, 8061), // &SquareUni -> &SquareUnio + new Transition (8116, 8117), // &straightepsil -> &straightepsilo + new Transition (8133, 8134), // &subd -> &subdo + new Transition (8141, 8142), // &subed -> &subedo + new Transition (8204, 8205), // &succappr -> &succappro + new Transition (8253, 8254), // &succnappr -> &succnappro + new Transition (8292, 8293), // &supd -> &supdo + new Transition (8304, 8305), // &suped -> &supedo + new Transition (8321, 8322), // &suphs -> &suphso + new Transition (8385, 8387), // &swarr -> &swarro + new Transition (8400, 8604), // &T -> &To + new Transition (8404, 8590), // &t -> &to + new Transition (8421, 8422), // &Tcar -> &Tcaro + new Transition (8427, 8428), // &tcar -> &tcaro + new Transition (8445, 8446), // &td -> &tdo + new Transition (8461, 8540), // &th -> &tho + new Transition (8471, 8472), // &Theref -> &Therefo + new Transition (8476, 8477), // &theref -> &therefo + new Transition (8499, 8500), // &thickappr -> &thickappro + new Transition (8596, 8597), // &topb -> &topbo + new Transition (8608, 8610), // &topf -> &topfo + new Transition (8640, 8641), // &triangled -> &triangledo + new Transition (8664, 8665), // &trid -> &trido + new Transition (8681, 8682), // &TripleD -> &TripleDo + new Transition (8728, 8729), // &Tstr -> &Tstro + new Transition (8733, 8734), // &tstr -> &tstro + new Transition (8737, 8742), // &tw -> &two + new Transition (8753, 8754), // &twoheadleftarr -> &twoheadleftarro + new Transition (8764, 8765), // &twoheadrightarr -> &twoheadrightarro + new Transition (8768, 8954), // &U -> &Uo + new Transition (8775, 8959), // &u -> &uo + new Transition (8783, 8792), // &Uarr -> &Uarro + new Transition (8888, 8889), // &ulc -> &ulco + new Transition (8896, 8897), // &ulcr -> &ulcro + new Transition (8945, 8946), // &Uni -> &Unio + new Transition (8955, 8956), // &Uog -> &Uogo + new Transition (8960, 8961), // &uog -> &uogo + new Transition (8973, 8974), // &UpArr -> &UpArro + new Transition (8979, 8980), // &Uparr -> &Uparro + new Transition (8986, 8987), // &uparr -> &uparro + new Transition (8994, 8995), // &UpArrowD -> &UpArrowDo + new Transition (9000, 9001), // &UpArrowDownArr -> &UpArrowDownArro + new Transition (9004, 9005), // &UpD -> &UpDo + new Transition (9010, 9011), // &UpDownArr -> &UpDownArro + new Transition (9014, 9015), // &Upd -> &Updo + new Transition (9020, 9021), // &Updownarr -> &Updownarro + new Transition (9024, 9025), // &upd -> &updo + new Transition (9030, 9031), // &updownarr -> &updownarro + new Transition (9049, 9050), // &upharp -> &upharpo + new Transition (9050, 9051), // &upharpo -> &upharpoo + new Transition (9077, 9078), // &UpperLeftArr -> &UpperLeftArro + new Transition (9088, 9089), // &UpperRightArr -> &UpperRightArro + new Transition (9100, 9101), // &Upsil -> &Upsilo + new Transition (9104, 9105), // &upsil -> &upsilo + new Transition (9114, 9115), // &UpTeeArr -> &UpTeeArro + new Transition (9122, 9123), // &upuparr -> &upuparro + new Transition (9128, 9129), // &urc -> &urco + new Transition (9136, 9137), // &urcr -> &urcro + new Transition (9162, 9163), // &utd -> &utdo + new Transition (9201, 9436), // &v -> &vo + new Transition (9213, 9214), // &varepsil -> &varepsilo + new Transition (9223, 9224), // &varn -> &varno + new Transition (9237, 9238), // &varpr -> &varpro + new Transition (9240, 9241), // &varpropt -> &varpropto + new Transition (9249, 9250), // &varrh -> &varrho + new Transition (9303, 9432), // &V -> &Vo + new Transition (9393, 9394), // &VerticalSeparat -> &VerticalSeparato + new Transition (9441, 9442), // &vpr -> &vpro + new Transition (9484, 9523), // &W -> &Wo + new Transition (9490, 9527), // &w -> &wo + new Transition (9548, 9602), // &x -> &xo + new Transition (9565, 9607), // &X -> &Xo + new Transition (9603, 9604), // &xod -> &xodo + new Transition (9665, 9716), // &Y -> &Yo + new Transition (9672, 9720), // &y -> &yo + new Transition (9747, 9832), // &Z -> &Zo + new Transition (9754, 9836), // &z -> &zo + new Transition (9763, 9764), // &Zcar -> &Zcaro + new Transition (9769, 9770), // &zcar -> &zcaro + new Transition (9777, 9778), // &Zd -> &Zdo + new Transition (9781, 9782), // &zd -> &zdo + new Transition (9792, 9793) // &Zer -> &Zero + }; + TransitionTable_p = new Transition[278] { + new Transition (0, 6463), // & -> &p + new Transition (1, 216), // &A -> &Ap + new Transition (8, 199), // &a -> &ap + new Transition (79, 94), // &al -> &alp + new Transition (80, 86), // &ale -> &alep + new Transition (89, 90), // &Al -> &Alp + new Transition (103, 114), // &am -> & + new Transition (130, 131), // &andslo -> &andslop + new Transition (172, 173), // &angs -> &angsp + new Transition (183, 193), // &Ao -> &Aop + new Transition (188, 196), // &ao -> &aop + new Transition (199, 229), // &ap -> &app + new Transition (216, 217), // &Ap -> &App + new Transition (263, 264), // &asym -> &asymp + new Transition (301, 719), // &b -> &bp + new Transition (304, 318), // &back -> &backp + new Transition (310, 311), // &backe -> &backep + new Transition (384, 405), // &be -> &bep + new Transition (399, 400), // &bem -> &bemp + new Transition (445, 446), // &bigca -> &bigcap + new Transition (452, 453), // &bigcu -> &bigcup + new Transition (455, 460), // &bigo -> &bigop + new Transition (474, 475), // &bigsqcu -> &bigsqcup + new Transition (494, 495), // &bigtriangleu -> &bigtriangleup + new Transition (497, 498), // &bigu -> &bigup + new Transition (594, 595), // &Bo -> &Bop + new Transition (598, 599), // &bo -> &bop + new Transition (613, 662), // &box -> &boxp + new Transition (774, 775), // &bum -> &bump + new Transition (782, 783), // &Bum -> &Bump + new Transition (790, 803), // &Ca -> &Cap + new Transition (797, 805), // &ca -> &cap + new Transition (814, 815), // &capbrcu -> &capbrcup + new Transition (818, 819), // &capca -> &capcap + new Transition (821, 822), // &capcu -> &capcup + new Transition (862, 863), // &cca -> &ccap + new Transition (900, 901), // &ccu -> &ccup + new Transition (927, 928), // &cem -> &cemp + new Transition (1126, 1200), // &Co -> &Cop + new Transition (1131, 1203), // &co -> &cop + new Transition (1142, 1148), // &com -> &comp + new Transition (1278, 1283), // &csu -> &csup + new Transition (1292, 1318), // &cu -> &cup + new Transition (1301, 1302), // &cue -> &cuep + new Transition (1311, 1313), // &cularr -> &cularrp + new Transition (1315, 1316), // &Cu -> &Cup + new Transition (1323, 1324), // &cupbrca -> &cupbrcap + new Transition (1327, 1328), // &CupCa -> &CupCap + new Transition (1331, 1332), // &cupca -> &cupcap + new Transition (1334, 1335), // &cupcu -> &cupcup + new Transition (1356, 1357), // &curlyeq -> &curlyeqp + new Transition (1529, 1530), // &dem -> &demp + new Transition (1676, 1677), // &dlcro -> &dlcrop + new Transition (1679, 1689), // &do -> &dop + new Transition (1685, 1686), // &Do -> &Dop + new Transition (1694, 1719), // &dot -> &dotp + new Transition (1851, 1852), // &DoubleU -> &DoubleUp + new Transition (1907, 1908), // &DownArrowU -> &DownArrowUp + new Transition (1934, 1935), // &downhar -> &downharp + new Transition (2037, 2038), // &drcro -> &drcrop + new Transition (2108, 2326), // &E -> &Ep + new Transition (2115, 2312), // &e -> &ep + new Transition (2228, 2246), // &Em -> &Emp + new Transition (2233, 2238), // &em -> &emp + new Transition (2279, 2280), // &ems -> &emsp + new Transition (2293, 2294), // &ens -> &ensp + new Transition (2296, 2306), // &Eo -> &Eop + new Transition (2301, 2309), // &eo -> &eop + new Transition (2402, 2403), // &eqv -> &eqvp + new Transition (2458, 2472), // &ex -> &exp + new Transition (2466, 2482), // &Ex -> &Exp + new Transition (2503, 2639), // &f -> &fp + new Transition (2608, 2609), // &Fo -> &Fop + new Transition (2612, 2613), // &fo -> &fop + new Transition (2702, 2722), // &ga -> &gap + new Transition (2833, 2834), // &gna -> &gnap + new Transition (2834, 2836), // &gnap -> &gnapp + new Transition (2853, 2854), // &Go -> &Gop + new Transition (2857, 2858), // &go -> &gop + new Transition (2966, 2967), // >ra -> >rap + new Transition (2967, 2968), // >rap -> >rapp + new Transition (3024, 3025), // &hairs -> &hairsp + new Transition (3086, 3087), // &helli -> &hellip + new Transition (3106, 3107), // &HilbertS -> &HilbertSp + new Transition (3126, 3163), // &ho -> &hop + new Transition (3159, 3160), // &Ho -> &Hop + new Transition (3208, 3209), // &Hum -> &Hump + new Transition (3216, 3217), // &HumpDownHum -> &HumpDownHump + new Transition (3225, 3231), // &hy -> &hyp + new Transition (3243, 3492), // &i -> &ip + new Transition (3330, 3372), // &Im -> &Imp + new Transition (3336, 3368), // &im -> &imp + new Transition (3341, 3357), // &imag -> &imagp + new Transition (3401, 3439), // &int -> &intp + new Transition (3467, 3483), // &io -> &iop + new Transition (3471, 3480), // &Io -> &Iop + new Transition (3582, 3583), // &Jo -> &Jop + new Transition (3586, 3587), // &jo -> &jop + new Transition (3619, 3620), // &Ka -> &Kap + new Transition (3620, 3621), // &Kap -> &Kapp + new Transition (3625, 3626), // &ka -> &kap + new Transition (3626, 3627), // &kap -> &kapp + new Transition (3676, 3677), // &Ko -> &Kop + new Transition (3680, 3681), // &ko -> &kop + new Transition (3692, 4621), // &l -> &lp + new Transition (3699, 3746), // &La -> &Lap + new Transition (3705, 3744), // &la -> &lap + new Transition (3712, 3713), // &laem -> &laemp + new Transition (3766, 3782), // &larr -> &larrp + new Transition (3779, 3780), // &larrl -> &larrlp + new Transition (4006, 4007), // &lefthar -> &leftharp + new Transition (4016, 4017), // &leftharpoonu -> &leftharpoonup + new Transition (4067, 4068), // &leftrighthar -> &leftrightharp + new Transition (4138, 4139), // &LeftU -> &LeftUp + new Transition (4216, 4217), // &lessa -> &lessap + new Transition (4217, 4218), // &lessap -> &lessapp + new Transition (4402, 4403), // &lna -> &lnap + new Transition (4403, 4405), // &lnap -> &lnapp + new Transition (4422, 4560), // &lo -> &lop + new Transition (4434, 4564), // &Lo -> &Lop + new Transition (4503, 4504), // &longma -> &longmap + new Transition (4542, 4543), // &loo -> &loop + new Transition (4767, 4935), // &m -> &mp + new Transition (4768, 4785), // &ma -> &map + new Transition (4782, 4783), // &Ma -> &Map + new Transition (4801, 4802), // &mapstou -> &mapstoup + new Transition (4848, 4849), // &MediumS -> &MediumSp + new Transition (4910, 4911), // &mlc -> &mlcp + new Transition (4916, 4917), // &mn -> &mnp + new Transition (4922, 4932), // &mo -> &mop + new Transition (4928, 4929), // &Mo -> &Mop + new Transition (4945, 4946), // &mst -> &mstp + new Transition (4958, 4959), // &multima -> &multimap + new Transition (4962, 4963), // &muma -> &mumap + new Transition (4965, 5821), // &n -> &np + new Transition (4966, 4986), // &na -> &nap + new Transition (4986, 4996), // &nap -> &napp + new Transition (5011, 5012), // &nbs ->   + new Transition (5015, 5016), // &nbum -> &nbump + new Transition (5021, 5022), // &nca -> &ncap + new Transition (5052, 5053), // &ncu -> &ncup + new Transition (5097, 5098), // &NegativeMediumS -> &NegativeMediumSp + new Transition (5108, 5109), // &NegativeThickS -> &NegativeThickSp + new Transition (5115, 5116), // &NegativeThinS -> &NegativeThinSp + new Transition (5129, 5130), // &NegativeVeryThinS -> &NegativeVeryThinSp + new Transition (5227, 5236), // &nh -> &nhp + new Transition (5347, 5369), // &No -> &Nop + new Transition (5363, 5364), // &NonBreakingS -> &NonBreakingSp + new Transition (5372, 5373), // &no -> &nop + new Transition (5390, 5391), // &NotCu -> &NotCup + new Transition (5393, 5394), // &NotCupCa -> &NotCupCap + new Transition (5495, 5496), // &NotHum -> &NotHump + new Transition (5503, 5504), // &NotHumpDownHum -> &NotHumpDownHump + new Transition (5701, 5713), // &NotSquareSu -> &NotSquareSup + new Transition (5726, 5768), // &NotSu -> &NotSup + new Transition (5895, 5938), // &ns -> &nsp + new Transition (5913, 5918), // &nshort -> &nshortp + new Transition (5944, 5948), // &nsqsu -> &nsqsup + new Transition (5951, 5973), // &nsu -> &nsup + new Transition (6040, 6041), // &nums -> &numsp + new Transition (6044, 6045), // &nva -> &nvap + new Transition (6131, 6306), // &O -> &Op + new Transition (6138, 6302), // &o -> &op + new Transition (6294, 6295), // &Oo -> &Oop + new Transition (6298, 6299), // &oo -> &oop + new Transition (6333, 6334), // &oper -> &operp + new Transition (6370, 6371), // &orslo -> &orslop + new Transition (6498, 6511), // &per -> &perp + new Transition (6609, 6630), // &Po -> &Pop + new Transition (6615, 6616), // &Poincare -> &Poincarep + new Transition (6622, 6633), // &po -> &pop + new Transition (6644, 6645), // &pra -> &prap + new Transition (6657, 6658), // &preca -> &precap + new Transition (6658, 6659), // &precap -> &precapp + new Transition (6706, 6707), // &precna -> &precnap + new Transition (6707, 6708), // &precnap -> &precnapp + new Transition (6736, 6737), // &prna -> &prnap + new Transition (6745, 6770), // &pro -> &prop + new Transition (6748, 6772), // &Pro -> &Prop + new Transition (6810, 6811), // &puncs -> &puncsp + new Transition (6817, 6833), // &q -> &qp + new Transition (6825, 6826), // &Qo -> &Qop + new Transition (6829, 6830), // &qo -> &qop + new Transition (6876, 7512), // &r -> &rp + new Transition (6902, 6903), // &raem -> &raemp + new Transition (6932, 6953), // &rarr -> &rarrp + new Transition (6934, 6935), // &rarra -> &rarrap + new Transition (6950, 6951), // &rarrl -> &rarrlp + new Transition (7076, 7082), // &real -> &realp + new Transition (7121, 7122), // &ReverseU -> &ReverseUp + new Transition (7281, 7282), // &righthar -> &rightharp + new Transition (7291, 7292), // &rightharpoonu -> &rightharpoonup + new Transition (7307, 7308), // &rightlefthar -> &rightleftharp + new Transition (7383, 7384), // &RightU -> &RightUp + new Transition (7469, 7481), // &ro -> &rop + new Transition (7485, 7486), // &Ro -> &Rop + new Transition (7505, 7506), // &RoundIm -> &RoundImp + new Transition (7512, 7519), // &rp -> &rpp + new Transition (7617, 7956), // &s -> &sp + new Transition (7631, 7680), // &sc -> &scp + new Transition (7633, 7634), // &sca -> &scap + new Transition (7671, 7672), // &scna -> &scnap + new Transition (7753, 7754), // &shar -> &sharp + new Transition (7798, 7803), // &short -> &shortp + new Transition (7823, 7824), // &ShortU -> &ShortUp + new Transition (7847, 7868), // &sim -> &simp + new Transition (7908, 7909), // &smash -> &smashp + new Transition (7911, 7912), // &sme -> &smep + new Transition (7936, 7953), // &so -> &sop + new Transition (7949, 7950), // &So -> &Sop + new Transition (7970, 7971), // &sqca -> &sqcap + new Transition (7975, 7976), // &sqcu -> &sqcup + new Transition (7985, 7997), // &sqsu -> &sqsup + new Transition (8033, 8045), // &SquareSu -> &SquareSup + new Transition (8111, 8120), // &straight -> &straightp + new Transition (8112, 8113), // &straighte -> &straightep + new Transition (8127, 8282), // &Su -> &Sup + new Transition (8130, 8284), // &su -> &sup + new Transition (8131, 8155), // &sub -> &subp + new Transition (8193, 8196), // &subsu -> &subsup + new Transition (8201, 8202), // &succa -> &succap + new Transition (8202, 8203), // &succap -> &succapp + new Transition (8250, 8251), // &succna -> &succnap + new Transition (8251, 8252), // &succnap -> &succnapp + new Transition (8284, 8343), // &sup -> &supp + new Transition (8370, 8373), // &supsu -> &supsup + new Transition (8404, 8617), // &t -> &tp + new Transition (8496, 8497), // &thicka -> &thickap + new Transition (8497, 8498), // &thickap -> &thickapp + new Transition (8510, 8511), // &ThickS -> &ThickSp + new Transition (8517, 8518), // &thins -> &thinsp + new Transition (8521, 8522), // &ThinS -> &ThinSp + new Transition (8528, 8529), // &thka -> &thkap + new Transition (8590, 8594), // &to -> &top + new Transition (8604, 8605), // &To -> &Top + new Transition (8628, 8698), // &tr -> &trp + new Transition (8633, 8685), // &tri -> &trip + new Transition (8677, 8678), // &Tri -> &Trip + new Transition (8768, 8970), // &U -> &Up + new Transition (8775, 8983), // &u -> &up + new Transition (8897, 8898), // &ulcro -> &ulcrop + new Transition (8954, 8964), // &Uo -> &Uop + new Transition (8959, 8967), // &uo -> &uop + new Transition (8970, 9068), // &Up -> &Upp + new Transition (9048, 9049), // &uphar -> &upharp + new Transition (9118, 9119), // &upu -> &upup + new Transition (9137, 9138), // &urcro -> &urcrop + new Transition (9201, 9440), // &v -> &vp + new Transition (9208, 9231), // &var -> &varp + new Transition (9209, 9210), // &vare -> &varep + new Transition (9218, 9219), // &varka -> &varkap + new Transition (9219, 9220), // &varkap -> &varkapp + new Transition (9238, 9239), // &varpro -> &varprop + new Transition (9258, 9269), // &varsu -> &varsup + new Transition (9357, 9358), // &velli -> &vellip + new Transition (9388, 9389), // &VerticalSe -> &VerticalSep + new Transition (9408, 9409), // &VeryThinS -> &VeryThinSp + new Transition (9427, 9430), // &vnsu -> &vnsup + new Transition (9432, 9433), // &Vo -> &Vop + new Transition (9436, 9437), // &vo -> &vop + new Transition (9442, 9443), // &vpro -> &vprop + new Transition (9458, 9465), // &vsu -> &vsup + new Transition (9490, 9531), // &w -> &wp + new Transition (9514, 9515), // &weier -> &weierp + new Transition (9523, 9524), // &Wo -> &Wop + new Transition (9527, 9528), // &wo -> &wop + new Transition (9550, 9551), // &xca -> &xcap + new Transition (9557, 9558), // &xcu -> &xcup + new Transition (9595, 9596), // &xma -> &xmap + new Transition (9602, 9611), // &xo -> &xop + new Transition (9607, 9608), // &Xo -> &Xop + new Transition (9642, 9643), // &xsqcu -> &xsqcup + new Transition (9645, 9646), // &xu -> &xup + new Transition (9716, 9717), // &Yo -> &Yop + new Transition (9720, 9721), // &yo -> &yop + new Transition (9799, 9800), // &ZeroWidthS -> &ZeroWidthSp + new Transition (9832, 9833), // &Zo -> &Zop + new Transition (9836, 9837) // &zo -> &zop + }; + TransitionTable_q = new Transition[144] { + new Transition (0, 6817), // & -> &q + new Transition (234, 235), // &approxe -> &approxeq + new Transition (266, 267), // &asympe -> &asympeq + new Transition (328, 329), // &backsime -> &backsimeq + new Transition (379, 380), // &bd -> &bdq + new Transition (471, 472), // &bigs -> &bigsq + new Transition (531, 532), // &blacks -> &blacksq + new Transition (580, 582), // &bne -> &bneq + new Transition (779, 787), // &bumpe -> &bumpeq + new Transition (784, 785), // &Bumpe -> &Bumpeq + new Transition (983, 984), // &circe -> &circeq + new Transition (1138, 1140), // &colone -> &coloneq + new Transition (1355, 1356), // &curlye -> &curlyeq + new Transition (1513, 1514), // &ddotse -> &ddotseq + new Transition (1700, 1701), // &dote -> &doteq + new Transition (1707, 1708), // &DotE -> &DotEq + new Transition (1724, 1725), // &dots -> &dotsq + new Transition (2108, 2367), // &E -> &Eq + new Transition (2115, 2339), // &e -> &eq + new Transition (2254, 2255), // &EmptySmallS -> &EmptySmallSq + new Transition (2272, 2273), // &EmptyVerySmallS -> &EmptyVerySmallSq + new Transition (2514, 2515), // &fallingdotse -> &fallingdotseq + new Transition (2564, 2565), // &FilledSmallS -> &FilledSmallSq + new Transition (2580, 2581), // &FilledVerySmallS -> &FilledVerySmallSq + new Transition (2765, 2771), // &ge -> &geq + new Transition (2771, 2773), // &geq -> &geqq + new Transition (2843, 2845), // &gne -> &gneq + new Transition (2845, 2847), // &gneq -> &gneqq + new Transition (2872, 2873), // &GreaterE -> &GreaterEq + new Transition (2887, 2888), // &GreaterFullE -> &GreaterFullEq + new Transition (2911, 2912), // &GreaterSlantE -> &GreaterSlantEq + new Transition (2942, 2959), // > -> >q + new Transition (2980, 2981), // >re -> >req + new Transition (2981, 2987), // >req -> >reqq + new Transition (3007, 3008), // &gvertne -> &gvertneq + new Transition (3008, 3009), // &gvertneq -> &gvertneqq + new Transition (3219, 3220), // &HumpE -> &HumpEq + new Transition (3243, 3497), // &i -> &iq + new Transition (3705, 3755), // &la -> &laq + new Transition (3869, 3873), // &ld -> &ldq + new Transition (3896, 4187), // &le -> &leq + new Transition (4074, 4075), // &leftrights -> &leftrightsq + new Transition (4132, 4133), // &LeftTriangleE -> &LeftTriangleEq + new Transition (4187, 4189), // &leq -> &leqq + new Transition (4227, 4228), // &lesse -> &lesseq + new Transition (4228, 4233), // &lesseq -> &lesseqq + new Transition (4240, 4241), // &LessE -> &LessEq + new Transition (4257, 4258), // &LessFullE -> &LessFullEq + new Transition (4289, 4290), // &LessSlantE -> &LessSlantEq + new Transition (4412, 4414), // &lne -> &lneq + new Transition (4414, 4416), // &lneq -> &lneqq + new Transition (4652, 4676), // &ls -> &lsq + new Transition (4653, 4654), // &lsa -> &lsaq + new Transition (4698, 4725), // < -> <q + new Transition (4760, 4761), // &lvertne -> &lvertneq + new Transition (4761, 4762), // &lvertneq -> &lvertneqq + new Transition (5064, 5135), // &ne -> &neq + new Transition (5198, 5200), // &nge -> &ngeq + new Transition (5200, 5202), // &ngeq -> &ngeqq + new Transition (5270, 5312), // &nle -> &nleq + new Transition (5312, 5314), // &nleq -> &nleqq + new Transition (5414, 5422), // &NotE -> &NotEq + new Transition (5447, 5448), // &NotGreaterE -> &NotGreaterEq + new Transition (5457, 5458), // &NotGreaterFullE -> &NotGreaterFullEq + new Transition (5481, 5482), // &NotGreaterSlantE -> &NotGreaterSlantEq + new Transition (5506, 5507), // &NotHumpE -> &NotHumpEq + new Transition (5545, 5546), // &NotLeftTriangleE -> &NotLeftTriangleEq + new Transition (5554, 5555), // &NotLessE -> &NotLessEq + new Transition (5578, 5579), // &NotLessSlantE -> &NotLessSlantEq + new Transition (5639, 5640), // &NotPrecedesE -> &NotPrecedesEq + new Transition (5650, 5651), // &NotPrecedesSlantE -> &NotPrecedesSlantEq + new Transition (5688, 5689), // &NotRightTriangleE -> &NotRightTriangleEq + new Transition (5694, 5695), // &NotS -> &NotSq + new Transition (5707, 5708), // &NotSquareSubsetE -> &NotSquareSubsetEq + new Transition (5720, 5721), // &NotSquareSupersetE -> &NotSquareSupersetEq + new Transition (5732, 5733), // &NotSubsetE -> &NotSubsetEq + new Transition (5745, 5746), // &NotSucceedsE -> &NotSucceedsEq + new Transition (5756, 5757), // &NotSucceedsSlantE -> &NotSucceedsSlantEq + new Transition (5775, 5776), // &NotSupersetE -> &NotSupersetEq + new Transition (5787, 5788), // &NotTildeE -> &NotTildeEq + new Transition (5797, 5798), // &NotTildeFullE -> &NotTildeFullEq + new Transition (5852, 5853), // &nprece -> &npreceq + new Transition (5895, 5942), // &ns -> &nsq + new Transition (5930, 5932), // &nsime -> &nsimeq + new Transition (5962, 5963), // &nsubsete -> &nsubseteq + new Transition (5963, 5965), // &nsubseteq -> &nsubseteqq + new Transition (5970, 5971), // &nsucce -> &nsucceq + new Transition (5983, 5984), // &nsupsete -> &nsupseteq + new Transition (5984, 5986), // &nsupseteq -> &nsupseteqq + new Transition (6018, 6019), // &ntrianglelefte -> &ntrianglelefteq + new Transition (6027, 6028), // &ntrianglerighte -> &ntrianglerighteq + new Transition (6669, 6670), // &preccurlye -> &preccurlyeq + new Transition (6679, 6680), // &PrecedesE -> &PrecedesEq + new Transition (6690, 6691), // &PrecedesSlantE -> &PrecedesSlantEq + new Transition (6702, 6703), // &prece -> &preceq + new Transition (6713, 6714), // &precne -> &precneq + new Transition (6714, 6715), // &precneq -> &precneqq + new Transition (6866, 6867), // &queste -> &questeq + new Transition (6882, 6921), // &ra -> &raq + new Transition (7053, 7063), // &rd -> &rdq + new Transition (7102, 7110), // &ReverseE -> &ReverseEq + new Transition (7123, 7124), // &ReverseUpE -> &ReverseUpEq + new Transition (7326, 7327), // &rights -> &rightsq + new Transition (7377, 7378), // &RightTriangleE -> &RightTriangleEq + new Transition (7439, 7440), // &risingdotse -> &risingdotseq + new Transition (7542, 7559), // &rs -> &rsq + new Transition (7543, 7544), // &rsa -> &rsaq + new Transition (7610, 7980), // &S -> &Sq + new Transition (7617, 7968), // &s -> &sq + new Transition (7624, 7625), // &sb -> &sbq + new Transition (7853, 7855), // &sime -> &simeq + new Transition (7994, 7995), // &sqsubsete -> &sqsubseteq + new Transition (8005, 8006), // &sqsupsete -> &sqsupseteq + new Transition (8039, 8040), // &SquareSubsetE -> &SquareSubsetEq + new Transition (8052, 8053), // &SquareSupersetE -> &SquareSupersetEq + new Transition (8173, 8174), // &subsete -> &subseteq + new Transition (8174, 8176), // &subseteq -> &subseteqq + new Transition (8178, 8179), // &SubsetE -> &SubsetEq + new Transition (8185, 8186), // &subsetne -> &subsetneq + new Transition (8186, 8188), // &subsetneq -> &subsetneqq + new Transition (8213, 8214), // &succcurlye -> &succcurlyeq + new Transition (8223, 8224), // &SucceedsE -> &SucceedsEq + new Transition (8234, 8235), // &SucceedsSlantE -> &SucceedsSlantEq + new Transition (8246, 8247), // &succe -> &succeq + new Transition (8257, 8258), // &succne -> &succneq + new Transition (8258, 8259), // &succneq -> &succneqq + new Transition (8314, 8315), // &SupersetE -> &SupersetEq + new Transition (8356, 8357), // &supsete -> &supseteq + new Transition (8357, 8359), // &supseteq -> &supseteqq + new Transition (8362, 8363), // &supsetne -> &supsetneq + new Transition (8363, 8365), // &supsetneq -> &supsetneqq + new Transition (8554, 8555), // &TildeE -> &TildeEq + new Transition (8564, 8565), // &TildeFullE -> &TildeFullEq + new Transition (8638, 8653), // &triangle -> &triangleq + new Transition (8650, 8651), // &trianglelefte -> &trianglelefteq + new Transition (8661, 8662), // &trianglerighte -> &trianglerighteq + new Transition (9034, 9035), // &UpE -> &UpEq + new Transition (9264, 9265), // &varsubsetne -> &varsubsetneq + new Transition (9265, 9267), // &varsubsetneq -> &varsubsetneqq + new Transition (9274, 9275), // &varsupsetne -> &varsupsetneq + new Transition (9275, 9277), // &varsupsetneq -> &varsupsetneqq + new Transition (9352, 9353), // &veee -> &veeeq + new Transition (9508, 9510), // &wedge -> &wedgeq + new Transition (9636, 9640) // &xs -> &xsq + }; + TransitionTable_r = new Transition[942] { + new Transition (0, 6876), // & -> &r + new Transition (1, 237), // &A -> &Ar + new Transition (8, 242), // &a -> &ar + new Transition (15, 16), // &Ab -> &Abr + new Transition (21, 22), // &ab -> &abr + new Transition (34, 35), // &Aci -> &Acir + new Transition (38, 39), // &aci -> &acir + new Transition (60, 65), // &af -> &afr + new Transition (62, 63), // &Af -> &Afr + new Transition (67, 68), // &Ag -> &Agr + new Transition (73, 74), // &ag -> &agr + new Transition (100, 101), // &Amac -> &Amacr + new Transition (105, 106), // &amac -> &amacr + new Transition (136, 164), // &ang -> &angr + new Transition (179, 180), // &angza -> &angzar + new Transition (180, 181), // &angzar -> &angzarr + new Transition (203, 204), // &apaci -> &apacir + new Transition (229, 230), // &app -> &appr + new Transition (248, 249), // &Asc -> &Ascr + new Transition (252, 253), // &asc -> &ascr + new Transition (301, 730), // &b -> &br + new Transition (302, 344), // &ba -> &bar + new Transition (318, 319), // &backp -> &backpr + new Transition (331, 725), // &B -> &Br + new Transition (332, 341), // &Ba -> &Bar + new Transition (360, 361), // &bb -> &bbr + new Transition (365, 366), // &bbrktb -> &bbrktbr + new Transition (384, 409), // &be -> &ber + new Transition (390, 414), // &Be -> &Ber + new Transition (436, 437), // &Bf -> &Bfr + new Transition (439, 440), // &bf -> &bfr + new Transition (448, 449), // &bigci -> &bigcir + new Transition (478, 479), // &bigsta -> &bigstar + new Transition (481, 482), // &bigt -> &bigtr + new Transition (514, 515), // &bka -> &bkar + new Transition (534, 535), // &blacksqua -> &blacksquar + new Transition (538, 539), // &blackt -> &blacktr + new Transition (545, 557), // &blacktriangle -> &blacktriangler + new Transition (618, 630), // &boxD -> &boxDr + new Transition (623, 634), // &boxd -> &boxdr + new Transition (673, 685), // &boxU -> &boxUr + new Transition (678, 689), // &boxu -> &boxur + new Transition (691, 713), // &boxV -> &boxVr + new Transition (693, 717), // &boxv -> &boxvr + new Transition (719, 720), // &bp -> &bpr + new Transition (737, 738), // &brvba -> ¦ + new Transition (741, 742), // &Bsc -> &Bscr + new Transition (745, 746), // &bsc -> &bscr + new Transition (789, 1261), // &C -> &Cr + new Transition (796, 1256), // &c -> &cr + new Transition (797, 848), // &ca -> &car + new Transition (811, 812), // &capb -> &capbr + new Transition (836, 837), // &CapitalDiffe -> &CapitalDiffer + new Transition (862, 872), // &cca -> &ccar + new Transition (867, 868), // &Cca -> &Ccar + new Transition (886, 887), // &Cci -> &Ccir + new Transition (890, 891), // &cci -> &ccir + new Transition (938, 939), // &Cente -> &Center + new Transition (944, 945), // ¢e -> ¢er + new Transition (950, 951), // &Cf -> &Cfr + new Transition (953, 954), // &cf -> &cfr + new Transition (969, 970), // &checkma -> &checkmar + new Transition (978, 979), // &ci -> &cir + new Transition (988, 989), // &circlea -> &circlear + new Transition (989, 990), // &circlear -> &circlearr + new Transition (992, 998), // &circlearrow -> &circlearrowr + new Transition (1010, 1011), // &circledci -> &circledcir + new Transition (1019, 1020), // &Ci -> &Cir + new Transition (1065, 1066), // &cirsci -> &cirscir + new Transition (1081, 1082), // &ClockwiseContou -> &ClockwiseContour + new Transition (1087, 1088), // &ClockwiseContourInteg -> &ClockwiseContourIntegr + new Transition (1095, 1096), // &CloseCu -> &CloseCur + new Transition (1172, 1173), // &Cong -> &Congr + new Transition (1189, 1190), // &Contou -> &Contour + new Transition (1195, 1196), // &ContourInteg -> &ContourIntegr + new Transition (1200, 1210), // &Cop -> &Copr + new Transition (1203, 1206), // &cop -> &copr + new Transition (1223, 1224), // ©s -> ©sr + new Transition (1229, 1230), // &Counte -> &Counter + new Transition (1245, 1246), // &CounterClockwiseContou -> &CounterClockwiseContour + new Transition (1251, 1252), // &CounterClockwiseContourInteg -> &CounterClockwiseContourIntegr + new Transition (1257, 1258), // &cra -> &crar + new Transition (1258, 1259), // &crar -> &crarr + new Transition (1271, 1272), // &Csc -> &Cscr + new Transition (1275, 1276), // &csc -> &cscr + new Transition (1292, 1346), // &cu -> &cur + new Transition (1294, 1295), // &cuda -> &cudar + new Transition (1295, 1296), // &cudar -> &cudarr + new Transition (1296, 1299), // &cudarr -> &cudarrr + new Transition (1302, 1303), // &cuep -> &cuepr + new Transition (1309, 1310), // &cula -> &cular + new Transition (1310, 1311), // &cular -> &cularr + new Transition (1320, 1321), // &cupb -> &cupbr + new Transition (1341, 1342), // &cupo -> &cupor + new Transition (1346, 1377), // &cur -> &curr + new Transition (1347, 1348), // &cura -> &curar + new Transition (1348, 1349), // &curar -> &curarr + new Transition (1357, 1358), // &curlyeqp -> &curlyeqpr + new Transition (1383, 1384), // &curvea -> &curvear + new Transition (1384, 1385), // &curvear -> &curvearr + new Transition (1387, 1393), // &curvearrow -> &curvearrowr + new Transition (1426, 1444), // &Da -> &Dar + new Transition (1429, 1430), // &Dagge -> &Dagger + new Transition (1432, 2023), // &d -> &dr + new Transition (1433, 1451), // &da -> &dar + new Transition (1436, 1437), // &dagge -> &dagger + new Transition (1444, 1445), // &Dar -> &Darr + new Transition (1447, 1448), // &dA -> &dAr + new Transition (1448, 1449), // &dAr -> &dArr + new Transition (1451, 1452), // &dar -> &darr + new Transition (1465, 1466), // &dbka -> &dbkar + new Transition (1475, 1476), // &Dca -> &Dcar + new Transition (1481, 1482), // &dca -> &dcar + new Transition (1494, 1500), // &dda -> &ddar + new Transition (1497, 1498), // &ddagge -> &ddagger + new Transition (1500, 1501), // &ddar -> &ddarr + new Transition (1504, 1505), // &DDot -> &DDotr + new Transition (1535, 1544), // &df -> &dfr + new Transition (1541, 1542), // &Df -> &Dfr + new Transition (1547, 1548), // &dHa -> &dHar + new Transition (1551, 1552), // &dha -> &dhar + new Transition (1552, 1555), // &dhar -> &dharr + new Transition (1559, 1560), // &Diac -> &Diacr + new Transition (1587, 1588), // &DiacriticalG -> &DiacriticalGr + new Transition (1623, 1624), // &Diffe -> &Differ + new Transition (1670, 1675), // &dlc -> &dlcr + new Transition (1671, 1672), // &dlco -> &dlcor + new Transition (1682, 1683), // &dolla -> &dollar + new Transition (1727, 1728), // &dotsqua -> &dotsquar + new Transition (1736, 1737), // &doubleba -> &doublebar + new Transition (1753, 1754), // &DoubleContou -> &DoubleContour + new Transition (1759, 1760), // &DoubleContourInteg -> &DoubleContourIntegr + new Transition (1770, 1771), // &DoubleDownA -> &DoubleDownAr + new Transition (1771, 1772), // &DoubleDownAr -> &DoubleDownArr + new Transition (1780, 1781), // &DoubleLeftA -> &DoubleLeftAr + new Transition (1781, 1782), // &DoubleLeftAr -> &DoubleLeftArr + new Transition (1791, 1792), // &DoubleLeftRightA -> &DoubleLeftRightAr + new Transition (1792, 1793), // &DoubleLeftRightAr -> &DoubleLeftRightArr + new Transition (1808, 1809), // &DoubleLongLeftA -> &DoubleLongLeftAr + new Transition (1809, 1810), // &DoubleLongLeftAr -> &DoubleLongLeftArr + new Transition (1819, 1820), // &DoubleLongLeftRightA -> &DoubleLongLeftRightAr + new Transition (1820, 1821), // &DoubleLongLeftRightAr -> &DoubleLongLeftRightArr + new Transition (1830, 1831), // &DoubleLongRightA -> &DoubleLongRightAr + new Transition (1831, 1832), // &DoubleLongRightAr -> &DoubleLongRightArr + new Transition (1841, 1842), // &DoubleRightA -> &DoubleRightAr + new Transition (1842, 1843), // &DoubleRightAr -> &DoubleRightArr + new Transition (1853, 1854), // &DoubleUpA -> &DoubleUpAr + new Transition (1854, 1855), // &DoubleUpAr -> &DoubleUpArr + new Transition (1863, 1864), // &DoubleUpDownA -> &DoubleUpDownAr + new Transition (1864, 1865), // &DoubleUpDownAr -> &DoubleUpDownArr + new Transition (1870, 1871), // &DoubleVe -> &DoubleVer + new Transition (1878, 1879), // &DoubleVerticalBa -> &DoubleVerticalBar + new Transition (1883, 1884), // &DownA -> &DownAr + new Transition (1884, 1885), // &DownAr -> &DownArr + new Transition (1889, 1890), // &Downa -> &Downar + new Transition (1890, 1891), // &Downar -> &Downarr + new Transition (1897, 1898), // &downa -> &downar + new Transition (1898, 1899), // &downar -> &downarr + new Transition (1904, 1905), // &DownArrowBa -> &DownArrowBar + new Transition (1909, 1910), // &DownArrowUpA -> &DownArrowUpAr + new Transition (1910, 1911), // &DownArrowUpAr -> &DownArrowUpArr + new Transition (1915, 1916), // &DownB -> &DownBr + new Transition (1925, 1926), // &downdowna -> &downdownar + new Transition (1926, 1927), // &downdownar -> &downdownarr + new Transition (1933, 1934), // &downha -> &downhar + new Transition (1938, 1944), // &downharpoon -> &downharpoonr + new Transition (1963, 1964), // &DownLeftRightVecto -> &DownLeftRightVector + new Transition (1973, 1974), // &DownLeftTeeVecto -> &DownLeftTeeVector + new Transition (1980, 1981), // &DownLeftVecto -> &DownLeftVector + new Transition (1984, 1985), // &DownLeftVectorBa -> &DownLeftVectorBar + new Transition (1999, 2000), // &DownRightTeeVecto -> &DownRightTeeVector + new Transition (2006, 2007), // &DownRightVecto -> &DownRightVector + new Transition (2010, 2011), // &DownRightVectorBa -> &DownRightVectorBar + new Transition (2017, 2018), // &DownTeeA -> &DownTeeAr + new Transition (2018, 2019), // &DownTeeAr -> &DownTeeArr + new Transition (2026, 2027), // &drbka -> &drbkar + new Transition (2031, 2036), // &drc -> &drcr + new Transition (2032, 2033), // &drco -> &drcor + new Transition (2041, 2042), // &Dsc -> &Dscr + new Transition (2045, 2046), // &dsc -> &dscr + new Transition (2057, 2058), // &Dst -> &Dstr + new Transition (2062, 2063), // &dst -> &dstr + new Transition (2067, 2072), // &dt -> &dtr + new Transition (2078, 2079), // &dua -> &duar + new Transition (2079, 2080), // &duar -> &duarr + new Transition (2083, 2084), // &duha -> &duhar + new Transition (2102, 2103), // &dzig -> &dzigr + new Transition (2104, 2105), // &dzigra -> &dzigrar + new Transition (2105, 2106), // &dzigrar -> &dzigrarr + new Transition (2115, 2409), // &e -> &er + new Transition (2124, 2125), // &easte -> &easter + new Transition (2128, 2129), // &Eca -> &Ecar + new Transition (2134, 2135), // &eca -> &ecar + new Transition (2139, 2140), // &eci -> &ecir + new Transition (2142, 2143), // &Eci -> &Ecir + new Transition (2175, 2183), // &ef -> &efr + new Transition (2180, 2181), // &Ef -> &Efr + new Transition (2185, 2193), // &eg -> &egr + new Transition (2187, 2188), // &Eg -> &Egr + new Transition (2216, 2217), // &elinte -> &elinter + new Transition (2230, 2231), // &Emac -> &Emacr + new Transition (2235, 2236), // &emac -> &emacr + new Transition (2257, 2258), // &EmptySmallSqua -> &EmptySmallSquar + new Transition (2264, 2265), // &EmptyVe -> &EmptyVer + new Transition (2275, 2276), // &EmptyVerySmallSqua -> &EmptyVerySmallSquar + new Transition (2313, 2314), // &epa -> &epar + new Transition (2341, 2342), // &eqci -> &eqcir + new Transition (2359, 2360), // &eqslantgt -> &eqslantgtr + new Transition (2390, 2391), // &Equilib -> &Equilibr + new Transition (2404, 2405), // &eqvpa -> &eqvpar + new Transition (2410, 2411), // &era -> &erar + new Transition (2411, 2412), // &erar -> &erarr + new Transition (2419, 2420), // &Esc -> &Escr + new Transition (2423, 2424), // &esc -> &escr + new Transition (2451, 2455), // &eu -> &eur + new Transition (2503, 2647), // &f -> &fr + new Transition (2530, 2547), // &ff -> &ffr + new Transition (2544, 2545), // &Ff -> &Ffr + new Transition (2567, 2568), // &FilledSmallSqua -> &FilledSmallSquar + new Transition (2572, 2573), // &FilledVe -> &FilledVer + new Transition (2583, 2584), // &FilledVerySmallSqua -> &FilledVerySmallSquar + new Transition (2608, 2616), // &Fo -> &For + new Transition (2612, 2621), // &fo -> &for + new Transition (2630, 2631), // &Fou -> &Four + new Transition (2633, 2634), // &Fourie -> &Fourier + new Transition (2635, 2636), // &Fouriert -> &Fouriertr + new Transition (2640, 2641), // &fpa -> &fpar + new Transition (2694, 2695), // &Fsc -> &Fscr + new Transition (2698, 2699), // &fsc -> &fscr + new Transition (2701, 2861), // &g -> &gr + new Transition (2708, 2866), // &G -> &Gr + new Transition (2724, 2725), // &Gb -> &Gbr + new Transition (2730, 2731), // &gb -> &gbr + new Transition (2742, 2743), // &Gci -> &Gcir + new Transition (2747, 2748), // &gci -> &gcir + new Transition (2799, 2800), // &Gf -> &Gfr + new Transition (2802, 2803), // &gf -> &gfr + new Transition (2836, 2837), // &gnapp -> &gnappr + new Transition (2870, 2871), // &Greate -> &Greater + new Transition (2893, 2894), // &GreaterG -> &GreaterGr + new Transition (2898, 2899), // &GreaterGreate -> &GreaterGreater + new Transition (2924, 2925), // &Gsc -> &Gscr + new Transition (2928, 2929), // &gsc -> &gscr + new Transition (2942, 2965), // > -> >r + new Transition (2947, 2948), // >ci -> >cir + new Transition (2956, 2957), // >lPa -> >lPar + new Transition (2966, 2973), // >ra -> >rar + new Transition (2968, 2969), // >rapp -> >rappr + new Transition (2973, 2974), // >rar -> >rarr + new Transition (3003, 3004), // &gve -> &gver + new Transition (3021, 3041), // &ha -> &har + new Transition (3022, 3023), // &hai -> &hair + new Transition (3041, 3050), // &har -> &harr + new Transition (3046, 3047), // &hA -> &hAr + new Transition (3047, 3048), // &hAr -> &hArr + new Transition (3053, 3054), // &harrci -> &harrcir + new Transition (3061, 3062), // &hba -> &hbar + new Transition (3065, 3066), // &Hci -> &Hcir + new Transition (3070, 3071), // &hci -> &hcir + new Transition (3074, 3089), // &he -> &her + new Transition (3075, 3076), // &hea -> &hear + new Transition (3094, 3095), // &Hf -> &Hfr + new Transition (3097, 3098), // &hf -> &hfr + new Transition (3103, 3104), // &Hilbe -> &Hilber + new Transition (3115, 3116), // &hksea -> &hksear + new Transition (3121, 3122), // &hkswa -> &hkswar + new Transition (3126, 3166), // &ho -> &hor + new Transition (3127, 3128), // &hoa -> &hoar + new Transition (3128, 3129), // &hoar -> &hoarr + new Transition (3137, 3148), // &hook -> &hookr + new Transition (3142, 3143), // &hooklefta -> &hookleftar + new Transition (3143, 3144), // &hookleftar -> &hookleftarr + new Transition (3153, 3154), // &hookrighta -> &hookrightar + new Transition (3154, 3155), // &hookrightar -> &hookrightarr + new Transition (3159, 3171), // &Ho -> &Hor + new Transition (3168, 3169), // &horba -> &horbar + new Transition (3185, 3186), // &Hsc -> &Hscr + new Transition (3189, 3190), // &hsc -> &hscr + new Transition (3197, 3198), // &Hst -> &Hstr + new Transition (3202, 3203), // &hst -> &hstr + new Transition (3253, 3254), // &Ici -> &Icir + new Transition (3257, 3258), // &ici -> &icir + new Transition (3281, 3287), // &if -> &ifr + new Transition (3284, 3285), // &If -> &Ifr + new Transition (3289, 3290), // &Ig -> &Igr + new Transition (3295, 3296), // &ig -> &igr + new Transition (3333, 3334), // &Imac -> &Imacr + new Transition (3338, 3339), // &imac -> &imacr + new Transition (3347, 3348), // &Imagina -> &Imaginar + new Transition (3358, 3359), // &imagpa -> &imagpar + new Transition (3381, 3382), // &inca -> &incar + new Transition (3407, 3419), // &inte -> &inter + new Transition (3409, 3410), // &intege -> &integer + new Transition (3413, 3424), // &Inte -> &Inter + new Transition (3414, 3415), // &Integ -> &Integr + new Transition (3434, 3435), // &intla -> &intlar + new Transition (3439, 3440), // &intp -> &intpr + new Transition (3492, 3493), // &ip -> &ipr + new Transition (3504, 3505), // &Isc -> &Iscr + new Transition (3508, 3509), // &isc -> &iscr + new Transition (3557, 3558), // &Jci -> &Jcir + new Transition (3563, 3564), // &jci -> &jcir + new Transition (3571, 3572), // &Jf -> &Jfr + new Transition (3574, 3575), // &jf -> &jfr + new Transition (3591, 3592), // &Jsc -> &Jscr + new Transition (3595, 3596), // &jsc -> &jscr + new Transition (3598, 3599), // &Jse -> &Jser + new Transition (3603, 3604), // &jse -> &jser + new Transition (3648, 3649), // &Kf -> &Kfr + new Transition (3651, 3652), // &kf -> &kfr + new Transition (3654, 3655), // &kg -> &kgr + new Transition (3685, 3686), // &Ksc -> &Kscr + new Transition (3689, 3690), // &ksc -> &kscr + new Transition (3692, 4628), // &l -> &lr + new Transition (3693, 3762), // &lA -> &lAr + new Transition (3694, 3695), // &lAa -> &lAar + new Transition (3695, 3696), // &lAar -> &lAarr + new Transition (3699, 3759), // &La -> &Lar + new Transition (3705, 3765), // &la -> &lar + new Transition (3718, 3719), // &lag -> &lagr + new Transition (3751, 3752), // &Laplacet -> &Laplacetr + new Transition (3759, 3760), // &Lar -> &Larr + new Transition (3762, 3763), // &lAr -> &lArr + new Transition (3765, 3766), // &lar -> &larr + new Transition (3808, 3809), // &lBa -> &lBar + new Transition (3809, 3810), // &lBar -> &lBarr + new Transition (3812, 3821), // &lb -> &lbr + new Transition (3813, 3814), // &lba -> &lbar + new Transition (3814, 3815), // &lbar -> &lbarr + new Transition (3817, 3818), // &lbb -> &lbbr + new Transition (3838, 3839), // &Lca -> &Lcar + new Transition (3844, 3845), // &lca -> &lcar + new Transition (3869, 3879), // &ld -> &ldr + new Transition (3875, 3877), // &ldquo -> &ldquor + new Transition (3882, 3883), // &ldrdha -> &ldrdhar + new Transition (3888, 3889), // &ldrusha -> &ldrushar + new Transition (3900, 4041), // &Left -> &Leftr + new Transition (3901, 3914), // &LeftA -> &LeftAr + new Transition (3906, 3907), // &LeftAngleB -> &LeftAngleBr + new Transition (3914, 3915), // &LeftAr -> &LeftArr + new Transition (3919, 3920), // &Lefta -> &Leftar + new Transition (3920, 3921), // &Leftar -> &Leftarr + new Transition (3926, 4052), // &left -> &leftr + new Transition (3927, 3928), // &lefta -> &leftar + new Transition (3928, 3929), // &leftar -> &leftarr + new Transition (3934, 3935), // &LeftArrowBa -> &LeftArrowBar + new Transition (3942, 3943), // &LeftArrowRightA -> &LeftArrowRightAr + new Transition (3943, 3944), // &LeftArrowRightAr -> &LeftArrowRightArr + new Transition (3967, 3968), // &LeftDoubleB -> &LeftDoubleBr + new Transition (3984, 3985), // &LeftDownTeeVecto -> &LeftDownTeeVector + new Transition (3991, 3992), // &LeftDownVecto -> &LeftDownVector + new Transition (3995, 3996), // &LeftDownVectorBa -> &LeftDownVectorBar + new Transition (4001, 4002), // &LeftFloo -> &LeftFloor + new Transition (4005, 4006), // &leftha -> &lefthar + new Transition (4023, 4024), // &leftlefta -> &leftleftar + new Transition (4024, 4025), // &leftleftar -> &leftleftarr + new Transition (4035, 4036), // &LeftRightA -> &LeftRightAr + new Transition (4036, 4037), // &LeftRightAr -> &LeftRightArr + new Transition (4046, 4047), // &Leftrighta -> &Leftrightar + new Transition (4047, 4048), // &Leftrightar -> &Leftrightarr + new Transition (4057, 4058), // &leftrighta -> &leftrightar + new Transition (4058, 4059), // &leftrightar -> &leftrightarr + new Transition (4066, 4067), // &leftrightha -> &leftrighthar + new Transition (4079, 4080), // &leftrightsquiga -> &leftrightsquigar + new Transition (4080, 4081), // &leftrightsquigar -> &leftrightsquigarr + new Transition (4089, 4090), // &LeftRightVecto -> &LeftRightVector + new Transition (4092, 4120), // &LeftT -> &LeftTr + new Transition (4096, 4097), // &LeftTeeA -> &LeftTeeAr + new Transition (4097, 4098), // &LeftTeeAr -> &LeftTeeArr + new Transition (4106, 4107), // &LeftTeeVecto -> &LeftTeeVector + new Transition (4110, 4111), // &leftth -> &leftthr + new Transition (4129, 4130), // &LeftTriangleBa -> &LeftTriangleBar + new Transition (4148, 4149), // &LeftUpDownVecto -> &LeftUpDownVector + new Transition (4158, 4159), // &LeftUpTeeVecto -> &LeftUpTeeVector + new Transition (4165, 4166), // &LeftUpVecto -> &LeftUpVector + new Transition (4169, 4170), // &LeftUpVectorBa -> &LeftUpVectorBar + new Transition (4176, 4177), // &LeftVecto -> &LeftVector + new Transition (4180, 4181), // &LeftVectorBa -> &LeftVectorBar + new Transition (4206, 4208), // &lesdoto -> &lesdotor + new Transition (4218, 4219), // &lessapp -> &lessappr + new Transition (4230, 4231), // &lesseqgt -> &lesseqgtr + new Transition (4235, 4236), // &lesseqqgt -> &lesseqqgtr + new Transition (4245, 4246), // &LessEqualG -> &LessEqualGr + new Transition (4250, 4251), // &LessEqualGreate -> &LessEqualGreater + new Transition (4263, 4264), // &LessG -> &LessGr + new Transition (4268, 4269), // &LessGreate -> &LessGreater + new Transition (4272, 4273), // &lessgt -> &lessgtr + new Transition (4301, 4315), // &lf -> &lfr + new Transition (4309, 4310), // &lfloo -> &lfloor + new Transition (4312, 4313), // &Lf -> &Lfr + new Transition (4322, 4323), // &lHa -> &lHar + new Transition (4326, 4327), // &lha -> &lhar + new Transition (4350, 4351), // &lla -> &llar + new Transition (4351, 4352), // &llar -> &llarr + new Transition (4355, 4356), // &llco -> &llcor + new Transition (4358, 4359), // &llcorne -> &llcorner + new Transition (4364, 4365), // &Llefta -> &Lleftar + new Transition (4365, 4366), // &Lleftar -> &Lleftarr + new Transition (4371, 4372), // &llha -> &llhar + new Transition (4375, 4376), // &llt -> &lltr + new Transition (4405, 4406), // &lnapp -> &lnappr + new Transition (4423, 4427), // &loa -> &loar + new Transition (4427, 4428), // &loar -> &loarr + new Transition (4430, 4431), // &lob -> &lobr + new Transition (4436, 4520), // &Long -> &Longr + new Transition (4441, 4442), // &LongLeftA -> &LongLeftAr + new Transition (4442, 4443), // &LongLeftAr -> &LongLeftArr + new Transition (4450, 4480), // &Longleft -> &Longleftr + new Transition (4451, 4452), // &Longlefta -> &Longleftar + new Transition (4452, 4453), // &Longleftar -> &Longleftarr + new Transition (4458, 4531), // &long -> &longr + new Transition (4462, 4491), // &longleft -> &longleftr + new Transition (4463, 4464), // &longlefta -> &longleftar + new Transition (4464, 4465), // &longleftar -> &longleftarr + new Transition (4474, 4475), // &LongLeftRightA -> &LongLeftRightAr + new Transition (4475, 4476), // &LongLeftRightAr -> &LongLeftRightArr + new Transition (4485, 4486), // &Longleftrighta -> &Longleftrightar + new Transition (4486, 4487), // &Longleftrightar -> &Longleftrightarr + new Transition (4496, 4497), // &longleftrighta -> &longleftrightar + new Transition (4497, 4498), // &longleftrightar -> &longleftrightarr + new Transition (4514, 4515), // &LongRightA -> &LongRightAr + new Transition (4515, 4516), // &LongRightAr -> &LongRightArr + new Transition (4525, 4526), // &Longrighta -> &Longrightar + new Transition (4526, 4527), // &Longrightar -> &Longrightarr + new Transition (4536, 4537), // &longrighta -> &longrightar + new Transition (4537, 4538), // &longrightar -> &longrightarr + new Transition (4544, 4545), // &loopa -> &loopar + new Transition (4545, 4546), // &loopar -> &looparr + new Transition (4548, 4554), // &looparrow -> &looparrowr + new Transition (4561, 4562), // &lopa -> &lopar + new Transition (4585, 4586), // &lowba -> &lowbar + new Transition (4589, 4590), // &Lowe -> &Lower + new Transition (4595, 4596), // &LowerLeftA -> &LowerLeftAr + new Transition (4596, 4597), // &LowerLeftAr -> &LowerLeftArr + new Transition (4606, 4607), // &LowerRightA -> &LowerRightAr + new Transition (4607, 4608), // &LowerRightAr -> &LowerRightArr + new Transition (4622, 4623), // &lpa -> &lpar + new Transition (4629, 4630), // &lra -> &lrar + new Transition (4630, 4631), // &lrar -> &lrarr + new Transition (4634, 4635), // &lrco -> &lrcor + new Transition (4637, 4638), // &lrcorne -> &lrcorner + new Transition (4641, 4642), // &lrha -> &lrhar + new Transition (4648, 4649), // &lrt -> &lrtr + new Transition (4659, 4660), // &Lsc -> &Lscr + new Transition (4662, 4663), // &lsc -> &lscr + new Transition (4680, 4682), // &lsquo -> &lsquor + new Transition (4684, 4685), // &Lst -> &Lstr + new Transition (4689, 4690), // &lst -> &lstr + new Transition (4698, 4731), // < -> <r + new Transition (4703, 4704), // <ci -> <cir + new Transition (4710, 4711), // <h -> <hr + new Transition (4721, 4722), // <la -> <lar + new Transition (4722, 4723), // <lar -> <larr + new Transition (4739, 4740), // <rPa -> <rPar + new Transition (4742, 4743), // &lu -> &lur + new Transition (4747, 4748), // &lurdsha -> &lurdshar + new Transition (4752, 4753), // &luruha -> &luruhar + new Transition (4756, 4757), // &lve -> &lver + new Transition (4768, 4804), // &ma -> &mar + new Transition (4769, 4770), // &mac -> ¯ + new Transition (4806, 4807), // &marke -> &marker + new Transition (4833, 4834), // &measu -> &measur + new Transition (4858, 4859), // &Mellint -> &Mellintr + new Transition (4862, 4863), // &Mf -> &Mfr + new Transition (4865, 4866), // &mf -> &mfr + new Transition (4872, 4873), // &mic -> &micr + new Transition (4883, 4884), // &midci -> &midcir + new Transition (4913, 4914), // &mld -> &mldr + new Transition (4938, 4939), // &Msc -> &Mscr + new Transition (4942, 4943), // &msc -> &mscr + new Transition (4965, 5855), // &n -> &nr + new Transition (4996, 4997), // &napp -> &nappr + new Transition (5002, 5003), // &natu -> &natur + new Transition (5021, 5030), // &nca -> &ncar + new Transition (5025, 5026), // &Nca -> &Ncar + new Transition (5066, 5067), // &nea -> &near + new Transition (5067, 5075), // &near -> &nearr + new Transition (5071, 5072), // &neA -> &neAr + new Transition (5072, 5073), // &neAr -> &neArr + new Transition (5122, 5123), // &NegativeVe -> &NegativeVer + new Transition (5142, 5143), // &nesea -> &nesear + new Transition (5152, 5153), // &NestedG -> &NestedGr + new Transition (5157, 5158), // &NestedGreate -> &NestedGreater + new Transition (5159, 5160), // &NestedGreaterG -> &NestedGreaterGr + new Transition (5164, 5165), // &NestedGreaterGreate -> &NestedGreaterGreater + new Transition (5189, 5190), // &Nf -> &Nfr + new Transition (5192, 5193), // &nf -> &nfr + new Transition (5221, 5223), // &ngt -> &ngtr + new Transition (5228, 5229), // &nhA -> &nhAr + new Transition (5229, 5230), // &nhAr -> &nhArr + new Transition (5232, 5233), // &nha -> &nhar + new Transition (5233, 5234), // &nhar -> &nharr + new Transition (5237, 5238), // &nhpa -> &nhpar + new Transition (5257, 5258), // &nlA -> &nlAr + new Transition (5258, 5259), // &nlAr -> &nlArr + new Transition (5261, 5262), // &nla -> &nlar + new Transition (5262, 5263), // &nlar -> &nlarr + new Transition (5265, 5266), // &nld -> &nldr + new Transition (5275, 5290), // &nLeft -> &nLeftr + new Transition (5276, 5277), // &nLefta -> &nLeftar + new Transition (5277, 5278), // &nLeftar -> &nLeftarr + new Transition (5283, 5301), // &nleft -> &nleftr + new Transition (5284, 5285), // &nlefta -> &nleftar + new Transition (5285, 5286), // &nleftar -> &nleftarr + new Transition (5295, 5296), // &nLeftrighta -> &nLeftrightar + new Transition (5296, 5297), // &nLeftrightar -> &nLeftrightarr + new Transition (5306, 5307), // &nleftrighta -> &nleftrightar + new Transition (5307, 5308), // &nleftrightar -> &nleftrightarr + new Transition (5334, 5336), // &nlt -> &nltr + new Transition (5348, 5349), // &NoB -> &NoBr + new Transition (5355, 5356), // &NonB -> &NonBr + new Transition (5383, 5384), // &NotCong -> &NotCongr + new Transition (5403, 5404), // &NotDoubleVe -> &NotDoubleVer + new Transition (5411, 5412), // &NotDoubleVerticalBa -> &NotDoubleVerticalBar + new Transition (5439, 5440), // &NotG -> &NotGr + new Transition (5444, 5445), // &NotGreate -> &NotGreater + new Transition (5463, 5464), // &NotGreaterG -> &NotGreaterGr + new Transition (5468, 5469), // &NotGreaterGreate -> &NotGreaterGreater + new Transition (5532, 5533), // &NotLeftT -> &NotLeftTr + new Transition (5542, 5543), // &NotLeftTriangleBa -> &NotLeftTriangleBar + new Transition (5560, 5561), // &NotLessG -> &NotLessGr + new Transition (5565, 5566), // &NotLessGreate -> &NotLessGreater + new Transition (5596, 5597), // &NotNestedG -> &NotNestedGr + new Transition (5601, 5602), // &NotNestedGreate -> &NotNestedGreater + new Transition (5603, 5604), // &NotNestedGreaterG -> &NotNestedGreaterGr + new Transition (5608, 5609), // &NotNestedGreaterGreate -> &NotNestedGreaterGreater + new Transition (5630, 5631), // &NotP -> &NotPr + new Transition (5659, 5660), // &NotReve -> &NotRever + new Transition (5675, 5676), // &NotRightT -> &NotRightTr + new Transition (5685, 5686), // &NotRightTriangleBa -> &NotRightTriangleBar + new Transition (5697, 5698), // &NotSqua -> &NotSquar + new Transition (5714, 5715), // &NotSquareSupe -> &NotSquareSuper + new Transition (5769, 5770), // &NotSupe -> &NotSuper + new Transition (5810, 5811), // &NotVe -> &NotVer + new Transition (5818, 5819), // &NotVerticalBa -> &NotVerticalBar + new Transition (5821, 5842), // &np -> &npr + new Transition (5822, 5823), // &npa -> &npar + new Transition (5856, 5857), // &nrA -> &nrAr + new Transition (5857, 5858), // &nrAr -> &nrArr + new Transition (5860, 5861), // &nra -> &nrar + new Transition (5861, 5862), // &nrar -> &nrarr + new Transition (5873, 5874), // &nRighta -> &nRightar + new Transition (5874, 5875), // &nRightar -> &nRightarr + new Transition (5883, 5884), // &nrighta -> &nrightar + new Transition (5884, 5885), // &nrightar -> &nrightarr + new Transition (5889, 5890), // &nrt -> &nrtr + new Transition (5896, 5908), // &nsc -> &nscr + new Transition (5905, 5906), // &Nsc -> &Nscr + new Transition (5911, 5912), // &nsho -> &nshor + new Transition (5919, 5920), // &nshortpa -> &nshortpar + new Transition (5939, 5940), // &nspa -> &nspar + new Transition (5988, 6006), // &nt -> &ntr + new Transition (6012, 6021), // &ntriangle -> &ntriangler + new Transition (6036, 6037), // &nume -> &numer + new Transition (6043, 6097), // &nv -> &nvr + new Transition (6074, 6075), // &nvHa -> &nvHar + new Transition (6075, 6076), // &nvHar -> &nvHarr + new Transition (6085, 6086), // &nvlA -> &nvlAr + new Transition (6086, 6087), // &nvlAr -> &nvlArr + new Transition (6091, 6093), // &nvlt -> &nvltr + new Transition (6098, 6099), // &nvrA -> &nvrAr + new Transition (6099, 6100), // &nvrAr -> &nvrArr + new Transition (6102, 6103), // &nvrt -> &nvrtr + new Transition (6112, 6113), // &nwa -> &nwar + new Transition (6113, 6121), // &nwar -> &nwarr + new Transition (6117, 6118), // &nwA -> &nwAr + new Transition (6118, 6119), // &nwAr -> &nwArr + new Transition (6128, 6129), // &nwnea -> &nwnear + new Transition (6131, 6340), // &O -> &Or + new Transition (6138, 6342), // &o -> &or + new Transition (6149, 6150), // &oci -> &ocir + new Transition (6153, 6154), // &Oci -> &Ocir + new Transition (6200, 6208), // &of -> &ofr + new Transition (6202, 6203), // &ofci -> &ofcir + new Transition (6205, 6206), // &Of -> &Ofr + new Transition (6210, 6220), // &og -> &ogr + new Transition (6214, 6215), // &Og -> &Ogr + new Transition (6229, 6230), // &ohba -> &ohbar + new Transition (6239, 6240), // &ola -> &olar + new Transition (6240, 6241), // &olar -> &olarr + new Transition (6243, 6247), // &olc -> &olcr + new Transition (6244, 6245), // &olci -> &olcir + new Transition (6260, 6261), // &Omac -> &Omacr + new Transition (6265, 6266), // &omac -> &omacr + new Transition (6277, 6278), // &Omic -> &Omicr + new Transition (6283, 6284), // &omic -> &omicr + new Transition (6303, 6304), // &opa -> &opar + new Transition (6310, 6311), // &OpenCu -> &OpenCur + new Transition (6332, 6333), // &ope -> &oper + new Transition (6344, 6345), // &ora -> &orar + new Transition (6345, 6346), // &orar -> &orarr + new Transition (6350, 6351), // &orde -> &order + new Transition (6365, 6366), // &oro -> &oror + new Transition (6379, 6380), // &Osc -> &Oscr + new Transition (6383, 6384), // &osc -> &oscr + new Transition (6432, 6433), // &ovba -> &ovbar + new Transition (6436, 6437), // &Ove -> &Over + new Transition (6438, 6442), // &OverB -> &OverBr + new Transition (6439, 6440), // &OverBa -> &OverBar + new Transition (6452, 6453), // &OverPa -> &OverPar + new Transition (6463, 6642), // &p -> &pr + new Transition (6464, 6465), // &pa -> &par + new Transition (6482, 6640), // &P -> &Pr + new Transition (6483, 6484), // &Pa -> &Par + new Transition (6497, 6498), // &pe -> &per + new Transition (6518, 6519), // &Pf -> &Pfr + new Transition (6521, 6522), // &pf -> &pfr + new Transition (6549, 6550), // &pitchfo -> &pitchfor + new Transition (6571, 6572), // &plusaci -> &plusacir + new Transition (6577, 6578), // &plusci -> &pluscir + new Transition (6613, 6614), // &Poinca -> &Poincar + new Transition (6659, 6660), // &precapp -> &precappr + new Transition (6665, 6666), // &preccu -> &preccur + new Transition (6708, 6709), // &precnapp -> &precnappr + new Transition (6757, 6758), // &profala -> &profalar + new Transition (6766, 6767), // &profsu -> &profsur + new Transition (6773, 6774), // &Propo -> &Propor + new Transition (6790, 6791), // &pru -> &prur + new Transition (6796, 6797), // &Psc -> &Pscr + new Transition (6800, 6801), // &psc -> &pscr + new Transition (6814, 6815), // &Qf -> &Qfr + new Transition (6818, 6819), // &qf -> &qfr + new Transition (6833, 6834), // &qp -> &qpr + new Transition (6840, 6841), // &Qsc -> &Qscr + new Transition (6844, 6845), // &qsc -> &qscr + new Transition (6850, 6851), // &quate -> &quater + new Transition (6876, 7526), // &r -> &rr + new Transition (6877, 6928), // &rA -> &rAr + new Transition (6878, 6879), // &rAa -> &rAar + new Transition (6879, 6880), // &rAar -> &rAarr + new Transition (6882, 6931), // &ra -> &rar + new Transition (6886, 7531), // &R -> &Rr + new Transition (6887, 6925), // &Ra -> &Rar + new Transition (6925, 6926), // &Rar -> &Rarr + new Transition (6928, 6929), // &rAr -> &rArr + new Transition (6931, 6932), // &rar -> &rarr + new Transition (6987, 6988), // &RBa -> &RBar + new Transition (6988, 6989), // &RBar -> &RBarr + new Transition (6992, 6993), // &rBa -> &rBar + new Transition (6993, 6994), // &rBar -> &rBarr + new Transition (6996, 7005), // &rb -> &rbr + new Transition (6997, 6998), // &rba -> &rbar + new Transition (6998, 6999), // &rbar -> &rbarr + new Transition (7001, 7002), // &rbb -> &rbbr + new Transition (7022, 7023), // &Rca -> &Rcar + new Transition (7028, 7029), // &rca -> &rcar + new Transition (7060, 7061), // &rdldha -> &rdldhar + new Transition (7065, 7067), // &rdquo -> &rdquor + new Transition (7083, 7084), // &realpa -> &realpar + new Transition (7098, 7099), // &Reve -> &Rever + new Transition (7115, 7116), // &ReverseEquilib -> &ReverseEquilibr + new Transition (7129, 7130), // &ReverseUpEquilib -> &ReverseUpEquilibr + new Transition (7135, 7149), // &rf -> &rfr + new Transition (7143, 7144), // &rfloo -> &rfloor + new Transition (7146, 7147), // &Rf -> &Rfr + new Transition (7152, 7153), // &rHa -> &rHar + new Transition (7156, 7157), // &rha -> &rhar + new Transition (7175, 7188), // &RightA -> &RightAr + new Transition (7180, 7181), // &RightAngleB -> &RightAngleBr + new Transition (7188, 7189), // &RightAr -> &RightArr + new Transition (7193, 7194), // &Righta -> &Rightar + new Transition (7194, 7195), // &Rightar -> &Rightarr + new Transition (7202, 7314), // &right -> &rightr + new Transition (7203, 7204), // &righta -> &rightar + new Transition (7204, 7205), // &rightar -> &rightarr + new Transition (7210, 7211), // &RightArrowBa -> &RightArrowBar + new Transition (7217, 7218), // &RightArrowLeftA -> &RightArrowLeftAr + new Transition (7218, 7219), // &RightArrowLeftAr -> &RightArrowLeftArr + new Transition (7242, 7243), // &RightDoubleB -> &RightDoubleBr + new Transition (7259, 7260), // &RightDownTeeVecto -> &RightDownTeeVector + new Transition (7266, 7267), // &RightDownVecto -> &RightDownVector + new Transition (7270, 7271), // &RightDownVectorBa -> &RightDownVectorBar + new Transition (7276, 7277), // &RightFloo -> &RightFloor + new Transition (7280, 7281), // &rightha -> &righthar + new Transition (7298, 7299), // &rightlefta -> &rightleftar + new Transition (7299, 7300), // &rightleftar -> &rightleftarr + new Transition (7306, 7307), // &rightleftha -> &rightlefthar + new Transition (7319, 7320), // &rightrighta -> &rightrightar + new Transition (7320, 7321), // &rightrightar -> &rightrightarr + new Transition (7331, 7332), // &rightsquiga -> &rightsquigar + new Transition (7332, 7333), // &rightsquigar -> &rightsquigarr + new Transition (7337, 7365), // &RightT -> &RightTr + new Transition (7341, 7342), // &RightTeeA -> &RightTeeAr + new Transition (7342, 7343), // &RightTeeAr -> &RightTeeArr + new Transition (7351, 7352), // &RightTeeVecto -> &RightTeeVector + new Transition (7355, 7356), // &rightth -> &rightthr + new Transition (7374, 7375), // &RightTriangleBa -> &RightTriangleBar + new Transition (7393, 7394), // &RightUpDownVecto -> &RightUpDownVector + new Transition (7403, 7404), // &RightUpTeeVecto -> &RightUpTeeVector + new Transition (7410, 7411), // &RightUpVecto -> &RightUpVector + new Transition (7414, 7415), // &RightUpVectorBa -> &RightUpVectorBar + new Transition (7421, 7422), // &RightVecto -> &RightVector + new Transition (7425, 7426), // &RightVectorBa -> &RightVectorBar + new Transition (7443, 7444), // &rla -> &rlar + new Transition (7444, 7445), // &rlar -> &rlarr + new Transition (7448, 7449), // &rlha -> &rlhar + new Transition (7470, 7474), // &roa -> &roar + new Transition (7474, 7475), // &roar -> &roarr + new Transition (7477, 7478), // &rob -> &robr + new Transition (7482, 7483), // &ropa -> &ropar + new Transition (7513, 7514), // &rpa -> &rpar + new Transition (7527, 7528), // &rra -> &rrar + new Transition (7528, 7529), // &rrar -> &rrarr + new Transition (7536, 7537), // &Rrighta -> &Rrightar + new Transition (7537, 7538), // &Rrightar -> &Rrightarr + new Transition (7549, 7550), // &Rsc -> &Rscr + new Transition (7552, 7553), // &rsc -> &rscr + new Transition (7563, 7565), // &rsquo -> &rsquor + new Transition (7567, 7578), // &rt -> &rtr + new Transition (7568, 7569), // &rth -> &rthr + new Transition (7586, 7587), // &rtrilt -> &rtriltr + new Transition (7605, 7606), // &ruluha -> &ruluhar + new Transition (7617, 8068), // &s -> &sr + new Transition (7633, 7641), // &sca -> &scar + new Transition (7636, 7637), // &Sca -> &Scar + new Transition (7662, 7663), // &Sci -> &Scir + new Transition (7666, 7667), // &sci -> &scir + new Transition (7704, 7705), // &sea -> &sear + new Transition (7705, 7713), // &sear -> &searr + new Transition (7709, 7710), // &seA -> &seAr + new Transition (7710, 7711), // &seAr -> &seArr + new Transition (7726, 7727), // &seswa -> &seswar + new Transition (7741, 7742), // &Sf -> &Sfr + new Transition (7744, 7745), // &sf -> &sfr + new Transition (7752, 7753), // &sha -> &shar + new Transition (7773, 7774), // &Sho -> &Shor + new Transition (7780, 7781), // &ShortDownA -> &ShortDownAr + new Transition (7781, 7782), // &ShortDownAr -> &ShortDownArr + new Transition (7790, 7791), // &ShortLeftA -> &ShortLeftAr + new Transition (7791, 7792), // &ShortLeftAr -> &ShortLeftArr + new Transition (7796, 7797), // &sho -> &shor + new Transition (7804, 7805), // &shortpa -> &shortpar + new Transition (7817, 7818), // &ShortRightA -> &ShortRightAr + new Transition (7818, 7819), // &ShortRightAr -> &ShortRightArr + new Transition (7825, 7826), // &ShortUpA -> &ShortUpAr + new Transition (7826, 7827), // &ShortUpAr -> &ShortUpArr + new Transition (7847, 7873), // &sim -> &simr + new Transition (7874, 7875), // &simra -> &simrar + new Transition (7875, 7876), // &simrar -> &simrarr + new Transition (7879, 7880), // &sla -> &slar + new Transition (7880, 7881), // &slar -> &slarr + new Transition (7888, 7889), // &SmallCi -> &SmallCir + new Transition (7913, 7914), // &smepa -> &smepar + new Transition (7946, 7947), // &solba -> &solbar + new Transition (7957, 7966), // &spa -> &spar + new Transition (7980, 7981), // &Sq -> &Sqr + new Transition (8011, 8012), // &Squa -> &Squar + new Transition (8015, 8016), // &squa -> &squar + new Transition (8022, 8023), // &SquareInte -> &SquareInter + new Transition (8046, 8047), // &SquareSupe -> &SquareSuper + new Transition (8069, 8070), // &sra -> &srar + new Transition (8070, 8071), // &srar -> &srarr + new Transition (8074, 8075), // &Ssc -> &Sscr + new Transition (8078, 8079), // &ssc -> &sscr + new Transition (8092, 8093), // &ssta -> &sstar + new Transition (8097, 8098), // &Sta -> &Star + new Transition (8100, 8106), // &st -> &str + new Transition (8101, 8102), // &sta -> &star + new Transition (8131, 8160), // &sub -> &subr + new Transition (8161, 8162), // &subra -> &subrar + new Transition (8162, 8163), // &subrar -> &subrarr + new Transition (8203, 8204), // &succapp -> &succappr + new Transition (8209, 8210), // &succcu -> &succcur + new Transition (8252, 8253), // &succnapp -> &succnappr + new Transition (8308, 8309), // &Supe -> &Super + new Transition (8329, 8330), // &supla -> &suplar + new Transition (8330, 8331), // &suplar -> &suplarr + new Transition (8376, 8377), // &swa -> &swar + new Transition (8377, 8385), // &swar -> &swarr + new Transition (8381, 8382), // &swA -> &swAr + new Transition (8382, 8383), // &swAr -> &swArr + new Transition (8392, 8393), // &swnwa -> &swnwar + new Transition (8400, 8676), // &T -> &Tr + new Transition (8404, 8628), // &t -> &tr + new Transition (8405, 8406), // &ta -> &tar + new Transition (8415, 8416), // &tb -> &tbr + new Transition (8420, 8421), // &Tca -> &Tcar + new Transition (8426, 8427), // &tca -> &tcar + new Transition (8450, 8451), // &tel -> &telr + new Transition (8455, 8456), // &Tf -> &Tfr + new Transition (8458, 8459), // &tf -> &tfr + new Transition (8462, 8463), // &the -> &ther + new Transition (8468, 8469), // &The -> &Ther + new Transition (8472, 8473), // &Therefo -> &Therefor + new Transition (8477, 8478), // &therefo -> &therefor + new Transition (8498, 8499), // &thickapp -> &thickappr + new Transition (8540, 8541), // &tho -> &thor + new Transition (8582, 8583), // ×ba -> ×bar + new Transition (8601, 8602), // &topci -> &topcir + new Transition (8610, 8611), // &topfo -> &topfor + new Transition (8617, 8618), // &tp -> &tpr + new Transition (8638, 8655), // &triangle -> &triangler + new Transition (8706, 8707), // &Tsc -> &Tscr + new Transition (8710, 8711), // &tsc -> &tscr + new Transition (8727, 8728), // &Tst -> &Tstr + new Transition (8732, 8733), // &tst -> &tstr + new Transition (8746, 8757), // &twohead -> &twoheadr + new Transition (8751, 8752), // &twoheadlefta -> &twoheadleftar + new Transition (8752, 8753), // &twoheadleftar -> &twoheadleftarr + new Transition (8762, 8763), // &twoheadrighta -> &twoheadrightar + new Transition (8763, 8764), // &twoheadrightar -> &twoheadrightarr + new Transition (8768, 9140), // &U -> &Ur + new Transition (8769, 8782), // &Ua -> &Uar + new Transition (8775, 9127), // &u -> &ur + new Transition (8776, 8789), // &ua -> &uar + new Transition (8782, 8783), // &Uar -> &Uarr + new Transition (8785, 8786), // &uA -> &uAr + new Transition (8786, 8787), // &uAr -> &uArr + new Transition (8789, 8790), // &uar -> &uarr + new Transition (8794, 8795), // &Uarroci -> &Uarrocir + new Transition (8797, 8798), // &Ub -> &Ubr + new Transition (8802, 8803), // &ub -> &ubr + new Transition (8816, 8817), // &Uci -> &Ucir + new Transition (8821, 8822), // &uci -> &ucir + new Transition (8830, 8831), // &uda -> &udar + new Transition (8831, 8832), // &udar -> &udarr + new Transition (8846, 8847), // &udha -> &udhar + new Transition (8849, 8858), // &uf -> &ufr + new Transition (8855, 8856), // &Uf -> &Ufr + new Transition (8860, 8861), // &Ug -> &Ugr + new Transition (8866, 8867), // &ug -> &ugr + new Transition (8873, 8874), // &uHa -> &uHar + new Transition (8877, 8878), // &uha -> &uhar + new Transition (8878, 8881), // &uhar -> &uharr + new Transition (8888, 8896), // &ulc -> &ulcr + new Transition (8889, 8890), // &ulco -> &ulcor + new Transition (8893, 8894), // &ulcorne -> &ulcorner + new Transition (8900, 8901), // &ult -> &ultr + new Transition (8906, 8907), // &Umac -> &Umacr + new Transition (8911, 8912), // &umac -> &umacr + new Transition (8918, 8919), // &Unde -> &Under + new Transition (8920, 8924), // &UnderB -> &UnderBr + new Transition (8921, 8922), // &UnderBa -> &UnderBar + new Transition (8934, 8935), // &UnderPa -> &UnderPar + new Transition (8971, 8972), // &UpA -> &UpAr + new Transition (8972, 8973), // &UpAr -> &UpArr + new Transition (8977, 8978), // &Upa -> &Upar + new Transition (8978, 8979), // &Upar -> &Uparr + new Transition (8984, 8985), // &upa -> &upar + new Transition (8985, 8986), // &upar -> &uparr + new Transition (8991, 8992), // &UpArrowBa -> &UpArrowBar + new Transition (8998, 8999), // &UpArrowDownA -> &UpArrowDownAr + new Transition (8999, 9000), // &UpArrowDownAr -> &UpArrowDownArr + new Transition (9008, 9009), // &UpDownA -> &UpDownAr + new Transition (9009, 9010), // &UpDownAr -> &UpDownArr + new Transition (9018, 9019), // &Updowna -> &Updownar + new Transition (9019, 9020), // &Updownar -> &Updownarr + new Transition (9028, 9029), // &updowna -> &updownar + new Transition (9029, 9030), // &updownar -> &updownarr + new Transition (9040, 9041), // &UpEquilib -> &UpEquilibr + new Transition (9047, 9048), // &upha -> &uphar + new Transition (9052, 9058), // &upharpoon -> &upharpoonr + new Transition (9069, 9070), // &Uppe -> &Upper + new Transition (9075, 9076), // &UpperLeftA -> &UpperLeftAr + new Transition (9076, 9077), // &UpperLeftAr -> &UpperLeftArr + new Transition (9086, 9087), // &UpperRightA -> &UpperRightAr + new Transition (9087, 9088), // &UpperRightAr -> &UpperRightArr + new Transition (9112, 9113), // &UpTeeA -> &UpTeeAr + new Transition (9113, 9114), // &UpTeeAr -> &UpTeeArr + new Transition (9120, 9121), // &upupa -> &upupar + new Transition (9121, 9122), // &upupar -> &upuparr + new Transition (9128, 9136), // &urc -> &urcr + new Transition (9129, 9130), // &urco -> &urcor + new Transition (9133, 9134), // &urcorne -> &urcorner + new Transition (9149, 9150), // &urt -> &urtr + new Transition (9154, 9155), // &Usc -> &Uscr + new Transition (9158, 9159), // &usc -> &uscr + new Transition (9161, 9177), // &ut -> &utr + new Transition (9183, 9184), // &uua -> &uuar + new Transition (9184, 9185), // &uuar -> &uuarr + new Transition (9201, 9445), // &v -> &vr + new Transition (9202, 9208), // &va -> &var + new Transition (9204, 9205), // &vang -> &vangr + new Transition (9208, 9247), // &var -> &varr + new Transition (9231, 9237), // &varp -> &varpr + new Transition (9243, 9244), // &vA -> &vAr + new Transition (9244, 9245), // &vAr -> &vArr + new Transition (9279, 9285), // &vart -> &vartr + new Transition (9291, 9297), // &vartriangle -> &vartriangler + new Transition (9305, 9306), // &Vba -> &Vbar + new Transition (9309, 9310), // &vBa -> &vBar + new Transition (9342, 9360), // &Ve -> &Ver + new Transition (9345, 9365), // &ve -> &ver + new Transition (9349, 9350), // &veeba -> &veebar + new Transition (9362, 9363), // &Verba -> &Verbar + new Transition (9367, 9368), // &verba -> &verbar + new Transition (9379, 9380), // &VerticalBa -> &VerticalBar + new Transition (9390, 9391), // &VerticalSepa -> &VerticalSepar + new Transition (9394, 9395), // &VerticalSeparato -> &VerticalSeparator + new Transition (9414, 9415), // &Vf -> &Vfr + new Transition (9417, 9418), // &vf -> &vfr + new Transition (9421, 9422), // &vlt -> &vltr + new Transition (9440, 9441), // &vp -> &vpr + new Transition (9446, 9447), // &vrt -> &vrtr + new Transition (9451, 9452), // &Vsc -> &Vscr + new Transition (9455, 9456), // &vsc -> &vscr + new Transition (9486, 9487), // &Wci -> &Wcir + new Transition (9490, 9533), // &w -> &wr + new Transition (9492, 9493), // &wci -> &wcir + new Transition (9499, 9500), // &wedba -> &wedbar + new Transition (9513, 9514), // &weie -> &weier + new Transition (9517, 9518), // &Wf -> &Wfr + new Transition (9520, 9521), // &wf -> &wfr + new Transition (9541, 9542), // &Wsc -> &Wscr + new Transition (9545, 9546), // &wsc -> &wscr + new Transition (9548, 9623), // &x -> &xr + new Transition (9553, 9554), // &xci -> &xcir + new Transition (9561, 9562), // &xdt -> &xdtr + new Transition (9566, 9567), // &Xf -> &Xfr + new Transition (9569, 9570), // &xf -> &xfr + new Transition (9573, 9574), // &xhA -> &xhAr + new Transition (9574, 9575), // &xhAr -> &xhArr + new Transition (9577, 9578), // &xha -> &xhar + new Transition (9578, 9579), // &xhar -> &xharr + new Transition (9586, 9587), // &xlA -> &xlAr + new Transition (9587, 9588), // &xlAr -> &xlArr + new Transition (9590, 9591), // &xla -> &xlar + new Transition (9591, 9592), // &xlar -> &xlarr + new Transition (9624, 9625), // &xrA -> &xrAr + new Transition (9625, 9626), // &xrAr -> &xrArr + new Transition (9628, 9629), // &xra -> &xrar + new Transition (9629, 9630), // &xrar -> &xrarr + new Transition (9633, 9634), // &Xsc -> &Xscr + new Transition (9637, 9638), // &xsc -> &xscr + new Transition (9651, 9652), // &xut -> &xutr + new Transition (9686, 9687), // &Yci -> &Ycir + new Transition (9691, 9692), // &yci -> &ycir + new Transition (9702, 9703), // &Yf -> &Yfr + new Transition (9705, 9706), // &yf -> &yfr + new Transition (9725, 9726), // &Ysc -> &Yscr + new Transition (9729, 9730), // &ysc -> &yscr + new Transition (9762, 9763), // &Zca -> &Zcar + new Transition (9768, 9769), // &zca -> &zcar + new Transition (9787, 9788), // &zeet -> &zeetr + new Transition (9791, 9792), // &Ze -> &Zer + new Transition (9811, 9812), // &Zf -> &Zfr + new Transition (9814, 9815), // &zf -> &zfr + new Transition (9826, 9827), // &zig -> &zigr + new Transition (9828, 9829), // &zigra -> &zigrar + new Transition (9829, 9830), // &zigrar -> &zigrarr + new Transition (9841, 9842), // &Zsc -> &Zscr + new Transition (9845, 9846) // &zsc -> &zscr + }; + TransitionTable_s = new Transition[368] { + new Transition (0, 7617), // & -> &s + new Transition (1, 247), // &A -> &As + new Transition (8, 251), // &a -> &as + new Transition (81, 82), // &alef -> &alefs + new Transition (120, 128), // &and -> &ands + new Transition (136, 172), // &ang -> &angs + new Transition (143, 144), // &angm -> &angms + new Transition (213, 214), // &apo -> &apos + new Transition (247, 255), // &As -> &Ass + new Transition (301, 744), // &b -> &bs + new Transition (304, 324), // &back -> &backs + new Transition (311, 312), // &backep -> &backeps + new Transition (331, 740), // &B -> &Bs + new Transition (334, 335), // &Back -> &Backs + new Transition (337, 338), // &Backsla -> &Backslas + new Transition (387, 388), // &becau -> &becaus + new Transition (393, 394), // &Becau -> &Becaus + new Transition (405, 406), // &bep -> &beps + new Transition (420, 421), // &Bernoulli -> &Bernoullis + new Transition (443, 471), // &big -> &bigs + new Transition (462, 463), // &bigoplu -> &bigoplus + new Transition (468, 469), // &bigotime -> &bigotimes + new Transition (500, 501), // &biguplu -> &biguplus + new Transition (522, 531), // &black -> &blacks + new Transition (659, 660), // &boxminu -> &boxminus + new Transition (664, 665), // &boxplu -> &boxplus + new Transition (670, 671), // &boxtime -> &boxtimes + new Transition (762, 763), // &bsolh -> &bsolhs + new Transition (789, 1270), // &C -> &Cs + new Transition (796, 1274), // &c -> &cs + new Transition (805, 846), // &cap -> &caps + new Transition (858, 859), // &Cayley -> &Cayleys + new Transition (863, 864), // &ccap -> &ccaps + new Transition (901, 902), // &ccup -> &ccups + new Transition (902, 904), // &ccups -> &ccupss + new Transition (979, 1063), // &cir -> &cirs + new Transition (1005, 1006), // &circleda -> &circledas + new Transition (1015, 1016), // &circledda -> &circleddas + new Transition (1035, 1036), // &CircleMinu -> &CircleMinus + new Transition (1040, 1041), // &CirclePlu -> &CirclePlus + new Transition (1046, 1047), // &CircleTime -> &CircleTimes + new Transition (1069, 1092), // &Clo -> &Clos + new Transition (1073, 1074), // &Clockwi -> &Clockwis + new Transition (1119, 1120), // &club -> &clubs + new Transition (1161, 1162), // &complexe -> &complexes + new Transition (1221, 1223), // © -> ©s + new Transition (1237, 1238), // &CounterClockwi -> &CounterClockwis + new Transition (1262, 1263), // &Cro -> &Cros + new Transition (1263, 1264), // &Cros -> &Cross + new Transition (1266, 1267), // &cro -> &cros + new Transition (1267, 1268), // &cros -> &cross + new Transition (1301, 1305), // &cue -> &cues + new Transition (1318, 1344), // &cup -> &cups + new Transition (1356, 1362), // &curlyeq -> &curlyeqs + new Transition (1425, 2040), // &D -> &Ds + new Transition (1426, 1457), // &Da -> &Das + new Transition (1432, 2044), // &d -> &ds + new Transition (1433, 1454), // &da -> &das + new Transition (1511, 1512), // &ddot -> &ddots + new Transition (1536, 1537), // &dfi -> &dfis + new Transition (1599, 1639), // &di -> &dis + new Transition (1601, 1617), // &diam -> &diams + new Transition (1610, 1612), // &diamond -> &diamonds + new Transition (1654, 1655), // ÷ontime -> ÷ontimes + new Transition (1694, 1724), // &dot -> &dots + new Transition (1716, 1717), // &dotminu -> &dotminus + new Transition (1721, 1722), // &dotplu -> &dotplus + new Transition (1929, 1930), // &downdownarrow -> &downdownarrows + new Transition (2108, 2418), // &E -> &Es + new Transition (2115, 2422), // &e -> &es + new Transition (2116, 2122), // &ea -> &eas + new Transition (2185, 2198), // &eg -> &egs + new Transition (2204, 2222), // &el -> &els + new Transition (2217, 2218), // &elinter -> &elinters + new Transition (2233, 2279), // &em -> &ems + new Transition (2240, 2242), // &empty -> &emptys + new Transition (2290, 2293), // &en -> &ens + new Transition (2312, 2323), // &ep -> &eps + new Transition (2314, 2316), // &epar -> &epars + new Transition (2320, 2321), // &eplu -> &eplus + new Transition (2326, 2327), // &Ep -> &Eps + new Transition (2339, 2350), // &eq -> &eqs + new Transition (2363, 2364), // &eqslantle -> &eqslantles + new Transition (2364, 2365), // &eqslantles -> &eqslantless + new Transition (2374, 2375), // &equal -> &equals + new Transition (2383, 2384), // &eque -> &eques + new Transition (2405, 2406), // &eqvpar -> &eqvpars + new Transition (2462, 2463), // &exi -> &exis + new Transition (2467, 2468), // &Exi -> &Exis + new Transition (2469, 2470), // &Exist -> &Exists + new Transition (2503, 2697), // &f -> &fs + new Transition (2512, 2513), // &fallingdot -> &fallingdots + new Transition (2517, 2693), // &F -> &Fs + new Transition (2601, 2602), // &fltn -> &fltns + new Transition (2648, 2686), // &fra -> &fras + new Transition (2701, 2927), // &g -> &gs + new Transition (2708, 2923), // &G -> &Gs + new Transition (2765, 2781), // &ge -> &ges + new Transition (2771, 2775), // &geq -> &geqs + new Transition (2796, 2797), // &gesle -> &gesles + new Transition (2832, 2849), // &gn -> &gns + new Transition (2879, 2880), // &GreaterEqualLe -> &GreaterEqualLes + new Transition (2880, 2881), // &GreaterEqualLes -> &GreaterEqualLess + new Transition (2902, 2903), // &GreaterLe -> &GreaterLes + new Transition (2903, 2904), // &GreaterLes -> &GreaterLess + new Transition (2961, 2962), // >que -> >ques + new Transition (2965, 2998), // >r -> >rs + new Transition (2983, 2984), // >reqle -> >reqles + new Transition (2984, 2985), // >reqles -> >reqless + new Transition (2989, 2990), // >reqqle -> >reqqles + new Transition (2990, 2991), // >reqqles -> >reqqless + new Transition (2994, 2995), // >rle -> >rles + new Transition (2995, 2996), // >rles -> >rless + new Transition (3014, 3184), // &H -> &Hs + new Transition (3020, 3188), // &h -> &hs + new Transition (3023, 3024), // &hair -> &hairs + new Transition (3077, 3078), // &heart -> &hearts + new Transition (3112, 3113), // &hk -> &hks + new Transition (3193, 3194), // &hsla -> &hslas + new Transition (3236, 3503), // &I -> &Is + new Transition (3243, 3507), // &i -> &is + new Transition (3375, 3376), // &Implie -> &Implies + new Transition (3410, 3411), // &integer -> &integers + new Transition (3424, 3425), // &Inter -> &Inters + new Transition (3445, 3446), // &Invi -> &Invis + new Transition (3460, 3461), // &InvisibleTime -> &InvisibleTimes + new Transition (3499, 3500), // &ique -> &iques + new Transition (3512, 3520), // &isin -> &isins + new Transition (3555, 3590), // &J -> &Js + new Transition (3561, 3594), // &j -> &js + new Transition (3618, 3684), // &K -> &Ks + new Transition (3624, 3688), // &k -> &ks + new Transition (3692, 4652), // &l -> &ls + new Transition (3698, 4658), // &L -> &Ls + new Transition (3766, 3785), // &larr -> &larrs + new Transition (3770, 3771), // &larrbf -> &larrbfs + new Transition (3773, 3774), // &larrf -> &larrfs + new Transition (3803, 3805), // &late -> &lates + new Transition (3828, 3831), // &lbrk -> &lbrks + new Transition (3869, 3891), // &ld -> &lds + new Transition (3885, 3886), // &ldru -> &ldrus + new Transition (3896, 4197), // &le -> &les + new Transition (3898, 4238), // &Le -> &Les + new Transition (4027, 4028), // &leftleftarrow -> &leftleftarrows + new Transition (4056, 4074), // &leftright -> &leftrights + new Transition (4061, 4063), // &leftrightarrow -> &leftrightarrows + new Transition (4071, 4072), // &leftrightharpoon -> &leftrightharpoons + new Transition (4117, 4118), // &leftthreetime -> &leftthreetimes + new Transition (4187, 4191), // &leq -> &leqs + new Transition (4197, 4215), // &les -> &less + new Transition (4212, 4213), // &lesge -> &lesges + new Transition (4215, 4280), // &less -> &lesss + new Transition (4238, 4239), // &Les -> &Less + new Transition (4276, 4277), // &LessLe -> &LessLes + new Transition (4277, 4278), // &LessLes -> &LessLess + new Transition (4302, 4303), // &lfi -> &lfis + new Transition (4392, 4393), // &lmou -> &lmous + new Transition (4401, 4418), // &ln -> &lns + new Transition (4504, 4505), // &longmap -> &longmaps + new Transition (4570, 4571), // &loplu -> &loplus + new Transition (4576, 4577), // &lotime -> &lotimes + new Transition (4580, 4581), // &lowa -> &lowas + new Transition (4717, 4718), // <ime -> <imes + new Transition (4727, 4728), // <que -> <ques + new Transition (4744, 4745), // &lurd -> &lurds + new Transition (4767, 4941), // &m -> &ms + new Transition (4777, 4778), // &malte -> &maltes + new Transition (4781, 4937), // &M -> &Ms + new Transition (4785, 4787), // &map -> &maps + new Transition (4821, 4822), // &mda -> &mdas + new Transition (4831, 4832), // &mea -> &meas + new Transition (4878, 4879), // &mida -> &midas + new Transition (4891, 4892), // &minu -> &minus + new Transition (4902, 4903), // &Minu -> &Minus + new Transition (4906, 4907), // &MinusPlu -> &MinusPlus + new Transition (4919, 4920), // &mnplu -> &mnplus + new Transition (4925, 4926), // &model -> &models + new Transition (4947, 4948), // &mstpo -> &mstpos + new Transition (4965, 5895), // &n -> &ns + new Transition (4971, 5904), // &N -> &Ns + new Transition (4993, 4994), // &napo -> &napos + new Transition (5006, 5008), // &natural -> &naturals + new Transition (5010, 5011), // &nb -> &nbs + new Transition (5060, 5061), // &nda -> &ndas + new Transition (5064, 5140), // &ne -> &nes + new Transition (5084, 5148), // &Ne -> &Nes + new Transition (5168, 5169), // &NestedLe -> &NestedLes + new Transition (5169, 5170), // &NestedLes -> &NestedLess + new Transition (5172, 5173), // &NestedLessLe -> &NestedLessLes + new Transition (5173, 5174), // &NestedLessLes -> &NestedLessLess + new Transition (5183, 5184), // &nexi -> &nexis + new Transition (5185, 5187), // &nexist -> &nexists + new Transition (5195, 5215), // &ng -> &ngs + new Transition (5198, 5210), // &nge -> &nges + new Transition (5200, 5204), // &ngeq -> &ngeqs + new Transition (5240, 5242), // &ni -> &nis + new Transition (5256, 5328), // &nl -> &nls + new Transition (5270, 5322), // &nle -> &nles + new Transition (5312, 5316), // &nleq -> &nleqs + new Transition (5322, 5324), // &nles -> &nless + new Transition (5434, 5435), // &NotExi -> &NotExis + new Transition (5436, 5437), // &NotExist -> &NotExists + new Transition (5472, 5473), // &NotGreaterLe -> &NotGreaterLes + new Transition (5473, 5474), // &NotGreaterLes -> &NotGreaterLess + new Transition (5529, 5551), // &NotLe -> &NotLes + new Transition (5551, 5552), // &NotLes -> &NotLess + new Transition (5569, 5570), // &NotLessLe -> &NotLessLes + new Transition (5570, 5571), // &NotLessLes -> &NotLessLess + new Transition (5591, 5592), // &NotNe -> &NotNes + new Transition (5612, 5613), // &NotNestedLe -> &NotNestedLes + new Transition (5613, 5614), // &NotNestedLes -> &NotNestedLess + new Transition (5616, 5617), // &NotNestedLessLe -> &NotNestedLessLes + new Transition (5617, 5618), // &NotNestedLessLes -> &NotNestedLessLess + new Transition (5636, 5637), // &NotPrecede -> &NotPrecedes + new Transition (5660, 5661), // &NotRever -> &NotRevers + new Transition (5702, 5703), // &NotSquareSub -> &NotSquareSubs + new Transition (5715, 5716), // &NotSquareSuper -> &NotSquareSupers + new Transition (5727, 5728), // &NotSub -> &NotSubs + new Transition (5742, 5743), // &NotSucceed -> &NotSucceeds + new Transition (5770, 5771), // &NotSuper -> &NotSupers + new Transition (5823, 5831), // &npar -> &npars + new Transition (5942, 5943), // &nsq -> &nsqs + new Transition (5952, 5958), // &nsub -> &nsubs + new Transition (5973, 5979), // &nsup -> &nsups + new Transition (6034, 6040), // &num -> &nums + new Transition (6043, 6107), // &nv -> &nvs + new Transition (6049, 6050), // &nVDa -> &nVDas + new Transition (6054, 6055), // &nVda -> &nVdas + new Transition (6059, 6060), // &nvDa -> &nvDas + new Transition (6064, 6065), // &nvda -> &nvdas + new Transition (6131, 6378), // &O -> &Os + new Transition (6138, 6382), // &o -> &os + new Transition (6139, 6145), // &oa -> &oas + new Transition (6163, 6185), // &od -> &ods + new Transition (6164, 6165), // &oda -> &odas + new Transition (6248, 6249), // &olcro -> &olcros + new Transition (6249, 6250), // &olcros -> &olcross + new Transition (6291, 6292), // &ominu -> &ominus + new Transition (6337, 6338), // &oplu -> &oplus + new Transition (6342, 6368), // &or -> &ors + new Transition (6387, 6388), // &Osla -> &Oslas + new Transition (6392, 6393), // &osla -> &oslas + new Transition (6412, 6413), // &Otime -> &Otimes + new Transition (6416, 6417), // &otime -> &otimes + new Transition (6419, 6420), // &otimesa -> &otimesas + new Transition (6458, 6459), // &OverParenthe -> &OverParenthes + new Transition (6460, 6461), // &OverParenthesi -> &OverParenthesis + new Transition (6463, 6799), // &p -> &ps + new Transition (6465, 6474), // &par -> &pars + new Transition (6482, 6795), // &P -> &Ps + new Transition (6566, 6567), // &plu -> &plus + new Transition (6567, 6599), // &plus -> &pluss + new Transition (6588, 6589), // &Plu -> &Plus + new Transition (6593, 6594), // &PlusMinu -> &PlusMinus + new Transition (6642, 6786), // &pr -> &prs + new Transition (6655, 6721), // &prec -> &precs + new Transition (6676, 6677), // &Precede -> &Precedes + new Transition (6705, 6717), // &precn -> &precns + new Transition (6731, 6733), // &prime -> &primes + new Transition (6735, 6741), // &prn -> &prns + new Transition (6754, 6765), // &prof -> &profs + new Transition (6809, 6810), // &punc -> &puncs + new Transition (6813, 6839), // &Q -> &Qs + new Transition (6817, 6843), // &q -> &qs + new Transition (6855, 6856), // &quaternion -> &quaternions + new Transition (6862, 6863), // &que -> &ques + new Transition (6876, 7542), // &r -> &rs + new Transition (6886, 7548), // &R -> &Rs + new Transition (6932, 6956), // &rarr -> &rarrs + new Transition (6939, 6940), // &rarrbf -> &rarrbfs + new Transition (6944, 6945), // &rarrf -> &rarrfs + new Transition (6983, 6984), // &rational -> &rationals + new Transition (7012, 7015), // &rbrk -> &rbrks + new Transition (7053, 7069), // &rd -> &rds + new Transition (7076, 7087), // &real -> &reals + new Transition (7099, 7100), // &Rever -> &Revers + new Transition (7136, 7137), // &rfi -> &rfis + new Transition (7199, 7431), // &ri -> &ris + new Transition (7202, 7326), // &right -> &rights + new Transition (7302, 7303), // &rightleftarrow -> &rightleftarrows + new Transition (7311, 7312), // &rightleftharpoon -> &rightleftharpoons + new Transition (7323, 7324), // &rightrightarrow -> &rightrightarrows + new Transition (7362, 7363), // &rightthreetime -> &rightthreetimes + new Transition (7437, 7438), // &risingdot -> &risingdots + new Transition (7455, 7456), // &rmou -> &rmous + new Transition (7492, 7493), // &roplu -> &roplus + new Transition (7498, 7499), // &rotime -> &rotimes + new Transition (7509, 7510), // &RoundImplie -> &RoundImplies + new Transition (7575, 7576), // &rtime -> &rtimes + new Transition (7610, 8073), // &S -> &Ss + new Transition (7617, 8077), // &s -> &ss + new Transition (7631, 7687), // &sc -> &scs + new Transition (7670, 7676), // &scn -> &scns + new Transition (7703, 7724), // &se -> &ses + new Transition (7733, 7734), // &setminu -> &setminus + new Transition (7870, 7871), // &simplu -> &simplus + new Transition (7895, 7907), // &sma -> &smas + new Transition (7897, 7898), // &small -> &smalls + new Transition (7904, 7905), // &smallsetminu -> &smallsetminus + new Transition (7914, 7915), // &smepar -> &smepars + new Transition (7926, 7928), // &smte -> &smtes + new Transition (7959, 7960), // &spade -> &spades + new Transition (7968, 7984), // &sq -> &sqs + new Transition (7971, 7973), // &sqcap -> &sqcaps + new Transition (7976, 7978), // &sqcup -> &sqcups + new Transition (7986, 7990), // &sqsub -> &sqsubs + new Transition (7997, 8001), // &sqsup -> &sqsups + new Transition (8023, 8024), // &SquareInter -> &SquareInters + new Transition (8034, 8035), // &SquareSub -> &SquareSubs + new Transition (8047, 8048), // &SquareSuper -> &SquareSupers + new Transition (8113, 8114), // &straightep -> &straighteps + new Transition (8124, 8125), // &strn -> &strns + new Transition (8128, 8165), // &Sub -> &Subs + new Transition (8131, 8169), // &sub -> &subs + new Transition (8157, 8158), // &subplu -> &subplus + new Transition (8199, 8265), // &succ -> &succs + new Transition (8220, 8221), // &Succeed -> &Succeeds + new Transition (8249, 8261), // &succn -> &succns + new Transition (8282, 8348), // &Sup -> &Sups + new Transition (8284, 8352), // &sup -> &sups + new Transition (8292, 8296), // &supd -> &supds + new Transition (8309, 8310), // &Super -> &Supers + new Transition (8320, 8321), // &suph -> &suphs + new Transition (8345, 8346), // &supplu -> &supplus + new Transition (8400, 8705), // &T -> &Ts + new Transition (8404, 8709), // &t -> &ts + new Transition (8485, 8487), // &theta -> &thetas + new Transition (8495, 8503), // &thick -> &thicks + new Transition (8516, 8517), // &thin -> &thins + new Transition (8527, 8531), // &thk -> &thks + new Transition (8577, 8578), // &time -> × + new Transition (8590, 8614), // &to -> &tos + new Transition (8633, 8690), // &tri -> &tris + new Transition (8673, 8674), // &triminu -> &triminus + new Transition (8687, 8688), // &triplu -> &triplus + new Transition (8768, 9153), // &U -> &Us + new Transition (8775, 9157), // &u -> &us + new Transition (8850, 8851), // &ufi -> &ufis + new Transition (8940, 8941), // &UnderParenthe -> &UnderParenthes + new Transition (8942, 8943), // &UnderParenthesi -> &UnderParenthesis + new Transition (8951, 8952), // &UnionPlu -> &UnionPlus + new Transition (8970, 9092), // &Up -> &Ups + new Transition (8983, 9095), // &up -> &ups + new Transition (9065, 9066), // &uplu -> &uplus + new Transition (9124, 9125), // &upuparrow -> &upuparrows + new Transition (9201, 9454), // &v -> &vs + new Transition (9208, 9252), // &var -> &vars + new Transition (9210, 9211), // &varep -> &vareps + new Transition (9259, 9260), // &varsub -> &varsubs + new Transition (9269, 9270), // &varsup -> &varsups + new Transition (9303, 9450), // &V -> &Vs + new Transition (9321, 9322), // &VDa -> &VDas + new Transition (9326, 9327), // &Vda -> &Vdas + new Transition (9331, 9332), // &vDa -> &vDas + new Transition (9336, 9337), // &vda -> &vdas + new Transition (9425, 9426), // &vn -> &vns + new Transition (9473, 9474), // &Vvda -> &Vvdas + new Transition (9484, 9540), // &W -> &Ws + new Transition (9490, 9544), // &w -> &ws + new Transition (9548, 9636), // &x -> &xs + new Transition (9565, 9632), // &X -> &Xs + new Transition (9599, 9600), // &xni -> &xnis + new Transition (9615, 9616), // &xoplu -> &xoplus + new Transition (9648, 9649), // &xuplu -> &xuplus + new Transition (9665, 9724), // &Y -> &Ys + new Transition (9672, 9728), // &y -> &ys + new Transition (9747, 9840), // &Z -> &Zs + new Transition (9754, 9844) // &z -> &zs + }; + TransitionTable_t = new Transition[499] { + new Transition (0, 8404), // & -> &t + new Transition (1, 269), // &A -> &At + new Transition (4, 5), // &Aacu -> &Aacut + new Transition (8, 275), // &a -> &at + new Transition (11, 12), // &aacu -> &aacut + new Transition (42, 43), // &acu -> &acut + new Transition (164, 165), // &angr -> &angrt + new Transition (172, 176), // &angs -> &angst + new Transition (223, 224), // &ApplyFunc -> &ApplyFunct + new Transition (251, 260), // &as -> &ast + new Transition (294, 295), // &awconin -> &awconint + new Transition (298, 299), // &awin -> &awint + new Transition (362, 364), // &bbrk -> &bbrkt + new Transition (384, 426), // &be -> &bet + new Transition (390, 423), // &Be -> &Bet + new Transition (400, 401), // &bemp -> &bempt + new Transition (443, 481), // &big -> &bigt + new Transition (455, 465), // &bigo -> &bigot + new Transition (457, 458), // &bigodo -> &bigodot + new Transition (471, 477), // &bigs -> &bigst + new Transition (522, 538), // &black -> &blackt + new Transition (554, 555), // &blacktrianglelef -> &blacktriangleleft + new Transition (560, 561), // &blacktrianglerigh -> &blacktriangleright + new Transition (588, 589), // &bNo -> &bNot + new Transition (591, 592), // &bno -> &bnot + new Transition (598, 602), // &bo -> &bot + new Transition (602, 604), // &bot -> &bott + new Transition (608, 609), // &bow -> &bowt + new Transition (613, 667), // &box -> &boxt + new Transition (771, 772), // &bulle -> &bullet + new Transition (792, 793), // &Cacu -> &Cacut + new Transition (796, 1287), // &c -> &ct + new Transition (799, 800), // &cacu -> &cacut + new Transition (825, 826), // &capdo -> &capdot + new Transition (828, 829), // &Capi -> &Capit + new Transition (839, 840), // &CapitalDifferen -> &CapitalDifferent + new Transition (849, 850), // &care -> &caret + new Transition (897, 898), // &Cconin -> &Cconint + new Transition (908, 909), // &Cdo -> &Cdot + new Transition (912, 913), // &cdo -> &cdot + new Transition (928, 929), // &cemp -> &cempt + new Transition (933, 934), // &cen -> ¢ + new Transition (936, 937), // &Cen -> &Cent + new Transition (941, 942), // &CenterDo -> &CenterDot + new Transition (947, 948), // ¢erdo -> ¢erdot + new Transition (995, 996), // &circlearrowlef -> &circlearrowleft + new Transition (1001, 1002), // &circlearrowrigh -> &circlearrowright + new Transition (1006, 1007), // &circledas -> &circledast + new Transition (1025, 1026), // &CircleDo -> &CircleDot + new Transition (1056, 1057), // &cirfnin -> &cirfnint + new Transition (1078, 1079), // &ClockwiseCon -> &ClockwiseCont + new Transition (1084, 1085), // &ClockwiseContourIn -> &ClockwiseContourInt + new Transition (1107, 1108), // &CloseCurlyDoubleQuo -> &CloseCurlyDoubleQuot + new Transition (1113, 1114), // &CloseCurlyQuo -> &CloseCurlyQuot + new Transition (1123, 1124), // &clubsui -> &clubsuit + new Transition (1144, 1146), // &comma -> &commat + new Transition (1157, 1158), // &complemen -> &complement + new Transition (1168, 1169), // &congdo -> &congdot + new Transition (1171, 1187), // &Con -> &Cont + new Transition (1176, 1177), // &Congruen -> &Congruent + new Transition (1180, 1181), // &Conin -> &Conint + new Transition (1184, 1185), // &conin -> &conint + new Transition (1192, 1193), // &ContourIn -> &ContourInt + new Transition (1214, 1215), // &Coproduc -> &Coproduct + new Transition (1227, 1228), // &Coun -> &Count + new Transition (1242, 1243), // &CounterClockwiseCon -> &CounterClockwiseCont + new Transition (1248, 1249), // &CounterClockwiseContourIn -> &CounterClockwiseContourInt + new Transition (1289, 1290), // &ctdo -> &ctdot + new Transition (1338, 1339), // &cupdo -> &cupdot + new Transition (1390, 1391), // &curvearrowlef -> &curvearrowleft + new Transition (1396, 1397), // &curvearrowrigh -> &curvearrowright + new Transition (1412, 1413), // &cwconin -> &cwconint + new Transition (1416, 1417), // &cwin -> &cwint + new Transition (1421, 1422), // &cylc -> &cylct + new Transition (1432, 2067), // &d -> &dt + new Transition (1440, 1441), // &dale -> &dalet + new Transition (1503, 1504), // &DDo -> &DDot + new Transition (1510, 1511), // &ddo -> &ddot + new Transition (1520, 1522), // &Del -> &Delt + new Transition (1525, 1526), // &del -> &delt + new Transition (1530, 1531), // &demp -> &dempt + new Transition (1538, 1539), // &dfish -> &dfisht + new Transition (1561, 1562), // &Diacri -> &Diacrit + new Transition (1569, 1570), // &DiacriticalAcu -> &DiacriticalAcut + new Transition (1574, 1575), // &DiacriticalDo -> &DiacriticalDot + new Transition (1583, 1584), // &DiacriticalDoubleAcu -> &DiacriticalDoubleAcut + new Transition (1614, 1615), // &diamondsui -> &diamondsuit + new Transition (1626, 1627), // &Differen -> &Different + new Transition (1650, 1651), // ÷on -> ÷ont + new Transition (1679, 1694), // &do -> &dot + new Transition (1685, 1692), // &Do -> &Dot + new Transition (1697, 1698), // &DotDo -> &DotDot + new Transition (1704, 1705), // &doteqdo -> &doteqdot + new Transition (1750, 1751), // &DoubleCon -> &DoubleCont + new Transition (1756, 1757), // &DoubleContourIn -> &DoubleContourInt + new Transition (1765, 1766), // &DoubleDo -> &DoubleDot + new Transition (1778, 1779), // &DoubleLef -> &DoubleLeft + new Transition (1789, 1790), // &DoubleLeftRigh -> &DoubleLeftRight + new Transition (1806, 1807), // &DoubleLongLef -> &DoubleLongLeft + new Transition (1817, 1818), // &DoubleLongLeftRigh -> &DoubleLongLeftRight + new Transition (1828, 1829), // &DoubleLongRigh -> &DoubleLongRight + new Transition (1839, 1840), // &DoubleRigh -> &DoubleRight + new Transition (1871, 1872), // &DoubleVer -> &DoubleVert + new Transition (1941, 1942), // &downharpoonlef -> &downharpoonleft + new Transition (1947, 1948), // &downharpoonrigh -> &downharpoonright + new Transition (1952, 1953), // &DownLef -> &DownLeft + new Transition (1957, 1958), // &DownLeftRigh -> &DownLeftRight + new Transition (1961, 1962), // &DownLeftRightVec -> &DownLeftRightVect + new Transition (1971, 1972), // &DownLeftTeeVec -> &DownLeftTeeVect + new Transition (1978, 1979), // &DownLeftVec -> &DownLeftVect + new Transition (1990, 1991), // &DownRigh -> &DownRight + new Transition (1997, 1998), // &DownRightTeeVec -> &DownRightTeeVect + new Transition (2004, 2005), // &DownRightVec -> &DownRightVect + new Transition (2040, 2057), // &Ds -> &Dst + new Transition (2044, 2062), // &ds -> &dst + new Transition (2069, 2070), // &dtdo -> &dtdot + new Transition (2108, 2436), // &E -> &Et + new Transition (2111, 2112), // &Eacu -> &Eacut + new Transition (2115, 2439), // &e -> &et + new Transition (2118, 2119), // &eacu -> &eacut + new Transition (2122, 2123), // &eas -> &east + new Transition (2159, 2160), // &eDDo -> &eDDot + new Transition (2163, 2164), // &Edo -> &Edot + new Transition (2166, 2167), // &eDo -> &eDot + new Transition (2170, 2171), // &edo -> &edot + new Transition (2177, 2178), // &efDo -> &efDot + new Transition (2201, 2202), // &egsdo -> &egsdot + new Transition (2210, 2211), // &Elemen -> &Element + new Transition (2214, 2215), // &elin -> &elint + new Transition (2225, 2226), // &elsdo -> &elsdot + new Transition (2238, 2239), // &emp -> &empt + new Transition (2243, 2244), // &emptyse -> &emptyset + new Transition (2246, 2247), // &Emp -> &Empt + new Transition (2356, 2357), // &eqslan -> &eqslant + new Transition (2358, 2359), // &eqslantg -> &eqslantgt + new Transition (2384, 2385), // &eques -> &equest + new Transition (2415, 2416), // &erDo -> &erDot + new Transition (2427, 2428), // &esdo -> &esdot + new Transition (2463, 2464), // &exis -> &exist + new Transition (2468, 2469), // &Exis -> &Exist + new Transition (2474, 2475), // &expec -> &expect + new Transition (2476, 2477), // &expecta -> &expectat + new Transition (2486, 2487), // &Exponen -> &Exponent + new Transition (2496, 2497), // &exponen -> &exponent + new Transition (2511, 2512), // &fallingdo -> &fallingdot + new Transition (2592, 2600), // &fl -> &flt + new Transition (2593, 2594), // &fla -> &flat + new Transition (2634, 2635), // &Fourier -> &Fouriert + new Transition (2641, 2642), // &fpar -> &fpart + new Transition (2644, 2645), // &fpartin -> &fpartint + new Transition (2701, 2942), // &g -> > + new Transition (2704, 2705), // &gacu -> &gacut + new Transition (2708, 2940), // &G -> &Gt + new Transition (2756, 2757), // &Gdo -> &Gdot + new Transition (2760, 2761), // &gdo -> &gdot + new Transition (2778, 2779), // &geqslan -> &geqslant + new Transition (2787, 2788), // &gesdo -> &gesdot + new Transition (2868, 2869), // &Grea -> &Great + new Transition (2896, 2897), // &GreaterGrea -> &GreaterGreat + new Transition (2909, 2910), // &GreaterSlan -> &GreaterSlant + new Transition (2951, 2952), // >do -> >dot + new Transition (2962, 2963), // >ques -> >quest + new Transition (2977, 2978), // >rdo -> >rdot + new Transition (3004, 3005), // &gver -> &gvert + new Transition (3015, 3058), // &Ha -> &Hat + new Transition (3032, 3033), // &hamil -> &hamilt + new Transition (3076, 3077), // &hear -> &heart + new Transition (3081, 3082), // &heartsui -> &heartsuit + new Transition (3104, 3105), // &Hilber -> &Hilbert + new Transition (3131, 3132), // &hom -> &homt + new Transition (3133, 3134), // &homth -> &homtht + new Transition (3140, 3141), // &hooklef -> &hookleft + new Transition (3151, 3152), // &hookrigh -> &hookright + new Transition (3175, 3176), // &Horizon -> &Horizont + new Transition (3184, 3197), // &Hs -> &Hst + new Transition (3188, 3202), // &hs -> &hst + new Transition (3236, 3528), // &I -> &It + new Transition (3239, 3240), // &Iacu -> &Iacut + new Transition (3243, 3526), // &i -> &it + new Transition (3246, 3247), // &iacu -> &iacut + new Transition (3266, 3267), // &Ido -> &Idot + new Transition (3305, 3306), // &iiiin -> &iiiint + new Transition (3308, 3309), // &iiin -> &iiint + new Transition (3316, 3317), // &iio -> &iiot + new Transition (3337, 3362), // &ima -> &imat + new Transition (3359, 3360), // &imagpar -> &imagpart + new Transition (3378, 3401), // &in -> &int + new Transition (3387, 3389), // &infin -> &infint + new Transition (3395, 3396), // &inodo -> &inodot + new Transition (3398, 3399), // &In -> &Int + new Transition (3427, 3428), // &Intersec -> &Intersect + new Transition (3467, 3489), // &io -> &iot + new Transition (3471, 3486), // &Io -> &Iot + new Transition (3500, 3501), // &iques -> ¿ + new Transition (3515, 3516), // &isindo -> &isindot + new Transition (3578, 3579), // &jma -> &jmat + new Transition (3692, 4698), // &l -> < + new Transition (3693, 3794), // &lA -> &lAt + new Transition (3698, 4696), // &L -> &Lt + new Transition (3701, 3702), // &Lacu -> &Lacut + new Transition (3705, 3792), // &la -> &lat + new Transition (3707, 3708), // &lacu -> &lacut + new Transition (3713, 3714), // &laemp -> &laempt + new Transition (3750, 3751), // &Laplace -> &Laplacet + new Transition (3766, 3789), // &larr -> &larrt + new Transition (3899, 3900), // &Lef -> &Left + new Transition (3911, 3912), // &LeftAngleBracke -> &LeftAngleBracket + new Transition (3925, 3926), // &lef -> &left + new Transition (3926, 4109), // &left -> &leftt + new Transition (3931, 3948), // &leftarrow -> &leftarrowt + new Transition (3940, 3941), // &LeftArrowRigh -> &LeftArrowRight + new Transition (3972, 3973), // &LeftDoubleBracke -> &LeftDoubleBracket + new Transition (3982, 3983), // &LeftDownTeeVec -> &LeftDownTeeVect + new Transition (3989, 3990), // &LeftDownVec -> &LeftDownVect + new Transition (4021, 4022), // &leftlef -> &leftleft + new Transition (4033, 4034), // &LeftRigh -> &LeftRight + new Transition (4044, 4045), // &Leftrigh -> &Leftright + new Transition (4055, 4056), // &leftrigh -> &leftright + new Transition (4087, 4088), // &LeftRightVec -> &LeftRightVect + new Transition (4104, 4105), // &LeftTeeVec -> &LeftTeeVect + new Transition (4113, 4114), // &leftthree -> &leftthreet + new Transition (4146, 4147), // &LeftUpDownVec -> &LeftUpDownVect + new Transition (4156, 4157), // &LeftUpTeeVec -> &LeftUpTeeVect + new Transition (4163, 4164), // &LeftUpVec -> &LeftUpVect + new Transition (4174, 4175), // &LeftVec -> &LeftVect + new Transition (4194, 4195), // &leqslan -> &leqslant + new Transition (4203, 4204), // &lesdo -> &lesdot + new Transition (4224, 4225), // &lessdo -> &lessdot + new Transition (4229, 4230), // &lesseqg -> &lesseqgt + new Transition (4234, 4235), // &lesseqqg -> &lesseqqgt + new Transition (4248, 4249), // &LessEqualGrea -> &LessEqualGreat + new Transition (4266, 4267), // &LessGrea -> &LessGreat + new Transition (4271, 4272), // &lessg -> &lessgt + new Transition (4287, 4288), // &LessSlan -> &LessSlant + new Transition (4304, 4305), // &lfish -> &lfisht + new Transition (4348, 4375), // &ll -> &llt + new Transition (4362, 4363), // &Llef -> &Lleft + new Transition (4382, 4383), // &Lmido -> &Lmidot + new Transition (4388, 4389), // &lmido -> &lmidot + new Transition (4393, 4394), // &lmous -> &lmoust + new Transition (4422, 4573), // &lo -> &lot + new Transition (4439, 4440), // &LongLef -> &LongLeft + new Transition (4449, 4450), // &Longlef -> &Longleft + new Transition (4461, 4462), // &longlef -> &longleft + new Transition (4472, 4473), // &LongLeftRigh -> &LongLeftRight + new Transition (4483, 4484), // &Longleftrigh -> &Longleftright + new Transition (4494, 4495), // &longleftrigh -> &longleftright + new Transition (4505, 4506), // &longmaps -> &longmapst + new Transition (4512, 4513), // &LongRigh -> &LongRight + new Transition (4523, 4524), // &Longrigh -> &Longright + new Transition (4534, 4535), // &longrigh -> &longright + new Transition (4551, 4552), // &looparrowlef -> &looparrowleft + new Transition (4557, 4558), // &looparrowrigh -> &looparrowright + new Transition (4581, 4582), // &lowas -> &lowast + new Transition (4593, 4594), // &LowerLef -> &LowerLeft + new Transition (4604, 4605), // &LowerRigh -> &LowerRight + new Transition (4625, 4626), // &lparl -> &lparlt + new Transition (4628, 4648), // &lr -> &lrt + new Transition (4652, 4689), // &ls -> &lst + new Transition (4658, 4684), // &Ls -> &Lst + new Transition (4707, 4708), // <do -> <dot + new Transition (4728, 4729), // <ques -> <quest + new Transition (4757, 4758), // &lver -> &lvert + new Transition (4772, 4775), // &mal -> &malt + new Transition (4787, 4788), // &maps -> &mapst + new Transition (4798, 4799), // &mapstolef -> &mapstoleft + new Transition (4827, 4828), // &mDDo -> &mDDot + new Transition (4857, 4858), // &Mellin -> &Mellint + new Transition (4879, 4880), // &midas -> &midast + new Transition (4887, 4888), // &middo -> · + new Transition (4941, 4945), // &ms -> &mst + new Transition (4954, 4955), // &mul -> &mult + new Transition (4965, 5988), // &n -> &nt + new Transition (4966, 5001), // &na -> &nat + new Transition (4971, 5992), // &N -> &Nt + new Transition (4974, 4975), // &Nacu -> &Nacut + new Transition (4979, 4980), // &nacu -> &nacut + new Transition (5049, 5050), // &ncongdo -> &ncongdot + new Transition (5081, 5082), // &nedo -> &nedot + new Transition (5086, 5087), // &Nega -> &Negat + new Transition (5148, 5149), // &Nes -> &Nest + new Transition (5155, 5156), // &NestedGrea -> &NestedGreat + new Transition (5162, 5163), // &NestedGreaterGrea -> &NestedGreaterGreat + new Transition (5184, 5185), // &nexis -> &nexist + new Transition (5195, 5221), // &ng -> &ngt + new Transition (5207, 5208), // &ngeqslan -> &ngeqslant + new Transition (5212, 5219), // &nG -> &nGt + new Transition (5256, 5334), // &nl -> &nlt + new Transition (5272, 5332), // &nL -> &nLt + new Transition (5274, 5275), // &nLef -> &nLeft + new Transition (5282, 5283), // &nlef -> &nleft + new Transition (5293, 5294), // &nLeftrigh -> &nLeftright + new Transition (5304, 5305), // &nleftrigh -> &nleftright + new Transition (5319, 5320), // &nleqslan -> &nleqslant + new Transition (5347, 5376), // &No -> &Not + new Transition (5372, 5378), // &no -> ¬ + new Transition (5387, 5388), // &NotCongruen -> &NotCongruent + new Transition (5404, 5405), // &NotDoubleVer -> &NotDoubleVert + new Transition (5419, 5420), // &NotElemen -> &NotElement + new Transition (5435, 5436), // &NotExis -> &NotExist + new Transition (5442, 5443), // &NotGrea -> &NotGreat + new Transition (5466, 5467), // &NotGreaterGrea -> &NotGreaterGreat + new Transition (5479, 5480), // &NotGreaterSlan -> &NotGreaterSlant + new Transition (5516, 5517), // ¬indo -> ¬indot + new Transition (5530, 5531), // &NotLef -> &NotLeft + new Transition (5563, 5564), // &NotLessGrea -> &NotLessGreat + new Transition (5576, 5577), // &NotLessSlan -> &NotLessSlant + new Transition (5592, 5593), // &NotNes -> &NotNest + new Transition (5599, 5600), // &NotNestedGrea -> &NotNestedGreat + new Transition (5606, 5607), // &NotNestedGreaterGrea -> &NotNestedGreaterGreat + new Transition (5648, 5649), // &NotPrecedesSlan -> &NotPrecedesSlant + new Transition (5668, 5669), // &NotReverseElemen -> &NotReverseElement + new Transition (5673, 5674), // &NotRigh -> &NotRight + new Transition (5704, 5705), // &NotSquareSubse -> &NotSquareSubset + new Transition (5717, 5718), // &NotSquareSuperse -> &NotSquareSuperset + new Transition (5729, 5730), // &NotSubse -> &NotSubset + new Transition (5754, 5755), // &NotSucceedsSlan -> &NotSucceedsSlant + new Transition (5772, 5773), // &NotSuperse -> &NotSuperset + new Transition (5811, 5812), // &NotVer -> &NotVert + new Transition (5823, 5834), // &npar -> &npart + new Transition (5839, 5840), // &npolin -> &npolint + new Transition (5855, 5889), // &nr -> &nrt + new Transition (5871, 5872), // &nRigh -> &nRight + new Transition (5881, 5882), // &nrigh -> &nright + new Transition (5912, 5913), // &nshor -> &nshort + new Transition (5959, 5960), // &nsubse -> &nsubset + new Transition (5980, 5981), // &nsupse -> &nsupset + new Transition (6015, 6016), // &ntrianglelef -> &ntriangleleft + new Transition (6024, 6025), // &ntrianglerigh -> &ntriangleright + new Transition (6068, 6071), // &nvg -> &nvgt + new Transition (6084, 6091), // &nvl -> &nvlt + new Transition (6097, 6102), // &nvr -> &nvrt + new Transition (6131, 6399), // &O -> &Ot + new Transition (6134, 6135), // &Oacu -> &Oacut + new Transition (6138, 6405), // &o -> &ot + new Transition (6141, 6142), // &oacu -> &oacut + new Transition (6145, 6146), // &oas -> &oast + new Transition (6182, 6183), // &odo -> &odot + new Transition (6210, 6225), // &og -> &ogt + new Transition (6235, 6236), // &oin -> &oint + new Transition (6238, 6256), // &ol -> &olt + new Transition (6322, 6323), // &OpenCurlyDoubleQuo -> &OpenCurlyDoubleQuot + new Transition (6328, 6329), // &OpenCurlyQuo -> &OpenCurlyQuot + new Transition (6448, 6449), // &OverBracke -> &OverBracket + new Transition (6455, 6456), // &OverParen -> &OverParent + new Transition (6465, 6480), // &par -> &part + new Transition (6484, 6485), // &Par -> &Part + new Transition (6498, 6513), // &per -> &pert + new Transition (6500, 6501), // &percn -> &percnt + new Transition (6534, 6535), // &phmma -> &phmmat + new Transition (6543, 6545), // &pi -> &pit + new Transition (6567, 6603), // &plus -> &plust + new Transition (6624, 6625), // &poin -> &point + new Transition (6627, 6628), // &pointin -> &pointint + new Transition (6688, 6689), // &PrecedesSlan -> &PrecedesSlant + new Transition (6751, 6752), // &Produc -> &Product + new Transition (6770, 6783), // &prop -> &propt + new Transition (6774, 6775), // &Propor -> &Proport + new Transition (6822, 6823), // &qin -> &qint + new Transition (6848, 6849), // &qua -> &quat + new Transition (6859, 6860), // &quatin -> &quatint + new Transition (6863, 6864), // &ques -> &quest + new Transition (6873, 6874), // &quo -> " + new Transition (6876, 7567), // &r -> &rt + new Transition (6877, 6968), // &rA -> &rAt + new Transition (6882, 6973), // &ra -> &rat + new Transition (6889, 6890), // &Racu -> &Racut + new Transition (6893, 6894), // &racu -> &racut + new Transition (6903, 6904), // &raemp -> &raempt + new Transition (6926, 6960), // &Rarr -> &Rarrt + new Transition (6932, 6963), // &rarr -> &rarrt + new Transition (7084, 7085), // &realpar -> &realpart + new Transition (7089, 7090), // &rec -> &rect + new Transition (7107, 7108), // &ReverseElemen -> &ReverseElement + new Transition (7138, 7139), // &rfish -> &rfisht + new Transition (7173, 7174), // &Righ -> &Right + new Transition (7185, 7186), // &RightAngleBracke -> &RightAngleBracket + new Transition (7201, 7202), // &righ -> &right + new Transition (7202, 7354), // &right -> &rightt + new Transition (7207, 7223), // &rightarrow -> &rightarrowt + new Transition (7215, 7216), // &RightArrowLef -> &RightArrowLeft + new Transition (7247, 7248), // &RightDoubleBracke -> &RightDoubleBracket + new Transition (7257, 7258), // &RightDownTeeVec -> &RightDownTeeVect + new Transition (7264, 7265), // &RightDownVec -> &RightDownVect + new Transition (7296, 7297), // &rightlef -> &rightleft + new Transition (7317, 7318), // &rightrigh -> &rightright + new Transition (7349, 7350), // &RightTeeVec -> &RightTeeVect + new Transition (7358, 7359), // &rightthree -> &rightthreet + new Transition (7391, 7392), // &RightUpDownVec -> &RightUpDownVect + new Transition (7401, 7402), // &RightUpTeeVec -> &RightUpTeeVect + new Transition (7408, 7409), // &RightUpVec -> &RightUpVect + new Transition (7419, 7420), // &RightVec -> &RightVect + new Transition (7436, 7437), // &risingdo -> &risingdot + new Transition (7456, 7457), // &rmous -> &rmoust + new Transition (7469, 7495), // &ro -> &rot + new Transition (7516, 7517), // &rparg -> &rpargt + new Transition (7523, 7524), // &rppolin -> &rppolint + new Transition (7534, 7535), // &Rrigh -> &Rright + new Transition (7585, 7586), // &rtril -> &rtrilt + new Transition (7610, 8096), // &S -> &St + new Transition (7613, 7614), // &Sacu -> &Sacut + new Transition (7617, 8100), // &s -> &st + new Transition (7620, 7621), // &sacu -> &sacut + new Transition (7684, 7685), // &scpolin -> &scpolint + new Transition (7696, 7697), // &sdo -> &sdot + new Transition (7703, 7729), // &se -> &set + new Transition (7718, 7719), // &sec -> § + new Transition (7738, 7739), // &sex -> &sext + new Transition (7774, 7775), // &Shor -> &Short + new Transition (7788, 7789), // &ShortLef -> &ShortLeft + new Transition (7797, 7798), // &shor -> &short + new Transition (7815, 7816), // &ShortRigh -> &ShortRight + new Transition (7850, 7851), // &simdo -> &simdot + new Transition (7894, 7924), // &sm -> &smt + new Transition (7899, 7900), // &smallse -> &smallset + new Transition (7937, 7938), // &sof -> &soft + new Transition (7963, 7964), // &spadesui -> &spadesuit + new Transition (7981, 7982), // &Sqr -> &Sqrt + new Transition (7991, 7992), // &sqsubse -> &sqsubset + new Transition (8002, 8003), // &sqsupse -> &sqsupset + new Transition (8020, 8021), // &SquareIn -> &SquareInt + new Transition (8026, 8027), // &SquareIntersec -> &SquareIntersect + new Transition (8036, 8037), // &SquareSubse -> &SquareSubset + new Transition (8049, 8050), // &SquareSuperse -> &SquareSuperset + new Transition (8077, 8091), // &ss -> &sst + new Transition (8081, 8082), // &sse -> &sset + new Transition (8110, 8111), // &straigh -> &straight + new Transition (8134, 8135), // &subdo -> &subdot + new Transition (8142, 8143), // &subedo -> &subedot + new Transition (8147, 8148), // &submul -> &submult + new Transition (8166, 8167), // &Subse -> &Subset + new Transition (8170, 8171), // &subse -> &subset + new Transition (8232, 8233), // &SucceedsSlan -> &SucceedsSlant + new Transition (8272, 8273), // &SuchTha -> &SuchThat + new Transition (8293, 8294), // &supdo -> &supdot + new Transition (8305, 8306), // &supedo -> &supedot + new Transition (8311, 8312), // &Superse -> &Superset + new Transition (8335, 8336), // &supmul -> &supmult + new Transition (8349, 8350), // &Supse -> &Supset + new Transition (8353, 8354), // &supse -> &supset + new Transition (8408, 8409), // &targe -> &target + new Transition (8446, 8447), // &tdo -> &tdot + new Transition (8462, 8484), // &the -> &thet + new Transition (8468, 8481), // &The -> &Thet + new Transition (8587, 8588), // &tin -> &tint + new Transition (8597, 8598), // &topbo -> &topbot + new Transition (8633, 8693), // &tri -> &trit + new Transition (8647, 8648), // &trianglelef -> &triangleleft + new Transition (8658, 8659), // &trianglerigh -> &triangleright + new Transition (8665, 8666), // &trido -> &tridot + new Transition (8682, 8683), // &TripleDo -> &TripleDot + new Transition (8705, 8727), // &Ts -> &Tst + new Transition (8709, 8732), // &ts -> &tst + new Transition (8739, 8740), // &twix -> &twixt + new Transition (8749, 8750), // &twoheadlef -> &twoheadleft + new Transition (8760, 8761), // &twoheadrigh -> &twoheadright + new Transition (8768, 9166), // &U -> &Ut + new Transition (8771, 8772), // &Uacu -> &Uacut + new Transition (8775, 9161), // &u -> &ut + new Transition (8778, 8779), // &uacu -> &uacut + new Transition (8852, 8853), // &ufish -> &ufisht + new Transition (8887, 8900), // &ul -> &ult + new Transition (8930, 8931), // &UnderBracke -> &UnderBracket + new Transition (8937, 8938), // &UnderParen -> &UnderParent + new Transition (9055, 9056), // &upharpoonlef -> &upharpoonleft + new Transition (9061, 9062), // &upharpoonrigh -> &upharpoonright + new Transition (9073, 9074), // &UpperLef -> &UpperLeft + new Transition (9084, 9085), // &UpperRigh -> &UpperRight + new Transition (9127, 9149), // &ur -> &urt + new Transition (9163, 9164), // &utdo -> &utdot + new Transition (9205, 9206), // &vangr -> &vangrt + new Transition (9208, 9279), // &var -> &vart + new Transition (9224, 9225), // &varno -> &varnot + new Transition (9239, 9240), // &varprop -> &varpropt + new Transition (9261, 9262), // &varsubse -> &varsubset + new Transition (9271, 9272), // &varsupse -> &varsupset + new Transition (9281, 9282), // &varthe -> &varthet + new Transition (9294, 9295), // &vartrianglelef -> &vartriangleleft + new Transition (9300, 9301), // &vartrianglerigh -> &vartriangleright + new Transition (9360, 9370), // &Ver -> &Vert + new Transition (9365, 9372), // &ver -> &vert + new Transition (9392, 9393), // &VerticalSepara -> &VerticalSeparat + new Transition (9420, 9421), // &vl -> &vlt + new Transition (9445, 9446), // &vr -> &vrt + new Transition (9536, 9537), // &wrea -> &wreat + new Transition (9560, 9561), // &xd -> &xdt + new Transition (9602, 9618), // &xo -> &xot + new Transition (9604, 9605), // &xodo -> &xodot + new Transition (9645, 9651), // &xu -> &xut + new Transition (9668, 9669), // &Yacu -> &Yacut + new Transition (9675, 9676), // &yacu -> &yacut + new Transition (9750, 9751), // &Zacu -> &Zacut + new Transition (9757, 9758), // &zacu -> &zacut + new Transition (9778, 9779), // &Zdo -> &Zdot + new Transition (9782, 9783), // &zdo -> &zdot + new Transition (9785, 9808), // &ze -> &zet + new Transition (9786, 9787), // &zee -> &zeet + new Transition (9791, 9805), // &Ze -> &Zet + new Transition (9796, 9797) // &ZeroWid -> &ZeroWidt + }; + TransitionTable_u = new Transition[278] { + new Transition (0, 8775), // & -> &u + new Transition (1, 281), // &A -> &Au + new Transition (3, 4), // &Aac -> &Aacu + new Transition (8, 285), // &a -> &au + new Transition (10, 11), // &aac -> &aacu + new Transition (27, 42), // &ac -> &acu + new Transition (220, 221), // &ApplyF -> &ApplyFu + new Transition (301, 767), // &b -> &bu + new Transition (331, 781), // &B -> &Bu + new Transition (380, 381), // &bdq -> &bdqu + new Transition (386, 387), // &beca -> &becau + new Transition (392, 393), // &Beca -> &Becau + new Transition (411, 412), // &berno -> &bernou + new Transition (416, 417), // &Berno -> &Bernou + new Transition (443, 497), // &big -> &bigu + new Transition (444, 452), // &bigc -> &bigcu + new Transition (461, 462), // &bigopl -> &bigoplu + new Transition (473, 474), // &bigsqc -> &bigsqcu + new Transition (488, 494), // &bigtriangle -> &bigtriangleu + new Transition (499, 500), // &bigupl -> &biguplu + new Transition (532, 533), // &blacksq -> &blacksqu + new Transition (582, 583), // &bneq -> &bnequ + new Transition (613, 678), // &box -> &boxu + new Transition (636, 650), // &boxH -> &boxHu + new Transition (638, 654), // &boxh -> &boxhu + new Transition (658, 659), // &boxmin -> &boxminu + new Transition (663, 664), // &boxpl -> &boxplu + new Transition (763, 764), // &bsolhs -> &bsolhsu + new Transition (789, 1315), // &C -> &Cu + new Transition (791, 792), // &Cac -> &Cacu + new Transition (796, 1292), // &c -> &cu + new Transition (798, 799), // &cac -> &cacu + new Transition (813, 814), // &capbrc -> &capbrcu + new Transition (817, 821), // &capc -> &capcu + new Transition (861, 900), // &cc -> &ccu + new Transition (1034, 1035), // &CircleMin -> &CircleMinu + new Transition (1039, 1040), // &CirclePl -> &CirclePlu + new Transition (1080, 1081), // &ClockwiseConto -> &ClockwiseContou + new Transition (1094, 1095), // &CloseC -> &CloseCu + new Transition (1100, 1101), // &CloseCurlyDo -> &CloseCurlyDou + new Transition (1105, 1106), // &CloseCurlyDoubleQ -> &CloseCurlyDoubleQu + new Transition (1111, 1112), // &CloseCurlyQ -> &CloseCurlyQu + new Transition (1117, 1118), // &cl -> &clu + new Transition (1120, 1122), // &clubs -> &clubsu + new Transition (1126, 1226), // &Co -> &Cou + new Transition (1173, 1174), // &Congr -> &Congru + new Transition (1188, 1189), // &Conto -> &Contou + new Transition (1212, 1213), // &Coprod -> &Coprodu + new Transition (1244, 1245), // &CounterClockwiseConto -> &CounterClockwiseContou + new Transition (1274, 1278), // &cs -> &csu + new Transition (1330, 1334), // &cupc -> &cupcu + new Transition (1362, 1363), // &curlyeqs -> &curlyeqsu + new Transition (1432, 2077), // &d -> &du + new Transition (1568, 1569), // &DiacriticalAc -> &DiacriticalAcu + new Transition (1574, 1577), // &DiacriticalDo -> &DiacriticalDou + new Transition (1582, 1583), // &DiacriticalDoubleAc -> &DiacriticalDoubleAcu + new Transition (1612, 1613), // &diamonds -> &diamondsu + new Transition (1679, 1731), // &do -> &dou + new Transition (1685, 1744), // &Do -> &Dou + new Transition (1708, 1709), // &DotEq -> &DotEqu + new Transition (1715, 1716), // &dotmin -> &dotminu + new Transition (1720, 1721), // &dotpl -> &dotplu + new Transition (1725, 1726), // &dotsq -> &dotsqu + new Transition (1752, 1753), // &DoubleConto -> &DoubleContou + new Transition (2108, 2447), // &E -> &Eu + new Transition (2110, 2111), // &Eac -> &Eacu + new Transition (2115, 2451), // &e -> &eu + new Transition (2117, 2118), // &eac -> &eacu + new Transition (2255, 2256), // &EmptySmallSq -> &EmptySmallSqu + new Transition (2273, 2274), // &EmptyVerySmallSq -> &EmptyVerySmallSqu + new Transition (2319, 2320), // &epl -> &eplu + new Transition (2339, 2372), // &eq -> &equ + new Transition (2367, 2368), // &Eq -> &Equ + new Transition (2392, 2393), // &Equilibri -> &Equilibriu + new Transition (2565, 2566), // &FilledSmallSq -> &FilledSmallSqu + new Transition (2581, 2582), // &FilledVerySmallSq -> &FilledVerySmallSqu + new Transition (2608, 2630), // &Fo -> &Fou + new Transition (2703, 2704), // &gac -> &gacu + new Transition (2873, 2874), // &GreaterEq -> &GreaterEqu + new Transition (2883, 2884), // &GreaterF -> &GreaterFu + new Transition (2888, 2889), // &GreaterFullEq -> &GreaterFullEqu + new Transition (2912, 2913), // &GreaterSlantEq -> &GreaterSlantEqu + new Transition (2959, 2960), // >q -> >qu + new Transition (3014, 3207), // &H -> &Hu + new Transition (3078, 3080), // &hearts -> &heartsu + new Transition (3214, 3215), // &HumpDownH -> &HumpDownHu + new Transition (3220, 3221), // &HumpEq -> &HumpEqu + new Transition (3226, 3227), // &hyb -> &hybu + new Transition (3236, 3539), // &I -> &Iu + new Transition (3238, 3239), // &Iac -> &Iacu + new Transition (3243, 3544), // &i -> &iu + new Transition (3245, 3246), // &iac -> &iacu + new Transition (3497, 3498), // &iq -> &iqu + new Transition (3555, 3608), // &J -> &Ju + new Transition (3561, 3613), // &j -> &ju + new Transition (3692, 4742), // &l -> &lu + new Transition (3700, 3701), // &Lac -> &Lacu + new Transition (3706, 3707), // &lac -> &lacu + new Transition (3755, 3756), // &laq -> &laqu + new Transition (3832, 3835), // &lbrksl -> &lbrkslu + new Transition (3843, 3862), // &lc -> &lcu + new Transition (3873, 3874), // &ldq -> &ldqu + new Transition (3879, 3885), // &ldr -> &ldru + new Transition (3962, 3963), // &LeftDo -> &LeftDou + new Transition (4010, 4016), // &leftharpoon -> &leftharpoonu + new Transition (4075, 4076), // &leftrightsq -> &leftrightsqu + new Transition (4133, 4134), // &LeftTriangleEq -> &LeftTriangleEqu + new Transition (4241, 4242), // &LessEq -> &LessEqu + new Transition (4253, 4254), // &LessF -> &LessFu + new Transition (4258, 4259), // &LessFullEq -> &LessFullEqu + new Transition (4290, 4291), // &LessSlantEq -> &LessSlantEqu + new Transition (4327, 4330), // &lhar -> &lharu + new Transition (4391, 4392), // &lmo -> &lmou + new Transition (4569, 4570), // &lopl -> &loplu + new Transition (4654, 4655), // &lsaq -> &lsaqu + new Transition (4676, 4679), // &lsq -> &lsqu + new Transition (4725, 4726), // <q -> <qu + new Transition (4743, 4750), // &lur -> &luru + new Transition (4767, 4952), // &m -> &mu + new Transition (4781, 4950), // &M -> &Mu + new Transition (4789, 4801), // &mapsto -> &mapstou + new Transition (4832, 4833), // &meas -> &measu + new Transition (4845, 4846), // &Medi -> &Mediu + new Transition (4890, 4891), // &min -> &minu + new Transition (4896, 4898), // &minusd -> &minusdu + new Transition (4901, 4902), // &Min -> &Minu + new Transition (4905, 4906), // &MinusPl -> &MinusPlu + new Transition (4918, 4919), // &mnpl -> &mnplu + new Transition (4965, 6032), // &n -> &nu + new Transition (4971, 6030), // &N -> &Nu + new Transition (4973, 4974), // &Nac -> &Nacu + new Transition (4978, 4979), // &nac -> &nacu + new Transition (5001, 5002), // &nat -> &natu + new Transition (5010, 5014), // &nb -> &nbu + new Transition (5020, 5052), // &nc -> &ncu + new Transition (5094, 5095), // &NegativeMedi -> &NegativeMediu + new Transition (5135, 5136), // &neq -> &nequ + new Transition (5380, 5390), // &NotC -> &NotCu + new Transition (5384, 5385), // &NotCongr -> &NotCongru + new Transition (5397, 5398), // &NotDo -> &NotDou + new Transition (5422, 5423), // &NotEq -> &NotEqu + new Transition (5448, 5449), // &NotGreaterEq -> &NotGreaterEqu + new Transition (5453, 5454), // &NotGreaterF -> &NotGreaterFu + new Transition (5458, 5459), // &NotGreaterFullEq -> &NotGreaterFullEqu + new Transition (5482, 5483), // &NotGreaterSlantEq -> &NotGreaterSlantEqu + new Transition (5493, 5494), // &NotH -> &NotHu + new Transition (5501, 5502), // &NotHumpDownH -> &NotHumpDownHu + new Transition (5507, 5508), // &NotHumpEq -> &NotHumpEqu + new Transition (5546, 5547), // &NotLeftTriangleEq -> &NotLeftTriangleEqu + new Transition (5555, 5556), // &NotLessEq -> &NotLessEqu + new Transition (5579, 5580), // &NotLessSlantEq -> &NotLessSlantEqu + new Transition (5640, 5641), // &NotPrecedesEq -> &NotPrecedesEqu + new Transition (5651, 5652), // &NotPrecedesSlantEq -> &NotPrecedesSlantEqu + new Transition (5689, 5690), // &NotRightTriangleEq -> &NotRightTriangleEqu + new Transition (5694, 5726), // &NotS -> &NotSu + new Transition (5695, 5696), // &NotSq -> &NotSqu + new Transition (5700, 5701), // &NotSquareS -> &NotSquareSu + new Transition (5708, 5709), // &NotSquareSubsetEq -> &NotSquareSubsetEqu + new Transition (5721, 5722), // &NotSquareSupersetEq -> &NotSquareSupersetEqu + new Transition (5733, 5734), // &NotSubsetEq -> &NotSubsetEqu + new Transition (5746, 5747), // &NotSucceedsEq -> &NotSucceedsEqu + new Transition (5757, 5758), // &NotSucceedsSlantEq -> &NotSucceedsSlantEqu + new Transition (5776, 5777), // &NotSupersetEq -> &NotSupersetEqu + new Transition (5788, 5789), // &NotTildeEq -> &NotTildeEqu + new Transition (5793, 5794), // &NotTildeF -> &NotTildeFu + new Transition (5798, 5799), // &NotTildeFullEq -> &NotTildeFullEqu + new Transition (5844, 5845), // &nprc -> &nprcu + new Transition (5895, 5951), // &ns -> &nsu + new Transition (5898, 5899), // &nscc -> &nsccu + new Transition (5943, 5944), // &nsqs -> &nsqsu + new Transition (6131, 6422), // &O -> &Ou + new Transition (6133, 6134), // &Oac -> &Oacu + new Transition (6138, 6426), // &o -> &ou + new Transition (6140, 6141), // &oac -> &oacu + new Transition (6290, 6291), // &omin -> &ominu + new Transition (6309, 6310), // &OpenC -> &OpenCu + new Transition (6315, 6316), // &OpenCurlyDo -> &OpenCurlyDou + new Transition (6320, 6321), // &OpenCurlyDoubleQ -> &OpenCurlyDoubleQu + new Transition (6326, 6327), // &OpenCurlyQ -> &OpenCurlyQu + new Transition (6336, 6337), // &opl -> &oplu + new Transition (6463, 6807), // &p -> &pu + new Transition (6555, 6566), // &pl -> &plu + new Transition (6580, 6583), // &plusd -> &plusdu + new Transition (6587, 6588), // &Pl -> &Plu + new Transition (6592, 6593), // &PlusMin -> &PlusMinu + new Transition (6622, 6636), // &po -> &pou + new Transition (6642, 6790), // &pr -> &pru + new Transition (6647, 6648), // &prc -> &prcu + new Transition (6664, 6665), // &precc -> &preccu + new Transition (6680, 6681), // &PrecedesEq -> &PrecedesEqu + new Transition (6691, 6692), // &PrecedesSlantEq -> &PrecedesSlantEqu + new Transition (6749, 6750), // &Prod -> &Produ + new Transition (6765, 6766), // &profs -> &profsu + new Transition (6817, 6847), // &q -> &qu + new Transition (6876, 7601), // &r -> &ru + new Transition (6883, 6893), // &rac -> &racu + new Transition (6886, 7590), // &R -> &Ru + new Transition (6888, 6889), // &Rac -> &Racu + new Transition (6921, 6922), // &raq -> &raqu + new Transition (7016, 7019), // &rbrksl -> &rbrkslu + new Transition (7027, 7046), // &rc -> &rcu + new Transition (7063, 7064), // &rdq -> &rdqu + new Transition (7110, 7111), // &ReverseEq -> &ReverseEqu + new Transition (7117, 7118), // &ReverseEquilibri -> &ReverseEquilibriu + new Transition (7124, 7125), // &ReverseUpEq -> &ReverseUpEqu + new Transition (7131, 7132), // &ReverseUpEquilibri -> &ReverseUpEquilibriu + new Transition (7157, 7160), // &rhar -> &rharu + new Transition (7237, 7238), // &RightDo -> &RightDou + new Transition (7285, 7291), // &rightharpoon -> &rightharpoonu + new Transition (7327, 7328), // &rightsq -> &rightsqu + new Transition (7378, 7379), // &RightTriangleEq -> &RightTriangleEqu + new Transition (7454, 7455), // &rmo -> &rmou + new Transition (7485, 7501), // &Ro -> &Rou + new Transition (7491, 7492), // &ropl -> &roplu + new Transition (7544, 7545), // &rsaq -> &rsaqu + new Transition (7559, 7562), // &rsq -> &rsqu + new Transition (7602, 7603), // &rul -> &rulu + new Transition (7610, 8127), // &S -> &Su + new Transition (7612, 7613), // &Sac -> &Sacu + new Transition (7617, 8130), // &s -> &su + new Transition (7619, 7620), // &sac -> &sacu + new Transition (7625, 7626), // &sbq -> &sbqu + new Transition (7645, 7646), // &scc -> &sccu + new Transition (7732, 7733), // &setmin -> &setminu + new Transition (7869, 7870), // &simpl -> &simplu + new Transition (7903, 7904), // &smallsetmin -> &smallsetminu + new Transition (7960, 7962), // &spades -> &spadesu + new Transition (7968, 8008), // &sq -> &squ + new Transition (7969, 7975), // &sqc -> &sqcu + new Transition (7980, 8010), // &Sq -> &Squ + new Transition (7984, 7985), // &sqs -> &sqsu + new Transition (8032, 8033), // &SquareS -> &SquareSu + new Transition (8040, 8041), // &SquareSubsetEq -> &SquareSubsetEqu + new Transition (8053, 8054), // &SquareSupersetEq -> &SquareSupersetEqu + new Transition (8145, 8146), // &subm -> &submu + new Transition (8156, 8157), // &subpl -> &subplu + new Transition (8169, 8193), // &subs -> &subsu + new Transition (8179, 8180), // &SubsetEq -> &SubsetEqu + new Transition (8208, 8209), // &succc -> &succcu + new Transition (8224, 8225), // &SucceedsEq -> &SucceedsEqu + new Transition (8235, 8236), // &SucceedsSlantEq -> &SucceedsSlantEqu + new Transition (8296, 8297), // &supds -> &supdsu + new Transition (8315, 8316), // &SupersetEq -> &SupersetEqu + new Transition (8321, 8325), // &suphs -> &suphsu + new Transition (8333, 8334), // &supm -> &supmu + new Transition (8344, 8345), // &suppl -> &supplu + new Transition (8352, 8370), // &sups -> &supsu + new Transition (8401, 8411), // &Ta -> &Tau + new Transition (8405, 8413), // &ta -> &tau + new Transition (8555, 8556), // &TildeEq -> &TildeEqu + new Transition (8560, 8561), // &TildeF -> &TildeFu + new Transition (8565, 8566), // &TildeFullEq -> &TildeFullEqu + new Transition (8672, 8673), // &trimin -> &triminu + new Transition (8686, 8687), // &tripl -> &triplu + new Transition (8701, 8702), // &trpezi -> &trpeziu + new Transition (8768, 9187), // &U -> &Uu + new Transition (8770, 8771), // &Uac -> &Uacu + new Transition (8775, 9182), // &u -> &uu + new Transition (8777, 8778), // &uac -> &uacu + new Transition (8950, 8951), // &UnionPl -> &UnionPlu + new Transition (8983, 9118), // &up -> &upu + new Transition (9035, 9036), // &UpEq -> &UpEqu + new Transition (9042, 9043), // &UpEquilibri -> &UpEquilibriu + new Transition (9064, 9065), // &upl -> &uplu + new Transition (9252, 9258), // &vars -> &varsu + new Transition (9426, 9427), // &vns -> &vnsu + new Transition (9454, 9458), // &vs -> &vsu + new Transition (9548, 9645), // &x -> &xu + new Transition (9549, 9557), // &xc -> &xcu + new Transition (9614, 9615), // &xopl -> &xoplu + new Transition (9641, 9642), // &xsqc -> &xsqcu + new Transition (9647, 9648), // &xupl -> &xuplu + new Transition (9665, 9740), // &Y -> &Yu + new Transition (9667, 9668), // &Yac -> &Yacu + new Transition (9672, 9736), // &y -> &yu + new Transition (9674, 9675), // &yac -> &yacu + new Transition (9749, 9750), // &Zac -> &Zacu + new Transition (9756, 9757) // &zac -> &zacu + }; + TransitionTable_v = new Transition[75] { + new Transition (0, 9201), // & -> &v + new Transition (17, 18), // &Abre -> &Abrev + new Transition (23, 24), // &abre -> &abrev + new Transition (69, 70), // &Agra -> &Agrav + new Transition (75, 76), // &agra -> &agrav + new Transition (120, 134), // &and -> &andv + new Transition (165, 167), // &angrt -> &angrtv + new Transition (341, 342), // &Bar -> &Barv + new Transition (344, 345), // &bar -> &barv + new Transition (402, 403), // &bempty -> &bemptyv + new Transition (443, 503), // &big -> &bigv + new Transition (584, 585), // &bnequi -> &bnequiv + new Transition (613, 693), // &box -> &boxv + new Transition (726, 727), // &Bre -> &Brev + new Transition (730, 735), // &br -> &brv + new Transition (731, 732), // &bre -> &brev + new Transition (930, 931), // &cempty -> &cemptyv + new Transition (1292, 1399), // &cu -> &cuv + new Transition (1346, 1381), // &cur -> &curv + new Transition (1354, 1367), // &curly -> &curlyv + new Transition (1455, 1461), // &dash -> &dashv + new Transition (1458, 1459), // &Dash -> &Dashv + new Transition (1532, 1533), // &dempty -> &demptyv + new Transition (1589, 1590), // &DiacriticalGra -> &DiacriticalGrav + new Transition (1599, 1643), // &di -> &div + new Transition (1917, 1918), // &DownBre -> &DownBrev + new Transition (2189, 2190), // &Egra -> &Egrav + new Transition (2194, 2195), // &egra -> &egrav + new Transition (2240, 2261), // &empty -> &emptyv + new Transition (2324, 2337), // &epsi -> &epsiv + new Transition (2339, 2402), // &eq -> &eqv + new Transition (2396, 2397), // &equi -> &equiv + new Transition (2626, 2628), // &fork -> &forkv + new Transition (2701, 3002), // &g -> &gv + new Transition (2726, 2727), // &Gbre -> &Gbrev + new Transition (2732, 2733), // &gbre -> &gbrev + new Transition (2862, 2863), // &gra -> &grav + new Transition (3291, 3292), // &Igra -> &Igrav + new Transition (3297, 3298), // &igra -> &igrav + new Transition (3398, 3444), // &In -> &Inv + new Transition (3512, 3524), // &isin -> &isinv + new Transition (3520, 3522), // &isins -> &isinsv + new Transition (3628, 3630), // &kappa -> &kappav + new Transition (3692, 4755), // &l -> &lv + new Transition (3715, 3716), // &laempty -> &laemptyv + new Transition (4965, 6043), // &n -> &nv + new Transition (5088, 5089), // &Negati -> &Negativ + new Transition (5137, 5138), // &nequi -> &nequiv + new Transition (5219, 5225), // &nGt -> &nGtv + new Transition (5240, 5246), // &ni -> &niv + new Transition (5332, 5341), // &nLt -> &nLtv + new Transition (5513, 5521), // ¬in -> ¬inv + new Transition (5621, 5623), // ¬ni -> ¬niv + new Transition (5657, 5658), // &NotRe -> &NotRev + new Transition (6131, 6435), // &O -> &Ov + new Transition (6138, 6430), // &o -> &ov + new Transition (6179, 6180), // &odi -> &odiv + new Transition (6216, 6217), // &Ogra -> &Ograv + new Transition (6221, 6222), // &ogra -> &ograv + new Transition (6342, 6374), // &or -> &orv + new Transition (6528, 6530), // &phi -> &phiv + new Transition (6543, 6553), // &pi -> &piv + new Transition (6563, 6564), // &plank -> &plankv + new Transition (6905, 6906), // &raempty -> &raemptyv + new Transition (7072, 7097), // &Re -> &Rev + new Transition (7167, 7169), // &rho -> &rhov + new Transition (7841, 7845), // &sigma -> &sigmav + new Transition (8485, 8491), // &theta -> &thetav + new Transition (8807, 8808), // &Ubre -> &Ubrev + new Transition (8811, 8812), // &ubre -> &ubrev + new Transition (8862, 8863), // &Ugra -> &Ugrav + new Transition (8868, 8869), // &ugra -> &ugrav + new Transition (9303, 9471), // &V -> &Vv + new Transition (9310, 9312), // &vBar -> &vBarv + new Transition (9548, 9655) // &x -> &xv + }; + TransitionTable_w = new Transition[137] { + new Transition (0, 9490), // & -> &w + new Transition (8, 289), // &a -> &aw + new Transition (341, 349), // &Bar -> &Barw + new Transition (344, 353), // &bar -> &barw + new Transition (426, 431), // &bet -> &betw + new Transition (443, 507), // &big -> &bigw + new Transition (490, 491), // &bigtriangledo -> &bigtriangledow + new Transition (516, 517), // &bkaro -> &bkarow + new Transition (548, 549), // &blacktriangledo -> &blacktriangledow + new Transition (598, 608), // &bo -> &bow + new Transition (796, 1407), // &c -> &cw + new Transition (991, 992), // &circlearro -> &circlearrow + new Transition (1071, 1072), // &Clock -> &Clockw + new Transition (1235, 1236), // &CounterClock -> &CounterClockw + new Transition (1292, 1403), // &cu -> &cuw + new Transition (1354, 1371), // &curly -> &curlyw + new Transition (1386, 1387), // &curvearro -> &curvearrow + new Transition (1432, 2086), // &d -> &dw + new Transition (1467, 1468), // &dbkaro -> &dbkarow + new Transition (1679, 1895), // &do -> &dow + new Transition (1685, 1881), // &Do -> &Dow + new Transition (1737, 1738), // &doublebar -> &doublebarw + new Transition (1765, 1768), // &DoubleDo -> &DoubleDow + new Transition (1773, 1774), // &DoubleDownArro -> &DoubleDownArrow + new Transition (1783, 1784), // &DoubleLeftArro -> &DoubleLeftArrow + new Transition (1794, 1795), // &DoubleLeftRightArro -> &DoubleLeftRightArrow + new Transition (1811, 1812), // &DoubleLongLeftArro -> &DoubleLongLeftArrow + new Transition (1822, 1823), // &DoubleLongLeftRightArro -> &DoubleLongLeftRightArrow + new Transition (1833, 1834), // &DoubleLongRightArro -> &DoubleLongRightArrow + new Transition (1844, 1845), // &DoubleRightArro -> &DoubleRightArrow + new Transition (1856, 1857), // &DoubleUpArro -> &DoubleUpArrow + new Transition (1860, 1861), // &DoubleUpDo -> &DoubleUpDow + new Transition (1866, 1867), // &DoubleUpDownArro -> &DoubleUpDownArrow + new Transition (1886, 1887), // &DownArro -> &DownArrow + new Transition (1892, 1893), // &Downarro -> &Downarrow + new Transition (1900, 1901), // &downarro -> &downarrow + new Transition (1912, 1913), // &DownArrowUpArro -> &DownArrowUpArrow + new Transition (1922, 1923), // &downdo -> &downdow + new Transition (1928, 1929), // &downdownarro -> &downdownarrow + new Transition (2020, 2021), // &DownTeeArro -> &DownTeeArrow + new Transition (2028, 2029), // &drbkaro -> &drbkarow + new Transition (2689, 2690), // &fro -> &frow + new Transition (3050, 3056), // &harr -> &harrw + new Transition (3113, 3120), // &hks -> &hksw + new Transition (3117, 3118), // &hksearo -> &hksearow + new Transition (3123, 3124), // &hkswaro -> &hkswarow + new Transition (3145, 3146), // &hookleftarro -> &hookleftarrow + new Transition (3156, 3157), // &hookrightarro -> &hookrightarrow + new Transition (3211, 3212), // &HumpDo -> &HumpDow + new Transition (3916, 3917), // &LeftArro -> &LeftArrow + new Transition (3922, 3923), // &Leftarro -> &Leftarrow + new Transition (3930, 3931), // &leftarro -> &leftarrow + new Transition (3945, 3946), // &LeftArrowRightArro -> &LeftArrowRightArrow + new Transition (3962, 3975), // &LeftDo -> &LeftDow + new Transition (4012, 4013), // &leftharpoondo -> &leftharpoondow + new Transition (4026, 4027), // &leftleftarro -> &leftleftarrow + new Transition (4038, 4039), // &LeftRightArro -> &LeftRightArrow + new Transition (4049, 4050), // &Leftrightarro -> &Leftrightarrow + new Transition (4060, 4061), // &leftrightarro -> &leftrightarrow + new Transition (4082, 4083), // &leftrightsquigarro -> &leftrightsquigarrow + new Transition (4099, 4100), // &LeftTeeArro -> &LeftTeeArrow + new Transition (4141, 4142), // &LeftUpDo -> &LeftUpDow + new Transition (4367, 4368), // &Lleftarro -> &Lleftarrow + new Transition (4422, 4579), // &lo -> &low + new Transition (4434, 4588), // &Lo -> &Low + new Transition (4444, 4445), // &LongLeftArro -> &LongLeftArrow + new Transition (4454, 4455), // &Longleftarro -> &Longleftarrow + new Transition (4466, 4467), // &longleftarro -> &longleftarrow + new Transition (4477, 4478), // &LongLeftRightArro -> &LongLeftRightArrow + new Transition (4488, 4489), // &Longleftrightarro -> &Longleftrightarrow + new Transition (4499, 4500), // &longleftrightarro -> &longleftrightarrow + new Transition (4517, 4518), // &LongRightArro -> &LongRightArrow + new Transition (4528, 4529), // &Longrightarro -> &Longrightarrow + new Transition (4539, 4540), // &longrightarro -> &longrightarrow + new Transition (4547, 4548), // &looparro -> &looparrow + new Transition (4598, 4599), // &LowerLeftArro -> &LowerLeftArrow + new Transition (4609, 4610), // &LowerRightArro -> &LowerRightArrow + new Transition (4792, 4793), // &mapstodo -> &mapstodow + new Transition (4965, 6111), // &n -> &nw + new Transition (5077, 5078), // &nearro -> &nearrow + new Transition (5084, 5176), // &Ne -> &New + new Transition (5279, 5280), // &nLeftarro -> &nLeftarrow + new Transition (5287, 5288), // &nleftarro -> &nleftarrow + new Transition (5298, 5299), // &nLeftrightarro -> &nLeftrightarrow + new Transition (5309, 5310), // &nleftrightarro -> &nleftrightarrow + new Transition (5498, 5499), // &NotHumpDo -> &NotHumpDow + new Transition (5862, 5866), // &nrarr -> &nrarrw + new Transition (5876, 5877), // &nRightarro -> &nRightarrow + new Transition (5886, 5887), // &nrightarro -> &nrightarrow + new Transition (6123, 6124), // &nwarro -> &nwarrow + new Transition (6603, 6604), // &plust -> &plustw + new Transition (6932, 6966), // &rarr -> &rarrw + new Transition (7190, 7191), // &RightArro -> &RightArrow + new Transition (7196, 7197), // &Rightarro -> &Rightarrow + new Transition (7206, 7207), // &rightarro -> &rightarrow + new Transition (7220, 7221), // &RightArrowLeftArro -> &RightArrowLeftArrow + new Transition (7237, 7250), // &RightDo -> &RightDow + new Transition (7287, 7288), // &rightharpoondo -> &rightharpoondow + new Transition (7301, 7302), // &rightleftarro -> &rightleftarrow + new Transition (7322, 7323), // &rightrightarro -> &rightrightarrow + new Transition (7334, 7335), // &rightsquigarro -> &rightsquigarrow + new Transition (7344, 7345), // &RightTeeArro -> &RightTeeArrow + new Transition (7386, 7387), // &RightUpDo -> &RightUpDow + new Transition (7539, 7540), // &Rrightarro -> &Rrightarrow + new Transition (7617, 8375), // &s -> &sw + new Transition (7715, 7716), // &searro -> &searrow + new Transition (7724, 7725), // &ses -> &sesw + new Transition (7747, 7748), // &sfro -> &sfrow + new Transition (7777, 7778), // &ShortDo -> &ShortDow + new Transition (7783, 7784), // &ShortDownArro -> &ShortDownArrow + new Transition (7793, 7794), // &ShortLeftArro -> &ShortLeftArrow + new Transition (7820, 7821), // &ShortRightArro -> &ShortRightArrow + new Transition (7828, 7829), // &ShortUpArro -> &ShortUpArrow + new Transition (8387, 8388), // &swarro -> &swarrow + new Transition (8390, 8391), // &swn -> &swnw + new Transition (8404, 8737), // &t -> &tw + new Transition (8641, 8642), // &triangledo -> &triangledow + new Transition (8754, 8755), // &twoheadleftarro -> &twoheadleftarrow + new Transition (8765, 8766), // &twoheadrightarro -> &twoheadrightarrow + new Transition (8775, 9194), // &u -> &uw + new Transition (8974, 8975), // &UpArro -> &UpArrow + new Transition (8980, 8981), // &Uparro -> &Uparrow + new Transition (8987, 8988), // &uparro -> &uparrow + new Transition (8995, 8996), // &UpArrowDo -> &UpArrowDow + new Transition (9001, 9002), // &UpArrowDownArro -> &UpArrowDownArrow + new Transition (9005, 9006), // &UpDo -> &UpDow + new Transition (9011, 9012), // &UpDownArro -> &UpDownArrow + new Transition (9015, 9016), // &Updo -> &Updow + new Transition (9021, 9022), // &Updownarro -> &Updownarrow + new Transition (9025, 9026), // &updo -> &updow + new Transition (9031, 9032), // &updownarro -> &updownarrow + new Transition (9078, 9079), // &UpperLeftArro -> &UpperLeftArrow + new Transition (9089, 9090), // &UpperRightArro -> &UpperRightArrow + new Transition (9115, 9116), // &UpTeeArro -> &UpTeeArrow + new Transition (9123, 9124), // &upuparro -> &upuparrow + new Transition (9548, 9659), // &x -> &xw + new Transition (9754, 9848) // &z -> &zw + }; + TransitionTable_x = new Transition[24] { + new Transition (0, 9548), // & -> &x + new Transition (231, 232), // &appro -> &approx + new Transition (598, 613), // &bo -> &box + new Transition (615, 616), // &boxbo -> &boxbox + new Transition (1154, 1160), // &comple -> &complex + new Transition (1658, 1659), // &divon -> &divonx + new Transition (2108, 2466), // &E -> &Ex + new Transition (2115, 2458), // &e -> &ex + new Transition (2838, 2839), // &gnappro -> &gnapprox + new Transition (2970, 2971), // >rappro -> >rapprox + new Transition (3273, 3277), // &ie -> &iex + new Transition (4220, 4221), // &lessappro -> &lessapprox + new Transition (4407, 4408), // &lnappro -> &lnapprox + new Transition (4998, 4999), // &nappro -> &napprox + new Transition (5064, 5182), // &ne -> &nex + new Transition (5414, 5433), // &NotE -> &NotEx + new Transition (6661, 6662), // &precappro -> &precapprox + new Transition (6710, 6711), // &precnappro -> &precnapprox + new Transition (6876, 7608), // &r -> &rx + new Transition (7703, 7738), // &se -> &sex + new Transition (8205, 8206), // &succappro -> &succapprox + new Transition (8254, 8255), // &succnappro -> &succnapprox + new Transition (8500, 8501), // &thickappro -> &thickapprox + new Transition (8738, 8739) // &twi -> &twix + }; + TransitionTable_y = new Transition[122] { + new Transition (0, 9672), // & -> &y + new Transition (27, 48), // &ac -> &acy + new Transition (33, 46), // &Ac -> &Acy + new Transition (82, 83), // &alefs -> &alefsy + new Transition (218, 219), // &Appl -> &Apply + new Transition (251, 262), // &as -> &asy + new Transition (369, 377), // &bc -> &bcy + new Transition (374, 375), // &Bc -> &Bcy + new Transition (401, 402), // &bempt -> &bempty + new Transition (790, 855), // &Ca -> &Cay + new Transition (796, 1419), // &c -> &cy + new Transition (857, 858), // &Cayle -> &Cayley + new Transition (929, 930), // &cempt -> &cempty + new Transition (957, 958), // &CHc -> &CHcy + new Transition (961, 962), // &chc -> &chcy + new Transition (1097, 1098), // &CloseCurl -> &CloseCurly + new Transition (1203, 1221), // &cop -> © + new Transition (1353, 1354), // &curl -> &curly + new Transition (1422, 1423), // &cylct -> &cylcty + new Transition (1474, 1486), // &Dc -> &Dcy + new Transition (1480, 1488), // &dc -> &dcy + new Transition (1531, 1532), // &dempt -> &dempty + new Transition (1662, 1663), // &DJc -> &DJcy + new Transition (1666, 1667), // &djc -> &djcy + new Transition (2045, 2052), // &dsc -> &dscy + new Transition (2049, 2050), // &DSc -> &DScy + new Transition (2094, 2095), // &DZc -> &DZcy + new Transition (2098, 2099), // &dzc -> &dzcy + new Transition (2127, 2153), // &Ec -> &Ecy + new Transition (2133, 2155), // &ec -> &ecy + new Transition (2239, 2240), // &empt -> &empty + new Transition (2247, 2248), // &Empt -> &Empty + new Transition (2265, 2266), // &EmptyVer -> &EmptyVery + new Transition (2518, 2519), // &Fc -> &Fcy + new Transition (2521, 2522), // &fc -> &fcy + new Transition (2573, 2574), // &FilledVer -> &FilledVery + new Transition (2736, 2751), // &Gc -> &Gcy + new Transition (2746, 2753), // &gc -> &gcy + new Transition (2817, 2818), // &GJc -> &GJcy + new Transition (2821, 2822), // &gjc -> &gjcy + new Transition (3020, 3225), // &h -> &hy + new Transition (3038, 3039), // &HARDc -> &HARDcy + new Transition (3043, 3044), // &hardc -> &hardcy + new Transition (3250, 3263), // &ic -> &icy + new Transition (3252, 3261), // &Ic -> &Icy + new Transition (3270, 3271), // &IEc -> &IEcy + new Transition (3274, 3275), // &iec -> &iecy + new Transition (3348, 3349), // &Imaginar -> &Imaginary + new Transition (3464, 3465), // &IOc -> &IOcy + new Transition (3468, 3469), // &ioc -> &iocy + new Transition (3541, 3542), // &Iukc -> &Iukcy + new Transition (3546, 3547), // &iukc -> &iukcy + new Transition (3556, 3567), // &Jc -> &Jcy + new Transition (3562, 3569), // &jc -> &jcy + new Transition (3600, 3601), // &Jserc -> &Jsercy + new Transition (3605, 3606), // &jserc -> &jsercy + new Transition (3610, 3611), // &Jukc -> &Jukcy + new Transition (3615, 3616), // &jukc -> &jukcy + new Transition (3632, 3644), // &Kc -> &Kcy + new Transition (3638, 3646), // &kc -> &kcy + new Transition (3661, 3662), // &KHc -> &KHcy + new Transition (3665, 3666), // &khc -> &khcy + new Transition (3669, 3670), // &KJc -> &KJcy + new Transition (3673, 3674), // &kjc -> &kjcy + new Transition (3714, 3715), // &laempt -> &laempty + new Transition (3837, 3865), // &Lc -> &Lcy + new Transition (3843, 3867), // &lc -> &lcy + new Transition (4339, 4340), // &LJc -> &LJcy + new Transition (4343, 4344), // &ljc -> &ljcy + new Transition (4809, 4818), // &mc -> &mcy + new Transition (4815, 4816), // &Mc -> &Mcy + new Transition (5020, 5057), // &nc -> &ncy + new Transition (5024, 5055), // &Nc -> &Ncy + new Transition (5123, 5124), // &NegativeVer -> &NegativeVery + new Transition (5249, 5250), // &NJc -> &NJcy + new Transition (5253, 5254), // &njc -> &njcy + new Transition (6148, 6161), // &oc -> &ocy + new Transition (6152, 6159), // &Oc -> &Ocy + new Transition (6312, 6313), // &OpenCurl -> &OpenCurly + new Transition (6491, 6492), // &Pc -> &Pcy + new Transition (6494, 6495), // &pc -> &pcy + new Transition (6667, 6668), // &preccurl -> &preccurly + new Transition (6904, 6905), // &raempt -> &raempty + new Transition (7021, 7049), // &Rc -> &Rcy + new Transition (7027, 7051), // &rc -> &rcy + new Transition (7596, 7597), // &RuleDela -> &RuleDelay + new Transition (7629, 7691), // &Sc -> &Scy + new Transition (7631, 7693), // &sc -> &scy + new Transition (7751, 7831), // &sh -> ­ + new Transition (7759, 7760), // &SHCHc -> &SHCHcy + new Transition (7762, 7770), // &shc -> &shcy + new Transition (7764, 7765), // &shchc -> &shchcy + new Transition (7767, 7768), // &SHc -> &SHcy + new Transition (7933, 7934), // &SOFTc -> &SOFTcy + new Transition (7939, 7940), // &softc -> &softcy + new Transition (8211, 8212), // &succcurl -> &succcurly + new Transition (8419, 8441), // &Tc -> &Tcy + new Transition (8425, 8443), // &tc -> &tcy + new Transition (8487, 8488), // &thetas -> &thetasy + new Transition (8710, 8717), // &tsc -> &tscy + new Transition (8714, 8715), // &TSc -> &TScy + new Transition (8720, 8721), // &TSHc -> &TSHcy + new Transition (8724, 8725), // &tshc -> &tshcy + new Transition (8799, 8800), // &Ubrc -> &Ubrcy + new Transition (8804, 8805), // &ubrc -> &ubrcy + new Transition (8815, 8825), // &Uc -> &Ucy + new Transition (8820, 8827), // &uc -> &ucy + new Transition (9314, 9315), // &Vc -> &Vcy + new Transition (9317, 9318), // &vc -> &vcy + new Transition (9360, 9403), // &Ver -> &Very + new Transition (9674, 9683), // &yac -> &yacy + new Transition (9680, 9681), // &YAc -> &YAcy + new Transition (9685, 9695), // &Yc -> &Ycy + new Transition (9690, 9697), // &yc -> &ycy + new Transition (9709, 9710), // &YIc -> &YIcy + new Transition (9713, 9714), // &yic -> &yicy + new Transition (9733, 9734), // &YUc -> &YUcy + new Transition (9737, 9738), // &yuc -> &yucy + new Transition (9761, 9773), // &Zc -> &Zcy + new Transition (9767, 9775), // &zc -> &zcy + new Transition (9818, 9819), // &ZHc -> &ZHcy + new Transition (9822, 9823) // &zhc -> &zhcy + }; + TransitionTable_z = new Transition[10] { + new Transition (0, 9754), // & -> &z + new Transition (136, 178), // &ang -> &angz + new Transition (524, 525), // &blacklo -> &blackloz + new Transition (1432, 2097), // &d -> &dz + new Transition (3172, 3173), // &Hori -> &Horiz + new Transition (4422, 4612), // &lo -> &loz + new Transition (7617, 8395), // &s -> &sz + new Transition (8699, 8700), // &trpe -> &trpez + new Transition (9201, 9477), // &v -> &vz + new Transition (9479, 9480) // &vzig -> &vzigz + }; + + NamedEntities = new Dictionary { + [6] = "\u00C1", // Á + [7] = "\u00C1", // Á + [13] = "\u00E1", // á + [14] = "\u00E1", // á + [20] = "\u0102", // Ă + [26] = "\u0103", // ă + [28] = "\u223E", // ∾ + [30] = "\u223F", // ∿ + [32] = "\u223E\u0333", // ∾̳ + [36] = "\u00C2", //  + [37] = "\u00C2", //  + [40] = "\u00E2", // â + [41] = "\u00E2", // â + [44] = "\u00B4", // ´ + [45] = "\u00B4", // ´ + [47] = "\u0410", // А + [49] = "\u0430", // а + [53] = "\u00C6", // Æ + [54] = "\u00C6", // Æ + [58] = "\u00E6", // æ + [59] = "\u00E6", // æ + [61] = "\u2061", // ⁡ + [64] = "\uD835\uDD04", // 𝔄 + [66] = "\uD835\uDD1E", // 𝔞 + [71] = "\u00C0", // À + [72] = "\u00C0", // À + [77] = "\u00E0", // à + [78] = "\u00E0", // à + [85] = "\u2135", // ℵ + [88] = "\u2135", // ℵ + [93] = "\u0391", // Α + [97] = "\u03B1", // α + [102] = "\u0100", // Ā + [107] = "\u0101", // ā + [110] = "\u2A3F", // ⨿ + [112] = "\u0026", // & + [113] = "\u0026", // & + [114] = "\u0026", // & + [115] = "\u0026", // & + [118] = "\u2A53", // ⩓ + [121] = "\u2227", // ∧ + [125] = "\u2A55", // ⩕ + [127] = "\u2A5C", // ⩜ + [133] = "\u2A58", // ⩘ + [135] = "\u2A5A", // ⩚ + [137] = "\u2220", // ∠ + [139] = "\u29A4", // ⦤ + [142] = "\u2220", // ∠ + [146] = "\u2221", // ∡ + [149] = "\u29A8", // ⦨ + [151] = "\u29A9", // ⦩ + [153] = "\u29AA", // ⦪ + [155] = "\u29AB", // ⦫ + [157] = "\u29AC", // ⦬ + [159] = "\u29AD", // ⦭ + [161] = "\u29AE", // ⦮ + [163] = "\u29AF", // ⦯ + [166] = "\u221F", // ∟ + [169] = "\u22BE", // ⊾ + [171] = "\u299D", // ⦝ + [175] = "\u2222", // ∢ + [177] = "\u00C5", // Å + [182] = "\u237C", // ⍼ + [187] = "\u0104", // Ą + [192] = "\u0105", // ą + [195] = "\uD835\uDD38", // 𝔸 + [198] = "\uD835\uDD52", // 𝕒 + [200] = "\u2248", // ≈ + [205] = "\u2A6F", // ⩯ + [207] = "\u2A70", // ⩰ + [209] = "\u224A", // ≊ + [212] = "\u224B", // ≋ + [215] = "\u0027", // ' + [228] = "\u2061", // ⁡ + [233] = "\u2248", // ≈ + [236] = "\u224A", // ≊ + [240] = "\u00C5", // Å + [241] = "\u00C5", // Å + [245] = "\u00E5", // å + [246] = "\u00E5", // å + [250] = "\uD835\uDC9C", // 𝒜 + [254] = "\uD835\uDCB6", // 𝒶 + [259] = "\u2254", // ≔ + [261] = "\u002A", // * + [265] = "\u2248", // ≈ + [268] = "\u224D", // ≍ + [273] = "\u00C3", // à + [274] = "\u00C3", // à + [279] = "\u00E3", // ã + [280] = "\u00E3", // ã + [283] = "\u00C4", // Ä + [284] = "\u00C4", // Ä + [287] = "\u00E4", // ä + [288] = "\u00E4", // ä + [296] = "\u2233", // ∳ + [300] = "\u2A11", // ⨑ + [309] = "\u224C", // ≌ + [317] = "\u03F6", // ϶ + [323] = "\u2035", // ‵ + [327] = "\u223D", // ∽ + [330] = "\u22CD", // ⋍ + [340] = "\u2216", // ∖ + [343] = "\u2AE7", // ⫧ + [348] = "\u22BD", // ⊽ + [352] = "\u2306", // ⌆ + [356] = "\u2305", // ⌅ + [359] = "\u2305", // ⌅ + [363] = "\u23B5", // ⎵ + [368] = "\u23B6", // ⎶ + [373] = "\u224C", // ≌ + [376] = "\u0411", // Б + [378] = "\u0431", // б + [383] = "\u201E", // „ + [389] = "\u2235", // ∵ + [396] = "\u2235", // ∵ + [398] = "\u2235", // ∵ + [404] = "\u29B0", // ⦰ + [408] = "\u03F6", // ϶ + [413] = "\u212C", // ℬ + [422] = "\u212C", // ℬ + [425] = "\u0392", // Β + [428] = "\u03B2", // β + [430] = "\u2136", // ℶ + [435] = "\u226C", // ≬ + [438] = "\uD835\uDD05", // 𝔅 + [441] = "\uD835\uDD1F", // 𝔟 + [447] = "\u22C2", // ⋂ + [451] = "\u25EF", // ◯ + [454] = "\u22C3", // ⋃ + [459] = "\u2A00", // ⨀ + [464] = "\u2A01", // ⨁ + [470] = "\u2A02", // ⨂ + [476] = "\u2A06", // ⨆ + [480] = "\u2605", // ★ + [493] = "\u25BD", // ▽ + [496] = "\u25B3", // △ + [502] = "\u2A04", // ⨄ + [506] = "\u22C1", // ⋁ + [512] = "\u22C0", // ⋀ + [518] = "\u290D", // ⤍ + [530] = "\u29EB", // ⧫ + [537] = "\u25AA", // ▪ + [546] = "\u25B4", // ▴ + [551] = "\u25BE", // ▾ + [556] = "\u25C2", // ◂ + [562] = "\u25B8", // ▸ + [565] = "\u2423", // ␣ + [569] = "\u2592", // ▒ + [571] = "\u2591", // ░ + [574] = "\u2593", // ▓ + [578] = "\u2588", // █ + [581] = "\u003D\u20E5", // =⃥ + [586] = "\u2261\u20E5", // ≡⃥ + [590] = "\u2AED", // ⫭ + [593] = "\u2310", // ⌐ + [597] = "\uD835\uDD39", // 𝔹 + [601] = "\uD835\uDD53", // 𝕓 + [603] = "\u22A5", // ⊥ + [607] = "\u22A5", // ⊥ + [612] = "\u22C8", // ⋈ + [617] = "\u29C9", // ⧉ + [620] = "\u2557", // ╗ + [622] = "\u2556", // ╖ + [625] = "\u2555", // ╕ + [627] = "\u2510", // ┐ + [629] = "\u2554", // ╔ + [631] = "\u2553", // ╓ + [633] = "\u2552", // ╒ + [635] = "\u250C", // ┌ + [637] = "\u2550", // ═ + [639] = "\u2500", // ─ + [641] = "\u2566", // ╦ + [643] = "\u2564", // ╤ + [645] = "\u2565", // ╥ + [647] = "\u252C", // ┬ + [649] = "\u2569", // ╩ + [651] = "\u2567", // ╧ + [653] = "\u2568", // ╨ + [655] = "\u2534", // ┴ + [661] = "\u229F", // ⊟ + [666] = "\u229E", // ⊞ + [672] = "\u22A0", // ⊠ + [675] = "\u255D", // ╝ + [677] = "\u255C", // ╜ + [680] = "\u255B", // ╛ + [682] = "\u2518", // ┘ + [684] = "\u255A", // ╚ + [686] = "\u2559", // ╙ + [688] = "\u2558", // ╘ + [690] = "\u2514", // └ + [692] = "\u2551", // ║ + [694] = "\u2502", // │ + [696] = "\u256C", // ╬ + [698] = "\u256B", // ╫ + [700] = "\u256A", // ╪ + [702] = "\u253C", // ┼ + [704] = "\u2563", // ╣ + [706] = "\u2562", // ╢ + [708] = "\u2561", // ╡ + [710] = "\u2524", // ┤ + [712] = "\u2560", // ╠ + [714] = "\u255F", // ╟ + [716] = "\u255E", // ╞ + [718] = "\u251C", // ├ + [724] = "\u2035", // ‵ + [729] = "\u02D8", // ˘ + [734] = "\u02D8", // ˘ + [738] = "\u00A6", // ¦ + [739] = "\u00A6", // ¦ + [743] = "\u212C", // ℬ + [747] = "\uD835\uDCB7", // 𝒷 + [751] = "\u204F", // ⁏ + [754] = "\u223D", // ∽ + [756] = "\u22CD", // ⋍ + [759] = "\u005C", // \ + [761] = "\u29C5", // ⧅ + [766] = "\u27C8", // ⟈ + [770] = "\u2022", // • + [773] = "\u2022", // • + [776] = "\u224E", // ≎ + [778] = "\u2AAE", // ⪮ + [780] = "\u224F", // ≏ + [786] = "\u224E", // ≎ + [788] = "\u224F", // ≏ + [795] = "\u0106", // Ć + [802] = "\u0107", // ć + [804] = "\u22D2", // ⋒ + [806] = "\u2229", // ∩ + [810] = "\u2A44", // ⩄ + [816] = "\u2A49", // ⩉ + [820] = "\u2A4B", // ⩋ + [823] = "\u2A47", // ⩇ + [827] = "\u2A40", // ⩀ + [845] = "\u2145", // ⅅ + [847] = "\u2229\uFE00", // ∩︀ + [851] = "\u2041", // ⁁ + [854] = "\u02C7", // ˇ + [860] = "\u212D", // ℭ + [865] = "\u2A4D", // ⩍ + [871] = "\u010C", // Č + [875] = "\u010D", // č + [879] = "\u00C7", // Ç + [880] = "\u00C7", // Ç + [884] = "\u00E7", // ç + [885] = "\u00E7", // ç + [889] = "\u0108", // Ĉ + [893] = "\u0109", // ĉ + [899] = "\u2230", // ∰ + [903] = "\u2A4C", // ⩌ + [906] = "\u2A50", // ⩐ + [910] = "\u010A", // Ċ + [914] = "\u010B", // ċ + [918] = "\u00B8", // ¸ + [919] = "\u00B8", // ¸ + [926] = "\u00B8", // ¸ + [932] = "\u29B2", // ⦲ + [934] = "\u00A2", // ¢ + [935] = "\u00A2", // ¢ + [943] = "\u00B7", // · + [949] = "\u00B7", // · + [952] = "\u212D", // ℭ + [955] = "\uD835\uDD20", // 𝔠 + [959] = "\u0427", // Ч + [963] = "\u0447", // ч + [967] = "\u2713", // ✓ + [972] = "\u2713", // ✓ + [975] = "\u03A7", // Χ + [977] = "\u03C7", // χ + [980] = "\u25CB", // ○ + [982] = "\u02C6", // ˆ + [985] = "\u2257", // ≗ + [997] = "\u21BA", // ↺ + [1003] = "\u21BB", // ↻ + [1008] = "\u229B", // ⊛ + [1013] = "\u229A", // ⊚ + [1018] = "\u229D", // ⊝ + [1027] = "\u2299", // ⊙ + [1029] = "\u00AE", // ® + [1031] = "\u24C8", // Ⓢ + [1037] = "\u2296", // ⊖ + [1042] = "\u2295", // ⊕ + [1048] = "\u2297", // ⊗ + [1050] = "\u29C3", // ⧃ + [1052] = "\u2257", // ≗ + [1058] = "\u2A10", // ⨐ + [1062] = "\u2AEF", // ⫯ + [1067] = "\u29C2", // ⧂ + [1091] = "\u2232", // ∲ + [1110] = "\u201D", // ” + [1116] = "\u2019", // ’ + [1121] = "\u2663", // ♣ + [1125] = "\u2663", // ♣ + [1130] = "\u2237", // ∷ + [1135] = "\u003A", // : + [1137] = "\u2A74", // ⩴ + [1139] = "\u2254", // ≔ + [1141] = "\u2254", // ≔ + [1145] = "\u002C", // , + [1147] = "\u0040", // @ + [1149] = "\u2201", // ∁ + [1152] = "\u2218", // ∘ + [1159] = "\u2201", // ∁ + [1163] = "\u2102", // ℂ + [1166] = "\u2245", // ≅ + [1170] = "\u2A6D", // ⩭ + [1178] = "\u2261", // ≡ + [1182] = "\u222F", // ∯ + [1186] = "\u222E", // ∮ + [1199] = "\u222E", // ∮ + [1202] = "\u2102", // ℂ + [1205] = "\uD835\uDD54", // 𝕔 + [1209] = "\u2210", // ∐ + [1216] = "\u2210", // ∐ + [1219] = "\u00A9", // © + [1220] = "\u00A9", // © + [1221] = "\u00A9", // © + [1222] = "\u00A9", // © + [1225] = "\u2117", // ℗ + [1255] = "\u2233", // ∳ + [1260] = "\u21B5", // ↵ + [1265] = "\u2A2F", // ⨯ + [1269] = "\u2717", // ✗ + [1273] = "\uD835\uDC9E", // 𝒞 + [1277] = "\uD835\uDCB8", // 𝒸 + [1280] = "\u2ACF", // ⫏ + [1282] = "\u2AD1", // ⫑ + [1284] = "\u2AD0", // ⫐ + [1286] = "\u2AD2", // ⫒ + [1291] = "\u22EF", // ⋯ + [1298] = "\u2938", // ⤸ + [1300] = "\u2935", // ⤵ + [1304] = "\u22DE", // ⋞ + [1307] = "\u22DF", // ⋟ + [1312] = "\u21B6", // ↶ + [1314] = "\u293D", // ⤽ + [1317] = "\u22D3", // ⋓ + [1319] = "\u222A", // ∪ + [1325] = "\u2A48", // ⩈ + [1329] = "\u224D", // ≍ + [1333] = "\u2A46", // ⩆ + [1336] = "\u2A4A", // ⩊ + [1340] = "\u228D", // ⊍ + [1343] = "\u2A45", // ⩅ + [1345] = "\u222A\uFE00", // ∪︀ + [1350] = "\u21B7", // ↷ + [1352] = "\u293C", // ⤼ + [1361] = "\u22DE", // ⋞ + [1366] = "\u22DF", // ⋟ + [1370] = "\u22CE", // ⋎ + [1376] = "\u22CF", // ⋏ + [1379] = "\u00A4", // ¤ + [1380] = "\u00A4", // ¤ + [1392] = "\u21B6", // ↶ + [1398] = "\u21B7", // ↷ + [1402] = "\u22CE", // ⋎ + [1406] = "\u22CF", // ⋏ + [1414] = "\u2232", // ∲ + [1418] = "\u2231", // ∱ + [1424] = "\u232D", // ⌭ + [1431] = "\u2021", // ‡ + [1438] = "\u2020", // † + [1443] = "\u2138", // ℸ + [1446] = "\u21A1", // ↡ + [1450] = "\u21D3", // ⇓ + [1453] = "\u2193", // ↓ + [1456] = "\u2010", // ‐ + [1460] = "\u2AE4", // ⫤ + [1462] = "\u22A3", // ⊣ + [1469] = "\u290F", // ⤏ + [1473] = "\u02DD", // ˝ + [1479] = "\u010E", // Ď + [1485] = "\u010F", // ď + [1487] = "\u0414", // Д + [1489] = "\u0434", // д + [1491] = "\u2145", // ⅅ + [1493] = "\u2146", // ⅆ + [1499] = "\u2021", // ‡ + [1502] = "\u21CA", // ⇊ + [1509] = "\u2911", // ⤑ + [1515] = "\u2A77", // ⩷ + [1517] = "\u00B0", // ° + [1518] = "\u00B0", // ° + [1521] = "\u2207", // ∇ + [1524] = "\u0394", // Δ + [1528] = "\u03B4", // δ + [1534] = "\u29B1", // ⦱ + [1540] = "\u297F", // ⥿ + [1543] = "\uD835\uDD07", // 𝔇 + [1545] = "\uD835\uDD21", // 𝔡 + [1549] = "\u2965", // ⥥ + [1554] = "\u21C3", // ⇃ + [1556] = "\u21C2", // ⇂ + [1572] = "\u00B4", // ´ + [1576] = "\u02D9", // ˙ + [1586] = "\u02DD", // ˝ + [1592] = "\u0060", // ` + [1598] = "\u02DC", // ˜ + [1602] = "\u22C4", // ⋄ + [1607] = "\u22C4", // ⋄ + [1611] = "\u22C4", // ⋄ + [1616] = "\u2666", // ♦ + [1618] = "\u2666", // ♦ + [1620] = "\u00A8", // ¨ + [1632] = "\u2146", // ⅆ + [1638] = "\u03DD", // ϝ + [1642] = "\u22F2", // ⋲ + [1644] = "\u00F7", // ÷ + [1647] = "\u00F7", // ÷ + [1648] = "\u00F7", // ÷ + [1656] = "\u22C7", // ⋇ + [1660] = "\u22C7", // ⋇ + [1664] = "\u0402", // Ђ + [1668] = "\u0452", // ђ + [1674] = "\u231E", // ⌞ + [1678] = "\u230D", // ⌍ + [1684] = "\u0024", // $ + [1688] = "\uD835\uDD3B", // 𝔻 + [1691] = "\uD835\uDD55", // 𝕕 + [1693] = "\u00A8", // ¨ + [1695] = "\u02D9", // ˙ + [1699] = "\u20DC", // ⃜ + [1702] = "\u2250", // ≐ + [1706] = "\u2251", // ≑ + [1712] = "\u2250", // ≐ + [1718] = "\u2238", // ∸ + [1723] = "\u2214", // ∔ + [1730] = "\u22A1", // ⊡ + [1743] = "\u2306", // ⌆ + [1763] = "\u222F", // ∯ + [1767] = "\u00A8", // ¨ + [1775] = "\u21D3", // ⇓ + [1785] = "\u21D0", // ⇐ + [1796] = "\u21D4", // ⇔ + [1800] = "\u2AE4", // ⫤ + [1813] = "\u27F8", // ⟸ + [1824] = "\u27FA", // ⟺ + [1835] = "\u27F9", // ⟹ + [1846] = "\u21D2", // ⇒ + [1850] = "\u22A8", // ⊨ + [1858] = "\u21D1", // ⇑ + [1868] = "\u21D5", // ⇕ + [1880] = "\u2225", // ∥ + [1888] = "\u2193", // ↓ + [1894] = "\u21D3", // ⇓ + [1902] = "\u2193", // ↓ + [1906] = "\u2913", // ⤓ + [1914] = "\u21F5", // ⇵ + [1920] = "\u0311", // ̑ + [1931] = "\u21CA", // ⇊ + [1943] = "\u21C3", // ⇃ + [1949] = "\u21C2", // ⇂ + [1965] = "\u2950", // ⥐ + [1975] = "\u295E", // ⥞ + [1982] = "\u21BD", // ↽ + [1986] = "\u2956", // ⥖ + [2001] = "\u295F", // ⥟ + [2008] = "\u21C1", // ⇁ + [2012] = "\u2957", // ⥗ + [2016] = "\u22A4", // ⊤ + [2022] = "\u21A7", // ↧ + [2030] = "\u2910", // ⤐ + [2035] = "\u231F", // ⌟ + [2039] = "\u230C", // ⌌ + [2043] = "\uD835\uDC9F", // 𝒟 + [2047] = "\uD835\uDCB9", // 𝒹 + [2051] = "\u0405", // Ѕ + [2053] = "\u0455", // ѕ + [2056] = "\u29F6", // ⧶ + [2061] = "\u0110", // Đ + [2066] = "\u0111", // đ + [2071] = "\u22F1", // ⋱ + [2074] = "\u25BF", // ▿ + [2076] = "\u25BE", // ▾ + [2081] = "\u21F5", // ⇵ + [2085] = "\u296F", // ⥯ + [2092] = "\u29A6", // ⦦ + [2096] = "\u040F", // Џ + [2100] = "\u045F", // џ + [2107] = "\u27FF", // ⟿ + [2113] = "\u00C9", // É + [2114] = "\u00C9", // É + [2120] = "\u00E9", // é + [2121] = "\u00E9", // é + [2126] = "\u2A6E", // ⩮ + [2132] = "\u011A", // Ě + [2138] = "\u011B", // ě + [2141] = "\u2256", // ≖ + [2144] = "\u00CA", // Ê + [2145] = "\u00CA", // Ê + [2146] = "\u00EA", // ê + [2147] = "\u00EA", // ê + [2152] = "\u2255", // ≕ + [2154] = "\u042D", // Э + [2156] = "\u044D", // э + [2161] = "\u2A77", // ⩷ + [2165] = "\u0116", // Ė + [2168] = "\u2251", // ≑ + [2172] = "\u0117", // ė + [2174] = "\u2147", // ⅇ + [2179] = "\u2252", // ≒ + [2182] = "\uD835\uDD08", // 𝔈 + [2184] = "\uD835\uDD22", // 𝔢 + [2186] = "\u2A9A", // ⪚ + [2191] = "\u00C8", // È + [2192] = "\u00C8", // È + [2196] = "\u00E8", // è + [2197] = "\u00E8", // è + [2199] = "\u2A96", // ⪖ + [2203] = "\u2A98", // ⪘ + [2205] = "\u2A99", // ⪙ + [2212] = "\u2208", // ∈ + [2219] = "\u23E7", // ⏧ + [2221] = "\u2113", // ℓ + [2223] = "\u2A95", // ⪕ + [2227] = "\u2A97", // ⪗ + [2232] = "\u0112", // Ē + [2237] = "\u0113", // ē + [2241] = "\u2205", // ∅ + [2245] = "\u2205", // ∅ + [2260] = "\u25FB", // ◻ + [2262] = "\u2205", // ∅ + [2278] = "\u25AB", // ▫ + [2281] = "\u2003", //   + [2284] = "\u2004", //   + [2286] = "\u2005", //   + [2289] = "\u014A", // Ŋ + [2292] = "\u014B", // ŋ + [2295] = "\u2002", //   + [2300] = "\u0118", // Ę + [2305] = "\u0119", // ę + [2308] = "\uD835\uDD3C", // 𝔼 + [2311] = "\uD835\uDD56", // 𝕖 + [2315] = "\u22D5", // ⋕ + [2318] = "\u29E3", // ⧣ + [2322] = "\u2A71", // ⩱ + [2325] = "\u03B5", // ε + [2332] = "\u0395", // Ε + [2336] = "\u03B5", // ε + [2338] = "\u03F5", // ϵ + [2344] = "\u2256", // ≖ + [2349] = "\u2255", // ≕ + [2353] = "\u2242", // ≂ + [2361] = "\u2A96", // ⪖ + [2366] = "\u2A95", // ⪕ + [2371] = "\u2A75", // ⩵ + [2376] = "\u003D", // = + [2382] = "\u2242", // ≂ + [2386] = "\u225F", // ≟ + [2395] = "\u21CC", // ⇌ + [2398] = "\u2261", // ≡ + [2401] = "\u2A78", // ⩸ + [2408] = "\u29E5", // ⧥ + [2413] = "\u2971", // ⥱ + [2417] = "\u2253", // ≓ + [2421] = "\u2130", // ℰ + [2425] = "\u212F", // ℯ + [2429] = "\u2250", // ≐ + [2432] = "\u2A73", // ⩳ + [2435] = "\u2242", // ≂ + [2438] = "\u0397", // Η + [2441] = "\u03B7", // η + [2443] = "\u00D0", // Ð + [2444] = "\u00D0", // Ð + [2445] = "\u00F0", // ð + [2446] = "\u00F0", // ð + [2449] = "\u00CB", // Ë + [2450] = "\u00CB", // Ë + [2453] = "\u00EB", // ë + [2454] = "\u00EB", // ë + [2457] = "\u20AC", // € + [2461] = "\u0021", // ! + [2465] = "\u2203", // ∃ + [2471] = "\u2203", // ∃ + [2481] = "\u2130", // ℰ + [2492] = "\u2147", // ⅇ + [2502] = "\u2147", // ⅇ + [2516] = "\u2252", // ≒ + [2520] = "\u0424", // Ф + [2523] = "\u0444", // ф + [2529] = "\u2640", // ♀ + [2535] = "\uFB03", // ffi + [2539] = "\uFB00", // ff + [2543] = "\uFB04", // ffl + [2546] = "\uD835\uDD09", // 𝔉 + [2548] = "\uD835\uDD23", // 𝔣 + [2553] = "\uFB01", // fi + [2570] = "\u25FC", // ◼ + [2586] = "\u25AA", // ▪ + [2591] = "\u0066\u006A", // fj + [2595] = "\u266D", // ♭ + [2599] = "\uFB02", // fl + [2603] = "\u25B1", // ▱ + [2607] = "\u0192", // ƒ + [2611] = "\uD835\uDD3D", // 𝔽 + [2615] = "\uD835\uDD57", // 𝕗 + [2620] = "\u2200", // ∀ + [2625] = "\u2200", // ∀ + [2627] = "\u22D4", // ⋔ + [2629] = "\u2AD9", // ⫙ + [2638] = "\u2131", // ℱ + [2646] = "\u2A0D", // ⨍ + [2651] = "\u00BD", // ½ + [2652] = "\u00BD", // ½ + [2654] = "\u2153", // ⅓ + [2655] = "\u00BC", // ¼ + [2656] = "\u00BC", // ¼ + [2658] = "\u2155", // ⅕ + [2660] = "\u2159", // ⅙ + [2662] = "\u215B", // ⅛ + [2665] = "\u2154", // ⅔ + [2667] = "\u2156", // ⅖ + [2669] = "\u00BE", // ¾ + [2670] = "\u00BE", // ¾ + [2672] = "\u2157", // ⅗ + [2674] = "\u215C", // ⅜ + [2677] = "\u2158", // ⅘ + [2680] = "\u215A", // ⅚ + [2682] = "\u215D", // ⅝ + [2685] = "\u215E", // ⅞ + [2688] = "\u2044", // ⁄ + [2692] = "\u2322", // ⌢ + [2696] = "\u2131", // ℱ + [2700] = "\uD835\uDCBB", // 𝒻 + [2707] = "\u01F5", // ǵ + [2713] = "\u0393", // Γ + [2717] = "\u03B3", // γ + [2719] = "\u03DC", // Ϝ + [2721] = "\u03DD", // ϝ + [2723] = "\u2A86", // ⪆ + [2729] = "\u011E", // Ğ + [2735] = "\u011F", // ğ + [2741] = "\u0122", // Ģ + [2745] = "\u011C", // Ĝ + [2750] = "\u011D", // ĝ + [2752] = "\u0413", // Г + [2754] = "\u0433", // г + [2758] = "\u0120", // Ġ + [2762] = "\u0121", // ġ + [2764] = "\u2267", // ≧ + [2766] = "\u2265", // ≥ + [2768] = "\u2A8C", // ⪌ + [2770] = "\u22DB", // ⋛ + [2772] = "\u2265", // ≥ + [2774] = "\u2267", // ≧ + [2780] = "\u2A7E", // ⩾ + [2782] = "\u2A7E", // ⩾ + [2785] = "\u2AA9", // ⪩ + [2789] = "\u2A80", // ⪀ + [2791] = "\u2A82", // ⪂ + [2793] = "\u2A84", // ⪄ + [2795] = "\u22DB\uFE00", // ⋛︀ + [2798] = "\u2A94", // ⪔ + [2801] = "\uD835\uDD0A", // 𝔊 + [2804] = "\uD835\uDD24", // 𝔤 + [2806] = "\u22D9", // ⋙ + [2808] = "\u226B", // ≫ + [2810] = "\u22D9", // ⋙ + [2815] = "\u2137", // ℷ + [2819] = "\u0403", // Ѓ + [2823] = "\u0453", // ѓ + [2825] = "\u2277", // ≷ + [2827] = "\u2AA5", // ⪥ + [2829] = "\u2A92", // ⪒ + [2831] = "\u2AA4", // ⪤ + [2835] = "\u2A8A", // ⪊ + [2840] = "\u2A8A", // ⪊ + [2842] = "\u2269", // ≩ + [2844] = "\u2A88", // ⪈ + [2846] = "\u2A88", // ⪈ + [2848] = "\u2269", // ≩ + [2852] = "\u22E7", // ⋧ + [2856] = "\uD835\uDD3E", // 𝔾 + [2860] = "\uD835\uDD58", // 𝕘 + [2865] = "\u0060", // ` + [2877] = "\u2265", // ≥ + [2882] = "\u22DB", // ⋛ + [2892] = "\u2267", // ≧ + [2900] = "\u2AA2", // ⪢ + [2905] = "\u2277", // ≷ + [2916] = "\u2A7E", // ⩾ + [2922] = "\u2273", // ≳ + [2926] = "\uD835\uDCA2", // 𝒢 + [2930] = "\u210A", // ℊ + [2933] = "\u2273", // ≳ + [2935] = "\u2A8E", // ⪎ + [2937] = "\u2A90", // ⪐ + [2938] = "\u003E", // > + [2939] = "\u003E", // > + [2941] = "\u226B", // ≫ + [2942] = "\u003E", // > + [2943] = "\u003E", // > + [2946] = "\u2AA7", // ⪧ + [2949] = "\u2A7A", // ⩺ + [2953] = "\u22D7", // ⋗ + [2958] = "\u2995", // ⦕ + [2964] = "\u2A7C", // ⩼ + [2972] = "\u2A86", // ⪆ + [2975] = "\u2978", // ⥸ + [2979] = "\u22D7", // ⋗ + [2986] = "\u22DB", // ⋛ + [2992] = "\u2A8C", // ⪌ + [2997] = "\u2277", // ≷ + [3001] = "\u2273", // ≳ + [3010] = "\u2269\uFE00", // ≩︀ + [3013] = "\u2269\uFE00", // ≩︀ + [3019] = "\u02C7", // ˇ + [3026] = "\u200A", //   + [3029] = "\u00BD", // ½ + [3034] = "\u210B", // ℋ + [3040] = "\u042A", // Ъ + [3045] = "\u044A", // ъ + [3049] = "\u21D4", // ⇔ + [3051] = "\u2194", // ↔ + [3055] = "\u2948", // ⥈ + [3057] = "\u21AD", // ↭ + [3059] = "\u005E", // ^ + [3063] = "\u210F", // ℏ + [3068] = "\u0124", // Ĥ + [3073] = "\u0125", // ĥ + [3079] = "\u2665", // ♥ + [3083] = "\u2665", // ♥ + [3088] = "\u2026", // … + [3093] = "\u22B9", // ⊹ + [3096] = "\u210C", // ℌ + [3099] = "\uD835\uDD25", // 𝔥 + [3111] = "\u210B", // ℋ + [3119] = "\u2925", // ⤥ + [3125] = "\u2926", // ⤦ + [3130] = "\u21FF", // ⇿ + [3135] = "\u223B", // ∻ + [3147] = "\u21A9", // ↩ + [3158] = "\u21AA", // ↪ + [3162] = "\u210D", // ℍ + [3165] = "\uD835\uDD59", // 𝕙 + [3170] = "\u2015", // ― + [3183] = "\u2500", // ─ + [3187] = "\u210B", // ℋ + [3191] = "\uD835\uDCBD", // 𝒽 + [3196] = "\u210F", // ℏ + [3201] = "\u0126", // Ħ + [3206] = "\u0127", // ħ + [3218] = "\u224E", // ≎ + [3224] = "\u224F", // ≏ + [3230] = "\u2043", // ⁃ + [3235] = "\u2010", // ‐ + [3241] = "\u00CD", // Í + [3242] = "\u00CD", // Í + [3248] = "\u00ED", // í + [3249] = "\u00ED", // í + [3251] = "\u2063", // ⁣ + [3255] = "\u00CE", // Î + [3256] = "\u00CE", // Î + [3259] = "\u00EE", // î + [3260] = "\u00EE", // î + [3262] = "\u0418", // И + [3264] = "\u0438", // и + [3268] = "\u0130", // İ + [3272] = "\u0415", // Е + [3276] = "\u0435", // е + [3279] = "\u00A1", // ¡ + [3280] = "\u00A1", // ¡ + [3283] = "\u21D4", // ⇔ + [3286] = "\u2111", // ℑ + [3288] = "\uD835\uDD26", // 𝔦 + [3293] = "\u00CC", // Ì + [3294] = "\u00CC", // Ì + [3299] = "\u00EC", // ì + [3300] = "\u00EC", // ì + [3302] = "\u2148", // ⅈ + [3307] = "\u2A0C", // ⨌ + [3310] = "\u222D", // ∭ + [3315] = "\u29DC", // ⧜ + [3319] = "\u2129", // ℩ + [3324] = "\u0132", // IJ + [3329] = "\u0133", // ij + [3331] = "\u2111", // ℑ + [3335] = "\u012A", // Ī + [3340] = "\u012B", // ī + [3343] = "\u2111", // ℑ + [3351] = "\u2148", // ⅈ + [3356] = "\u2110", // ℐ + [3361] = "\u2111", // ℑ + [3364] = "\u0131", // ı + [3367] = "\u22B7", // ⊷ + [3371] = "\u01B5", // Ƶ + [3377] = "\u21D2", // ⇒ + [3379] = "\u2208", // ∈ + [3384] = "\u2105", // ℅ + [3388] = "\u221E", // ∞ + [3392] = "\u29DD", // ⧝ + [3397] = "\u0131", // ı + [3400] = "\u222C", // ∬ + [3402] = "\u222B", // ∫ + [3406] = "\u22BA", // ⊺ + [3412] = "\u2124", // ℤ + [3418] = "\u222B", // ∫ + [3423] = "\u22BA", // ⊺ + [3432] = "\u22C2", // ⋂ + [3438] = "\u2A17", // ⨗ + [3443] = "\u2A3C", // ⨼ + [3456] = "\u2063", // ⁣ + [3462] = "\u2062", // ⁢ + [3466] = "\u0401", // Ё + [3470] = "\u0451", // ё + [3475] = "\u012E", // Į + [3479] = "\u012F", // į + [3482] = "\uD835\uDD40", // 𝕀 + [3485] = "\uD835\uDD5A", // 𝕚 + [3488] = "\u0399", // Ι + [3491] = "\u03B9", // ι + [3496] = "\u2A3C", // ⨼ + [3501] = "\u00BF", // ¿ + [3502] = "\u00BF", // ¿ + [3506] = "\u2110", // ℐ + [3510] = "\uD835\uDCBE", // 𝒾 + [3513] = "\u2208", // ∈ + [3517] = "\u22F5", // ⋵ + [3519] = "\u22F9", // ⋹ + [3521] = "\u22F4", // ⋴ + [3523] = "\u22F3", // ⋳ + [3525] = "\u2208", // ∈ + [3527] = "\u2062", // ⁢ + [3533] = "\u0128", // Ĩ + [3538] = "\u0129", // ĩ + [3543] = "\u0406", // І + [3548] = "\u0456", // і + [3550] = "\u00CF", // Ï + [3551] = "\u00CF", // Ï + [3553] = "\u00EF", // ï + [3554] = "\u00EF", // ï + [3560] = "\u0134", // Ĵ + [3566] = "\u0135", // ĵ + [3568] = "\u0419", // Й + [3570] = "\u0439", // й + [3573] = "\uD835\uDD0D", // 𝔍 + [3576] = "\uD835\uDD27", // 𝔧 + [3581] = "\u0237", // ȷ + [3585] = "\uD835\uDD41", // 𝕁 + [3589] = "\uD835\uDD5B", // 𝕛 + [3593] = "\uD835\uDCA5", // 𝒥 + [3597] = "\uD835\uDCBF", // 𝒿 + [3602] = "\u0408", // Ј + [3607] = "\u0458", // ј + [3612] = "\u0404", // Є + [3617] = "\u0454", // є + [3623] = "\u039A", // Κ + [3629] = "\u03BA", // κ + [3631] = "\u03F0", // ϰ + [3637] = "\u0136", // Ķ + [3643] = "\u0137", // ķ + [3645] = "\u041A", // К + [3647] = "\u043A", // к + [3650] = "\uD835\uDD0E", // 𝔎 + [3653] = "\uD835\uDD28", // 𝔨 + [3659] = "\u0138", // ĸ + [3663] = "\u0425", // Х + [3667] = "\u0445", // х + [3671] = "\u040C", // Ќ + [3675] = "\u045C", // ќ + [3679] = "\uD835\uDD42", // 𝕂 + [3683] = "\uD835\uDD5C", // 𝕜 + [3687] = "\uD835\uDCA6", // 𝒦 + [3691] = "\uD835\uDCC0", // 𝓀 + [3697] = "\u21DA", // ⇚ + [3704] = "\u0139", // Ĺ + [3710] = "\u013A", // ĺ + [3717] = "\u29B4", // ⦴ + [3722] = "\u2112", // ℒ + [3727] = "\u039B", // Λ + [3732] = "\u03BB", // λ + [3735] = "\u27EA", // ⟪ + [3738] = "\u27E8", // ⟨ + [3740] = "\u2991", // ⦑ + [3743] = "\u27E8", // ⟨ + [3745] = "\u2A85", // ⪅ + [3754] = "\u2112", // ℒ + [3757] = "\u00AB", // « + [3758] = "\u00AB", // « + [3761] = "\u219E", // ↞ + [3764] = "\u21D0", // ⇐ + [3767] = "\u2190", // ← + [3769] = "\u21E4", // ⇤ + [3772] = "\u291F", // ⤟ + [3775] = "\u291D", // ⤝ + [3778] = "\u21A9", // ↩ + [3781] = "\u21AB", // ↫ + [3784] = "\u2939", // ⤹ + [3788] = "\u2973", // ⥳ + [3791] = "\u21A2", // ↢ + [3793] = "\u2AAB", // ⪫ + [3798] = "\u291B", // ⤛ + [3802] = "\u2919", // ⤙ + [3804] = "\u2AAD", // ⪭ + [3806] = "\u2AAD\uFE00", // ⪭︀ + [3811] = "\u290E", // ⤎ + [3816] = "\u290C", // ⤌ + [3820] = "\u2772", // ❲ + [3825] = "\u007B", // { + [3827] = "\u005B", // [ + [3830] = "\u298B", // ⦋ + [3834] = "\u298F", // ⦏ + [3836] = "\u298D", // ⦍ + [3842] = "\u013D", // Ľ + [3848] = "\u013E", // ľ + [3853] = "\u013B", // Ļ + [3858] = "\u013C", // ļ + [3861] = "\u2308", // ⌈ + [3864] = "\u007B", // { + [3866] = "\u041B", // Л + [3868] = "\u043B", // л + [3872] = "\u2936", // ⤶ + [3876] = "\u201C", // “ + [3878] = "\u201E", // „ + [3884] = "\u2967", // ⥧ + [3890] = "\u294B", // ⥋ + [3893] = "\u21B2", // ↲ + [3895] = "\u2266", // ≦ + [3897] = "\u2264", // ≤ + [3913] = "\u27E8", // ⟨ + [3918] = "\u2190", // ← + [3924] = "\u21D0", // ⇐ + [3932] = "\u2190", // ← + [3936] = "\u21E4", // ⇤ + [3947] = "\u21C6", // ⇆ + [3952] = "\u21A2", // ↢ + [3960] = "\u2308", // ⌈ + [3974] = "\u27E6", // ⟦ + [3986] = "\u2961", // ⥡ + [3993] = "\u21C3", // ⇃ + [3997] = "\u2959", // ⥙ + [4003] = "\u230A", // ⌊ + [4015] = "\u21BD", // ↽ + [4018] = "\u21BC", // ↼ + [4029] = "\u21C7", // ⇇ + [4040] = "\u2194", // ↔ + [4051] = "\u21D4", // ⇔ + [4062] = "\u2194", // ↔ + [4064] = "\u21C6", // ⇆ + [4073] = "\u21CB", // ⇋ + [4084] = "\u21AD", // ↭ + [4091] = "\u294E", // ⥎ + [4095] = "\u22A3", // ⊣ + [4101] = "\u21A4", // ↤ + [4108] = "\u295A", // ⥚ + [4119] = "\u22CB", // ⋋ + [4127] = "\u22B2", // ⊲ + [4131] = "\u29CF", // ⧏ + [4137] = "\u22B4", // ⊴ + [4150] = "\u2951", // ⥑ + [4160] = "\u2960", // ⥠ + [4167] = "\u21BF", // ↿ + [4171] = "\u2958", // ⥘ + [4178] = "\u21BC", // ↼ + [4182] = "\u2952", // ⥒ + [4184] = "\u2A8B", // ⪋ + [4186] = "\u22DA", // ⋚ + [4188] = "\u2264", // ≤ + [4190] = "\u2266", // ≦ + [4196] = "\u2A7D", // ⩽ + [4198] = "\u2A7D", // ⩽ + [4201] = "\u2AA8", // ⪨ + [4205] = "\u2A7F", // ⩿ + [4207] = "\u2A81", // ⪁ + [4209] = "\u2A83", // ⪃ + [4211] = "\u22DA\uFE00", // ⋚︀ + [4214] = "\u2A93", // ⪓ + [4222] = "\u2A85", // ⪅ + [4226] = "\u22D6", // ⋖ + [4232] = "\u22DA", // ⋚ + [4237] = "\u2A8B", // ⪋ + [4252] = "\u22DA", // ⋚ + [4262] = "\u2266", // ≦ + [4270] = "\u2276", // ≶ + [4274] = "\u2276", // ≶ + [4279] = "\u2AA1", // ⪡ + [4283] = "\u2272", // ≲ + [4294] = "\u2A7D", // ⩽ + [4300] = "\u2272", // ≲ + [4306] = "\u297C", // ⥼ + [4311] = "\u230A", // ⌊ + [4314] = "\uD835\uDD0F", // 𝔏 + [4316] = "\uD835\uDD29", // 𝔩 + [4318] = "\u2276", // ≶ + [4320] = "\u2A91", // ⪑ + [4324] = "\u2962", // ⥢ + [4329] = "\u21BD", // ↽ + [4331] = "\u21BC", // ↼ + [4333] = "\u296A", // ⥪ + [4337] = "\u2584", // ▄ + [4341] = "\u0409", // Љ + [4345] = "\u0459", // љ + [4347] = "\u22D8", // ⋘ + [4349] = "\u226A", // ≪ + [4353] = "\u21C7", // ⇇ + [4360] = "\u231E", // ⌞ + [4369] = "\u21DA", // ⇚ + [4374] = "\u296B", // ⥫ + [4378] = "\u25FA", // ◺ + [4384] = "\u013F", // Ŀ + [4390] = "\u0140", // ŀ + [4395] = "\u23B0", // ⎰ + [4400] = "\u23B0", // ⎰ + [4404] = "\u2A89", // ⪉ + [4409] = "\u2A89", // ⪉ + [4411] = "\u2268", // ≨ + [4413] = "\u2A87", // ⪇ + [4415] = "\u2A87", // ⪇ + [4417] = "\u2268", // ≨ + [4421] = "\u22E6", // ⋦ + [4426] = "\u27EC", // ⟬ + [4429] = "\u21FD", // ⇽ + [4433] = "\u27E6", // ⟦ + [4446] = "\u27F5", // ⟵ + [4456] = "\u27F8", // ⟸ + [4468] = "\u27F5", // ⟵ + [4479] = "\u27F7", // ⟷ + [4490] = "\u27FA", // ⟺ + [4501] = "\u27F7", // ⟷ + [4508] = "\u27FC", // ⟼ + [4519] = "\u27F6", // ⟶ + [4530] = "\u27F9", // ⟹ + [4541] = "\u27F6", // ⟶ + [4553] = "\u21AB", // ↫ + [4559] = "\u21AC", // ↬ + [4563] = "\u2985", // ⦅ + [4566] = "\uD835\uDD43", // 𝕃 + [4568] = "\uD835\uDD5D", // 𝕝 + [4572] = "\u2A2D", // ⨭ + [4578] = "\u2A34", // ⨴ + [4583] = "\u2217", // ∗ + [4587] = "\u005F", // _ + [4600] = "\u2199", // ↙ + [4611] = "\u2198", // ↘ + [4613] = "\u25CA", // ◊ + [4618] = "\u25CA", // ◊ + [4620] = "\u29EB", // ⧫ + [4624] = "\u0028", // ( + [4627] = "\u2993", // ⦓ + [4632] = "\u21C6", // ⇆ + [4639] = "\u231F", // ⌟ + [4643] = "\u21CB", // ⇋ + [4645] = "\u296D", // ⥭ + [4647] = "\u200E", // ‎ + [4651] = "\u22BF", // ⊿ + [4657] = "\u2039", // ‹ + [4661] = "\u2112", // ℒ + [4664] = "\uD835\uDCC1", // 𝓁 + [4666] = "\u21B0", // ↰ + [4668] = "\u21B0", // ↰ + [4671] = "\u2272", // ≲ + [4673] = "\u2A8D", // ⪍ + [4675] = "\u2A8F", // ⪏ + [4678] = "\u005B", // [ + [4681] = "\u2018", // ‘ + [4683] = "\u201A", // ‚ + [4688] = "\u0141", // Ł + [4693] = "\u0142", // ł + [4694] = "\u003C", // < + [4695] = "\u003C", // < + [4697] = "\u226A", // ≪ + [4698] = "\u003C", // < + [4699] = "\u003C", // < + [4702] = "\u2AA6", // ⪦ + [4705] = "\u2A79", // ⩹ + [4709] = "\u22D6", // ⋖ + [4714] = "\u22CB", // ⋋ + [4719] = "\u22C9", // ⋉ + [4724] = "\u2976", // ⥶ + [4730] = "\u2A7B", // ⩻ + [4733] = "\u25C3", // ◃ + [4735] = "\u22B4", // ⊴ + [4737] = "\u25C2", // ◂ + [4741] = "\u2996", // ⦖ + [4749] = "\u294A", // ⥊ + [4754] = "\u2966", // ⥦ + [4763] = "\u2268\uFE00", // ≨︀ + [4766] = "\u2268\uFE00", // ≨︀ + [4770] = "\u00AF", // ¯ + [4771] = "\u00AF", // ¯ + [4774] = "\u2642", // ♂ + [4776] = "\u2720", // ✠ + [4780] = "\u2720", // ✠ + [4784] = "\u2905", // ⤅ + [4786] = "\u21A6", // ↦ + [4790] = "\u21A6", // ↦ + [4795] = "\u21A7", // ↧ + [4800] = "\u21A4", // ↤ + [4803] = "\u21A5", // ↥ + [4808] = "\u25AE", // ▮ + [4814] = "\u2A29", // ⨩ + [4817] = "\u041C", // М + [4819] = "\u043C", // м + [4824] = "\u2014", // — + [4829] = "\u223A", // ∺ + [4842] = "\u2221", // ∡ + [4853] = "\u205F", //   + [4861] = "\u2133", // ℳ + [4864] = "\uD835\uDD10", // 𝔐 + [4867] = "\uD835\uDD2A", // 𝔪 + [4870] = "\u2127", // ℧ + [4874] = "\u00B5", // µ + [4875] = "\u00B5", // µ + [4877] = "\u2223", // ∣ + [4881] = "\u002A", // * + [4885] = "\u2AF0", // ⫰ + [4888] = "\u00B7", // · + [4889] = "\u00B7", // · + [4893] = "\u2212", // − + [4895] = "\u229F", // ⊟ + [4897] = "\u2238", // ∸ + [4899] = "\u2A2A", // ⨪ + [4908] = "\u2213", // ∓ + [4912] = "\u2ADB", // ⫛ + [4915] = "\u2026", // … + [4921] = "\u2213", // ∓ + [4927] = "\u22A7", // ⊧ + [4931] = "\uD835\uDD44", // 𝕄 + [4934] = "\uD835\uDD5E", // 𝕞 + [4936] = "\u2213", // ∓ + [4940] = "\u2133", // ℳ + [4944] = "\uD835\uDCC2", // 𝓂 + [4949] = "\u223E", // ∾ + [4951] = "\u039C", // Μ + [4953] = "\u03BC", // μ + [4960] = "\u22B8", // ⊸ + [4964] = "\u22B8", // ⊸ + [4970] = "\u2207", // ∇ + [4977] = "\u0143", // Ń + [4982] = "\u0144", // ń + [4985] = "\u2220\u20D2", // ∠⃒ + [4987] = "\u2249", // ≉ + [4989] = "\u2A70\u0338", // ⩰̸ + [4992] = "\u224B\u0338", // ≋̸ + [4995] = "\u0149", // ʼn + [5000] = "\u2249", // ≉ + [5004] = "\u266E", // ♮ + [5007] = "\u266E", // ♮ + [5009] = "\u2115", // ℕ + [5012] = "\u00A0", //   + [5013] = "\u00A0", //   + [5017] = "\u224E\u0338", // ≎̸ + [5019] = "\u224F\u0338", // ≏̸ + [5023] = "\u2A43", // ⩃ + [5029] = "\u0147", // Ň + [5033] = "\u0148", // ň + [5038] = "\u0145", // Ņ + [5043] = "\u0146", // ņ + [5047] = "\u2247", // ≇ + [5051] = "\u2A6D\u0338", // ⩭̸ + [5054] = "\u2A42", // ⩂ + [5056] = "\u041D", // Н + [5058] = "\u043D", // н + [5063] = "\u2013", // – + [5065] = "\u2260", // ≠ + [5070] = "\u2924", // ⤤ + [5074] = "\u21D7", // ⇗ + [5076] = "\u2197", // ↗ + [5079] = "\u2197", // ↗ + [5083] = "\u2250\u0338", // ≐̸ + [5102] = "\u200B", // ​ + [5113] = "\u200B", // ​ + [5120] = "\u200B", // ​ + [5134] = "\u200B", // ​ + [5139] = "\u2262", // ≢ + [5144] = "\u2928", // ⤨ + [5147] = "\u2242\u0338", // ≂̸ + [5166] = "\u226B", // ≫ + [5175] = "\u226A", // ≪ + [5181] = "\u000A", // + [5186] = "\u2204", // ∄ + [5188] = "\u2204", // ∄ + [5191] = "\uD835\uDD11", // 𝔑 + [5194] = "\uD835\uDD2B", // 𝔫 + [5197] = "\u2267\u0338", // ≧̸ + [5199] = "\u2271", // ≱ + [5201] = "\u2271", // ≱ + [5203] = "\u2267\u0338", // ≧̸ + [5209] = "\u2A7E\u0338", // ⩾̸ + [5211] = "\u2A7E\u0338", // ⩾̸ + [5214] = "\u22D9\u0338", // ⋙̸ + [5218] = "\u2275", // ≵ + [5220] = "\u226B\u20D2", // ≫⃒ + [5222] = "\u226F", // ≯ + [5224] = "\u226F", // ≯ + [5226] = "\u226B\u0338", // ≫̸ + [5231] = "\u21CE", // ⇎ + [5235] = "\u21AE", // ↮ + [5239] = "\u2AF2", // ⫲ + [5241] = "\u220B", // ∋ + [5243] = "\u22FC", // ⋼ + [5245] = "\u22FA", // ⋺ + [5247] = "\u220B", // ∋ + [5251] = "\u040A", // Њ + [5255] = "\u045A", // њ + [5260] = "\u21CD", // ⇍ + [5264] = "\u219A", // ↚ + [5267] = "\u2025", // ‥ + [5269] = "\u2266\u0338", // ≦̸ + [5271] = "\u2270", // ≰ + [5281] = "\u21CD", // ⇍ + [5289] = "\u219A", // ↚ + [5300] = "\u21CE", // ⇎ + [5311] = "\u21AE", // ↮ + [5313] = "\u2270", // ≰ + [5315] = "\u2266\u0338", // ≦̸ + [5321] = "\u2A7D\u0338", // ⩽̸ + [5323] = "\u2A7D\u0338", // ⩽̸ + [5325] = "\u226E", // ≮ + [5327] = "\u22D8\u0338", // ⋘̸ + [5331] = "\u2274", // ≴ + [5333] = "\u226A\u20D2", // ≪⃒ + [5335] = "\u226E", // ≮ + [5338] = "\u22EA", // ⋪ + [5340] = "\u22EC", // ⋬ + [5342] = "\u226A\u0338", // ≪̸ + [5346] = "\u2224", // ∤ + [5353] = "\u2060", // ⁠ + [5368] = "\u00A0", //   + [5371] = "\u2115", // ℕ + [5375] = "\uD835\uDD5F", // 𝕟 + [5377] = "\u2AEC", // ⫬ + [5378] = "\u00AC", // ¬ + [5379] = "\u00AC", // ¬ + [5389] = "\u2262", // ≢ + [5395] = "\u226D", // ≭ + [5413] = "\u2226", // ∦ + [5421] = "\u2209", // ∉ + [5426] = "\u2260", // ≠ + [5432] = "\u2242\u0338", // ≂̸ + [5438] = "\u2204", // ∄ + [5446] = "\u226F", // ≯ + [5452] = "\u2271", // ≱ + [5462] = "\u2267\u0338", // ≧̸ + [5470] = "\u226B\u0338", // ≫̸ + [5475] = "\u2279", // ≹ + [5486] = "\u2A7E\u0338", // ⩾̸ + [5492] = "\u2275", // ≵ + [5505] = "\u224E\u0338", // ≎̸ + [5511] = "\u224F\u0338", // ≏̸ + [5514] = "\u2209", // ∉ + [5518] = "\u22F5\u0338", // ⋵̸ + [5520] = "\u22F9\u0338", // ⋹̸ + [5523] = "\u2209", // ∉ + [5525] = "\u22F7", // ⋷ + [5527] = "\u22F6", // ⋶ + [5540] = "\u22EA", // ⋪ + [5544] = "\u29CF\u0338", // ⧏̸ + [5550] = "\u22EC", // ⋬ + [5553] = "\u226E", // ≮ + [5559] = "\u2270", // ≰ + [5567] = "\u2278", // ≸ + [5572] = "\u226A\u0338", // ≪̸ + [5583] = "\u2A7D\u0338", // ⩽̸ + [5589] = "\u2274", // ≴ + [5610] = "\u2AA2\u0338", // ⪢̸ + [5619] = "\u2AA1\u0338", // ⪡̸ + [5622] = "\u220C", // ∌ + [5625] = "\u220C", // ∌ + [5627] = "\u22FE", // ⋾ + [5629] = "\u22FD", // ⋽ + [5638] = "\u2280", // ⊀ + [5644] = "\u2AAF\u0338", // ⪯̸ + [5655] = "\u22E0", // ⋠ + [5670] = "\u220C", // ∌ + [5683] = "\u22EB", // ⋫ + [5687] = "\u29D0\u0338", // ⧐̸ + [5693] = "\u22ED", // ⋭ + [5706] = "\u228F\u0338", // ⊏̸ + [5712] = "\u22E2", // ⋢ + [5719] = "\u2290\u0338", // ⊐̸ + [5725] = "\u22E3", // ⋣ + [5731] = "\u2282\u20D2", // ⊂⃒ + [5737] = "\u2288", // ⊈ + [5744] = "\u2281", // ⊁ + [5750] = "\u2AB0\u0338", // ⪰̸ + [5761] = "\u22E1", // ⋡ + [5767] = "\u227F\u0338", // ≿̸ + [5774] = "\u2283\u20D2", // ⊃⃒ + [5780] = "\u2289", // ⊉ + [5786] = "\u2241", // ≁ + [5792] = "\u2244", // ≄ + [5802] = "\u2247", // ≇ + [5808] = "\u2249", // ≉ + [5820] = "\u2224", // ∤ + [5824] = "\u2226", // ∦ + [5830] = "\u2226", // ∦ + [5833] = "\u2AFD\u20E5", // ⫽⃥ + [5835] = "\u2202\u0338", // ∂̸ + [5841] = "\u2A14", // ⨔ + [5843] = "\u2280", // ⊀ + [5847] = "\u22E0", // ⋠ + [5849] = "\u2AAF\u0338", // ⪯̸ + [5851] = "\u2280", // ⊀ + [5854] = "\u2AAF\u0338", // ⪯̸ + [5859] = "\u21CF", // ⇏ + [5863] = "\u219B", // ↛ + [5865] = "\u2933\u0338", // ⤳̸ + [5867] = "\u219D\u0338", // ↝̸ + [5878] = "\u21CF", // ⇏ + [5888] = "\u219B", // ↛ + [5892] = "\u22EB", // ⋫ + [5894] = "\u22ED", // ⋭ + [5897] = "\u2281", // ⊁ + [5901] = "\u22E1", // ⋡ + [5903] = "\u2AB0\u0338", // ⪰̸ + [5907] = "\uD835\uDCA9", // 𝒩 + [5909] = "\uD835\uDCC3", // 𝓃 + [5917] = "\u2224", // ∤ + [5926] = "\u2226", // ∦ + [5929] = "\u2241", // ≁ + [5931] = "\u2244", // ≄ + [5933] = "\u2244", // ≄ + [5937] = "\u2224", // ∤ + [5941] = "\u2226", // ∦ + [5947] = "\u22E2", // ⋢ + [5950] = "\u22E3", // ⋣ + [5953] = "\u2284", // ⊄ + [5955] = "\u2AC5\u0338", // ⫅̸ + [5957] = "\u2288", // ⊈ + [5961] = "\u2282\u20D2", // ⊂⃒ + [5964] = "\u2288", // ⊈ + [5966] = "\u2AC5\u0338", // ⫅̸ + [5969] = "\u2281", // ⊁ + [5972] = "\u2AB0\u0338", // ⪰̸ + [5974] = "\u2285", // ⊅ + [5976] = "\u2AC6\u0338", // ⫆̸ + [5978] = "\u2289", // ⊉ + [5982] = "\u2283\u20D2", // ⊃⃒ + [5985] = "\u2289", // ⊉ + [5987] = "\u2AC6\u0338", // ⫆̸ + [5991] = "\u2279", // ≹ + [5996] = "\u00D1", // Ñ + [5997] = "\u00D1", // Ñ + [6001] = "\u00F1", // ñ + [6002] = "\u00F1", // ñ + [6005] = "\u2278", // ≸ + [6017] = "\u22EA", // ⋪ + [6020] = "\u22EC", // ⋬ + [6026] = "\u22EB", // ⋫ + [6029] = "\u22ED", // ⋭ + [6031] = "\u039D", // Ν + [6033] = "\u03BD", // ν + [6035] = "\u0023", // # + [6039] = "\u2116", // № + [6042] = "\u2007", //   + [6046] = "\u224D\u20D2", // ≍⃒ + [6052] = "\u22AF", // ⊯ + [6057] = "\u22AE", // ⊮ + [6062] = "\u22AD", // ⊭ + [6067] = "\u22AC", // ⊬ + [6070] = "\u2265\u20D2", // ≥⃒ + [6072] = "\u003E\u20D2", // >⃒ + [6077] = "\u2904", // ⤄ + [6083] = "\u29DE", // ⧞ + [6088] = "\u2902", // ⤂ + [6090] = "\u2264\u20D2", // ≤⃒ + [6092] = "\u003C\u20D2", // <⃒ + [6096] = "\u22B4\u20D2", // ⊴⃒ + [6101] = "\u2903", // ⤃ + [6106] = "\u22B5\u20D2", // ⊵⃒ + [6110] = "\u223C\u20D2", // ∼⃒ + [6116] = "\u2923", // ⤣ + [6120] = "\u21D6", // ⇖ + [6122] = "\u2196", // ↖ + [6125] = "\u2196", // ↖ + [6130] = "\u2927", // ⤧ + [6136] = "\u00D3", // Ó + [6137] = "\u00D3", // Ó + [6143] = "\u00F3", // ó + [6144] = "\u00F3", // ó + [6147] = "\u229B", // ⊛ + [6151] = "\u229A", // ⊚ + [6155] = "\u00D4", // Ô + [6156] = "\u00D4", // Ô + [6157] = "\u00F4", // ô + [6158] = "\u00F4", // ô + [6160] = "\u041E", // О + [6162] = "\u043E", // о + [6167] = "\u229D", // ⊝ + [6173] = "\u0150", // Ő + [6178] = "\u0151", // ő + [6181] = "\u2A38", // ⨸ + [6184] = "\u2299", // ⊙ + [6189] = "\u29BC", // ⦼ + [6194] = "\u0152", // Œ + [6199] = "\u0153", // œ + [6204] = "\u29BF", // ⦿ + [6207] = "\uD835\uDD12", // 𝔒 + [6209] = "\uD835\uDD2C", // 𝔬 + [6213] = "\u02DB", // ˛ + [6218] = "\u00D2", // Ò + [6219] = "\u00D2", // Ò + [6223] = "\u00F2", // ò + [6224] = "\u00F2", // ò + [6226] = "\u29C1", // ⧁ + [6231] = "\u29B5", // ⦵ + [6233] = "\u03A9", // Ω + [6237] = "\u222E", // ∮ + [6242] = "\u21BA", // ↺ + [6246] = "\u29BE", // ⦾ + [6251] = "\u29BB", // ⦻ + [6255] = "\u203E", // ‾ + [6257] = "\u29C0", // ⧀ + [6262] = "\u014C", // Ō + [6267] = "\u014D", // ō + [6271] = "\u03A9", // Ω + [6275] = "\u03C9", // ω + [6281] = "\u039F", // Ο + [6287] = "\u03BF", // ο + [6289] = "\u29B6", // ⦶ + [6293] = "\u2296", // ⊖ + [6297] = "\uD835\uDD46", // 𝕆 + [6301] = "\uD835\uDD60", // 𝕠 + [6305] = "\u29B7", // ⦷ + [6325] = "\u201C", // “ + [6331] = "\u2018", // ‘ + [6335] = "\u29B9", // ⦹ + [6339] = "\u2295", // ⊕ + [6341] = "\u2A54", // ⩔ + [6343] = "\u2228", // ∨ + [6347] = "\u21BB", // ↻ + [6349] = "\u2A5D", // ⩝ + [6352] = "\u2134", // ℴ + [6355] = "\u2134", // ℴ + [6356] = "\u00AA", // ª + [6357] = "\u00AA", // ª + [6358] = "\u00BA", // º + [6359] = "\u00BA", // º + [6364] = "\u22B6", // ⊶ + [6367] = "\u2A56", // ⩖ + [6373] = "\u2A57", // ⩗ + [6375] = "\u2A5B", // ⩛ + [6377] = "\u24C8", // Ⓢ + [6381] = "\uD835\uDCAA", // 𝒪 + [6385] = "\u2134", // ℴ + [6389] = "\u00D8", // Ø + [6390] = "\u00D8", // Ø + [6394] = "\u00F8", // ø + [6395] = "\u00F8", // ø + [6398] = "\u2298", // ⊘ + [6403] = "\u00D5", // Õ + [6404] = "\u00D5", // Õ + [6409] = "\u00F5", // õ + [6410] = "\u00F5", // õ + [6414] = "\u2A37", // ⨷ + [6418] = "\u2297", // ⊗ + [6421] = "\u2A36", // ⨶ + [6424] = "\u00D6", // Ö + [6425] = "\u00D6", // Ö + [6428] = "\u00F6", // ö + [6429] = "\u00F6", // ö + [6434] = "\u233D", // ⌽ + [6441] = "\u203E", // ‾ + [6446] = "\u23DE", // ⏞ + [6450] = "\u23B4", // ⎴ + [6462] = "\u23DC", // ⏜ + [6466] = "\u2225", // ∥ + [6467] = "\u00B6", // ¶ + [6468] = "\u00B6", // ¶ + [6473] = "\u2225", // ∥ + [6477] = "\u2AF3", // ⫳ + [6479] = "\u2AFD", // ⫽ + [6481] = "\u2202", // ∂ + [6490] = "\u2202", // ∂ + [6493] = "\u041F", // П + [6496] = "\u043F", // п + [6502] = "\u0025", // % + [6506] = "\u002E", // . + [6510] = "\u2030", // ‰ + [6512] = "\u22A5", // ⊥ + [6517] = "\u2031", // ‱ + [6520] = "\uD835\uDD13", // 𝔓 + [6523] = "\uD835\uDD2D", // 𝔭 + [6526] = "\u03A6", // Φ + [6529] = "\u03C6", // φ + [6531] = "\u03D5", // ϕ + [6536] = "\u2133", // ℳ + [6540] = "\u260E", // ☎ + [6542] = "\u03A0", // Π + [6544] = "\u03C0", // π + [6552] = "\u22D4", // ⋔ + [6554] = "\u03D6", // ϖ + [6560] = "\u210F", // ℏ + [6562] = "\u210E", // ℎ + [6565] = "\u210F", // ℏ + [6568] = "\u002B", // + + [6573] = "\u2A23", // ⨣ + [6575] = "\u229E", // ⊞ + [6579] = "\u2A22", // ⨢ + [6582] = "\u2214", // ∔ + [6584] = "\u2A25", // ⨥ + [6586] = "\u2A72", // ⩲ + [6595] = "\u00B1", // ± + [6597] = "\u00B1", // ± + [6598] = "\u00B1", // ± + [6602] = "\u2A26", // ⨦ + [6606] = "\u2A27", // ⨧ + [6608] = "\u00B1", // ± + [6621] = "\u210C", // ℌ + [6629] = "\u2A15", // ⨕ + [6632] = "\u2119", // ℙ + [6635] = "\uD835\uDD61", // 𝕡 + [6638] = "\u00A3", // £ + [6639] = "\u00A3", // £ + [6641] = "\u2ABB", // ⪻ + [6643] = "\u227A", // ≺ + [6646] = "\u2AB7", // ⪷ + [6650] = "\u227C", // ≼ + [6652] = "\u2AB3", // ⪳ + [6654] = "\u2AAF", // ⪯ + [6656] = "\u227A", // ≺ + [6663] = "\u2AB7", // ⪷ + [6671] = "\u227C", // ≼ + [6678] = "\u227A", // ≺ + [6684] = "\u2AAF", // ⪯ + [6695] = "\u227C", // ≼ + [6701] = "\u227E", // ≾ + [6704] = "\u2AAF", // ⪯ + [6712] = "\u2AB9", // ⪹ + [6716] = "\u2AB5", // ⪵ + [6720] = "\u22E8", // ⋨ + [6724] = "\u227E", // ≾ + [6728] = "\u2033", // ″ + [6732] = "\u2032", // ′ + [6734] = "\u2119", // ℙ + [6738] = "\u2AB9", // ⪹ + [6740] = "\u2AB5", // ⪵ + [6744] = "\u22E8", // ⋨ + [6747] = "\u220F", // ∏ + [6753] = "\u220F", // ∏ + [6759] = "\u232E", // ⌮ + [6764] = "\u2312", // ⌒ + [6769] = "\u2313", // ⌓ + [6771] = "\u221D", // ∝ + [6779] = "\u2237", // ∷ + [6782] = "\u221D", // ∝ + [6785] = "\u221D", // ∝ + [6789] = "\u227E", // ≾ + [6794] = "\u22B0", // ⊰ + [6798] = "\uD835\uDCAB", // 𝒫 + [6802] = "\uD835\uDCC5", // 𝓅 + [6804] = "\u03A8", // Ψ + [6806] = "\u03C8", // ψ + [6812] = "\u2008", //   + [6816] = "\uD835\uDD14", // 𝔔 + [6820] = "\uD835\uDD2E", // 𝔮 + [6824] = "\u2A0C", // ⨌ + [6828] = "\u211A", // ℚ + [6832] = "\uD835\uDD62", // 𝕢 + [6838] = "\u2057", // ⁗ + [6842] = "\uD835\uDCAC", // 𝒬 + [6846] = "\uD835\uDCC6", // 𝓆 + [6857] = "\u210D", // ℍ + [6861] = "\u2A16", // ⨖ + [6865] = "\u003F", // ? + [6868] = "\u225F", // ≟ + [6871] = "\u0022", // " + [6872] = "\u0022", // " + [6874] = "\u0022", // " + [6875] = "\u0022", // " + [6881] = "\u21DB", // ⇛ + [6885] = "\u223D\u0331", // ∽̱ + [6892] = "\u0154", // Ŕ + [6896] = "\u0155", // ŕ + [6900] = "\u221A", // √ + [6907] = "\u29B3", // ⦳ + [6910] = "\u27EB", // ⟫ + [6913] = "\u27E9", // ⟩ + [6915] = "\u2992", // ⦒ + [6917] = "\u29A5", // ⦥ + [6920] = "\u27E9", // ⟩ + [6923] = "\u00BB", // » + [6924] = "\u00BB", // » + [6927] = "\u21A0", // ↠ + [6930] = "\u21D2", // ⇒ + [6933] = "\u2192", // → + [6936] = "\u2975", // ⥵ + [6938] = "\u21E5", // ⇥ + [6941] = "\u2920", // ⤠ + [6943] = "\u2933", // ⤳ + [6946] = "\u291E", // ⤞ + [6949] = "\u21AA", // ↪ + [6952] = "\u21AC", // ↬ + [6955] = "\u2945", // ⥅ + [6959] = "\u2974", // ⥴ + [6962] = "\u2916", // ⤖ + [6965] = "\u21A3", // ↣ + [6967] = "\u219D", // ↝ + [6972] = "\u291C", // ⤜ + [6977] = "\u291A", // ⤚ + [6980] = "\u2236", // ∶ + [6985] = "\u211A", // ℚ + [6990] = "\u2910", // ⤐ + [6995] = "\u290F", // ⤏ + [7000] = "\u290D", // ⤍ + [7004] = "\u2773", // ❳ + [7009] = "\u007D", // } + [7011] = "\u005D", // ] + [7014] = "\u298C", // ⦌ + [7018] = "\u298E", // ⦎ + [7020] = "\u2990", // ⦐ + [7026] = "\u0158", // Ř + [7032] = "\u0159", // ř + [7037] = "\u0156", // Ŗ + [7042] = "\u0157", // ŗ + [7045] = "\u2309", // ⌉ + [7048] = "\u007D", // } + [7050] = "\u0420", // Р + [7052] = "\u0440", // р + [7056] = "\u2937", // ⤷ + [7062] = "\u2969", // ⥩ + [7066] = "\u201D", // ” + [7068] = "\u201D", // ” + [7071] = "\u21B3", // ↳ + [7073] = "\u211C", // ℜ + [7077] = "\u211C", // ℜ + [7081] = "\u211B", // ℛ + [7086] = "\u211C", // ℜ + [7088] = "\u211D", // ℝ + [7091] = "\u25AD", // ▭ + [7093] = "\u00AE", // ® + [7094] = "\u00AE", // ® + [7095] = "\u00AE", // ® + [7096] = "\u00AE", // ® + [7109] = "\u220B", // ∋ + [7120] = "\u21CB", // ⇋ + [7134] = "\u296F", // ⥯ + [7140] = "\u297D", // ⥽ + [7145] = "\u230B", // ⌋ + [7148] = "\u211C", // ℜ + [7150] = "\uD835\uDD2F", // 𝔯 + [7154] = "\u2964", // ⥤ + [7159] = "\u21C1", // ⇁ + [7161] = "\u21C0", // ⇀ + [7163] = "\u296C", // ⥬ + [7166] = "\u03A1", // Ρ + [7168] = "\u03C1", // ρ + [7170] = "\u03F1", // ϱ + [7187] = "\u27E9", // ⟩ + [7192] = "\u2192", // → + [7198] = "\u21D2", // ⇒ + [7208] = "\u2192", // → + [7212] = "\u21E5", // ⇥ + [7222] = "\u21C4", // ⇄ + [7227] = "\u21A3", // ↣ + [7235] = "\u2309", // ⌉ + [7249] = "\u27E7", // ⟧ + [7261] = "\u295D", // ⥝ + [7268] = "\u21C2", // ⇂ + [7272] = "\u2955", // ⥕ + [7278] = "\u230B", // ⌋ + [7290] = "\u21C1", // ⇁ + [7293] = "\u21C0", // ⇀ + [7304] = "\u21C4", // ⇄ + [7313] = "\u21CC", // ⇌ + [7325] = "\u21C9", // ⇉ + [7336] = "\u219D", // ↝ + [7340] = "\u22A2", // ⊢ + [7346] = "\u21A6", // ↦ + [7353] = "\u295B", // ⥛ + [7364] = "\u22CC", // ⋌ + [7372] = "\u22B3", // ⊳ + [7376] = "\u29D0", // ⧐ + [7382] = "\u22B5", // ⊵ + [7395] = "\u294F", // ⥏ + [7405] = "\u295C", // ⥜ + [7412] = "\u21BE", // ↾ + [7416] = "\u2954", // ⥔ + [7423] = "\u21C0", // ⇀ + [7427] = "\u2953", // ⥓ + [7430] = "\u02DA", // ˚ + [7441] = "\u2253", // ≓ + [7446] = "\u21C4", // ⇄ + [7450] = "\u21CC", // ⇌ + [7452] = "\u200F", // ‏ + [7458] = "\u23B1", // ⎱ + [7463] = "\u23B1", // ⎱ + [7468] = "\u2AEE", // ⫮ + [7473] = "\u27ED", // ⟭ + [7476] = "\u21FE", // ⇾ + [7480] = "\u27E7", // ⟧ + [7484] = "\u2986", // ⦆ + [7488] = "\u211D", // ℝ + [7490] = "\uD835\uDD63", // 𝕣 + [7494] = "\u2A2E", // ⨮ + [7500] = "\u2A35", // ⨵ + [7511] = "\u2970", // ⥰ + [7515] = "\u0029", // ) + [7518] = "\u2994", // ⦔ + [7525] = "\u2A12", // ⨒ + [7530] = "\u21C9", // ⇉ + [7541] = "\u21DB", // ⇛ + [7547] = "\u203A", // › + [7551] = "\u211B", // ℛ + [7554] = "\uD835\uDCC7", // 𝓇 + [7556] = "\u21B1", // ↱ + [7558] = "\u21B1", // ↱ + [7561] = "\u005D", // ] + [7564] = "\u2019", // ’ + [7566] = "\u2019", // ’ + [7572] = "\u22CC", // ⋌ + [7577] = "\u22CA", // ⋊ + [7580] = "\u25B9", // ▹ + [7582] = "\u22B5", // ⊵ + [7584] = "\u25B8", // ▸ + [7589] = "\u29CE", // ⧎ + [7600] = "\u29F4", // ⧴ + [7607] = "\u2968", // ⥨ + [7609] = "\u211E", // ℞ + [7616] = "\u015A", // Ś + [7623] = "\u015B", // ś + [7628] = "\u201A", // ‚ + [7630] = "\u2ABC", // ⪼ + [7632] = "\u227B", // ≻ + [7635] = "\u2AB8", // ⪸ + [7640] = "\u0160", // Š + [7644] = "\u0161", // š + [7648] = "\u227D", // ≽ + [7650] = "\u2AB4", // ⪴ + [7652] = "\u2AB0", // ⪰ + [7657] = "\u015E", // Ş + [7661] = "\u015F", // ş + [7665] = "\u015C", // Ŝ + [7669] = "\u015D", // ŝ + [7673] = "\u2ABA", // ⪺ + [7675] = "\u2AB6", // ⪶ + [7679] = "\u22E9", // ⋩ + [7686] = "\u2A13", // ⨓ + [7690] = "\u227F", // ≿ + [7692] = "\u0421", // С + [7694] = "\u0441", // с + [7698] = "\u22C5", // ⋅ + [7700] = "\u22A1", // ⊡ + [7702] = "\u2A66", // ⩦ + [7708] = "\u2925", // ⤥ + [7712] = "\u21D8", // ⇘ + [7714] = "\u2198", // ↘ + [7717] = "\u2198", // ↘ + [7719] = "\u00A7", // § + [7720] = "\u00A7", // § + [7723] = "\u003B", // ; + [7728] = "\u2929", // ⤩ + [7735] = "\u2216", // ∖ + [7737] = "\u2216", // ∖ + [7740] = "\u2736", // ✶ + [7743] = "\uD835\uDD16", // 𝔖 + [7746] = "\uD835\uDD30", // 𝔰 + [7750] = "\u2322", // ⌢ + [7755] = "\u266F", // ♯ + [7761] = "\u0429", // Щ + [7766] = "\u0449", // щ + [7769] = "\u0428", // Ш + [7771] = "\u0448", // ш + [7785] = "\u2193", // ↓ + [7795] = "\u2190", // ← + [7802] = "\u2223", // ∣ + [7811] = "\u2225", // ∥ + [7822] = "\u2192", // → + [7830] = "\u2191", // ↑ + [7831] = "\u00AD", // ­ + [7832] = "\u00AD", // ­ + [7837] = "\u03A3", // Σ + [7842] = "\u03C3", // σ + [7844] = "\u03C2", // ς + [7846] = "\u03C2", // ς + [7848] = "\u223C", // ∼ + [7852] = "\u2A6A", // ⩪ + [7854] = "\u2243", // ≃ + [7856] = "\u2243", // ≃ + [7858] = "\u2A9E", // ⪞ + [7860] = "\u2AA0", // ⪠ + [7862] = "\u2A9D", // ⪝ + [7864] = "\u2A9F", // ⪟ + [7867] = "\u2246", // ≆ + [7872] = "\u2A24", // ⨤ + [7877] = "\u2972", // ⥲ + [7882] = "\u2190", // ← + [7893] = "\u2218", // ∘ + [7906] = "\u2216", // ∖ + [7910] = "\u2A33", // ⨳ + [7917] = "\u29E4", // ⧤ + [7920] = "\u2223", // ∣ + [7923] = "\u2323", // ⌣ + [7925] = "\u2AAA", // ⪪ + [7927] = "\u2AAC", // ⪬ + [7929] = "\u2AAC\uFE00", // ⪬︀ + [7935] = "\u042C", // Ь + [7941] = "\u044C", // ь + [7943] = "\u002F", // / + [7945] = "\u29C4", // ⧄ + [7948] = "\u233F", // ⌿ + [7952] = "\uD835\uDD4A", // 𝕊 + [7955] = "\uD835\uDD64", // 𝕤 + [7961] = "\u2660", // ♠ + [7965] = "\u2660", // ♠ + [7967] = "\u2225", // ∥ + [7972] = "\u2293", // ⊓ + [7974] = "\u2293\uFE00", // ⊓︀ + [7977] = "\u2294", // ⊔ + [7979] = "\u2294\uFE00", // ⊔︀ + [7983] = "\u221A", // √ + [7987] = "\u228F", // ⊏ + [7989] = "\u2291", // ⊑ + [7993] = "\u228F", // ⊏ + [7996] = "\u2291", // ⊑ + [7998] = "\u2290", // ⊐ + [8000] = "\u2292", // ⊒ + [8004] = "\u2290", // ⊐ + [8007] = "\u2292", // ⊒ + [8009] = "\u25A1", // □ + [8014] = "\u25A1", // □ + [8018] = "\u25A1", // □ + [8031] = "\u2293", // ⊓ + [8038] = "\u228F", // ⊏ + [8044] = "\u2291", // ⊑ + [8051] = "\u2290", // ⊐ + [8057] = "\u2292", // ⊒ + [8063] = "\u2294", // ⊔ + [8065] = "\u25AA", // ▪ + [8067] = "\u25AA", // ▪ + [8072] = "\u2192", // → + [8076] = "\uD835\uDCAE", // 𝒮 + [8080] = "\uD835\uDCC8", // 𝓈 + [8085] = "\u2216", // ∖ + [8090] = "\u2323", // ⌣ + [8095] = "\u22C6", // ⋆ + [8099] = "\u22C6", // ⋆ + [8103] = "\u2606", // ☆ + [8105] = "\u2605", // ★ + [8119] = "\u03F5", // ϵ + [8123] = "\u03D5", // ϕ + [8126] = "\u00AF", // ¯ + [8129] = "\u22D0", // ⋐ + [8132] = "\u2282", // ⊂ + [8136] = "\u2ABD", // ⪽ + [8138] = "\u2AC5", // ⫅ + [8140] = "\u2286", // ⊆ + [8144] = "\u2AC3", // ⫃ + [8149] = "\u2AC1", // ⫁ + [8152] = "\u2ACB", // ⫋ + [8154] = "\u228A", // ⊊ + [8159] = "\u2ABF", // ⪿ + [8164] = "\u2979", // ⥹ + [8168] = "\u22D0", // ⋐ + [8172] = "\u2282", // ⊂ + [8175] = "\u2286", // ⊆ + [8177] = "\u2AC5", // ⫅ + [8183] = "\u2286", // ⊆ + [8187] = "\u228A", // ⊊ + [8189] = "\u2ACB", // ⫋ + [8192] = "\u2AC7", // ⫇ + [8195] = "\u2AD5", // ⫕ + [8197] = "\u2AD3", // ⫓ + [8200] = "\u227B", // ≻ + [8207] = "\u2AB8", // ⪸ + [8215] = "\u227D", // ≽ + [8222] = "\u227B", // ≻ + [8228] = "\u2AB0", // ⪰ + [8239] = "\u227D", // ≽ + [8245] = "\u227F", // ≿ + [8248] = "\u2AB0", // ⪰ + [8256] = "\u2ABA", // ⪺ + [8260] = "\u2AB6", // ⪶ + [8264] = "\u22E9", // ⋩ + [8268] = "\u227F", // ≿ + [8274] = "\u220B", // ∋ + [8276] = "\u2211", // ∑ + [8278] = "\u2211", // ∑ + [8281] = "\u266A", // ♪ + [8283] = "\u22D1", // ⋑ + [8285] = "\u2283", // ⊃ + [8286] = "\u00B9", // ¹ + [8287] = "\u00B9", // ¹ + [8288] = "\u00B2", // ² + [8289] = "\u00B2", // ² + [8290] = "\u00B3", // ³ + [8291] = "\u00B3", // ³ + [8295] = "\u2ABE", // ⪾ + [8299] = "\u2AD8", // ⫘ + [8301] = "\u2AC6", // ⫆ + [8303] = "\u2287", // ⊇ + [8307] = "\u2AC4", // ⫄ + [8313] = "\u2283", // ⊃ + [8319] = "\u2287", // ⊇ + [8324] = "\u27C9", // ⟉ + [8327] = "\u2AD7", // ⫗ + [8332] = "\u297B", // ⥻ + [8337] = "\u2AC2", // ⫂ + [8340] = "\u2ACC", // ⫌ + [8342] = "\u228B", // ⊋ + [8347] = "\u2AC0", // ⫀ + [8351] = "\u22D1", // ⋑ + [8355] = "\u2283", // ⊃ + [8358] = "\u2287", // ⊇ + [8360] = "\u2AC6", // ⫆ + [8364] = "\u228B", // ⊋ + [8366] = "\u2ACC", // ⫌ + [8369] = "\u2AC8", // ⫈ + [8372] = "\u2AD4", // ⫔ + [8374] = "\u2AD6", // ⫖ + [8380] = "\u2926", // ⤦ + [8384] = "\u21D9", // ⇙ + [8386] = "\u2199", // ↙ + [8389] = "\u2199", // ↙ + [8394] = "\u292A", // ⤪ + [8398] = "\u00DF", // ß + [8399] = "\u00DF", // ß + [8403] = "\u0009", // + [8410] = "\u2316", // ⌖ + [8412] = "\u03A4", // Τ + [8414] = "\u03C4", // τ + [8418] = "\u23B4", // ⎴ + [8424] = "\u0164", // Ť + [8430] = "\u0165", // ť + [8435] = "\u0162", // Ţ + [8440] = "\u0163", // ţ + [8442] = "\u0422", // Т + [8444] = "\u0442", // т + [8448] = "\u20DB", // ⃛ + [8454] = "\u2315", // ⌕ + [8457] = "\uD835\uDD17", // 𝔗 + [8460] = "\uD835\uDD31", // 𝔱 + [8466] = "\u2234", // ∴ + [8475] = "\u2234", // ∴ + [8480] = "\u2234", // ∴ + [8483] = "\u0398", // Θ + [8486] = "\u03B8", // θ + [8490] = "\u03D1", // ϑ + [8492] = "\u03D1", // ϑ + [8502] = "\u2248", // ≈ + [8506] = "\u223C", // ∼ + [8515] = "\u205F\u200A", //    + [8519] = "\u2009", //   + [8526] = "\u2009", //   + [8530] = "\u2248", // ≈ + [8534] = "\u223C", // ∼ + [8538] = "\u00DE", // Þ + [8539] = "\u00DE", // Þ + [8542] = "\u00FE", // þ + [8543] = "\u00FE", // þ + [8548] = "\u223C", // ∼ + [8553] = "\u02DC", // ˜ + [8559] = "\u2243", // ≃ + [8569] = "\u2245", // ≅ + [8575] = "\u2248", // ≈ + [8578] = "\u00D7", // × + [8579] = "\u00D7", // × + [8581] = "\u22A0", // ⊠ + [8584] = "\u2A31", // ⨱ + [8586] = "\u2A30", // ⨰ + [8589] = "\u222D", // ∭ + [8593] = "\u2928", // ⤨ + [8595] = "\u22A4", // ⊤ + [8599] = "\u2336", // ⌶ + [8603] = "\u2AF1", // ⫱ + [8607] = "\uD835\uDD4B", // 𝕋 + [8609] = "\uD835\uDD65", // 𝕥 + [8613] = "\u2ADA", // ⫚ + [8616] = "\u2929", // ⤩ + [8622] = "\u2034", // ‴ + [8627] = "\u2122", // ™ + [8632] = "\u2122", // ™ + [8639] = "\u25B5", // ▵ + [8644] = "\u25BF", // ▿ + [8649] = "\u25C3", // ◃ + [8652] = "\u22B4", // ⊴ + [8654] = "\u225C", // ≜ + [8660] = "\u25B9", // ▹ + [8663] = "\u22B5", // ⊵ + [8667] = "\u25EC", // ◬ + [8669] = "\u225C", // ≜ + [8675] = "\u2A3A", // ⨺ + [8684] = "\u20DB", // ⃛ + [8689] = "\u2A39", // ⨹ + [8692] = "\u29CD", // ⧍ + [8697] = "\u2A3B", // ⨻ + [8704] = "\u23E2", // ⏢ + [8708] = "\uD835\uDCAF", // 𝒯 + [8712] = "\uD835\uDCC9", // 𝓉 + [8716] = "\u0426", // Ц + [8718] = "\u0446", // ц + [8722] = "\u040B", // Ћ + [8726] = "\u045B", // ћ + [8731] = "\u0166", // Ŧ + [8736] = "\u0167", // ŧ + [8741] = "\u226C", // ≬ + [8756] = "\u219E", // ↞ + [8767] = "\u21A0", // ↠ + [8773] = "\u00DA", // Ú + [8774] = "\u00DA", // Ú + [8780] = "\u00FA", // ú + [8781] = "\u00FA", // ú + [8784] = "\u219F", // ↟ + [8788] = "\u21D1", // ⇑ + [8791] = "\u2191", // ↑ + [8796] = "\u2949", // ⥉ + [8801] = "\u040E", // Ў + [8806] = "\u045E", // ў + [8810] = "\u016C", // Ŭ + [8814] = "\u016D", // ŭ + [8818] = "\u00DB", // Û + [8819] = "\u00DB", // Û + [8823] = "\u00FB", // û + [8824] = "\u00FB", // û + [8826] = "\u0423", // У + [8828] = "\u0443", // у + [8833] = "\u21C5", // ⇅ + [8839] = "\u0170", // Ű + [8844] = "\u0171", // ű + [8848] = "\u296E", // ⥮ + [8854] = "\u297E", // ⥾ + [8857] = "\uD835\uDD18", // 𝔘 + [8859] = "\uD835\uDD32", // 𝔲 + [8864] = "\u00D9", // Ù + [8865] = "\u00D9", // Ù + [8870] = "\u00F9", // ù + [8871] = "\u00F9", // ù + [8875] = "\u2963", // ⥣ + [8880] = "\u21BF", // ↿ + [8882] = "\u21BE", // ↾ + [8886] = "\u2580", // ▀ + [8892] = "\u231C", // ⌜ + [8895] = "\u231C", // ⌜ + [8899] = "\u230F", // ⌏ + [8903] = "\u25F8", // ◸ + [8908] = "\u016A", // Ū + [8913] = "\u016B", // ū + [8914] = "\u00A8", // ¨ + [8915] = "\u00A8", // ¨ + [8923] = "\u005F", // _ + [8928] = "\u23DF", // ⏟ + [8932] = "\u23B5", // ⎵ + [8944] = "\u23DD", // ⏝ + [8948] = "\u22C3", // ⋃ + [8953] = "\u228E", // ⊎ + [8958] = "\u0172", // Ų + [8963] = "\u0173", // ų + [8966] = "\uD835\uDD4C", // 𝕌 + [8969] = "\uD835\uDD66", // 𝕦 + [8976] = "\u2191", // ↑ + [8982] = "\u21D1", // ⇑ + [8989] = "\u2191", // ↑ + [8993] = "\u2912", // ⤒ + [9003] = "\u21C5", // ⇅ + [9013] = "\u2195", // ↕ + [9023] = "\u21D5", // ⇕ + [9033] = "\u2195", // ↕ + [9045] = "\u296E", // ⥮ + [9057] = "\u21BF", // ↿ + [9063] = "\u21BE", // ↾ + [9067] = "\u228E", // ⊎ + [9080] = "\u2196", // ↖ + [9091] = "\u2197", // ↗ + [9094] = "\u03D2", // ϒ + [9097] = "\u03C5", // υ + [9099] = "\u03D2", // ϒ + [9103] = "\u03A5", // Υ + [9107] = "\u03C5", // υ + [9111] = "\u22A5", // ⊥ + [9117] = "\u21A5", // ↥ + [9126] = "\u21C8", // ⇈ + [9132] = "\u231D", // ⌝ + [9135] = "\u231D", // ⌝ + [9139] = "\u230E", // ⌎ + [9144] = "\u016E", // Ů + [9148] = "\u016F", // ů + [9152] = "\u25F9", // ◹ + [9156] = "\uD835\uDCB0", // 𝒰 + [9160] = "\uD835\uDCCA", // 𝓊 + [9165] = "\u22F0", // ⋰ + [9171] = "\u0168", // Ũ + [9176] = "\u0169", // ũ + [9179] = "\u25B5", // ▵ + [9181] = "\u25B4", // ▴ + [9186] = "\u21C8", // ⇈ + [9189] = "\u00DC", // Ü + [9190] = "\u00DC", // Ü + [9192] = "\u00FC", // ü + [9193] = "\u00FC", // ü + [9200] = "\u29A7", // ⦧ + [9207] = "\u299C", // ⦜ + [9216] = "\u03F5", // ϵ + [9222] = "\u03F0", // ϰ + [9230] = "\u2205", // ∅ + [9234] = "\u03D5", // ϕ + [9236] = "\u03D6", // ϖ + [9242] = "\u221D", // ∝ + [9246] = "\u21D5", // ⇕ + [9248] = "\u2195", // ↕ + [9251] = "\u03F1", // ϱ + [9257] = "\u03C2", // ς + [9266] = "\u228A\uFE00", // ⊊︀ + [9268] = "\u2ACB\uFE00", // ⫋︀ + [9276] = "\u228B\uFE00", // ⊋︀ + [9278] = "\u2ACC\uFE00", // ⫌︀ + [9284] = "\u03D1", // ϑ + [9296] = "\u22B2", // ⊲ + [9302] = "\u22B3", // ⊳ + [9307] = "\u2AEB", // ⫫ + [9311] = "\u2AE8", // ⫨ + [9313] = "\u2AE9", // ⫩ + [9316] = "\u0412", // В + [9319] = "\u0432", // в + [9324] = "\u22AB", // ⊫ + [9329] = "\u22A9", // ⊩ + [9334] = "\u22A8", // ⊨ + [9339] = "\u22A2", // ⊢ + [9341] = "\u2AE6", // ⫦ + [9344] = "\u22C1", // ⋁ + [9347] = "\u2228", // ∨ + [9351] = "\u22BB", // ⊻ + [9354] = "\u225A", // ≚ + [9359] = "\u22EE", // ⋮ + [9364] = "\u2016", // ‖ + [9369] = "\u007C", // | + [9371] = "\u2016", // ‖ + [9373] = "\u007C", // | + [9381] = "\u2223", // ∣ + [9386] = "\u007C", // | + [9396] = "\u2758", // ❘ + [9402] = "\u2240", // ≀ + [9413] = "\u200A", //   + [9416] = "\uD835\uDD19", // 𝔙 + [9419] = "\uD835\uDD33", // 𝔳 + [9424] = "\u22B2", // ⊲ + [9429] = "\u2282\u20D2", // ⊂⃒ + [9431] = "\u2283\u20D2", // ⊃⃒ + [9435] = "\uD835\uDD4D", // 𝕍 + [9439] = "\uD835\uDD67", // 𝕧 + [9444] = "\u221D", // ∝ + [9449] = "\u22B3", // ⊳ + [9453] = "\uD835\uDCB1", // 𝒱 + [9457] = "\uD835\uDCCB", // 𝓋 + [9462] = "\u2ACB\uFE00", // ⫋︀ + [9464] = "\u228A\uFE00", // ⊊︀ + [9468] = "\u2ACC\uFE00", // ⫌︀ + [9470] = "\u228B\uFE00", // ⊋︀ + [9476] = "\u22AA", // ⊪ + [9483] = "\u299A", // ⦚ + [9489] = "\u0174", // Ŵ + [9495] = "\u0175", // ŵ + [9501] = "\u2A5F", // ⩟ + [9506] = "\u22C0", // ⋀ + [9509] = "\u2227", // ∧ + [9511] = "\u2259", // ≙ + [9516] = "\u2118", // ℘ + [9519] = "\uD835\uDD1A", // 𝔚 + [9522] = "\uD835\uDD34", // 𝔴 + [9526] = "\uD835\uDD4E", // 𝕎 + [9530] = "\uD835\uDD68", // 𝕨 + [9532] = "\u2118", // ℘ + [9534] = "\u2240", // ≀ + [9539] = "\u2240", // ≀ + [9543] = "\uD835\uDCB2", // 𝒲 + [9547] = "\uD835\uDCCC", // 𝓌 + [9552] = "\u22C2", // ⋂ + [9556] = "\u25EF", // ◯ + [9559] = "\u22C3", // ⋃ + [9564] = "\u25BD", // ▽ + [9568] = "\uD835\uDD1B", // 𝔛 + [9571] = "\uD835\uDD35", // 𝔵 + [9576] = "\u27FA", // ⟺ + [9580] = "\u27F7", // ⟷ + [9582] = "\u039E", // Ξ + [9584] = "\u03BE", // ξ + [9589] = "\u27F8", // ⟸ + [9593] = "\u27F5", // ⟵ + [9597] = "\u27FC", // ⟼ + [9601] = "\u22FB", // ⋻ + [9606] = "\u2A00", // ⨀ + [9610] = "\uD835\uDD4F", // 𝕏 + [9613] = "\uD835\uDD69", // 𝕩 + [9617] = "\u2A01", // ⨁ + [9622] = "\u2A02", // ⨂ + [9627] = "\u27F9", // ⟹ + [9631] = "\u27F6", // ⟶ + [9635] = "\uD835\uDCB3", // 𝒳 + [9639] = "\uD835\uDCCD", // 𝓍 + [9644] = "\u2A06", // ⨆ + [9650] = "\u2A04", // ⨄ + [9654] = "\u25B3", // △ + [9658] = "\u22C1", // ⋁ + [9664] = "\u22C0", // ⋀ + [9670] = "\u00DD", // Ý + [9671] = "\u00DD", // Ý + [9677] = "\u00FD", // ý + [9678] = "\u00FD", // ý + [9682] = "\u042F", // Я + [9684] = "\u044F", // я + [9689] = "\u0176", // Ŷ + [9694] = "\u0177", // ŷ + [9696] = "\u042B", // Ы + [9698] = "\u044B", // ы + [9700] = "\u00A5", // ¥ + [9701] = "\u00A5", // ¥ + [9704] = "\uD835\uDD1C", // 𝔜 + [9707] = "\uD835\uDD36", // 𝔶 + [9711] = "\u0407", // Ї + [9715] = "\u0457", // ї + [9719] = "\uD835\uDD50", // 𝕐 + [9723] = "\uD835\uDD6A", // 𝕪 + [9727] = "\uD835\uDCB4", // 𝒴 + [9731] = "\uD835\uDCCE", // 𝓎 + [9735] = "\u042E", // Ю + [9739] = "\u044E", // ю + [9743] = "\u0178", // Ÿ + [9745] = "\u00FF", // ÿ + [9746] = "\u00FF", // ÿ + [9753] = "\u0179", // Ź + [9760] = "\u017A", // ź + [9766] = "\u017D", // Ž + [9772] = "\u017E", // ž + [9774] = "\u0417", // З + [9776] = "\u0437", // з + [9780] = "\u017B", // Ż + [9784] = "\u017C", // ż + [9790] = "\u2128", // ℨ + [9804] = "\u200B", // ​ + [9807] = "\u0396", // Ζ + [9810] = "\u03B6", // ζ + [9813] = "\u2128", // ℨ + [9816] = "\uD835\uDD37", // 𝔷 + [9820] = "\u0416", // Ж + [9824] = "\u0436", // ж + [9831] = "\u21DD", // ⇝ + [9835] = "\u2124", // ℤ + [9839] = "\uD835\uDD6B", // 𝕫 + [9843] = "\uD835\uDCB5", // 𝒵 + [9847] = "\uD835\uDCCF", // 𝓏 + [9850] = "\u200D", // ‍ + [9853] = "\u200C", // ‌ + }; + } + + static int BinarySearchNextState (Transition[] transitions, int state) + { + int min = 0, max = transitions.Length; + + do { + int i = min + ((max - min) / 2); + + if (state > transitions[i].From) { + min = i + 1; + } else if (state < transitions[i].From) { + max = i; + } else { + return transitions[i].To; + } + } while (min < max); + + return -1; + } bool PushNamedEntity (char c) { - int state = states[index - 1]; + int next, state = states[index - 1]; + Transition[] table = null; switch (c) { - case '1': - switch (state) { - case 436: state = 437; break; // &blk -> &blk1 - case 1791: state = 1792; break; // &emsp -> &emsp1 - case 2085: state = 2086; break; // &frac -> &frac1 - case 6500: state = 6501; break; // &sup -> ¹ - default: return false; - } - break; - case '2': - switch (state) { - case 437: state = 438; break; // &blk1 -> &blk12 - case 2085: state = 2093; break; // &frac -> &frac2 - case 2086: state = 2087; break; // &frac1 -> ½ - case 6500: state = 6502; break; // &sup -> ² - default: return false; - } - break; - case '3': - switch (state) { - case 436: state = 440; break; // &blk -> &blk3 - case 1792: state = 1793; break; // &emsp1 -> &emsp13 - case 2085: state = 2096; break; // &frac -> &frac3 - case 2086: state = 2088; break; // &frac1 -> &frac13 - case 2093: state = 2094; break; // &frac2 -> &frac23 - case 6500: state = 6503; break; // &sup -> ³ - default: return false; - } - break; - case '4': - switch (state) { - case 437: state = 439; break; // &blk1 -> &blk14 - case 440: state = 441; break; // &blk3 -> &blk34 - case 1792: state = 1794; break; // &emsp1 -> &emsp14 - case 2085: state = 2100; break; // &frac -> &frac4 - case 2086: state = 2089; break; // &frac1 -> ¼ - case 2096: state = 2097; break; // &frac3 -> ¾ - case 6632: state = 6633; break; // &there -> &there4 - default: return false; - } - break; - case '5': - switch (state) { - case 2085: state = 2102; break; // &frac -> &frac5 - case 2086: state = 2090; break; // &frac1 -> &frac15 - case 2093: state = 2095; break; // &frac2 -> &frac25 - case 2096: state = 2098; break; // &frac3 -> &frac35 - case 2100: state = 2101; break; // &frac4 -> &frac45 - default: return false; - } - break; - case '6': - switch (state) { - case 2086: state = 2091; break; // &frac1 -> &frac16 - case 2102: state = 2103; break; // &frac5 -> &frac56 - default: return false; - } - break; - case '7': - switch (state) { - case 2085: state = 2105; break; // &frac -> &frac7 - default: return false; - } - break; - case '8': - switch (state) { - case 2086: state = 2092; break; // &frac1 -> &frac18 - case 2096: state = 2099; break; // &frac3 -> &frac38 - case 2102: state = 2104; break; // &frac5 -> &frac58 - case 2105: state = 2106; break; // &frac7 -> &frac78 - default: return false; - } - break; - case 'A': - switch (state) { - case 0: state = 1; break; // & -> &A - case 1097: state = 1109; break; // &d -> &dA - case 1200: state = 1201; break; // &Diacritical -> &DiacriticalA - case 1212: state = 1213; break; // &DiacriticalDouble -> &DiacriticalDoubleA - case 1366: state = 1367; break; // &DoubleDown -> &DoubleDownA - case 1375: state = 1376; break; // &DoubleLeft -> &DoubleLeftA - case 1385: state = 1386; break; // &DoubleLeftRight -> &DoubleLeftRightA - case 1400: state = 1401; break; // &DoubleLongLeft -> &DoubleLongLeftA - case 1410: state = 1411; break; // &DoubleLongLeftRight -> &DoubleLongLeftRightA - case 1420: state = 1421; break; // &DoubleLongRight -> &DoubleLongRightA - case 1430: state = 1431; break; // &DoubleRight -> &DoubleRightA - case 1440: state = 1441; break; // &DoubleUp -> &DoubleUpA - case 1449: state = 1450; break; // &DoubleUpDown -> &DoubleUpDownA - case 1467: state = 1468; break; // &Down -> &DownA - case 1489: state = 1490; break; // &DownArrowUp -> &DownArrowUpA - case 1584: state = 1585; break; // &DownTee -> &DownTeeA - case 2058: state = 2059; break; // &For -> &ForA - case 2351: state = 2368; break; // &H -> &HA - case 2356: state = 2377; break; // &h -> &hA - case 2881: state = 2882; break; // &l -> &lA - case 3035: state = 3036; break; // &Left -> &LeftA - case 3071: state = 3072; break; // &LeftArrowRight -> &LeftArrowRightA - case 3153: state = 3154; break; // &LeftRight -> &LeftRightA - case 3206: state = 3207; break; // &LeftTee -> &LeftTeeA - case 3481: state = 3482; break; // &LongLeft -> &LongLeftA - case 3511: state = 3512; break; // &LongLeftRight -> &LongLeftRightA - case 3547: state = 3548; break; // &LongRight -> &LongRightA - case 3616: state = 3617; break; // &LowerLeft -> &LowerLeftA - case 3626: state = 3627; break; // &LowerRight -> &LowerRightA - case 3970: state = 3975; break; // &ne -> &neA - case 4101: state = 4102; break; // &nh -> &nhA - case 4121: state = 4122; break; // &nl -> &nlA - case 4621: state = 4622; break; // &nr -> &nrA - case 4792: state = 4793; break; // &nvl -> &nvlA - case 4801: state = 4802; break; // &nvr -> &nvrA - case 4812: state = 4817; break; // &nw -> &nwA - case 5397: state = 5398; break; // &r -> &rA - case 5620: state = 5621; break; // &Right -> &RightA - case 5657: state = 5658; break; // &RightArrowLeft -> &RightArrowLeftA - case 5766: state = 5767; break; // &RightTee -> &RightTeeA - case 6053: state = 6058; break; // &se -> &seA - case 6111: state = 6112; break; // &ShortDown -> &ShortDownA - case 6120: state = 6121; break; // &ShortLeft -> &ShortLeftA - case 6144: state = 6145; break; // &ShortRight -> &ShortRightA - case 6151: state = 6152; break; // &ShortUp -> &ShortUpA - case 6564: state = 6569; break; // &sw -> &swA - case 6756: state = 6757; break; // &TR -> &TRA - case 6879: state = 6887; break; // &u -> &uA - case 7031: state = 7032; break; // &Up -> &UpA - case 7054: state = 7055; break; // &UpArrowDown -> &UpArrowDownA - case 7063: state = 7064; break; // &UpDown -> &UpDownA - case 7123: state = 7124; break; // &UpperLeft -> &UpperLeftA - case 7133: state = 7134; break; // &UpperRight -> &UpperRightA - case 7152: state = 7153; break; // &UpTee -> &UpTeeA - case 7223: state = 7258; break; // &v -> &vA - case 7513: state = 7514; break; // &xh -> &xhA - case 7522: state = 7523; break; // &xl -> &xlA - case 7551: state = 7552; break; // &xr -> &xrA - case 7584: state = 7596; break; // &Y -> &YA - default: return false; - } - break; - case 'B': - switch (state) { - case 0: state = 247; break; // & -> &B - case 1462: state = 1463; break; // &DoubleVertical -> &DoubleVerticalB - case 1467: state = 1495; break; // &Down -> &DownB - case 1472: state = 1485; break; // &DownArrow -> &DownArrowB - case 1555: state = 1556; break; // &DownLeftVector -> &DownLeftVectorB - case 1578: state = 1579; break; // &DownRightVector -> &DownRightVectorB - case 2881: state = 2966; break; // &l -> &lB - case 3040: state = 3041; break; // &LeftAngle -> &LeftAngleB - case 3051: state = 3064; break; // &LeftArrow -> &LeftArrowB - case 3093: state = 3094; break; // &LeftDouble -> &LeftDoubleB - case 3117: state = 3118; break; // &LeftDownVector -> &LeftDownVectorB - case 3234: state = 3235; break; // &LeftTriangle -> &LeftTriangleB - case 3269: state = 3270; break; // &LeftUpVector -> &LeftUpVectorB - case 3278: state = 3279; break; // &LeftVector -> &LeftVectorB - case 4190: state = 4191; break; // &No -> &NoB - case 4196: state = 4197; break; // &Non -> &NonB - case 4244: state = 4245; break; // &NotDoubleVertical -> &NotDoubleVerticalB - case 4354: state = 4355; break; // &NotLeftTriangle -> &NotLeftTriangleB - case 4478: state = 4479; break; // &NotRightTriangle -> &NotRightTriangleB - case 4593: state = 4594; break; // &NotVertical -> &NotVerticalB - case 5061: state = 5062; break; // &Over -> &OverB - case 5397: state = 5480; break; // &r -> &rB - case 5405: state = 5476; break; // &R -> &RB - case 5625: state = 5626; break; // &RightAngle -> &RightAngleB - case 5636: state = 5651; break; // &RightArrow -> &RightArrowB - case 5679: state = 5680; break; // &RightDouble -> &RightDoubleB - case 5703: state = 5704; break; // &RightDownVector -> &RightDownVectorB - case 5794: state = 5795; break; // &RightTriangle -> &RightTriangleB - case 5829: state = 5830; break; // &RightUpVector -> &RightUpVectorB - case 5838: state = 5839; break; // &RightVector -> &RightVectorB - case 6990: state = 6991; break; // &Under -> &UnderB - case 7036: state = 7048; break; // &UpArrow -> &UpArrowB - case 7223: state = 7311; break; // &v -> &vB - case 7362: state = 7363; break; // &Vertical -> &VerticalB - default: return false; - } - break; - case 'C': - switch (state) { - case 0: state = 583; break; // & -> &C - case 810: state = 811; break; // &Clockwise -> &ClockwiseC - case 827: state = 828; break; // &Close -> &CloseC - case 936: state = 937; break; // &Counter -> &CounterC - case 945: state = 946; break; // &CounterClockwise -> &CounterClockwiseC - case 1005: state = 1012; break; // &Cup -> &CupC - case 1346: state = 1347; break; // &Double -> &DoubleC - case 2699: state = 2700; break; // &Invisible -> &InvisibleC - case 3035: state = 3081; break; // &Left -> &LeftC - case 4215: state = 4217; break; // &Not -> &NotC - case 4227: state = 4228; break; // &NotCup -> &NotCupC - case 4962: state = 4963; break; // &Open -> &OpenC - case 5620: state = 5667; break; // &Right -> &RightC - case 6092: state = 6093; break; // &SH -> &SHC - case 6195: state = 6196; break; // &Small -> &SmallC - default: return false; - } - break; - case 'D': - switch (state) { - case 0: state = 1091; break; // & -> &D - case 470: state = 474; break; // &box -> &boxD - case 484: state = 486; break; // &boxH -> &boxHD - case 485: state = 488; break; // &boxh -> &boxhD - case 616: state = 617; break; // &Capital -> &CapitalD - case 628: state = 629; break; // &CapitalDifferential -> &CapitalDifferentialD - case 703: state = 704; break; // &Center -> &CenterD - case 769: state = 770; break; // &Circle -> &CircleD - case 832: state = 833; break; // &CloseCurly -> &CloseCurlyD - case 1091: state = 1141; break; // &D -> &DD - case 1200: state = 1206; break; // &Diacritical -> &DiacriticalD - case 1253: state = 1254; break; // &Differential -> &DifferentialD - case 1301: state = 1303; break; // &Dot -> &DotD - case 1346: state = 1362; break; // &Double -> &DoubleD - case 1440: state = 1446; break; // &DoubleUp -> &DoubleUpD - case 1662: state = 1694; break; // &e -> &eD - case 1694: state = 1695; break; // &eD -> &eDD - case 1707: state = 1708; break; // &ef -> &efD - case 1881: state = 1882; break; // &equiv -> &equivD - case 1882: state = 1883; break; // &equivD -> &equivDD - case 1890: state = 1894; break; // &er -> &erD - case 2369: state = 2370; break; // &HAR -> &HARD - case 2510: state = 2511; break; // &Hump -> &HumpD - case 3035: state = 3088; break; // &Left -> &LeftD - case 3244: state = 3245; break; // &LeftUp -> &LeftUpD - case 3745: state = 3788; break; // &m -> &mD - case 3788: state = 3789; break; // &mD -> &mDD - case 4215: state = 4231; break; // &Not -> &NotD - case 4319: state = 4320; break; // &NotHump -> &NotHumpD - case 4760: state = 4772; break; // &nv -> &nvD - case 4763: state = 4764; break; // &nV -> &nVD - case 4967: state = 4968; break; // &OpenCurly -> &OpenCurlyD - case 5102: state = 5103; break; // &Partial -> &PartialD - case 5620: state = 5674; break; // &Right -> &RightD - case 5804: state = 5805; break; // &RightUp -> &RightUpD - case 5970: state = 5971; break; // &Rule -> &RuleD - case 6107: state = 6108; break; // &Short -> &ShortD - case 6757: state = 6758; break; // &TRA -> &TRAD - case 6801: state = 6802; break; // &Triple -> &TripleD - case 7031: state = 7060; break; // &Up -> &UpD - case 7036: state = 7051; break; // &UpArrow -> &UpArrowD - case 7223: state = 7327; break; // &v -> &vD - case 7307: state = 7319; break; // &V -> &VD - default: return false; - } - break; - case 'E': - switch (state) { - case 0: state = 1656; break; // & -> &E - case 1: state = 38; break; // &A -> &AE - case 23: state = 25; break; // &ac -> &acE - case 143: state = 148; break; // &ap -> &apE - case 574: state = 575; break; // &bump -> &bumpE - case 733: state = 789; break; // &cir -> &cirE - case 1301: state = 1311; break; // &Dot -> &DotE - case 1953: state = 1954; break; // &Exponential -> &ExponentialE - case 2118: state = 2165; break; // &g -> &gE - case 2204: state = 2206; break; // &gl -> &glE - case 2208: state = 2215; break; // &gn -> &gnE - case 2237: state = 2238; break; // &Greater -> &GreaterE - case 2250: state = 2251; break; // &GreaterFull -> &GreaterFullE - case 2271: state = 2272; break; // &GreaterSlant -> &GreaterSlantE - case 2349: state = 2350; break; // &gvn -> &gvnE - case 2510: state = 2519; break; // &Hump -> &HumpE - case 2533: state = 2558; break; // &I -> &IE - case 2747: state = 2751; break; // &isin -> &isinE - case 2881: state = 3031; break; // &l -> &lE - case 3234: state = 3238; break; // &LeftTriangle -> &LeftTriangleE - case 3322: state = 3323; break; // &Less -> &LessE - case 3338: state = 3339; break; // &LessFull -> &LessFullE - case 3365: state = 3366; break; // &LessSlant -> &LessSlantE - case 3388: state = 3389; break; // &lg -> &lgE - case 3452: state = 3459; break; // &ln -> &lnE - case 3743: state = 3744; break; // &lvn -> &lvnE - case 3914: state = 3915; break; // &nap -> &napE - case 4081: state = 4082; break; // &ng -> &ngE - case 4121: state = 4130; break; // &nl -> &nlE - case 4215: state = 4248; break; // &Not -> &NotE - case 4275: state = 4276; break; // &NotGreater -> &NotGreaterE - case 4284: state = 4285; break; // &NotGreaterFull -> &NotGreaterFullE - case 4305: state = 4306; break; // &NotGreaterSlant -> &NotGreaterSlantE - case 4319: state = 4328; break; // &NotHump -> &NotHumpE - case 4334: state = 4338; break; // ¬in -> ¬inE - case 4354: state = 4358; break; // &NotLeftTriangle -> &NotLeftTriangleE - case 4364: state = 4365; break; // &NotLess -> &NotLessE - case 4385: state = 4386; break; // &NotLessSlant -> &NotLessSlantE - case 4437: state = 4438; break; // &NotPrecedes -> &NotPrecedesE - case 4447: state = 4448; break; // &NotPrecedesSlant -> &NotPrecedesSlantE - case 4459: state = 4460; break; // &NotReverse -> &NotReverseE - case 4478: state = 4482; break; // &NotRightTriangle -> &NotRightTriangleE - case 4498: state = 4499; break; // &NotSquareSubset -> &NotSquareSubsetE - case 4509: state = 4510; break; // &NotSquareSuperset -> &NotSquareSupersetE - case 4519: state = 4520; break; // &NotSubset -> &NotSubsetE - case 4530: state = 4531; break; // &NotSucceeds -> &NotSucceedsE - case 4540: state = 4541; break; // &NotSucceedsSlant -> &NotSucceedsSlantE - case 4556: state = 4557; break; // &NotSuperset -> &NotSupersetE - case 4566: state = 4567; break; // &NotTilde -> &NotTildeE - case 4575: state = 4576; break; // &NotTildeFull -> &NotTildeFullE - case 4696: state = 4697; break; // &nsub -> &nsubE - case 4709: state = 4710; break; // &nsup -> &nsupE - case 4827: state = 4872; break; // &O -> &OE - case 5216: state = 5222; break; // &pr -> &prE - case 5243: state = 5244; break; // &Precedes -> &PrecedesE - case 5253: state = 5254; break; // &PrecedesSlant -> &PrecedesSlantE - case 5289: state = 5292; break; // &prn -> &prnE - case 5405: state = 5554; break; // &R -> &RE - case 5561: state = 5562; break; // &Reverse -> &ReverseE - case 5580: state = 5581; break; // &ReverseUp -> &ReverseUpE - case 5794: state = 5798; break; // &RightTriangle -> &RightTriangleE - case 6002: state = 6015; break; // &sc -> &scE - case 6030: state = 6033; break; // &scn -> &scnE - case 6174: state = 6175; break; // &simg -> &simgE - case 6176: state = 6177; break; // &siml -> &simlE - case 6310: state = 6311; break; // &SquareSubset -> &SquareSubsetE - case 6321: state = 6322; break; // &SquareSuperset -> &SquareSupersetE - case 6384: state = 6388; break; // &sub -> &subE - case 6397: state = 6398; break; // &subn -> &subnE - case 6410: state = 6417; break; // &Subset -> &SubsetE - case 6451: state = 6452; break; // &Succeeds -> &SucceedsE - case 6461: state = 6462; break; // &SucceedsSlant -> &SucceedsSlantE - case 6500: state = 6510; break; // &sup -> &supE - case 6519: state = 6520; break; // &Superset -> &SupersetE - case 6539: state = 6540; break; // &supn -> &supnE - case 6699: state = 6704; break; // &Tilde -> &TildeE - case 6712: state = 6713; break; // &TildeFull -> &TildeFullE - case 6758: state = 6759; break; // &TRAD -> &TRADE - case 7031: state = 7087; break; // &Up -> &UpE - case 7429: state = 7430; break; // &vsubn -> &vsubnE - case 7433: state = 7434; break; // &vsupn -> &vsupnE - default: return false; - } - break; - case 'F': - switch (state) { - case 0: state = 1977; break; // & -> &F - case 157: state = 158; break; // &Apply -> &ApplyF - case 2237: state = 2247; break; // &Greater -> &GreaterF - case 3035: state = 3121; break; // &Left -> &LeftF - case 3322: state = 3335; break; // &Less -> &LessF - case 4275: state = 4281; break; // &NotGreater -> &NotGreaterF - case 4566: state = 4572; break; // &NotTilde -> &NotTildeF - case 5620: state = 5707; break; // &Right -> &RightF - case 6230: state = 6231; break; // &SO -> &SOF - case 6699: state = 6709; break; // &Tilde -> &TildeF - default: return false; - } - break; - case 'G': - switch (state) { - case 0: state = 2124; break; // & -> &G - case 1200: state = 1218; break; // &Diacritical -> &DiacriticalG - case 1795: state = 1796; break; // &EN -> &ENG - case 2237: state = 2256; break; // &Greater -> &GreaterG - case 3322: state = 3344; break; // &Less -> &LessG - case 3327: state = 3328; break; // &LessEqual -> &LessEqualG - case 3897: state = 4092; break; // &n -> &nG - case 4044: state = 4045; break; // &Nested -> &NestedG - case 4051: state = 4052; break; // &NestedGreater -> &NestedGreaterG - case 4215: state = 4269; break; // &Not -> &NotG - case 4275: state = 4290; break; // &NotGreater -> &NotGreaterG - case 4364: state = 4370; break; // &NotLess -> &NotLessG - case 4401: state = 4402; break; // &NotNested -> &NotNestedG - case 4408: state = 4409; break; // &NotNestedGreater -> &NotNestedGreaterG - case 5554: state = 5555; break; // &RE -> ® - default: return false; - } - break; - case 'H': - switch (state) { - case 0: state = 2351; break; // & -> &H - case 470: state = 484; break; // &box -> &boxH - case 518: state = 520; break; // &boxV -> &boxVH - case 519: state = 522; break; // &boxv -> &boxvH - case 583: state = 716; break; // &C -> &CH - case 1097: state = 1183; break; // &d -> &dH - case 1914: state = 1915; break; // &ET -> Ð - case 2514: state = 2515; break; // &HumpDown -> &HumpDownH - case 2825: state = 2857; break; // &K -> &KH - case 2881: state = 3390; break; // &l -> &lH - case 4215: state = 4316; break; // &Not -> &NotH - case 4323: state = 4324; break; // &NotHumpDown -> &NotHumpDownH - case 4760: state = 4783; break; // &nv -> &nvH - case 5397: state = 5604; break; // &r -> &rH - case 5985: state = 6092; break; // &S -> &SH - case 6093: state = 6094; break; // &SHC -> &SHCH - case 6583: state = 6689; break; // &T -> &TH - case 6827: state = 6831; break; // &TS -> &TSH - case 6879: state = 6954; break; // &u -> &uH - case 7645: state = 7701; break; // &Z -> &ZH - default: return false; - } - break; - case 'I': - switch (state) { - case 0: state = 2533; break; // & -> &I - case 817: state = 818; break; // &ClockwiseContour -> &ClockwiseContourI - case 904: state = 905; break; // &Contour -> &ContourI - case 952: state = 953; break; // &CounterClockwiseContour -> &CounterClockwiseContourI - case 1353: state = 1354; break; // &DoubleContour -> &DoubleContourI - case 2619: state = 2620; break; // &Imaginary -> &ImaginaryI - case 5901: state = 5902; break; // &Round -> &RoundI - case 6289: state = 6293; break; // &Square -> &SquareI - case 7584: state = 7616; break; // &Y -> &YI - default: return false; - } - break; - case 'J': - switch (state) { - case 0: state = 2777; break; // & -> &J - case 1091: state = 1277; break; // &D -> &DJ - case 2124: state = 2198; break; // &G -> &GJ - case 2533: state = 2596; break; // &I -> &IJ - case 2825: state = 2863; break; // &K -> &KJ - case 2886: state = 3402; break; // &L -> &LJ - case 3902: state = 4115; break; // &N -> &NJ - default: return false; - } - break; - case 'K': - switch (state) { - case 0: state = 2825; break; // & -> &K - default: return false; - } - break; - case 'L': - switch (state) { - case 0: state = 2886; break; // & -> &L - case 474: state = 475; break; // &boxD -> &boxDL - case 477: state = 478; break; // &boxd -> &boxdL - case 508: state = 509; break; // &boxU -> &boxUL - case 511: state = 512; break; // &boxu -> &boxuL - case 518: state = 524; break; // &boxV -> &boxVL - case 519: state = 526; break; // &boxv -> &boxvL - case 1346: state = 1372; break; // &Double -> &DoubleL - case 1396: state = 1397; break; // &DoubleLong -> &DoubleLongL - case 1467: state = 1526; break; // &Down -> &DownL - case 2237: state = 2263; break; // &Greater -> &GreaterL - case 2242: state = 2243; break; // &GreaterEqual -> &GreaterEqualL - case 2485: state = 2486; break; // &Horizontal -> &HorizontalL - case 3322: state = 3354; break; // &Less -> &LessL - case 3477: state = 3478; break; // &Long -> &LongL - case 3612: state = 3613; break; // &Lower -> &LowerL - case 3897: state = 4132; break; // &n -> &nL - case 4044: state = 4059; break; // &Nested -> &NestedL - case 4062: state = 4063; break; // &NestedLess -> &NestedLessL - case 4067: state = 4068; break; // &New -> &NewL - case 4215: state = 4343; break; // &Not -> &NotL - case 4275: state = 4297; break; // &NotGreater -> &NotGreaterL - case 4364: state = 4377; break; // &NotLess -> &NotLessL - case 4401: state = 4416; break; // &NotNested -> &NotNestedL - case 4419: state = 4420; break; // &NotNestedLess -> &NotNestedLessL - case 5636: state = 5654; break; // &RightArrow -> &RightArrowL - case 6107: state = 6117; break; // &Short -> &ShortL - case 7119: state = 7120; break; // &Upper -> &UpperL - case 7362: state = 7366; break; // &Vertical -> &VerticalL - default: return false; - } - break; - case 'M': - switch (state) { - case 0: state = 3755; break; // & -> &M - case 1: state = 85; break; // &A -> &AM - case 769: state = 775; break; // &Circle -> &CircleM - case 3990: state = 3991; break; // &Negative -> &NegativeM - case 5174: state = 5175; break; // &Plus -> &PlusM - default: return false; - } - break; - case 'N': - switch (state) { - case 0: state = 3902; break; // & -> &N - case 222: state = 451; break; // &b -> &bN - case 1656: state = 1795; break; // &E -> &EN - case 4215: state = 4396; break; // &Not -> &NotN - case 6691: state = 6692; break; // &THOR -> Þ - default: return false; - } - break; - case 'O': - switch (state) { - case 0: state = 4827; break; // & -> &O - case 583: state = 926; break; // &C -> &CO - case 2533: state = 2710; break; // &I -> &IO - case 5392: state = 5393; break; // &QU -> &QUO - case 5985: state = 6230; break; // &S -> &SO - case 6689: state = 6690; break; // &TH -> &THO - default: return false; - } - break; - case 'P': - switch (state) { - case 0: state = 5096; break; // & -> &P - case 85: state = 86; break; // &AM -> & - case 769: state = 780; break; // &Circle -> &CircleP - case 926: state = 927; break; // &CO -> &COP - case 2302: state = 2303; break; // >l -> >lP - case 3717: state = 3721; break; // <r -> <rP - case 3850: state = 3851; break; // &Minus -> &MinusP - case 4215: state = 4430; break; // &Not -> &NotP - case 5061: state = 5072; break; // &Over -> &OverP - case 6990: state = 7001; break; // &Under -> &UnderP - case 7014: state = 7015; break; // &Union -> &UnionP - default: return false; - } - break; - case 'Q': - switch (state) { - case 0: state = 5348; break; // & -> &Q - case 832: state = 844; break; // &CloseCurly -> &CloseCurlyQ - case 838: state = 839; break; // &CloseCurlyDouble -> &CloseCurlyDoubleQ - case 4967: state = 4979; break; // &OpenCurly -> &OpenCurlyQ - case 4973: state = 4974; break; // &OpenCurlyDouble -> &OpenCurlyDoubleQ - default: return false; - } - break; - case 'R': - switch (state) { - case 0: state = 5405; break; // & -> &R - case 474: state = 480; break; // &boxD -> &boxDR - case 477: state = 482; break; // &boxd -> &boxdR - case 508: state = 514; break; // &boxU -> &boxUR - case 511: state = 516; break; // &boxu -> &boxuR - case 518: state = 528; break; // &boxV -> &boxVR - case 519: state = 530; break; // &boxv -> &boxvR - case 753: state = 773; break; // &circled -> &circledR - case 1346: state = 1426; break; // &Double -> &DoubleR - case 1375: state = 1381; break; // &DoubleLeft -> &DoubleLeftR - case 1396: state = 1416; break; // &DoubleLong -> &DoubleLongR - case 1400: state = 1406; break; // &DoubleLongLeft -> &DoubleLongLeftR - case 1467: state = 1559; break; // &Down -> &DownR - case 1529: state = 1530; break; // &DownLeft -> &DownLeftR - case 2368: state = 2369; break; // &HA -> &HAR - case 3035: state = 3149; break; // &Left -> &LeftR - case 3051: state = 3067; break; // &LeftArrow -> &LeftArrowR - case 3477: state = 3543; break; // &Long -> &LongR - case 3481: state = 3507; break; // &LongLeft -> &LongLeftR - case 3612: state = 3622; break; // &Lower -> &LowerR - case 3897: state = 4630; break; // &n -> &nR - case 4215: state = 4453; break; // &Not -> &NotR - case 6107: state = 6140; break; // &Short -> &ShortR - case 6583: state = 6756; break; // &T -> &TR - case 6690: state = 6691; break; // &THO -> &THOR - case 7119: state = 7129; break; // &Upper -> &UpperR - default: return false; - } - break; - case 'S': - switch (state) { - case 0: state = 5985; break; // & -> &S - case 753: state = 774; break; // &circled -> &circledS - case 1091: state = 1610; break; // &D -> &DS - case 1762: state = 1763; break; // &Empty -> &EmptyS - case 1767: state = 1768; break; // &EmptySmall -> &EmptySmallS - case 1778: state = 1779; break; // &EmptyVery -> &EmptyVeryS - case 1783: state = 1784; break; // &EmptyVerySmall -> &EmptyVerySmallS - case 2009: state = 2010; break; // &Filled -> &FilledS - case 2014: state = 2015; break; // &FilledSmall -> &FilledSmallS - case 2024: state = 2025; break; // &FilledVery -> &FilledVeryS - case 2029: state = 2030; break; // &FilledVerySmall -> &FilledVerySmallS - case 2237: state = 2267; break; // &Greater -> &GreaterS - case 2422: state = 2423; break; // &Hilbert -> &HilbertS - case 3322: state = 3361; break; // &Less -> &LessS - case 3808: state = 3809; break; // &Medium -> &MediumS - case 3996: state = 3997; break; // &NegativeMedium -> &NegativeMediumS - case 4006: state = 4007; break; // &NegativeThick -> &NegativeThickS - case 4012: state = 4013; break; // &NegativeThin -> &NegativeThinS - case 4025: state = 4026; break; // &NegativeVeryThin -> &NegativeVeryThinS - case 4204: state = 4205; break; // &NonBreaking -> &NonBreakingS - case 4215: state = 4487; break; // &Not -> &NotS - case 4275: state = 4301; break; // &NotGreater -> &NotGreaterS - case 4364: state = 4381; break; // &NotLess -> &NotLessS - case 4437: state = 4443; break; // &NotPrecedes -> &NotPrecedesS - case 4492: state = 4493; break; // &NotSquare -> &NotSquareS - case 4530: state = 4536; break; // &NotSucceeds -> &NotSucceedsS - case 4833: state = 5014; break; // &o -> &oS - case 5243: state = 5249; break; // &Precedes -> &PrecedesS - case 6289: state = 6305; break; // &Square -> &SquareS - case 6451: state = 6457; break; // &Succeeds -> &SucceedsS - case 6583: state = 6827; break; // &T -> &TS - case 6668: state = 6669; break; // &Thick -> &ThickS - case 6677: state = 6678; break; // &Thin -> &ThinS - case 7362: state = 7370; break; // &Vertical -> &VerticalS - case 7388: state = 7389; break; // &VeryThin -> &VeryThinS - case 7687: state = 7688; break; // &ZeroWidth -> &ZeroWidthS - default: return false; - } - break; - case 'T': - switch (state) { - case 0: state = 6583; break; // & -> &T - case 769: state = 784; break; // &Circle -> &CircleT - case 1200: state = 1223; break; // &Diacritical -> &DiacriticalT - case 1375: state = 1391; break; // &DoubleLeft -> &DoubleLeftT - case 1430: state = 1436; break; // &DoubleRight -> &DoubleRightT - case 1467: state = 1582; break; // &Down -> &DownT - case 1529: state = 1541; break; // &DownLeft -> &DownLeftT - case 1563: state = 1564; break; // &DownRight -> &DownRightT - case 1656: state = 1914; break; // &E -> &ET - case 1859: state = 1864; break; // &Equal -> &EqualT - case 2124: state = 2292; break; // &G -> > - case 2237: state = 2277; break; // &Greater -> &GreaterT - case 2699: state = 2705; break; // &Invisible -> &InvisibleT - case 2886: state = 3690; break; // &L -> < - case 3035: state = 3204; break; // &Left -> &LeftT - case 3102: state = 3103; break; // &LeftDown -> &LeftDownT - case 3244: state = 3255; break; // &LeftUp -> &LeftUpT - case 3322: state = 3371; break; // &Less -> &LessT - case 3990: state = 4002; break; // &Negative -> &NegativeT - case 4021: state = 4022; break; // &NegativeVery -> &NegativeVeryT - case 4215: state = 4562; break; // &Not -> &NotT - case 4258: state = 4259; break; // &NotEqual -> &NotEqualT - case 4275: state = 4311; break; // &NotGreater -> &NotGreaterT - case 4346: state = 4347; break; // &NotLeft -> &NotLeftT - case 4364: state = 4391; break; // &NotLess -> &NotLessT - case 4470: state = 4471; break; // &NotRight -> &NotRightT - case 4530: state = 4546; break; // &NotSucceeds -> &NotSucceedsT - case 4566: state = 4581; break; // &NotTilde -> &NotTildeT - case 5243: state = 5259; break; // &Precedes -> &PrecedesT - case 5393: state = 5394; break; // &QUO -> " - case 5620: state = 5764; break; // &Right -> &RightT - case 5688: state = 5689; break; // &RightDown -> &RightDownT - case 5804: state = 5815; break; // &RightUp -> &RightUpT - case 6231: state = 6232; break; // &SOF -> &SOFT - case 6451: state = 6467; break; // &Succeeds -> &SucceedsT - case 6490: state = 6491; break; // &Such -> &SuchT - case 6699: state = 6718; break; // &Tilde -> &TildeT - case 7031: state = 7150; break; // &Up -> &UpT - case 7362: state = 7379; break; // &Vertical -> &VerticalT - case 7384: state = 7385; break; // &Very -> &VeryT - default: return false; - } - break; - case 'U': - switch (state) { - case 0: state = 6873; break; // & -> &U - case 470: state = 508; break; // &box -> &boxU - case 484: state = 490; break; // &boxH -> &boxHU - case 485: state = 492; break; // &boxh -> &boxhU - case 1346: state = 1439; break; // &Double -> &DoubleU - case 1472: state = 1488; break; // &DownArrow -> &DownArrowU - case 3035: state = 3243; break; // &Left -> &LeftU - case 5348: state = 5392; break; // &Q -> &QU - case 5561: state = 5579; break; // &Reverse -> &ReverseU - case 5620: state = 5803; break; // &Right -> &RightU - case 6107: state = 6150; break; // &Short -> &ShortU - case 6289: state = 6327; break; // &Square -> &SquareU - case 7584: state = 7634; break; // &Y -> &YU - default: return false; - } - break; - case 'V': - switch (state) { - case 0: state = 7307; break; // & -> &V - case 470: state = 518; break; // &box -> &boxV - case 1346: state = 1455; break; // &Double -> &DoubleV - case 1529: state = 1550; break; // &DownLeft -> &DownLeftV - case 1534: state = 1535; break; // &DownLeftRight -> &DownLeftRightV - case 1543: state = 1544; break; // &DownLeftTee -> &DownLeftTeeV - case 1563: state = 1573; break; // &DownRight -> &DownRightV - case 1566: state = 1567; break; // &DownRightTee -> &DownRightTeeV - case 1762: state = 1775; break; // &Empty -> &EmptyV - case 2009: state = 2021; break; // &Filled -> &FilledV - case 3035: state = 3273; break; // &Left -> &LeftV - case 3102: state = 3112; break; // &LeftDown -> &LeftDownV - case 3105: state = 3106; break; // &LeftDownTee -> &LeftDownTeeV - case 3153: state = 3198; break; // &LeftRight -> &LeftRightV - case 3206: state = 3212; break; // &LeftTee -> &LeftTeeV - case 3244: state = 3264; break; // &LeftUp -> &LeftUpV - case 3248: state = 3249; break; // &LeftUpDown -> &LeftUpDownV - case 3257: state = 3258; break; // &LeftUpTee -> &LeftUpTeeV - case 3897: state = 4763; break; // &n -> &nV - case 3990: state = 4018; break; // &Negative -> &NegativeV - case 4215: state = 4586; break; // &Not -> &NotV - case 4236: state = 4237; break; // &NotDouble -> &NotDoubleV - case 5620: state = 5833; break; // &Right -> &RightV - case 5688: state = 5698; break; // &RightDown -> &RightDownV - case 5691: state = 5692; break; // &RightDownTee -> &RightDownTeeV - case 5766: state = 5772; break; // &RightTee -> &RightTeeV - case 5804: state = 5824; break; // &RightUp -> &RightUpV - case 5808: state = 5809; break; // &RightUpDown -> &RightUpDownV - case 5817: state = 5818; break; // &RightUpTee -> &RightUpTeeV - default: return false; - } - break; - case 'W': - switch (state) { - case 0: state = 7447; break; // & -> &W - case 7682: state = 7683; break; // &Zero -> &ZeroW - default: return false; - } - break; - case 'X': - switch (state) { - case 0: state = 7508; break; // & -> &X - default: return false; - } - break; - case 'Y': - switch (state) { - case 0: state = 7584; break; // & -> &Y - case 927: state = 928; break; // &COP -> © - default: return false; - } - break; - case 'Z': - switch (state) { - case 0: state = 7645; break; // & -> &Z - case 1091: state = 1644; break; // &D -> &DZ - default: return false; - } - break; - case 'a': - switch (state) { - case 0: state = 7; break; // & -> &a - case 1: state = 2; break; // &A -> &Aa - case 7: state = 8; break; // &a -> &aa - case 51: state = 52; break; // &Agr -> &Agra - case 56: state = 57; break; // &agr -> &agra - case 70: state = 71; break; // &Alph -> &Alpha - case 73: state = 74; break; // &alph -> &alpha - case 75: state = 76; break; // &Am -> &Ama - case 79: state = 80; break; // &am -> &ama - case 91: state = 92; break; // &and -> &anda - case 108: state = 109; break; // &angmsd -> &angmsda - case 109: state = 110; break; // &angmsda -> &angmsdaa - case 127: state = 128; break; // &angz -> &angza - case 143: state = 144; break; // &ap -> &apa - case 222: state = 223; break; // &b -> &ba - case 247: state = 248; break; // &B -> &Ba - case 252: state = 253; break; // &Backsl -> &Backsla - case 289: state = 290; break; // &bec -> &beca - case 294: state = 295; break; // &Bec -> &Beca - case 320: state = 321; break; // &Bet -> &Beta - case 322: state = 323; break; // &bet -> &beta - case 335: state = 336; break; // &bigc -> &bigca - case 361: state = 362; break; // &bigst -> &bigsta - case 366: state = 367; break; // &bigtri -> &bigtria - case 391: state = 392; break; // &bk -> &bka - case 396: state = 397; break; // &bl -> &bla - case 409: state = 410; break; // &blacksqu -> &blacksqua - case 415: state = 416; break; // &blacktri -> &blacktria - case 546: state = 547; break; // &brvb -> &brvba - case 583: state = 584; break; // &C -> &Ca - case 589: state = 590; break; // &c -> &ca - case 596: state = 597; break; // &cap -> &capa - case 605: state = 606; break; // &capc -> &capca - case 614: state = 615; break; // &Capit -> &Capita - case 626: state = 627; break; // &CapitalDifferenti -> &CapitalDifferentia - case 641: state = 642; break; // &cc -> &cca - case 645: state = 646; break; // &Cc -> &Cca - case 691: state = 692; break; // &Cedill -> &Cedilla - case 725: state = 726; break; // &checkm -> &checkma - case 738: state = 739; break; // &circle -> &circlea - case 753: state = 754; break; // &circled -> &circleda - case 761: state = 762; break; // &circledd -> &circledda - case 823: state = 824; break; // &ClockwiseContourIntegr -> &ClockwiseContourIntegra - case 868: state = 869; break; // &comm -> &comma - case 910: state = 911; break; // &ContourIntegr -> &ContourIntegra - case 958: state = 959; break; // &CounterClockwiseContourIntegr -> &CounterClockwiseContourIntegra - case 961: state = 962; break; // &cr -> &cra - case 988: state = 989; break; // &cud -> &cuda - case 999: state = 1000; break; // &cul -> &cula - case 1009: state = 1010; break; // &cupbrc -> &cupbrca - case 1012: state = 1013; break; // &CupC -> &CupCa - case 1015: state = 1016; break; // &cupc -> &cupca - case 1026: state = 1027; break; // &cur -> &cura - case 1055: state = 1056; break; // &curve -> &curvea - case 1091: state = 1092; break; // &D -> &Da - case 1097: state = 1098; break; // &d -> &da - case 1121: state = 1122; break; // &dbk -> &dbka - case 1126: state = 1127; break; // &dbl -> &dbla - case 1129: state = 1130; break; // &Dc -> &Dca - case 1134: state = 1135; break; // &dc -> &dca - case 1142: state = 1143; break; // &dd -> &dda - case 1152: state = 1153; break; // &DDotr -> &DDotra - case 1165: state = 1166; break; // &Delt -> &Delta - case 1168: state = 1169; break; // &delt -> &delta - case 1183: state = 1184; break; // &dH -> &dHa - case 1186: state = 1187; break; // &dh -> &dha - case 1191: state = 1192; break; // &Di -> &Dia - case 1198: state = 1199; break; // &Diacritic -> &Diacritica - case 1219: state = 1220; break; // &DiacriticalGr -> &DiacriticalGra - case 1228: state = 1229; break; // &di -> &dia - case 1251: state = 1252; break; // &Differenti -> &Differentia - case 1255: state = 1256; break; // &dig -> &diga - case 1258: state = 1259; break; // &digamm -> &digamma - case 1293: state = 1294; break; // &doll -> &dolla - case 1313: state = 1314; break; // &DotEqu -> &DotEqua - case 1327: state = 1328; break; // &dotsqu -> &dotsqua - case 1335: state = 1336; break; // &doubleb -> &doubleba - case 1359: state = 1360; break; // &DoubleContourIntegr -> &DoubleContourIntegra - case 1460: state = 1461; break; // &DoubleVertic -> &DoubleVertica - case 1463: state = 1464; break; // &DoubleVerticalB -> &DoubleVerticalBa - case 1467: state = 1473; break; // &Down -> &Downa - case 1479: state = 1480; break; // &down -> &downa - case 1485: state = 1486; break; // &DownArrowB -> &DownArrowBa - case 1503: state = 1504; break; // &downdown -> &downdowna - case 1510: state = 1511; break; // &downh -> &downha - case 1556: state = 1557; break; // &DownLeftVectorB -> &DownLeftVectorBa - case 1579: state = 1580; break; // &DownRightVectorB -> &DownRightVectorBa - case 1592: state = 1593; break; // &drbk -> &drbka - case 1631: state = 1632; break; // &du -> &dua - case 1635: state = 1636; break; // &duh -> &duha - case 1638: state = 1639; break; // &dw -> &dwa - case 1652: state = 1653; break; // &dzigr -> &dzigra - case 1656: state = 1657; break; // &E -> &Ea - case 1662: state = 1663; break; // &e -> &ea - case 1672: state = 1673; break; // &Ec -> &Eca - case 1677: state = 1678; break; // &ec -> &eca - case 1716: state = 1717; break; // &Egr -> &Egra - case 1720: state = 1721; break; // &egr -> &egra - case 1746: state = 1747; break; // &Em -> &Ema - case 1750: state = 1751; break; // &em -> &ema - case 1764: state = 1765; break; // &EmptySm -> &EmptySma - case 1770: state = 1771; break; // &EmptySmallSqu -> &EmptySmallSqua - case 1780: state = 1781; break; // &EmptyVerySm -> &EmptyVerySma - case 1786: state = 1787; break; // &EmptyVerySmallSqu -> &EmptyVerySmallSqua - case 1813: state = 1814; break; // &ep -> &epa - case 1845: state = 1846; break; // &eqsl -> &eqsla - case 1857: state = 1858; break; // &Equ -> &Equa - case 1860: state = 1861; break; // &equ -> &equa - case 1885: state = 1886; break; // &eqvp -> &eqvpa - case 1890: state = 1891; break; // &er -> &era - case 1910: state = 1911; break; // &Et -> &Eta - case 1912: state = 1913; break; // &et -> &eta - case 1939: state = 1940; break; // &expect -> &expecta - case 1951: state = 1952; break; // &Exponenti -> &Exponentia - case 1960: state = 1961; break; // &exponenti -> &exponentia - case 1964: state = 1965; break; // &f -> &fa - case 1983: state = 1984; break; // &fem -> &fema - case 2011: state = 2012; break; // &FilledSm -> &FilledSma - case 2017: state = 2018; break; // &FilledSmallSqu -> &FilledSmallSqua - case 2026: state = 2027; break; // &FilledVerySm -> &FilledVerySma - case 2032: state = 2033; break; // &FilledVerySmallSqu -> &FilledVerySmallSqua - case 2040: state = 2041; break; // &fl -> &fla - case 2062: state = 2063; break; // &for -> &fora - case 2076: state = 2077; break; // &fp -> &fpa - case 2083: state = 2084; break; // &fr -> &fra - case 2118: state = 2119; break; // &g -> &ga - case 2124: state = 2125; break; // &G -> &Ga - case 2127: state = 2128; break; // &Gamm -> &Gamma - case 2130: state = 2131; break; // &gamm -> &gamma - case 2172: state = 2173; break; // &geqsl -> &geqsla - case 2204: state = 2205; break; // &gl -> &gla - case 2208: state = 2209; break; // &gn -> &gna - case 2228: state = 2229; break; // &gr -> &gra - case 2233: state = 2234; break; // &Gre -> &Grea - case 2240: state = 2241; break; // &GreaterEqu -> &GreaterEqua - case 2253: state = 2254; break; // &GreaterFullEqu -> &GreaterFullEqua - case 2258: state = 2259; break; // &GreaterGre -> &GreaterGrea - case 2268: state = 2269; break; // &GreaterSl -> &GreaterSla - case 2274: state = 2275; break; // &GreaterSlantEqu -> &GreaterSlantEqua - case 2303: state = 2304; break; // >lP -> >lPa - case 2311: state = 2312; break; // >r -> >ra - case 2351: state = 2352; break; // &H -> &Ha - case 2356: state = 2357; break; // &h -> &ha - case 2386: state = 2387; break; // &hb -> &hba - case 2397: state = 2398; break; // &he -> &hea - case 2424: state = 2425; break; // &HilbertSp -> &HilbertSpa - case 2430: state = 2431; break; // &hkse -> &hksea - case 2435: state = 2436; break; // &hksw -> &hkswa - case 2440: state = 2441; break; // &ho -> &hoa - case 2453: state = 2454; break; // &hookleft -> &hooklefta - case 2463: state = 2464; break; // &hookright -> &hookrighta - case 2475: state = 2476; break; // &horb -> &horba - case 2483: state = 2484; break; // &Horizont -> &Horizonta - case 2496: state = 2497; break; // &hsl -> &hsla - case 2521: state = 2522; break; // &HumpEqu -> &HumpEqua - case 2533: state = 2534; break; // &I -> &Ia - case 2539: state = 2540; break; // &i -> &ia - case 2573: state = 2574; break; // &Igr -> &Igra - case 2578: state = 2579; break; // &igr -> &igra - case 2594: state = 2595; break; // &iiot -> &iiota - case 2604: state = 2605; break; // &Im -> &Ima - case 2608: state = 2609; break; // &im -> &ima - case 2616: state = 2617; break; // &Imagin -> &Imagina - case 2625: state = 2626; break; // &imagp -> &imagpa - case 2642: state = 2643; break; // &inc -> &inca - case 2659: state = 2660; break; // &intc -> &intca - case 2669: state = 2670; break; // &Integr -> &Integra - case 2673: state = 2674; break; // &interc -> &interca - case 2684: state = 2685; break; // &intl -> &intla - case 2703: state = 2704; break; // &InvisibleComm -> &InvisibleComma - case 2727: state = 2728; break; // &Iot -> &Iota - case 2729: state = 2730; break; // &iot -> &iota - case 2793: state = 2794; break; // &jm -> &jma - case 2825: state = 2826; break; // &K -> &Ka - case 2828: state = 2829; break; // &Kapp -> &Kappa - case 2830: state = 2831; break; // &k -> &ka - case 2833: state = 2834; break; // &kapp -> &kappa - case 2881: state = 2892; break; // &l -> &la - case 2882: state = 2883; break; // &lA -> &lAa - case 2886: state = 2887; break; // &L -> &La - case 2904: state = 2905; break; // &lagr -> &lagra - case 2909: state = 2910; break; // &Lambd -> &Lambda - case 2913: state = 2914; break; // &lambd -> &lambda - case 2924: state = 2925; break; // &Lapl -> &Lapla - case 2956: state = 2961; break; // &lat -> &lata - case 2957: state = 2958; break; // &lAt -> &lAta - case 2966: state = 2967; break; // &lB -> &lBa - case 2970: state = 2971; break; // &lb -> &lba - case 2977: state = 2978; break; // &lbr -> &lbra - case 2988: state = 2989; break; // &Lc -> &Lca - case 2993: state = 2994; break; // &lc -> &lca - case 3013: state = 3014; break; // &ldc -> &ldca - case 3021: state = 3022; break; // &ldrdh -> &ldrdha - case 3026: state = 3027; break; // &ldrush -> &ldrusha - case 3035: state = 3052; break; // &Left -> &Lefta - case 3042: state = 3043; break; // &LeftAngleBr -> &LeftAngleBra - case 3058: state = 3059; break; // &left -> &lefta - case 3064: state = 3065; break; // &LeftArrowB -> &LeftArrowBa - case 3077: state = 3078; break; // &leftarrowt -> &leftarrowta - case 3095: state = 3096; break; // &LeftDoubleBr -> &LeftDoubleBra - case 3118: state = 3119; break; // &LeftDownVectorB -> &LeftDownVectorBa - case 3126: state = 3127; break; // &lefth -> &leftha - case 3142: state = 3143; break; // &leftleft -> &leftlefta - case 3163: state = 3164; break; // &Leftright -> &Leftrighta - case 3173: state = 3174; break; // &leftright -> &leftrighta - case 3180: state = 3181; break; // &leftrighth -> &leftrightha - case 3192: state = 3193; break; // &leftrightsquig -> &leftrightsquiga - case 3229: state = 3230; break; // &LeftTri -> &LeftTria - case 3235: state = 3236; break; // &LeftTriangleB -> &LeftTriangleBa - case 3240: state = 3241; break; // &LeftTriangleEqu -> &LeftTriangleEqua - case 3270: state = 3271; break; // &LeftUpVectorB -> &LeftUpVectorBa - case 3279: state = 3280; break; // &LeftVectorB -> &LeftVectorBa - case 3287: state = 3288; break; // &leqsl -> &leqsla - case 3302: state = 3303; break; // &less -> &lessa - case 3325: state = 3326; break; // &LessEqu -> &LessEqua - case 3330: state = 3331; break; // &LessEqualGre -> &LessEqualGrea - case 3341: state = 3342; break; // &LessFullEqu -> &LessFullEqua - case 3346: state = 3347; break; // &LessGre -> &LessGrea - case 3362: state = 3363; break; // &LessSl -> &LessSla - case 3368: state = 3369; break; // &LessSlantEqu -> &LessSlantEqua - case 3390: state = 3391; break; // &lH -> &lHa - case 3393: state = 3394; break; // &lh -> &lha - case 3409: state = 3410; break; // &ll -> &lla - case 3421: state = 3422; break; // &Lleft -> &Llefta - case 3427: state = 3428; break; // &llh -> &llha - case 3447: state = 3448; break; // &lmoust -> &lmousta - case 3452: state = 3453; break; // &ln -> &lna - case 3466: state = 3467; break; // &lo -> &loa - case 3490: state = 3491; break; // &Longleft -> &Longlefta - case 3501: state = 3502; break; // &longleft -> &longlefta - case 3521: state = 3522; break; // &Longleftright -> &Longleftrighta - case 3531: state = 3532; break; // &longleftright -> &longleftrighta - case 3537: state = 3538; break; // &longm -> &longma - case 3557: state = 3558; break; // &Longright -> &Longrighta - case 3567: state = 3568; break; // &longright -> &longrighta - case 3574: state = 3575; break; // &loop -> &loopa - case 3589: state = 3590; break; // &lop -> &lopa - case 3603: state = 3604; break; // &low -> &lowa - case 3607: state = 3608; break; // &lowb -> &lowba - case 3638: state = 3639; break; // &lp -> &lpa - case 3643: state = 3644; break; // &lr -> &lra - case 3653: state = 3654; break; // &lrh -> &lrha - case 3661: state = 3662; break; // &ls -> &lsa - case 3708: state = 3709; break; // <l -> <la - case 3721: state = 3722; break; // <rP -> <rPa - case 3728: state = 3729; break; // &lurdsh -> &lurdsha - case 3732: state = 3733; break; // &luruh -> &luruha - case 3745: state = 3746; break; // &m -> &ma - case 3755: state = 3756; break; // &M -> &Ma - case 3779: state = 3780; break; // &mcomm -> &mcomma - case 3784: state = 3785; break; // &md -> &mda - case 3792: state = 3793; break; // &me -> &mea - case 3798: state = 3799; break; // &measured -> &measureda - case 3810: state = 3811; break; // &MediumSp -> &MediumSpa - case 3831: state = 3832; break; // &mid -> &mida - case 3891: state = 3892; break; // &multim -> &multima - case 3894: state = 3895; break; // &mum -> &muma - case 3897: state = 3898; break; // &n -> &na - case 3900: state = 3901; break; // &nabl -> &nabla - case 3902: state = 3903; break; // &N -> &Na - case 3926: state = 3927; break; // &natur -> &natura - case 3937: state = 3938; break; // &nc -> &nca - case 3940: state = 3941; break; // &Nc -> &Nca - case 3966: state = 3967; break; // &nd -> &nda - case 3970: state = 3971; break; // &ne -> &nea - case 3985: state = 3986; break; // &Neg -> &Nega - case 3998: state = 3999; break; // &NegativeMediumSp -> &NegativeMediumSpa - case 4008: state = 4009; break; // &NegativeThickSp -> &NegativeThickSpa - case 4014: state = 4015; break; // &NegativeThinSp -> &NegativeThinSpa - case 4027: state = 4028; break; // &NegativeVeryThinSp -> &NegativeVeryThinSpa - case 4036: state = 4037; break; // &nese -> &nesea - case 4047: state = 4048; break; // &NestedGre -> &NestedGrea - case 4054: state = 4055; break; // &NestedGreaterGre -> &NestedGreaterGrea - case 4087: state = 4088; break; // &ngeqsl -> &ngeqsla - case 4101: state = 4105; break; // &nh -> &nha - case 4108: state = 4109; break; // &nhp -> &nhpa - case 4121: state = 4125; break; // &nl -> &nla - case 4135: state = 4136; break; // &nLeft -> &nLefta - case 4142: state = 4143; break; // &nleft -> &nlefta - case 4152: state = 4153; break; // &nLeftright -> &nLeftrighta - case 4162: state = 4163; break; // &nleftright -> &nleftrighta - case 4171: state = 4172; break; // &nleqsl -> &nleqsla - case 4193: state = 4194; break; // &NoBre -> &NoBrea - case 4199: state = 4200; break; // &NonBre -> &NonBrea - case 4206: state = 4207; break; // &NonBreakingSp -> &NonBreakingSpa - case 4228: state = 4229; break; // &NotCupC -> &NotCupCa - case 4242: state = 4243; break; // &NotDoubleVertic -> &NotDoubleVertica - case 4245: state = 4246; break; // &NotDoubleVerticalB -> &NotDoubleVerticalBa - case 4256: state = 4257; break; // &NotEqu -> &NotEqua - case 4271: state = 4272; break; // &NotGre -> &NotGrea - case 4278: state = 4279; break; // &NotGreaterEqu -> &NotGreaterEqua - case 4287: state = 4288; break; // &NotGreaterFullEqu -> &NotGreaterFullEqua - case 4292: state = 4293; break; // &NotGreaterGre -> &NotGreaterGrea - case 4302: state = 4303; break; // &NotGreaterSl -> &NotGreaterSla - case 4308: state = 4309; break; // &NotGreaterSlantEqu -> &NotGreaterSlantEqua - case 4330: state = 4331; break; // &NotHumpEqu -> &NotHumpEqua - case 4339: state = 4340; break; // ¬inv -> ¬inva - case 4349: state = 4350; break; // &NotLeftTri -> &NotLeftTria - case 4355: state = 4356; break; // &NotLeftTriangleB -> &NotLeftTriangleBa - case 4360: state = 4361; break; // &NotLeftTriangleEqu -> &NotLeftTriangleEqua - case 4367: state = 4368; break; // &NotLessEqu -> &NotLessEqua - case 4372: state = 4373; break; // &NotLessGre -> &NotLessGrea - case 4382: state = 4383; break; // &NotLessSl -> &NotLessSla - case 4388: state = 4389; break; // &NotLessSlantEqu -> &NotLessSlantEqua - case 4404: state = 4405; break; // &NotNestedGre -> &NotNestedGrea - case 4411: state = 4412; break; // &NotNestedGreaterGre -> &NotNestedGreaterGrea - case 4426: state = 4427; break; // ¬niv -> ¬niva - case 4440: state = 4441; break; // &NotPrecedesEqu -> &NotPrecedesEqua - case 4444: state = 4445; break; // &NotPrecedesSl -> &NotPrecedesSla - case 4450: state = 4451; break; // &NotPrecedesSlantEqu -> &NotPrecedesSlantEqua - case 4473: state = 4474; break; // &NotRightTri -> &NotRightTria - case 4479: state = 4480; break; // &NotRightTriangleB -> &NotRightTriangleBa - case 4484: state = 4485; break; // &NotRightTriangleEqu -> &NotRightTriangleEqua - case 4489: state = 4490; break; // &NotSqu -> &NotSqua - case 4501: state = 4502; break; // &NotSquareSubsetEqu -> &NotSquareSubsetEqua - case 4512: state = 4513; break; // &NotSquareSupersetEqu -> &NotSquareSupersetEqua - case 4522: state = 4523; break; // &NotSubsetEqu -> &NotSubsetEqua - case 4533: state = 4534; break; // &NotSucceedsEqu -> &NotSucceedsEqua - case 4537: state = 4538; break; // &NotSucceedsSl -> &NotSucceedsSla - case 4543: state = 4544; break; // &NotSucceedsSlantEqu -> &NotSucceedsSlantEqua - case 4559: state = 4560; break; // &NotSupersetEqu -> &NotSupersetEqua - case 4569: state = 4570; break; // &NotTildeEqu -> &NotTildeEqua - case 4578: state = 4579; break; // &NotTildeFullEqu -> &NotTildeFullEqua - case 4591: state = 4592; break; // &NotVertic -> &NotVertica - case 4594: state = 4595; break; // &NotVerticalB -> &NotVerticalBa - case 4597: state = 4598; break; // &np -> &npa - case 4599: state = 4600; break; // &npar -> &npara - case 4621: state = 4625; break; // &nr -> &nra - case 4634: state = 4635; break; // &nRight -> &nRighta - case 4643: state = 4644; break; // &nright -> &nrighta - case 4670: state = 4671; break; // &nshortp -> &nshortpa - case 4672: state = 4673; break; // &nshortpar -> &nshortpara - case 4685: state = 4686; break; // &nsp -> &nspa - case 4733: state = 4734; break; // &ntri -> &ntria - case 4760: state = 4761; break; // &nv -> &nva - case 4764: state = 4765; break; // &nVD -> &nVDa - case 4768: state = 4769; break; // &nVd -> &nVda - case 4772: state = 4773; break; // &nvD -> &nvDa - case 4776: state = 4777; break; // &nvd -> &nvda - case 4783: state = 4784; break; // &nvH -> &nvHa - case 4812: state = 4813; break; // &nw -> &nwa - case 4824: state = 4825; break; // &nwne -> &nwnea - case 4827: state = 4828; break; // &O -> &Oa - case 4833: state = 4834; break; // &o -> &oa - case 4851: state = 4852; break; // &od -> &oda - case 4857: state = 4858; break; // &Odbl -> &Odbla - case 4861: state = 4862; break; // &odbl -> &odbla - case 4891: state = 4892; break; // &Ogr -> &Ogra - case 4895: state = 4896; break; // &ogr -> &ogra - case 4901: state = 4902; break; // &ohb -> &ohba - case 4908: state = 4909; break; // &ol -> &ola - case 4923: state = 4924; break; // &Om -> &Oma - case 4927: state = 4928; break; // &om -> &oma - case 4932: state = 4933; break; // &Omeg -> &Omega - case 4935: state = 4936; break; // &omeg -> &omega - case 4957: state = 4958; break; // &op -> &opa - case 4991: state = 4992; break; // &or -> &ora - case 5021: state = 5022; break; // &Osl -> &Osla - case 5025: state = 5026; break; // &osl -> &osla - case 5046: state = 5047; break; // &otimes -> &otimesa - case 5056: state = 5057; break; // &ovb -> &ovba - case 5062: state = 5063; break; // &OverB -> &OverBa - case 5065: state = 5066; break; // &OverBr -> &OverBra - case 5072: state = 5073; break; // &OverP -> &OverPa - case 5083: state = 5084; break; // &p -> &pa - case 5085: state = 5086; break; // &par -> ¶ - case 5096: state = 5097; break; // &P -> &Pa - case 5100: state = 5101; break; // &Parti -> &Partia - case 5134: state = 5135; break; // &phmm -> &phmma - case 5150: state = 5151; break; // &pl -> &pla - case 5159: state = 5160; break; // &plus -> &plusa - case 5192: state = 5193; break; // &Poinc -> &Poinca - case 5197: state = 5198; break; // &Poincarepl -> &Poincarepla - case 5216: state = 5217; break; // &pr -> &pra - case 5224: state = 5225; break; // &prec -> &preca - case 5246: state = 5247; break; // &PrecedesEqu -> &PrecedesEqua - case 5250: state = 5251; break; // &PrecedesSl -> &PrecedesSla - case 5256: state = 5257; break; // &PrecedesSlantEqu -> &PrecedesSlantEqua - case 5266: state = 5267; break; // &precn -> &precna - case 5289: state = 5290; break; // &prn -> &prna - case 5303: state = 5304; break; // &prof -> &profa - case 5305: state = 5306; break; // &profal -> &profala - case 5323: state = 5324; break; // &Proportion -> &Proportiona - case 5374: state = 5375; break; // &qu -> &qua - case 5397: state = 5402; break; // &r -> &ra - case 5398: state = 5399; break; // &rA -> &rAa - case 5405: state = 5406; break; // &R -> &Ra - case 5439: state = 5440; break; // &rarr -> &rarra - case 5462: state = 5463; break; // &rAt -> &rAta - case 5466: state = 5467; break; // &rat -> &rata - case 5472: state = 5473; break; // &ration -> &rationa - case 5476: state = 5477; break; // &RB -> &RBa - case 5480: state = 5481; break; // &rB -> &rBa - case 5484: state = 5485; break; // &rb -> &rba - case 5491: state = 5492; break; // &rbr -> &rbra - case 5502: state = 5503; break; // &Rc -> &Rca - case 5507: state = 5508; break; // &rc -> &rca - case 5527: state = 5528; break; // &rdc -> &rdca - case 5531: state = 5532; break; // &rdldh -> &rdldha - case 5541: state = 5542; break; // &re -> &rea - case 5547: state = 5548; break; // &realp -> &realpa - case 5604: state = 5605; break; // &rH -> &rHa - case 5607: state = 5608; break; // &rh -> &rha - case 5620: state = 5637; break; // &Right -> &Righta - case 5627: state = 5628; break; // &RightAngleBr -> &RightAngleBra - case 5645: state = 5646; break; // &right -> &righta - case 5651: state = 5652; break; // &RightArrowB -> &RightArrowBa - case 5663: state = 5664; break; // &rightarrowt -> &rightarrowta - case 5681: state = 5682; break; // &RightDoubleBr -> &RightDoubleBra - case 5704: state = 5705; break; // &RightDownVectorB -> &RightDownVectorBa - case 5712: state = 5713; break; // &righth -> &rightha - case 5728: state = 5729; break; // &rightleft -> &rightlefta - case 5735: state = 5736; break; // &rightlefth -> &rightleftha - case 5747: state = 5748; break; // &rightright -> &rightrighta - case 5758: state = 5759; break; // &rightsquig -> &rightsquiga - case 5789: state = 5790; break; // &RightTri -> &RightTria - case 5795: state = 5796; break; // &RightTriangleB -> &RightTriangleBa - case 5800: state = 5801; break; // &RightTriangleEqu -> &RightTriangleEqua - case 5830: state = 5831; break; // &RightUpVectorB -> &RightUpVectorBa - case 5839: state = 5840; break; // &RightVectorB -> &RightVectorBa - case 5854: state = 5855; break; // &rl -> &rla - case 5858: state = 5859; break; // &rlh -> &rlha - case 5866: state = 5867; break; // &rmoust -> &rmousta - case 5875: state = 5876; break; // &ro -> &roa - case 5884: state = 5885; break; // &rop -> &ropa - case 5909: state = 5910; break; // &rp -> &rpa - case 5920: state = 5921; break; // &rr -> &rra - case 5928: state = 5929; break; // &Rright -> &Rrighta - case 5934: state = 5935; break; // &rs -> &rsa - case 5973: state = 5974; break; // &RuleDel -> &RuleDela - case 5981: state = 5982; break; // &ruluh -> &ruluha - case 5985: state = 5986; break; // &S -> &Sa - case 5991: state = 5992; break; // &s -> &sa - case 6001: state = 6005; break; // &Sc -> &Sca - case 6002: state = 6003; break; // &sc -> &sca - case 6030: state = 6031; break; // &scn -> &scna - case 6053: state = 6054; break; // &se -> &sea - case 6069: state = 6070; break; // &sesw -> &seswa - case 6088: state = 6089; break; // &sh -> &sha - case 6132: state = 6133; break; // &shortp -> &shortpa - case 6134: state = 6135; break; // &shortpar -> &shortpara - case 6160: state = 6161; break; // &Sigm -> &Sigma - case 6164: state = 6165; break; // &sigm -> &sigma - case 6184: state = 6185; break; // &simr -> &simra - case 6188: state = 6189; break; // &sl -> &sla - case 6192: state = 6193; break; // &Sm -> &Sma - case 6202: state = 6203; break; // &sm -> &sma - case 6218: state = 6219; break; // &smep -> &smepa - case 6241: state = 6242; break; // &solb -> &solba - case 6249: state = 6250; break; // &sp -> &spa - case 6259: state = 6260; break; // &sqc -> &sqca - case 6285: state = 6290; break; // &squ -> &squa - case 6286: state = 6287; break; // &Squ -> &Squa - case 6313: state = 6314; break; // &SquareSubsetEqu -> &SquareSubsetEqua - case 6324: state = 6325; break; // &SquareSupersetEqu -> &SquareSupersetEqua - case 6334: state = 6335; break; // &sr -> &sra - case 6352: state = 6353; break; // &sst -> &ssta - case 6356: state = 6357; break; // &St -> &Sta - case 6359: state = 6360; break; // &st -> &sta - case 6363: state = 6364; break; // &str -> &stra - case 6404: state = 6405; break; // &subr -> &subra - case 6419: state = 6420; break; // &SubsetEqu -> &SubsetEqua - case 6432: state = 6433; break; // &succ -> &succa - case 6454: state = 6455; break; // &SucceedsEqu -> &SucceedsEqua - case 6458: state = 6459; break; // &SucceedsSl -> &SucceedsSla - case 6464: state = 6465; break; // &SucceedsSlantEqu -> &SucceedsSlantEqua - case 6474: state = 6475; break; // &succn -> &succna - case 6492: state = 6493; break; // &SuchTh -> &SuchTha - case 6522: state = 6523; break; // &SupersetEqu -> &SupersetEqua - case 6531: state = 6532; break; // &supl -> &supla - case 6564: state = 6565; break; // &sw -> &swa - case 6576: state = 6577; break; // &swnw -> &swnwa - case 6583: state = 6584; break; // &T -> &Ta - case 6586: state = 6587; break; // &t -> &ta - case 6597: state = 6598; break; // &Tc -> &Tca - case 6602: state = 6603; break; // &tc -> &tca - case 6646: state = 6647; break; // &Thet -> &Theta - case 6648: state = 6649; break; // &thet -> &theta - case 6656: state = 6657; break; // &thick -> &thicka - case 6670: state = 6671; break; // &ThickSp -> &ThickSpa - case 6679: state = 6680; break; // &ThinSp -> &ThinSpa - case 6683: state = 6684; break; // &thk -> &thka - case 6706: state = 6707; break; // &TildeEqu -> &TildeEqua - case 6715: state = 6716; break; // &TildeFullEqu -> &TildeFullEqua - case 6726: state = 6727; break; // ×b -> ×ba - case 6733: state = 6734; break; // &toe -> &toea - case 6749: state = 6750; break; // &tos -> &tosa - case 6760: state = 6761; break; // &tr -> &tra - case 6764: state = 6765; break; // &tri -> &tria - case 6851: state = 6852; break; // &twohe -> &twohea - case 6857: state = 6858; break; // &twoheadleft -> &twoheadlefta - case 6867: state = 6868; break; // &twoheadright -> &twoheadrighta - case 6873: state = 6874; break; // &U -> &Ua - case 6879: state = 6880; break; // &u -> &ua - case 6920: state = 6921; break; // &ud -> &uda - case 6926: state = 6927; break; // &Udbl -> &Udbla - case 6930: state = 6931; break; // &udbl -> &udbla - case 6933: state = 6934; break; // &udh -> &udha - case 6945: state = 6946; break; // &Ugr -> &Ugra - case 6950: state = 6951; break; // &ugr -> &ugra - case 6954: state = 6955; break; // &uH -> &uHa - case 6957: state = 6958; break; // &uh -> &uha - case 6978: state = 6979; break; // &Um -> &Uma - case 6982: state = 6983; break; // &um -> &uma - case 6991: state = 6992; break; // &UnderB -> &UnderBa - case 6994: state = 6995; break; // &UnderBr -> &UnderBra - case 7001: state = 7002; break; // &UnderP -> &UnderPa - case 7031: state = 7037; break; // &Up -> &Upa - case 7042: state = 7043; break; // &up -> &upa - case 7048: state = 7049; break; // &UpArrowB -> &UpArrowBa - case 7072: state = 7073; break; // &Updown -> &Updowna - case 7081: state = 7082; break; // &updown -> &updowna - case 7098: state = 7099; break; // &uph -> &upha - case 7159: state = 7160; break; // &upup -> &upupa - case 7208: state = 7209; break; // &uu -> &uua - case 7217: state = 7218; break; // &uw -> &uwa - case 7223: state = 7224; break; // &v -> &va - case 7237: state = 7238; break; // &vark -> &varka - case 7240: state = 7241; break; // &varkapp -> &varkappa - case 7267: state = 7268; break; // &varsigm -> &varsigma - case 7289: state = 7290; break; // &varthet -> &vartheta - case 7292: state = 7293; break; // &vartri -> &vartria - case 7308: state = 7309; break; // &Vb -> &Vba - case 7311: state = 7312; break; // &vB -> &vBa - case 7319: state = 7320; break; // &VD -> &VDa - case 7323: state = 7324; break; // &Vd -> &Vda - case 7327: state = 7328; break; // &vD -> &vDa - case 7331: state = 7332; break; // &vd -> &vda - case 7340: state = 7341; break; // &veeb -> &veeba - case 7350: state = 7351; break; // &Verb -> &Verba - case 7354: state = 7355; break; // &verb -> &verba - case 7360: state = 7361; break; // &Vertic -> &Vertica - case 7363: state = 7364; break; // &VerticalB -> &VerticalBa - case 7372: state = 7373; break; // &VerticalSep -> &VerticalSepa - case 7374: state = 7375; break; // &VerticalSepar -> &VerticalSepara - case 7390: state = 7391; break; // &VeryThinSp -> &VeryThinSpa - case 7437: state = 7438; break; // &Vvd -> &Vvda - case 7444: state = 7445; break; // &vzigz -> &vzigza - case 7459: state = 7460; break; // &wedb -> &wedba - case 7485: state = 7486; break; // &wre -> &wrea - case 7496: state = 7497; break; // &xc -> &xca - case 7513: state = 7517; break; // &xh -> &xha - case 7522: state = 7526; break; // &xl -> &xla - case 7529: state = 7530; break; // &xm -> &xma - case 7551: state = 7555; break; // &xr -> &xra - case 7584: state = 7585; break; // &Y -> &Ya - case 7590: state = 7591; break; // &y -> &ya - case 7645: state = 7646; break; // &Z -> &Za - case 7651: state = 7652; break; // &z -> &za - case 7657: state = 7658; break; // &Zc -> &Zca - case 7662: state = 7663; break; // &zc -> &zca - case 7689: state = 7690; break; // &ZeroWidthSp -> &ZeroWidthSpa - case 7693: state = 7694; break; // &Zet -> &Zeta - case 7695: state = 7696; break; // &zet -> &zeta - case 7709: state = 7710; break; // &zigr -> &zigra - default: return false; - } - break; - case 'b': - switch (state) { - case 0: state = 222; break; // & -> &b - case 1: state = 13; break; // &A -> &Ab - case 7: state = 18; break; // &a -> &ab - case 109: state = 111; break; // &angmsda -> &angmsdab - case 120: state = 121; break; // &angrtv -> &angrtvb - case 222: state = 270; break; // &b -> &bb - case 273: state = 274; break; // &bbrkt -> &bbrktb - case 470: state = 471; break; // &box -> &boxb - case 545: state = 546; break; // &brv -> &brvb - case 562: state = 563; break; // &bsol -> &bsolb - case 566: state = 567; break; // &bsolhsu -> &bsolhsub - case 596: state = 600; break; // &cap -> &capb - case 835: state = 836; break; // &CloseCurlyDou -> &CloseCurlyDoub - case 850: state = 851; break; // &clu -> &club - case 978: state = 979; break; // &csu -> &csub - case 1006: state = 1007; break; // &cup -> &cupb - case 1097: state = 1120; break; // &d -> &db - case 1209: state = 1210; break; // &DiacriticalDou -> &DiacriticalDoub - case 1331: state = 1332; break; // &dou -> &doub - case 1334: state = 1335; break; // &double -> &doubleb - case 1343: state = 1344; break; // &Dou -> &Doub - case 1590: state = 1591; break; // &dr -> &drb - case 1874: state = 1875; break; // &Equili -> &Equilib - case 2118: state = 2140; break; // &g -> &gb - case 2124: state = 2135; break; // &G -> &Gb - case 2356: state = 2386; break; // &h -> &hb - case 2418: state = 2419; break; // &Hil -> &Hilb - case 2474: state = 2475; break; // &hor -> &horb - case 2524: state = 2525; break; // &hy -> &hyb - case 2696: state = 2697; break; // &Invisi -> &Invisib - case 2881: state = 2970; break; // &l -> &lb - case 2907: state = 2908; break; // &Lam -> &Lamb - case 2911: state = 2912; break; // &lam -> &lamb - case 2939: state = 2940; break; // &larr -> &larrb - case 2970: state = 2974; break; // &lb -> &lbb - case 3008: state = 3009; break; // &lcu -> &lcub - case 3090: state = 3091; break; // &LeftDou -> &LeftDoub - case 3393: state = 3399; break; // &lh -> &lhb - case 3466: state = 3472; break; // &lo -> &lob - case 3603: state = 3607; break; // &low -> &lowb - case 3677: state = 3678; break; // &lsq -> &lsqb - case 3843: state = 3844; break; // &minus -> &minusb - case 3897: state = 3930; break; // &n -> &nb - case 3898: state = 3899; break; // &na -> &nab - case 4233: state = 4234; break; // &NotDou -> &NotDoub - case 4339: state = 4341; break; // ¬inv -> ¬invb - case 4426: state = 4428; break; // ¬niv -> ¬nivb - case 4494: state = 4495; break; // &NotSquareSu -> &NotSquareSub - case 4515: state = 4516; break; // &NotSu -> &NotSub - case 4690: state = 4691; break; // &nsqsu -> &nsqsub - case 4695: state = 4696; break; // &nsu -> &nsub - case 4851: state = 4860; break; // &od -> &odb - case 4855: state = 4856; break; // &Od -> &Odb - case 4900: state = 4901; break; // &oh -> &ohb - case 4970: state = 4971; break; // &OpenCurlyDou -> &OpenCurlyDoub - case 5055: state = 5056; break; // &ov -> &ovb - case 5159: state = 5164; break; // &plus -> &plusb - case 5397: state = 5484; break; // &r -> &rb - case 5439: state = 5442; break; // &rarr -> &rarrb - case 5484: state = 5488; break; // &rb -> &rbb - case 5522: state = 5523; break; // &rcu -> &rcub - case 5573: state = 5574; break; // &ReverseEquili -> &ReverseEquilib - case 5586: state = 5587; break; // &ReverseUpEquili -> &ReverseUpEquilib - case 5676: state = 5677; break; // &RightDou -> &RightDoub - case 5875: state = 5881; break; // &ro -> &rob - case 5946: state = 5947; break; // &rsq -> &rsqb - case 5991: state = 5997; break; // &s -> &sb - case 6050: state = 6051; break; // &sdot -> &sdotb - case 6240: state = 6241; break; // &sol -> &solb - case 6270: state = 6271; break; // &sqsu -> &sqsub - case 6306: state = 6307; break; // &SquareSu -> &SquareSub - case 6381: state = 6382; break; // &Su -> &Sub - case 6383: state = 6384; break; // &su -> &sub - case 6428: state = 6429; break; // &subsu -> &subsub - case 6508: state = 6509; break; // &supdsu -> &supdsub - case 6529: state = 6530; break; // &suphsu -> &suphsub - case 6561: state = 6562; break; // &supsu -> &supsub - case 6584: state = 6585; break; // &Ta -> &Tab - case 6586: state = 6594; break; // &t -> &tb - case 6725: state = 6726; break; // × -> ×b - case 6735: state = 6736; break; // &top -> &topb - case 6809: state = 6810; break; // &tris -> &trisb - case 6873: state = 6896; break; // &U -> &Ub - case 6879: state = 6900; break; // &u -> &ub - case 6920: state = 6929; break; // &ud -> &udb - case 6924: state = 6925; break; // &Ud -> &Udb - case 6957: state = 6962; break; // &uh -> &uhb - case 7092: state = 7093; break; // &UpEquili -> &UpEquilib - case 7269: state = 7270; break; // &varsu -> &varsub - case 7307: state = 7308; break; // &V -> &Vb - case 7339: state = 7340; break; // &vee -> &veeb - case 7349: state = 7350; break; // &Ver -> &Verb - case 7353: state = 7354; break; // &ver -> &verb - case 7404: state = 7405; break; // &vnsu -> &vnsub - case 7427: state = 7428; break; // &vsu -> &vsub - case 7458: state = 7459; break; // &wed -> &wedb - default: return false; - } - break; - case 'c': - switch (state) { - case 0: state = 589; break; // & -> &c - case 1: state = 26; break; // &A -> &Ac - case 2: state = 3; break; // &Aa -> &Aac - case 7: state = 23; break; // &a -> &ac - case 8: state = 9; break; // &aa -> &aac - case 28: state = 29; break; // &Acir ->  - case 31: state = 32; break; // &acir -> â - case 76: state = 77; break; // &Ama -> &Amac - case 80: state = 81; break; // &ama -> &amac - case 109: state = 112; break; // &angmsda -> &angmsdac - case 144: state = 145; break; // &apa -> &apac - case 160: state = 161; break; // &ApplyFun -> &ApplyFunc - case 180: state = 181; break; // &As -> &Asc - case 183: state = 184; break; // &as -> &asc - case 212: state = 213; break; // &aw -> &awc - case 222: state = 277; break; // &b -> &bc - case 223: state = 224; break; // &ba -> &bac - case 225: state = 226; break; // &back -> &backc - case 247: state = 281; break; // &B -> &Bc - case 248: state = 249; break; // &Ba -> &Bac - case 288: state = 289; break; // &be -> &bec - case 293: state = 294; break; // &Be -> &Bec - case 334: state = 335; break; // &big -> &bigc - case 339: state = 340; break; // &bigcir -> &bigcirc - case 357: state = 358; break; // &bigsq -> &bigsqc - case 397: state = 398; break; // &bla -> &blac - case 442: state = 443; break; // &blo -> &bloc - case 549: state = 550; break; // &Bs -> &Bsc - case 552: state = 553; break; // &bs -> &bsc - case 583: state = 645; break; // &C -> &Cc - case 584: state = 585; break; // &Ca -> &Cac - case 589: state = 641; break; // &c -> &cc - case 590: state = 591; break; // &ca -> &cac - case 596: state = 605; break; // &cap -> &capc - case 601: state = 602; break; // &capbr -> &capbrc - case 662: state = 663; break; // &Ccir -> &Ccirc - case 665: state = 666; break; // &ccir -> &ccirc - case 716: state = 717; break; // &CH -> &CHc - case 719: state = 720; break; // &ch -> &chc - case 722: state = 723; break; // &che -> &chec - case 733: state = 734; break; // &cir -> &circ - case 753: state = 757; break; // &circled -> &circledc - case 759: state = 760; break; // &circledcir -> &circledcirc - case 766: state = 767; break; // &Cir -> &Circ - case 799: state = 800; break; // &cirs -> &cirsc - case 804: state = 805; break; // &Clo -> &Cloc - case 923: state = 924; break; // &Coprodu -> &Coproduc - case 939: state = 940; break; // &CounterClo -> &CounterCloc - case 972: state = 973; break; // &Cs -> &Csc - case 975: state = 976; break; // &cs -> &csc - case 997: state = 998; break; // &cues -> &cuesc - case 1006: state = 1015; break; // &cup -> &cupc - case 1008: state = 1009; break; // &cupbr -> &cupbrc - case 1037: state = 1038; break; // &curlyeqpre -> &curlyeqprec - case 1040: state = 1041; break; // &curlyeqsu -> &curlyeqsuc - case 1041: state = 1042; break; // &curlyeqsuc -> &curlyeqsucc - case 1076: state = 1077; break; // &cw -> &cwc - case 1087: state = 1088; break; // &cyl -> &cylc - case 1091: state = 1129; break; // &D -> &Dc - case 1097: state = 1134; break; // &d -> &dc - case 1127: state = 1128; break; // &dbla -> &dblac - case 1192: state = 1193; break; // &Dia -> &Diac - case 1197: state = 1198; break; // &Diacriti -> &Diacritic - case 1201: state = 1202; break; // &DiacriticalA -> &DiacriticalAc - case 1213: state = 1214; break; // &DiacriticalDoubleA -> &DiacriticalDoubleAc - case 1277: state = 1278; break; // &DJ -> &DJc - case 1280: state = 1281; break; // &dj -> &djc - case 1283: state = 1284; break; // &dl -> &dlc - case 1459: state = 1460; break; // &DoubleVerti -> &DoubleVertic - case 1536: state = 1537; break; // &DownLeftRightVe -> &DownLeftRightVec - case 1545: state = 1546; break; // &DownLeftTeeVe -> &DownLeftTeeVec - case 1551: state = 1552; break; // &DownLeftVe -> &DownLeftVec - case 1568: state = 1569; break; // &DownRightTeeVe -> &DownRightTeeVec - case 1574: state = 1575; break; // &DownRightVe -> &DownRightVec - case 1590: state = 1597; break; // &dr -> &drc - case 1604: state = 1605; break; // &Ds -> &Dsc - case 1607: state = 1608; break; // &ds -> &dsc - case 1610: state = 1611; break; // &DS -> &DSc - case 1644: state = 1645; break; // &DZ -> &DZc - case 1647: state = 1648; break; // &dz -> &dzc - case 1656: state = 1672; break; // &E -> &Ec - case 1657: state = 1658; break; // &Ea -> &Eac - case 1662: state = 1677; break; // &e -> &ec - case 1663: state = 1664; break; // &ea -> &eac - case 1683: state = 1687; break; // &ecir -> ê - case 1685: state = 1686; break; // &Ecir -> Ê - case 1747: state = 1748; break; // &Ema -> &Emac - case 1751: state = 1752; break; // &ema -> &emac - case 1833: state = 1834; break; // &eq -> &eqc - case 1836: state = 1837; break; // &eqcir -> &eqcirc - case 1897: state = 1898; break; // &Es -> &Esc - case 1900: state = 1901; break; // &es -> &esc - case 1925: state = 1926; break; // &ex -> &exc - case 1937: state = 1938; break; // &expe -> &expec - case 1964: state = 1980; break; // &f -> &fc - case 1977: state = 1978; break; // &F -> &Fc - case 2084: state = 2085; break; // &fra -> &frac - case 2112: state = 2113; break; // &Fs -> &Fsc - case 2115: state = 2116; break; // &fs -> &fsc - case 2118: state = 2153; break; // &g -> &gc - case 2119: state = 2120; break; // &ga -> &gac - case 2124: state = 2145; break; // &G -> &Gc - case 2151: state = 2152; break; // &Gcir -> &Gcirc - case 2155: state = 2156; break; // &gcir -> &gcirc - case 2176: state = 2177; break; // &ges -> &gesc - case 2177: state = 2178; break; // &gesc -> &gescc - case 2198: state = 2199; break; // &GJ -> &GJc - case 2201: state = 2202; break; // &gj -> &gjc - case 2282: state = 2283; break; // &Gs -> &Gsc - case 2285: state = 2286; break; // &gs -> &gsc - case 2294: state = 2295; break; // > -> >c - case 2295: state = 2296; break; // >c -> >cc - case 2351: state = 2389; break; // &H -> &Hc - case 2352: state = 2353; break; // &Ha -> &Hac - case 2356: state = 2393; break; // &h -> &hc - case 2370: state = 2371; break; // &HARD -> &HARDc - case 2374: state = 2375; break; // &hard -> &hardc - case 2380: state = 2381; break; // &harr -> &harrc - case 2391: state = 2392; break; // &Hcir -> &Hcirc - case 2395: state = 2396; break; // &hcir -> &hcirc - case 2409: state = 2410; break; // &her -> &herc - case 2425: state = 2426; break; // &HilbertSpa -> &HilbertSpac - case 2490: state = 2491; break; // &Hs -> &Hsc - case 2493: state = 2494; break; // &hs -> &hsc - case 2533: state = 2546; break; // &I -> &Ic - case 2534: state = 2535; break; // &Ia -> &Iac - case 2539: state = 2545; break; // &i -> &ic - case 2540: state = 2541; break; // &ia -> &iac - case 2548: state = 2549; break; // &Icir -> Î - case 2551: state = 2552; break; // &icir -> î - case 2558: state = 2559; break; // &IE -> &IEc - case 2561: state = 2562; break; // &ie -> &iec - case 2564: state = 2565; break; // &iex -> &iexc - case 2605: state = 2606; break; // &Ima -> &Imac - case 2609: state = 2610; break; // &ima -> &imac - case 2641: state = 2642; break; // &in -> &inc - case 2658: state = 2659; break; // &int -> &intc - case 2672: state = 2673; break; // &inter -> &interc - case 2678: state = 2679; break; // &Interse -> &Intersec - case 2710: state = 2711; break; // &IO -> &IOc - case 2713: state = 2714; break; // &io -> &ioc - case 2740: state = 2741; break; // &Is -> &Isc - case 2743: state = 2744; break; // &is -> &isc - case 2766: state = 2767; break; // &Iuk -> &Iukc - case 2770: state = 2771; break; // &iuk -> &iukc - case 2777: state = 2778; break; // &J -> &Jc - case 2780: state = 2781; break; // &Jcir -> &Jcirc - case 2782: state = 2783; break; // &j -> &jc - case 2785: state = 2786; break; // &jcir -> &jcirc - case 2803: state = 2804; break; // &Js -> &Jsc - case 2806: state = 2807; break; // &js -> &jsc - case 2810: state = 2811; break; // &Jser -> &Jserc - case 2814: state = 2815; break; // &jser -> &jserc - case 2818: state = 2819; break; // &Juk -> &Jukc - case 2822: state = 2823; break; // &juk -> &jukc - case 2825: state = 2836; break; // &K -> &Kc - case 2830: state = 2841; break; // &k -> &kc - case 2857: state = 2858; break; // &KH -> &KHc - case 2860: state = 2861; break; // &kh -> &khc - case 2863: state = 2864; break; // &KJ -> &KJc - case 2866: state = 2867; break; // &kj -> &kjc - case 2875: state = 2876; break; // &Ks -> &Ksc - case 2878: state = 2879; break; // &ks -> &ksc - case 2881: state = 2993; break; // &l -> &lc - case 2886: state = 2988; break; // &L -> &Lc - case 2887: state = 2888; break; // &La -> &Lac - case 2892: state = 2893; break; // &la -> &lac - case 2925: state = 2926; break; // &Lapla -> &Laplac - case 2978: state = 2979; break; // &lbra -> &lbrac - case 3012: state = 3013; break; // &ld -> &ldc - case 3043: state = 3044; break; // &LeftAngleBra -> &LeftAngleBrac - case 3096: state = 3097; break; // &LeftDoubleBra -> &LeftDoubleBrac - case 3107: state = 3108; break; // &LeftDownTeeVe -> &LeftDownTeeVec - case 3113: state = 3114; break; // &LeftDownVe -> &LeftDownVec - case 3199: state = 3200; break; // &LeftRightVe -> &LeftRightVec - case 3213: state = 3214; break; // &LeftTeeVe -> &LeftTeeVec - case 3250: state = 3251; break; // &LeftUpDownVe -> &LeftUpDownVec - case 3259: state = 3260; break; // &LeftUpTeeVe -> &LeftUpTeeVec - case 3265: state = 3266; break; // &LeftUpVe -> &LeftUpVec - case 3274: state = 3275; break; // &LeftVe -> &LeftVec - case 3291: state = 3292; break; // &les -> &lesc - case 3292: state = 3293; break; // &lesc -> &lescc - case 3402: state = 3403; break; // &LJ -> &LJc - case 3405: state = 3406; break; // &lj -> &ljc - case 3409: state = 3413; break; // &ll -> &llc - case 3448: state = 3449; break; // &lmousta -> &lmoustac - case 3643: state = 3647; break; // &lr -> &lrc - case 3661: state = 3669; break; // &ls -> &lsc - case 3666: state = 3667; break; // &Ls -> &Lsc - case 3692: state = 3693; break; // < -> <c - case 3693: state = 3694; break; // <c -> <cc - case 3745: state = 3776; break; // &m -> &mc - case 3746: state = 3747; break; // &ma -> &mac - case 3755: state = 3781; break; // &M -> &Mc - case 3811: state = 3812; break; // &MediumSpa -> &MediumSpac - case 3827: state = 3828; break; // &mi -> &mic - case 3831: state = 3835; break; // &mid -> &midc - case 3855: state = 3856; break; // &ml -> &mlc - case 3876: state = 3877; break; // &Ms -> &Msc - case 3879: state = 3880; break; // &ms -> &msc - case 3897: state = 3937; break; // &n -> &nc - case 3898: state = 3908; break; // &na -> &nac - case 3902: state = 3940; break; // &N -> &Nc - case 3903: state = 3904; break; // &Na -> &Nac - case 3999: state = 4000; break; // &NegativeMediumSpa -> &NegativeMediumSpac - case 4004: state = 4005; break; // &NegativeThi -> &NegativeThic - case 4009: state = 4010; break; // &NegativeThickSpa -> &NegativeThickSpac - case 4015: state = 4016; break; // &NegativeThinSpa -> &NegativeThinSpac - case 4028: state = 4029; break; // &NegativeVeryThinSpa -> &NegativeVeryThinSpac - case 4115: state = 4116; break; // &NJ -> &NJc - case 4118: state = 4119; break; // &nj -> &njc - case 4207: state = 4208; break; // &NonBreakingSpa -> &NonBreakingSpac - case 4241: state = 4242; break; // &NotDoubleVerti -> &NotDoubleVertic - case 4339: state = 4342; break; // ¬inv -> ¬invc - case 4426: state = 4429; break; // ¬niv -> ¬nivc - case 4432: state = 4433; break; // &NotPre -> &NotPrec - case 4515: state = 4525; break; // &NotSu -> &NotSuc - case 4525: state = 4526; break; // &NotSuc -> &NotSucc - case 4590: state = 4591; break; // &NotVerti -> &NotVertic - case 4613: state = 4614; break; // &npr -> &nprc - case 4617: state = 4618; break; // &npre -> &nprec - case 4627: state = 4628; break; // &nrarr -> &nrarrc - case 4653: state = 4654; break; // &ns -> &nsc - case 4654: state = 4655; break; // &nsc -> &nscc - case 4659: state = 4660; break; // &Ns -> &Nsc - case 4695: state = 4705; break; // &nsu -> &nsuc - case 4705: state = 4706; break; // &nsuc -> &nsucc - case 4827: state = 4844; break; // &O -> &Oc - case 4828: state = 4829; break; // &Oa -> &Oac - case 4833: state = 4841; break; // &o -> &oc - case 4834: state = 4835; break; // &oa -> &oac - case 4843: state = 4848; break; // &ocir -> ô - case 4846: state = 4847; break; // &Ocir -> Ô - case 4858: state = 4859; break; // &Odbla -> &Odblac - case 4862: state = 4863; break; // &odbla -> &odblac - case 4880: state = 4881; break; // &of -> &ofc - case 4908: state = 4912; break; // &ol -> &olc - case 4924: state = 4925; break; // &Oma -> &Omac - case 4928: state = 4929; break; // &oma -> &omac - case 4937: state = 4938; break; // &Omi -> &Omic - case 4942: state = 4943; break; // &omi -> &omic - case 5015: state = 5016; break; // &Os -> &Osc - case 5018: state = 5019; break; // &os -> &osc - case 5066: state = 5067; break; // &OverBra -> &OverBrac - case 5083: state = 5106; break; // &p -> &pc - case 5096: state = 5104; break; // &P -> &Pc - case 5109: state = 5110; break; // &per -> &perc - case 5142: state = 5143; break; // &pit -> &pitc - case 5152: state = 5153; break; // &plan -> &planc - case 5159: state = 5165; break; // &plus -> &plusc - case 5160: state = 5161; break; // &plusa -> &plusac - case 5191: state = 5192; break; // &Poin -> &Poinc - case 5216: state = 5219; break; // &pr -> &prc - case 5223: state = 5224; break; // &pre -> &prec - case 5224: state = 5231; break; // &prec -> &precc - case 5238: state = 5239; break; // &Pre -> &Prec - case 5300: state = 5301; break; // &Produ -> &Produc - case 5335: state = 5336; break; // &Ps -> &Psc - case 5338: state = 5339; break; // &ps -> &psc - case 5344: state = 5345; break; // &pun -> &punc - case 5368: state = 5369; break; // &Qs -> &Qsc - case 5371: state = 5372; break; // &qs -> &qsc - case 5397: state = 5507; break; // &r -> &rc - case 5402: state = 5403; break; // &ra -> &rac - case 5405: state = 5502; break; // &R -> &Rc - case 5406: state = 5407; break; // &Ra -> &Rac - case 5415: state = 5416; break; // &radi -> &radic - case 5439: state = 5445; break; // &rarr -> &rarrc - case 5492: state = 5493; break; // &rbra -> &rbrac - case 5526: state = 5527; break; // &rd -> &rdc - case 5541: state = 5552; break; // &re -> &rec - case 5628: state = 5629; break; // &RightAngleBra -> &RightAngleBrac - case 5682: state = 5683; break; // &RightDoubleBra -> &RightDoubleBrac - case 5693: state = 5694; break; // &RightDownTeeVe -> &RightDownTeeVec - case 5699: state = 5700; break; // &RightDownVe -> &RightDownVec - case 5773: state = 5774; break; // &RightTeeVe -> &RightTeeVec - case 5810: state = 5811; break; // &RightUpDownVe -> &RightUpDownVec - case 5819: state = 5820; break; // &RightUpTeeVe -> &RightUpTeeVec - case 5825: state = 5826; break; // &RightUpVe -> &RightUpVec - case 5834: state = 5835; break; // &RightVe -> &RightVec - case 5867: state = 5868; break; // &rmousta -> &rmoustac - case 5934: state = 5942; break; // &rs -> &rsc - case 5939: state = 5940; break; // &Rs -> &Rsc - case 5985: state = 6001; break; // &S -> &Sc - case 5986: state = 5987; break; // &Sa -> &Sac - case 5991: state = 6002; break; // &s -> &sc - case 5992: state = 5993; break; // &sa -> &sac - case 6002: state = 6012; break; // &sc -> &scc - case 6025: state = 6026; break; // &Scir -> &Scirc - case 6028: state = 6029; break; // &scir -> &scirc - case 6053: state = 6064; break; // &se -> &sec - case 6088: state = 6097; break; // &sh -> &shc - case 6092: state = 6101; break; // &SH -> &SHc - case 6094: state = 6095; break; // &SHCH -> &SHCHc - case 6098: state = 6099; break; // &shch -> &shchc - case 6198: state = 6199; break; // &SmallCir -> &SmallCirc - case 6232: state = 6233; break; // &SOFT -> &SOFTc - case 6237: state = 6238; break; // &soft -> &softc - case 6258: state = 6259; break; // &sq -> &sqc - case 6299: state = 6300; break; // &SquareInterse -> &SquareIntersec - case 6338: state = 6339; break; // &Ss -> &Ssc - case 6341: state = 6342; break; // &ss -> &ssc - case 6381: state = 6446; break; // &Su -> &Suc - case 6383: state = 6431; break; // &su -> &suc - case 6431: state = 6432; break; // &suc -> &succ - case 6432: state = 6439; break; // &succ -> &succc - case 6446: state = 6447; break; // &Suc -> &Succ - case 6583: state = 6597; break; // &T -> &Tc - case 6586: state = 6602; break; // &t -> &tc - case 6623: state = 6624; break; // &telre -> &telrec - case 6654: state = 6655; break; // &thi -> &thic - case 6666: state = 6667; break; // &Thi -> &Thic - case 6671: state = 6672; break; // &ThickSpa -> &ThickSpac - case 6680: state = 6681; break; // &ThinSpa -> &ThinSpac - case 6735: state = 6739; break; // &top -> &topc - case 6821: state = 6822; break; // &Ts -> &Tsc - case 6824: state = 6825; break; // &ts -> &tsc - case 6827: state = 6828; break; // &TS -> &TSc - case 6831: state = 6832; break; // &TSH -> &TSHc - case 6834: state = 6835; break; // &tsh -> &tshc - case 6873: state = 6910; break; // &U -> &Uc - case 6874: state = 6875; break; // &Ua -> &Uac - case 6879: state = 6914; break; // &u -> &uc - case 6880: state = 6881; break; // &ua -> &uac - case 6892: state = 6893; break; // &Uarro -> &Uarroc - case 6897: state = 6898; break; // &Ubr -> &Ubrc - case 6901: state = 6902; break; // &ubr -> &ubrc - case 6912: state = 6913; break; // &Ucir -> Û - case 6916: state = 6917; break; // &ucir -> û - case 6927: state = 6928; break; // &Udbla -> &Udblac - case 6931: state = 6932; break; // &udbla -> &udblac - case 6965: state = 6966; break; // &ul -> &ulc - case 6979: state = 6980; break; // &Uma -> &Umac - case 6983: state = 6984; break; // &uma -> &umac - case 6995: state = 6996; break; // &UnderBra -> &UnderBrac - case 7166: state = 7167; break; // &ur -> &urc - case 7186: state = 7187; break; // &Us -> &Usc - case 7189: state = 7190; break; // &us -> &usc - case 7223: state = 7317; break; // &v -> &vc - case 7307: state = 7315; break; // &V -> &Vc - case 7359: state = 7360; break; // &Verti -> &Vertic - case 7391: state = 7392; break; // &VeryThinSpa -> &VeryThinSpac - case 7421: state = 7422; break; // &Vs -> &Vsc - case 7424: state = 7425; break; // &vs -> &vsc - case 7447: state = 7448; break; // &W -> &Wc - case 7450: state = 7451; break; // &Wcir -> &Wcirc - case 7452: state = 7453; break; // &w -> &wc - case 7455: state = 7456; break; // &wcir -> &wcirc - case 7489: state = 7490; break; // &Ws -> &Wsc - case 7492: state = 7493; break; // &ws -> &wsc - case 7495: state = 7496; break; // &x -> &xc - case 7500: state = 7501; break; // &xcir -> &xcirc - case 7558: state = 7559; break; // &Xs -> &Xsc - case 7561: state = 7562; break; // &xs -> &xsc - case 7564: state = 7565; break; // &xsq -> &xsqc - case 7584: state = 7600; break; // &Y -> &Yc - case 7585: state = 7586; break; // &Ya -> &Yac - case 7590: state = 7604; break; // &y -> &yc - case 7591: state = 7592; break; // &ya -> &yac - case 7596: state = 7597; break; // &YA -> &YAc - case 7602: state = 7603; break; // &Ycir -> &Ycirc - case 7606: state = 7607; break; // &ycir -> &ycirc - case 7616: state = 7617; break; // &YI -> &YIc - case 7619: state = 7620; break; // &yi -> &yic - case 7628: state = 7629; break; // &Ys -> &Ysc - case 7631: state = 7632; break; // &ys -> &ysc - case 7634: state = 7635; break; // &YU -> &YUc - case 7637: state = 7638; break; // &yu -> &yuc - case 7645: state = 7657; break; // &Z -> &Zc - case 7646: state = 7647; break; // &Za -> &Zac - case 7651: state = 7662; break; // &z -> &zc - case 7652: state = 7653; break; // &za -> &zac - case 7690: state = 7691; break; // &ZeroWidthSpa -> &ZeroWidthSpac - case 7701: state = 7702; break; // &ZH -> &ZHc - case 7704: state = 7705; break; // &zh -> &zhc - case 7719: state = 7720; break; // &Zs -> &Zsc - case 7722: state = 7723; break; // &zs -> &zsc - default: return false; - } - break; - case 'd': - switch (state) { - case 0: state = 1097; break; // & -> &d - case 23: state = 24; break; // &ac -> &acd - case 88: state = 89; break; // &An -> &And - case 90: state = 91; break; // &an -> &and - case 91: state = 95; break; // &and -> &andd - case 93: state = 94; break; // &andan -> &andand - case 107: state = 108; break; // &angms -> &angmsd - case 109: state = 113; break; // &angmsda -> &angmsdad - case 121: state = 122; break; // &angrtvb -> &angrtvbd - case 150: state = 151; break; // &api -> &apid - case 198: state = 199; break; // &Atil -> &Atild - case 203: state = 204; break; // &atil -> &atild - case 222: state = 284; break; // &b -> &bd - case 263: state = 264; break; // &Barwe -> &Barwed - case 266: state = 267; break; // &barwe -> &barwed - case 343: state = 344; break; // &bigo -> &bigod - case 371: state = 372; break; // &bigtriangle -> &bigtriangled - case 387: state = 388; break; // &bigwe -> &bigwed - case 420: state = 421; break; // &blacktriangle -> &blacktriangled - case 470: state = 477; break; // &box -> &boxd - case 484: state = 487; break; // &boxH -> &boxHd - case 485: state = 489; break; // &boxh -> &boxhd - case 583: state = 677; break; // &C -> &Cd - case 589: state = 680; break; // &c -> &cd - case 596: state = 610; break; // &cap -> &capd - case 598: state = 599; break; // &capan -> &capand - case 653: state = 654; break; // &Cce -> &Cced - case 657: state = 658; break; // &cce -> &cced - case 683: state = 684; break; // &ce -> &ced - case 687: state = 688; break; // &Ce -> &Ced - case 708: state = 709; break; // ¢er -> ¢erd - case 738: state = 753; break; // &circle -> &circled - case 753: state = 761; break; // &circled -> &circledd - case 797: state = 798; break; // &cirmi -> &cirmid - case 884: state = 885; break; // &cong -> &congd - case 918: state = 919; break; // &copro -> &coprod - case 921: state = 922; break; // &Copro -> &Coprod - case 983: state = 984; break; // &ct -> &ctd - case 987: state = 988; break; // &cu -> &cud - case 1006: state = 1020; break; // &cup -> &cupd - case 1047: state = 1048; break; // &curlywe -> &curlywed - case 1074: state = 1075; break; // &cuwe -> &cuwed - case 1097: state = 1142; break; // &d -> &dd - case 1154: state = 1155; break; // &DDotrah -> &DDotrahd - case 1225: state = 1226; break; // &DiacriticalTil -> &DiacriticalTild - case 1233: state = 1234; break; // &Diamon -> &Diamond - case 1236: state = 1237; break; // &diamon -> &diamond - case 1264: state = 1265; break; // &divi -> &divid - case 1307: state = 1308; break; // &doteq -> &doteqd - case 1339: state = 1340; break; // &doublebarwe -> &doublebarwed - case 1479: state = 1500; break; // &down -> &downd - case 1624: state = 1625; break; // &dt -> &dtd - case 1656: state = 1698; break; // &E -> &Ed - case 1662: state = 1703; break; // &e -> &ed - case 1724: state = 1725; break; // &egs -> &egsd - case 1742: state = 1743; break; // &els -> &elsd - case 1866: state = 1867; break; // &EqualTil -> &EqualTild - case 1900: state = 1903; break; // &es -> &esd - case 1970: state = 1971; break; // &falling -> &fallingd - case 2008: state = 2009; break; // &Fille -> &Filled - case 2118: state = 2162; break; // &g -> &gd - case 2124: state = 2159; break; // &G -> &Gd - case 2128: state = 2132; break; // &Gamma -> &Gammad - case 2131: state = 2133; break; // &gamma -> &gammad - case 2146: state = 2147; break; // &Gce -> &Gced - case 2176: state = 2179; break; // &ges -> &gesd - case 2279: state = 2280; break; // &GreaterTil -> &GreaterTild - case 2294: state = 2299; break; // > -> >d - case 2311: state = 2320; break; // >r -> >rd - case 2373: state = 2374; break; // &har -> &hard - case 2533: state = 2555; break; // &I -> &Id - case 2634: state = 2635; break; // &impe -> &imped - case 2652: state = 2653; break; // &ino -> &inod - case 2691: state = 2692; break; // &intpro -> &intprod - case 2733: state = 2734; break; // &ipro -> &iprod - case 2747: state = 2748; break; // &isin -> &isind - case 2758: state = 2759; break; // &Itil -> &Itild - case 2762: state = 2763; break; // &itil -> &itild - case 2837: state = 2838; break; // &Kce -> &Kced - case 2842: state = 2843; break; // &kce -> &kced - case 2881: state = 3012; break; // &l -> &ld - case 2908: state = 2909; break; // &Lamb -> &Lambd - case 2912: state = 2913; break; // &lamb -> &lambd - case 2918: state = 2919; break; // &lang -> &langd - case 2985: state = 2986; break; // &lbrksl -> &lbrksld - case 2998: state = 2999; break; // &Lce -> &Lced - case 3002: state = 3003; break; // &lce -> &lced - case 3019: state = 3020; break; // &ldr -> &ldrd - case 3132: state = 3133; break; // &leftharpoon -> &leftharpoond - case 3291: state = 3294; break; // &les -> &lesd - case 3302: state = 3309; break; // &less -> &lessd - case 3373: state = 3374; break; // &LessTil -> &LessTild - case 3395: state = 3396; break; // &lhar -> &lhard - case 3429: state = 3430; break; // &llhar -> &llhard - case 3435: state = 3436; break; // &Lmi -> &Lmid - case 3440: state = 3441; break; // &lmi -> &lmid - case 3655: state = 3656; break; // &lrhar -> &lrhard - case 3692: state = 3697; break; // < -> <d - case 3725: state = 3726; break; // &lur -> &lurd - case 3745: state = 3784; break; // &m -> &md - case 3761: state = 3762; break; // &mapsto -> &mapstod - case 3797: state = 3798; break; // &measure -> &measured - case 3804: state = 3805; break; // &Me -> &Med - case 3827: state = 3831; break; // &mi -> &mid - case 3831: state = 3838; break; // &mid -> &midd - case 3843: state = 3845; break; // &minus -> &minusd - case 3855: state = 3858; break; // &ml -> &mld - case 3865: state = 3866; break; // &mo -> &mod - case 3897: state = 3966; break; // &n -> &nd - case 3916: state = 3917; break; // &napi -> &napid - case 3948: state = 3949; break; // &Nce -> &Nced - case 3952: state = 3953; break; // &nce -> &nced - case 3958: state = 3959; break; // &ncong -> &ncongd - case 3970: state = 3981; break; // &ne -> &ned - case 3992: state = 3993; break; // &NegativeMe -> &NegativeMed - case 4043: state = 4044; break; // &Neste -> &Nested - case 4112: state = 4113; break; // &nis -> &nisd - case 4121: state = 4128; break; // &nl -> &nld - case 4188: state = 4189; break; // &nmi -> &nmid - case 4261: state = 4262; break; // &NotEqualTil -> &NotEqualTild - case 4313: state = 4314; break; // &NotGreaterTil -> &NotGreaterTild - case 4334: state = 4335; break; // ¬in -> ¬ind - case 4393: state = 4394; break; // &NotLessTil -> &NotLessTild - case 4400: state = 4401; break; // &NotNeste -> &NotNested - case 4434: state = 4435; break; // &NotPrece -> &NotPreced - case 4528: state = 4529; break; // &NotSuccee -> &NotSucceed - case 4548: state = 4549; break; // &NotSucceedsTil -> &NotSucceedsTild - case 4564: state = 4565; break; // &NotTil -> &NotTild - case 4583: state = 4584; break; // &NotTildeTil -> &NotTildeTild - case 4668: state = 4669; break; // &nshortmi -> &nshortmid - case 4683: state = 4684; break; // &nsmi -> &nsmid - case 4723: state = 4724; break; // &Ntil -> &Ntild - case 4727: state = 4728; break; // &ntil -> &ntild - case 4760: state = 4776; break; // &nv -> &nvd - case 4763: state = 4768; break; // &nV -> &nVd - case 4827: state = 4855; break; // &O -> &Od - case 4833: state = 4851; break; // &o -> &od - case 4870: state = 4871; break; // &odsol -> &odsold - case 4942: state = 4947; break; // &omi -> &omid - case 4991: state = 4995; break; // &or -> &ord - case 5033: state = 5034; break; // &Otil -> &Otild - case 5038: state = 5039; break; // &otil -> &otild - case 5114: state = 5115; break; // &perio -> &period - case 5159: state = 5168; break; // &plus -> &plusd - case 5213: state = 5214; break; // &poun -> £ - case 5240: state = 5241; break; // &Prece -> &Preced - case 5261: state = 5262; break; // &PrecedesTil -> &PrecedesTild - case 5296: state = 5297; break; // &pro -> &prod - case 5298: state = 5299; break; // &Pro -> &Prod - case 5397: state = 5526; break; // &r -> &rd - case 5402: state = 5414; break; // &ra -> &rad - case 5426: state = 5427; break; // &rang -> &rangd - case 5499: state = 5500; break; // &rbrksl -> &rbrksld - case 5512: state = 5513; break; // &Rce -> &Rced - case 5516: state = 5517; break; // &rce -> &rced - case 5529: state = 5530; break; // &rdl -> &rdld - case 5609: state = 5610; break; // &rhar -> &rhard - case 5718: state = 5719; break; // &rightharpoon -> &rightharpoond - case 5847: state = 5848; break; // &rising -> &risingd - case 5873: state = 5874; break; // &rnmi -> &rnmid - case 5900: state = 5901; break; // &Roun -> &Round - case 5976: state = 5977; break; // &RuleDelaye -> &RuleDelayed - case 5991: state = 6048; break; // &s -> &sd - case 6016: state = 6021; break; // &sce -> &sced - case 6017: state = 6018; break; // &Sce -> &Sced - case 6130: state = 6131; break; // &shortmi -> &shortmid - case 6168: state = 6169; break; // &sim -> &simd - case 6223: state = 6224; break; // &smi -> &smid - case 6250: state = 6251; break; // &spa -> &spad - case 6384: state = 6385; break; // &sub -> &subd - case 6389: state = 6390; break; // &sube -> &subed - case 6449: state = 6450; break; // &Succee -> &Succeed - case 6469: state = 6470; break; // &SucceedsTil -> &SucceedsTild - case 6500: state = 6504; break; // &sup -> &supd - case 6511: state = 6512; break; // &supe -> &suped - case 6586: state = 6617; break; // &t -> &td - case 6607: state = 6608; break; // &Tce -> &Tced - case 6611: state = 6612; break; // &tce -> &tced - case 6697: state = 6698; break; // &Til -> &Tild - case 6701: state = 6702; break; // &til -> &tild - case 6720: state = 6721; break; // &TildeTil -> &TildeTild - case 6725: state = 6729; break; // × -> ×d - case 6761: state = 6762; break; // &tra -> &trad - case 6764: state = 6788; break; // &tri -> &trid - case 6769: state = 6770; break; // &triangle -> &triangled - case 6852: state = 6853; break; // &twohea -> &twohead - case 6873: state = 6924; break; // &U -> &Ud - case 6879: state = 6920; break; // &u -> &ud - case 6987: state = 6988; break; // &Un -> &Und - case 7031: state = 7069; break; // &Up -> &Upd - case 7042: state = 7078; break; // &up -> &upd - case 7192: state = 7193; break; // &ut -> &utd - case 7198: state = 7199; break; // &Util -> &Utild - case 7202: state = 7203; break; // &util -> &utild - case 7223: state = 7331; break; // &v -> &vd - case 7307: state = 7323; break; // &V -> &Vd - case 7381: state = 7382; break; // &VerticalTil -> &VerticalTild - case 7436: state = 7437; break; // &Vv -> &Vvd - case 7457: state = 7458; break; // &we -> &wed - case 7462: state = 7463; break; // &We -> &Wed - case 7495: state = 7504; break; // &x -> &xd - case 7535: state = 7536; break; // &xo -> &xod - case 7580: state = 7581; break; // &xwe -> &xwed - case 7645: state = 7669; break; // &Z -> &Zd - case 7651: state = 7672; break; // &z -> &zd - case 7684: state = 7685; break; // &ZeroWi -> &ZeroWid - default: return false; - } - break; - case 'e': - switch (state) { - case 0: state = 1662; break; // & -> &e - case 5: state = 6; break; // &Aacut -> Á - case 7: state = 42; break; // &a -> &ae - case 11: state = 12; break; // &aacut -> á - case 14: state = 15; break; // &Abr -> &Abre - case 16: state = 17; break; // &Abrev -> &Abreve - case 19: state = 20; break; // &abr -> &abre - case 21: state = 22; break; // &abrev -> &abreve - case 34: state = 35; break; // &acut -> ´ - case 53: state = 54; break; // &Agrav -> À - case 58: state = 59; break; // &agrav -> à - case 60: state = 61; break; // &al -> &ale - case 99: state = 100; break; // &andslop -> &andslope - case 102: state = 103; break; // &ang -> &ange - case 104: state = 105; break; // &angl -> &angle - case 109: state = 114; break; // &angmsda -> &angmsdae - case 143: state = 149; break; // &ap -> &ape - case 169: state = 170; break; // &approx -> &approxe - case 193: state = 194; break; // &asymp -> &asympe - case 199: state = 200; break; // &Atild -> à - case 204: state = 205; break; // &atild -> ã - case 222: state = 288; break; // &b -> &be - case 225: state = 230; break; // &back -> &backe - case 240: state = 241; break; // &backprim -> &backprime - case 244: state = 245; break; // &backsim -> &backsime - case 247: state = 293; break; // &B -> &Be - case 259: state = 260; break; // &barv -> &barve - case 260: state = 261; break; // &barve -> &barvee - case 262: state = 263; break; // &Barw -> &Barwe - case 265: state = 266; break; // &barw -> &barwe - case 268: state = 269; break; // &barwedg -> &barwedge - case 292: state = 299; break; // &becaus -> &because - case 297: state = 298; break; // &Becaus -> &Because - case 325: state = 326; break; // &betw -> &betwe - case 326: state = 327; break; // &betwe -> &betwee - case 353: state = 354; break; // &bigotim -> &bigotime - case 370: state = 371; break; // &bigtriangl -> &bigtriangle - case 383: state = 384; break; // &bigv -> &bigve - case 384: state = 385; break; // &bigve -> &bigvee - case 386: state = 387; break; // &bigw -> &bigwe - case 389: state = 390; break; // &bigwedg -> &bigwedge - case 402: state = 403; break; // &blackloz -> &blackloze - case 405: state = 406; break; // &blacklozeng -> &blacklozenge - case 411: state = 412; break; // &blacksquar -> &blacksquare - case 419: state = 420; break; // &blacktriangl -> &blacktriangle - case 425: state = 426; break; // &blacktrianglel -> &blacktrianglele - case 445: state = 446; break; // &bn -> &bne - case 468: state = 469; break; // &bowti -> &bowtie - case 505: state = 506; break; // &boxtim -> &boxtime - case 535: state = 536; break; // &bprim -> &bprime - case 537: state = 538; break; // &Br -> &Bre - case 539: state = 540; break; // &Brev -> &Breve - case 541: state = 542; break; // &br -> &bre - case 543: state = 544; break; // &brev -> &breve - case 552: state = 555; break; // &bs -> &bse - case 559: state = 560; break; // &bsim -> &bsime - case 570: state = 571; break; // &bull -> &bulle - case 574: state = 576; break; // &bump -> &bumpe - case 579: state = 580; break; // &Bump -> &Bumpe - case 583: state = 687; break; // &C -> &Ce - case 587: state = 588; break; // &Cacut -> &Cacute - case 589: state = 683; break; // &c -> &ce - case 593: state = 594; break; // &cacut -> &cacute - case 620: state = 621; break; // &CapitalDiff -> &CapitalDiffe - case 622: state = 623; break; // &CapitalDiffer -> &CapitalDiffere - case 631: state = 632; break; // &car -> &care - case 637: state = 638; break; // &Cayl -> &Cayle - case 641: state = 657; break; // &cc -> &cce - case 645: state = 653; break; // &Cc -> &Cce - case 699: state = 707; break; // ¢ -> ¢e - case 701: state = 702; break; // &Cent -> &Cente - case 719: state = 722; break; // &ch -> &che - case 733: state = 790; break; // &cir -> &cire - case 734: state = 735; break; // &circ -> &circe - case 737: state = 738; break; // &circl -> &circle - case 744: state = 745; break; // &circlearrowl -> &circlearrowle - case 768: state = 769; break; // &Circl -> &Circle - case 786: state = 787; break; // &CircleTim -> &CircleTime - case 809: state = 810; break; // &Clockwis -> &Clockwise - case 820: state = 821; break; // &ClockwiseContourInt -> &ClockwiseContourInte - case 826: state = 827; break; // &Clos -> &Close - case 837: state = 838; break; // &CloseCurlyDoubl -> &CloseCurlyDouble - case 842: state = 843; break; // &CloseCurlyDoubleQuot -> &CloseCurlyDoubleQuote - case 847: state = 848; break; // &CloseCurlyQuot -> &CloseCurlyQuote - case 859: state = 864; break; // &Colon -> &Colone - case 863: state = 865; break; // &colon -> &colone - case 874: state = 875; break; // &compl -> &comple - case 876: state = 877; break; // &complem -> &compleme - case 880: state = 881; break; // &complex -> &complexe - case 891: state = 892; break; // &Congru -> &Congrue - case 907: state = 908; break; // &ContourInt -> &ContourInte - case 934: state = 935; break; // &Count -> &Counte - case 944: state = 945; break; // &CounterClockwis -> &CounterClockwise - case 955: state = 956; break; // &CounterClockwiseContourInt -> &CounterClockwiseContourInte - case 979: state = 980; break; // &csub -> &csube - case 981: state = 982; break; // &csup -> &csupe - case 987: state = 994; break; // &cu -> &cue - case 1032: state = 1033; break; // &curly -> &curlye - case 1036: state = 1037; break; // &curlyeqpr -> &curlyeqpre - case 1043: state = 1044; break; // &curlyv -> &curlyve - case 1044: state = 1045; break; // &curlyve -> &curlyvee - case 1046: state = 1047; break; // &curlyw -> &curlywe - case 1049: state = 1050; break; // &curlywedg -> &curlywedge - case 1051: state = 1052; break; // &curr -> &curre - case 1054: state = 1055; break; // &curv -> &curve - case 1061: state = 1062; break; // &curvearrowl -> &curvearrowle - case 1070: state = 1071; break; // &cuv -> &cuve - case 1071: state = 1072; break; // &cuve -> &cuvee - case 1073: state = 1074; break; // &cuw -> &cuwe - case 1091: state = 1163; break; // &D -> &De - case 1094: state = 1095; break; // &Dagg -> &Dagge - case 1097: state = 1161; break; // &d -> &de - case 1100: state = 1101; break; // &dagg -> &dagge - case 1103: state = 1104; break; // &dal -> &dale - case 1145: state = 1146; break; // &ddagg -> &ddagge - case 1158: state = 1159; break; // &ddots -> &ddotse - case 1204: state = 1205; break; // &DiacriticalAcut -> &DiacriticalAcute - case 1211: state = 1212; break; // &DiacriticalDoubl -> &DiacriticalDouble - case 1216: state = 1217; break; // &DiacriticalDoubleAcut -> &DiacriticalDoubleAcute - case 1221: state = 1222; break; // &DiacriticalGrav -> &DiacriticalGrave - case 1226: state = 1227; break; // &DiacriticalTild -> &DiacriticalTilde - case 1228: state = 1243; break; // &di -> &die - case 1245: state = 1246; break; // &Diff -> &Diffe - case 1247: state = 1248; break; // &Differ -> &Differe - case 1265: state = 1266; break; // &divid -> ÷ - case 1271: state = 1272; break; // ÷ontim -> ÷ontime - case 1302: state = 1306; break; // &dot -> &dote - case 1329: state = 1330; break; // &dotsquar -> &dotsquare - case 1333: state = 1334; break; // &doubl -> &double - case 1338: state = 1339; break; // &doublebarw -> &doublebarwe - case 1341: state = 1342; break; // &doublebarwedg -> &doublebarwedge - case 1345: state = 1346; break; // &Doubl -> &Double - case 1356: state = 1357; break; // &DoubleContourInt -> &DoubleContourInte - case 1372: state = 1373; break; // &DoubleL -> &DoubleLe - case 1391: state = 1392; break; // &DoubleLeftT -> &DoubleLeftTe - case 1392: state = 1393; break; // &DoubleLeftTe -> &DoubleLeftTee - case 1397: state = 1398; break; // &DoubleLongL -> &DoubleLongLe - case 1436: state = 1437; break; // &DoubleRightT -> &DoubleRightTe - case 1437: state = 1438; break; // &DoubleRightTe -> &DoubleRightTee - case 1455: state = 1456; break; // &DoubleV -> &DoubleVe - case 1496: state = 1497; break; // &DownBr -> &DownBre - case 1498: state = 1499; break; // &DownBrev -> &DownBreve - case 1517: state = 1518; break; // &downharpoonl -> &downharpoonle - case 1526: state = 1527; break; // &DownL -> &DownLe - case 1535: state = 1536; break; // &DownLeftRightV -> &DownLeftRightVe - case 1541: state = 1542; break; // &DownLeftT -> &DownLeftTe - case 1542: state = 1543; break; // &DownLeftTe -> &DownLeftTee - case 1544: state = 1545; break; // &DownLeftTeeV -> &DownLeftTeeVe - case 1550: state = 1551; break; // &DownLeftV -> &DownLeftVe - case 1564: state = 1565; break; // &DownRightT -> &DownRightTe - case 1565: state = 1566; break; // &DownRightTe -> &DownRightTee - case 1567: state = 1568; break; // &DownRightTeeV -> &DownRightTeeVe - case 1573: state = 1574; break; // &DownRightV -> &DownRightVe - case 1582: state = 1583; break; // &DownT -> &DownTe - case 1583: state = 1584; break; // &DownTe -> &DownTee - case 1642: state = 1643; break; // &dwangl -> &dwangle - case 1660: state = 1661; break; // &Eacut -> É - case 1662: state = 1706; break; // &e -> &ee - case 1666: state = 1667; break; // &eacut -> é - case 1669: state = 1670; break; // &east -> &easte - case 1718: state = 1719; break; // &Egrav -> È - case 1722: state = 1723; break; // &egrav -> è - case 1729: state = 1730; break; // &El -> &Ele - case 1731: state = 1732; break; // &Elem -> &Eleme - case 1737: state = 1738; break; // &elint -> &elinte - case 1757: state = 1758; break; // &emptys -> &emptyse - case 1772: state = 1773; break; // &EmptySmallSquar -> &EmptySmallSquare - case 1775: state = 1776; break; // &EmptyV -> &EmptyVe - case 1788: state = 1789; break; // &EmptyVerySmallSquar -> &EmptyVerySmallSquare - case 1852: state = 1853; break; // &eqslantl -> &eqslantle - case 1860: state = 1869; break; // &equ -> &eque - case 1867: state = 1868; break; // &EqualTild -> &EqualTilde - case 1936: state = 1937; break; // &exp -> &expe - case 1947: state = 1948; break; // &Expon -> &Expone - case 1956: state = 1957; break; // &expon -> &expone - case 1962: state = 1963; break; // &exponential -> &exponentiale - case 1964: state = 1982; break; // &f -> &fe - case 1974: state = 1975; break; // &fallingdots -> &fallingdotse - case 1985: state = 1986; break; // &femal -> &female - case 2007: state = 2008; break; // &Fill -> &Fille - case 2019: state = 2020; break; // &FilledSmallSquar -> &FilledSmallSquare - case 2021: state = 2022; break; // &FilledV -> &FilledVe - case 2034: state = 2035; break; // &FilledVerySmallSquar -> &FilledVerySmallSquare - case 2070: state = 2071; break; // &Fouri -> &Fourie - case 2118: state = 2166; break; // &g -> &ge - case 2122: state = 2123; break; // &gacut -> &gacute - case 2136: state = 2137; break; // &Gbr -> &Gbre - case 2138: state = 2139; break; // &Gbrev -> &Gbreve - case 2141: state = 2142; break; // &gbr -> &gbre - case 2143: state = 2144; break; // &gbrev -> &gbreve - case 2145: state = 2146; break; // &Gc -> &Gce - case 2184: state = 2185; break; // &gesl -> &gesle - case 2195: state = 2196; break; // &gim -> &gime - case 2208: state = 2216; break; // &gn -> &gne - case 2230: state = 2231; break; // &grav -> &grave - case 2232: state = 2233; break; // &Gr -> &Gre - case 2235: state = 2236; break; // &Great -> &Greate - case 2243: state = 2244; break; // &GreaterEqualL -> &GreaterEqualLe - case 2257: state = 2258; break; // &GreaterGr -> &GreaterGre - case 2260: state = 2261; break; // &GreaterGreat -> &GreaterGreate - case 2263: state = 2264; break; // &GreaterL -> &GreaterLe - case 2280: state = 2281; break; // &GreaterTild -> &GreaterTilde - case 2289: state = 2290; break; // &gsim -> &gsime - case 2307: state = 2308; break; // >qu -> >que - case 2311: state = 2323; break; // >r -> >re - case 2325: state = 2326; break; // >reql -> >reqle - case 2330: state = 2331; break; // >reqql -> >reqqle - case 2334: state = 2335; break; // >rl -> >rle - case 2341: state = 2342; break; // &gv -> &gve - case 2345: state = 2346; break; // &gvertn -> &gvertne - case 2353: state = 2354; break; // &Hac -> &Hace - case 2356: state = 2397; break; // &h -> &he - case 2419: state = 2420; break; // &Hilb -> &Hilbe - case 2426: state = 2427; break; // &HilbertSpac -> &HilbertSpace - case 2429: state = 2430; break; // &hks -> &hkse - case 2450: state = 2451; break; // &hookl -> &hookle - case 2488: state = 2489; break; // &HorizontalLin -> &HorizontalLine - case 2530: state = 2531; break; // &hyph -> &hyphe - case 2537: state = 2538; break; // &Iacut -> Í - case 2539: state = 2561; break; // &i -> &ie - case 2543: state = 2544; break; // &iacut -> í - case 2575: state = 2576; break; // &Igrav -> Ì - case 2580: state = 2581; break; // &igrav -> ì - case 2612: state = 2613; break; // &imag -> &image - case 2623: state = 2624; break; // &imaglin -> &imagline - case 2633: state = 2634; break; // &imp -> &impe - case 2638: state = 2639; break; // &Impli -> &Implie - case 2644: state = 2645; break; // &incar -> &incare - case 2650: state = 2651; break; // &infinti -> &infintie - case 2657: state = 2667; break; // &Int -> &Inte - case 2658: state = 2662; break; // &int -> &inte - case 2663: state = 2664; break; // &integ -> &intege - case 2677: state = 2678; break; // &Inters -> &Interse - case 2698: state = 2699; break; // &Invisibl -> &Invisible - case 2707: state = 2708; break; // &InvisibleTim -> &InvisibleTime - case 2736: state = 2737; break; // &iqu -> &ique - case 2759: state = 2760; break; // &Itild -> &Itilde - case 2763: state = 2764; break; // &itild -> &itilde - case 2803: state = 2809; break; // &Js -> &Jse - case 2806: state = 2813; break; // &js -> &jse - case 2836: state = 2837; break; // &Kc -> &Kce - case 2841: state = 2842; break; // &kc -> &kce - case 2853: state = 2854; break; // &kgr -> &kgre - case 2854: state = 2855; break; // &kgre -> &kgree - case 2881: state = 3032; break; // &l -> &le - case 2886: state = 3033; break; // &L -> &Le - case 2890: state = 2891; break; // &Lacut -> &Lacute - case 2892: state = 2897; break; // &la -> &lae - case 2895: state = 2896; break; // &lacut -> &lacute - case 2920: state = 2921; break; // &langl -> &langle - case 2926: state = 2927; break; // &Laplac -> &Laplace - case 2956: state = 2964; break; // &lat -> &late - case 2979: state = 2980; break; // &lbrac -> &lbrace - case 2982: state = 2983; break; // &lbrk -> &lbrke - case 2988: state = 2998; break; // &Lc -> &Lce - case 2993: state = 3002; break; // &lc -> &lce - case 3039: state = 3040; break; // &LeftAngl -> &LeftAngle - case 3045: state = 3046; break; // &LeftAngleBrack -> &LeftAngleBracke - case 3081: state = 3082; break; // &LeftC -> &LeftCe - case 3092: state = 3093; break; // &LeftDoubl -> &LeftDouble - case 3098: state = 3099; break; // &LeftDoubleBrack -> &LeftDoubleBracke - case 3103: state = 3104; break; // &LeftDownT -> &LeftDownTe - case 3104: state = 3105; break; // &LeftDownTe -> &LeftDownTee - case 3106: state = 3107; break; // &LeftDownTeeV -> &LeftDownTeeVe - case 3112: state = 3113; break; // &LeftDownV -> &LeftDownVe - case 3139: state = 3140; break; // &leftl -> &leftle - case 3198: state = 3199; break; // &LeftRightV -> &LeftRightVe - case 3204: state = 3205; break; // &LeftT -> &LeftTe - case 3205: state = 3206; break; // &LeftTe -> &LeftTee - case 3212: state = 3213; break; // &LeftTeeV -> &LeftTeeVe - case 3220: state = 3221; break; // &leftthr -> &leftthre - case 3221: state = 3222; break; // &leftthre -> &leftthree - case 3225: state = 3226; break; // &leftthreetim -> &leftthreetime - case 3233: state = 3234; break; // &LeftTriangl -> &LeftTriangle - case 3249: state = 3250; break; // &LeftUpDownV -> &LeftUpDownVe - case 3255: state = 3256; break; // &LeftUpT -> &LeftUpTe - case 3256: state = 3257; break; // &LeftUpTe -> &LeftUpTee - case 3258: state = 3259; break; // &LeftUpTeeV -> &LeftUpTeeVe - case 3264: state = 3265; break; // &LeftUpV -> &LeftUpVe - case 3273: state = 3274; break; // &LeftV -> &LeftVe - case 3299: state = 3300; break; // &lesg -> &lesge - case 3302: state = 3312; break; // &less -> &lesse - case 3329: state = 3330; break; // &LessEqualGr -> &LessEqualGre - case 3332: state = 3333; break; // &LessEqualGreat -> &LessEqualGreate - case 3345: state = 3346; break; // &LessGr -> &LessGre - case 3348: state = 3349; break; // &LessGreat -> &LessGreate - case 3354: state = 3355; break; // &LessL -> &LessLe - case 3374: state = 3375; break; // &LessTild -> &LessTilde - case 3408: state = 3419; break; // &Ll -> &Lle - case 3416: state = 3417; break; // &llcorn -> &llcorne - case 3450: state = 3451; break; // &lmoustach -> &lmoustache - case 3452: state = 3460; break; // &ln -> &lne - case 3478: state = 3479; break; // &LongL -> &LongLe - case 3487: state = 3488; break; // &Longl -> &Longle - case 3498: state = 3499; break; // &longl -> &longle - case 3580: state = 3581; break; // &looparrowl -> &looparrowle - case 3600: state = 3601; break; // &lotim -> &lotime - case 3610: state = 3611; break; // &Low -> &Lowe - case 3613: state = 3614; break; // &LowerL -> &LowerLe - case 3632: state = 3633; break; // &loz -> &loze - case 3635: state = 3636; break; // &lozeng -> &lozenge - case 3650: state = 3651; break; // &lrcorn -> &lrcorne - case 3674: state = 3675; break; // &lsim -> &lsime - case 3701: state = 3702; break; // <hr -> <hre - case 3702: state = 3703; break; // <hre -> <hree - case 3705: state = 3706; break; // <im -> <ime - case 3713: state = 3714; break; // <qu -> <que - case 3718: state = 3719; break; // <ri -> <rie - case 3735: state = 3736; break; // &lv -> &lve - case 3739: state = 3740; break; // &lvertn -> &lvertne - case 3745: state = 3792; break; // &m -> &me - case 3749: state = 3750; break; // &mal -> &male - case 3751: state = 3752; break; // &malt -> &malte - case 3753: state = 3754; break; // &maltes -> &maltese - case 3755: state = 3804; break; // &M -> &Me - case 3766: state = 3767; break; // &mapstol -> &mapstole - case 3773: state = 3774; break; // &mark -> &marke - case 3796: state = 3797; break; // &measur -> &measure - case 3802: state = 3803; break; // &measuredangl -> &measuredangle - case 3812: state = 3813; break; // &MediumSpac -> &MediumSpace - case 3866: state = 3867; break; // &mod -> &mode - case 3897: state = 3970; break; // &n -> &ne - case 3902: state = 3984; break; // &N -> &Ne - case 3906: state = 3907; break; // &Nacut -> &Nacute - case 3910: state = 3911; break; // &nacut -> &nacute - case 3935: state = 3936; break; // &nbump -> &nbumpe - case 3937: state = 3952; break; // &nc -> &nce - case 3940: state = 3948; break; // &Nc -> &Nce - case 3989: state = 3990; break; // &Negativ -> &Negative - case 3991: state = 3992; break; // &NegativeM -> &NegativeMe - case 4000: state = 4001; break; // &NegativeMediumSpac -> &NegativeMediumSpace - case 4010: state = 4011; break; // &NegativeThickSpac -> &NegativeThickSpace - case 4016: state = 4017; break; // &NegativeThinSpac -> &NegativeThinSpace - case 4018: state = 4019; break; // &NegativeV -> &NegativeVe - case 4029: state = 4030; break; // &NegativeVeryThinSpac -> &NegativeVeryThinSpace - case 4035: state = 4036; break; // &nes -> &nese - case 4042: state = 4043; break; // &Nest -> &Neste - case 4046: state = 4047; break; // &NestedGr -> &NestedGre - case 4049: state = 4050; break; // &NestedGreat -> &NestedGreate - case 4053: state = 4054; break; // &NestedGreaterGr -> &NestedGreaterGre - case 4056: state = 4057; break; // &NestedGreaterGreat -> &NestedGreaterGreate - case 4059: state = 4060; break; // &NestedL -> &NestedLe - case 4063: state = 4064; break; // &NestedLessL -> &NestedLessLe - case 4070: state = 4071; break; // &NewLin -> &NewLine - case 4081: state = 4083; break; // &ng -> &nge - case 4121: state = 4131; break; // &nl -> &nle - case 4132: state = 4133; break; // &nL -> &nLe - case 4184: state = 4185; break; // &nltri -> &nltrie - case 4192: state = 4193; break; // &NoBr -> &NoBre - case 4198: state = 4199; break; // &NonBr -> &NonBre - case 4208: state = 4209; break; // &NonBreakingSpac -> &NonBreakingSpace - case 4222: state = 4223; break; // &NotCongru -> &NotCongrue - case 4235: state = 4236; break; // &NotDoubl -> &NotDouble - case 4237: state = 4238; break; // &NotDoubleV -> &NotDoubleVe - case 4249: state = 4250; break; // &NotEl -> &NotEle - case 4251: state = 4252; break; // &NotElem -> &NotEleme - case 4262: state = 4263; break; // &NotEqualTild -> &NotEqualTilde - case 4270: state = 4271; break; // &NotGr -> &NotGre - case 4273: state = 4274; break; // &NotGreat -> &NotGreate - case 4291: state = 4292; break; // &NotGreaterGr -> &NotGreaterGre - case 4294: state = 4295; break; // &NotGreaterGreat -> &NotGreaterGreate - case 4297: state = 4298; break; // &NotGreaterL -> &NotGreaterLe - case 4314: state = 4315; break; // &NotGreaterTild -> &NotGreaterTilde - case 4343: state = 4344; break; // &NotL -> &NotLe - case 4353: state = 4354; break; // &NotLeftTriangl -> &NotLeftTriangle - case 4371: state = 4372; break; // &NotLessGr -> &NotLessGre - case 4374: state = 4375; break; // &NotLessGreat -> &NotLessGreate - case 4377: state = 4378; break; // &NotLessL -> &NotLessLe - case 4394: state = 4395; break; // &NotLessTild -> &NotLessTilde - case 4396: state = 4397; break; // &NotN -> &NotNe - case 4399: state = 4400; break; // &NotNest -> &NotNeste - case 4403: state = 4404; break; // &NotNestedGr -> &NotNestedGre - case 4406: state = 4407; break; // &NotNestedGreat -> &NotNestedGreate - case 4410: state = 4411; break; // &NotNestedGreaterGr -> &NotNestedGreaterGre - case 4413: state = 4414; break; // &NotNestedGreaterGreat -> &NotNestedGreaterGreate - case 4416: state = 4417; break; // &NotNestedL -> &NotNestedLe - case 4420: state = 4421; break; // &NotNestedLessL -> &NotNestedLessLe - case 4431: state = 4432; break; // &NotPr -> &NotPre - case 4433: state = 4434; break; // &NotPrec -> &NotPrece - case 4435: state = 4436; break; // &NotPreced -> &NotPrecede - case 4453: state = 4454; break; // &NotR -> &NotRe - case 4455: state = 4456; break; // &NotRev -> &NotReve - case 4458: state = 4459; break; // &NotRevers -> &NotReverse - case 4461: state = 4462; break; // &NotReverseEl -> &NotReverseEle - case 4463: state = 4464; break; // &NotReverseElem -> &NotReverseEleme - case 4477: state = 4478; break; // &NotRightTriangl -> &NotRightTriangle - case 4491: state = 4492; break; // &NotSquar -> &NotSquare - case 4496: state = 4497; break; // &NotSquareSubs -> &NotSquareSubse - case 4504: state = 4505; break; // &NotSquareSup -> &NotSquareSupe - case 4507: state = 4508; break; // &NotSquareSupers -> &NotSquareSuperse - case 4517: state = 4518; break; // &NotSubs -> &NotSubse - case 4526: state = 4527; break; // &NotSucc -> &NotSucce - case 4527: state = 4528; break; // &NotSucce -> &NotSuccee - case 4549: state = 4550; break; // &NotSucceedsTild -> &NotSucceedsTilde - case 4551: state = 4552; break; // &NotSup -> &NotSupe - case 4554: state = 4555; break; // &NotSupers -> &NotSuperse - case 4565: state = 4566; break; // &NotTild -> &NotTilde - case 4584: state = 4585; break; // &NotTildeTild -> &NotTildeTilde - case 4586: state = 4587; break; // &NotV -> &NotVe - case 4602: state = 4603; break; // &nparall -> &nparalle - case 4613: state = 4617; break; // &npr -> &npre - case 4615: state = 4616; break; // &nprcu -> &nprcue - case 4618: state = 4619; break; // &nprec -> &nprece - case 4651: state = 4652; break; // &nrtri -> &nrtrie - case 4654: state = 4658; break; // &nsc -> &nsce - case 4656: state = 4657; break; // &nsccu -> &nsccue - case 4675: state = 4676; break; // &nshortparall -> &nshortparalle - case 4679: state = 4680; break; // &nsim -> &nsime - case 4691: state = 4692; break; // &nsqsub -> &nsqsube - case 4693: state = 4694; break; // &nsqsup -> &nsqsupe - case 4696: state = 4698; break; // &nsub -> &nsube - case 4699: state = 4700; break; // &nsubs -> &nsubse - case 4701: state = 4702; break; // &nsubset -> &nsubsete - case 4706: state = 4707; break; // &nsucc -> &nsucce - case 4709: state = 4711; break; // &nsup -> &nsupe - case 4712: state = 4713; break; // &nsups -> &nsupse - case 4714: state = 4715; break; // &nsupset -> &nsupsete - case 4724: state = 4725; break; // &Ntild -> Ñ - case 4728: state = 4729; break; // &ntild -> ñ - case 4737: state = 4738; break; // &ntriangl -> &ntriangle - case 4739: state = 4740; break; // &ntrianglel -> &ntrianglele - case 4742: state = 4743; break; // &ntriangleleft -> &ntrianglelefte - case 4749: state = 4750; break; // &ntriangleright -> &ntrianglerighte - case 4754: state = 4755; break; // &num -> &nume - case 4780: state = 4781; break; // &nvg -> &nvge - case 4792: state = 4796; break; // &nvl -> &nvle - case 4799: state = 4800; break; // &nvltri -> &nvltrie - case 4807: state = 4808; break; // &nvrtri -> &nvrtrie - case 4823: state = 4824; break; // &nwn -> &nwne - case 4831: state = 4832; break; // &Oacut -> Ó - case 4833: state = 4876; break; // &o -> &oe - case 4837: state = 4838; break; // &oacut -> ó - case 4893: state = 4894; break; // &Ograv -> Ò - case 4897: state = 4898; break; // &ograv -> ò - case 4920: state = 4921; break; // &olin -> &oline - case 4923: state = 4931; break; // &Om -> &Ome - case 4927: state = 4934; break; // &om -> &ome - case 4957: state = 4984; break; // &op -> &ope - case 4960: state = 4961; break; // &Op -> &Ope - case 4972: state = 4973; break; // &OpenCurlyDoubl -> &OpenCurlyDouble - case 4977: state = 4978; break; // &OpenCurlyDoubleQuot -> &OpenCurlyDoubleQuote - case 4982: state = 4983; break; // &OpenCurlyQuot -> &OpenCurlyQuote - case 4995: state = 4996; break; // &ord -> &orde - case 5011: state = 5012; break; // &orslop -> &orslope - case 5034: state = 5035; break; // &Otild -> Õ - case 5039: state = 5040; break; // &otild -> õ - case 5041: state = 5042; break; // &Otim -> &Otime - case 5044: state = 5045; break; // &otim -> &otime - case 5059: state = 5060; break; // &Ov -> &Ove - case 5067: state = 5068; break; // &OverBrac -> &OverBrace - case 5069: state = 5070; break; // &OverBrack -> &OverBracke - case 5074: state = 5075; break; // &OverPar -> &OverPare - case 5078: state = 5079; break; // &OverParenth -> &OverParenthe - case 5083: state = 5108; break; // &p -> &pe - case 5088: state = 5089; break; // ¶ll -> ¶lle - case 5120: state = 5121; break; // &pert -> &perte - case 5138: state = 5139; break; // &phon -> &phone - case 5159: state = 5171; break; // &plus -> &pluse - case 5194: state = 5195; break; // &Poincar -> &Poincare - case 5199: state = 5200; break; // &Poincareplan -> &Poincareplane - case 5215: state = 5238; break; // &Pr -> &Pre - case 5216: state = 5223; break; // &pr -> &pre - case 5220: state = 5221; break; // &prcu -> &prcue - case 5224: state = 5264; break; // &prec -> &prece - case 5235: state = 5236; break; // &preccurly -> &preccurlye - case 5239: state = 5240; break; // &Prec -> &Prece - case 5241: state = 5242; break; // &Preced -> &Precede - case 5262: state = 5263; break; // &PrecedesTild -> &PrecedesTilde - case 5266: state = 5273; break; // &precn -> &precne - case 5283: state = 5284; break; // &Prim -> &Prime - case 5286: state = 5287; break; // &prim -> &prime - case 5310: state = 5311; break; // &proflin -> &profline - case 5332: state = 5333; break; // &prur -> &prure - case 5366: state = 5367; break; // &qprim -> &qprime - case 5374: state = 5387; break; // &qu -> &que - case 5376: state = 5377; break; // &quat -> &quate - case 5389: state = 5390; break; // &quest -> &queste - case 5397: state = 5541; break; // &r -> &re - case 5402: state = 5417; break; // &ra -> &rae - case 5403: state = 5404; break; // &rac -> &race - case 5405: state = 5540; break; // &R -> &Re - case 5409: state = 5410; break; // &Racut -> &Racute - case 5412: state = 5413; break; // &racut -> &racute - case 5426: state = 5428; break; // &rang -> &range - case 5429: state = 5430; break; // &rangl -> &rangle - case 5493: state = 5494; break; // &rbrac -> &rbrace - case 5496: state = 5497; break; // &rbrk -> &rbrke - case 5502: state = 5512; break; // &Rc -> &Rce - case 5507: state = 5516; break; // &rc -> &rce - case 5545: state = 5546; break; // &realin -> &realine - case 5557: state = 5558; break; // &Rev -> &Reve - case 5560: state = 5561; break; // &Revers -> &Reverse - case 5563: state = 5564; break; // &ReverseEl -> &ReverseEle - case 5565: state = 5566; break; // &ReverseElem -> &ReverseEleme - case 5624: state = 5625; break; // &RightAngl -> &RightAngle - case 5630: state = 5631; break; // &RightAngleBrack -> &RightAngleBracke - case 5654: state = 5655; break; // &RightArrowL -> &RightArrowLe - case 5667: state = 5668; break; // &RightC -> &RightCe - case 5678: state = 5679; break; // &RightDoubl -> &RightDouble - case 5684: state = 5685; break; // &RightDoubleBrack -> &RightDoubleBracke - case 5689: state = 5690; break; // &RightDownT -> &RightDownTe - case 5690: state = 5691; break; // &RightDownTe -> &RightDownTee - case 5692: state = 5693; break; // &RightDownTeeV -> &RightDownTeeVe - case 5698: state = 5699; break; // &RightDownV -> &RightDownVe - case 5725: state = 5726; break; // &rightl -> &rightle - case 5764: state = 5765; break; // &RightT -> &RightTe - case 5765: state = 5766; break; // &RightTe -> &RightTee - case 5772: state = 5773; break; // &RightTeeV -> &RightTeeVe - case 5780: state = 5781; break; // &rightthr -> &rightthre - case 5781: state = 5782; break; // &rightthre -> &rightthree - case 5785: state = 5786; break; // &rightthreetim -> &rightthreetime - case 5793: state = 5794; break; // &RightTriangl -> &RightTriangle - case 5809: state = 5810; break; // &RightUpDownV -> &RightUpDownVe - case 5815: state = 5816; break; // &RightUpT -> &RightUpTe - case 5816: state = 5817; break; // &RightUpTe -> &RightUpTee - case 5818: state = 5819; break; // &RightUpTeeV -> &RightUpTeeVe - case 5824: state = 5825; break; // &RightUpV -> &RightUpVe - case 5833: state = 5834; break; // &RightV -> &RightVe - case 5851: state = 5852; break; // &risingdots -> &risingdotse - case 5869: state = 5870; break; // &rmoustach -> &rmoustache - case 5896: state = 5897; break; // &rotim -> &rotime - case 5906: state = 5907; break; // &RoundImpli -> &RoundImplie - case 5953: state = 5954; break; // &rthr -> &rthre - case 5954: state = 5955; break; // &rthre -> &rthree - case 5957: state = 5958; break; // &rtim -> &rtime - case 5961: state = 5962; break; // &rtri -> &rtrie - case 5969: state = 5970; break; // &Rul -> &Rule - case 5971: state = 5972; break; // &RuleD -> &RuleDe - case 5975: state = 5976; break; // &RuleDelay -> &RuleDelaye - case 5989: state = 5990; break; // &Sacut -> &Sacute - case 5991: state = 6053; break; // &s -> &se - case 5995: state = 5996; break; // &sacut -> &sacute - case 6001: state = 6017; break; // &Sc -> &Sce - case 6002: state = 6016; break; // &sc -> &sce - case 6013: state = 6014; break; // &sccu -> &sccue - case 6050: state = 6052; break; // &sdot -> &sdote - case 6117: state = 6118; break; // &ShortL -> &ShortLe - case 6137: state = 6138; break; // &shortparall -> &shortparalle - case 6168: state = 6172; break; // &sim -> &sime - case 6178: state = 6179; break; // &simn -> &simne - case 6200: state = 6201; break; // &SmallCircl -> &SmallCircle - case 6202: state = 6217; break; // &sm -> &sme - case 6206: state = 6207; break; // &smalls -> &smallse - case 6225: state = 6226; break; // &smil -> &smile - case 6227: state = 6228; break; // &smt -> &smte - case 6251: state = 6252; break; // &spad -> &spade - case 6271: state = 6272; break; // &sqsub -> &sqsube - case 6273: state = 6274; break; // &sqsubs -> &sqsubse - case 6275: state = 6276; break; // &sqsubset -> &sqsubsete - case 6278: state = 6279; break; // &sqsup -> &sqsupe - case 6280: state = 6281; break; // &sqsups -> &sqsupse - case 6282: state = 6283; break; // &sqsupset -> &sqsupsete - case 6288: state = 6289; break; // &Squar -> &Square - case 6291: state = 6292; break; // &squar -> &square - case 6295: state = 6296; break; // &SquareInt -> &SquareInte - case 6298: state = 6299; break; // &SquareInters -> &SquareInterse - case 6308: state = 6309; break; // &SquareSubs -> &SquareSubse - case 6316: state = 6317; break; // &SquareSup -> &SquareSupe - case 6319: state = 6320; break; // &SquareSupers -> &SquareSuperse - case 6341: state = 6344; break; // &ss -> &sse - case 6350: state = 6351; break; // &ssmil -> &ssmile - case 6368: state = 6369; break; // &straight -> &straighte - case 6384: state = 6389; break; // &sub -> &sube - case 6397: state = 6399; break; // &subn -> &subne - case 6408: state = 6409; break; // &Subs -> &Subse - case 6411: state = 6412; break; // &subs -> &subse - case 6413: state = 6414; break; // &subset -> &subsete - case 6422: state = 6423; break; // &subsetn -> &subsetne - case 6432: state = 6472; break; // &succ -> &succe - case 6443: state = 6444; break; // &succcurly -> &succcurlye - case 6447: state = 6448; break; // &Succ -> &Succe - case 6448: state = 6449; break; // &Succe -> &Succee - case 6470: state = 6471; break; // &SucceedsTild -> &SucceedsTilde - case 6474: state = 6481; break; // &succn -> &succne - case 6499: state = 6515; break; // &Sup -> &Supe - case 6500: state = 6511; break; // &sup -> &supe - case 6517: state = 6518; break; // &Supers -> &Superse - case 6539: state = 6541; break; // &supn -> &supne - case 6546: state = 6547; break; // &Sups -> &Supse - case 6549: state = 6550; break; // &sups -> &supse - case 6551: state = 6552; break; // &supset -> &supsete - case 6555: state = 6556; break; // &supsetn -> &supsetne - case 6586: state = 6620; break; // &t -> &te - case 6589: state = 6590; break; // &targ -> &targe - case 6597: state = 6607; break; // &Tc -> &Tce - case 6602: state = 6611; break; // &tc -> &tce - case 6622: state = 6623; break; // &telr -> &telre - case 6629: state = 6630; break; // &th -> &the - case 6631: state = 6632; break; // &ther -> &there - case 6634: state = 6635; break; // &Th -> &The - case 6636: state = 6637; break; // &Ther -> &There - case 6640: state = 6641; break; // &Therefor -> &Therefore - case 6644: state = 6645; break; // &therefor -> &therefore - case 6672: state = 6673; break; // &ThickSpac -> &ThickSpace - case 6681: state = 6682; break; // &ThinSpac -> &ThinSpace - case 6698: state = 6699; break; // &Tild -> &Tilde - case 6702: state = 6703; break; // &tild -> &tilde - case 6721: state = 6722; break; // &TildeTild -> &TildeTilde - case 6723: state = 6724; break; // &tim -> &time - case 6732: state = 6733; break; // &to -> &toe - case 6754: state = 6755; break; // &tprim -> &tprime - case 6762: state = 6763; break; // &trad -> &trade - case 6764: state = 6791; break; // &tri -> &trie - case 6768: state = 6769; break; // &triangl -> &triangle - case 6774: state = 6775; break; // &trianglel -> &trianglele - case 6777: state = 6778; break; // &triangleleft -> &trianglelefte - case 6785: state = 6786; break; // &triangleright -> &trianglerighte - case 6800: state = 6801; break; // &Tripl -> &Triple - case 6813: state = 6814; break; // &tritim -> &tritime - case 6815: state = 6816; break; // &trp -> &trpe - case 6850: state = 6851; break; // &twoh -> &twohe - case 6854: state = 6855; break; // &twoheadl -> &twoheadle - case 6877: state = 6878; break; // &Uacut -> Ú - case 6883: state = 6884; break; // &uacut -> ú - case 6897: state = 6904; break; // &Ubr -> &Ubre - case 6901: state = 6907; break; // &ubr -> &ubre - case 6905: state = 6906; break; // &Ubrev -> &Ubreve - case 6908: state = 6909; break; // &ubrev -> &ubreve - case 6947: state = 6948; break; // &Ugrav -> Ù - case 6952: state = 6953; break; // &ugrav -> ù - case 6969: state = 6970; break; // &ulcorn -> &ulcorne - case 6988: state = 6989; break; // &Und -> &Unde - case 6996: state = 6997; break; // &UnderBrac -> &UnderBrace - case 6998: state = 6999; break; // &UnderBrack -> &UnderBracke - case 7003: state = 7004; break; // &UnderPar -> &UnderPare - case 7007: state = 7008; break; // &UnderParenth -> &UnderParenthe - case 7105: state = 7106; break; // &upharpoonl -> &upharpoonle - case 7117: state = 7118; break; // &Upp -> &Uppe - case 7120: state = 7121; break; // &UpperL -> &UpperLe - case 7150: state = 7151; break; // &UpT -> &UpTe - case 7151: state = 7152; break; // &UpTe -> &UpTee - case 7170: state = 7171; break; // &urcorn -> &urcorne - case 7199: state = 7200; break; // &Utild -> &Utilde - case 7203: state = 7204; break; // &utild -> &utilde - case 7221: state = 7222; break; // &uwangl -> &uwangle - case 7223: state = 7338; break; // &v -> &ve - case 7229: state = 7230; break; // &var -> &vare - case 7271: state = 7272; break; // &varsubs -> &varsubse - case 7274: state = 7275; break; // &varsubsetn -> &varsubsetne - case 7279: state = 7280; break; // &varsups -> &varsupse - case 7282: state = 7283; break; // &varsupsetn -> &varsupsetne - case 7287: state = 7288; break; // &varth -> &varthe - case 7296: state = 7297; break; // &vartriangl -> &vartriangle - case 7298: state = 7299; break; // &vartrianglel -> &vartrianglele - case 7307: state = 7336; break; // &V -> &Ve - case 7336: state = 7337; break; // &Ve -> &Vee - case 7338: state = 7339; break; // &ve -> &vee - case 7339: state = 7343; break; // &vee -> &veee - case 7368: state = 7369; break; // &VerticalLin -> &VerticalLine - case 7370: state = 7371; break; // &VerticalS -> &VerticalSe - case 7382: state = 7383; break; // &VerticalTild -> &VerticalTilde - case 7392: state = 7393; break; // &VeryThinSpac -> &VeryThinSpace - case 7429: state = 7431; break; // &vsubn -> &vsubne - case 7433: state = 7435; break; // &vsupn -> &vsupne - case 7447: state = 7462; break; // &W -> &We - case 7452: state = 7457; break; // &w -> &we - case 7464: state = 7465; break; // &Wedg -> &Wedge - case 7466: state = 7467; break; // &wedg -> &wedge - case 7469: state = 7470; break; // &wei -> &weie - case 7484: state = 7485; break; // &wr -> &wre - case 7549: state = 7550; break; // &xotim -> &xotime - case 7576: state = 7577; break; // &xv -> &xve - case 7577: state = 7578; break; // &xve -> &xvee - case 7579: state = 7580; break; // &xw -> &xwe - case 7582: state = 7583; break; // &xwedg -> &xwedge - case 7588: state = 7589; break; // &Yacut -> Ý - case 7590: state = 7610; break; // &y -> &ye - case 7594: state = 7595; break; // &yacut -> ý - case 7645: state = 7680; break; // &Z -> &Ze - case 7649: state = 7650; break; // &Zacut -> &Zacute - case 7651: state = 7675; break; // &z -> &ze - case 7655: state = 7656; break; // &zacut -> &zacute - case 7675: state = 7676; break; // &ze -> &zee - case 7691: state = 7692; break; // &ZeroWidthSpac -> &ZeroWidthSpace - default: return false; - } - break; - case 'f': - switch (state) { - case 0: state = 1964; break; // & -> &f - case 1: state = 47; break; // &A -> &Af - case 7: state = 46; break; // &a -> &af - case 61: state = 62; break; // &ale -> &alef - case 109: state = 115; break; // &angmsda -> &angmsdaf - case 139: state = 140; break; // &Aop -> &Aopf - case 141: state = 142; break; // &aop -> &aopf - case 222: state = 331; break; // &b -> &bf - case 247: state = 329; break; // &B -> &Bf - case 426: state = 427; break; // &blacktrianglele -> &blacktrianglelef - case 457: state = 458; break; // &Bop -> &Bopf - case 460: state = 461; break; // &bop -> &bopf - case 583: state = 712; break; // &C -> &Cf - case 589: state = 714; break; // &c -> &cf - case 618: state = 619; break; // &CapitalDi -> &CapitalDif - case 619: state = 620; break; // &CapitalDif -> &CapitalDiff - case 733: state = 791; break; // &cir -> &cirf - case 745: state = 746; break; // &circlearrowle -> &circlearrowlef - case 871: state = 872; break; // &comp -> &compf - case 913: state = 914; break; // &Cop -> &Copf - case 915: state = 916; break; // &cop -> &copf - case 1062: state = 1063; break; // &curvearrowle -> &curvearrowlef - case 1091: state = 1180; break; // &D -> &Df - case 1097: state = 1175; break; // &d -> &df - case 1191: state = 1244; break; // &Di -> &Dif - case 1244: state = 1245; break; // &Dif -> &Diff - case 1297: state = 1298; break; // &Dop -> &Dopf - case 1299: state = 1300; break; // &dop -> &dopf - case 1373: state = 1374; break; // &DoubleLe -> &DoubleLef - case 1398: state = 1399; break; // &DoubleLongLe -> &DoubleLongLef - case 1518: state = 1519; break; // &downharpoonle -> &downharpoonlef - case 1527: state = 1528; break; // &DownLe -> &DownLef - case 1629: state = 1630; break; // &dtri -> &dtrif - case 1656: state = 1711; break; // &E -> &Ef - case 1662: state = 1707; break; // &e -> &ef - case 1809: state = 1810; break; // &Eop -> &Eopf - case 1811: state = 1812; break; // &eop -> &eopf - case 1964: state = 1987; break; // &f -> &ff - case 1977: state = 1998; break; // &F -> &Ff - case 2050: state = 2051; break; // &fno -> &fnof - case 2053: state = 2054; break; // &Fop -> &Fopf - case 2056: state = 2057; break; // &fop -> &fopf - case 2074: state = 2075; break; // &Fouriertr -> &Fouriertrf - case 2118: state = 2189; break; // &g -> &gf - case 2124: state = 2187; break; // &G -> &Gf - case 2223: state = 2224; break; // &Gop -> &Gopf - case 2226: state = 2227; break; // &gop -> &gopf - case 2351: state = 2413; break; // &H -> &Hf - case 2356: state = 2415; break; // &h -> &hf - case 2362: state = 2363; break; // &hal -> &half - case 2451: state = 2452; break; // &hookle -> &hooklef - case 2470: state = 2471; break; // &Hop -> &Hopf - case 2472: state = 2473; break; // &hop -> &hopf - case 2533: state = 2569; break; // &I -> &If - case 2539: state = 2567; break; // &i -> &if - case 2567: state = 2568; break; // &if -> &iff - case 2589: state = 2590; break; // &iin -> &iinf - case 2631: state = 2632; break; // &imo -> &imof - case 2641: state = 2646; break; // &in -> &inf - case 2723: state = 2724; break; // &Iop -> &Iopf - case 2725: state = 2726; break; // &iop -> &iopf - case 2777: state = 2789; break; // &J -> &Jf - case 2782: state = 2791; break; // &j -> &jf - case 2798: state = 2799; break; // &Jop -> &Jopf - case 2801: state = 2802; break; // &jop -> &jopf - case 2825: state = 2848; break; // &K -> &Kf - case 2830: state = 2850; break; // &k -> &kf - case 2870: state = 2871; break; // &Kop -> &Kopf - case 2873: state = 2874; break; // &kop -> &kopf - case 2881: state = 3376; break; // &l -> &lf - case 2886: state = 3385; break; // &L -> &Lf - case 2929: state = 2930; break; // &Laplacetr -> &Laplacetrf - case 2939: state = 2943; break; // &larr -> &larrf - case 2940: state = 2941; break; // &larrb -> &larrbf - case 3032: state = 3057; break; // &le -> &lef - case 3033: state = 3034; break; // &Le -> &Lef - case 3140: state = 3141; break; // &leftle -> &leftlef - case 3419: state = 3420; break; // &Lle -> &Llef - case 3479: state = 3480; break; // &LongLe -> &LongLef - case 3488: state = 3489; break; // &Longle -> &Longlef - case 3499: state = 3500; break; // &longle -> &longlef - case 3581: state = 3582; break; // &looparrowle -> &looparrowlef - case 3589: state = 3594; break; // &lop -> &lopf - case 3592: state = 3593; break; // &Lop -> &Lopf - case 3614: state = 3615; break; // &LowerLe -> &LowerLef - case 3632: state = 3637; break; // &loz -> &lozf - case 3718: state = 3720; break; // <ri -> <rif - case 3745: state = 3823; break; // &m -> &mf - case 3755: state = 3821; break; // &M -> &Mf - case 3767: state = 3768; break; // &mapstole -> &mapstolef - case 3819: state = 3820; break; // &Mellintr -> &Mellintrf - case 3871: state = 3872; break; // &Mop -> &Mopf - case 3873: state = 3874; break; // &mop -> &mopf - case 3897: state = 4079; break; // &n -> &nf - case 3902: state = 4077; break; // &N -> &Nf - case 4131: state = 4141; break; // &nle -> &nlef - case 4133: state = 4134; break; // &nLe -> &nLef - case 4210: state = 4211; break; // &Nop -> &Nopf - case 4213: state = 4214; break; // &nop -> &nopf - case 4344: state = 4345; break; // &NotLe -> &NotLef - case 4740: state = 4741; break; // &ntrianglele -> &ntrianglelef - case 4788: state = 4789; break; // &nvin -> &nvinf - case 4827: state = 4884; break; // &O -> &Of - case 4833: state = 4880; break; // &o -> &of - case 4952: state = 4953; break; // &Oop -> &Oopf - case 4955: state = 4956; break; // &oop -> &oopf - case 4995: state = 5000; break; // &ord -> ª - case 4998: state = 4999; break; // &ordero -> &orderof - case 5004: state = 5005; break; // &origo -> &origof - case 5083: state = 5126; break; // &p -> &pf - case 5096: state = 5124; break; // &P -> &Pf - case 5144: state = 5145; break; // &pitch -> &pitchf - case 5208: state = 5209; break; // &Pop -> &Popf - case 5210: state = 5211; break; // &pop -> &popf - case 5296: state = 5303; break; // &pro -> &prof - case 5314: state = 5315; break; // &profsur -> &profsurf - case 5348: state = 5349; break; // &Q -> &Qf - case 5351: state = 5352; break; // &q -> &qf - case 5358: state = 5359; break; // &Qop -> &Qopf - case 5361: state = 5362; break; // &qop -> &qopf - case 5397: state = 5592; break; // &r -> &rf - case 5405: state = 5601; break; // &R -> &Rf - case 5439: state = 5446; break; // &rarr -> &rarrf - case 5442: state = 5443; break; // &rarrb -> &rarrbf - case 5655: state = 5656; break; // &RightArrowLe -> &RightArrowLef - case 5726: state = 5727; break; // &rightle -> &rightlef - case 5884: state = 5890; break; // &rop -> &ropf - case 5888: state = 5889; break; // &Rop -> &Ropf - case 5961: state = 5963; break; // &rtri -> &rtrif - case 5985: state = 6081; break; // &S -> &Sf - case 5991: state = 6083; break; // &s -> &sf - case 6118: state = 6119; break; // &ShortLe -> &ShortLef - case 6165: state = 6166; break; // &sigma -> &sigmaf - case 6235: state = 6236; break; // &so -> &sof - case 6245: state = 6246; break; // &Sop -> &Sopf - case 6247: state = 6248; break; // &sop -> &sopf - case 6285: state = 6333; break; // &squ -> &squf - case 6291: state = 6332; break; // &squar -> &squarf - case 6354: state = 6355; break; // &sstar -> &sstarf - case 6361: state = 6362; break; // &star -> &starf - case 6583: state = 6625; break; // &T -> &Tf - case 6586: state = 6627; break; // &t -> &tf - case 6632: state = 6642; break; // &there -> &theref - case 6637: state = 6638; break; // &There -> &Theref - case 6735: state = 6745; break; // &top -> &topf - case 6743: state = 6744; break; // &Top -> &Topf - case 6775: state = 6776; break; // &trianglele -> &trianglelef - case 6855: state = 6856; break; // &twoheadle -> &twoheadlef - case 6873: state = 6941; break; // &U -> &Uf - case 6879: state = 6936; break; // &u -> &uf - case 7027: state = 7028; break; // &Uop -> &Uopf - case 7029: state = 7030; break; // &uop -> &uopf - case 7106: state = 7107; break; // &upharpoonle -> &upharpoonlef - case 7121: state = 7122; break; // &UpperLe -> &UpperLef - case 7206: state = 7207; break; // &utri -> &utrif - case 7223: state = 7396; break; // &v -> &vf - case 7299: state = 7300; break; // &vartrianglele -> &vartrianglelef - case 7307: state = 7394; break; // &V -> &Vf - case 7408: state = 7409; break; // &Vop -> &Vopf - case 7411: state = 7412; break; // &vop -> &vopf - case 7447: state = 7473; break; // &W -> &Wf - case 7452: state = 7475; break; // &w -> &wf - case 7478: state = 7479; break; // &Wop -> &Wopf - case 7481: state = 7482; break; // &wop -> &wopf - case 7495: state = 7511; break; // &x -> &xf - case 7508: state = 7509; break; // &X -> &Xf - case 7540: state = 7541; break; // &Xop -> &Xopf - case 7542: state = 7543; break; // &xop -> &xopf - case 7584: state = 7612; break; // &Y -> &Yf - case 7590: state = 7614; break; // &y -> &yf - case 7623: state = 7624; break; // &Yop -> &Yopf - case 7626: state = 7627; break; // &yop -> &yopf - case 7645: state = 7697; break; // &Z -> &Zf - case 7651: state = 7699; break; // &z -> &zf - case 7678: state = 7679; break; // &zeetr -> &zeetrf - case 7714: state = 7715; break; // &Zop -> &Zopf - case 7717: state = 7718; break; // &zop -> &zopf - default: return false; - } - break; - case 'g': - switch (state) { - case 0: state = 2118; break; // & -> &g - case 1: state = 50; break; // &A -> &Ag - case 7: state = 55; break; // &a -> &ag - case 40: state = 41; break; // &AEli -> Æ - case 44: state = 45; break; // &aeli -> æ - case 83: state = 84; break; // &amal -> &amalg - case 90: state = 102; break; // &an -> &ang - case 109: state = 116; break; // &angmsda -> &angmsdag - case 131: state = 132; break; // &Ao -> &Aog - case 135: state = 136; break; // &ao -> &aog - case 174: state = 175; break; // &Arin -> Å - case 178: state = 179; break; // &arin -> å - case 187: state = 188; break; // &Assi -> &Assig - case 228: state = 229; break; // &backcon -> &backcong - case 267: state = 268; break; // &barwed -> &barwedg - case 279: state = 280; break; // &bcon -> &bcong - case 333: state = 334; break; // &bi -> &big - case 368: state = 369; break; // &bigtrian -> &bigtriang - case 388: state = 389; break; // &bigwed -> &bigwedg - case 404: state = 405; break; // &blacklozen -> &blacklozeng - case 417: state = 418; break; // &blacktrian -> &blacktriang - case 430: state = 431; break; // &blacktriangleri -> &blacktrianglerig - case 749: state = 750; break; // &circlearrowri -> &circlearrowrig - case 821: state = 822; break; // &ClockwiseContourInte -> &ClockwiseContourInteg - case 883: state = 884; break; // &con -> &cong - case 888: state = 889; break; // &Con -> &Cong - case 908: state = 909; break; // &ContourInte -> &ContourInteg - case 956: state = 957; break; // &CounterClockwiseContourInte -> &CounterClockwiseContourInteg - case 1048: state = 1049; break; // &curlywed -> &curlywedg - case 1066: state = 1067; break; // &curvearrowri -> &curvearrowrig - case 1092: state = 1093; break; // &Da -> &Dag - case 1093: state = 1094; break; // &Dag -> &Dagg - case 1098: state = 1099; break; // &da -> &dag - case 1099: state = 1100; break; // &dag -> &dagg - case 1143: state = 1144; break; // &dda -> &ddag - case 1144: state = 1145; break; // &ddag -> &ddagg - case 1161: state = 1162; break; // &de -> ° - case 1228: state = 1255; break; // &di -> &dig - case 1340: state = 1341; break; // &doublebarwed -> &doublebarwedg - case 1357: state = 1358; break; // &DoubleContourInte -> &DoubleContourInteg - case 1382: state = 1383; break; // &DoubleLeftRi -> &DoubleLeftRig - case 1395: state = 1396; break; // &DoubleLon -> &DoubleLong - case 1407: state = 1408; break; // &DoubleLongLeftRi -> &DoubleLongLeftRig - case 1417: state = 1418; break; // &DoubleLongRi -> &DoubleLongRig - case 1427: state = 1428; break; // &DoubleRi -> &DoubleRig - case 1522: state = 1523; break; // &downharpoonri -> &downharpoonrig - case 1531: state = 1532; break; // &DownLeftRi -> &DownLeftRig - case 1560: state = 1561; break; // &DownRi -> &DownRig - case 1640: state = 1641; break; // &dwan -> &dwang - case 1650: state = 1651; break; // &dzi -> &dzig - case 1656: state = 1715; break; // &E -> &Eg - case 1662: state = 1714; break; // &e -> &eg - case 1797: state = 1798; break; // &en -> &eng - case 1801: state = 1802; break; // &Eo -> &Eog - case 1805: state = 1806; break; // &eo -> &eog - case 1848: state = 1849; break; // &eqslant -> &eqslantg - case 1969: state = 1970; break; // &fallin -> &falling - case 1990: state = 1991; break; // &ffili -> &ffilig - case 1993: state = 1994; break; // &ffli -> &fflig - case 1996: state = 1997; break; // &fflli -> &ffllig - case 2003: state = 2004; break; // &fili -> &filig - case 2038: state = 2039; break; // &fjli -> &fjlig - case 2044: state = 2045; break; // &flli -> &fllig - case 2118: state = 2192; break; // &g -> &gg - case 2124: state = 2191; break; // &G -> &Gg - case 2192: state = 2193; break; // &gg -> &ggg - case 2460: state = 2461; break; // &hookri -> &hookrig - case 2533: state = 2572; break; // &I -> &Ig - case 2539: state = 2577; break; // &i -> &ig - case 2598: state = 2599; break; // &IJli -> &IJlig - case 2602: state = 2603; break; // &ijli -> &ijlig - case 2605: state = 2614; break; // &Ima -> &Imag - case 2609: state = 2612; break; // &ima -> &imag - case 2662: state = 2663; break; // &inte -> &integ - case 2667: state = 2668; break; // &Inte -> &Integ - case 2713: state = 2720; break; // &io -> &iog - case 2716: state = 2717; break; // &Io -> &Iog - case 2830: state = 2852; break; // &k -> &kg - case 2881: state = 3388; break; // &l -> &lg - case 2892: state = 2903; break; // &la -> &lag - case 2915: state = 2916; break; // &Lan -> &Lang - case 2917: state = 2918; break; // &lan -> &lang - case 3031: state = 3282; break; // &lE -> &lEg - case 3032: state = 3283; break; // &le -> &leg - case 3037: state = 3038; break; // &LeftAn -> &LeftAng - case 3068: state = 3069; break; // &LeftArrowRi -> &LeftArrowRig - case 3086: state = 3087; break; // &LeftCeilin -> &LeftCeiling - case 3150: state = 3151; break; // &LeftRi -> &LeftRig - case 3160: state = 3161; break; // &Leftri -> &Leftrig - case 3170: state = 3171; break; // &leftri -> &leftrig - case 3191: state = 3192; break; // &leftrightsqui -> &leftrightsquig - case 3231: state = 3232; break; // &LeftTrian -> &LeftTriang - case 3291: state = 3299; break; // &les -> &lesg - case 3302: state = 3351; break; // &less -> &lessg - case 3313: state = 3314; break; // &lesseq -> &lesseqg - case 3317: state = 3318; break; // &lesseqq -> &lesseqqg - case 3468: state = 3469; break; // &loan -> &loang - case 3476: state = 3477; break; // &Lon -> &Long - case 3496: state = 3497; break; // &lon -> &long - case 3508: state = 3509; break; // &LongLeftRi -> &LongLeftRig - case 3518: state = 3519; break; // &Longleftri -> &Longleftrig - case 3528: state = 3529; break; // &longleftri -> &longleftrig - case 3544: state = 3545; break; // &LongRi -> &LongRig - case 3554: state = 3555; break; // &Longri -> &Longrig - case 3564: state = 3565; break; // &longri -> &longrig - case 3585: state = 3586; break; // &looparrowri -> &looparrowrig - case 3623: state = 3624; break; // &LowerRi -> &LowerRig - case 3634: state = 3635; break; // &lozen -> &lozeng - case 3674: state = 3676; break; // &lsim -> &lsimg - case 3800: state = 3801; break; // &measuredan -> &measuredang - case 3897: state = 4081; break; // &n -> &ng - case 3912: state = 3913; break; // &nan -> &nang - case 3957: state = 3958; break; // &ncon -> &ncong - case 3984: state = 3985; break; // &Ne -> &Neg - case 4092: state = 4093; break; // &nG -> &nGg - case 4149: state = 4150; break; // &nLeftri -> &nLeftrig - case 4159: state = 4160; break; // &nleftri -> &nleftrig - case 4203: state = 4204; break; // &NonBreakin -> &NonBreaking - case 4219: state = 4220; break; // &NotCon -> &NotCong - case 4351: state = 4352; break; // &NotLeftTrian -> &NotLeftTriang - case 4467: state = 4468; break; // &NotRi -> &NotRig - case 4475: state = 4476; break; // &NotRightTrian -> &NotRightTriang - case 4631: state = 4632; break; // &nRi -> &nRig - case 4640: state = 4641; break; // &nri -> &nrig - case 4718: state = 4719; break; // &nt -> &ntg - case 4730: state = 4731; break; // &ntl -> &ntlg - case 4735: state = 4736; break; // &ntrian -> &ntriang - case 4746: state = 4747; break; // &ntriangleri -> &ntrianglerig - case 4760: state = 4780; break; // &nv -> &nvg - case 4827: state = 4890; break; // &O -> &Og - case 4833: state = 4887; break; // &o -> &og - case 4874: state = 4875; break; // &OEli -> &OElig - case 4878: state = 4879; break; // &oeli -> &oelig - case 4931: state = 4932; break; // &Ome -> &Omeg - case 4934: state = 4935; break; // &ome -> &omeg - case 5002: state = 5003; break; // &ori -> &orig - case 5423: state = 5424; break; // &Ran -> &Rang - case 5425: state = 5426; break; // &ran -> &rang - case 5541: state = 5556; break; // &re -> ® - case 5617: state = 5618; break; // &Ri -> &Rig - case 5622: state = 5623; break; // &RightAn -> &RightAng - case 5642: state = 5643; break; // &ri -> &rig - case 5672: state = 5673; break; // &RightCeilin -> &RightCeiling - case 5744: state = 5745; break; // &rightri -> &rightrig - case 5757: state = 5758; break; // &rightsqui -> &rightsquig - case 5791: state = 5792; break; // &RightTrian -> &RightTriang - case 5842: state = 5843; break; // &rin -> &ring - case 5846: state = 5847; break; // &risin -> &rising - case 5877: state = 5878; break; // &roan -> &roang - case 5911: state = 5912; break; // &rpar -> &rparg - case 5925: state = 5926; break; // &Rri -> &Rrig - case 6141: state = 6142; break; // &ShortRi -> &ShortRig - case 6158: state = 6159; break; // &Si -> &Sig - case 6162: state = 6163; break; // &si -> &sig - case 6168: state = 6174; break; // &sim -> &simg - case 6365: state = 6366; break; // &strai -> &straig - case 6497: state = 6498; break; // &sun -> &sung - case 6581: state = 6582; break; // &szli -> ß - case 6588: state = 6589; break; // &tar -> &targ - case 6766: state = 6767; break; // &trian -> &triang - case 6782: state = 6783; break; // &triangleri -> &trianglerig - case 6864: state = 6865; break; // &twoheadri -> &twoheadrig - case 6873: state = 6944; break; // &U -> &Ug - case 6879: state = 6949; break; // &u -> &ug - case 7019: state = 7020; break; // &Uo -> &Uog - case 7023: state = 7024; break; // &uo -> &uog - case 7110: state = 7111; break; // &upharpoonri -> &upharpoonrig - case 7130: state = 7131; break; // &UpperRi -> &UpperRig - case 7178: state = 7179; break; // &Urin -> &Uring - case 7181: state = 7182; break; // &urin -> &uring - case 7219: state = 7220; break; // &uwan -> &uwang - case 7225: state = 7226; break; // &van -> &vang - case 7247: state = 7248; break; // &varnothin -> &varnothing - case 7265: state = 7266; break; // &varsi -> &varsig - case 7294: state = 7295; break; // &vartrian -> &vartriang - case 7303: state = 7304; break; // &vartriangleri -> &vartrianglerig - case 7442: state = 7443; break; // &vzi -> &vzig - case 7445: state = 7446; break; // &vzigza -> &vzigzag - case 7458: state = 7466; break; // &wed -> &wedg - case 7463: state = 7464; break; // &Wed -> &Wedg - case 7581: state = 7582; break; // &xwed -> &xwedg - case 7707: state = 7708; break; // &zi -> &zig - default: return false; - } - break; - case 'h': - switch (state) { - case 0: state = 2356; break; // & -> &h - case 66: state = 67; break; // &alep -> &aleph - case 69: state = 70; break; // &Alp -> &Alph - case 72: state = 73; break; // &alp -> &alph - case 109: state = 117; break; // &angmsda -> &angmsdah - case 124: state = 125; break; // &angsp -> &angsph - case 254: state = 255; break; // &Backslas -> &Backslash - case 322: state = 324; break; // &bet -> &beth - case 431: state = 432; break; // &blacktrianglerig -> &blacktrianglerigh - case 470: state = 485; break; // &box -> &boxh - case 518: state = 521; break; // &boxV -> &boxVh - case 519: state = 523; break; // &boxv -> &boxvh - case 562: state = 564; break; // &bsol -> &bsolh - case 583: state = 729; break; // &C -> &Ch - case 589: state = 719; break; // &c -> &ch - case 750: state = 751; break; // &circlearrowrig -> &circlearrowrigh - case 763: state = 764; break; // &circleddas -> &circleddash - case 1067: state = 1068; break; // &curvearrowrig -> &curvearrowrigh - case 1097: state = 1186; break; // &d -> &dh - case 1105: state = 1106; break; // &dalet -> &daleth - case 1114: state = 1115; break; // &das -> &dash - case 1116: state = 1117; break; // &Das -> &Dash - case 1153: state = 1154; break; // &DDotra -> &DDotrah - case 1177: state = 1178; break; // &dfis -> &dfish - case 1383: state = 1384; break; // &DoubleLeftRig -> &DoubleLeftRigh - case 1408: state = 1409; break; // &DoubleLongLeftRig -> &DoubleLongLeftRigh - case 1418: state = 1419; break; // &DoubleLongRig -> &DoubleLongRigh - case 1428: state = 1429; break; // &DoubleRig -> &DoubleRigh - case 1479: state = 1510; break; // &down -> &downh - case 1523: state = 1524; break; // &downharpoonrig -> &downharpoonrigh - case 1532: state = 1533; break; // &DownLeftRig -> &DownLeftRigh - case 1561: state = 1562; break; // &DownRig -> &DownRigh - case 1631: state = 1635; break; // &du -> &duh - case 1912: state = 1916; break; // &et -> ð - case 2445: state = 2446; break; // &homt -> &homth - case 2461: state = 2462; break; // &hookrig -> &hookrigh - case 2498: state = 2499; break; // &hslas -> &hslash - case 2529: state = 2530; break; // &hyp -> &hyph - case 2629: state = 2630; break; // &imat -> &imath - case 2686: state = 2687; break; // &intlar -> &intlarh - case 2795: state = 2796; break; // &jmat -> &jmath - case 2830: state = 2860; break; // &k -> &kh - case 2881: state = 3393; break; // &l -> &lh - case 2939: state = 2945; break; // &larr -> &larrh - case 3020: state = 3021; break; // &ldrd -> &ldrdh - case 3025: state = 3026; break; // &ldrus -> &ldrush - case 3029: state = 3030; break; // &lds -> &ldsh - case 3058: state = 3126; break; // &left -> &lefth - case 3069: state = 3070; break; // &LeftArrowRig -> &LeftArrowRigh - case 3151: state = 3152; break; // &LeftRig -> &LeftRigh - case 3161: state = 3162; break; // &Leftrig -> &Leftrigh - case 3171: state = 3172; break; // &leftrig -> &leftrigh - case 3173: state = 3180; break; // &leftright -> &leftrighth - case 3218: state = 3219; break; // &leftt -> &leftth - case 3378: state = 3379; break; // &lfis -> &lfish - case 3409: state = 3427; break; // &ll -> &llh - case 3449: state = 3450; break; // &lmoustac -> &lmoustach - case 3509: state = 3510; break; // &LongLeftRig -> &LongLeftRigh - case 3519: state = 3520; break; // &Longleftrig -> &Longleftrigh - case 3529: state = 3530; break; // &longleftrig -> &longleftrigh - case 3545: state = 3546; break; // &LongRig -> &LongRigh - case 3555: state = 3556; break; // &Longrig -> &Longrigh - case 3565: state = 3566; break; // &longrig -> &longrigh - case 3586: state = 3587; break; // &looparrowrig -> &looparrowrigh - case 3624: state = 3625; break; // &LowerRig -> &LowerRigh - case 3643: state = 3653; break; // &lr -> &lrh - case 3661: state = 3672; break; // &ls -> &lsh - case 3666: state = 3671; break; // &Ls -> &Lsh - case 3692: state = 3700; break; // < -> <h - case 3727: state = 3728; break; // &lurds -> &lurdsh - case 3731: state = 3732; break; // &luru -> &luruh - case 3745: state = 3825; break; // &m -> &mh - case 3786: state = 3787; break; // &mdas -> &mdash - case 3897: state = 4101; break; // &n -> &nh - case 3968: state = 3969; break; // &ndas -> &ndash - case 3972: state = 3973; break; // &near -> &nearh - case 4002: state = 4003; break; // &NegativeT -> &NegativeTh - case 4022: state = 4023; break; // &NegativeVeryT -> &NegativeVeryTh - case 4150: state = 4151; break; // &nLeftrig -> &nLeftrigh - case 4160: state = 4161; break; // &nleftrig -> &nleftrigh - case 4468: state = 4469; break; // &NotRig -> &NotRigh - case 4632: state = 4633; break; // &nRig -> &nRigh - case 4641: state = 4642; break; // &nrig -> &nrigh - case 4653: state = 4663; break; // &ns -> &nsh - case 4747: state = 4748; break; // &ntrianglerig -> &ntrianglerigh - case 4766: state = 4767; break; // &nVDas -> &nVDash - case 4770: state = 4771; break; // &nVdas -> &nVdash - case 4774: state = 4775; break; // &nvDas -> &nvDash - case 4778: state = 4779; break; // &nvdas -> &nvdash - case 4814: state = 4815; break; // &nwar -> &nwarh - case 4833: state = 4900; break; // &o -> &oh - case 4853: state = 4854; break; // &odas -> &odash - case 5023: state = 5024; break; // &Oslas -> Ø - case 5027: state = 5028; break; // &oslas -> ø - case 5077: state = 5078; break; // &OverParent -> &OverParenth - case 5083: state = 5130; break; // &p -> &ph - case 5096: state = 5128; break; // &P -> &Ph - case 5143: state = 5144; break; // &pitc -> &pitch - case 5154: state = 5155; break; // &planck -> &planckh - case 5397: state = 5607; break; // &r -> &rh - case 5405: state = 5613; break; // &R -> &Rh - case 5439: state = 5448; break; // &rarr -> &rarrh - case 5530: state = 5531; break; // &rdld -> &rdldh - case 5538: state = 5539; break; // &rds -> &rdsh - case 5594: state = 5595; break; // &rfis -> &rfish - case 5618: state = 5619; break; // &Rig -> &Righ - case 5643: state = 5644; break; // &rig -> &righ - case 5645: state = 5712; break; // &right -> &righth - case 5728: state = 5735; break; // &rightleft -> &rightlefth - case 5745: state = 5746; break; // &rightrig -> &rightrigh - case 5778: state = 5779; break; // &rightt -> &rightth - case 5854: state = 5858; break; // &rl -> &rlh - case 5868: state = 5869; break; // &rmoustac -> &rmoustach - case 5926: state = 5927; break; // &Rrig -> &Rrigh - case 5934: state = 5945; break; // &rs -> &rsh - case 5939: state = 5944; break; // &Rs -> &Rsh - case 5951: state = 5952; break; // &rt -> &rth - case 5980: state = 5981; break; // &rulu -> &ruluh - case 5985: state = 6104; break; // &S -> &Sh - case 5991: state = 6088; break; // &s -> &sh - case 6055: state = 6056; break; // &sear -> &searh - case 6097: state = 6098; break; // &shc -> &shch - case 6142: state = 6143; break; // &ShortRig -> &ShortRigh - case 6214: state = 6215; break; // &smas -> &smash - case 6366: state = 6367; break; // &straig -> &straigh - case 6376: state = 6377; break; // &straightp -> &straightph - case 6446: state = 6490; break; // &Suc -> &Such - case 6491: state = 6492; break; // &SuchT -> &SuchTh - case 6500: state = 6525; break; // &sup -> &suph - case 6566: state = 6567; break; // &swar -> &swarh - case 6583: state = 6634; break; // &T -> &Th - case 6586: state = 6629; break; // &t -> &th - case 6783: state = 6784; break; // &trianglerig -> &trianglerigh - case 6824: state = 6834; break; // &ts -> &tsh - case 6849: state = 6850; break; // &two -> &twoh - case 6865: state = 6866; break; // &twoheadrig -> &twoheadrigh - case 6879: state = 6957; break; // &u -> &uh - case 6920: state = 6933; break; // &ud -> &udh - case 6938: state = 6939; break; // &ufis -> &ufish - case 7006: state = 7007; break; // &UnderParent -> &UnderParenth - case 7042: state = 7098; break; // &up -> &uph - case 7111: state = 7112; break; // &upharpoonrig -> &upharpoonrigh - case 7131: state = 7132; break; // &UpperRig -> &UpperRigh - case 7142: state = 7143; break; // &upsi -> &upsih - case 7244: state = 7245; break; // &varnot -> &varnoth - case 7249: state = 7250; break; // &varp -> &varph - case 7261: state = 7262; break; // &varr -> &varrh - case 7286: state = 7287; break; // &vart -> &varth - case 7304: state = 7305; break; // &vartrianglerig -> &vartrianglerigh - case 7321: state = 7322; break; // &VDas -> &VDash - case 7325: state = 7326; break; // &Vdas -> &Vdash - case 7329: state = 7330; break; // &vDas -> &vDash - case 7333: state = 7334; break; // &vdas -> &vdash - case 7385: state = 7386; break; // &VeryT -> &VeryTh - case 7439: state = 7440; break; // &Vvdas -> &Vvdash - case 7487: state = 7488; break; // &wreat -> &wreath - case 7495: state = 7513; break; // &x -> &xh - case 7651: state = 7704; break; // &z -> &zh - case 7686: state = 7687; break; // &ZeroWidt -> &ZeroWidth - default: return false; - } - break; - case 'i': - switch (state) { - case 0: state = 2539; break; // & -> &i - case 23: state = 30; break; // &ac -> &aci - case 26: state = 27; break; // &Ac -> &Aci - case 39: state = 40; break; // &AEl -> &AEli - case 43: state = 44; break; // &ael -> &aeli - case 143: state = 150; break; // &ap -> &api - case 145: state = 146; break; // &apac -> &apaci - case 162: state = 163; break; // &ApplyFunct -> &ApplyFuncti - case 172: state = 173; break; // &Ar -> &Ari - case 176: state = 177; break; // &ar -> &ari - case 186: state = 187; break; // &Ass -> &Assi - case 196: state = 197; break; // &At -> &Ati - case 201: state = 202; break; // &at -> &ati - case 212: state = 219; break; // &aw -> &awi - case 215: state = 216; break; // &awcon -> &awconi - case 222: state = 333; break; // &b -> &bi - case 232: state = 233; break; // &backeps -> &backepsi - case 238: state = 239; break; // &backpr -> &backpri - case 242: state = 243; break; // &backs -> &backsi - case 306: state = 307; break; // &beps -> &bepsi - case 317: state = 318; break; // &Bernoull -> &Bernoulli - case 335: state = 338; break; // &bigc -> &bigci - case 351: state = 352; break; // &bigot -> &bigoti - case 365: state = 366; break; // &bigtr -> &bigtri - case 414: state = 415; break; // &blacktr -> &blacktri - case 429: state = 430; break; // &blacktriangler -> &blacktriangleri - case 448: state = 449; break; // &bnequ -> &bnequi - case 467: state = 468; break; // &bowt -> &bowti - case 494: state = 495; break; // &boxm -> &boxmi - case 503: state = 504; break; // &boxt -> &boxti - case 533: state = 534; break; // &bpr -> &bpri - case 552: state = 558; break; // &bs -> &bsi - case 556: state = 557; break; // &bsem -> &bsemi - case 583: state = 765; break; // &C -> &Ci - case 589: state = 732; break; // &c -> &ci - case 595: state = 613; break; // &Cap -> &Capi - case 617: state = 618; break; // &CapitalD -> &CapitalDi - case 625: state = 626; break; // &CapitalDifferent -> &CapitalDifferenti - case 641: state = 664; break; // &cc -> &cci - case 645: state = 661; break; // &Cc -> &Cci - case 654: state = 655; break; // &Cced -> &Ccedi - case 658: state = 659; break; // &cced -> &ccedi - case 668: state = 669; break; // &Ccon -> &Cconi - case 684: state = 685; break; // &ced -> &cedi - case 688: state = 689; break; // &Ced -> &Cedi - case 719: state = 731; break; // &ch -> &chi - case 729: state = 730; break; // &Ch -> &Chi - case 748: state = 749; break; // &circlearrowr -> &circlearrowri - case 757: state = 758; break; // &circledc -> &circledci - case 775: state = 776; break; // &CircleM -> &CircleMi - case 784: state = 785; break; // &CircleT -> &CircleTi - case 792: state = 793; break; // &cirfn -> &cirfni - case 796: state = 797; break; // &cirm -> &cirmi - case 800: state = 801; break; // &cirsc -> &cirsci - case 807: state = 808; break; // &Clockw -> &Clockwi - case 853: state = 854; break; // &clubsu -> &clubsui - case 883: state = 898; break; // &con -> &coni - case 888: state = 895; break; // &Con -> &Coni - case 942: state = 943; break; // &CounterClockw -> &CounterClockwi - case 1065: state = 1066; break; // &curvearrowr -> &curvearrowri - case 1076: state = 1083; break; // &cw -> &cwi - case 1079: state = 1080; break; // &cwcon -> &cwconi - case 1091: state = 1191; break; // &D -> &Di - case 1097: state = 1228; break; // &d -> &di - case 1175: state = 1176; break; // &df -> &dfi - case 1194: state = 1195; break; // &Diacr -> &Diacri - case 1196: state = 1197; break; // &Diacrit -> &Diacriti - case 1223: state = 1224; break; // &DiacriticalT -> &DiacriticalTi - case 1239: state = 1240; break; // &diamondsu -> &diamondsui - case 1250: state = 1251; break; // &Different -> &Differenti - case 1260: state = 1261; break; // &dis -> &disi - case 1263: state = 1264; break; // &div -> &divi - case 1269: state = 1270; break; // ÷ont -> ÷onti - case 1316: state = 1317; break; // &dotm -> &dotmi - case 1381: state = 1382; break; // &DoubleLeftR -> &DoubleLeftRi - case 1406: state = 1407; break; // &DoubleLongLeftR -> &DoubleLongLeftRi - case 1416: state = 1417; break; // &DoubleLongR -> &DoubleLongRi - case 1426: state = 1427; break; // &DoubleR -> &DoubleRi - case 1458: state = 1459; break; // &DoubleVert -> &DoubleVerti - case 1521: state = 1522; break; // &downharpoonr -> &downharpoonri - case 1530: state = 1531; break; // &DownLeftR -> &DownLeftRi - case 1559: state = 1560; break; // &DownR -> &DownRi - case 1628: state = 1629; break; // &dtr -> &dtri - case 1647: state = 1650; break; // &dz -> &dzi - case 1672: state = 1684; break; // &Ec -> &Eci - case 1677: state = 1682; break; // &ec -> &eci - case 1728: state = 1735; break; // &el -> &eli - case 1821: state = 1822; break; // &eps -> &epsi - case 1824: state = 1825; break; // &Eps -> &Epsi - case 1834: state = 1835; break; // &eqc -> &eqci - case 1842: state = 1843; break; // &eqs -> &eqsi - case 1857: state = 1872; break; // &Equ -> &Equi - case 1860: state = 1880; break; // &equ -> &equi - case 1864: state = 1865; break; // &EqualT -> &EqualTi - case 1873: state = 1874; break; // &Equil -> &Equili - case 1876: state = 1877; break; // &Equilibr -> &Equilibri - case 1897: state = 1906; break; // &Es -> &Esi - case 1900: state = 1908; break; // &es -> &esi - case 1925: state = 1928; break; // &ex -> &exi - case 1931: state = 1932; break; // &Ex -> &Exi - case 1941: state = 1942; break; // &expectat -> &expectati - case 1950: state = 1951; break; // &Exponent -> &Exponenti - case 1959: state = 1960; break; // &exponent -> &exponenti - case 1964: state = 2001; break; // &f -> &fi - case 1967: state = 1968; break; // &fall -> &falli - case 1977: state = 2005; break; // &F -> &Fi - case 1987: state = 1988; break; // &ff -> &ffi - case 1989: state = 1990; break; // &ffil -> &ffili - case 1992: state = 1993; break; // &ffl -> &ffli - case 1995: state = 1996; break; // &ffll -> &fflli - case 2002: state = 2003; break; // &fil -> &fili - case 2037: state = 2038; break; // &fjl -> &fjli - case 2043: state = 2044; break; // &fll -> &flli - case 2069: state = 2070; break; // &Four -> &Fouri - case 2079: state = 2080; break; // &fpart -> &fparti - case 2118: state = 2194; break; // &g -> &gi - case 2145: state = 2150; break; // &Gc -> &Gci - case 2147: state = 2148; break; // &Gced -> &Gcedi - case 2153: state = 2154; break; // &gc -> &gci - case 2219: state = 2220; break; // &gns -> &gnsi - case 2277: state = 2278; break; // &GreaterT -> &GreaterTi - case 2285: state = 2288; break; // &gs -> &gsi - case 2295: state = 2297; break; // >c -> >ci - case 2338: state = 2339; break; // >rs -> >rsi - case 2351: state = 2417; break; // &H -> &Hi - case 2357: state = 2358; break; // &ha -> &hai - case 2364: state = 2365; break; // &ham -> &hami - case 2381: state = 2382; break; // &harrc -> &harrci - case 2389: state = 2390; break; // &Hc -> &Hci - case 2393: state = 2394; break; // &hc -> &hci - case 2402: state = 2403; break; // &heartsu -> &heartsui - case 2406: state = 2407; break; // &hell -> &helli - case 2459: state = 2460; break; // &hookr -> &hookri - case 2478: state = 2479; break; // &Hor -> &Hori - case 2486: state = 2487; break; // &HorizontalL -> &HorizontalLi - case 2539: state = 2582; break; // &i -> &ii - case 2545: state = 2550; break; // &ic -> &ici - case 2546: state = 2547; break; // &Ic -> &Ici - case 2582: state = 2583; break; // &ii -> &iii - case 2583: state = 2584; break; // &iii -> &iiii - case 2590: state = 2591; break; // &iinf -> &iinfi - case 2597: state = 2598; break; // &IJl -> &IJli - case 2601: state = 2602; break; // &ijl -> &ijli - case 2614: state = 2615; break; // &Imag -> &Imagi - case 2621: state = 2622; break; // &imagl -> &imagli - case 2637: state = 2638; break; // &Impl -> &Impli - case 2646: state = 2647; break; // &inf -> &infi - case 2649: state = 2650; break; // &infint -> &infinti - case 2680: state = 2681; break; // &Intersect -> &Intersecti - case 2693: state = 2694; break; // &Inv -> &Invi - case 2695: state = 2696; break; // &Invis -> &Invisi - case 2705: state = 2706; break; // &InvisibleT -> &InvisibleTi - case 2743: state = 2746; break; // &is -> &isi - case 2755: state = 2761; break; // &it -> &iti - case 2756: state = 2757; break; // &It -> &Iti - case 2778: state = 2779; break; // &Jc -> &Jci - case 2783: state = 2784; break; // &jc -> &jci - case 2838: state = 2839; break; // &Kced -> &Kcedi - case 2843: state = 2844; break; // &kced -> &kcedi - case 2951: state = 2952; break; // &larrs -> &larrsi - case 2958: state = 2959; break; // &lAta -> &lAtai - case 2961: state = 2962; break; // &lata -> &latai - case 2999: state = 3000; break; // &Lced -> &Lcedi - case 3002: state = 3006; break; // &lce -> &lcei - case 3003: state = 3004; break; // &lced -> &lcedi - case 3067: state = 3068; break; // &LeftArrowR -> &LeftArrowRi - case 3078: state = 3079; break; // &leftarrowta -> &leftarrowtai - case 3082: state = 3083; break; // &LeftCe -> &LeftCei - case 3084: state = 3085; break; // &LeftCeil -> &LeftCeili - case 3149: state = 3150; break; // &LeftR -> &LeftRi - case 3159: state = 3160; break; // &Leftr -> &Leftri - case 3169: state = 3170; break; // &leftr -> &leftri - case 3190: state = 3191; break; // &leftrightsqu -> &leftrightsqui - case 3223: state = 3224; break; // &leftthreet -> &leftthreeti - case 3228: state = 3229; break; // &LeftTr -> &LeftTri - case 3358: state = 3359; break; // &lesss -> &lesssi - case 3371: state = 3372; break; // &LessT -> &LessTi - case 3376: state = 3377; break; // &lf -> &lfi - case 3432: state = 3433; break; // &lltr -> &lltri - case 3434: state = 3435; break; // &Lm -> &Lmi - case 3439: state = 3440; break; // &lm -> &lmi - case 3463: state = 3464; break; // &lns -> &lnsi - case 3507: state = 3508; break; // &LongLeftR -> &LongLeftRi - case 3517: state = 3518; break; // &Longleftr -> &Longleftri - case 3527: state = 3528; break; // &longleftr -> &longleftri - case 3543: state = 3544; break; // &LongR -> &LongRi - case 3553: state = 3554; break; // &Longr -> &Longri - case 3563: state = 3564; break; // &longr -> &longri - case 3584: state = 3585; break; // &looparrowr -> &looparrowri - case 3598: state = 3599; break; // &lot -> &loti - case 3622: state = 3623; break; // &LowerR -> &LowerRi - case 3659: state = 3660; break; // &lrtr -> &lrtri - case 3661: state = 3673; break; // &ls -> &lsi - case 3692: state = 3704; break; // < -> <i - case 3693: state = 3695; break; // <c -> <ci - case 3717: state = 3718; break; // <r -> <ri - case 3745: state = 3827; break; // &m -> &mi - case 3755: state = 3847; break; // &M -> &Mi - case 3805: state = 3806; break; // &Med -> &Medi - case 3815: state = 3816; break; // &Mell -> &Melli - case 3835: state = 3836; break; // &midc -> &midci - case 3889: state = 3890; break; // &mult -> &multi - case 3897: state = 4111; break; // &n -> &ni - case 3914: state = 3916; break; // &nap -> &napi - case 3949: state = 3950; break; // &Nced -> &Ncedi - case 3953: state = 3954; break; // &nced -> &ncedi - case 3987: state = 3988; break; // &Negat -> &Negati - case 3993: state = 3994; break; // &NegativeMed -> &NegativeMedi - case 4003: state = 4004; break; // &NegativeTh -> &NegativeThi - case 4023: state = 4024; break; // &NegativeVeryTh -> &NegativeVeryThi - case 4032: state = 4033; break; // &nequ -> &nequi - case 4035: state = 4039; break; // &nes -> &nesi - case 4068: state = 4069; break; // &NewL -> &NewLi - case 4072: state = 4073; break; // &nex -> &nexi - case 4094: state = 4095; break; // &ngs -> &ngsi - case 4148: state = 4149; break; // &nLeftr -> &nLeftri - case 4158: state = 4159; break; // &nleftr -> &nleftri - case 4178: state = 4179; break; // &nls -> &nlsi - case 4183: state = 4184; break; // &nltr -> &nltri - case 4187: state = 4188; break; // &nm -> &nmi - case 4201: state = 4202; break; // &NonBreak -> &NonBreaki - case 4216: state = 4333; break; // ¬ -> ¬i - case 4240: state = 4241; break; // &NotDoubleVert -> &NotDoubleVerti - case 4259: state = 4260; break; // &NotEqualT -> &NotEqualTi - case 4264: state = 4265; break; // &NotEx -> &NotExi - case 4311: state = 4312; break; // &NotGreaterT -> &NotGreaterTi - case 4348: state = 4349; break; // &NotLeftTr -> &NotLeftTri - case 4391: state = 4392; break; // &NotLessT -> &NotLessTi - case 4424: state = 4425; break; // ¬n -> ¬ni - case 4453: state = 4467; break; // &NotR -> &NotRi - case 4472: state = 4473; break; // &NotRightTr -> &NotRightTri - case 4546: state = 4547; break; // &NotSucceedsT -> &NotSucceedsTi - case 4562: state = 4563; break; // &NotT -> &NotTi - case 4581: state = 4582; break; // &NotTildeT -> &NotTildeTi - case 4589: state = 4590; break; // &NotVert -> &NotVerti - case 4609: state = 4610; break; // &npol -> &npoli - case 4621: state = 4640; break; // &nr -> &nri - case 4630: state = 4631; break; // &nR -> &nRi - case 4650: state = 4651; break; // &nrtr -> &nrtri - case 4653: state = 4678; break; // &ns -> &nsi - case 4667: state = 4668; break; // &nshortm -> &nshortmi - case 4682: state = 4683; break; // &nsm -> &nsmi - case 4718: state = 4726; break; // &nt -> &nti - case 4721: state = 4722; break; // &Nt -> &Nti - case 4732: state = 4733; break; // &ntr -> &ntri - case 4745: state = 4746; break; // &ntriangler -> &ntriangleri - case 4760: state = 4787; break; // &nv -> &nvi - case 4789: state = 4790; break; // &nvinf -> &nvinfi - case 4798: state = 4799; break; // &nvltr -> &nvltri - case 4806: state = 4807; break; // &nvrtr -> &nvrtri - case 4809: state = 4810; break; // &nvs -> &nvsi - case 4833: state = 4905; break; // &o -> &oi - case 4841: state = 4842; break; // &oc -> &oci - case 4844: state = 4845; break; // &Oc -> &Oci - case 4851: state = 4864; break; // &od -> &odi - case 4873: state = 4874; break; // &OEl -> &OEli - case 4877: state = 4878; break; // &oel -> &oeli - case 4881: state = 4882; break; // &ofc -> &ofci - case 4908: state = 4919; break; // &ol -> &oli - case 4912: state = 4913; break; // &olc -> &olci - case 4923: state = 4937; break; // &Om -> &Omi - case 4927: state = 4942; break; // &om -> &omi - case 4991: state = 5002; break; // &or -> &ori - case 5031: state = 5032; break; // &Ot -> &Oti - case 5036: state = 5037; break; // &ot -> &oti - case 5080: state = 5081; break; // &OverParenthes -> &OverParenthesi - case 5083: state = 5141; break; // &p -> &pi - case 5091: state = 5092; break; // &pars -> &parsi - case 5096: state = 5140; break; // &P -> &Pi - case 5099: state = 5100; break; // &Part -> &Parti - case 5109: state = 5113; break; // &per -> &peri - case 5116: state = 5117; break; // &perm -> &permi - case 5128: state = 5129; break; // &Ph -> &Phi - case 5130: state = 5131; break; // &ph -> &phi - case 5161: state = 5162; break; // &plusac -> &plusaci - case 5165: state = 5166; break; // &plusc -> &plusci - case 5175: state = 5176; break; // &PlusM -> &PlusMi - case 5182: state = 5183; break; // &pluss -> &plussi - case 5189: state = 5190; break; // &Po -> &Poi - case 5201: state = 5202; break; // &po -> &poi - case 5204: state = 5205; break; // &point -> &pointi - case 5215: state = 5282; break; // &Pr -> &Pri - case 5216: state = 5285; break; // &pr -> &pri - case 5259: state = 5260; break; // &PrecedesT -> &PrecedesTi - case 5276: state = 5277; break; // &precns -> &precnsi - case 5279: state = 5280; break; // &precs -> &precsi - case 5293: state = 5294; break; // &prns -> &prnsi - case 5308: state = 5309; break; // &profl -> &profli - case 5320: state = 5321; break; // &Proport -> &Proporti - case 5328: state = 5329; break; // &prs -> &prsi - case 5335: state = 5341; break; // &Ps -> &Psi - case 5338: state = 5342; break; // &ps -> &psi - case 5351: state = 5354; break; // &q -> &qi - case 5364: state = 5365; break; // &qpr -> &qpri - case 5376: state = 5384; break; // &quat -> &quati - case 5379: state = 5380; break; // &quatern -> &quaterni - case 5397: state = 5642; break; // &r -> &ri - case 5405: state = 5617; break; // &R -> &Ri - case 5414: state = 5415; break; // &rad -> &radi - case 5454: state = 5455; break; // &rarrs -> &rarrsi - case 5463: state = 5464; break; // &rAta -> &rAtai - case 5466: state = 5470; break; // &rat -> &rati - case 5467: state = 5468; break; // &rata -> &ratai - case 5513: state = 5514; break; // &Rced -> &Rcedi - case 5516: state = 5520; break; // &rce -> &rcei - case 5517: state = 5518; break; // &rced -> &rcedi - case 5543: state = 5544; break; // &real -> &reali - case 5570: state = 5571; break; // &ReverseEqu -> &ReverseEqui - case 5572: state = 5573; break; // &ReverseEquil -> &ReverseEquili - case 5575: state = 5576; break; // &ReverseEquilibr -> &ReverseEquilibri - case 5583: state = 5584; break; // &ReverseUpEqu -> &ReverseUpEqui - case 5585: state = 5586; break; // &ReverseUpEquil -> &ReverseUpEquili - case 5588: state = 5589; break; // &ReverseUpEquilibr -> &ReverseUpEquilibri - case 5592: state = 5593; break; // &rf -> &rfi - case 5664: state = 5665; break; // &rightarrowta -> &rightarrowtai - case 5668: state = 5669; break; // &RightCe -> &RightCei - case 5670: state = 5671; break; // &RightCeil -> &RightCeili - case 5743: state = 5744; break; // &rightr -> &rightri - case 5756: state = 5757; break; // &rightsqu -> &rightsqui - case 5783: state = 5784; break; // &rightthreet -> &rightthreeti - case 5788: state = 5789; break; // &RightTr -> &RightTri - case 5844: state = 5845; break; // &ris -> &risi - case 5872: state = 5873; break; // &rnm -> &rnmi - case 5894: state = 5895; break; // &rot -> &roti - case 5905: state = 5906; break; // &RoundImpl -> &RoundImpli - case 5916: state = 5917; break; // &rppol -> &rppoli - case 5924: state = 5925; break; // &Rr -> &Rri - case 5951: state = 5956; break; // &rt -> &rti - case 5960: state = 5961; break; // &rtr -> &rtri - case 5966: state = 5967; break; // &rtriltr -> &rtriltri - case 5985: state = 6158; break; // &S -> &Si - case 5991: state = 6162; break; // &s -> &si - case 6001: state = 6024; break; // &Sc -> &Sci - case 6002: state = 6027; break; // &sc -> &sci - case 6018: state = 6019; break; // &Sced -> &Scedi - case 6021: state = 6022; break; // &sced -> &scedi - case 6034: state = 6035; break; // &scns -> &scnsi - case 6039: state = 6040; break; // &scpol -> &scpoli - case 6043: state = 6044; break; // &scs -> &scsi - case 6066: state = 6067; break; // &sem -> &semi - case 6073: state = 6074; break; // &setm -> &setmi - case 6129: state = 6130; break; // &shortm -> &shortmi - case 6140: state = 6141; break; // &ShortR -> &ShortRi - case 6196: state = 6197; break; // &SmallC -> &SmallCi - case 6202: state = 6223; break; // &sm -> &smi - case 6209: state = 6210; break; // &smallsetm -> &smallsetmi - case 6254: state = 6255; break; // &spadesu -> &spadesui - case 6301: state = 6302; break; // &SquareIntersect -> &SquareIntersecti - case 6328: state = 6329; break; // &SquareUn -> &SquareUni - case 6348: state = 6349; break; // &ssm -> &ssmi - case 6364: state = 6365; break; // &stra -> &strai - case 6371: state = 6372; break; // &straighteps -> &straightepsi - case 6377: state = 6378; break; // &straightph -> &straightphi - case 6411: state = 6426; break; // &subs -> &subsi - case 6467: state = 6468; break; // &SucceedsT -> &SucceedsTi - case 6484: state = 6485; break; // &succns -> &succnsi - case 6487: state = 6488; break; // &succs -> &succsi - case 6549: state = 6559; break; // &sups -> &supsi - case 6580: state = 6581; break; // &szl -> &szli - case 6583: state = 6696; break; // &T -> &Ti - case 6586: state = 6700; break; // &t -> &ti - case 6608: state = 6609; break; // &Tced -> &Tcedi - case 6612: state = 6613; break; // &tced -> &tcedi - case 6629: state = 6654; break; // &th -> &thi - case 6634: state = 6666; break; // &Th -> &Thi - case 6663: state = 6664; break; // &thicks -> &thicksi - case 6686: state = 6687; break; // &thks -> &thksi - case 6718: state = 6719; break; // &TildeT -> &TildeTi - case 6739: state = 6740; break; // &topc -> &topci - case 6752: state = 6753; break; // &tpr -> &tpri - case 6760: state = 6764; break; // &tr -> &tri - case 6781: state = 6782; break; // &triangler -> &triangleri - case 6792: state = 6793; break; // &trim -> &trimi - case 6797: state = 6798; break; // &Tr -> &Tri - case 6811: state = 6812; break; // &trit -> &triti - case 6817: state = 6818; break; // &trpez -> &trpezi - case 6845: state = 6846; break; // &tw -> &twi - case 6863: state = 6864; break; // &twoheadr -> &twoheadri - case 6893: state = 6894; break; // &Uarroc -> &Uarroci - case 6910: state = 6911; break; // &Uc -> &Uci - case 6914: state = 6915; break; // &uc -> &uci - case 6936: state = 6937; break; // &uf -> &ufi - case 6976: state = 6977; break; // &ultr -> &ultri - case 6987: state = 7012; break; // &Un -> &Uni - case 7009: state = 7010; break; // &UnderParenthes -> &UnderParenthesi - case 7089: state = 7090; break; // &UpEqu -> &UpEqui - case 7091: state = 7092; break; // &UpEquil -> &UpEquili - case 7094: state = 7095; break; // &UpEquilibr -> &UpEquilibri - case 7109: state = 7110; break; // &upharpoonr -> &upharpoonri - case 7129: state = 7130; break; // &UpperR -> &UpperRi - case 7139: state = 7140; break; // &Ups -> &Upsi - case 7141: state = 7142; break; // &ups -> &upsi - case 7166: state = 7180; break; // &ur -> &uri - case 7176: state = 7177; break; // &Ur -> &Uri - case 7184: state = 7185; break; // &urtr -> &urtri - case 7192: state = 7201; break; // &ut -> &uti - case 7196: state = 7197; break; // &Ut -> &Uti - case 7205: state = 7206; break; // &utr -> &utri - case 7232: state = 7233; break; // &vareps -> &varepsi - case 7245: state = 7246; break; // &varnoth -> &varnothi - case 7249: state = 7252; break; // &varp -> &varpi - case 7250: state = 7251; break; // &varph -> &varphi - case 7264: state = 7265; break; // &vars -> &varsi - case 7291: state = 7292; break; // &vartr -> &vartri - case 7302: state = 7303; break; // &vartriangler -> &vartriangleri - case 7346: state = 7347; break; // &vell -> &velli - case 7357: state = 7359; break; // &Vert -> &Verti - case 7366: state = 7367; break; // &VerticalL -> &VerticalLi - case 7379: state = 7380; break; // &VerticalT -> &VerticalTi - case 7386: state = 7387; break; // &VeryTh -> &VeryThi - case 7400: state = 7401; break; // &vltr -> &vltri - case 7419: state = 7420; break; // &vrtr -> &vrtri - case 7441: state = 7442; break; // &vz -> &vzi - case 7448: state = 7449; break; // &Wc -> &Wci - case 7453: state = 7454; break; // &wc -> &wci - case 7457: state = 7469; break; // &we -> &wei - case 7495: state = 7521; break; // &x -> &xi - case 7496: state = 7499; break; // &xc -> &xci - case 7506: state = 7507; break; // &xdtr -> &xdtri - case 7508: state = 7520; break; // &X -> &Xi - case 7532: state = 7533; break; // &xn -> &xni - case 7547: state = 7548; break; // &xot -> &xoti - case 7574: state = 7575; break; // &xutr -> &xutri - case 7590: state = 7619; break; // &y -> &yi - case 7600: state = 7601; break; // &Yc -> &Yci - case 7604: state = 7605; break; // &yc -> &yci - case 7651: state = 7707; break; // &z -> &zi - case 7683: state = 7684; break; // &ZeroW -> &ZeroWi - default: return false; - } - break; - case 'j': - switch (state) { - case 0: state = 2782; break; // & -> &j - case 1097: state = 1280; break; // &d -> &dj - case 1964: state = 2036; break; // &f -> &fj - case 2118: state = 2201; break; // &g -> &gj - case 2204: state = 2207; break; // &gl -> &glj - case 2539: state = 2600; break; // &i -> &ij - case 2830: state = 2866; break; // &k -> &kj - case 2881: state = 3405; break; // &l -> &lj - case 3897: state = 4118; break; // &n -> &nj - case 7725: state = 7726; break; // &zw -> &zwj - case 7727: state = 7728; break; // &zwn -> &zwnj - default: return false; - } - break; - case 'k': - switch (state) { - case 0: state = 2830; break; // & -> &k - case 222: state = 391; break; // &b -> &bk - case 224: state = 225; break; // &bac -> &back - case 249: state = 250; break; // &Bac -> &Back - case 271: state = 272; break; // &bbr -> &bbrk - case 275: state = 276; break; // &bbrktbr -> &bbrktbrk - case 396: state = 436; break; // &bl -> &blk - case 398: state = 399; break; // &blac -> &black - case 434: state = 435; break; // &blan -> &blank - case 443: state = 444; break; // &bloc -> &block - case 723: state = 724; break; // &chec -> &check - case 727: state = 728; break; // &checkmar -> &checkmark - case 805: state = 806; break; // &Cloc -> &Clock - case 940: state = 941; break; // &CounterCloc -> &CounterClock - case 1120: state = 1121; break; // &db -> &dbk - case 1591: state = 1592; break; // &drb -> &drbk - case 1618: state = 1619; break; // &Dstro -> &Dstrok - case 1622: state = 1623; break; // &dstro -> &dstrok - case 2062: state = 2066; break; // &for -> &fork - case 2354: state = 2355; break; // &Hace -> &Hacek - case 2356: state = 2428; break; // &h -> &hk - case 2448: state = 2449; break; // &hoo -> &hook - case 2502: state = 2503; break; // &Hstro -> &Hstrok - case 2506: state = 2507; break; // &hstro -> &hstrok - case 2687: state = 2688; break; // &intlarh -> &intlarhk - case 2765: state = 2766; break; // &Iu -> &Iuk - case 2769: state = 2770; break; // &iu -> &iuk - case 2817: state = 2818; break; // &Ju -> &Juk - case 2821: state = 2822; break; // &ju -> &juk - case 2945: state = 2946; break; // &larrh -> &larrhk - case 2975: state = 2976; break; // &lbbr -> &lbbrk - case 2977: state = 2982; break; // &lbr -> &lbrk - case 2979: state = 2981; break; // &lbrac -> &lbrack - case 3044: state = 3045; break; // &LeftAngleBrac -> &LeftAngleBrack - case 3097: state = 3098; break; // &LeftDoubleBrac -> &LeftDoubleBrack - case 3400: state = 3401; break; // &lhbl -> &lhblk - case 3473: state = 3474; break; // &lobr -> &lobrk - case 3684: state = 3685; break; // &Lstro -> &Lstrok - case 3688: state = 3689; break; // &lstro -> &lstrok - case 3772: state = 3773; break; // &mar -> &mark - case 3973: state = 3974; break; // &nearh -> &nearhk - case 4005: state = 4006; break; // &NegativeThic -> &NegativeThick - case 4194: state = 4195; break; // &NoBrea -> &NoBreak - case 4200: state = 4201; break; // &NonBrea -> &NonBreak - case 4815: state = 4816; break; // &nwarh -> &nwarhk - case 5067: state = 5069; break; // &OverBrac -> &OverBrack - case 5122: state = 5123; break; // &perten -> &pertenk - case 5147: state = 5148; break; // &pitchfor -> &pitchfork - case 5152: state = 5156; break; // &plan -> &plank - case 5153: state = 5154; break; // &planc -> &planck - case 5448: state = 5449; break; // &rarrh -> &rarrhk - case 5489: state = 5490; break; // &rbbr -> &rbbrk - case 5491: state = 5496; break; // &rbr -> &rbrk - case 5493: state = 5495; break; // &rbrac -> &rbrack - case 5629: state = 5630; break; // &RightAngleBrac -> &RightAngleBrack - case 5683: state = 5684; break; // &RightDoubleBrac -> &RightDoubleBrack - case 5882: state = 5883; break; // &robr -> &robrk - case 6056: state = 6057; break; // &searh -> &searhk - case 6567: state = 6568; break; // &swarh -> &swarhk - case 6595: state = 6596; break; // &tbr -> &tbrk - case 6629: state = 6683; break; // &th -> &thk - case 6655: state = 6656; break; // &thic -> &thick - case 6667: state = 6668; break; // &Thic -> &Thick - case 6747: state = 6748; break; // &topfor -> &topfork - case 6839: state = 6840; break; // &Tstro -> &Tstrok - case 6843: state = 6844; break; // &tstro -> &tstrok - case 6963: state = 6964; break; // &uhbl -> &uhblk - case 6996: state = 6998; break; // &UnderBrac -> &UnderBrack - case 7229: state = 7237; break; // &var -> &vark - default: return false; - } - break; - case 'l': - switch (state) { - case 0: state = 2881; break; // & -> &l - case 1: state = 68; break; // &A -> &Al - case 7: state = 60; break; // &a -> &al - case 38: state = 39; break; // &AE -> &AEl - case 42: state = 43; break; // &ae -> &ael - case 80: state = 83; break; // &ama -> &amal - case 96: state = 97; break; // &ands -> &andsl - case 102: state = 104; break; // &ang -> &angl - case 155: state = 156; break; // &App -> &Appl - case 197: state = 198; break; // &Ati -> &Atil - case 202: state = 203; break; // &ati -> &atil - case 207: state = 208; break; // &Aum -> Ä - case 210: state = 211; break; // &aum -> ä - case 222: state = 396; break; // &b -> &bl - case 233: state = 234; break; // &backepsi -> &backepsil - case 251: state = 252; break; // &Backs -> &Backsl - case 315: state = 316; break; // &Bernou -> &Bernoul - case 316: state = 317; break; // &Bernoul -> &Bernoull - case 347: state = 348; break; // &bigop -> &bigopl - case 369: state = 370; break; // &bigtriang -> &bigtriangl - case 379: state = 380; break; // &bigup -> &bigupl - case 399: state = 400; break; // &black -> &blackl - case 418: state = 419; break; // &blacktriang -> &blacktriangl - case 420: state = 425; break; // &blacktriangle -> &blacktrianglel - case 474: state = 476; break; // &boxD -> &boxDl - case 477: state = 479; break; // &boxd -> &boxdl - case 499: state = 500; break; // &boxp -> &boxpl - case 508: state = 510; break; // &boxU -> &boxUl - case 511: state = 513; break; // &boxu -> &boxul - case 518: state = 525; break; // &boxV -> &boxVl - case 519: state = 527; break; // &boxv -> &boxvl - case 561: state = 562; break; // &bso -> &bsol - case 568: state = 569; break; // &bu -> &bul - case 569: state = 570; break; // &bul -> &bull - case 583: state = 803; break; // &C -> &Cl - case 589: state = 849; break; // &c -> &cl - case 615: state = 616; break; // &Capita -> &Capital - case 627: state = 628; break; // &CapitalDifferentia -> &CapitalDifferential - case 636: state = 637; break; // &Cay -> &Cayl - case 655: state = 656; break; // &Ccedi -> Ç - case 659: state = 660; break; // &ccedi -> ç - case 685: state = 686; break; // &cedi -> ¸ - case 689: state = 690; break; // &Cedi -> &Cedil - case 690: state = 691; break; // &Cedil -> &Cedill - case 734: state = 737; break; // &circ -> &circl - case 743: state = 744; break; // &circlearrow -> &circlearrowl - case 767: state = 768; break; // &Circ -> &Circl - case 780: state = 781; break; // &CircleP -> &CirclePl - case 824: state = 825; break; // &ClockwiseContourIntegra -> &ClockwiseContourIntegral - case 830: state = 831; break; // &CloseCur -> &CloseCurl - case 836: state = 837; break; // &CloseCurlyDoub -> &CloseCurlyDoubl - case 856: state = 857; break; // &Co -> &Col - case 860: state = 861; break; // &co -> &col - case 871: state = 874; break; // &comp -> &compl - case 911: state = 912; break; // &ContourIntegra -> &ContourIntegral - case 937: state = 938; break; // &CounterC -> &CounterCl - case 959: state = 960; break; // &CounterClockwiseContourIntegra -> &CounterClockwiseContourIntegral - case 987: state = 999; break; // &cu -> &cul - case 991: state = 992; break; // &cudarr -> &cudarrl - case 1026: state = 1031; break; // &cur -> &curl - case 1060: state = 1061; break; // &curvearrow -> &curvearrowl - case 1086: state = 1087; break; // &cy -> &cyl - case 1097: state = 1283; break; // &d -> &dl - case 1098: state = 1103; break; // &da -> &dal - case 1120: state = 1126; break; // &db -> &dbl - case 1161: state = 1167; break; // &de -> &del - case 1163: state = 1164; break; // &De -> &Del - case 1188: state = 1189; break; // &dhar -> &dharl - case 1199: state = 1200; break; // &Diacritica -> &Diacritical - case 1210: state = 1211; break; // &DiacriticalDoub -> &DiacriticalDoubl - case 1224: state = 1225; break; // &DiacriticalTi -> &DiacriticalTil - case 1252: state = 1253; break; // &Differentia -> &Differential - case 1291: state = 1292; break; // &do -> &dol - case 1292: state = 1293; break; // &dol -> &doll - case 1314: state = 1315; break; // &DotEqua -> &DotEqual - case 1321: state = 1322; break; // &dotp -> &dotpl - case 1332: state = 1333; break; // &doub -> &doubl - case 1344: state = 1345; break; // &Doub -> &Doubl - case 1360: state = 1361; break; // &DoubleContourIntegra -> &DoubleContourIntegral - case 1461: state = 1462; break; // &DoubleVertica -> &DoubleVertical - case 1516: state = 1517; break; // &downharpoon -> &downharpoonl - case 1614: state = 1615; break; // &dso -> &dsol - case 1641: state = 1642; break; // &dwang -> &dwangl - case 1656: state = 1729; break; // &E -> &El - case 1662: state = 1728; break; // &e -> &el - case 1688: state = 1689; break; // &eco -> &ecol - case 1728: state = 1741; break; // &el -> &ell - case 1765: state = 1766; break; // &EmptySma -> &EmptySmal - case 1766: state = 1767; break; // &EmptySmal -> &EmptySmall - case 1781: state = 1782; break; // &EmptyVerySma -> &EmptyVerySmal - case 1782: state = 1783; break; // &EmptyVerySmal -> &EmptyVerySmall - case 1813: state = 1818; break; // &ep -> &epl - case 1816: state = 1817; break; // &epars -> &eparsl - case 1822: state = 1829; break; // &epsi -> &epsil - case 1825: state = 1826; break; // &Epsi -> &Epsil - case 1838: state = 1839; break; // &eqco -> &eqcol - case 1842: state = 1845; break; // &eqs -> &eqsl - case 1848: state = 1852; break; // &eqslant -> &eqslantl - case 1858: state = 1859; break; // &Equa -> &Equal - case 1861: state = 1862; break; // &equa -> &equal - case 1865: state = 1866; break; // &EqualTi -> &EqualTil - case 1872: state = 1873; break; // &Equi -> &Equil - case 1888: state = 1889; break; // &eqvpars -> &eqvparsl - case 1918: state = 1919; break; // &Eum -> Ë - case 1921: state = 1922; break; // &eum -> ë - case 1926: state = 1927; break; // &exc -> &excl - case 1952: state = 1953; break; // &Exponentia -> &Exponential - case 1961: state = 1962; break; // &exponentia -> &exponential - case 1964: state = 2040; break; // &f -> &fl - case 1965: state = 1966; break; // &fa -> &fal - case 1966: state = 1967; break; // &fal -> &fall - case 1984: state = 1985; break; // &fema -> &femal - case 1987: state = 1992; break; // &ff -> &ffl - case 1988: state = 1989; break; // &ffi -> &ffil - case 1992: state = 1995; break; // &ffl -> &ffll - case 2001: state = 2002; break; // &fi -> &fil - case 2005: state = 2006; break; // &Fi -> &Fil - case 2006: state = 2007; break; // &Fil -> &Fill - case 2012: state = 2013; break; // &FilledSma -> &FilledSmal - case 2013: state = 2014; break; // &FilledSmal -> &FilledSmall - case 2027: state = 2028; break; // &FilledVerySma -> &FilledVerySmal - case 2028: state = 2029; break; // &FilledVerySmal -> &FilledVerySmall - case 2036: state = 2037; break; // &fj -> &fjl - case 2040: state = 2043; break; // &fl -> &fll - case 2059: state = 2060; break; // &ForA -> &ForAl - case 2060: state = 2061; break; // &ForAl -> &ForAll - case 2063: state = 2064; break; // &fora -> &foral - case 2064: state = 2065; break; // &foral -> &forall - case 2107: state = 2108; break; // &fras -> &frasl - case 2118: state = 2204; break; // &g -> &gl - case 2148: state = 2149; break; // &Gcedi -> &Gcedil - case 2165: state = 2167; break; // &gE -> &gEl - case 2166: state = 2168; break; // &ge -> &gel - case 2171: state = 2172; break; // &geqs -> &geqsl - case 2176: state = 2184; break; // &ges -> &gesl - case 2182: state = 2183; break; // &gesdoto -> &gesdotol - case 2196: state = 2197; break; // &gime -> &gimel - case 2241: state = 2242; break; // &GreaterEqua -> &GreaterEqual - case 2248: state = 2249; break; // &GreaterFu -> &GreaterFul - case 2249: state = 2250; break; // &GreaterFul -> &GreaterFull - case 2254: state = 2255; break; // &GreaterFullEqua -> &GreaterFullEqual - case 2267: state = 2268; break; // &GreaterS -> &GreaterSl - case 2275: state = 2276; break; // &GreaterSlantEqua -> &GreaterSlantEqual - case 2278: state = 2279; break; // &GreaterTi -> &GreaterTil - case 2289: state = 2291; break; // &gsim -> &gsiml - case 2294: state = 2302; break; // > -> >l - case 2311: state = 2334; break; // >r -> >rl - case 2324: state = 2325; break; // >req -> >reql - case 2329: state = 2330; break; // >reqq -> >reqql - case 2357: state = 2362; break; // &ha -> &hal - case 2365: state = 2366; break; // &hami -> &hamil - case 2397: state = 2405; break; // &he -> &hel - case 2405: state = 2406; break; // &hel -> &hell - case 2417: state = 2418; break; // &Hi -> &Hil - case 2449: state = 2450; break; // &hook -> &hookl - case 2484: state = 2485; break; // &Horizonta -> &Horizontal - case 2493: state = 2496; break; // &hs -> &hsl - case 2522: state = 2523; break; // &HumpEqua -> &HumpEqual - case 2526: state = 2527; break; // &hybu -> &hybul - case 2527: state = 2528; break; // &hybul -> &hybull - case 2565: state = 2566; break; // &iexc -> ¡ - case 2596: state = 2597; break; // &IJ -> &IJl - case 2600: state = 2601; break; // &ij -> &ijl - case 2612: state = 2621; break; // &imag -> &imagl - case 2636: state = 2637; break; // &Imp -> &Impl - case 2658: state = 2684; break; // &int -> &intl - case 2660: state = 2661; break; // &intca -> &intcal - case 2670: state = 2671; break; // &Integra -> &Integral - case 2674: state = 2675; break; // &interca -> &intercal - case 2697: state = 2698; break; // &Invisib -> &Invisibl - case 2757: state = 2758; break; // &Iti -> &Itil - case 2761: state = 2762; break; // &iti -> &itil - case 2773: state = 2774; break; // &Ium -> Ï - case 2775: state = 2776; break; // &ium -> ï - case 2839: state = 2840; break; // &Kcedi -> &Kcedil - case 2844: state = 2845; break; // &kcedi -> &kcedil - case 2881: state = 3409; break; // &l -> &ll - case 2886: state = 3408; break; // &L -> &Ll - case 2918: state = 2920; break; // &lang -> &langl - case 2923: state = 2924; break; // &Lap -> &Lapl - case 2939: state = 2947; break; // &larr -> &larrl - case 2949: state = 2950; break; // &larrp -> &larrpl - case 2954: state = 2955; break; // &larrt -> &larrtl - case 2959: state = 2960; break; // &lAtai -> &lAtail - case 2962: state = 2963; break; // &latai -> &latail - case 2984: state = 2985; break; // &lbrks -> &lbrksl - case 3000: state = 3001; break; // &Lcedi -> &Lcedil - case 3004: state = 3005; break; // &lcedi -> &lcedil - case 3006: state = 3007; break; // &lcei -> &lceil - case 3038: state = 3039; break; // &LeftAng -> &LeftAngl - case 3058: state = 3139; break; // &left -> &leftl - case 3079: state = 3080; break; // &leftarrowtai -> &leftarrowtail - case 3083: state = 3084; break; // &LeftCei -> &LeftCeil - case 3091: state = 3092; break; // &LeftDoub -> &LeftDoubl - case 3121: state = 3122; break; // &LeftF -> &LeftFl - case 3232: state = 3233; break; // &LeftTriang -> &LeftTriangl - case 3241: state = 3242; break; // &LeftTriangleEqua -> &LeftTriangleEqual - case 3286: state = 3287; break; // &leqs -> &leqsl - case 3326: state = 3327; break; // &LessEqua -> &LessEqual - case 3336: state = 3337; break; // &LessFu -> &LessFul - case 3337: state = 3338; break; // &LessFul -> &LessFull - case 3342: state = 3343; break; // &LessFullEqua -> &LessFullEqual - case 3361: state = 3362; break; // &LessS -> &LessSl - case 3369: state = 3370; break; // &LessSlantEqua -> &LessSlantEqual - case 3372: state = 3373; break; // &LessTi -> &LessTil - case 3376: state = 3381; break; // &lf -> &lfl - case 3397: state = 3398; break; // &lharu -> &lharul - case 3399: state = 3400; break; // &lhb -> &lhbl - case 3477: state = 3487; break; // &Long -> &Longl - case 3497: state = 3498; break; // &long -> &longl - case 3579: state = 3580; break; // &looparrow -> &looparrowl - case 3589: state = 3595; break; // &lop -> &lopl - case 3640: state = 3641; break; // &lpar -> &lparl - case 3692: state = 3708; break; // < -> <l - case 3745: state = 3855; break; // &m -> &ml - case 3746: state = 3749; break; // &ma -> &mal - case 3761: state = 3766; break; // &mapsto -> &mapstol - case 3801: state = 3802; break; // &measuredang -> &measuredangl - case 3804: state = 3814; break; // &Me -> &Mel - case 3814: state = 3815; break; // &Mel -> &Mell - case 3851: state = 3852; break; // &MinusP -> &MinusPl - case 3861: state = 3862; break; // &mnp -> &mnpl - case 3867: state = 3868; break; // &mode -> &model - case 3887: state = 3888; break; // &mu -> &mul - case 3897: state = 4121; break; // &n -> &nl - case 3899: state = 3900; break; // &nab -> &nabl - case 3927: state = 3928; break; // &natura -> &natural - case 3950: state = 3951; break; // &Ncedi -> &Ncedil - case 3954: state = 3955; break; // &ncedi -> &ncedil - case 4086: state = 4087; break; // &ngeqs -> &ngeqsl - case 4132: state = 4177; break; // &nL -> &nLl - case 4170: state = 4171; break; // &nleqs -> &nleqsl - case 4234: state = 4235; break; // &NotDoub -> &NotDoubl - case 4243: state = 4244; break; // &NotDoubleVertica -> &NotDoubleVertical - case 4248: state = 4249; break; // &NotE -> &NotEl - case 4257: state = 4258; break; // &NotEqua -> &NotEqual - case 4260: state = 4261; break; // &NotEqualTi -> &NotEqualTil - case 4279: state = 4280; break; // &NotGreaterEqua -> &NotGreaterEqual - case 4282: state = 4283; break; // &NotGreaterFu -> &NotGreaterFul - case 4283: state = 4284; break; // &NotGreaterFul -> &NotGreaterFull - case 4288: state = 4289; break; // &NotGreaterFullEqua -> &NotGreaterFullEqual - case 4301: state = 4302; break; // &NotGreaterS -> &NotGreaterSl - case 4309: state = 4310; break; // &NotGreaterSlantEqua -> &NotGreaterSlantEqual - case 4312: state = 4313; break; // &NotGreaterTi -> &NotGreaterTil - case 4331: state = 4332; break; // &NotHumpEqua -> &NotHumpEqual - case 4352: state = 4353; break; // &NotLeftTriang -> &NotLeftTriangl - case 4361: state = 4362; break; // &NotLeftTriangleEqua -> &NotLeftTriangleEqual - case 4368: state = 4369; break; // &NotLessEqua -> &NotLessEqual - case 4381: state = 4382; break; // &NotLessS -> &NotLessSl - case 4389: state = 4390; break; // &NotLessSlantEqua -> &NotLessSlantEqual - case 4392: state = 4393; break; // &NotLessTi -> &NotLessTil - case 4441: state = 4442; break; // &NotPrecedesEqua -> &NotPrecedesEqual - case 4443: state = 4444; break; // &NotPrecedesS -> &NotPrecedesSl - case 4451: state = 4452; break; // &NotPrecedesSlantEqua -> &NotPrecedesSlantEqual - case 4460: state = 4461; break; // &NotReverseE -> &NotReverseEl - case 4476: state = 4477; break; // &NotRightTriang -> &NotRightTriangl - case 4485: state = 4486; break; // &NotRightTriangleEqua -> &NotRightTriangleEqual - case 4502: state = 4503; break; // &NotSquareSubsetEqua -> &NotSquareSubsetEqual - case 4513: state = 4514; break; // &NotSquareSupersetEqua -> &NotSquareSupersetEqual - case 4523: state = 4524; break; // &NotSubsetEqua -> &NotSubsetEqual - case 4534: state = 4535; break; // &NotSucceedsEqua -> &NotSucceedsEqual - case 4536: state = 4537; break; // &NotSucceedsS -> &NotSucceedsSl - case 4544: state = 4545; break; // &NotSucceedsSlantEqua -> &NotSucceedsSlantEqual - case 4547: state = 4548; break; // &NotSucceedsTi -> &NotSucceedsTil - case 4560: state = 4561; break; // &NotSupersetEqua -> &NotSupersetEqual - case 4563: state = 4564; break; // &NotTi -> &NotTil - case 4570: state = 4571; break; // &NotTildeEqua -> &NotTildeEqual - case 4573: state = 4574; break; // &NotTildeFu -> &NotTildeFul - case 4574: state = 4575; break; // &NotTildeFul -> &NotTildeFull - case 4579: state = 4580; break; // &NotTildeFullEqua -> &NotTildeFullEqual - case 4582: state = 4583; break; // &NotTildeTi -> &NotTildeTil - case 4592: state = 4593; break; // &NotVertica -> &NotVertical - case 4600: state = 4601; break; // &npara -> &nparal - case 4601: state = 4602; break; // &nparal -> &nparall - case 4603: state = 4604; break; // &nparalle -> &nparallel - case 4605: state = 4606; break; // &npars -> &nparsl - case 4608: state = 4609; break; // &npo -> &npol - case 4673: state = 4674; break; // &nshortpara -> &nshortparal - case 4674: state = 4675; break; // &nshortparal -> &nshortparall - case 4676: state = 4677; break; // &nshortparalle -> &nshortparallel - case 4718: state = 4730; break; // &nt -> &ntl - case 4719: state = 4720; break; // &ntg -> &ntgl - case 4722: state = 4723; break; // &Nti -> &Ntil - case 4726: state = 4727; break; // &nti -> &ntil - case 4736: state = 4737; break; // &ntriang -> &ntriangl - case 4738: state = 4739; break; // &ntriangle -> &ntrianglel - case 4760: state = 4792; break; // &nv -> &nvl - case 4833: state = 4908; break; // &o -> &ol - case 4856: state = 4857; break; // &Odb -> &Odbl - case 4860: state = 4861; break; // &odb -> &odbl - case 4869: state = 4870; break; // &odso -> &odsol - case 4872: state = 4873; break; // &OE -> &OEl - case 4876: state = 4877; break; // &oe -> &oel - case 4957: state = 4987; break; // &op -> &opl - case 4965: state = 4966; break; // &OpenCur -> &OpenCurl - case 4971: state = 4972; break; // &OpenCurlyDoub -> &OpenCurlyDoubl - case 5008: state = 5009; break; // &ors -> &orsl - case 5015: state = 5021; break; // &Os -> &Osl - case 5018: state = 5025; break; // &os -> &osl - case 5029: state = 5030; break; // &oso -> &osol - case 5032: state = 5033; break; // &Oti -> &Otil - case 5037: state = 5038; break; // &oti -> &otil - case 5050: state = 5051; break; // &Oum -> Ö - case 5053: state = 5054; break; // &oum -> ö - case 5083: state = 5150; break; // &p -> &pl - case 5086: state = 5087; break; // ¶ -> ¶l - case 5087: state = 5088; break; // ¶l -> ¶ll - case 5089: state = 5090; break; // ¶lle -> ¶llel - case 5091: state = 5094; break; // &pars -> &parsl - case 5096: state = 5172; break; // &P -> &Pl - case 5101: state = 5102; break; // &Partia -> &Partial - case 5117: state = 5118; break; // &permi -> &permil - case 5196: state = 5197; break; // &Poincarep -> &Poincarepl - case 5233: state = 5234; break; // &preccur -> &preccurl - case 5247: state = 5248; break; // &PrecedesEqua -> &PrecedesEqual - case 5249: state = 5250; break; // &PrecedesS -> &PrecedesSl - case 5257: state = 5258; break; // &PrecedesSlantEqua -> &PrecedesSlantEqual - case 5260: state = 5261; break; // &PrecedesTi -> &PrecedesTil - case 5303: state = 5308; break; // &prof -> &profl - case 5304: state = 5305; break; // &profa -> &profal - case 5324: state = 5325; break; // &Proportiona -> &Proportional - case 5333: state = 5334; break; // &prure -> &prurel - case 5397: state = 5854; break; // &r -> &rl - case 5426: state = 5429; break; // &rang -> &rangl - case 5439: state = 5450; break; // &rarr -> &rarrl - case 5452: state = 5453; break; // &rarrp -> &rarrpl - case 5457: state = 5458; break; // &Rarrt -> &Rarrtl - case 5459: state = 5460; break; // &rarrt -> &rarrtl - case 5464: state = 5465; break; // &rAtai -> &rAtail - case 5468: state = 5469; break; // &ratai -> &ratail - case 5473: state = 5474; break; // &rationa -> &rational - case 5498: state = 5499; break; // &rbrks -> &rbrksl - case 5514: state = 5515; break; // &Rcedi -> &Rcedil - case 5518: state = 5519; break; // &rcedi -> &rcedil - case 5520: state = 5521; break; // &rcei -> &rceil - case 5526: state = 5529; break; // &rd -> &rdl - case 5542: state = 5543; break; // &rea -> &real - case 5562: state = 5563; break; // &ReverseE -> &ReverseEl - case 5571: state = 5572; break; // &ReverseEqui -> &ReverseEquil - case 5584: state = 5585; break; // &ReverseUpEqui -> &ReverseUpEquil - case 5592: state = 5597; break; // &rf -> &rfl - case 5611: state = 5612; break; // &rharu -> &rharul - case 5623: state = 5624; break; // &RightAng -> &RightAngl - case 5645: state = 5725; break; // &right -> &rightl - case 5665: state = 5666; break; // &rightarrowtai -> &rightarrowtail - case 5669: state = 5670; break; // &RightCei -> &RightCeil - case 5677: state = 5678; break; // &RightDoub -> &RightDoubl - case 5707: state = 5708; break; // &RightF -> &RightFl - case 5792: state = 5793; break; // &RightTriang -> &RightTriangl - case 5801: state = 5802; break; // &RightTriangleEqua -> &RightTriangleEqual - case 5884: state = 5891; break; // &rop -> &ropl - case 5904: state = 5905; break; // &RoundImp -> &RoundImpl - case 5915: state = 5916; break; // &rppo -> &rppol - case 5961: state = 5964; break; // &rtri -> &rtril - case 5968: state = 5969; break; // &Ru -> &Rul - case 5972: state = 5973; break; // &RuleDe -> &RuleDel - case 5978: state = 5979; break; // &ru -> &rul - case 5991: state = 6188; break; // &s -> &sl - case 6019: state = 6020; break; // &Scedi -> &Scedil - case 6022: state = 6023; break; // &scedi -> &scedil - case 6038: state = 6039; break; // &scpo -> &scpol - case 6135: state = 6136; break; // &shortpara -> &shortparal - case 6136: state = 6137; break; // &shortparal -> &shortparall - case 6138: state = 6139; break; // &shortparalle -> &shortparallel - case 6168: state = 6176; break; // &sim -> &siml - case 6180: state = 6181; break; // &simp -> &simpl - case 6193: state = 6194; break; // &Sma -> &Smal - case 6194: state = 6195; break; // &Smal -> &Small - case 6199: state = 6200; break; // &SmallCirc -> &SmallCircl - case 6203: state = 6204; break; // &sma -> &smal - case 6204: state = 6205; break; // &smal -> &small - case 6221: state = 6222; break; // &smepars -> &smeparsl - case 6223: state = 6225; break; // &smi -> &smil - case 6235: state = 6240; break; // &so -> &sol - case 6314: state = 6315; break; // &SquareSubsetEqua -> &SquareSubsetEqual - case 6325: state = 6326; break; // &SquareSupersetEqua -> &SquareSupersetEqual - case 6349: state = 6350; break; // &ssmi -> &ssmil - case 6372: state = 6373; break; // &straightepsi -> &straightepsil - case 6394: state = 6395; break; // &submu -> &submul - case 6400: state = 6401; break; // &subp -> &subpl - case 6420: state = 6421; break; // &SubsetEqua -> &SubsetEqual - case 6441: state = 6442; break; // &succcur -> &succcurl - case 6455: state = 6456; break; // &SucceedsEqua -> &SucceedsEqual - case 6457: state = 6458; break; // &SucceedsS -> &SucceedsSl - case 6465: state = 6466; break; // &SucceedsSlantEqua -> &SucceedsSlantEqual - case 6468: state = 6469; break; // &SucceedsTi -> &SucceedsTil - case 6500: state = 6531; break; // &sup -> &supl - case 6523: state = 6524; break; // &SupersetEqua -> &SupersetEqual - case 6527: state = 6528; break; // &suphso -> &suphsol - case 6536: state = 6537; break; // &supmu -> &supmul - case 6542: state = 6543; break; // &supp -> &suppl - case 6579: state = 6580; break; // &sz -> &szl - case 6609: state = 6610; break; // &Tcedi -> &Tcedil - case 6613: state = 6614; break; // &tcedi -> &tcedil - case 6620: state = 6621; break; // &te -> &tel - case 6696: state = 6697; break; // &Ti -> &Til - case 6700: state = 6701; break; // &ti -> &til - case 6707: state = 6708; break; // &TildeEqua -> &TildeEqual - case 6710: state = 6711; break; // &TildeFu -> &TildeFul - case 6711: state = 6712; break; // &TildeFul -> &TildeFull - case 6716: state = 6717; break; // &TildeFullEqua -> &TildeFullEqual - case 6719: state = 6720; break; // &TildeTi -> &TildeTil - case 6767: state = 6768; break; // &triang -> &triangl - case 6769: state = 6774; break; // &triangle -> &trianglel - case 6799: state = 6800; break; // &Trip -> &Tripl - case 6805: state = 6806; break; // &trip -> &tripl - case 6853: state = 6854; break; // &twohead -> &twoheadl - case 6879: state = 6965; break; // &u -> &ul - case 6925: state = 6926; break; // &Udb -> &Udbl - case 6929: state = 6930; break; // &udb -> &udbl - case 6959: state = 6960; break; // &uhar -> &uharl - case 6962: state = 6963; break; // &uhb -> &uhbl - case 6982: state = 6986; break; // &um -> ¨ - case 7015: state = 7016; break; // &UnionP -> &UnionPl - case 7042: state = 7114; break; // &up -> &upl - case 7090: state = 7091; break; // &UpEqui -> &UpEquil - case 7104: state = 7105; break; // &upharpoon -> &upharpoonl - case 7140: state = 7144; break; // &Upsi -> &Upsil - case 7142: state = 7147; break; // &upsi -> &upsil - case 7197: state = 7198; break; // &Uti -> &Util - case 7201: state = 7202; break; // &uti -> &util - case 7213: state = 7214; break; // &Uum -> Ü - case 7215: state = 7216; break; // &uum -> ü - case 7220: state = 7221; break; // &uwang -> &uwangl - case 7223: state = 7398; break; // &v -> &vl - case 7233: state = 7234; break; // &varepsi -> &varepsil - case 7295: state = 7296; break; // &vartriang -> &vartriangl - case 7297: state = 7298; break; // &vartriangle -> &vartrianglel - case 7326: state = 7335; break; // &Vdash -> &Vdashl - case 7338: state = 7345; break; // &ve -> &vel - case 7345: state = 7346; break; // &vel -> &vell - case 7361: state = 7362; break; // &Vertica -> &Vertical - case 7380: state = 7381; break; // &VerticalTi -> &VerticalTil - case 7495: state = 7522; break; // &x -> &xl - case 7542: state = 7544; break; // &xop -> &xopl - case 7569: state = 7570; break; // &xup -> &xupl - case 7641: state = 7642; break; // &Yum -> &Yuml - case 7643: state = 7644; break; // &yum -> ÿ - default: return false; - } - break; - case 'm': - switch (state) { - case 0: state = 3745; break; // & -> &m - case 1: state = 75; break; // &A -> &Am - case 7: state = 79; break; // &a -> &am - case 64: state = 65; break; // &alefsy -> &alefsym - case 102: state = 106; break; // &ang -> &angm - case 191: state = 192; break; // &asy -> &asym - case 206: state = 207; break; // &Au -> &Aum - case 209: state = 210; break; // &au -> &aum - case 239: state = 240; break; // &backpri -> &backprim - case 243: state = 244; break; // &backsi -> &backsim - case 288: state = 300; break; // &be -> &bem - case 352: state = 353; break; // &bigoti -> &bigotim - case 464: state = 465; break; // &botto -> &bottom - case 470: state = 494; break; // &box -> &boxm - case 504: state = 505; break; // &boxti -> &boxtim - case 534: state = 535; break; // &bpri -> &bprim - case 555: state = 556; break; // &bse -> &bsem - case 558: state = 559; break; // &bsi -> &bsim - case 568: state = 573; break; // &bu -> &bum - case 577: state = 578; break; // &Bu -> &Bum - case 675: state = 676; break; // &ccupss -> &ccupssm - case 683: state = 693; break; // &ce -> &cem - case 724: state = 725; break; // &check -> &checkm - case 733: state = 796; break; // &cir -> &cirm - case 785: state = 786; break; // &CircleTi -> &CircleTim - case 860: state = 867; break; // &co -> &com - case 867: state = 868; break; // &com -> &comm - case 875: state = 876; break; // &comple -> &complem - case 1029: state = 1030; break; // &curarr -> &curarrm - case 1161: state = 1170; break; // &de -> &dem - case 1192: state = 1231; break; // &Dia -> &Diam - case 1229: state = 1230; break; // &dia -> &diam - case 1256: state = 1257; break; // &diga -> &digam - case 1257: state = 1258; break; // &digam -> &digamm - case 1270: state = 1271; break; // ÷onti -> ÷ontim - case 1302: state = 1316; break; // &dot -> &dotm - case 1656: state = 1746; break; // &E -> &Em - case 1662: state = 1750; break; // &e -> &em - case 1730: state = 1731; break; // &Ele -> &Elem - case 1763: state = 1764; break; // &EmptyS -> &EmptySm - case 1779: state = 1780; break; // &EmptyVeryS -> &EmptyVerySm - case 1843: state = 1844; break; // &eqsi -> &eqsim - case 1878: state = 1879; break; // &Equilibriu -> &Equilibrium - case 1906: state = 1907; break; // &Esi -> &Esim - case 1908: state = 1909; break; // &esi -> &esim - case 1917: state = 1918; break; // &Eu -> &Eum - case 1920: state = 1921; break; // &eu -> &eum - case 1982: state = 1983; break; // &fe -> &fem - case 2010: state = 2011; break; // &FilledS -> &FilledSm - case 2025: state = 2026; break; // &FilledVeryS -> &FilledVerySm - case 2119: state = 2129; break; // &ga -> &gam - case 2125: state = 2126; break; // &Ga -> &Gam - case 2126: state = 2127; break; // &Gam -> &Gamm - case 2129: state = 2130; break; // &gam -> &gamm - case 2194: state = 2195; break; // &gi -> &gim - case 2220: state = 2221; break; // &gnsi -> &gnsim - case 2288: state = 2289; break; // &gsi -> &gsim - case 2339: state = 2340; break; // >rsi -> >rsim - case 2357: state = 2364; break; // &ha -> &ham - case 2440: state = 2444; break; // &ho -> &hom - case 2508: state = 2509; break; // &Hu -> &Hum - case 2516: state = 2517; break; // &HumpDownHu -> &HumpDownHum - case 2533: state = 2604; break; // &I -> &Im - case 2539: state = 2608; break; // &i -> &im - case 2701: state = 2702; break; // &InvisibleCo -> &InvisibleCom - case 2702: state = 2703; break; // &InvisibleCom -> &InvisibleComm - case 2706: state = 2707; break; // &InvisibleTi -> &InvisibleTim - case 2765: state = 2773; break; // &Iu -> &Ium - case 2769: state = 2775; break; // &iu -> &ium - case 2782: state = 2793; break; // &j -> &jm - case 2881: state = 3439; break; // &l -> &lm - case 2886: state = 3434; break; // &L -> &Lm - case 2887: state = 2907; break; // &La -> &Lam - case 2892: state = 2911; break; // &la -> &lam - case 2897: state = 2898; break; // &lae -> &laem - case 2952: state = 2953; break; // &larrsi -> &larrsim - case 3224: state = 3225; break; // &leftthreeti -> &leftthreetim - case 3359: state = 3360; break; // &lesssi -> &lesssim - case 3464: state = 3465; break; // &lnsi -> &lnsim - case 3497: state = 3537; break; // &long -> &longm - case 3599: state = 3600; break; // &loti -> &lotim - case 3643: state = 3657; break; // &lr -> &lrm - case 3673: state = 3674; break; // &lsi -> &lsim - case 3704: state = 3705; break; // <i -> <im - case 3777: state = 3778; break; // &mco -> &mcom - case 3778: state = 3779; break; // &mcom -> &mcomm - case 3807: state = 3808; break; // &Mediu -> &Medium - case 3887: state = 3894; break; // &mu -> &mum - case 3890: state = 3891; break; // &multi -> &multim - case 3897: state = 4187; break; // &n -> &nm - case 3933: state = 3934; break; // &nbu -> &nbum - case 3995: state = 3996; break; // &NegativeMediu -> &NegativeMedium - case 4039: state = 4040; break; // &nesi -> &nesim - case 4095: state = 4096; break; // &ngsi -> &ngsim - case 4179: state = 4180; break; // &nlsi -> &nlsim - case 4250: state = 4251; break; // &NotEle -> &NotElem - case 4317: state = 4318; break; // &NotHu -> &NotHum - case 4325: state = 4326; break; // &NotHumpDownHu -> &NotHumpDownHum - case 4462: state = 4463; break; // &NotReverseEle -> &NotReverseElem - case 4653: state = 4682; break; // &ns -> &nsm - case 4666: state = 4667; break; // &nshort -> &nshortm - case 4678: state = 4679; break; // &nsi -> &nsim - case 4753: state = 4754; break; // &nu -> &num - case 4810: state = 4811; break; // &nvsi -> &nvsim - case 4827: state = 4923; break; // &O -> &Om - case 4833: state = 4927; break; // &o -> &om - case 4900: state = 4904; break; // &oh -> &ohm - case 4995: state = 5001; break; // &ord -> º - case 5032: state = 5041; break; // &Oti -> &Otim - case 5037: state = 5044; break; // &oti -> &otim - case 5049: state = 5050; break; // &Ou -> &Oum - case 5052: state = 5053; break; // &ou -> &oum - case 5083: state = 5188; break; // &p -> &pm - case 5092: state = 5093; break; // &parsi -> &parsim - case 5109: state = 5116; break; // &per -> &perm - case 5130: state = 5133; break; // &ph -> &phm - case 5133: state = 5134; break; // &phm -> &phmm - case 5159: state = 5180; break; // &plus -> &plusm - case 5183: state = 5184; break; // &plussi -> &plussim - case 5277: state = 5278; break; // &precnsi -> &precnsim - case 5280: state = 5281; break; // &precsi -> &precsim - case 5282: state = 5283; break; // &Pri -> &Prim - case 5285: state = 5286; break; // &pri -> &prim - case 5294: state = 5295; break; // &prnsi -> &prnsim - case 5329: state = 5330; break; // &prsi -> &prsim - case 5365: state = 5366; break; // &qpri -> &qprim - case 5397: state = 5862; break; // &r -> &rm - case 5417: state = 5418; break; // &rae -> &raem - case 5455: state = 5456; break; // &rarrsi -> &rarrsim - case 5564: state = 5565; break; // &ReverseEle -> &ReverseElem - case 5577: state = 5578; break; // &ReverseEquilibriu -> &ReverseEquilibrium - case 5590: state = 5591; break; // &ReverseUpEquilibriu -> &ReverseUpEquilibrium - case 5784: state = 5785; break; // &rightthreeti -> &rightthreetim - case 5854: state = 5861; break; // &rl -> &rlm - case 5871: state = 5872; break; // &rn -> &rnm - case 5895: state = 5896; break; // &roti -> &rotim - case 5902: state = 5903; break; // &RoundI -> &RoundIm - case 5956: state = 5957; break; // &rti -> &rtim - case 5985: state = 6192; break; // &S -> &Sm - case 5991: state = 6202; break; // &s -> &sm - case 6035: state = 6036; break; // &scnsi -> &scnsim - case 6044: state = 6045; break; // &scsi -> &scsim - case 6053: state = 6066; break; // &se -> &sem - case 6072: state = 6073; break; // &set -> &setm - case 6128: state = 6129; break; // &short -> &shortm - case 6159: state = 6160; break; // &Sig -> &Sigm - case 6162: state = 6168; break; // &si -> &sim - case 6163: state = 6164; break; // &sig -> &sigm - case 6208: state = 6209; break; // &smallset -> &smallsetm - case 6341: state = 6348; break; // &ss -> &ssm - case 6345: state = 6346; break; // &sset -> &ssetm - case 6381: state = 6495; break; // &Su -> &Sum - case 6383: state = 6496; break; // &su -> &sum - case 6384: state = 6393; break; // &sub -> &subm - case 6426: state = 6427; break; // &subsi -> &subsim - case 6485: state = 6486; break; // &succnsi -> &succnsim - case 6488: state = 6489; break; // &succsi -> &succsim - case 6500: state = 6535; break; // &sup -> &supm - case 6559: state = 6560; break; // &supsi -> &supsim - case 6651: state = 6652; break; // &thetasy -> &thetasym - case 6664: state = 6665; break; // &thicksi -> &thicksim - case 6687: state = 6688; break; // &thksi -> &thksim - case 6700: state = 6723; break; // &ti -> &tim - case 6753: state = 6754; break; // &tpri -> &tprim - case 6764: state = 6792; break; // &tri -> &trim - case 6812: state = 6813; break; // &triti -> &tritim - case 6819: state = 6820; break; // &trpeziu -> &trpezium - case 6873: state = 6978; break; // &U -> &Um - case 6879: state = 6982; break; // &u -> &um - case 7096: state = 7097; break; // &UpEquilibriu -> &UpEquilibrium - case 7208: state = 7215; break; // &uu -> &uum - case 7212: state = 7213; break; // &Uu -> &Uum - case 7266: state = 7267; break; // &varsig -> &varsigm - case 7495: state = 7529; break; // &x -> &xm - case 7548: state = 7549; break; // &xoti -> &xotim - case 7637: state = 7643; break; // &yu -> &yum - case 7640: state = 7641; break; // &Yu -> &Yum - default: return false; - } - break; - case 'n': - switch (state) { - case 0: state = 3897; break; // & -> &n - case 1: state = 88; break; // &A -> &An - case 7: state = 90; break; // &a -> &an - case 92: state = 93; break; // &anda -> &andan - case 133: state = 134; break; // &Aogo -> &Aogon - case 137: state = 138; break; // &aogo -> &aogon - case 159: state = 160; break; // &ApplyFu -> &ApplyFun - case 164: state = 165; break; // &ApplyFunctio -> &ApplyFunction - case 173: state = 174; break; // &Ari -> &Arin - case 177: state = 178; break; // &ari -> &arin - case 188: state = 189; break; // &Assig -> &Assign - case 214: state = 215; break; // &awco -> &awcon - case 216: state = 217; break; // &awconi -> &awconin - case 219: state = 220; break; // &awi -> &awin - case 222: state = 445; break; // &b -> &bn - case 227: state = 228; break; // &backco -> &backcon - case 235: state = 236; break; // &backepsilo -> &backepsilon - case 278: state = 279; break; // &bco -> &bcon - case 308: state = 309; break; // &ber -> &bern - case 312: state = 313; break; // &Ber -> &Bern - case 327: state = 328; break; // &betwee -> &between - case 367: state = 368; break; // &bigtria -> &bigtrian - case 374: state = 375; break; // &bigtriangledow -> &bigtriangledown - case 397: state = 434; break; // &bla -> &blan - case 403: state = 404; break; // &blackloze -> &blacklozen - case 416: state = 417; break; // &blacktria -> &blacktrian - case 423: state = 424; break; // &blacktriangledow -> &blacktriangledown - case 495: state = 496; break; // &boxmi -> &boxmin - case 597: state = 598; break; // &capa -> &capan - case 623: state = 624; break; // &CapitalDiffere -> &CapitalDifferen - case 634: state = 635; break; // &caro -> &caron - case 648: state = 649; break; // &Ccaro -> &Ccaron - case 651: state = 652; break; // &ccaro -> &ccaron - case 667: state = 668; break; // &Cco -> &Ccon - case 669: state = 670; break; // &Cconi -> &Cconin - case 683: state = 698; break; // &ce -> &cen - case 687: state = 700; break; // &Ce -> &Cen - case 776: state = 777; break; // &CircleMi -> &CircleMin - case 791: state = 792; break; // &cirf -> &cirfn - case 793: state = 794; break; // &cirfni -> &cirfnin - case 812: state = 813; break; // &ClockwiseCo -> &ClockwiseCon - case 818: state = 819; break; // &ClockwiseContourI -> &ClockwiseContourIn - case 856: state = 888; break; // &Co -> &Con - case 858: state = 859; break; // &Colo -> &Colon - case 860: state = 883; break; // &co -> &con - case 862: state = 863; break; // &colo -> &colon - case 872: state = 873; break; // &compf -> &compfn - case 877: state = 878; break; // &compleme -> &complemen - case 892: state = 893; break; // &Congrue -> &Congruen - case 895: state = 896; break; // &Coni -> &Conin - case 898: state = 899; break; // &coni -> &conin - case 905: state = 906; break; // &ContourI -> &ContourIn - case 932: state = 933; break; // &Cou -> &Coun - case 947: state = 948; break; // &CounterClockwiseCo -> &CounterClockwiseCon - case 953: state = 954; break; // &CounterClockwiseContourI -> &CounterClockwiseContourIn - case 1052: state = 1053; break; // &curre -> ¤ - case 1078: state = 1079; break; // &cwco -> &cwcon - case 1080: state = 1081; break; // &cwconi -> &cwconin - case 1083: state = 1084; break; // &cwi -> &cwin - case 1132: state = 1133; break; // &Dcaro -> &Dcaron - case 1137: state = 1138; break; // &dcaro -> &dcaron - case 1232: state = 1233; break; // &Diamo -> &Diamon - case 1235: state = 1236; break; // &diamo -> &diamon - case 1248: state = 1249; break; // &Differe -> &Differen - case 1261: state = 1262; break; // &disi -> &disin - case 1267: state = 1268; break; // ÷o -> ÷on - case 1274: state = 1275; break; // &divo -> &divon - case 1286: state = 1287; break; // &dlcor -> &dlcorn - case 1317: state = 1318; break; // &dotmi -> &dotmin - case 1348: state = 1349; break; // &DoubleCo -> &DoubleCon - case 1354: state = 1355; break; // &DoubleContourI -> &DoubleContourIn - case 1365: state = 1366; break; // &DoubleDow -> &DoubleDown - case 1394: state = 1395; break; // &DoubleLo -> &DoubleLon - case 1448: state = 1449; break; // &DoubleUpDow -> &DoubleUpDown - case 1466: state = 1467; break; // &Dow -> &Down - case 1478: state = 1479; break; // &dow -> &down - case 1502: state = 1503; break; // &downdow -> &downdown - case 1515: state = 1516; break; // &downharpoo -> &downharpoon - case 1599: state = 1600; break; // &drcor -> &drcorn - case 1639: state = 1640; break; // &dwa -> &dwan - case 1662: state = 1797; break; // &e -> &en - case 1675: state = 1676; break; // &Ecaro -> &Ecaron - case 1680: state = 1681; break; // &ecaro -> &ecaron - case 1690: state = 1691; break; // &ecolo -> &ecolon - case 1732: state = 1733; break; // &Eleme -> &Elemen - case 1735: state = 1736; break; // &eli -> &elin - case 1803: state = 1804; break; // &Eogo -> &Eogon - case 1807: state = 1808; break; // &eogo -> &eogon - case 1827: state = 1828; break; // &Epsilo -> &Epsilon - case 1830: state = 1831; break; // &epsilo -> &epsilon - case 1840: state = 1841; break; // &eqcolo -> &eqcolon - case 1846: state = 1847; break; // &eqsla -> &eqslan - case 1943: state = 1944; break; // &expectatio -> &expectation - case 1946: state = 1947; break; // &Expo -> &Expon - case 1948: state = 1949; break; // &Expone -> &Exponen - case 1955: state = 1956; break; // &expo -> &expon - case 1957: state = 1958; break; // &expone -> &exponen - case 1964: state = 2049; break; // &f -> &fn - case 1968: state = 1969; break; // &falli -> &fallin - case 2046: state = 2047; break; // &flt -> &fltn - case 2080: state = 2081; break; // &fparti -> &fpartin - case 2110: state = 2111; break; // &frow -> &frown - case 2118: state = 2208; break; // &g -> &gn - case 2173: state = 2174; break; // &geqsla -> &geqslan - case 2269: state = 2270; break; // &GreaterSla -> &GreaterSlan - case 2341: state = 2349; break; // &gv -> &gvn - case 2344: state = 2345; break; // &gvert -> &gvertn - case 2411: state = 2412; break; // &herco -> &hercon - case 2481: state = 2482; break; // &Horizo -> &Horizon - case 2487: state = 2488; break; // &HorizontalLi -> &HorizontalLin - case 2513: state = 2514; break; // &HumpDow -> &HumpDown - case 2531: state = 2532; break; // &hyphe -> &hyphen - case 2533: state = 2656; break; // &I -> &In - case 2539: state = 2641; break; // &i -> &in - case 2582: state = 2589; break; // &ii -> &iin - case 2583: state = 2587; break; // &iii -> &iiin - case 2584: state = 2585; break; // &iiii -> &iiiin - case 2591: state = 2592; break; // &iinfi -> &iinfin - case 2615: state = 2616; break; // &Imagi -> &Imagin - case 2622: state = 2623; break; // &imagli -> &imaglin - case 2647: state = 2648; break; // &infi -> &infin - case 2682: state = 2683; break; // &Intersectio -> &Intersection - case 2718: state = 2719; break; // &Iogo -> &Iogon - case 2721: state = 2722; break; // &iogo -> &iogon - case 2746: state = 2747; break; // &isi -> &isin - case 2855: state = 2856; break; // &kgree -> &kgreen - case 2881: state = 3452; break; // &l -> &ln - case 2887: state = 2915; break; // &La -> &Lan - case 2892: state = 2917; break; // &la -> &lan - case 2905: state = 2906; break; // &lagra -> &lagran - case 2991: state = 2992; break; // &Lcaro -> &Lcaron - case 2996: state = 2997; break; // &lcaro -> &lcaron - case 3036: state = 3037; break; // &LeftA -> &LeftAn - case 3085: state = 3086; break; // &LeftCeili -> &LeftCeilin - case 3101: state = 3102; break; // &LeftDow -> &LeftDown - case 3131: state = 3132; break; // &leftharpoo -> &leftharpoon - case 3135: state = 3136; break; // &leftharpoondow -> &leftharpoondown - case 3185: state = 3186; break; // &leftrightharpoo -> &leftrightharpoon - case 3230: state = 3231; break; // &LeftTria -> &LeftTrian - case 3247: state = 3248; break; // &LeftUpDow -> &LeftUpDown - case 3288: state = 3289; break; // &leqsla -> &leqslan - case 3363: state = 3364; break; // &LessSla -> &LessSlan - case 3415: state = 3416; break; // &llcor -> &llcorn - case 3466: state = 3496; break; // &lo -> &lon - case 3467: state = 3468; break; // &loa -> &loan - case 3475: state = 3476; break; // &Lo -> &Lon - case 3633: state = 3634; break; // &loze -> &lozen - case 3649: state = 3650; break; // &lrcor -> &lrcorn - case 3735: state = 3743; break; // &lv -> &lvn - case 3738: state = 3739; break; // &lvert -> &lvertn - case 3745: state = 3860; break; // &m -> &mn - case 3764: state = 3765; break; // &mapstodow -> &mapstodown - case 3799: state = 3800; break; // &measureda -> &measuredan - case 3816: state = 3817; break; // &Melli -> &Mellin - case 3827: state = 3841; break; // &mi -> &min - case 3847: state = 3848; break; // &Mi -> &Min - case 3898: state = 3912; break; // &na -> &nan - case 3943: state = 3944; break; // &Ncaro -> &Ncaron - case 3946: state = 3947; break; // &ncaro -> &ncaron - case 3956: state = 3957; break; // &nco -> &ncon - case 4004: state = 4012; break; // &NegativeThi -> &NegativeThin - case 4024: state = 4025; break; // &NegativeVeryThi -> &NegativeVeryThin - case 4069: state = 4070; break; // &NewLi -> &NewLin - case 4088: state = 4089; break; // &ngeqsla -> &ngeqslan - case 4172: state = 4173; break; // &nleqsla -> &nleqslan - case 4190: state = 4196; break; // &No -> &Non - case 4202: state = 4203; break; // &NonBreaki -> &NonBreakin - case 4216: state = 4424; break; // ¬ -> ¬n - case 4218: state = 4219; break; // &NotCo -> &NotCon - case 4223: state = 4224; break; // &NotCongrue -> &NotCongruen - case 4252: state = 4253; break; // &NotEleme -> &NotElemen - case 4303: state = 4304; break; // &NotGreaterSla -> &NotGreaterSlan - case 4322: state = 4323; break; // &NotHumpDow -> &NotHumpDown - case 4333: state = 4334; break; // ¬i -> ¬in - case 4350: state = 4351; break; // &NotLeftTria -> &NotLeftTrian - case 4383: state = 4384; break; // &NotLessSla -> &NotLessSlan - case 4445: state = 4446; break; // &NotPrecedesSla -> &NotPrecedesSlan - case 4464: state = 4465; break; // &NotReverseEleme -> &NotReverseElemen - case 4474: state = 4475; break; // &NotRightTria -> &NotRightTrian - case 4538: state = 4539; break; // &NotSucceedsSla -> &NotSucceedsSlan - case 4610: state = 4611; break; // &npoli -> &npolin - case 4734: state = 4735; break; // &ntria -> &ntrian - case 4787: state = 4788; break; // &nvi -> &nvin - case 4790: state = 4791; break; // &nvinfi -> &nvinfin - case 4812: state = 4823; break; // &nw -> &nwn - case 4888: state = 4889; break; // &ogo -> &ogon - case 4905: state = 4906; break; // &oi -> &oin - case 4919: state = 4920; break; // &oli -> &olin - case 4940: state = 4941; break; // &Omicro -> &Omicron - case 4942: state = 4948; break; // &omi -> &omin - case 4945: state = 4946; break; // &omicro -> &omicron - case 4961: state = 4962; break; // &Ope -> &Open - case 5075: state = 5076; break; // &OverPare -> &OverParen - case 5110: state = 5111; break; // &perc -> &percn - case 5121: state = 5122; break; // &perte -> &perten - case 5137: state = 5138; break; // &pho -> &phon - case 5151: state = 5152; break; // &pla -> &plan - case 5176: state = 5177; break; // &PlusMi -> &PlusMin - case 5180: state = 5181; break; // &plusm -> ± - case 5190: state = 5191; break; // &Poi -> &Poin - case 5198: state = 5199; break; // &Poincarepla -> &Poincareplan - case 5202: state = 5203; break; // &poi -> &poin - case 5205: state = 5206; break; // &pointi -> &pointin - case 5212: state = 5213; break; // &pou -> &poun - case 5216: state = 5289; break; // &pr -> &prn - case 5224: state = 5266; break; // &prec -> &precn - case 5251: state = 5252; break; // &PrecedesSla -> &PrecedesSlan - case 5309: state = 5310; break; // &profli -> &proflin - case 5322: state = 5323; break; // &Proportio -> &Proportion - case 5343: state = 5344; break; // &pu -> &pun - case 5354: state = 5355; break; // &qi -> &qin - case 5378: state = 5379; break; // &quater -> &quatern - case 5381: state = 5382; break; // &quaternio -> &quaternion - case 5384: state = 5385; break; // &quati -> &quatin - case 5397: state = 5871; break; // &r -> &rn - case 5402: state = 5425; break; // &ra -> &ran - case 5406: state = 5423; break; // &Ra -> &Ran - case 5471: state = 5472; break; // &ratio -> &ration - case 5505: state = 5506; break; // &Rcaro -> &Rcaron - case 5510: state = 5511; break; // &rcaro -> &rcaron - case 5544: state = 5545; break; // &reali -> &realin - case 5566: state = 5567; break; // &ReverseEleme -> &ReverseElemen - case 5621: state = 5622; break; // &RightA -> &RightAn - case 5642: state = 5842; break; // &ri -> &rin - case 5671: state = 5672; break; // &RightCeili -> &RightCeilin - case 5687: state = 5688; break; // &RightDow -> &RightDown - case 5717: state = 5718; break; // &rightharpoo -> &rightharpoon - case 5721: state = 5722; break; // &rightharpoondow -> &rightharpoondown - case 5740: state = 5741; break; // &rightleftharpoo -> &rightleftharpoon - case 5790: state = 5791; break; // &RightTria -> &RightTrian - case 5807: state = 5808; break; // &RightUpDow -> &RightUpDown - case 5845: state = 5846; break; // &risi -> &risin - case 5876: state = 5877; break; // &roa -> &roan - case 5899: state = 5900; break; // &Rou -> &Roun - case 5917: state = 5918; break; // &rppoli -> &rppolin - case 6002: state = 6030; break; // &sc -> &scn - case 6007: state = 6008; break; // &Scaro -> &Scaron - case 6010: state = 6011; break; // &scaro -> &scaron - case 6040: state = 6041; break; // &scpoli -> &scpolin - case 6073: state = 6078; break; // &setm -> &setmn - case 6074: state = 6075; break; // &setmi -> &setmin - case 6086: state = 6087; break; // &sfrow -> &sfrown - case 6110: state = 6111; break; // &ShortDow -> &ShortDown - case 6168: state = 6178; break; // &sim -> &simn - case 6210: state = 6211; break; // &smallsetmi -> &smallsetmin - case 6293: state = 6294; break; // &SquareI -> &SquareIn - case 6303: state = 6304; break; // &SquareIntersectio -> &SquareIntersection - case 6327: state = 6328; break; // &SquareU -> &SquareUn - case 6330: state = 6331; break; // &SquareUnio -> &SquareUnion - case 6346: state = 6347; break; // &ssetm -> &ssetmn - case 6363: state = 6379; break; // &str -> &strn - case 6374: state = 6375; break; // &straightepsilo -> &straightepsilon - case 6383: state = 6497; break; // &su -> &sun - case 6384: state = 6397; break; // &sub -> &subn - case 6413: state = 6422; break; // &subset -> &subsetn - case 6432: state = 6474; break; // &succ -> &succn - case 6459: state = 6460; break; // &SucceedsSla -> &SucceedsSlan - case 6500: state = 6539; break; // &sup -> &supn - case 6551: state = 6555; break; // &supset -> &supsetn - case 6564: state = 6575; break; // &sw -> &swn - case 6600: state = 6601; break; // &Tcaro -> &Tcaron - case 6605: state = 6606; break; // &tcaro -> &tcaron - case 6654: state = 6674; break; // &thi -> &thin - case 6666: state = 6677; break; // &Thi -> &Thin - case 6694: state = 6695; break; // &thor -> þ - case 6700: state = 6730; break; // &ti -> &tin - case 6765: state = 6766; break; // &tria -> &trian - case 6772: state = 6773; break; // &triangledow -> &triangledown - case 6793: state = 6794; break; // &trimi -> &trimin - case 6873: state = 6987; break; // &U -> &Un - case 6968: state = 6969; break; // &ulcor -> &ulcorn - case 7004: state = 7005; break; // &UnderPare -> &UnderParen - case 7013: state = 7014; break; // &Unio -> &Union - case 7021: state = 7022; break; // &Uogo -> &Uogon - case 7025: state = 7026; break; // &uogo -> &uogon - case 7053: state = 7054; break; // &UpArrowDow -> &UpArrowDown - case 7062: state = 7063; break; // &UpDow -> &UpDown - case 7071: state = 7072; break; // &Updow -> &Updown - case 7080: state = 7081; break; // &updow -> &updown - case 7103: state = 7104; break; // &upharpoo -> &upharpoon - case 7145: state = 7146; break; // &Upsilo -> &Upsilon - case 7148: state = 7149; break; // &upsilo -> &upsilon - case 7169: state = 7170; break; // &urcor -> &urcorn - case 7177: state = 7178; break; // &Uri -> &Urin - case 7180: state = 7181; break; // &uri -> &urin - case 7218: state = 7219; break; // &uwa -> &uwan - case 7223: state = 7402; break; // &v -> &vn - case 7224: state = 7225; break; // &va -> &van - case 7229: state = 7242; break; // &var -> &varn - case 7235: state = 7236; break; // &varepsilo -> &varepsilon - case 7246: state = 7247; break; // &varnothi -> &varnothin - case 7273: state = 7274; break; // &varsubset -> &varsubsetn - case 7281: state = 7282; break; // &varsupset -> &varsupsetn - case 7293: state = 7294; break; // &vartria -> &vartrian - case 7367: state = 7368; break; // &VerticalLi -> &VerticalLin - case 7387: state = 7388; break; // &VeryThi -> &VeryThin - case 7428: state = 7429; break; // &vsub -> &vsubn - case 7432: state = 7433; break; // &vsup -> &vsupn - case 7495: state = 7532; break; // &x -> &xn - case 7610: state = 7611; break; // &ye -> ¥ - case 7660: state = 7661; break; // &Zcaro -> &Zcaron - case 7665: state = 7666; break; // &zcaro -> &zcaron - case 7725: state = 7727; break; // &zw -> &zwn - default: return false; - } - break; - case 'o': - switch (state) { - case 0: state = 4833; break; // & -> &o - case 1: state = 131; break; // &A -> &Ao - case 7: state = 135; break; // &a -> &ao - case 97: state = 98; break; // &andsl -> &andslo - case 132: state = 133; break; // &Aog -> &Aogo - case 136: state = 137; break; // &aog -> &aogo - case 143: state = 152; break; // &ap -> &apo - case 163: state = 164; break; // &ApplyFuncti -> &ApplyFunctio - case 167: state = 168; break; // &appr -> &appro - case 213: state = 214; break; // &awc -> &awco - case 222: state = 459; break; // &b -> &bo - case 226: state = 227; break; // &backc -> &backco - case 234: state = 235; break; // &backepsil -> &backepsilo - case 247: state = 456; break; // &B -> &Bo - case 277: state = 278; break; // &bc -> &bco - case 286: state = 287; break; // &bdqu -> &bdquo - case 309: state = 310; break; // &bern -> &berno - case 313: state = 314; break; // &Bern -> &Berno - case 334: state = 343; break; // &big -> &bigo - case 344: state = 345; break; // &bigod -> &bigodo - case 372: state = 373; break; // &bigtriangled -> &bigtriangledo - case 393: state = 394; break; // &bkar -> &bkaro - case 396: state = 442; break; // &bl -> &blo - case 400: state = 401; break; // &blackl -> &blacklo - case 421: state = 422; break; // &blacktriangled -> &blacktriangledo - case 445: state = 454; break; // &bn -> &bno - case 451: state = 452; break; // &bN -> &bNo - case 463: state = 464; break; // &bott -> &botto - case 471: state = 472; break; // &boxb -> &boxbo - case 552: state = 561; break; // &bs -> &bso - case 583: state = 856; break; // &C -> &Co - case 589: state = 860; break; // &c -> &co - case 610: state = 611; break; // &capd -> &capdo - case 631: state = 634; break; // &car -> &caro - case 645: state = 667; break; // &Cc -> &Cco - case 647: state = 648; break; // &Ccar -> &Ccaro - case 650: state = 651; break; // &ccar -> &ccaro - case 677: state = 678; break; // &Cd -> &Cdo - case 680: state = 681; break; // &cd -> &cdo - case 704: state = 705; break; // &CenterD -> &CenterDo - case 709: state = 710; break; // ¢erd -> ¢erdo - case 741: state = 742; break; // &circlearr -> &circlearro - case 770: state = 771; break; // &CircleD -> &CircleDo - case 803: state = 804; break; // &Cl -> &Clo - case 811: state = 812; break; // &ClockwiseC -> &ClockwiseCo - case 814: state = 815; break; // &ClockwiseCont -> &ClockwiseConto - case 833: state = 834; break; // &CloseCurlyD -> &CloseCurlyDo - case 840: state = 841; break; // &CloseCurlyDoubleQu -> &CloseCurlyDoubleQuo - case 845: state = 846; break; // &CloseCurlyQu -> &CloseCurlyQuo - case 857: state = 858; break; // &Col -> &Colo - case 861: state = 862; break; // &col -> &colo - case 885: state = 886; break; // &congd -> &congdo - case 901: state = 902; break; // &Cont -> &Conto - case 917: state = 918; break; // &copr -> &copro - case 920: state = 921; break; // &Copr -> &Copro - case 938: state = 939; break; // &CounterCl -> &CounterClo - case 946: state = 947; break; // &CounterClockwiseC -> &CounterClockwiseCo - case 949: state = 950; break; // &CounterClockwiseCont -> &CounterClockwiseConto - case 961: state = 969; break; // &cr -> &cro - case 965: state = 966; break; // &Cr -> &Cro - case 984: state = 985; break; // &ctd -> &ctdo - case 1006: state = 1023; break; // &cup -> &cupo - case 1020: state = 1021; break; // &cupd -> &cupdo - case 1058: state = 1059; break; // &curvearr -> &curvearro - case 1077: state = 1078; break; // &cwc -> &cwco - case 1091: state = 1296; break; // &D -> &Do - case 1097: state = 1291; break; // &d -> &do - case 1123: state = 1124; break; // &dbkar -> &dbkaro - case 1131: state = 1132; break; // &Dcar -> &Dcaro - case 1136: state = 1137; break; // &dcar -> &dcaro - case 1141: state = 1150; break; // &DD -> &DDo - case 1142: state = 1156; break; // &dd -> &ddo - case 1206: state = 1207; break; // &DiacriticalD -> &DiacriticalDo - case 1230: state = 1235; break; // &diam -> &diamo - case 1231: state = 1232; break; // &Diam -> &Diamo - case 1263: state = 1274; break; // &div -> &divo - case 1266: state = 1267; break; // ÷ -> ÷o - case 1284: state = 1285; break; // &dlc -> &dlco - case 1288: state = 1289; break; // &dlcr -> &dlcro - case 1303: state = 1304; break; // &DotD -> &DotDo - case 1308: state = 1309; break; // &doteqd -> &doteqdo - case 1347: state = 1348; break; // &DoubleC -> &DoubleCo - case 1350: state = 1351; break; // &DoubleCont -> &DoubleConto - case 1362: state = 1363; break; // &DoubleD -> &DoubleDo - case 1369: state = 1370; break; // &DoubleDownArr -> &DoubleDownArro - case 1372: state = 1394; break; // &DoubleL -> &DoubleLo - case 1378: state = 1379; break; // &DoubleLeftArr -> &DoubleLeftArro - case 1388: state = 1389; break; // &DoubleLeftRightArr -> &DoubleLeftRightArro - case 1403: state = 1404; break; // &DoubleLongLeftArr -> &DoubleLongLeftArro - case 1413: state = 1414; break; // &DoubleLongLeftRightArr -> &DoubleLongLeftRightArro - case 1423: state = 1424; break; // &DoubleLongRightArr -> &DoubleLongRightArro - case 1433: state = 1434; break; // &DoubleRightArr -> &DoubleRightArro - case 1443: state = 1444; break; // &DoubleUpArr -> &DoubleUpArro - case 1446: state = 1447; break; // &DoubleUpD -> &DoubleUpDo - case 1452: state = 1453; break; // &DoubleUpDownArr -> &DoubleUpDownArro - case 1470: state = 1471; break; // &DownArr -> &DownArro - case 1475: state = 1476; break; // &Downarr -> &Downarro - case 1482: state = 1483; break; // &downarr -> &downarro - case 1492: state = 1493; break; // &DownArrowUpArr -> &DownArrowUpArro - case 1500: state = 1501; break; // &downd -> &downdo - case 1506: state = 1507; break; // &downdownarr -> &downdownarro - case 1513: state = 1514; break; // &downharp -> &downharpo - case 1514: state = 1515; break; // &downharpo -> &downharpoo - case 1538: state = 1539; break; // &DownLeftRightVect -> &DownLeftRightVecto - case 1547: state = 1548; break; // &DownLeftTeeVect -> &DownLeftTeeVecto - case 1553: state = 1554; break; // &DownLeftVect -> &DownLeftVecto - case 1570: state = 1571; break; // &DownRightTeeVect -> &DownRightTeeVecto - case 1576: state = 1577; break; // &DownRightVect -> &DownRightVecto - case 1587: state = 1588; break; // &DownTeeArr -> &DownTeeArro - case 1594: state = 1595; break; // &drbkar -> &drbkaro - case 1597: state = 1598; break; // &drc -> &drco - case 1601: state = 1602; break; // &drcr -> &drcro - case 1607: state = 1614; break; // &ds -> &dso - case 1617: state = 1618; break; // &Dstr -> &Dstro - case 1621: state = 1622; break; // &dstr -> &dstro - case 1625: state = 1626; break; // &dtd -> &dtdo - case 1656: state = 1801; break; // &E -> &Eo - case 1662: state = 1805; break; // &e -> &eo - case 1674: state = 1675; break; // &Ecar -> &Ecaro - case 1677: state = 1688; break; // &ec -> &eco - case 1679: state = 1680; break; // &ecar -> &ecaro - case 1689: state = 1690; break; // &ecol -> &ecolo - case 1694: state = 1701; break; // &eD -> &eDo - case 1695: state = 1696; break; // &eDD -> &eDDo - case 1698: state = 1699; break; // &Ed -> &Edo - case 1703: state = 1704; break; // &ed -> &edo - case 1708: state = 1709; break; // &efD -> &efDo - case 1725: state = 1726; break; // &egsd -> &egsdo - case 1743: state = 1744; break; // &elsd -> &elsdo - case 1802: state = 1803; break; // &Eog -> &Eogo - case 1806: state = 1807; break; // &eog -> &eogo - case 1826: state = 1827; break; // &Epsil -> &Epsilo - case 1829: state = 1830; break; // &epsil -> &epsilo - case 1834: state = 1838; break; // &eqc -> &eqco - case 1839: state = 1840; break; // &eqcol -> &eqcolo - case 1894: state = 1895; break; // &erD -> &erDo - case 1903: state = 1904; break; // &esd -> &esdo - case 1923: state = 1924; break; // &eur -> &euro - case 1936: state = 1955; break; // &exp -> &expo - case 1942: state = 1943; break; // &expectati -> &expectatio - case 1945: state = 1946; break; // &Exp -> &Expo - case 1964: state = 2055; break; // &f -> &fo - case 1971: state = 1972; break; // &fallingd -> &fallingdo - case 1977: state = 2052; break; // &F -> &Fo - case 2049: state = 2050; break; // &fn -> &fno - case 2083: state = 2109; break; // &fr -> &fro - case 2118: state = 2225; break; // &g -> &go - case 2124: state = 2222; break; // &G -> &Go - case 2159: state = 2160; break; // &Gd -> &Gdo - case 2162: state = 2163; break; // &gd -> &gdo - case 2179: state = 2180; break; // &gesd -> &gesdo - case 2181: state = 2182; break; // &gesdot -> &gesdoto - case 2212: state = 2213; break; // &gnappr -> &gnappro - case 2299: state = 2300; break; // >d -> >do - case 2315: state = 2316; break; // >rappr -> >rappro - case 2320: state = 2321; break; // >rd -> >rdo - case 2351: state = 2469; break; // &H -> &Ho - case 2356: state = 2440; break; // &h -> &ho - case 2410: state = 2411; break; // &herc -> &herco - case 2432: state = 2433; break; // &hksear -> &hksearo - case 2437: state = 2438; break; // &hkswar -> &hkswaro - case 2440: state = 2448; break; // &ho -> &hoo - case 2456: state = 2457; break; // &hookleftarr -> &hookleftarro - case 2466: state = 2467; break; // &hookrightarr -> &hookrightarro - case 2480: state = 2481; break; // &Horiz -> &Horizo - case 2501: state = 2502; break; // &Hstr -> &Hstro - case 2505: state = 2506; break; // &hstr -> &hstro - case 2511: state = 2512; break; // &HumpD -> &HumpDo - case 2533: state = 2716; break; // &I -> &Io - case 2539: state = 2713; break; // &i -> &io - case 2555: state = 2556; break; // &Id -> &Ido - case 2582: state = 2593; break; // &ii -> &iio - case 2608: state = 2631; break; // &im -> &imo - case 2641: state = 2652; break; // &in -> &ino - case 2653: state = 2654; break; // &inod -> &inodo - case 2681: state = 2682; break; // &Intersecti -> &Intersectio - case 2690: state = 2691; break; // &intpr -> &intpro - case 2700: state = 2701; break; // &InvisibleC -> &InvisibleCo - case 2717: state = 2718; break; // &Iog -> &Iogo - case 2720: state = 2721; break; // &iog -> &iogo - case 2732: state = 2733; break; // &ipr -> &ipro - case 2748: state = 2749; break; // &isind -> &isindo - case 2777: state = 2797; break; // &J -> &Jo - case 2782: state = 2800; break; // &j -> &jo - case 2825: state = 2869; break; // &K -> &Ko - case 2830: state = 2872; break; // &k -> &ko - case 2881: state = 3466; break; // &l -> &lo - case 2886: state = 3475; break; // &L -> &Lo - case 2932: state = 2933; break; // &laqu -> « - case 2990: state = 2991; break; // &Lcar -> &Lcaro - case 2995: state = 2996; break; // &lcar -> &lcaro - case 3016: state = 3017; break; // &ldqu -> &ldquo - case 3049: state = 3050; break; // &LeftArr -> &LeftArro - case 3054: state = 3055; break; // &Leftarr -> &Leftarro - case 3061: state = 3062; break; // &leftarr -> &leftarro - case 3074: state = 3075; break; // &LeftArrowRightArr -> &LeftArrowRightArro - case 3088: state = 3089; break; // &LeftD -> &LeftDo - case 3109: state = 3110; break; // &LeftDownTeeVect -> &LeftDownTeeVecto - case 3115: state = 3116; break; // &LeftDownVect -> &LeftDownVecto - case 3122: state = 3123; break; // &LeftFl -> &LeftFlo - case 3123: state = 3124; break; // &LeftFlo -> &LeftFloo - case 3129: state = 3130; break; // &leftharp -> &leftharpo - case 3130: state = 3131; break; // &leftharpo -> &leftharpoo - case 3133: state = 3134; break; // &leftharpoond -> &leftharpoondo - case 3145: state = 3146; break; // &leftleftarr -> &leftleftarro - case 3156: state = 3157; break; // &LeftRightArr -> &LeftRightArro - case 3166: state = 3167; break; // &Leftrightarr -> &Leftrightarro - case 3176: state = 3177; break; // &leftrightarr -> &leftrightarro - case 3183: state = 3184; break; // &leftrightharp -> &leftrightharpo - case 3184: state = 3185; break; // &leftrightharpo -> &leftrightharpoo - case 3195: state = 3196; break; // &leftrightsquigarr -> &leftrightsquigarro - case 3201: state = 3202; break; // &LeftRightVect -> &LeftRightVecto - case 3209: state = 3210; break; // &LeftTeeArr -> &LeftTeeArro - case 3215: state = 3216; break; // &LeftTeeVect -> &LeftTeeVecto - case 3245: state = 3246; break; // &LeftUpD -> &LeftUpDo - case 3252: state = 3253; break; // &LeftUpDownVect -> &LeftUpDownVecto - case 3261: state = 3262; break; // &LeftUpTeeVect -> &LeftUpTeeVecto - case 3267: state = 3268; break; // &LeftUpVect -> &LeftUpVecto - case 3276: state = 3277; break; // &LeftVect -> &LeftVecto - case 3294: state = 3295; break; // &lesd -> &lesdo - case 3296: state = 3297; break; // &lesdot -> &lesdoto - case 3306: state = 3307; break; // &lessappr -> &lessappro - case 3309: state = 3310; break; // &lessd -> &lessdo - case 3381: state = 3382; break; // &lfl -> &lflo - case 3382: state = 3383; break; // &lflo -> &lfloo - case 3413: state = 3414; break; // &llc -> &llco - case 3424: state = 3425; break; // &Lleftarr -> &Lleftarro - case 3436: state = 3437; break; // &Lmid -> &Lmido - case 3439: state = 3444; break; // &lm -> &lmo - case 3441: state = 3442; break; // &lmid -> &lmido - case 3456: state = 3457; break; // &lnappr -> &lnappro - case 3466: state = 3573; break; // &lo -> &loo - case 3484: state = 3485; break; // &LongLeftArr -> &LongLeftArro - case 3493: state = 3494; break; // &Longleftarr -> &Longleftarro - case 3504: state = 3505; break; // &longleftarr -> &longleftarro - case 3514: state = 3515; break; // &LongLeftRightArr -> &LongLeftRightArro - case 3524: state = 3525; break; // &Longleftrightarr -> &Longleftrightarro - case 3534: state = 3535; break; // &longleftrightarr -> &longleftrightarro - case 3541: state = 3542; break; // &longmapst -> &longmapsto - case 3550: state = 3551; break; // &LongRightArr -> &LongRightArro - case 3560: state = 3561; break; // &Longrightarr -> &Longrightarro - case 3570: state = 3571; break; // &longrightarr -> &longrightarro - case 3577: state = 3578; break; // &looparr -> &looparro - case 3619: state = 3620; break; // &LowerLeftArr -> &LowerLeftArro - case 3629: state = 3630; break; // &LowerRightArr -> &LowerRightArro - case 3647: state = 3648; break; // &lrc -> &lrco - case 3664: state = 3665; break; // &lsaqu -> &lsaquo - case 3679: state = 3680; break; // &lsqu -> &lsquo - case 3683: state = 3684; break; // &Lstr -> &Lstro - case 3687: state = 3688; break; // &lstr -> &lstro - case 3697: state = 3698; break; // <d -> <do - case 3745: state = 3865; break; // &m -> &mo - case 3755: state = 3870; break; // &M -> &Mo - case 3760: state = 3761; break; // &mapst -> &mapsto - case 3762: state = 3763; break; // &mapstod -> &mapstodo - case 3776: state = 3777; break; // &mc -> &mco - case 3789: state = 3790; break; // &mDD -> &mDDo - case 3825: state = 3826; break; // &mh -> &mho - case 3829: state = 3830; break; // &micr -> µ - case 3838: state = 3839; break; // &midd -> &middo - case 3883: state = 3884; break; // &mstp -> &mstpo - case 3897: state = 4212; break; // &n -> &no - case 3902: state = 4190; break; // &N -> &No - case 3914: state = 3918; break; // &nap -> &napo - case 3921: state = 3922; break; // &nappr -> &nappro - case 3937: state = 3956; break; // &nc -> &nco - case 3942: state = 3943; break; // &Ncar -> &Ncaro - case 3945: state = 3946; break; // &ncar -> &ncaro - case 3959: state = 3960; break; // &ncongd -> &ncongdo - case 3978: state = 3979; break; // &nearr -> &nearro - case 3981: state = 3982; break; // &ned -> &nedo - case 4138: state = 4139; break; // &nLeftarr -> &nLeftarro - case 4145: state = 4146; break; // &nleftarr -> &nleftarro - case 4155: state = 4156; break; // &nLeftrightarr -> &nLeftrightarro - case 4165: state = 4166; break; // &nleftrightarr -> &nleftrightarro - case 4217: state = 4218; break; // &NotC -> &NotCo - case 4231: state = 4232; break; // &NotD -> &NotDo - case 4320: state = 4321; break; // &NotHumpD -> &NotHumpDo - case 4335: state = 4336; break; // ¬ind -> ¬indo - case 4597: state = 4608; break; // &np -> &npo - case 4637: state = 4638; break; // &nRightarr -> &nRightarro - case 4646: state = 4647; break; // &nrightarr -> &nrightarro - case 4663: state = 4664; break; // &nsh -> &nsho - case 4756: state = 4757; break; // &numer -> &numero - case 4820: state = 4821; break; // &nwarr -> &nwarro - case 4827: state = 4951; break; // &O -> &Oo - case 4833: state = 4954; break; // &o -> &oo - case 4851: state = 4866; break; // &od -> &odo - case 4868: state = 4869; break; // &ods -> &odso - case 4887: state = 4888; break; // &og -> &ogo - case 4915: state = 4916; break; // &olcr -> &olcro - case 4939: state = 4940; break; // &Omicr -> &Omicro - case 4944: state = 4945; break; // &omicr -> &omicro - case 4968: state = 4969; break; // &OpenCurlyD -> &OpenCurlyDo - case 4975: state = 4976; break; // &OpenCurlyDoubleQu -> &OpenCurlyDoubleQuo - case 4980: state = 4981; break; // &OpenCurlyQu -> &OpenCurlyQuo - case 4991: state = 5006; break; // &or -> &oro - case 4997: state = 4998; break; // &order -> &ordero - case 5003: state = 5004; break; // &orig -> &origo - case 5009: state = 5010; break; // &orsl -> &orslo - case 5018: state = 5029; break; // &os -> &oso - case 5083: state = 5201; break; // &p -> &po - case 5096: state = 5189; break; // &P -> &Po - case 5113: state = 5114; break; // &peri -> &perio - case 5130: state = 5137; break; // &ph -> &pho - case 5145: state = 5146; break; // &pitchf -> &pitchfo - case 5168: state = 5169; break; // &plusd -> &plusdo - case 5186: state = 5187; break; // &plustw -> &plustwo - case 5215: state = 5298; break; // &Pr -> &Pro - case 5216: state = 5296; break; // &pr -> &pro - case 5228: state = 5229; break; // &precappr -> &precappro - case 5270: state = 5271; break; // &precnappr -> &precnappro - case 5317: state = 5318; break; // &Prop -> &Propo - case 5321: state = 5322; break; // &Proporti -> &Proportio - case 5326: state = 5327; break; // &propt -> &propto - case 5348: state = 5357; break; // &Q -> &Qo - case 5351: state = 5360; break; // &q -> &qo - case 5374: state = 5395; break; // &qu -> &quo - case 5380: state = 5381; break; // &quaterni -> &quaternio - case 5397: state = 5875; break; // &r -> &ro - case 5405: state = 5887; break; // &R -> &Ro - case 5432: state = 5433; break; // &raqu -> » - case 5470: state = 5471; break; // &rati -> &ratio - case 5504: state = 5505; break; // &Rcar -> &Rcaro - case 5509: state = 5510; break; // &rcar -> &rcaro - case 5535: state = 5536; break; // &rdqu -> &rdquo - case 5597: state = 5598; break; // &rfl -> &rflo - case 5598: state = 5599; break; // &rflo -> &rfloo - case 5607: state = 5615; break; // &rh -> &rho - case 5613: state = 5614; break; // &Rh -> &Rho - case 5634: state = 5635; break; // &RightArr -> &RightArro - case 5639: state = 5640; break; // &Rightarr -> &Rightarro - case 5648: state = 5649; break; // &rightarr -> &rightarro - case 5660: state = 5661; break; // &RightArrowLeftArr -> &RightArrowLeftArro - case 5674: state = 5675; break; // &RightD -> &RightDo - case 5695: state = 5696; break; // &RightDownTeeVect -> &RightDownTeeVecto - case 5701: state = 5702; break; // &RightDownVect -> &RightDownVecto - case 5708: state = 5709; break; // &RightFl -> &RightFlo - case 5709: state = 5710; break; // &RightFlo -> &RightFloo - case 5715: state = 5716; break; // &rightharp -> &rightharpo - case 5716: state = 5717; break; // &rightharpo -> &rightharpoo - case 5719: state = 5720; break; // &rightharpoond -> &rightharpoondo - case 5731: state = 5732; break; // &rightleftarr -> &rightleftarro - case 5738: state = 5739; break; // &rightleftharp -> &rightleftharpo - case 5739: state = 5740; break; // &rightleftharpo -> &rightleftharpoo - case 5750: state = 5751; break; // &rightrightarr -> &rightrightarro - case 5761: state = 5762; break; // &rightsquigarr -> &rightsquigarro - case 5769: state = 5770; break; // &RightTeeArr -> &RightTeeArro - case 5775: state = 5776; break; // &RightTeeVect -> &RightTeeVecto - case 5805: state = 5806; break; // &RightUpD -> &RightUpDo - case 5812: state = 5813; break; // &RightUpDownVect -> &RightUpDownVecto - case 5821: state = 5822; break; // &RightUpTeeVect -> &RightUpTeeVecto - case 5827: state = 5828; break; // &RightUpVect -> &RightUpVecto - case 5836: state = 5837; break; // &RightVect -> &RightVecto - case 5848: state = 5849; break; // &risingd -> &risingdo - case 5862: state = 5863; break; // &rm -> &rmo - case 5914: state = 5915; break; // &rpp -> &rppo - case 5931: state = 5932; break; // &Rrightarr -> &Rrightarro - case 5937: state = 5938; break; // &rsaqu -> &rsaquo - case 5948: state = 5949; break; // &rsqu -> &rsquo - case 5985: state = 6244; break; // &S -> &So - case 5991: state = 6235; break; // &s -> &so - case 5999: state = 6000; break; // &sbqu -> &sbquo - case 6006: state = 6007; break; // &Scar -> &Scaro - case 6009: state = 6010; break; // &scar -> &scaro - case 6037: state = 6038; break; // &scp -> &scpo - case 6048: state = 6049; break; // &sd -> &sdo - case 6061: state = 6062; break; // &searr -> &searro - case 6084: state = 6085; break; // &sfr -> &sfro - case 6088: state = 6126; break; // &sh -> &sho - case 6104: state = 6105; break; // &Sh -> &Sho - case 6108: state = 6109; break; // &ShortD -> &ShortDo - case 6114: state = 6115; break; // &ShortDownArr -> &ShortDownArro - case 6123: state = 6124; break; // &ShortLeftArr -> &ShortLeftArro - case 6147: state = 6148; break; // &ShortRightArr -> &ShortRightArro - case 6154: state = 6155; break; // &ShortUpArr -> &ShortUpArro - case 6169: state = 6170; break; // &simd -> &simdo - case 6302: state = 6303; break; // &SquareIntersecti -> &SquareIntersectio - case 6329: state = 6330; break; // &SquareUni -> &SquareUnio - case 6373: state = 6374; break; // &straightepsil -> &straightepsilo - case 6385: state = 6386; break; // &subd -> &subdo - case 6390: state = 6391; break; // &subed -> &subedo - case 6436: state = 6437; break; // &succappr -> &succappro - case 6478: state = 6479; break; // &succnappr -> &succnappro - case 6504: state = 6505; break; // &supd -> &supdo - case 6512: state = 6513; break; // &suped -> &supedo - case 6526: state = 6527; break; // &suphs -> &suphso - case 6572: state = 6573; break; // &swarr -> &swarro - case 6583: state = 6742; break; // &T -> &To - case 6586: state = 6732; break; // &t -> &to - case 6599: state = 6600; break; // &Tcar -> &Tcaro - case 6604: state = 6605; break; // &tcar -> &tcaro - case 6617: state = 6618; break; // &td -> &tdo - case 6629: state = 6693; break; // &th -> &tho - case 6638: state = 6639; break; // &Theref -> &Therefo - case 6642: state = 6643; break; // &theref -> &therefo - case 6660: state = 6661; break; // &thickappr -> &thickappro - case 6736: state = 6737; break; // &topb -> &topbo - case 6745: state = 6746; break; // &topf -> &topfo - case 6770: state = 6771; break; // &triangled -> &triangledo - case 6788: state = 6789; break; // &trid -> &trido - case 6802: state = 6803; break; // &TripleD -> &TripleDo - case 6838: state = 6839; break; // &Tstr -> &Tstro - case 6842: state = 6843; break; // &tstr -> &tstro - case 6845: state = 6849; break; // &tw -> &two - case 6860: state = 6861; break; // &twoheadleftarr -> &twoheadleftarro - case 6870: state = 6871; break; // &twoheadrightarr -> &twoheadrightarro - case 6873: state = 7019; break; // &U -> &Uo - case 6879: state = 7023; break; // &u -> &uo - case 6886: state = 6892; break; // &Uarr -> &Uarro - case 6966: state = 6967; break; // &ulc -> &ulco - case 6972: state = 6973; break; // &ulcr -> &ulcro - case 7012: state = 7013; break; // &Uni -> &Unio - case 7020: state = 7021; break; // &Uog -> &Uogo - case 7024: state = 7025; break; // &uog -> &uogo - case 7034: state = 7035; break; // &UpArr -> &UpArro - case 7039: state = 7040; break; // &Uparr -> &Uparro - case 7045: state = 7046; break; // &uparr -> &uparro - case 7051: state = 7052; break; // &UpArrowD -> &UpArrowDo - case 7057: state = 7058; break; // &UpArrowDownArr -> &UpArrowDownArro - case 7060: state = 7061; break; // &UpD -> &UpDo - case 7066: state = 7067; break; // &UpDownArr -> &UpDownArro - case 7069: state = 7070; break; // &Upd -> &Updo - case 7075: state = 7076; break; // &Updownarr -> &Updownarro - case 7078: state = 7079; break; // &upd -> &updo - case 7084: state = 7085; break; // &updownarr -> &updownarro - case 7101: state = 7102; break; // &upharp -> &upharpo - case 7102: state = 7103; break; // &upharpo -> &upharpoo - case 7126: state = 7127; break; // &UpperLeftArr -> &UpperLeftArro - case 7136: state = 7137; break; // &UpperRightArr -> &UpperRightArro - case 7144: state = 7145; break; // &Upsil -> &Upsilo - case 7147: state = 7148; break; // &upsil -> &upsilo - case 7155: state = 7156; break; // &UpTeeArr -> &UpTeeArro - case 7162: state = 7163; break; // &upuparr -> &upuparro - case 7167: state = 7168; break; // &urc -> &urco - case 7173: state = 7174; break; // &urcr -> &urcro - case 7193: state = 7194; break; // &utd -> &utdo - case 7223: state = 7410; break; // &v -> &vo - case 7234: state = 7235; break; // &varepsil -> &varepsilo - case 7242: state = 7243; break; // &varn -> &varno - case 7253: state = 7254; break; // &varpr -> &varpro - case 7256: state = 7257; break; // &varpropt -> &varpropto - case 7262: state = 7263; break; // &varrh -> &varrho - case 7307: state = 7407; break; // &V -> &Vo - case 7376: state = 7377; break; // &VerticalSeparat -> &VerticalSeparato - case 7414: state = 7415; break; // &vpr -> &vpro - case 7447: state = 7477; break; // &W -> &Wo - case 7452: state = 7480; break; // &w -> &wo - case 7495: state = 7535; break; // &x -> &xo - case 7508: state = 7539; break; // &X -> &Xo - case 7536: state = 7537; break; // &xod -> &xodo - case 7584: state = 7622; break; // &Y -> &Yo - case 7590: state = 7625; break; // &y -> &yo - case 7645: state = 7713; break; // &Z -> &Zo - case 7651: state = 7716; break; // &z -> &zo - case 7659: state = 7660; break; // &Zcar -> &Zcaro - case 7664: state = 7665; break; // &zcar -> &zcaro - case 7669: state = 7670; break; // &Zd -> &Zdo - case 7672: state = 7673; break; // &zd -> &zdo - case 7681: state = 7682; break; // &Zer -> &Zero - default: return false; - } - break; - case 'p': - switch (state) { - case 0: state = 5083; break; // & -> &p - case 1: state = 154; break; // &A -> &Ap - case 7: state = 143; break; // &a -> &ap - case 60: state = 72; break; // &al -> &alp - case 61: state = 66; break; // &ale -> &alep - case 68: state = 69; break; // &Al -> &Alp - case 79: state = 87; break; // &am -> & - case 98: state = 99; break; // &andslo -> &andslop - case 123: state = 124; break; // &angs -> &angsp - case 131: state = 139; break; // &Ao -> &Aop - case 135: state = 141; break; // &ao -> &aop - case 143: state = 166; break; // &ap -> &app - case 154: state = 155; break; // &Ap -> &App - case 192: state = 193; break; // &asym -> &asymp - case 222: state = 532; break; // &b -> &bp - case 225: state = 237; break; // &back -> &backp - case 230: state = 231; break; // &backe -> &backep - case 288: state = 305; break; // &be -> &bep - case 300: state = 301; break; // &bem -> &bemp - case 336: state = 337; break; // &bigca -> &bigcap - case 341: state = 342; break; // &bigcu -> &bigcup - case 343: state = 347; break; // &bigo -> &bigop - case 359: state = 360; break; // &bigsqcu -> &bigsqcup - case 376: state = 377; break; // &bigtriangleu -> &bigtriangleup - case 378: state = 379; break; // &bigu -> &bigup - case 456: state = 457; break; // &Bo -> &Bop - case 459: state = 460; break; // &bo -> &bop - case 470: state = 499; break; // &box -> &boxp - case 573: state = 574; break; // &bum -> &bump - case 578: state = 579; break; // &Bum -> &Bump - case 584: state = 595; break; // &Ca -> &Cap - case 590: state = 596; break; // &ca -> &cap - case 603: state = 604; break; // &capbrcu -> &capbrcup - case 606: state = 607; break; // &capca -> &capcap - case 608: state = 609; break; // &capcu -> &capcup - case 642: state = 643; break; // &cca -> &ccap - case 672: state = 673; break; // &ccu -> &ccup - case 693: state = 694; break; // &cem -> &cemp - case 856: state = 913; break; // &Co -> &Cop - case 860: state = 915; break; // &co -> &cop - case 867: state = 871; break; // &com -> &comp - case 978: state = 981; break; // &csu -> &csup - case 987: state = 1006; break; // &cu -> &cup - case 994: state = 995; break; // &cue -> &cuep - case 1002: state = 1003; break; // &cularr -> &cularrp - case 1004: state = 1005; break; // &Cu -> &Cup - case 1010: state = 1011; break; // &cupbrca -> &cupbrcap - case 1013: state = 1014; break; // &CupCa -> &CupCap - case 1016: state = 1017; break; // &cupca -> &cupcap - case 1018: state = 1019; break; // &cupcu -> &cupcup - case 1034: state = 1035; break; // &curlyeq -> &curlyeqp - case 1170: state = 1171; break; // &dem -> &demp - case 1289: state = 1290; break; // &dlcro -> &dlcrop - case 1291: state = 1299; break; // &do -> &dop - case 1296: state = 1297; break; // &Do -> &Dop - case 1302: state = 1321; break; // &dot -> &dotp - case 1439: state = 1440; break; // &DoubleU -> &DoubleUp - case 1488: state = 1489; break; // &DownArrowU -> &DownArrowUp - case 1512: state = 1513; break; // &downhar -> &downharp - case 1602: state = 1603; break; // &drcro -> &drcrop - case 1656: state = 1823; break; // &E -> &Ep - case 1662: state = 1813; break; // &e -> &ep - case 1746: state = 1760; break; // &Em -> &Emp - case 1750: state = 1754; break; // &em -> &emp - case 1790: state = 1791; break; // &ems -> &emsp - case 1799: state = 1800; break; // &ens -> &ensp - case 1801: state = 1809; break; // &Eo -> &Eop - case 1805: state = 1811; break; // &eo -> &eop - case 1884: state = 1885; break; // &eqv -> &eqvp - case 1925: state = 1936; break; // &ex -> &exp - case 1931: state = 1945; break; // &Ex -> &Exp - case 1964: state = 2076; break; // &f -> &fp - case 2052: state = 2053; break; // &Fo -> &Fop - case 2055: state = 2056; break; // &fo -> &fop - case 2119: state = 2134; break; // &ga -> &gap - case 2209: state = 2210; break; // &gna -> &gnap - case 2210: state = 2211; break; // &gnap -> &gnapp - case 2222: state = 2223; break; // &Go -> &Gop - case 2225: state = 2226; break; // &go -> &gop - case 2312: state = 2313; break; // >ra -> >rap - case 2313: state = 2314; break; // >rap -> >rapp - case 2360: state = 2361; break; // &hairs -> &hairsp - case 2407: state = 2408; break; // &helli -> &hellip - case 2423: state = 2424; break; // &HilbertS -> &HilbertSp - case 2440: state = 2472; break; // &ho -> &hop - case 2469: state = 2470; break; // &Ho -> &Hop - case 2509: state = 2510; break; // &Hum -> &Hump - case 2517: state = 2518; break; // &HumpDownHum -> &HumpDownHump - case 2524: state = 2529; break; // &hy -> &hyp - case 2539: state = 2731; break; // &i -> &ip - case 2604: state = 2636; break; // &Im -> &Imp - case 2608: state = 2633; break; // &im -> &imp - case 2612: state = 2625; break; // &imag -> &imagp - case 2658: state = 2689; break; // &int -> &intp - case 2713: state = 2725; break; // &io -> &iop - case 2716: state = 2723; break; // &Io -> &Iop - case 2797: state = 2798; break; // &Jo -> &Jop - case 2800: state = 2801; break; // &jo -> &jop - case 2826: state = 2827; break; // &Ka -> &Kap - case 2827: state = 2828; break; // &Kap -> &Kapp - case 2831: state = 2832; break; // &ka -> &kap - case 2832: state = 2833; break; // &kap -> &kapp - case 2869: state = 2870; break; // &Ko -> &Kop - case 2872: state = 2873; break; // &ko -> &kop - case 2881: state = 3638; break; // &l -> &lp - case 2887: state = 2923; break; // &La -> &Lap - case 2892: state = 2922; break; // &la -> &lap - case 2898: state = 2899; break; // &laem -> &laemp - case 2939: state = 2949; break; // &larr -> &larrp - case 2947: state = 2948; break; // &larrl -> &larrlp - case 3128: state = 3129; break; // &lefthar -> &leftharp - case 3137: state = 3138; break; // &leftharpoonu -> &leftharpoonup - case 3182: state = 3183; break; // &leftrighthar -> &leftrightharp - case 3243: state = 3244; break; // &LeftU -> &LeftUp - case 3303: state = 3304; break; // &lessa -> &lessap - case 3304: state = 3305; break; // &lessap -> &lessapp - case 3453: state = 3454; break; // &lna -> &lnap - case 3454: state = 3455; break; // &lnap -> &lnapp - case 3466: state = 3589; break; // &lo -> &lop - case 3475: state = 3592; break; // &Lo -> &Lop - case 3538: state = 3539; break; // &longma -> &longmap - case 3573: state = 3574; break; // &loo -> &loop - case 3745: state = 3875; break; // &m -> &mp - case 3746: state = 3758; break; // &ma -> &map - case 3756: state = 3757; break; // &Ma -> &Map - case 3770: state = 3771; break; // &mapstou -> &mapstoup - case 3809: state = 3810; break; // &MediumS -> &MediumSp - case 3856: state = 3857; break; // &mlc -> &mlcp - case 3860: state = 3861; break; // &mn -> &mnp - case 3865: state = 3873; break; // &mo -> &mop - case 3870: state = 3871; break; // &Mo -> &Mop - case 3882: state = 3883; break; // &mst -> &mstp - case 3892: state = 3893; break; // &multima -> &multimap - case 3895: state = 3896; break; // &muma -> &mumap - case 3897: state = 4597; break; // &n -> &np - case 3898: state = 3914; break; // &na -> &nap - case 3914: state = 3920; break; // &nap -> &napp - case 3931: state = 3932; break; // &nbs ->   - case 3934: state = 3935; break; // &nbum -> &nbump - case 3938: state = 3939; break; // &nca -> &ncap - case 3962: state = 3963; break; // &ncu -> &ncup - case 3997: state = 3998; break; // &NegativeMediumS -> &NegativeMediumSp - case 4007: state = 4008; break; // &NegativeThickS -> &NegativeThickSp - case 4013: state = 4014; break; // &NegativeThinS -> &NegativeThinSp - case 4026: state = 4027; break; // &NegativeVeryThinS -> &NegativeVeryThinSp - case 4101: state = 4108; break; // &nh -> &nhp - case 4190: state = 4210; break; // &No -> &Nop - case 4205: state = 4206; break; // &NonBreakingS -> &NonBreakingSp - case 4212: state = 4213; break; // &no -> &nop - case 4226: state = 4227; break; // &NotCu -> &NotCup - case 4229: state = 4230; break; // &NotCupCa -> &NotCupCap - case 4318: state = 4319; break; // &NotHum -> &NotHump - case 4326: state = 4327; break; // &NotHumpDownHum -> &NotHumpDownHump - case 4494: state = 4504; break; // &NotSquareSu -> &NotSquareSup - case 4515: state = 4551; break; // &NotSu -> &NotSup - case 4653: state = 4685; break; // &ns -> &nsp - case 4666: state = 4670; break; // &nshort -> &nshortp - case 4690: state = 4693; break; // &nsqsu -> &nsqsup - case 4695: state = 4709; break; // &nsu -> &nsup - case 4758: state = 4759; break; // &nums -> &numsp - case 4761: state = 4762; break; // &nva -> &nvap - case 4827: state = 4960; break; // &O -> &Op - case 4833: state = 4957; break; // &o -> &op - case 4951: state = 4952; break; // &Oo -> &Oop - case 4954: state = 4955; break; // &oo -> &oop - case 4985: state = 4986; break; // &oper -> &operp - case 5010: state = 5011; break; // &orslo -> &orslop - case 5109: state = 5119; break; // &per -> &perp - case 5189: state = 5208; break; // &Po -> &Pop - case 5195: state = 5196; break; // &Poincare -> &Poincarep - case 5201: state = 5210; break; // &po -> &pop - case 5217: state = 5218; break; // &pra -> &prap - case 5225: state = 5226; break; // &preca -> &precap - case 5226: state = 5227; break; // &precap -> &precapp - case 5267: state = 5268; break; // &precna -> &precnap - case 5268: state = 5269; break; // &precnap -> &precnapp - case 5290: state = 5291; break; // &prna -> &prnap - case 5296: state = 5316; break; // &pro -> &prop - case 5298: state = 5317; break; // &Pro -> &Prop - case 5346: state = 5347; break; // &puncs -> &puncsp - case 5351: state = 5363; break; // &q -> &qp - case 5357: state = 5358; break; // &Qo -> &Qop - case 5360: state = 5361; break; // &qo -> &qop - case 5397: state = 5909; break; // &r -> &rp - case 5418: state = 5419; break; // &raem -> &raemp - case 5439: state = 5452; break; // &rarr -> &rarrp - case 5440: state = 5441; break; // &rarra -> &rarrap - case 5450: state = 5451; break; // &rarrl -> &rarrlp - case 5543: state = 5547; break; // &real -> &realp - case 5579: state = 5580; break; // &ReverseU -> &ReverseUp - case 5714: state = 5715; break; // &righthar -> &rightharp - case 5723: state = 5724; break; // &rightharpoonu -> &rightharpoonup - case 5737: state = 5738; break; // &rightlefthar -> &rightleftharp - case 5803: state = 5804; break; // &RightU -> &RightUp - case 5875: state = 5884; break; // &ro -> &rop - case 5887: state = 5888; break; // &Ro -> &Rop - case 5903: state = 5904; break; // &RoundIm -> &RoundImp - case 5909: state = 5914; break; // &rp -> &rpp - case 5991: state = 6249; break; // &s -> &sp - case 6002: state = 6037; break; // &sc -> &scp - case 6003: state = 6004; break; // &sca -> &scap - case 6031: state = 6032; break; // &scna -> &scnap - case 6090: state = 6091; break; // &shar -> &sharp - case 6128: state = 6132; break; // &short -> &shortp - case 6150: state = 6151; break; // &ShortU -> &ShortUp - case 6168: state = 6180; break; // &sim -> &simp - case 6215: state = 6216; break; // &smash -> &smashp - case 6217: state = 6218; break; // &sme -> &smep - case 6235: state = 6247; break; // &so -> &sop - case 6244: state = 6245; break; // &So -> &Sop - case 6260: state = 6261; break; // &sqca -> &sqcap - case 6263: state = 6264; break; // &sqcu -> &sqcup - case 6270: state = 6278; break; // &sqsu -> &sqsup - case 6306: state = 6316; break; // &SquareSu -> &SquareSup - case 6368: state = 6376; break; // &straight -> &straightp - case 6369: state = 6370; break; // &straighte -> &straightep - case 6381: state = 6499; break; // &Su -> &Sup - case 6383: state = 6500; break; // &su -> &sup - case 6384: state = 6400; break; // &sub -> &subp - case 6428: state = 6430; break; // &subsu -> &subsup - case 6433: state = 6434; break; // &succa -> &succap - case 6434: state = 6435; break; // &succap -> &succapp - case 6475: state = 6476; break; // &succna -> &succnap - case 6476: state = 6477; break; // &succnap -> &succnapp - case 6500: state = 6542; break; // &sup -> &supp - case 6561: state = 6563; break; // &supsu -> &supsup - case 6586: state = 6751; break; // &t -> &tp - case 6657: state = 6658; break; // &thicka -> &thickap - case 6658: state = 6659; break; // &thickap -> &thickapp - case 6669: state = 6670; break; // &ThickS -> &ThickSp - case 6675: state = 6676; break; // &thins -> &thinsp - case 6678: state = 6679; break; // &ThinS -> &ThinSp - case 6684: state = 6685; break; // &thka -> &thkap - case 6732: state = 6735; break; // &to -> &top - case 6742: state = 6743; break; // &To -> &Top - case 6760: state = 6815; break; // &tr -> &trp - case 6764: state = 6805; break; // &tri -> &trip - case 6798: state = 6799; break; // &Tri -> &Trip - case 6873: state = 7031; break; // &U -> &Up - case 6879: state = 7042; break; // &u -> &up - case 6973: state = 6974; break; // &ulcro -> &ulcrop - case 7019: state = 7027; break; // &Uo -> &Uop - case 7023: state = 7029; break; // &uo -> &uop - case 7031: state = 7117; break; // &Up -> &Upp - case 7100: state = 7101; break; // &uphar -> &upharp - case 7158: state = 7159; break; // &upu -> &upup - case 7174: state = 7175; break; // &urcro -> &urcrop - case 7223: state = 7413; break; // &v -> &vp - case 7229: state = 7249; break; // &var -> &varp - case 7230: state = 7231; break; // &vare -> &varep - case 7238: state = 7239; break; // &varka -> &varkap - case 7239: state = 7240; break; // &varkap -> &varkapp - case 7254: state = 7255; break; // &varpro -> &varprop - case 7269: state = 7278; break; // &varsu -> &varsup - case 7347: state = 7348; break; // &velli -> &vellip - case 7371: state = 7372; break; // &VerticalSe -> &VerticalSep - case 7389: state = 7390; break; // &VeryThinS -> &VeryThinSp - case 7404: state = 7406; break; // &vnsu -> &vnsup - case 7407: state = 7408; break; // &Vo -> &Vop - case 7410: state = 7411; break; // &vo -> &vop - case 7415: state = 7416; break; // &vpro -> &vprop - case 7427: state = 7432; break; // &vsu -> &vsup - case 7452: state = 7483; break; // &w -> &wp - case 7471: state = 7472; break; // &weier -> &weierp - case 7477: state = 7478; break; // &Wo -> &Wop - case 7480: state = 7481; break; // &wo -> &wop - case 7497: state = 7498; break; // &xca -> &xcap - case 7502: state = 7503; break; // &xcu -> &xcup - case 7530: state = 7531; break; // &xma -> &xmap - case 7535: state = 7542; break; // &xo -> &xop - case 7539: state = 7540; break; // &Xo -> &Xop - case 7566: state = 7567; break; // &xsqcu -> &xsqcup - case 7568: state = 7569; break; // &xu -> &xup - case 7622: state = 7623; break; // &Yo -> &Yop - case 7625: state = 7626; break; // &yo -> &yop - case 7688: state = 7689; break; // &ZeroWidthS -> &ZeroWidthSp - case 7713: state = 7714; break; // &Zo -> &Zop - case 7716: state = 7717; break; // &zo -> &zop - default: return false; - } - break; - case 'q': - switch (state) { - case 0: state = 5351; break; // & -> &q - case 170: state = 171; break; // &approxe -> &approxeq - case 194: state = 195; break; // &asympe -> &asympeq - case 245: state = 246; break; // &backsime -> &backsimeq - case 284: state = 285; break; // &bd -> &bdq - case 356: state = 357; break; // &bigs -> &bigsq - case 407: state = 408; break; // &blacks -> &blacksq - case 446: state = 447; break; // &bne -> &bneq - case 576: state = 582; break; // &bumpe -> &bumpeq - case 580: state = 581; break; // &Bumpe -> &Bumpeq - case 735: state = 736; break; // &circe -> &circeq - case 865: state = 866; break; // &colone -> &coloneq - case 1033: state = 1034; break; // &curlye -> &curlyeq - case 1159: state = 1160; break; // &ddotse -> &ddotseq - case 1306: state = 1307; break; // &dote -> &doteq - case 1311: state = 1312; break; // &DotE -> &DotEq - case 1325: state = 1326; break; // &dots -> &dotsq - case 1656: state = 1856; break; // &E -> &Eq - case 1662: state = 1833; break; // &e -> &eq - case 1768: state = 1769; break; // &EmptySmallS -> &EmptySmallSq - case 1784: state = 1785; break; // &EmptyVerySmallS -> &EmptyVerySmallSq - case 1975: state = 1976; break; // &fallingdotse -> &fallingdotseq - case 2015: state = 2016; break; // &FilledSmallS -> &FilledSmallSq - case 2030: state = 2031; break; // &FilledVerySmallS -> &FilledVerySmallSq - case 2166: state = 2169; break; // &ge -> &geq - case 2169: state = 2170; break; // &geq -> &geqq - case 2216: state = 2217; break; // &gne -> &gneq - case 2217: state = 2218; break; // &gneq -> &gneqq - case 2238: state = 2239; break; // &GreaterE -> &GreaterEq - case 2251: state = 2252; break; // &GreaterFullE -> &GreaterFullEq - case 2272: state = 2273; break; // &GreaterSlantE -> &GreaterSlantEq - case 2294: state = 2306; break; // > -> >q - case 2323: state = 2324; break; // >re -> >req - case 2324: state = 2329; break; // >req -> >reqq - case 2346: state = 2347; break; // &gvertne -> &gvertneq - case 2347: state = 2348; break; // &gvertneq -> &gvertneqq - case 2519: state = 2520; break; // &HumpE -> &HumpEq - case 2539: state = 2735; break; // &i -> &iq - case 2892: state = 2931; break; // &la -> &laq - case 3012: state = 3015; break; // &ld -> &ldq - case 3032: state = 3284; break; // &le -> &leq - case 3188: state = 3189; break; // &leftrights -> &leftrightsq - case 3238: state = 3239; break; // &LeftTriangleE -> &LeftTriangleEq - case 3284: state = 3285; break; // &leq -> &leqq - case 3312: state = 3313; break; // &lesse -> &lesseq - case 3313: state = 3317; break; // &lesseq -> &lesseqq - case 3323: state = 3324; break; // &LessE -> &LessEq - case 3339: state = 3340; break; // &LessFullE -> &LessFullEq - case 3366: state = 3367; break; // &LessSlantE -> &LessSlantEq - case 3460: state = 3461; break; // &lne -> &lneq - case 3461: state = 3462; break; // &lneq -> &lneqq - case 3661: state = 3677; break; // &ls -> &lsq - case 3662: state = 3663; break; // &lsa -> &lsaq - case 3692: state = 3712; break; // < -> <q - case 3740: state = 3741; break; // &lvertne -> &lvertneq - case 3741: state = 3742; break; // &lvertneq -> &lvertneqq - case 3970: state = 4031; break; // &ne -> &neq - case 4083: state = 4084; break; // &nge -> &ngeq - case 4084: state = 4085; break; // &ngeq -> &ngeqq - case 4131: state = 4168; break; // &nle -> &nleq - case 4168: state = 4169; break; // &nleq -> &nleqq - case 4248: state = 4255; break; // &NotE -> &NotEq - case 4276: state = 4277; break; // &NotGreaterE -> &NotGreaterEq - case 4285: state = 4286; break; // &NotGreaterFullE -> &NotGreaterFullEq - case 4306: state = 4307; break; // &NotGreaterSlantE -> &NotGreaterSlantEq - case 4328: state = 4329; break; // &NotHumpE -> &NotHumpEq - case 4358: state = 4359; break; // &NotLeftTriangleE -> &NotLeftTriangleEq - case 4365: state = 4366; break; // &NotLessE -> &NotLessEq - case 4386: state = 4387; break; // &NotLessSlantE -> &NotLessSlantEq - case 4438: state = 4439; break; // &NotPrecedesE -> &NotPrecedesEq - case 4448: state = 4449; break; // &NotPrecedesSlantE -> &NotPrecedesSlantEq - case 4482: state = 4483; break; // &NotRightTriangleE -> &NotRightTriangleEq - case 4487: state = 4488; break; // &NotS -> &NotSq - case 4499: state = 4500; break; // &NotSquareSubsetE -> &NotSquareSubsetEq - case 4510: state = 4511; break; // &NotSquareSupersetE -> &NotSquareSupersetEq - case 4520: state = 4521; break; // &NotSubsetE -> &NotSubsetEq - case 4531: state = 4532; break; // &NotSucceedsE -> &NotSucceedsEq - case 4541: state = 4542; break; // &NotSucceedsSlantE -> &NotSucceedsSlantEq - case 4557: state = 4558; break; // &NotSupersetE -> &NotSupersetEq - case 4567: state = 4568; break; // &NotTildeE -> &NotTildeEq - case 4576: state = 4577; break; // &NotTildeFullE -> &NotTildeFullEq - case 4619: state = 4620; break; // &nprece -> &npreceq - case 4653: state = 4688; break; // &ns -> &nsq - case 4680: state = 4681; break; // &nsime -> &nsimeq - case 4702: state = 4703; break; // &nsubsete -> &nsubseteq - case 4703: state = 4704; break; // &nsubseteq -> &nsubseteqq - case 4707: state = 4708; break; // &nsucce -> &nsucceq - case 4715: state = 4716; break; // &nsupsete -> &nsupseteq - case 4716: state = 4717; break; // &nsupseteq -> &nsupseteqq - case 4743: state = 4744; break; // &ntrianglelefte -> &ntrianglelefteq - case 4750: state = 4751; break; // &ntrianglerighte -> &ntrianglerighteq - case 5236: state = 5237; break; // &preccurlye -> &preccurlyeq - case 5244: state = 5245; break; // &PrecedesE -> &PrecedesEq - case 5254: state = 5255; break; // &PrecedesSlantE -> &PrecedesSlantEq - case 5264: state = 5265; break; // &prece -> &preceq - case 5273: state = 5274; break; // &precne -> &precneq - case 5274: state = 5275; break; // &precneq -> &precneqq - case 5390: state = 5391; break; // &queste -> &questeq - case 5402: state = 5431; break; // &ra -> &raq - case 5526: state = 5534; break; // &rd -> &rdq - case 5562: state = 5569; break; // &ReverseE -> &ReverseEq - case 5581: state = 5582; break; // &ReverseUpE -> &ReverseUpEq - case 5754: state = 5755; break; // &rights -> &rightsq - case 5798: state = 5799; break; // &RightTriangleE -> &RightTriangleEq - case 5852: state = 5853; break; // &risingdotse -> &risingdotseq - case 5934: state = 5946; break; // &rs -> &rsq - case 5935: state = 5936; break; // &rsa -> &rsaq - case 5985: state = 6266; break; // &S -> &Sq - case 5991: state = 6258; break; // &s -> &sq - case 5997: state = 5998; break; // &sb -> &sbq - case 6172: state = 6173; break; // &sime -> &simeq - case 6276: state = 6277; break; // &sqsubsete -> &sqsubseteq - case 6283: state = 6284; break; // &sqsupsete -> &sqsupseteq - case 6311: state = 6312; break; // &SquareSubsetE -> &SquareSubsetEq - case 6322: state = 6323; break; // &SquareSupersetE -> &SquareSupersetEq - case 6414: state = 6415; break; // &subsete -> &subseteq - case 6415: state = 6416; break; // &subseteq -> &subseteqq - case 6417: state = 6418; break; // &SubsetE -> &SubsetEq - case 6423: state = 6424; break; // &subsetne -> &subsetneq - case 6424: state = 6425; break; // &subsetneq -> &subsetneqq - case 6444: state = 6445; break; // &succcurlye -> &succcurlyeq - case 6452: state = 6453; break; // &SucceedsE -> &SucceedsEq - case 6462: state = 6463; break; // &SucceedsSlantE -> &SucceedsSlantEq - case 6472: state = 6473; break; // &succe -> &succeq - case 6481: state = 6482; break; // &succne -> &succneq - case 6482: state = 6483; break; // &succneq -> &succneqq - case 6520: state = 6521; break; // &SupersetE -> &SupersetEq - case 6552: state = 6553; break; // &supsete -> &supseteq - case 6553: state = 6554; break; // &supseteq -> &supseteqq - case 6556: state = 6557; break; // &supsetne -> &supsetneq - case 6557: state = 6558; break; // &supsetneq -> &supsetneqq - case 6704: state = 6705; break; // &TildeE -> &TildeEq - case 6713: state = 6714; break; // &TildeFullE -> &TildeFullEq - case 6769: state = 6780; break; // &triangle -> &triangleq - case 6778: state = 6779; break; // &trianglelefte -> &trianglelefteq - case 6786: state = 6787; break; // &trianglerighte -> &trianglerighteq - case 7087: state = 7088; break; // &UpE -> &UpEq - case 7275: state = 7276; break; // &varsubsetne -> &varsubsetneq - case 7276: state = 7277; break; // &varsubsetneq -> &varsubsetneqq - case 7283: state = 7284; break; // &varsupsetne -> &varsupsetneq - case 7284: state = 7285; break; // &varsupsetneq -> &varsupsetneqq - case 7343: state = 7344; break; // &veee -> &veeeq - case 7467: state = 7468; break; // &wedge -> &wedgeq - case 7561: state = 7564; break; // &xs -> &xsq - default: return false; - } - break; - case 'r': - switch (state) { - case 0: state = 5397; break; // & -> &r - case 1: state = 172; break; // &A -> &Ar - case 7: state = 176; break; // &a -> &ar - case 13: state = 14; break; // &Ab -> &Abr - case 18: state = 19; break; // &ab -> &abr - case 27: state = 28; break; // &Aci -> &Acir - case 30: state = 31; break; // &aci -> &acir - case 46: state = 49; break; // &af -> &afr - case 47: state = 48; break; // &Af -> &Afr - case 50: state = 51; break; // &Ag -> &Agr - case 55: state = 56; break; // &ag -> &agr - case 77: state = 78; break; // &Amac -> &Amacr - case 81: state = 82; break; // &amac -> &amacr - case 102: state = 118; break; // &ang -> &angr - case 128: state = 129; break; // &angza -> &angzar - case 129: state = 130; break; // &angzar -> &angzarr - case 146: state = 147; break; // &apaci -> &apacir - case 166: state = 167; break; // &app -> &appr - case 181: state = 182; break; // &Asc -> &Ascr - case 184: state = 185; break; // &asc -> &ascr - case 222: state = 541; break; // &b -> &br - case 223: state = 258; break; // &ba -> &bar - case 237: state = 238; break; // &backp -> &backpr - case 247: state = 537; break; // &B -> &Br - case 248: state = 256; break; // &Ba -> &Bar - case 270: state = 271; break; // &bb -> &bbr - case 274: state = 275; break; // &bbrktb -> &bbrktbr - case 288: state = 308; break; // &be -> &ber - case 293: state = 312; break; // &Be -> &Ber - case 329: state = 330; break; // &Bf -> &Bfr - case 331: state = 332; break; // &bf -> &bfr - case 338: state = 339; break; // &bigci -> &bigcir - case 362: state = 363; break; // &bigsta -> &bigstar - case 364: state = 365; break; // &bigt -> &bigtr - case 392: state = 393; break; // &bka -> &bkar - case 410: state = 411; break; // &blacksqua -> &blacksquar - case 413: state = 414; break; // &blackt -> &blacktr - case 420: state = 429; break; // &blacktriangle -> &blacktriangler - case 474: state = 481; break; // &boxD -> &boxDr - case 477: state = 483; break; // &boxd -> &boxdr - case 508: state = 515; break; // &boxU -> &boxUr - case 511: state = 517; break; // &boxu -> &boxur - case 518: state = 529; break; // &boxV -> &boxVr - case 519: state = 531; break; // &boxv -> &boxvr - case 532: state = 533; break; // &bp -> &bpr - case 547: state = 548; break; // &brvba -> ¦ - case 550: state = 551; break; // &Bsc -> &Bscr - case 553: state = 554; break; // &bsc -> &bscr - case 583: state = 965; break; // &C -> &Cr - case 589: state = 961; break; // &c -> &cr - case 590: state = 631; break; // &ca -> &car - case 600: state = 601; break; // &capb -> &capbr - case 621: state = 622; break; // &CapitalDiffe -> &CapitalDiffer - case 642: state = 650; break; // &cca -> &ccar - case 646: state = 647; break; // &Cca -> &Ccar - case 661: state = 662; break; // &Cci -> &Ccir - case 664: state = 665; break; // &cci -> &ccir - case 702: state = 703; break; // &Cente -> &Center - case 707: state = 708; break; // ¢e -> ¢er - case 712: state = 713; break; // &Cf -> &Cfr - case 714: state = 715; break; // &cf -> &cfr - case 726: state = 727; break; // &checkma -> &checkmar - case 732: state = 733; break; // &ci -> &cir - case 739: state = 740; break; // &circlea -> &circlear - case 740: state = 741; break; // &circlear -> &circlearr - case 743: state = 748; break; // &circlearrow -> &circlearrowr - case 758: state = 759; break; // &circledci -> &circledcir - case 765: state = 766; break; // &Ci -> &Cir - case 801: state = 802; break; // &cirsci -> &cirscir - case 816: state = 817; break; // &ClockwiseContou -> &ClockwiseContour - case 822: state = 823; break; // &ClockwiseContourInteg -> &ClockwiseContourIntegr - case 829: state = 830; break; // &CloseCu -> &CloseCur - case 889: state = 890; break; // &Cong -> &Congr - case 903: state = 904; break; // &Contou -> &Contour - case 909: state = 910; break; // &ContourInteg -> &ContourIntegr - case 913: state = 920; break; // &Cop -> &Copr - case 915: state = 917; break; // &cop -> &copr - case 930: state = 931; break; // ©s -> ©sr - case 935: state = 936; break; // &Counte -> &Counter - case 951: state = 952; break; // &CounterClockwiseContou -> &CounterClockwiseContour - case 957: state = 958; break; // &CounterClockwiseContourInteg -> &CounterClockwiseContourIntegr - case 962: state = 963; break; // &cra -> &crar - case 963: state = 964; break; // &crar -> &crarr - case 973: state = 974; break; // &Csc -> &Cscr - case 976: state = 977; break; // &csc -> &cscr - case 987: state = 1026; break; // &cu -> &cur - case 989: state = 990; break; // &cuda -> &cudar - case 990: state = 991; break; // &cudar -> &cudarr - case 991: state = 993; break; // &cudarr -> &cudarrr - case 995: state = 996; break; // &cuep -> &cuepr - case 1000: state = 1001; break; // &cula -> &cular - case 1001: state = 1002; break; // &cular -> &cularr - case 1007: state = 1008; break; // &cupb -> &cupbr - case 1023: state = 1024; break; // &cupo -> &cupor - case 1026: state = 1051; break; // &cur -> &curr - case 1027: state = 1028; break; // &cura -> &curar - case 1028: state = 1029; break; // &curar -> &curarr - case 1035: state = 1036; break; // &curlyeqp -> &curlyeqpr - case 1056: state = 1057; break; // &curvea -> &curvear - case 1057: state = 1058; break; // &curvear -> &curvearr - case 1060: state = 1065; break; // &curvearrow -> &curvearrowr - case 1092: state = 1107; break; // &Da -> &Dar - case 1095: state = 1096; break; // &Dagge -> &Dagger - case 1097: state = 1590; break; // &d -> &dr - case 1098: state = 1112; break; // &da -> &dar - case 1101: state = 1102; break; // &dagge -> &dagger - case 1107: state = 1108; break; // &Dar -> &Darr - case 1109: state = 1110; break; // &dA -> &dAr - case 1110: state = 1111; break; // &dAr -> &dArr - case 1112: state = 1113; break; // &dar -> &darr - case 1122: state = 1123; break; // &dbka -> &dbkar - case 1130: state = 1131; break; // &Dca -> &Dcar - case 1135: state = 1136; break; // &dca -> &dcar - case 1143: state = 1148; break; // &dda -> &ddar - case 1146: state = 1147; break; // &ddagge -> &ddagger - case 1148: state = 1149; break; // &ddar -> &ddarr - case 1151: state = 1152; break; // &DDot -> &DDotr - case 1175: state = 1182; break; // &df -> &dfr - case 1180: state = 1181; break; // &Df -> &Dfr - case 1184: state = 1185; break; // &dHa -> &dHar - case 1187: state = 1188; break; // &dha -> &dhar - case 1188: state = 1190; break; // &dhar -> &dharr - case 1193: state = 1194; break; // &Diac -> &Diacr - case 1218: state = 1219; break; // &DiacriticalG -> &DiacriticalGr - case 1246: state = 1247; break; // &Diffe -> &Differ - case 1284: state = 1288; break; // &dlc -> &dlcr - case 1285: state = 1286; break; // &dlco -> &dlcor - case 1294: state = 1295; break; // &dolla -> &dollar - case 1328: state = 1329; break; // &dotsqua -> &dotsquar - case 1336: state = 1337; break; // &doubleba -> &doublebar - case 1352: state = 1353; break; // &DoubleContou -> &DoubleContour - case 1358: state = 1359; break; // &DoubleContourInteg -> &DoubleContourIntegr - case 1367: state = 1368; break; // &DoubleDownA -> &DoubleDownAr - case 1368: state = 1369; break; // &DoubleDownAr -> &DoubleDownArr - case 1376: state = 1377; break; // &DoubleLeftA -> &DoubleLeftAr - case 1377: state = 1378; break; // &DoubleLeftAr -> &DoubleLeftArr - case 1386: state = 1387; break; // &DoubleLeftRightA -> &DoubleLeftRightAr - case 1387: state = 1388; break; // &DoubleLeftRightAr -> &DoubleLeftRightArr - case 1401: state = 1402; break; // &DoubleLongLeftA -> &DoubleLongLeftAr - case 1402: state = 1403; break; // &DoubleLongLeftAr -> &DoubleLongLeftArr - case 1411: state = 1412; break; // &DoubleLongLeftRightA -> &DoubleLongLeftRightAr - case 1412: state = 1413; break; // &DoubleLongLeftRightAr -> &DoubleLongLeftRightArr - case 1421: state = 1422; break; // &DoubleLongRightA -> &DoubleLongRightAr - case 1422: state = 1423; break; // &DoubleLongRightAr -> &DoubleLongRightArr - case 1431: state = 1432; break; // &DoubleRightA -> &DoubleRightAr - case 1432: state = 1433; break; // &DoubleRightAr -> &DoubleRightArr - case 1441: state = 1442; break; // &DoubleUpA -> &DoubleUpAr - case 1442: state = 1443; break; // &DoubleUpAr -> &DoubleUpArr - case 1450: state = 1451; break; // &DoubleUpDownA -> &DoubleUpDownAr - case 1451: state = 1452; break; // &DoubleUpDownAr -> &DoubleUpDownArr - case 1456: state = 1457; break; // &DoubleVe -> &DoubleVer - case 1464: state = 1465; break; // &DoubleVerticalBa -> &DoubleVerticalBar - case 1468: state = 1469; break; // &DownA -> &DownAr - case 1469: state = 1470; break; // &DownAr -> &DownArr - case 1473: state = 1474; break; // &Downa -> &Downar - case 1474: state = 1475; break; // &Downar -> &Downarr - case 1480: state = 1481; break; // &downa -> &downar - case 1481: state = 1482; break; // &downar -> &downarr - case 1486: state = 1487; break; // &DownArrowBa -> &DownArrowBar - case 1490: state = 1491; break; // &DownArrowUpA -> &DownArrowUpAr - case 1491: state = 1492; break; // &DownArrowUpAr -> &DownArrowUpArr - case 1495: state = 1496; break; // &DownB -> &DownBr - case 1504: state = 1505; break; // &downdowna -> &downdownar - case 1505: state = 1506; break; // &downdownar -> &downdownarr - case 1511: state = 1512; break; // &downha -> &downhar - case 1516: state = 1521; break; // &downharpoon -> &downharpoonr - case 1539: state = 1540; break; // &DownLeftRightVecto -> &DownLeftRightVector - case 1548: state = 1549; break; // &DownLeftTeeVecto -> &DownLeftTeeVector - case 1554: state = 1555; break; // &DownLeftVecto -> &DownLeftVector - case 1557: state = 1558; break; // &DownLeftVectorBa -> &DownLeftVectorBar - case 1571: state = 1572; break; // &DownRightTeeVecto -> &DownRightTeeVector - case 1577: state = 1578; break; // &DownRightVecto -> &DownRightVector - case 1580: state = 1581; break; // &DownRightVectorBa -> &DownRightVectorBar - case 1585: state = 1586; break; // &DownTeeA -> &DownTeeAr - case 1586: state = 1587; break; // &DownTeeAr -> &DownTeeArr - case 1593: state = 1594; break; // &drbka -> &drbkar - case 1597: state = 1601; break; // &drc -> &drcr - case 1598: state = 1599; break; // &drco -> &drcor - case 1605: state = 1606; break; // &Dsc -> &Dscr - case 1608: state = 1609; break; // &dsc -> &dscr - case 1616: state = 1617; break; // &Dst -> &Dstr - case 1620: state = 1621; break; // &dst -> &dstr - case 1624: state = 1628; break; // &dt -> &dtr - case 1632: state = 1633; break; // &dua -> &duar - case 1633: state = 1634; break; // &duar -> &duarr - case 1636: state = 1637; break; // &duha -> &duhar - case 1651: state = 1652; break; // &dzig -> &dzigr - case 1653: state = 1654; break; // &dzigra -> &dzigrar - case 1654: state = 1655; break; // &dzigrar -> &dzigrarr - case 1662: state = 1890; break; // &e -> &er - case 1670: state = 1671; break; // &easte -> &easter - case 1673: state = 1674; break; // &Eca -> &Ecar - case 1678: state = 1679; break; // &eca -> &ecar - case 1682: state = 1683; break; // &eci -> &ecir - case 1684: state = 1685; break; // &Eci -> &Ecir - case 1707: state = 1713; break; // &ef -> &efr - case 1711: state = 1712; break; // &Ef -> &Efr - case 1714: state = 1720; break; // &eg -> &egr - case 1715: state = 1716; break; // &Eg -> &Egr - case 1738: state = 1739; break; // &elinte -> &elinter - case 1748: state = 1749; break; // &Emac -> &Emacr - case 1752: state = 1753; break; // &emac -> &emacr - case 1771: state = 1772; break; // &EmptySmallSqua -> &EmptySmallSquar - case 1776: state = 1777; break; // &EmptyVe -> &EmptyVer - case 1787: state = 1788; break; // &EmptyVerySmallSqua -> &EmptyVerySmallSquar - case 1814: state = 1815; break; // &epa -> &epar - case 1835: state = 1836; break; // &eqci -> &eqcir - case 1850: state = 1851; break; // &eqslantgt -> &eqslantgtr - case 1875: state = 1876; break; // &Equilib -> &Equilibr - case 1886: state = 1887; break; // &eqvpa -> &eqvpar - case 1891: state = 1892; break; // &era -> &erar - case 1892: state = 1893; break; // &erar -> &erarr - case 1898: state = 1899; break; // &Esc -> &Escr - case 1901: state = 1902; break; // &esc -> &escr - case 1920: state = 1923; break; // &eu -> &eur - case 1964: state = 2083; break; // &f -> &fr - case 1987: state = 2000; break; // &ff -> &ffr - case 1998: state = 1999; break; // &Ff -> &Ffr - case 2018: state = 2019; break; // &FilledSmallSqua -> &FilledSmallSquar - case 2022: state = 2023; break; // &FilledVe -> &FilledVer - case 2033: state = 2034; break; // &FilledVerySmallSqua -> &FilledVerySmallSquar - case 2052: state = 2058; break; // &Fo -> &For - case 2055: state = 2062; break; // &fo -> &for - case 2068: state = 2069; break; // &Fou -> &Four - case 2071: state = 2072; break; // &Fourie -> &Fourier - case 2073: state = 2074; break; // &Fouriert -> &Fouriertr - case 2077: state = 2078; break; // &fpa -> &fpar - case 2113: state = 2114; break; // &Fsc -> &Fscr - case 2116: state = 2117; break; // &fsc -> &fscr - case 2118: state = 2228; break; // &g -> &gr - case 2124: state = 2232; break; // &G -> &Gr - case 2135: state = 2136; break; // &Gb -> &Gbr - case 2140: state = 2141; break; // &gb -> &gbr - case 2150: state = 2151; break; // &Gci -> &Gcir - case 2154: state = 2155; break; // &gci -> &gcir - case 2187: state = 2188; break; // &Gf -> &Gfr - case 2189: state = 2190; break; // &gf -> &gfr - case 2211: state = 2212; break; // &gnapp -> &gnappr - case 2236: state = 2237; break; // &Greate -> &Greater - case 2256: state = 2257; break; // &GreaterG -> &GreaterGr - case 2261: state = 2262; break; // &GreaterGreate -> &GreaterGreater - case 2283: state = 2284; break; // &Gsc -> &Gscr - case 2286: state = 2287; break; // &gsc -> &gscr - case 2294: state = 2311; break; // > -> >r - case 2297: state = 2298; break; // >ci -> >cir - case 2304: state = 2305; break; // >lPa -> >lPar - case 2312: state = 2318; break; // >ra -> >rar - case 2314: state = 2315; break; // >rapp -> >rappr - case 2318: state = 2319; break; // >rar -> >rarr - case 2342: state = 2343; break; // &gve -> &gver - case 2357: state = 2373; break; // &ha -> &har - case 2358: state = 2359; break; // &hai -> &hair - case 2373: state = 2380; break; // &har -> &harr - case 2377: state = 2378; break; // &hA -> &hAr - case 2378: state = 2379; break; // &hAr -> &hArr - case 2382: state = 2383; break; // &harrci -> &harrcir - case 2387: state = 2388; break; // &hba -> &hbar - case 2390: state = 2391; break; // &Hci -> &Hcir - case 2394: state = 2395; break; // &hci -> &hcir - case 2397: state = 2409; break; // &he -> &her - case 2398: state = 2399; break; // &hea -> &hear - case 2413: state = 2414; break; // &Hf -> &Hfr - case 2415: state = 2416; break; // &hf -> &hfr - case 2420: state = 2421; break; // &Hilbe -> &Hilber - case 2431: state = 2432; break; // &hksea -> &hksear - case 2436: state = 2437; break; // &hkswa -> &hkswar - case 2440: state = 2474; break; // &ho -> &hor - case 2441: state = 2442; break; // &hoa -> &hoar - case 2442: state = 2443; break; // &hoar -> &hoarr - case 2449: state = 2459; break; // &hook -> &hookr - case 2454: state = 2455; break; // &hooklefta -> &hookleftar - case 2455: state = 2456; break; // &hookleftar -> &hookleftarr - case 2464: state = 2465; break; // &hookrighta -> &hookrightar - case 2465: state = 2466; break; // &hookrightar -> &hookrightarr - case 2469: state = 2478; break; // &Ho -> &Hor - case 2476: state = 2477; break; // &horba -> &horbar - case 2491: state = 2492; break; // &Hsc -> &Hscr - case 2494: state = 2495; break; // &hsc -> &hscr - case 2500: state = 2501; break; // &Hst -> &Hstr - case 2504: state = 2505; break; // &hst -> &hstr - case 2547: state = 2548; break; // &Ici -> &Icir - case 2550: state = 2551; break; // &ici -> &icir - case 2567: state = 2571; break; // &if -> &ifr - case 2569: state = 2570; break; // &If -> &Ifr - case 2572: state = 2573; break; // &Ig -> &Igr - case 2577: state = 2578; break; // &ig -> &igr - case 2606: state = 2607; break; // &Imac -> &Imacr - case 2610: state = 2611; break; // &imac -> &imacr - case 2617: state = 2618; break; // &Imagina -> &Imaginar - case 2626: state = 2627; break; // &imagpa -> &imagpar - case 2643: state = 2644; break; // &inca -> &incar - case 2662: state = 2672; break; // &inte -> &inter - case 2664: state = 2665; break; // &intege -> &integer - case 2667: state = 2676; break; // &Inte -> &Inter - case 2668: state = 2669; break; // &Integ -> &Integr - case 2685: state = 2686; break; // &intla -> &intlar - case 2689: state = 2690; break; // &intp -> &intpr - case 2731: state = 2732; break; // &ip -> &ipr - case 2741: state = 2742; break; // &Isc -> &Iscr - case 2744: state = 2745; break; // &isc -> &iscr - case 2779: state = 2780; break; // &Jci -> &Jcir - case 2784: state = 2785; break; // &jci -> &jcir - case 2789: state = 2790; break; // &Jf -> &Jfr - case 2791: state = 2792; break; // &jf -> &jfr - case 2804: state = 2805; break; // &Jsc -> &Jscr - case 2807: state = 2808; break; // &jsc -> &jscr - case 2809: state = 2810; break; // &Jse -> &Jser - case 2813: state = 2814; break; // &jse -> &jser - case 2848: state = 2849; break; // &Kf -> &Kfr - case 2850: state = 2851; break; // &kf -> &kfr - case 2852: state = 2853; break; // &kg -> &kgr - case 2876: state = 2877; break; // &Ksc -> &Kscr - case 2879: state = 2880; break; // &ksc -> &kscr - case 2881: state = 3643; break; // &l -> &lr - case 2882: state = 2936; break; // &lA -> &lAr - case 2883: state = 2884; break; // &lAa -> &lAar - case 2884: state = 2885; break; // &lAar -> &lAarr - case 2887: state = 2934; break; // &La -> &Lar - case 2892: state = 2938; break; // &la -> &lar - case 2903: state = 2904; break; // &lag -> &lagr - case 2928: state = 2929; break; // &Laplacet -> &Laplacetr - case 2934: state = 2935; break; // &Lar -> &Larr - case 2936: state = 2937; break; // &lAr -> &lArr - case 2938: state = 2939; break; // &lar -> &larr - case 2967: state = 2968; break; // &lBa -> &lBar - case 2968: state = 2969; break; // &lBar -> &lBarr - case 2970: state = 2977; break; // &lb -> &lbr - case 2971: state = 2972; break; // &lba -> &lbar - case 2972: state = 2973; break; // &lbar -> &lbarr - case 2974: state = 2975; break; // &lbb -> &lbbr - case 2989: state = 2990; break; // &Lca -> &Lcar - case 2994: state = 2995; break; // &lca -> &lcar - case 3012: state = 3019; break; // &ld -> &ldr - case 3017: state = 3018; break; // &ldquo -> &ldquor - case 3022: state = 3023; break; // &ldrdha -> &ldrdhar - case 3027: state = 3028; break; // &ldrusha -> &ldrushar - case 3035: state = 3159; break; // &Left -> &Leftr - case 3036: state = 3048; break; // &LeftA -> &LeftAr - case 3041: state = 3042; break; // &LeftAngleB -> &LeftAngleBr - case 3048: state = 3049; break; // &LeftAr -> &LeftArr - case 3052: state = 3053; break; // &Lefta -> &Leftar - case 3053: state = 3054; break; // &Leftar -> &Leftarr - case 3058: state = 3169; break; // &left -> &leftr - case 3059: state = 3060; break; // &lefta -> &leftar - case 3060: state = 3061; break; // &leftar -> &leftarr - case 3065: state = 3066; break; // &LeftArrowBa -> &LeftArrowBar - case 3072: state = 3073; break; // &LeftArrowRightA -> &LeftArrowRightAr - case 3073: state = 3074; break; // &LeftArrowRightAr -> &LeftArrowRightArr - case 3094: state = 3095; break; // &LeftDoubleB -> &LeftDoubleBr - case 3110: state = 3111; break; // &LeftDownTeeVecto -> &LeftDownTeeVector - case 3116: state = 3117; break; // &LeftDownVecto -> &LeftDownVector - case 3119: state = 3120; break; // &LeftDownVectorBa -> &LeftDownVectorBar - case 3124: state = 3125; break; // &LeftFloo -> &LeftFloor - case 3127: state = 3128; break; // &leftha -> &lefthar - case 3143: state = 3144; break; // &leftlefta -> &leftleftar - case 3144: state = 3145; break; // &leftleftar -> &leftleftarr - case 3154: state = 3155; break; // &LeftRightA -> &LeftRightAr - case 3155: state = 3156; break; // &LeftRightAr -> &LeftRightArr - case 3164: state = 3165; break; // &Leftrighta -> &Leftrightar - case 3165: state = 3166; break; // &Leftrightar -> &Leftrightarr - case 3174: state = 3175; break; // &leftrighta -> &leftrightar - case 3175: state = 3176; break; // &leftrightar -> &leftrightarr - case 3181: state = 3182; break; // &leftrightha -> &leftrighthar - case 3193: state = 3194; break; // &leftrightsquiga -> &leftrightsquigar - case 3194: state = 3195; break; // &leftrightsquigar -> &leftrightsquigarr - case 3202: state = 3203; break; // &LeftRightVecto -> &LeftRightVector - case 3204: state = 3228; break; // &LeftT -> &LeftTr - case 3207: state = 3208; break; // &LeftTeeA -> &LeftTeeAr - case 3208: state = 3209; break; // &LeftTeeAr -> &LeftTeeArr - case 3216: state = 3217; break; // &LeftTeeVecto -> &LeftTeeVector - case 3219: state = 3220; break; // &leftth -> &leftthr - case 3236: state = 3237; break; // &LeftTriangleBa -> &LeftTriangleBar - case 3253: state = 3254; break; // &LeftUpDownVecto -> &LeftUpDownVector - case 3262: state = 3263; break; // &LeftUpTeeVecto -> &LeftUpTeeVector - case 3268: state = 3269; break; // &LeftUpVecto -> &LeftUpVector - case 3271: state = 3272; break; // &LeftUpVectorBa -> &LeftUpVectorBar - case 3277: state = 3278; break; // &LeftVecto -> &LeftVector - case 3280: state = 3281; break; // &LeftVectorBa -> &LeftVectorBar - case 3297: state = 3298; break; // &lesdoto -> &lesdotor - case 3305: state = 3306; break; // &lessapp -> &lessappr - case 3315: state = 3316; break; // &lesseqgt -> &lesseqgtr - case 3319: state = 3320; break; // &lesseqqgt -> &lesseqqgtr - case 3328: state = 3329; break; // &LessEqualG -> &LessEqualGr - case 3333: state = 3334; break; // &LessEqualGreate -> &LessEqualGreater - case 3344: state = 3345; break; // &LessG -> &LessGr - case 3349: state = 3350; break; // &LessGreate -> &LessGreater - case 3352: state = 3353; break; // &lessgt -> &lessgtr - case 3376: state = 3387; break; // &lf -> &lfr - case 3383: state = 3384; break; // &lfloo -> &lfloor - case 3385: state = 3386; break; // &Lf -> &Lfr - case 3391: state = 3392; break; // &lHa -> &lHar - case 3394: state = 3395; break; // &lha -> &lhar - case 3410: state = 3411; break; // &lla -> &llar - case 3411: state = 3412; break; // &llar -> &llarr - case 3414: state = 3415; break; // &llco -> &llcor - case 3417: state = 3418; break; // &llcorne -> &llcorner - case 3422: state = 3423; break; // &Llefta -> &Lleftar - case 3423: state = 3424; break; // &Lleftar -> &Lleftarr - case 3428: state = 3429; break; // &llha -> &llhar - case 3431: state = 3432; break; // &llt -> &lltr - case 3455: state = 3456; break; // &lnapp -> &lnappr - case 3467: state = 3470; break; // &loa -> &loar - case 3470: state = 3471; break; // &loar -> &loarr - case 3472: state = 3473; break; // &lob -> &lobr - case 3477: state = 3553; break; // &Long -> &Longr - case 3482: state = 3483; break; // &LongLeftA -> &LongLeftAr - case 3483: state = 3484; break; // &LongLeftAr -> &LongLeftArr - case 3490: state = 3517; break; // &Longleft -> &Longleftr - case 3491: state = 3492; break; // &Longlefta -> &Longleftar - case 3492: state = 3493; break; // &Longleftar -> &Longleftarr - case 3497: state = 3563; break; // &long -> &longr - case 3501: state = 3527; break; // &longleft -> &longleftr - case 3502: state = 3503; break; // &longlefta -> &longleftar - case 3503: state = 3504; break; // &longleftar -> &longleftarr - case 3512: state = 3513; break; // &LongLeftRightA -> &LongLeftRightAr - case 3513: state = 3514; break; // &LongLeftRightAr -> &LongLeftRightArr - case 3522: state = 3523; break; // &Longleftrighta -> &Longleftrightar - case 3523: state = 3524; break; // &Longleftrightar -> &Longleftrightarr - case 3532: state = 3533; break; // &longleftrighta -> &longleftrightar - case 3533: state = 3534; break; // &longleftrightar -> &longleftrightarr - case 3548: state = 3549; break; // &LongRightA -> &LongRightAr - case 3549: state = 3550; break; // &LongRightAr -> &LongRightArr - case 3558: state = 3559; break; // &Longrighta -> &Longrightar - case 3559: state = 3560; break; // &Longrightar -> &Longrightarr - case 3568: state = 3569; break; // &longrighta -> &longrightar - case 3569: state = 3570; break; // &longrightar -> &longrightarr - case 3575: state = 3576; break; // &loopa -> &loopar - case 3576: state = 3577; break; // &loopar -> &looparr - case 3579: state = 3584; break; // &looparrow -> &looparrowr - case 3590: state = 3591; break; // &lopa -> &lopar - case 3608: state = 3609; break; // &lowba -> &lowbar - case 3611: state = 3612; break; // &Lowe -> &Lower - case 3617: state = 3618; break; // &LowerLeftA -> &LowerLeftAr - case 3618: state = 3619; break; // &LowerLeftAr -> &LowerLeftArr - case 3627: state = 3628; break; // &LowerRightA -> &LowerRightAr - case 3628: state = 3629; break; // &LowerRightAr -> &LowerRightArr - case 3639: state = 3640; break; // &lpa -> &lpar - case 3644: state = 3645; break; // &lra -> &lrar - case 3645: state = 3646; break; // &lrar -> &lrarr - case 3648: state = 3649; break; // &lrco -> &lrcor - case 3651: state = 3652; break; // &lrcorne -> &lrcorner - case 3654: state = 3655; break; // &lrha -> &lrhar - case 3658: state = 3659; break; // &lrt -> &lrtr - case 3667: state = 3668; break; // &Lsc -> &Lscr - case 3669: state = 3670; break; // &lsc -> &lscr - case 3680: state = 3681; break; // &lsquo -> &lsquor - case 3682: state = 3683; break; // &Lst -> &Lstr - case 3686: state = 3687; break; // &lst -> &lstr - case 3692: state = 3717; break; // < -> <r - case 3695: state = 3696; break; // <ci -> <cir - case 3700: state = 3701; break; // <h -> <hr - case 3709: state = 3710; break; // <la -> <lar - case 3710: state = 3711; break; // <lar -> <larr - case 3722: state = 3723; break; // <rPa -> <rPar - case 3724: state = 3725; break; // &lu -> &lur - case 3729: state = 3730; break; // &lurdsha -> &lurdshar - case 3733: state = 3734; break; // &luruha -> &luruhar - case 3736: state = 3737; break; // &lve -> &lver - case 3746: state = 3772; break; // &ma -> &mar - case 3747: state = 3748; break; // &mac -> ¯ - case 3774: state = 3775; break; // &marke -> &marker - case 3795: state = 3796; break; // &measu -> &measur - case 3818: state = 3819; break; // &Mellint -> &Mellintr - case 3821: state = 3822; break; // &Mf -> &Mfr - case 3823: state = 3824; break; // &mf -> &mfr - case 3828: state = 3829; break; // &mic -> &micr - case 3836: state = 3837; break; // &midci -> &midcir - case 3858: state = 3859; break; // &mld -> &mldr - case 3877: state = 3878; break; // &Msc -> &Mscr - case 3880: state = 3881; break; // &msc -> &mscr - case 3897: state = 4621; break; // &n -> &nr - case 3920: state = 3921; break; // &napp -> &nappr - case 3925: state = 3926; break; // &natu -> &natur - case 3938: state = 3945; break; // &nca -> &ncar - case 3941: state = 3942; break; // &Nca -> &Ncar - case 3971: state = 3972; break; // &nea -> &near - case 3972: state = 3978; break; // &near -> &nearr - case 3975: state = 3976; break; // &neA -> &neAr - case 3976: state = 3977; break; // &neAr -> &neArr - case 4019: state = 4020; break; // &NegativeVe -> &NegativeVer - case 4037: state = 4038; break; // &nesea -> &nesear - case 4045: state = 4046; break; // &NestedG -> &NestedGr - case 4050: state = 4051; break; // &NestedGreate -> &NestedGreater - case 4052: state = 4053; break; // &NestedGreaterG -> &NestedGreaterGr - case 4057: state = 4058; break; // &NestedGreaterGreate -> &NestedGreaterGreater - case 4077: state = 4078; break; // &Nf -> &Nfr - case 4079: state = 4080; break; // &nf -> &nfr - case 4098: state = 4099; break; // &ngt -> &ngtr - case 4102: state = 4103; break; // &nhA -> &nhAr - case 4103: state = 4104; break; // &nhAr -> &nhArr - case 4105: state = 4106; break; // &nha -> &nhar - case 4106: state = 4107; break; // &nhar -> &nharr - case 4109: state = 4110; break; // &nhpa -> &nhpar - case 4122: state = 4123; break; // &nlA -> &nlAr - case 4123: state = 4124; break; // &nlAr -> &nlArr - case 4125: state = 4126; break; // &nla -> &nlar - case 4126: state = 4127; break; // &nlar -> &nlarr - case 4128: state = 4129; break; // &nld -> &nldr - case 4135: state = 4148; break; // &nLeft -> &nLeftr - case 4136: state = 4137; break; // &nLefta -> &nLeftar - case 4137: state = 4138; break; // &nLeftar -> &nLeftarr - case 4142: state = 4158; break; // &nleft -> &nleftr - case 4143: state = 4144; break; // &nlefta -> &nleftar - case 4144: state = 4145; break; // &nleftar -> &nleftarr - case 4153: state = 4154; break; // &nLeftrighta -> &nLeftrightar - case 4154: state = 4155; break; // &nLeftrightar -> &nLeftrightarr - case 4163: state = 4164; break; // &nleftrighta -> &nleftrightar - case 4164: state = 4165; break; // &nleftrightar -> &nleftrightarr - case 4182: state = 4183; break; // &nlt -> &nltr - case 4191: state = 4192; break; // &NoB -> &NoBr - case 4197: state = 4198; break; // &NonB -> &NonBr - case 4220: state = 4221; break; // &NotCong -> &NotCongr - case 4238: state = 4239; break; // &NotDoubleVe -> &NotDoubleVer - case 4246: state = 4247; break; // &NotDoubleVerticalBa -> &NotDoubleVerticalBar - case 4269: state = 4270; break; // &NotG -> &NotGr - case 4274: state = 4275; break; // &NotGreate -> &NotGreater - case 4290: state = 4291; break; // &NotGreaterG -> &NotGreaterGr - case 4295: state = 4296; break; // &NotGreaterGreate -> &NotGreaterGreater - case 4347: state = 4348; break; // &NotLeftT -> &NotLeftTr - case 4356: state = 4357; break; // &NotLeftTriangleBa -> &NotLeftTriangleBar - case 4370: state = 4371; break; // &NotLessG -> &NotLessGr - case 4375: state = 4376; break; // &NotLessGreate -> &NotLessGreater - case 4402: state = 4403; break; // &NotNestedG -> &NotNestedGr - case 4407: state = 4408; break; // &NotNestedGreate -> &NotNestedGreater - case 4409: state = 4410; break; // &NotNestedGreaterG -> &NotNestedGreaterGr - case 4414: state = 4415; break; // &NotNestedGreaterGreate -> &NotNestedGreaterGreater - case 4430: state = 4431; break; // &NotP -> &NotPr - case 4456: state = 4457; break; // &NotReve -> &NotRever - case 4471: state = 4472; break; // &NotRightT -> &NotRightTr - case 4480: state = 4481; break; // &NotRightTriangleBa -> &NotRightTriangleBar - case 4490: state = 4491; break; // &NotSqua -> &NotSquar - case 4505: state = 4506; break; // &NotSquareSupe -> &NotSquareSuper - case 4552: state = 4553; break; // &NotSupe -> &NotSuper - case 4587: state = 4588; break; // &NotVe -> &NotVer - case 4595: state = 4596; break; // &NotVerticalBa -> &NotVerticalBar - case 4597: state = 4613; break; // &np -> &npr - case 4598: state = 4599; break; // &npa -> &npar - case 4622: state = 4623; break; // &nrA -> &nrAr - case 4623: state = 4624; break; // &nrAr -> &nrArr - case 4625: state = 4626; break; // &nra -> &nrar - case 4626: state = 4627; break; // &nrar -> &nrarr - case 4635: state = 4636; break; // &nRighta -> &nRightar - case 4636: state = 4637; break; // &nRightar -> &nRightarr - case 4644: state = 4645; break; // &nrighta -> &nrightar - case 4645: state = 4646; break; // &nrightar -> &nrightarr - case 4649: state = 4650; break; // &nrt -> &nrtr - case 4654: state = 4662; break; // &nsc -> &nscr - case 4660: state = 4661; break; // &Nsc -> &Nscr - case 4664: state = 4665; break; // &nsho -> &nshor - case 4671: state = 4672; break; // &nshortpa -> &nshortpar - case 4686: state = 4687; break; // &nspa -> &nspar - case 4718: state = 4732; break; // &nt -> &ntr - case 4738: state = 4745; break; // &ntriangle -> &ntriangler - case 4755: state = 4756; break; // &nume -> &numer - case 4760: state = 4801; break; // &nv -> &nvr - case 4784: state = 4785; break; // &nvHa -> &nvHar - case 4785: state = 4786; break; // &nvHar -> &nvHarr - case 4793: state = 4794; break; // &nvlA -> &nvlAr - case 4794: state = 4795; break; // &nvlAr -> &nvlArr - case 4797: state = 4798; break; // &nvlt -> &nvltr - case 4802: state = 4803; break; // &nvrA -> &nvrAr - case 4803: state = 4804; break; // &nvrAr -> &nvrArr - case 4805: state = 4806; break; // &nvrt -> &nvrtr - case 4813: state = 4814; break; // &nwa -> &nwar - case 4814: state = 4820; break; // &nwar -> &nwarr - case 4817: state = 4818; break; // &nwA -> &nwAr - case 4818: state = 4819; break; // &nwAr -> &nwArr - case 4825: state = 4826; break; // &nwnea -> &nwnear - case 4827: state = 4990; break; // &O -> &Or - case 4833: state = 4991; break; // &o -> &or - case 4842: state = 4843; break; // &oci -> &ocir - case 4845: state = 4846; break; // &Oci -> &Ocir - case 4880: state = 4886; break; // &of -> &ofr - case 4882: state = 4883; break; // &ofci -> &ofcir - case 4884: state = 4885; break; // &Of -> &Ofr - case 4887: state = 4895; break; // &og -> &ogr - case 4890: state = 4891; break; // &Og -> &Ogr - case 4902: state = 4903; break; // &ohba -> &ohbar - case 4909: state = 4910; break; // &ola -> &olar - case 4910: state = 4911; break; // &olar -> &olarr - case 4912: state = 4915; break; // &olc -> &olcr - case 4913: state = 4914; break; // &olci -> &olcir - case 4925: state = 4926; break; // &Omac -> &Omacr - case 4929: state = 4930; break; // &omac -> &omacr - case 4938: state = 4939; break; // &Omic -> &Omicr - case 4943: state = 4944; break; // &omic -> &omicr - case 4958: state = 4959; break; // &opa -> &opar - case 4964: state = 4965; break; // &OpenCu -> &OpenCur - case 4984: state = 4985; break; // &ope -> &oper - case 4992: state = 4993; break; // &ora -> &orar - case 4993: state = 4994; break; // &orar -> &orarr - case 4996: state = 4997; break; // &orde -> &order - case 5006: state = 5007; break; // &oro -> &oror - case 5016: state = 5017; break; // &Osc -> &Oscr - case 5019: state = 5020; break; // &osc -> &oscr - case 5057: state = 5058; break; // &ovba -> &ovbar - case 5060: state = 5061; break; // &Ove -> &Over - case 5062: state = 5065; break; // &OverB -> &OverBr - case 5063: state = 5064; break; // &OverBa -> &OverBar - case 5073: state = 5074; break; // &OverPa -> &OverPar - case 5083: state = 5216; break; // &p -> &pr - case 5084: state = 5085; break; // &pa -> &par - case 5096: state = 5215; break; // &P -> &Pr - case 5097: state = 5098; break; // &Pa -> &Par - case 5108: state = 5109; break; // &pe -> &per - case 5124: state = 5125; break; // &Pf -> &Pfr - case 5126: state = 5127; break; // &pf -> &pfr - case 5146: state = 5147; break; // &pitchfo -> &pitchfor - case 5162: state = 5163; break; // &plusaci -> &plusacir - case 5166: state = 5167; break; // &plusci -> &pluscir - case 5193: state = 5194; break; // &Poinca -> &Poincar - case 5227: state = 5228; break; // &precapp -> &precappr - case 5232: state = 5233; break; // &preccu -> &preccur - case 5269: state = 5270; break; // &precnapp -> &precnappr - case 5306: state = 5307; break; // &profala -> &profalar - case 5313: state = 5314; break; // &profsu -> &profsur - case 5318: state = 5319; break; // &Propo -> &Propor - case 5331: state = 5332; break; // &pru -> &prur - case 5336: state = 5337; break; // &Psc -> &Pscr - case 5339: state = 5340; break; // &psc -> &pscr - case 5349: state = 5350; break; // &Qf -> &Qfr - case 5352: state = 5353; break; // &qf -> &qfr - case 5363: state = 5364; break; // &qp -> &qpr - case 5369: state = 5370; break; // &Qsc -> &Qscr - case 5372: state = 5373; break; // &qsc -> &qscr - case 5377: state = 5378; break; // &quate -> &quater - case 5397: state = 5920; break; // &r -> &rr - case 5398: state = 5436; break; // &rA -> &rAr - case 5399: state = 5400; break; // &rAa -> &rAar - case 5400: state = 5401; break; // &rAar -> &rAarr - case 5402: state = 5438; break; // &ra -> &rar - case 5405: state = 5924; break; // &R -> &Rr - case 5406: state = 5434; break; // &Ra -> &Rar - case 5434: state = 5435; break; // &Rar -> &Rarr - case 5436: state = 5437; break; // &rAr -> &rArr - case 5438: state = 5439; break; // &rar -> &rarr - case 5477: state = 5478; break; // &RBa -> &RBar - case 5478: state = 5479; break; // &RBar -> &RBarr - case 5481: state = 5482; break; // &rBa -> &rBar - case 5482: state = 5483; break; // &rBar -> &rBarr - case 5484: state = 5491; break; // &rb -> &rbr - case 5485: state = 5486; break; // &rba -> &rbar - case 5486: state = 5487; break; // &rbar -> &rbarr - case 5488: state = 5489; break; // &rbb -> &rbbr - case 5503: state = 5504; break; // &Rca -> &Rcar - case 5508: state = 5509; break; // &rca -> &rcar - case 5532: state = 5533; break; // &rdldha -> &rdldhar - case 5536: state = 5537; break; // &rdquo -> &rdquor - case 5548: state = 5549; break; // &realpa -> &realpar - case 5558: state = 5559; break; // &Reve -> &Rever - case 5574: state = 5575; break; // &ReverseEquilib -> &ReverseEquilibr - case 5587: state = 5588; break; // &ReverseUpEquilib -> &ReverseUpEquilibr - case 5592: state = 5603; break; // &rf -> &rfr - case 5599: state = 5600; break; // &rfloo -> &rfloor - case 5601: state = 5602; break; // &Rf -> &Rfr - case 5605: state = 5606; break; // &rHa -> &rHar - case 5608: state = 5609; break; // &rha -> &rhar - case 5621: state = 5633; break; // &RightA -> &RightAr - case 5626: state = 5627; break; // &RightAngleB -> &RightAngleBr - case 5633: state = 5634; break; // &RightAr -> &RightArr - case 5637: state = 5638; break; // &Righta -> &Rightar - case 5638: state = 5639; break; // &Rightar -> &Rightarr - case 5645: state = 5743; break; // &right -> &rightr - case 5646: state = 5647; break; // &righta -> &rightar - case 5647: state = 5648; break; // &rightar -> &rightarr - case 5652: state = 5653; break; // &RightArrowBa -> &RightArrowBar - case 5658: state = 5659; break; // &RightArrowLeftA -> &RightArrowLeftAr - case 5659: state = 5660; break; // &RightArrowLeftAr -> &RightArrowLeftArr - case 5680: state = 5681; break; // &RightDoubleB -> &RightDoubleBr - case 5696: state = 5697; break; // &RightDownTeeVecto -> &RightDownTeeVector - case 5702: state = 5703; break; // &RightDownVecto -> &RightDownVector - case 5705: state = 5706; break; // &RightDownVectorBa -> &RightDownVectorBar - case 5710: state = 5711; break; // &RightFloo -> &RightFloor - case 5713: state = 5714; break; // &rightha -> &righthar - case 5729: state = 5730; break; // &rightlefta -> &rightleftar - case 5730: state = 5731; break; // &rightleftar -> &rightleftarr - case 5736: state = 5737; break; // &rightleftha -> &rightlefthar - case 5748: state = 5749; break; // &rightrighta -> &rightrightar - case 5749: state = 5750; break; // &rightrightar -> &rightrightarr - case 5759: state = 5760; break; // &rightsquiga -> &rightsquigar - case 5760: state = 5761; break; // &rightsquigar -> &rightsquigarr - case 5764: state = 5788; break; // &RightT -> &RightTr - case 5767: state = 5768; break; // &RightTeeA -> &RightTeeAr - case 5768: state = 5769; break; // &RightTeeAr -> &RightTeeArr - case 5776: state = 5777; break; // &RightTeeVecto -> &RightTeeVector - case 5779: state = 5780; break; // &rightth -> &rightthr - case 5796: state = 5797; break; // &RightTriangleBa -> &RightTriangleBar - case 5813: state = 5814; break; // &RightUpDownVecto -> &RightUpDownVector - case 5822: state = 5823; break; // &RightUpTeeVecto -> &RightUpTeeVector - case 5828: state = 5829; break; // &RightUpVecto -> &RightUpVector - case 5831: state = 5832; break; // &RightUpVectorBa -> &RightUpVectorBar - case 5837: state = 5838; break; // &RightVecto -> &RightVector - case 5840: state = 5841; break; // &RightVectorBa -> &RightVectorBar - case 5855: state = 5856; break; // &rla -> &rlar - case 5856: state = 5857; break; // &rlar -> &rlarr - case 5859: state = 5860; break; // &rlha -> &rlhar - case 5876: state = 5879; break; // &roa -> &roar - case 5879: state = 5880; break; // &roar -> &roarr - case 5881: state = 5882; break; // &rob -> &robr - case 5885: state = 5886; break; // &ropa -> &ropar - case 5910: state = 5911; break; // &rpa -> &rpar - case 5921: state = 5922; break; // &rra -> &rrar - case 5922: state = 5923; break; // &rrar -> &rrarr - case 5929: state = 5930; break; // &Rrighta -> &Rrightar - case 5930: state = 5931; break; // &Rrightar -> &Rrightarr - case 5940: state = 5941; break; // &Rsc -> &Rscr - case 5942: state = 5943; break; // &rsc -> &rscr - case 5949: state = 5950; break; // &rsquo -> &rsquor - case 5951: state = 5960; break; // &rt -> &rtr - case 5952: state = 5953; break; // &rth -> &rthr - case 5965: state = 5966; break; // &rtrilt -> &rtriltr - case 5982: state = 5983; break; // &ruluha -> &ruluhar - case 5991: state = 6334; break; // &s -> &sr - case 6003: state = 6009; break; // &sca -> &scar - case 6005: state = 6006; break; // &Sca -> &Scar - case 6024: state = 6025; break; // &Sci -> &Scir - case 6027: state = 6028; break; // &sci -> &scir - case 6054: state = 6055; break; // &sea -> &sear - case 6055: state = 6061; break; // &sear -> &searr - case 6058: state = 6059; break; // &seA -> &seAr - case 6059: state = 6060; break; // &seAr -> &seArr - case 6070: state = 6071; break; // &seswa -> &seswar - case 6081: state = 6082; break; // &Sf -> &Sfr - case 6083: state = 6084; break; // &sf -> &sfr - case 6089: state = 6090; break; // &sha -> &shar - case 6105: state = 6106; break; // &Sho -> &Shor - case 6112: state = 6113; break; // &ShortDownA -> &ShortDownAr - case 6113: state = 6114; break; // &ShortDownAr -> &ShortDownArr - case 6121: state = 6122; break; // &ShortLeftA -> &ShortLeftAr - case 6122: state = 6123; break; // &ShortLeftAr -> &ShortLeftArr - case 6126: state = 6127; break; // &sho -> &shor - case 6133: state = 6134; break; // &shortpa -> &shortpar - case 6145: state = 6146; break; // &ShortRightA -> &ShortRightAr - case 6146: state = 6147; break; // &ShortRightAr -> &ShortRightArr - case 6152: state = 6153; break; // &ShortUpA -> &ShortUpAr - case 6153: state = 6154; break; // &ShortUpAr -> &ShortUpArr - case 6168: state = 6184; break; // &sim -> &simr - case 6185: state = 6186; break; // &simra -> &simrar - case 6186: state = 6187; break; // &simrar -> &simrarr - case 6189: state = 6190; break; // &sla -> &slar - case 6190: state = 6191; break; // &slar -> &slarr - case 6197: state = 6198; break; // &SmallCi -> &SmallCir - case 6219: state = 6220; break; // &smepa -> &smepar - case 6242: state = 6243; break; // &solba -> &solbar - case 6250: state = 6257; break; // &spa -> &spar - case 6266: state = 6267; break; // &Sq -> &Sqr - case 6287: state = 6288; break; // &Squa -> &Squar - case 6290: state = 6291; break; // &squa -> &squar - case 6296: state = 6297; break; // &SquareInte -> &SquareInter - case 6317: state = 6318; break; // &SquareSupe -> &SquareSuper - case 6335: state = 6336; break; // &sra -> &srar - case 6336: state = 6337; break; // &srar -> &srarr - case 6339: state = 6340; break; // &Ssc -> &Sscr - case 6342: state = 6343; break; // &ssc -> &sscr - case 6353: state = 6354; break; // &ssta -> &sstar - case 6357: state = 6358; break; // &Sta -> &Star - case 6359: state = 6363; break; // &st -> &str - case 6360: state = 6361; break; // &sta -> &star - case 6384: state = 6404; break; // &sub -> &subr - case 6405: state = 6406; break; // &subra -> &subrar - case 6406: state = 6407; break; // &subrar -> &subrarr - case 6435: state = 6436; break; // &succapp -> &succappr - case 6440: state = 6441; break; // &succcu -> &succcur - case 6477: state = 6478; break; // &succnapp -> &succnappr - case 6515: state = 6516; break; // &Supe -> &Super - case 6532: state = 6533; break; // &supla -> &suplar - case 6533: state = 6534; break; // &suplar -> &suplarr - case 6565: state = 6566; break; // &swa -> &swar - case 6566: state = 6572; break; // &swar -> &swarr - case 6569: state = 6570; break; // &swA -> &swAr - case 6570: state = 6571; break; // &swAr -> &swArr - case 6577: state = 6578; break; // &swnwa -> &swnwar - case 6583: state = 6797; break; // &T -> &Tr - case 6586: state = 6760; break; // &t -> &tr - case 6587: state = 6588; break; // &ta -> &tar - case 6594: state = 6595; break; // &tb -> &tbr - case 6598: state = 6599; break; // &Tca -> &Tcar - case 6603: state = 6604; break; // &tca -> &tcar - case 6621: state = 6622; break; // &tel -> &telr - case 6625: state = 6626; break; // &Tf -> &Tfr - case 6627: state = 6628; break; // &tf -> &tfr - case 6630: state = 6631; break; // &the -> &ther - case 6635: state = 6636; break; // &The -> &Ther - case 6639: state = 6640; break; // &Therefo -> &Therefor - case 6643: state = 6644; break; // &therefo -> &therefor - case 6659: state = 6660; break; // &thickapp -> &thickappr - case 6693: state = 6694; break; // &tho -> &thor - case 6727: state = 6728; break; // ×ba -> ×bar - case 6740: state = 6741; break; // &topci -> &topcir - case 6746: state = 6747; break; // &topfo -> &topfor - case 6751: state = 6752; break; // &tp -> &tpr - case 6769: state = 6781; break; // &triangle -> &triangler - case 6822: state = 6823; break; // &Tsc -> &Tscr - case 6825: state = 6826; break; // &tsc -> &tscr - case 6837: state = 6838; break; // &Tst -> &Tstr - case 6841: state = 6842; break; // &tst -> &tstr - case 6853: state = 6863; break; // &twohead -> &twoheadr - case 6858: state = 6859; break; // &twoheadlefta -> &twoheadleftar - case 6859: state = 6860; break; // &twoheadleftar -> &twoheadleftarr - case 6868: state = 6869; break; // &twoheadrighta -> &twoheadrightar - case 6869: state = 6870; break; // &twoheadrightar -> &twoheadrightarr - case 6873: state = 7176; break; // &U -> &Ur - case 6874: state = 6885; break; // &Ua -> &Uar - case 6879: state = 7166; break; // &u -> &ur - case 6880: state = 6890; break; // &ua -> &uar - case 6885: state = 6886; break; // &Uar -> &Uarr - case 6887: state = 6888; break; // &uA -> &uAr - case 6888: state = 6889; break; // &uAr -> &uArr - case 6890: state = 6891; break; // &uar -> &uarr - case 6894: state = 6895; break; // &Uarroci -> &Uarrocir - case 6896: state = 6897; break; // &Ub -> &Ubr - case 6900: state = 6901; break; // &ub -> &ubr - case 6911: state = 6912; break; // &Uci -> &Ucir - case 6915: state = 6916; break; // &uci -> &ucir - case 6921: state = 6922; break; // &uda -> &udar - case 6922: state = 6923; break; // &udar -> &udarr - case 6934: state = 6935; break; // &udha -> &udhar - case 6936: state = 6943; break; // &uf -> &ufr - case 6941: state = 6942; break; // &Uf -> &Ufr - case 6944: state = 6945; break; // &Ug -> &Ugr - case 6949: state = 6950; break; // &ug -> &ugr - case 6955: state = 6956; break; // &uHa -> &uHar - case 6958: state = 6959; break; // &uha -> &uhar - case 6959: state = 6961; break; // &uhar -> &uharr - case 6966: state = 6972; break; // &ulc -> &ulcr - case 6967: state = 6968; break; // &ulco -> &ulcor - case 6970: state = 6971; break; // &ulcorne -> &ulcorner - case 6975: state = 6976; break; // &ult -> &ultr - case 6980: state = 6981; break; // &Umac -> &Umacr - case 6984: state = 6985; break; // &umac -> &umacr - case 6989: state = 6990; break; // &Unde -> &Under - case 6991: state = 6994; break; // &UnderB -> &UnderBr - case 6992: state = 6993; break; // &UnderBa -> &UnderBar - case 7002: state = 7003; break; // &UnderPa -> &UnderPar - case 7032: state = 7033; break; // &UpA -> &UpAr - case 7033: state = 7034; break; // &UpAr -> &UpArr - case 7037: state = 7038; break; // &Upa -> &Upar - case 7038: state = 7039; break; // &Upar -> &Uparr - case 7043: state = 7044; break; // &upa -> &upar - case 7044: state = 7045; break; // &upar -> &uparr - case 7049: state = 7050; break; // &UpArrowBa -> &UpArrowBar - case 7055: state = 7056; break; // &UpArrowDownA -> &UpArrowDownAr - case 7056: state = 7057; break; // &UpArrowDownAr -> &UpArrowDownArr - case 7064: state = 7065; break; // &UpDownA -> &UpDownAr - case 7065: state = 7066; break; // &UpDownAr -> &UpDownArr - case 7073: state = 7074; break; // &Updowna -> &Updownar - case 7074: state = 7075; break; // &Updownar -> &Updownarr - case 7082: state = 7083; break; // &updowna -> &updownar - case 7083: state = 7084; break; // &updownar -> &updownarr - case 7093: state = 7094; break; // &UpEquilib -> &UpEquilibr - case 7099: state = 7100; break; // &upha -> &uphar - case 7104: state = 7109; break; // &upharpoon -> &upharpoonr - case 7118: state = 7119; break; // &Uppe -> &Upper - case 7124: state = 7125; break; // &UpperLeftA -> &UpperLeftAr - case 7125: state = 7126; break; // &UpperLeftAr -> &UpperLeftArr - case 7134: state = 7135; break; // &UpperRightA -> &UpperRightAr - case 7135: state = 7136; break; // &UpperRightAr -> &UpperRightArr - case 7153: state = 7154; break; // &UpTeeA -> &UpTeeAr - case 7154: state = 7155; break; // &UpTeeAr -> &UpTeeArr - case 7160: state = 7161; break; // &upupa -> &upupar - case 7161: state = 7162; break; // &upupar -> &upuparr - case 7167: state = 7173; break; // &urc -> &urcr - case 7168: state = 7169; break; // &urco -> &urcor - case 7171: state = 7172; break; // &urcorne -> &urcorner - case 7183: state = 7184; break; // &urt -> &urtr - case 7187: state = 7188; break; // &Usc -> &Uscr - case 7190: state = 7191; break; // &usc -> &uscr - case 7192: state = 7205; break; // &ut -> &utr - case 7209: state = 7210; break; // &uua -> &uuar - case 7210: state = 7211; break; // &uuar -> &uuarr - case 7223: state = 7417; break; // &v -> &vr - case 7224: state = 7229; break; // &va -> &var - case 7226: state = 7227; break; // &vang -> &vangr - case 7229: state = 7261; break; // &var -> &varr - case 7249: state = 7253; break; // &varp -> &varpr - case 7258: state = 7259; break; // &vA -> &vAr - case 7259: state = 7260; break; // &vAr -> &vArr - case 7286: state = 7291; break; // &vart -> &vartr - case 7297: state = 7302; break; // &vartriangle -> &vartriangler - case 7309: state = 7310; break; // &Vba -> &Vbar - case 7312: state = 7313; break; // &vBa -> &vBar - case 7336: state = 7349; break; // &Ve -> &Ver - case 7338: state = 7353; break; // &ve -> &ver - case 7341: state = 7342; break; // &veeba -> &veebar - case 7351: state = 7352; break; // &Verba -> &Verbar - case 7355: state = 7356; break; // &verba -> &verbar - case 7364: state = 7365; break; // &VerticalBa -> &VerticalBar - case 7373: state = 7374; break; // &VerticalSepa -> &VerticalSepar - case 7377: state = 7378; break; // &VerticalSeparato -> &VerticalSeparator - case 7394: state = 7395; break; // &Vf -> &Vfr - case 7396: state = 7397; break; // &vf -> &vfr - case 7399: state = 7400; break; // &vlt -> &vltr - case 7413: state = 7414; break; // &vp -> &vpr - case 7418: state = 7419; break; // &vrt -> &vrtr - case 7422: state = 7423; break; // &Vsc -> &Vscr - case 7425: state = 7426; break; // &vsc -> &vscr - case 7449: state = 7450; break; // &Wci -> &Wcir - case 7452: state = 7484; break; // &w -> &wr - case 7454: state = 7455; break; // &wci -> &wcir - case 7460: state = 7461; break; // &wedba -> &wedbar - case 7470: state = 7471; break; // &weie -> &weier - case 7473: state = 7474; break; // &Wf -> &Wfr - case 7475: state = 7476; break; // &wf -> &wfr - case 7490: state = 7491; break; // &Wsc -> &Wscr - case 7493: state = 7494; break; // &wsc -> &wscr - case 7495: state = 7551; break; // &x -> &xr - case 7499: state = 7500; break; // &xci -> &xcir - case 7505: state = 7506; break; // &xdt -> &xdtr - case 7509: state = 7510; break; // &Xf -> &Xfr - case 7511: state = 7512; break; // &xf -> &xfr - case 7514: state = 7515; break; // &xhA -> &xhAr - case 7515: state = 7516; break; // &xhAr -> &xhArr - case 7517: state = 7518; break; // &xha -> &xhar - case 7518: state = 7519; break; // &xhar -> &xharr - case 7523: state = 7524; break; // &xlA -> &xlAr - case 7524: state = 7525; break; // &xlAr -> &xlArr - case 7526: state = 7527; break; // &xla -> &xlar - case 7527: state = 7528; break; // &xlar -> &xlarr - case 7552: state = 7553; break; // &xrA -> &xrAr - case 7553: state = 7554; break; // &xrAr -> &xrArr - case 7555: state = 7556; break; // &xra -> &xrar - case 7556: state = 7557; break; // &xrar -> &xrarr - case 7559: state = 7560; break; // &Xsc -> &Xscr - case 7562: state = 7563; break; // &xsc -> &xscr - case 7573: state = 7574; break; // &xut -> &xutr - case 7601: state = 7602; break; // &Yci -> &Ycir - case 7605: state = 7606; break; // &yci -> &ycir - case 7612: state = 7613; break; // &Yf -> &Yfr - case 7614: state = 7615; break; // &yf -> &yfr - case 7629: state = 7630; break; // &Ysc -> &Yscr - case 7632: state = 7633; break; // &ysc -> &yscr - case 7658: state = 7659; break; // &Zca -> &Zcar - case 7663: state = 7664; break; // &zca -> &zcar - case 7677: state = 7678; break; // &zeet -> &zeetr - case 7680: state = 7681; break; // &Ze -> &Zer - case 7697: state = 7698; break; // &Zf -> &Zfr - case 7699: state = 7700; break; // &zf -> &zfr - case 7708: state = 7709; break; // &zig -> &zigr - case 7710: state = 7711; break; // &zigra -> &zigrar - case 7711: state = 7712; break; // &zigrar -> &zigrarr - case 7720: state = 7721; break; // &Zsc -> &Zscr - case 7723: state = 7724; break; // &zsc -> &zscr - default: return false; - } - break; - case 's': - switch (state) { - case 0: state = 5991; break; // & -> &s - case 1: state = 180; break; // &A -> &As - case 7: state = 183; break; // &a -> &as - case 62: state = 63; break; // &alef -> &alefs - case 91: state = 96; break; // &and -> &ands - case 102: state = 123; break; // &ang -> &angs - case 106: state = 107; break; // &angm -> &angms - case 152: state = 153; break; // &apo -> &apos - case 180: state = 186; break; // &As -> &Ass - case 222: state = 552; break; // &b -> &bs - case 225: state = 242; break; // &back -> &backs - case 231: state = 232; break; // &backep -> &backeps - case 247: state = 549; break; // &B -> &Bs - case 250: state = 251; break; // &Back -> &Backs - case 253: state = 254; break; // &Backsla -> &Backslas - case 291: state = 292; break; // &becau -> &becaus - case 296: state = 297; break; // &Becau -> &Becaus - case 305: state = 306; break; // &bep -> &beps - case 318: state = 319; break; // &Bernoulli -> &Bernoullis - case 334: state = 356; break; // &big -> &bigs - case 349: state = 350; break; // &bigoplu -> &bigoplus - case 354: state = 355; break; // &bigotime -> &bigotimes - case 381: state = 382; break; // &biguplu -> &biguplus - case 399: state = 407; break; // &black -> &blacks - case 497: state = 498; break; // &boxminu -> &boxminus - case 501: state = 502; break; // &boxplu -> &boxplus - case 506: state = 507; break; // &boxtime -> &boxtimes - case 564: state = 565; break; // &bsolh -> &bsolhs - case 583: state = 972; break; // &C -> &Cs - case 589: state = 975; break; // &c -> &cs - case 596: state = 630; break; // &cap -> &caps - case 639: state = 640; break; // &Cayley -> &Cayleys - case 643: state = 644; break; // &ccap -> &ccaps - case 673: state = 674; break; // &ccup -> &ccups - case 674: state = 675; break; // &ccups -> &ccupss - case 733: state = 799; break; // &cir -> &cirs - case 754: state = 755; break; // &circleda -> &circledas - case 762: state = 763; break; // &circledda -> &circleddas - case 778: state = 779; break; // &CircleMinu -> &CircleMinus - case 782: state = 783; break; // &CirclePlu -> &CirclePlus - case 787: state = 788; break; // &CircleTime -> &CircleTimes - case 804: state = 826; break; // &Clo -> &Clos - case 808: state = 809; break; // &Clockwi -> &Clockwis - case 851: state = 852; break; // &club -> &clubs - case 881: state = 882; break; // &complexe -> &complexes - case 929: state = 930; break; // © -> ©s - case 943: state = 944; break; // &CounterClockwi -> &CounterClockwis - case 966: state = 967; break; // &Cro -> &Cros - case 967: state = 968; break; // &Cros -> &Cross - case 969: state = 970; break; // &cro -> &cros - case 970: state = 971; break; // &cros -> &cross - case 994: state = 997; break; // &cue -> &cues - case 1006: state = 1025; break; // &cup -> &cups - case 1034: state = 1039; break; // &curlyeq -> &curlyeqs - case 1091: state = 1604; break; // &D -> &Ds - case 1092: state = 1116; break; // &Da -> &Das - case 1097: state = 1607; break; // &d -> &ds - case 1098: state = 1114; break; // &da -> &das - case 1157: state = 1158; break; // &ddot -> &ddots - case 1176: state = 1177; break; // &dfi -> &dfis - case 1228: state = 1260; break; // &di -> &dis - case 1230: state = 1242; break; // &diam -> &diams - case 1237: state = 1238; break; // &diamond -> &diamonds - case 1272: state = 1273; break; // ÷ontime -> ÷ontimes - case 1302: state = 1325; break; // &dot -> &dots - case 1319: state = 1320; break; // &dotminu -> &dotminus - case 1323: state = 1324; break; // &dotplu -> &dotplus - case 1508: state = 1509; break; // &downdownarrow -> &downdownarrows - case 1656: state = 1897; break; // &E -> &Es - case 1662: state = 1900; break; // &e -> &es - case 1663: state = 1668; break; // &ea -> &eas - case 1714: state = 1724; break; // &eg -> &egs - case 1728: state = 1742; break; // &el -> &els - case 1739: state = 1740; break; // &elinter -> &elinters - case 1750: state = 1790; break; // &em -> &ems - case 1756: state = 1757; break; // &empty -> &emptys - case 1797: state = 1799; break; // &en -> &ens - case 1813: state = 1821; break; // &ep -> &eps - case 1815: state = 1816; break; // &epar -> &epars - case 1819: state = 1820; break; // &eplu -> &eplus - case 1823: state = 1824; break; // &Ep -> &Eps - case 1833: state = 1842; break; // &eq -> &eqs - case 1853: state = 1854; break; // &eqslantle -> &eqslantles - case 1854: state = 1855; break; // &eqslantles -> &eqslantless - case 1862: state = 1863; break; // &equal -> &equals - case 1869: state = 1870; break; // &eque -> &eques - case 1887: state = 1888; break; // &eqvpar -> &eqvpars - case 1928: state = 1929; break; // &exi -> &exis - case 1932: state = 1933; break; // &Exi -> &Exis - case 1934: state = 1935; break; // &Exist -> &Exists - case 1964: state = 2115; break; // &f -> &fs - case 1973: state = 1974; break; // &fallingdot -> &fallingdots - case 1977: state = 2112; break; // &F -> &Fs - case 2047: state = 2048; break; // &fltn -> &fltns - case 2084: state = 2107; break; // &fra -> &fras - case 2118: state = 2285; break; // &g -> &gs - case 2124: state = 2282; break; // &G -> &Gs - case 2166: state = 2176; break; // &ge -> &ges - case 2169: state = 2171; break; // &geq -> &geqs - case 2185: state = 2186; break; // &gesle -> &gesles - case 2208: state = 2219; break; // &gn -> &gns - case 2244: state = 2245; break; // &GreaterEqualLe -> &GreaterEqualLes - case 2245: state = 2246; break; // &GreaterEqualLes -> &GreaterEqualLess - case 2264: state = 2265; break; // &GreaterLe -> &GreaterLes - case 2265: state = 2266; break; // &GreaterLes -> &GreaterLess - case 2308: state = 2309; break; // >que -> >ques - case 2311: state = 2338; break; // >r -> >rs - case 2326: state = 2327; break; // >reqle -> >reqles - case 2327: state = 2328; break; // >reqles -> >reqless - case 2331: state = 2332; break; // >reqqle -> >reqqles - case 2332: state = 2333; break; // >reqqles -> >reqqless - case 2335: state = 2336; break; // >rle -> >rles - case 2336: state = 2337; break; // >rles -> >rless - case 2351: state = 2490; break; // &H -> &Hs - case 2356: state = 2493; break; // &h -> &hs - case 2359: state = 2360; break; // &hair -> &hairs - case 2400: state = 2401; break; // &heart -> &hearts - case 2428: state = 2429; break; // &hk -> &hks - case 2497: state = 2498; break; // &hsla -> &hslas - case 2533: state = 2740; break; // &I -> &Is - case 2539: state = 2743; break; // &i -> &is - case 2639: state = 2640; break; // &Implie -> &Implies - case 2665: state = 2666; break; // &integer -> &integers - case 2676: state = 2677; break; // &Inter -> &Inters - case 2694: state = 2695; break; // &Invi -> &Invis - case 2708: state = 2709; break; // &InvisibleTime -> &InvisibleTimes - case 2737: state = 2738; break; // &ique -> &iques - case 2747: state = 2752; break; // &isin -> &isins - case 2777: state = 2803; break; // &J -> &Js - case 2782: state = 2806; break; // &j -> &js - case 2825: state = 2875; break; // &K -> &Ks - case 2830: state = 2878; break; // &k -> &ks - case 2881: state = 3661; break; // &l -> &ls - case 2886: state = 3666; break; // &L -> &Ls - case 2939: state = 2951; break; // &larr -> &larrs - case 2941: state = 2942; break; // &larrbf -> &larrbfs - case 2943: state = 2944; break; // &larrf -> &larrfs - case 2964: state = 2965; break; // &late -> &lates - case 2982: state = 2984; break; // &lbrk -> &lbrks - case 3012: state = 3029; break; // &ld -> &lds - case 3024: state = 3025; break; // &ldru -> &ldrus - case 3032: state = 3291; break; // &le -> &les - case 3033: state = 3321; break; // &Le -> &Les - case 3147: state = 3148; break; // &leftleftarrow -> &leftleftarrows - case 3173: state = 3188; break; // &leftright -> &leftrights - case 3178: state = 3179; break; // &leftrightarrow -> &leftrightarrows - case 3186: state = 3187; break; // &leftrightharpoon -> &leftrightharpoons - case 3226: state = 3227; break; // &leftthreetime -> &leftthreetimes - case 3284: state = 3286; break; // &leq -> &leqs - case 3291: state = 3302; break; // &les -> &less - case 3300: state = 3301; break; // &lesge -> &lesges - case 3302: state = 3358; break; // &less -> &lesss - case 3321: state = 3322; break; // &Les -> &Less - case 3355: state = 3356; break; // &LessLe -> &LessLes - case 3356: state = 3357; break; // &LessLes -> &LessLess - case 3377: state = 3378; break; // &lfi -> &lfis - case 3445: state = 3446; break; // &lmou -> &lmous - case 3452: state = 3463; break; // &ln -> &lns - case 3539: state = 3540; break; // &longmap -> &longmaps - case 3596: state = 3597; break; // &loplu -> &loplus - case 3601: state = 3602; break; // &lotime -> &lotimes - case 3604: state = 3605; break; // &lowa -> &lowas - case 3706: state = 3707; break; // <ime -> <imes - case 3714: state = 3715; break; // <que -> <ques - case 3726: state = 3727; break; // &lurd -> &lurds - case 3745: state = 3879; break; // &m -> &ms - case 3752: state = 3753; break; // &malte -> &maltes - case 3755: state = 3876; break; // &M -> &Ms - case 3758: state = 3759; break; // &map -> &maps - case 3785: state = 3786; break; // &mda -> &mdas - case 3793: state = 3794; break; // &mea -> &meas - case 3832: state = 3833; break; // &mida -> &midas - case 3842: state = 3843; break; // &minu -> &minus - case 3849: state = 3850; break; // &Minu -> &Minus - case 3853: state = 3854; break; // &MinusPlu -> &MinusPlus - case 3863: state = 3864; break; // &mnplu -> &mnplus - case 3868: state = 3869; break; // &model -> &models - case 3884: state = 3885; break; // &mstpo -> &mstpos - case 3897: state = 4653; break; // &n -> &ns - case 3902: state = 4659; break; // &N -> &Ns - case 3918: state = 3919; break; // &napo -> &napos - case 3928: state = 3929; break; // &natural -> &naturals - case 3930: state = 3931; break; // &nb -> &nbs - case 3967: state = 3968; break; // &nda -> &ndas - case 3970: state = 4035; break; // &ne -> &nes - case 3984: state = 4041; break; // &Ne -> &Nes - case 4060: state = 4061; break; // &NestedLe -> &NestedLes - case 4061: state = 4062; break; // &NestedLes -> &NestedLess - case 4064: state = 4065; break; // &NestedLessLe -> &NestedLessLes - case 4065: state = 4066; break; // &NestedLessLes -> &NestedLessLess - case 4073: state = 4074; break; // &nexi -> &nexis - case 4075: state = 4076; break; // &nexist -> &nexists - case 4081: state = 4094; break; // &ng -> &ngs - case 4083: state = 4091; break; // &nge -> &nges - case 4084: state = 4086; break; // &ngeq -> &ngeqs - case 4111: state = 4112; break; // &ni -> &nis - case 4121: state = 4178; break; // &nl -> &nls - case 4131: state = 4175; break; // &nle -> &nles - case 4168: state = 4170; break; // &nleq -> &nleqs - case 4175: state = 4176; break; // &nles -> &nless - case 4265: state = 4266; break; // &NotExi -> &NotExis - case 4267: state = 4268; break; // &NotExist -> &NotExists - case 4298: state = 4299; break; // &NotGreaterLe -> &NotGreaterLes - case 4299: state = 4300; break; // &NotGreaterLes -> &NotGreaterLess - case 4344: state = 4363; break; // &NotLe -> &NotLes - case 4363: state = 4364; break; // &NotLes -> &NotLess - case 4378: state = 4379; break; // &NotLessLe -> &NotLessLes - case 4379: state = 4380; break; // &NotLessLes -> &NotLessLess - case 4397: state = 4398; break; // &NotNe -> &NotNes - case 4417: state = 4418; break; // &NotNestedLe -> &NotNestedLes - case 4418: state = 4419; break; // &NotNestedLes -> &NotNestedLess - case 4421: state = 4422; break; // &NotNestedLessLe -> &NotNestedLessLes - case 4422: state = 4423; break; // &NotNestedLessLes -> &NotNestedLessLess - case 4436: state = 4437; break; // &NotPrecede -> &NotPrecedes - case 4457: state = 4458; break; // &NotRever -> &NotRevers - case 4495: state = 4496; break; // &NotSquareSub -> &NotSquareSubs - case 4506: state = 4507; break; // &NotSquareSuper -> &NotSquareSupers - case 4516: state = 4517; break; // &NotSub -> &NotSubs - case 4529: state = 4530; break; // &NotSucceed -> &NotSucceeds - case 4553: state = 4554; break; // &NotSuper -> &NotSupers - case 4599: state = 4605; break; // &npar -> &npars - case 4688: state = 4689; break; // &nsq -> &nsqs - case 4696: state = 4699; break; // &nsub -> &nsubs - case 4709: state = 4712; break; // &nsup -> &nsups - case 4754: state = 4758; break; // &num -> &nums - case 4760: state = 4809; break; // &nv -> &nvs - case 4765: state = 4766; break; // &nVDa -> &nVDas - case 4769: state = 4770; break; // &nVda -> &nVdas - case 4773: state = 4774; break; // &nvDa -> &nvDas - case 4777: state = 4778; break; // &nvda -> &nvdas - case 4827: state = 5015; break; // &O -> &Os - case 4833: state = 5018; break; // &o -> &os - case 4834: state = 4839; break; // &oa -> &oas - case 4851: state = 4868; break; // &od -> &ods - case 4852: state = 4853; break; // &oda -> &odas - case 4916: state = 4917; break; // &olcro -> &olcros - case 4917: state = 4918; break; // &olcros -> &olcross - case 4949: state = 4950; break; // &ominu -> &ominus - case 4988: state = 4989; break; // &oplu -> &oplus - case 4991: state = 5008; break; // &or -> &ors - case 5022: state = 5023; break; // &Osla -> &Oslas - case 5026: state = 5027; break; // &osla -> &oslas - case 5042: state = 5043; break; // &Otime -> &Otimes - case 5045: state = 5046; break; // &otime -> &otimes - case 5047: state = 5048; break; // &otimesa -> &otimesas - case 5079: state = 5080; break; // &OverParenthe -> &OverParenthes - case 5081: state = 5082; break; // &OverParenthesi -> &OverParenthesis - case 5083: state = 5338; break; // &p -> &ps - case 5085: state = 5091; break; // &par -> &pars - case 5096: state = 5335; break; // &P -> &Ps - case 5158: state = 5159; break; // &plu -> &plus - case 5159: state = 5182; break; // &plus -> &pluss - case 5173: state = 5174; break; // &Plu -> &Plus - case 5178: state = 5179; break; // &PlusMinu -> &PlusMinus - case 5216: state = 5328; break; // &pr -> &prs - case 5224: state = 5279; break; // &prec -> &precs - case 5242: state = 5243; break; // &Precede -> &Precedes - case 5266: state = 5276; break; // &precn -> &precns - case 5287: state = 5288; break; // &prime -> &primes - case 5289: state = 5293; break; // &prn -> &prns - case 5303: state = 5312; break; // &prof -> &profs - case 5345: state = 5346; break; // &punc -> &puncs - case 5348: state = 5368; break; // &Q -> &Qs - case 5351: state = 5371; break; // &q -> &qs - case 5382: state = 5383; break; // &quaternion -> &quaternions - case 5387: state = 5388; break; // &que -> &ques - case 5397: state = 5934; break; // &r -> &rs - case 5405: state = 5939; break; // &R -> &Rs - case 5439: state = 5454; break; // &rarr -> &rarrs - case 5443: state = 5444; break; // &rarrbf -> &rarrbfs - case 5446: state = 5447; break; // &rarrf -> &rarrfs - case 5474: state = 5475; break; // &rational -> &rationals - case 5496: state = 5498; break; // &rbrk -> &rbrks - case 5526: state = 5538; break; // &rd -> &rds - case 5543: state = 5551; break; // &real -> &reals - case 5559: state = 5560; break; // &Rever -> &Revers - case 5593: state = 5594; break; // &rfi -> &rfis - case 5642: state = 5844; break; // &ri -> &ris - case 5645: state = 5754; break; // &right -> &rights - case 5733: state = 5734; break; // &rightleftarrow -> &rightleftarrows - case 5741: state = 5742; break; // &rightleftharpoon -> &rightleftharpoons - case 5752: state = 5753; break; // &rightrightarrow -> &rightrightarrows - case 5786: state = 5787; break; // &rightthreetime -> &rightthreetimes - case 5850: state = 5851; break; // &risingdot -> &risingdots - case 5864: state = 5865; break; // &rmou -> &rmous - case 5892: state = 5893; break; // &roplu -> &roplus - case 5897: state = 5898; break; // &rotime -> &rotimes - case 5907: state = 5908; break; // &RoundImplie -> &RoundImplies - case 5958: state = 5959; break; // &rtime -> &rtimes - case 5985: state = 6338; break; // &S -> &Ss - case 5991: state = 6341; break; // &s -> &ss - case 6002: state = 6043; break; // &sc -> &scs - case 6030: state = 6034; break; // &scn -> &scns - case 6053: state = 6068; break; // &se -> &ses - case 6076: state = 6077; break; // &setminu -> &setminus - case 6182: state = 6183; break; // &simplu -> &simplus - case 6203: state = 6214; break; // &sma -> &smas - case 6205: state = 6206; break; // &small -> &smalls - case 6212: state = 6213; break; // &smallsetminu -> &smallsetminus - case 6220: state = 6221; break; // &smepar -> &smepars - case 6228: state = 6229; break; // &smte -> &smtes - case 6252: state = 6253; break; // &spade -> &spades - case 6258: state = 6269; break; // &sq -> &sqs - case 6261: state = 6262; break; // &sqcap -> &sqcaps - case 6264: state = 6265; break; // &sqcup -> &sqcups - case 6271: state = 6273; break; // &sqsub -> &sqsubs - case 6278: state = 6280; break; // &sqsup -> &sqsups - case 6297: state = 6298; break; // &SquareInter -> &SquareInters - case 6307: state = 6308; break; // &SquareSub -> &SquareSubs - case 6318: state = 6319; break; // &SquareSuper -> &SquareSupers - case 6370: state = 6371; break; // &straightep -> &straighteps - case 6379: state = 6380; break; // &strn -> &strns - case 6382: state = 6408; break; // &Sub -> &Subs - case 6384: state = 6411; break; // &sub -> &subs - case 6402: state = 6403; break; // &subplu -> &subplus - case 6432: state = 6487; break; // &succ -> &succs - case 6450: state = 6451; break; // &Succeed -> &Succeeds - case 6474: state = 6484; break; // &succn -> &succns - case 6499: state = 6546; break; // &Sup -> &Sups - case 6500: state = 6549; break; // &sup -> &sups - case 6504: state = 6507; break; // &supd -> &supds - case 6516: state = 6517; break; // &Super -> &Supers - case 6525: state = 6526; break; // &suph -> &suphs - case 6544: state = 6545; break; // &supplu -> &supplus - case 6583: state = 6821; break; // &T -> &Ts - case 6586: state = 6824; break; // &t -> &ts - case 6649: state = 6650; break; // &theta -> &thetas - case 6656: state = 6663; break; // &thick -> &thicks - case 6674: state = 6675; break; // &thin -> &thins - case 6683: state = 6686; break; // &thk -> &thks - case 6724: state = 6725; break; // &time -> × - case 6732: state = 6749; break; // &to -> &tos - case 6764: state = 6809; break; // &tri -> &tris - case 6795: state = 6796; break; // &triminu -> &triminus - case 6807: state = 6808; break; // &triplu -> &triplus - case 6873: state = 7186; break; // &U -> &Us - case 6879: state = 7189; break; // &u -> &us - case 6937: state = 6938; break; // &ufi -> &ufis - case 7008: state = 7009; break; // &UnderParenthe -> &UnderParenthes - case 7010: state = 7011; break; // &UnderParenthesi -> &UnderParenthesis - case 7017: state = 7018; break; // &UnionPlu -> &UnionPlus - case 7031: state = 7139; break; // &Up -> &Ups - case 7042: state = 7141; break; // &up -> &ups - case 7115: state = 7116; break; // &uplu -> &uplus - case 7164: state = 7165; break; // &upuparrow -> &upuparrows - case 7223: state = 7424; break; // &v -> &vs - case 7229: state = 7264; break; // &var -> &vars - case 7231: state = 7232; break; // &varep -> &vareps - case 7270: state = 7271; break; // &varsub -> &varsubs - case 7278: state = 7279; break; // &varsup -> &varsups - case 7307: state = 7421; break; // &V -> &Vs - case 7320: state = 7321; break; // &VDa -> &VDas - case 7324: state = 7325; break; // &Vda -> &Vdas - case 7328: state = 7329; break; // &vDa -> &vDas - case 7332: state = 7333; break; // &vda -> &vdas - case 7402: state = 7403; break; // &vn -> &vns - case 7438: state = 7439; break; // &Vvda -> &Vvdas - case 7447: state = 7489; break; // &W -> &Ws - case 7452: state = 7492; break; // &w -> &ws - case 7495: state = 7561; break; // &x -> &xs - case 7508: state = 7558; break; // &X -> &Xs - case 7533: state = 7534; break; // &xni -> &xnis - case 7545: state = 7546; break; // &xoplu -> &xoplus - case 7571: state = 7572; break; // &xuplu -> &xuplus - case 7584: state = 7628; break; // &Y -> &Ys - case 7590: state = 7631; break; // &y -> &ys - case 7645: state = 7719; break; // &Z -> &Zs - case 7651: state = 7722; break; // &z -> &zs - default: return false; - } - break; - case 't': - switch (state) { - case 0: state = 6586; break; // & -> &t - case 1: state = 196; break; // &A -> &At - case 4: state = 5; break; // &Aacu -> &Aacut - case 7: state = 201; break; // &a -> &at - case 10: state = 11; break; // &aacu -> &aacut - case 33: state = 34; break; // &acu -> &acut - case 118: state = 119; break; // &angr -> &angrt - case 123: state = 126; break; // &angs -> &angst - case 161: state = 162; break; // &ApplyFunc -> &ApplyFunct - case 183: state = 190; break; // &as -> &ast - case 217: state = 218; break; // &awconin -> &awconint - case 220: state = 221; break; // &awin -> &awint - case 272: state = 273; break; // &bbrk -> &bbrkt - case 288: state = 322; break; // &be -> &bet - case 293: state = 320; break; // &Be -> &Bet - case 301: state = 302; break; // &bemp -> &bempt - case 334: state = 364; break; // &big -> &bigt - case 343: state = 351; break; // &bigo -> &bigot - case 345: state = 346; break; // &bigodo -> &bigodot - case 356: state = 361; break; // &bigs -> &bigst - case 399: state = 413; break; // &black -> &blackt - case 427: state = 428; break; // &blacktrianglelef -> &blacktriangleleft - case 432: state = 433; break; // &blacktrianglerigh -> &blacktriangleright - case 452: state = 453; break; // &bNo -> &bNot - case 454: state = 455; break; // &bno -> &bnot - case 459: state = 462; break; // &bo -> &bot - case 462: state = 463; break; // &bot -> &bott - case 466: state = 467; break; // &bow -> &bowt - case 470: state = 503; break; // &box -> &boxt - case 571: state = 572; break; // &bulle -> &bullet - case 586: state = 587; break; // &Cacu -> &Cacut - case 589: state = 983; break; // &c -> &ct - case 592: state = 593; break; // &cacu -> &cacut - case 611: state = 612; break; // &capdo -> &capdot - case 613: state = 614; break; // &Capi -> &Capit - case 624: state = 625; break; // &CapitalDifferen -> &CapitalDifferent - case 632: state = 633; break; // &care -> &caret - case 670: state = 671; break; // &Cconin -> &Cconint - case 678: state = 679; break; // &Cdo -> &Cdot - case 681: state = 682; break; // &cdo -> &cdot - case 694: state = 695; break; // &cemp -> &cempt - case 698: state = 699; break; // &cen -> ¢ - case 700: state = 701; break; // &Cen -> &Cent - case 705: state = 706; break; // &CenterDo -> &CenterDot - case 710: state = 711; break; // ¢erdo -> ¢erdot - case 746: state = 747; break; // &circlearrowlef -> &circlearrowleft - case 751: state = 752; break; // &circlearrowrigh -> &circlearrowright - case 755: state = 756; break; // &circledas -> &circledast - case 771: state = 772; break; // &CircleDo -> &CircleDot - case 794: state = 795; break; // &cirfnin -> &cirfnint - case 813: state = 814; break; // &ClockwiseCon -> &ClockwiseCont - case 819: state = 820; break; // &ClockwiseContourIn -> &ClockwiseContourInt - case 841: state = 842; break; // &CloseCurlyDoubleQuo -> &CloseCurlyDoubleQuot - case 846: state = 847; break; // &CloseCurlyQuo -> &CloseCurlyQuot - case 854: state = 855; break; // &clubsui -> &clubsuit - case 869: state = 870; break; // &comma -> &commat - case 878: state = 879; break; // &complemen -> &complement - case 886: state = 887; break; // &congdo -> &congdot - case 888: state = 901; break; // &Con -> &Cont - case 893: state = 894; break; // &Congruen -> &Congruent - case 896: state = 897; break; // &Conin -> &Conint - case 899: state = 900; break; // &conin -> &conint - case 906: state = 907; break; // &ContourIn -> &ContourInt - case 924: state = 925; break; // &Coproduc -> &Coproduct - case 933: state = 934; break; // &Coun -> &Count - case 948: state = 949; break; // &CounterClockwiseCon -> &CounterClockwiseCont - case 954: state = 955; break; // &CounterClockwiseContourIn -> &CounterClockwiseContourInt - case 985: state = 986; break; // &ctdo -> &ctdot - case 1021: state = 1022; break; // &cupdo -> &cupdot - case 1063: state = 1064; break; // &curvearrowlef -> &curvearrowleft - case 1068: state = 1069; break; // &curvearrowrigh -> &curvearrowright - case 1081: state = 1082; break; // &cwconin -> &cwconint - case 1084: state = 1085; break; // &cwin -> &cwint - case 1088: state = 1089; break; // &cylc -> &cylct - case 1097: state = 1624; break; // &d -> &dt - case 1104: state = 1105; break; // &dale -> &dalet - case 1150: state = 1151; break; // &DDo -> &DDot - case 1156: state = 1157; break; // &ddo -> &ddot - case 1164: state = 1165; break; // &Del -> &Delt - case 1167: state = 1168; break; // &del -> &delt - case 1171: state = 1172; break; // &demp -> &dempt - case 1178: state = 1179; break; // &dfish -> &dfisht - case 1195: state = 1196; break; // &Diacri -> &Diacrit - case 1203: state = 1204; break; // &DiacriticalAcu -> &DiacriticalAcut - case 1207: state = 1208; break; // &DiacriticalDo -> &DiacriticalDot - case 1215: state = 1216; break; // &DiacriticalDoubleAcu -> &DiacriticalDoubleAcut - case 1240: state = 1241; break; // &diamondsui -> &diamondsuit - case 1249: state = 1250; break; // &Differen -> &Different - case 1268: state = 1269; break; // ÷on -> ÷ont - case 1291: state = 1302; break; // &do -> &dot - case 1296: state = 1301; break; // &Do -> &Dot - case 1304: state = 1305; break; // &DotDo -> &DotDot - case 1309: state = 1310; break; // &doteqdo -> &doteqdot - case 1349: state = 1350; break; // &DoubleCon -> &DoubleCont - case 1355: state = 1356; break; // &DoubleContourIn -> &DoubleContourInt - case 1363: state = 1364; break; // &DoubleDo -> &DoubleDot - case 1374: state = 1375; break; // &DoubleLef -> &DoubleLeft - case 1384: state = 1385; break; // &DoubleLeftRigh -> &DoubleLeftRight - case 1399: state = 1400; break; // &DoubleLongLef -> &DoubleLongLeft - case 1409: state = 1410; break; // &DoubleLongLeftRigh -> &DoubleLongLeftRight - case 1419: state = 1420; break; // &DoubleLongRigh -> &DoubleLongRight - case 1429: state = 1430; break; // &DoubleRigh -> &DoubleRight - case 1457: state = 1458; break; // &DoubleVer -> &DoubleVert - case 1519: state = 1520; break; // &downharpoonlef -> &downharpoonleft - case 1524: state = 1525; break; // &downharpoonrigh -> &downharpoonright - case 1528: state = 1529; break; // &DownLef -> &DownLeft - case 1533: state = 1534; break; // &DownLeftRigh -> &DownLeftRight - case 1537: state = 1538; break; // &DownLeftRightVec -> &DownLeftRightVect - case 1546: state = 1547; break; // &DownLeftTeeVec -> &DownLeftTeeVect - case 1552: state = 1553; break; // &DownLeftVec -> &DownLeftVect - case 1562: state = 1563; break; // &DownRigh -> &DownRight - case 1569: state = 1570; break; // &DownRightTeeVec -> &DownRightTeeVect - case 1575: state = 1576; break; // &DownRightVec -> &DownRightVect - case 1604: state = 1616; break; // &Ds -> &Dst - case 1607: state = 1620; break; // &ds -> &dst - case 1626: state = 1627; break; // &dtdo -> &dtdot - case 1656: state = 1910; break; // &E -> &Et - case 1659: state = 1660; break; // &Eacu -> &Eacut - case 1662: state = 1912; break; // &e -> &et - case 1665: state = 1666; break; // &eacu -> &eacut - case 1668: state = 1669; break; // &eas -> &east - case 1696: state = 1697; break; // &eDDo -> &eDDot - case 1699: state = 1700; break; // &Edo -> &Edot - case 1701: state = 1702; break; // &eDo -> &eDot - case 1704: state = 1705; break; // &edo -> &edot - case 1709: state = 1710; break; // &efDo -> &efDot - case 1726: state = 1727; break; // &egsdo -> &egsdot - case 1733: state = 1734; break; // &Elemen -> &Element - case 1736: state = 1737; break; // &elin -> &elint - case 1744: state = 1745; break; // &elsdo -> &elsdot - case 1754: state = 1755; break; // &emp -> &empt - case 1758: state = 1759; break; // &emptyse -> &emptyset - case 1760: state = 1761; break; // &Emp -> &Empt - case 1847: state = 1848; break; // &eqslan -> &eqslant - case 1849: state = 1850; break; // &eqslantg -> &eqslantgt - case 1870: state = 1871; break; // &eques -> &equest - case 1895: state = 1896; break; // &erDo -> &erDot - case 1904: state = 1905; break; // &esdo -> &esdot - case 1929: state = 1930; break; // &exis -> &exist - case 1933: state = 1934; break; // &Exis -> &Exist - case 1938: state = 1939; break; // &expec -> &expect - case 1940: state = 1941; break; // &expecta -> &expectat - case 1949: state = 1950; break; // &Exponen -> &Exponent - case 1958: state = 1959; break; // &exponen -> &exponent - case 1972: state = 1973; break; // &fallingdo -> &fallingdot - case 2040: state = 2046; break; // &fl -> &flt - case 2041: state = 2042; break; // &fla -> &flat - case 2072: state = 2073; break; // &Fourier -> &Fouriert - case 2078: state = 2079; break; // &fpar -> &fpart - case 2081: state = 2082; break; // &fpartin -> &fpartint - case 2118: state = 2294; break; // &g -> > - case 2121: state = 2122; break; // &gacu -> &gacut - case 2124: state = 2293; break; // &G -> &Gt - case 2160: state = 2161; break; // &Gdo -> &Gdot - case 2163: state = 2164; break; // &gdo -> &gdot - case 2174: state = 2175; break; // &geqslan -> &geqslant - case 2180: state = 2181; break; // &gesdo -> &gesdot - case 2234: state = 2235; break; // &Grea -> &Great - case 2259: state = 2260; break; // &GreaterGrea -> &GreaterGreat - case 2270: state = 2271; break; // &GreaterSlan -> &GreaterSlant - case 2300: state = 2301; break; // >do -> >dot - case 2309: state = 2310; break; // >ques -> >quest - case 2321: state = 2322; break; // >rdo -> >rdot - case 2343: state = 2344; break; // &gver -> &gvert - case 2352: state = 2385; break; // &Ha -> &Hat - case 2366: state = 2367; break; // &hamil -> &hamilt - case 2399: state = 2400; break; // &hear -> &heart - case 2403: state = 2404; break; // &heartsui -> &heartsuit - case 2421: state = 2422; break; // &Hilber -> &Hilbert - case 2444: state = 2445; break; // &hom -> &homt - case 2446: state = 2447; break; // &homth -> &homtht - case 2452: state = 2453; break; // &hooklef -> &hookleft - case 2462: state = 2463; break; // &hookrigh -> &hookright - case 2482: state = 2483; break; // &Horizon -> &Horizont - case 2490: state = 2500; break; // &Hs -> &Hst - case 2493: state = 2504; break; // &hs -> &hst - case 2533: state = 2756; break; // &I -> &It - case 2536: state = 2537; break; // &Iacu -> &Iacut - case 2539: state = 2755; break; // &i -> &it - case 2542: state = 2543; break; // &iacu -> &iacut - case 2556: state = 2557; break; // &Ido -> &Idot - case 2585: state = 2586; break; // &iiiin -> &iiiint - case 2587: state = 2588; break; // &iiin -> &iiint - case 2593: state = 2594; break; // &iio -> &iiot - case 2609: state = 2629; break; // &ima -> &imat - case 2627: state = 2628; break; // &imagpar -> &imagpart - case 2641: state = 2658; break; // &in -> &int - case 2648: state = 2649; break; // &infin -> &infint - case 2654: state = 2655; break; // &inodo -> &inodot - case 2656: state = 2657; break; // &In -> &Int - case 2679: state = 2680; break; // &Intersec -> &Intersect - case 2713: state = 2729; break; // &io -> &iot - case 2716: state = 2727; break; // &Io -> &Iot - case 2738: state = 2739; break; // &iques -> ¿ - case 2749: state = 2750; break; // &isindo -> &isindot - case 2794: state = 2795; break; // &jma -> &jmat - case 2881: state = 3692; break; // &l -> < - case 2882: state = 2957; break; // &lA -> &lAt - case 2886: state = 3691; break; // &L -> &Lt - case 2889: state = 2890; break; // &Lacu -> &Lacut - case 2892: state = 2956; break; // &la -> &lat - case 2894: state = 2895; break; // &lacu -> &lacut - case 2899: state = 2900; break; // &laemp -> &laempt - case 2927: state = 2928; break; // &Laplace -> &Laplacet - case 2939: state = 2954; break; // &larr -> &larrt - case 3034: state = 3035; break; // &Lef -> &Left - case 3046: state = 3047; break; // &LeftAngleBracke -> &LeftAngleBracket - case 3057: state = 3058; break; // &lef -> &left - case 3058: state = 3218; break; // &left -> &leftt - case 3063: state = 3077; break; // &leftarrow -> &leftarrowt - case 3070: state = 3071; break; // &LeftArrowRigh -> &LeftArrowRight - case 3099: state = 3100; break; // &LeftDoubleBracke -> &LeftDoubleBracket - case 3108: state = 3109; break; // &LeftDownTeeVec -> &LeftDownTeeVect - case 3114: state = 3115; break; // &LeftDownVec -> &LeftDownVect - case 3141: state = 3142; break; // &leftlef -> &leftleft - case 3152: state = 3153; break; // &LeftRigh -> &LeftRight - case 3162: state = 3163; break; // &Leftrigh -> &Leftright - case 3172: state = 3173; break; // &leftrigh -> &leftright - case 3200: state = 3201; break; // &LeftRightVec -> &LeftRightVect - case 3214: state = 3215; break; // &LeftTeeVec -> &LeftTeeVect - case 3222: state = 3223; break; // &leftthree -> &leftthreet - case 3251: state = 3252; break; // &LeftUpDownVec -> &LeftUpDownVect - case 3260: state = 3261; break; // &LeftUpTeeVec -> &LeftUpTeeVect - case 3266: state = 3267; break; // &LeftUpVec -> &LeftUpVect - case 3275: state = 3276; break; // &LeftVec -> &LeftVect - case 3289: state = 3290; break; // &leqslan -> &leqslant - case 3295: state = 3296; break; // &lesdo -> &lesdot - case 3310: state = 3311; break; // &lessdo -> &lessdot - case 3314: state = 3315; break; // &lesseqg -> &lesseqgt - case 3318: state = 3319; break; // &lesseqqg -> &lesseqqgt - case 3331: state = 3332; break; // &LessEqualGrea -> &LessEqualGreat - case 3347: state = 3348; break; // &LessGrea -> &LessGreat - case 3351: state = 3352; break; // &lessg -> &lessgt - case 3364: state = 3365; break; // &LessSlan -> &LessSlant - case 3379: state = 3380; break; // &lfish -> &lfisht - case 3409: state = 3431; break; // &ll -> &llt - case 3420: state = 3421; break; // &Llef -> &Lleft - case 3437: state = 3438; break; // &Lmido -> &Lmidot - case 3442: state = 3443; break; // &lmido -> &lmidot - case 3446: state = 3447; break; // &lmous -> &lmoust - case 3466: state = 3598; break; // &lo -> &lot - case 3480: state = 3481; break; // &LongLef -> &LongLeft - case 3489: state = 3490; break; // &Longlef -> &Longleft - case 3500: state = 3501; break; // &longlef -> &longleft - case 3510: state = 3511; break; // &LongLeftRigh -> &LongLeftRight - case 3520: state = 3521; break; // &Longleftrigh -> &Longleftright - case 3530: state = 3531; break; // &longleftrigh -> &longleftright - case 3540: state = 3541; break; // &longmaps -> &longmapst - case 3546: state = 3547; break; // &LongRigh -> &LongRight - case 3556: state = 3557; break; // &Longrigh -> &Longright - case 3566: state = 3567; break; // &longrigh -> &longright - case 3582: state = 3583; break; // &looparrowlef -> &looparrowleft - case 3587: state = 3588; break; // &looparrowrigh -> &looparrowright - case 3605: state = 3606; break; // &lowas -> &lowast - case 3615: state = 3616; break; // &LowerLef -> &LowerLeft - case 3625: state = 3626; break; // &LowerRigh -> &LowerRight - case 3641: state = 3642; break; // &lparl -> &lparlt - case 3643: state = 3658; break; // &lr -> &lrt - case 3661: state = 3686; break; // &ls -> &lst - case 3666: state = 3682; break; // &Ls -> &Lst - case 3698: state = 3699; break; // <do -> <dot - case 3715: state = 3716; break; // <ques -> <quest - case 3737: state = 3738; break; // &lver -> &lvert - case 3749: state = 3751; break; // &mal -> &malt - case 3759: state = 3760; break; // &maps -> &mapst - case 3768: state = 3769; break; // &mapstolef -> &mapstoleft - case 3790: state = 3791; break; // &mDDo -> &mDDot - case 3817: state = 3818; break; // &Mellin -> &Mellint - case 3833: state = 3834; break; // &midas -> &midast - case 3839: state = 3840; break; // &middo -> · - case 3879: state = 3882; break; // &ms -> &mst - case 3888: state = 3889; break; // &mul -> &mult - case 3897: state = 4718; break; // &n -> &nt - case 3898: state = 3924; break; // &na -> &nat - case 3902: state = 4721; break; // &N -> &Nt - case 3905: state = 3906; break; // &Nacu -> &Nacut - case 3909: state = 3910; break; // &nacu -> &nacut - case 3960: state = 3961; break; // &ncongdo -> &ncongdot - case 3982: state = 3983; break; // &nedo -> &nedot - case 3986: state = 3987; break; // &Nega -> &Negat - case 4041: state = 4042; break; // &Nes -> &Nest - case 4048: state = 4049; break; // &NestedGrea -> &NestedGreat - case 4055: state = 4056; break; // &NestedGreaterGrea -> &NestedGreaterGreat - case 4074: state = 4075; break; // &nexis -> &nexist - case 4081: state = 4098; break; // &ng -> &ngt - case 4089: state = 4090; break; // &ngeqslan -> &ngeqslant - case 4092: state = 4097; break; // &nG -> &nGt - case 4121: state = 4182; break; // &nl -> &nlt - case 4132: state = 4181; break; // &nL -> &nLt - case 4134: state = 4135; break; // &nLef -> &nLeft - case 4141: state = 4142; break; // &nlef -> &nleft - case 4151: state = 4152; break; // &nLeftrigh -> &nLeftright - case 4161: state = 4162; break; // &nleftrigh -> &nleftright - case 4173: state = 4174; break; // &nleqslan -> &nleqslant - case 4190: state = 4215; break; // &No -> &Not - case 4212: state = 4216; break; // &no -> ¬ - case 4224: state = 4225; break; // &NotCongruen -> &NotCongruent - case 4239: state = 4240; break; // &NotDoubleVer -> &NotDoubleVert - case 4253: state = 4254; break; // &NotElemen -> &NotElement - case 4266: state = 4267; break; // &NotExis -> &NotExist - case 4272: state = 4273; break; // &NotGrea -> &NotGreat - case 4293: state = 4294; break; // &NotGreaterGrea -> &NotGreaterGreat - case 4304: state = 4305; break; // &NotGreaterSlan -> &NotGreaterSlant - case 4336: state = 4337; break; // ¬indo -> ¬indot - case 4345: state = 4346; break; // &NotLef -> &NotLeft - case 4373: state = 4374; break; // &NotLessGrea -> &NotLessGreat - case 4384: state = 4385; break; // &NotLessSlan -> &NotLessSlant - case 4398: state = 4399; break; // &NotNes -> &NotNest - case 4405: state = 4406; break; // &NotNestedGrea -> &NotNestedGreat - case 4412: state = 4413; break; // &NotNestedGreaterGrea -> &NotNestedGreaterGreat - case 4446: state = 4447; break; // &NotPrecedesSlan -> &NotPrecedesSlant - case 4465: state = 4466; break; // &NotReverseElemen -> &NotReverseElement - case 4469: state = 4470; break; // &NotRigh -> &NotRight - case 4497: state = 4498; break; // &NotSquareSubse -> &NotSquareSubset - case 4508: state = 4509; break; // &NotSquareSuperse -> &NotSquareSuperset - case 4518: state = 4519; break; // &NotSubse -> &NotSubset - case 4539: state = 4540; break; // &NotSucceedsSlan -> &NotSucceedsSlant - case 4555: state = 4556; break; // &NotSuperse -> &NotSuperset - case 4588: state = 4589; break; // &NotVer -> &NotVert - case 4599: state = 4607; break; // &npar -> &npart - case 4611: state = 4612; break; // &npolin -> &npolint - case 4621: state = 4649; break; // &nr -> &nrt - case 4633: state = 4634; break; // &nRigh -> &nRight - case 4642: state = 4643; break; // &nrigh -> &nright - case 4665: state = 4666; break; // &nshor -> &nshort - case 4700: state = 4701; break; // &nsubse -> &nsubset - case 4713: state = 4714; break; // &nsupse -> &nsupset - case 4741: state = 4742; break; // &ntrianglelef -> &ntriangleleft - case 4748: state = 4749; break; // &ntrianglerigh -> &ntriangleright - case 4780: state = 4782; break; // &nvg -> &nvgt - case 4792: state = 4797; break; // &nvl -> &nvlt - case 4801: state = 4805; break; // &nvr -> &nvrt - case 4827: state = 5031; break; // &O -> &Ot - case 4830: state = 4831; break; // &Oacu -> &Oacut - case 4833: state = 5036; break; // &o -> &ot - case 4836: state = 4837; break; // &oacu -> &oacut - case 4839: state = 4840; break; // &oas -> &oast - case 4866: state = 4867; break; // &odo -> &odot - case 4887: state = 4899; break; // &og -> &ogt - case 4906: state = 4907; break; // &oin -> &oint - case 4908: state = 4922; break; // &ol -> &olt - case 4976: state = 4977; break; // &OpenCurlyDoubleQuo -> &OpenCurlyDoubleQuot - case 4981: state = 4982; break; // &OpenCurlyQuo -> &OpenCurlyQuot - case 5070: state = 5071; break; // &OverBracke -> &OverBracket - case 5076: state = 5077; break; // &OverParen -> &OverParent - case 5085: state = 5095; break; // &par -> &part - case 5098: state = 5099; break; // &Par -> &Part - case 5109: state = 5120; break; // &per -> &pert - case 5111: state = 5112; break; // &percn -> &percnt - case 5135: state = 5136; break; // &phmma -> &phmmat - case 5141: state = 5142; break; // &pi -> &pit - case 5159: state = 5185; break; // &plus -> &plust - case 5203: state = 5204; break; // &poin -> &point - case 5206: state = 5207; break; // &pointin -> &pointint - case 5252: state = 5253; break; // &PrecedesSlan -> &PrecedesSlant - case 5301: state = 5302; break; // &Produc -> &Product - case 5316: state = 5326; break; // &prop -> &propt - case 5319: state = 5320; break; // &Propor -> &Proport - case 5355: state = 5356; break; // &qin -> &qint - case 5375: state = 5376; break; // &qua -> &quat - case 5385: state = 5386; break; // &quatin -> &quatint - case 5388: state = 5389; break; // &ques -> &quest - case 5395: state = 5396; break; // &quo -> " - case 5397: state = 5951; break; // &r -> &rt - case 5398: state = 5462; break; // &rA -> &rAt - case 5402: state = 5466; break; // &ra -> &rat - case 5408: state = 5409; break; // &Racu -> &Racut - case 5411: state = 5412; break; // &racu -> &racut - case 5419: state = 5420; break; // &raemp -> &raempt - case 5435: state = 5457; break; // &Rarr -> &Rarrt - case 5439: state = 5459; break; // &rarr -> &rarrt - case 5549: state = 5550; break; // &realpar -> &realpart - case 5552: state = 5553; break; // &rec -> &rect - case 5567: state = 5568; break; // &ReverseElemen -> &ReverseElement - case 5595: state = 5596; break; // &rfish -> &rfisht - case 5619: state = 5620; break; // &Righ -> &Right - case 5631: state = 5632; break; // &RightAngleBracke -> &RightAngleBracket - case 5644: state = 5645; break; // &righ -> &right - case 5645: state = 5778; break; // &right -> &rightt - case 5650: state = 5663; break; // &rightarrow -> &rightarrowt - case 5656: state = 5657; break; // &RightArrowLef -> &RightArrowLeft - case 5685: state = 5686; break; // &RightDoubleBracke -> &RightDoubleBracket - case 5694: state = 5695; break; // &RightDownTeeVec -> &RightDownTeeVect - case 5700: state = 5701; break; // &RightDownVec -> &RightDownVect - case 5727: state = 5728; break; // &rightlef -> &rightleft - case 5746: state = 5747; break; // &rightrigh -> &rightright - case 5774: state = 5775; break; // &RightTeeVec -> &RightTeeVect - case 5782: state = 5783; break; // &rightthree -> &rightthreet - case 5811: state = 5812; break; // &RightUpDownVec -> &RightUpDownVect - case 5820: state = 5821; break; // &RightUpTeeVec -> &RightUpTeeVect - case 5826: state = 5827; break; // &RightUpVec -> &RightUpVect - case 5835: state = 5836; break; // &RightVec -> &RightVect - case 5849: state = 5850; break; // &risingdo -> &risingdot - case 5865: state = 5866; break; // &rmous -> &rmoust - case 5875: state = 5894; break; // &ro -> &rot - case 5912: state = 5913; break; // &rparg -> &rpargt - case 5918: state = 5919; break; // &rppolin -> &rppolint - case 5927: state = 5928; break; // &Rrigh -> &Rright - case 5964: state = 5965; break; // &rtril -> &rtrilt - case 5985: state = 6356; break; // &S -> &St - case 5988: state = 5989; break; // &Sacu -> &Sacut - case 5991: state = 6359; break; // &s -> &st - case 5994: state = 5995; break; // &sacu -> &sacut - case 6041: state = 6042; break; // &scpolin -> &scpolint - case 6049: state = 6050; break; // &sdo -> &sdot - case 6053: state = 6072; break; // &se -> &set - case 6064: state = 6065; break; // &sec -> § - case 6079: state = 6080; break; // &sex -> &sext - case 6106: state = 6107; break; // &Shor -> &Short - case 6119: state = 6120; break; // &ShortLef -> &ShortLeft - case 6127: state = 6128; break; // &shor -> &short - case 6143: state = 6144; break; // &ShortRigh -> &ShortRight - case 6170: state = 6171; break; // &simdo -> &simdot - case 6202: state = 6227; break; // &sm -> &smt - case 6207: state = 6208; break; // &smallse -> &smallset - case 6236: state = 6237; break; // &sof -> &soft - case 6255: state = 6256; break; // &spadesui -> &spadesuit - case 6267: state = 6268; break; // &Sqr -> &Sqrt - case 6274: state = 6275; break; // &sqsubse -> &sqsubset - case 6281: state = 6282; break; // &sqsupse -> &sqsupset - case 6294: state = 6295; break; // &SquareIn -> &SquareInt - case 6300: state = 6301; break; // &SquareIntersec -> &SquareIntersect - case 6309: state = 6310; break; // &SquareSubse -> &SquareSubset - case 6320: state = 6321; break; // &SquareSuperse -> &SquareSuperset - case 6341: state = 6352; break; // &ss -> &sst - case 6344: state = 6345; break; // &sse -> &sset - case 6367: state = 6368; break; // &straigh -> &straight - case 6386: state = 6387; break; // &subdo -> &subdot - case 6391: state = 6392; break; // &subedo -> &subedot - case 6395: state = 6396; break; // &submul -> &submult - case 6409: state = 6410; break; // &Subse -> &Subset - case 6412: state = 6413; break; // &subse -> &subset - case 6460: state = 6461; break; // &SucceedsSlan -> &SucceedsSlant - case 6493: state = 6494; break; // &SuchTha -> &SuchThat - case 6505: state = 6506; break; // &supdo -> &supdot - case 6513: state = 6514; break; // &supedo -> &supedot - case 6518: state = 6519; break; // &Superse -> &Superset - case 6537: state = 6538; break; // &supmul -> &supmult - case 6547: state = 6548; break; // &Supse -> &Supset - case 6550: state = 6551; break; // &supse -> &supset - case 6590: state = 6591; break; // &targe -> &target - case 6618: state = 6619; break; // &tdo -> &tdot - case 6630: state = 6648; break; // &the -> &thet - case 6635: state = 6646; break; // &The -> &Thet - case 6730: state = 6731; break; // &tin -> &tint - case 6737: state = 6738; break; // &topbo -> &topbot - case 6764: state = 6811; break; // &tri -> &trit - case 6776: state = 6777; break; // &trianglelef -> &triangleleft - case 6784: state = 6785; break; // &trianglerigh -> &triangleright - case 6789: state = 6790; break; // &trido -> &tridot - case 6803: state = 6804; break; // &TripleDo -> &TripleDot - case 6821: state = 6837; break; // &Ts -> &Tst - case 6824: state = 6841; break; // &ts -> &tst - case 6847: state = 6848; break; // &twix -> &twixt - case 6856: state = 6857; break; // &twoheadlef -> &twoheadleft - case 6866: state = 6867; break; // &twoheadrigh -> &twoheadright - case 6873: state = 7196; break; // &U -> &Ut - case 6876: state = 6877; break; // &Uacu -> &Uacut - case 6879: state = 7192; break; // &u -> &ut - case 6882: state = 6883; break; // &uacu -> &uacut - case 6939: state = 6940; break; // &ufish -> &ufisht - case 6965: state = 6975; break; // &ul -> &ult - case 6999: state = 7000; break; // &UnderBracke -> &UnderBracket - case 7005: state = 7006; break; // &UnderParen -> &UnderParent - case 7107: state = 7108; break; // &upharpoonlef -> &upharpoonleft - case 7112: state = 7113; break; // &upharpoonrigh -> &upharpoonright - case 7122: state = 7123; break; // &UpperLef -> &UpperLeft - case 7132: state = 7133; break; // &UpperRigh -> &UpperRight - case 7166: state = 7183; break; // &ur -> &urt - case 7194: state = 7195; break; // &utdo -> &utdot - case 7227: state = 7228; break; // &vangr -> &vangrt - case 7229: state = 7286; break; // &var -> &vart - case 7243: state = 7244; break; // &varno -> &varnot - case 7255: state = 7256; break; // &varprop -> &varpropt - case 7272: state = 7273; break; // &varsubse -> &varsubset - case 7280: state = 7281; break; // &varsupse -> &varsupset - case 7288: state = 7289; break; // &varthe -> &varthet - case 7300: state = 7301; break; // &vartrianglelef -> &vartriangleleft - case 7305: state = 7306; break; // &vartrianglerigh -> &vartriangleright - case 7349: state = 7357; break; // &Ver -> &Vert - case 7353: state = 7358; break; // &ver -> &vert - case 7375: state = 7376; break; // &VerticalSepara -> &VerticalSeparat - case 7398: state = 7399; break; // &vl -> &vlt - case 7417: state = 7418; break; // &vr -> &vrt - case 7486: state = 7487; break; // &wrea -> &wreat - case 7504: state = 7505; break; // &xd -> &xdt - case 7535: state = 7547; break; // &xo -> &xot - case 7537: state = 7538; break; // &xodo -> &xodot - case 7568: state = 7573; break; // &xu -> &xut - case 7587: state = 7588; break; // &Yacu -> &Yacut - case 7593: state = 7594; break; // &yacu -> &yacut - case 7648: state = 7649; break; // &Zacu -> &Zacut - case 7654: state = 7655; break; // &zacu -> &zacut - case 7670: state = 7671; break; // &Zdo -> &Zdot - case 7673: state = 7674; break; // &zdo -> &zdot - case 7675: state = 7695; break; // &ze -> &zet - case 7676: state = 7677; break; // &zee -> &zeet - case 7680: state = 7693; break; // &Ze -> &Zet - case 7685: state = 7686; break; // &ZeroWid -> &ZeroWidt - default: return false; - } - break; - case 'u': - switch (state) { - case 0: state = 6879; break; // & -> &u - case 1: state = 206; break; // &A -> &Au - case 3: state = 4; break; // &Aac -> &Aacu - case 7: state = 209; break; // &a -> &au - case 9: state = 10; break; // &aac -> &aacu - case 23: state = 33; break; // &ac -> &acu - case 158: state = 159; break; // &ApplyF -> &ApplyFu - case 222: state = 568; break; // &b -> &bu - case 247: state = 577; break; // &B -> &Bu - case 285: state = 286; break; // &bdq -> &bdqu - case 290: state = 291; break; // &beca -> &becau - case 295: state = 296; break; // &Beca -> &Becau - case 310: state = 311; break; // &berno -> &bernou - case 314: state = 315; break; // &Berno -> &Bernou - case 334: state = 378; break; // &big -> &bigu - case 335: state = 341; break; // &bigc -> &bigcu - case 348: state = 349; break; // &bigopl -> &bigoplu - case 358: state = 359; break; // &bigsqc -> &bigsqcu - case 371: state = 376; break; // &bigtriangle -> &bigtriangleu - case 380: state = 381; break; // &bigupl -> &biguplu - case 408: state = 409; break; // &blacksq -> &blacksqu - case 447: state = 448; break; // &bneq -> &bnequ - case 470: state = 511; break; // &box -> &boxu - case 484: state = 491; break; // &boxH -> &boxHu - case 485: state = 493; break; // &boxh -> &boxhu - case 496: state = 497; break; // &boxmin -> &boxminu - case 500: state = 501; break; // &boxpl -> &boxplu - case 565: state = 566; break; // &bsolhs -> &bsolhsu - case 583: state = 1004; break; // &C -> &Cu - case 585: state = 586; break; // &Cac -> &Cacu - case 589: state = 987; break; // &c -> &cu - case 591: state = 592; break; // &cac -> &cacu - case 602: state = 603; break; // &capbrc -> &capbrcu - case 605: state = 608; break; // &capc -> &capcu - case 641: state = 672; break; // &cc -> &ccu - case 777: state = 778; break; // &CircleMin -> &CircleMinu - case 781: state = 782; break; // &CirclePl -> &CirclePlu - case 815: state = 816; break; // &ClockwiseConto -> &ClockwiseContou - case 828: state = 829; break; // &CloseC -> &CloseCu - case 834: state = 835; break; // &CloseCurlyDo -> &CloseCurlyDou - case 839: state = 840; break; // &CloseCurlyDoubleQ -> &CloseCurlyDoubleQu - case 844: state = 845; break; // &CloseCurlyQ -> &CloseCurlyQu - case 849: state = 850; break; // &cl -> &clu - case 852: state = 853; break; // &clubs -> &clubsu - case 856: state = 932; break; // &Co -> &Cou - case 890: state = 891; break; // &Congr -> &Congru - case 902: state = 903; break; // &Conto -> &Contou - case 922: state = 923; break; // &Coprod -> &Coprodu - case 950: state = 951; break; // &CounterClockwiseConto -> &CounterClockwiseContou - case 975: state = 978; break; // &cs -> &csu - case 1015: state = 1018; break; // &cupc -> &cupcu - case 1039: state = 1040; break; // &curlyeqs -> &curlyeqsu - case 1097: state = 1631; break; // &d -> &du - case 1202: state = 1203; break; // &DiacriticalAc -> &DiacriticalAcu - case 1207: state = 1209; break; // &DiacriticalDo -> &DiacriticalDou - case 1214: state = 1215; break; // &DiacriticalDoubleAc -> &DiacriticalDoubleAcu - case 1238: state = 1239; break; // &diamonds -> &diamondsu - case 1291: state = 1331; break; // &do -> &dou - case 1296: state = 1343; break; // &Do -> &Dou - case 1312: state = 1313; break; // &DotEq -> &DotEqu - case 1318: state = 1319; break; // &dotmin -> &dotminu - case 1322: state = 1323; break; // &dotpl -> &dotplu - case 1326: state = 1327; break; // &dotsq -> &dotsqu - case 1351: state = 1352; break; // &DoubleConto -> &DoubleContou - case 1656: state = 1917; break; // &E -> &Eu - case 1658: state = 1659; break; // &Eac -> &Eacu - case 1662: state = 1920; break; // &e -> &eu - case 1664: state = 1665; break; // &eac -> &eacu - case 1769: state = 1770; break; // &EmptySmallSq -> &EmptySmallSqu - case 1785: state = 1786; break; // &EmptyVerySmallSq -> &EmptyVerySmallSqu - case 1818: state = 1819; break; // &epl -> &eplu - case 1833: state = 1860; break; // &eq -> &equ - case 1856: state = 1857; break; // &Eq -> &Equ - case 1877: state = 1878; break; // &Equilibri -> &Equilibriu - case 2016: state = 2017; break; // &FilledSmallSq -> &FilledSmallSqu - case 2031: state = 2032; break; // &FilledVerySmallSq -> &FilledVerySmallSqu - case 2052: state = 2068; break; // &Fo -> &Fou - case 2120: state = 2121; break; // &gac -> &gacu - case 2239: state = 2240; break; // &GreaterEq -> &GreaterEqu - case 2247: state = 2248; break; // &GreaterF -> &GreaterFu - case 2252: state = 2253; break; // &GreaterFullEq -> &GreaterFullEqu - case 2273: state = 2274; break; // &GreaterSlantEq -> &GreaterSlantEqu - case 2306: state = 2307; break; // >q -> >qu - case 2351: state = 2508; break; // &H -> &Hu - case 2401: state = 2402; break; // &hearts -> &heartsu - case 2515: state = 2516; break; // &HumpDownH -> &HumpDownHu - case 2520: state = 2521; break; // &HumpEq -> &HumpEqu - case 2525: state = 2526; break; // &hyb -> &hybu - case 2533: state = 2765; break; // &I -> &Iu - case 2535: state = 2536; break; // &Iac -> &Iacu - case 2539: state = 2769; break; // &i -> &iu - case 2541: state = 2542; break; // &iac -> &iacu - case 2735: state = 2736; break; // &iq -> &iqu - case 2777: state = 2817; break; // &J -> &Ju - case 2782: state = 2821; break; // &j -> &ju - case 2881: state = 3724; break; // &l -> &lu - case 2888: state = 2889; break; // &Lac -> &Lacu - case 2893: state = 2894; break; // &lac -> &lacu - case 2931: state = 2932; break; // &laq -> &laqu - case 2985: state = 2987; break; // &lbrksl -> &lbrkslu - case 2993: state = 3008; break; // &lc -> &lcu - case 3015: state = 3016; break; // &ldq -> &ldqu - case 3019: state = 3024; break; // &ldr -> &ldru - case 3089: state = 3090; break; // &LeftDo -> &LeftDou - case 3132: state = 3137; break; // &leftharpoon -> &leftharpoonu - case 3189: state = 3190; break; // &leftrightsq -> &leftrightsqu - case 3239: state = 3240; break; // &LeftTriangleEq -> &LeftTriangleEqu - case 3324: state = 3325; break; // &LessEq -> &LessEqu - case 3335: state = 3336; break; // &LessF -> &LessFu - case 3340: state = 3341; break; // &LessFullEq -> &LessFullEqu - case 3367: state = 3368; break; // &LessSlantEq -> &LessSlantEqu - case 3395: state = 3397; break; // &lhar -> &lharu - case 3444: state = 3445; break; // &lmo -> &lmou - case 3595: state = 3596; break; // &lopl -> &loplu - case 3663: state = 3664; break; // &lsaq -> &lsaqu - case 3677: state = 3679; break; // &lsq -> &lsqu - case 3712: state = 3713; break; // <q -> <qu - case 3725: state = 3731; break; // &lur -> &luru - case 3745: state = 3887; break; // &m -> &mu - case 3755: state = 3886; break; // &M -> &Mu - case 3761: state = 3770; break; // &mapsto -> &mapstou - case 3794: state = 3795; break; // &meas -> &measu - case 3806: state = 3807; break; // &Medi -> &Mediu - case 3841: state = 3842; break; // &min -> &minu - case 3845: state = 3846; break; // &minusd -> &minusdu - case 3848: state = 3849; break; // &Min -> &Minu - case 3852: state = 3853; break; // &MinusPl -> &MinusPlu - case 3862: state = 3863; break; // &mnpl -> &mnplu - case 3897: state = 4753; break; // &n -> &nu - case 3902: state = 4752; break; // &N -> &Nu - case 3904: state = 3905; break; // &Nac -> &Nacu - case 3908: state = 3909; break; // &nac -> &nacu - case 3924: state = 3925; break; // &nat -> &natu - case 3930: state = 3933; break; // &nb -> &nbu - case 3937: state = 3962; break; // &nc -> &ncu - case 3994: state = 3995; break; // &NegativeMedi -> &NegativeMediu - case 4031: state = 4032; break; // &neq -> &nequ - case 4217: state = 4226; break; // &NotC -> &NotCu - case 4221: state = 4222; break; // &NotCongr -> &NotCongru - case 4232: state = 4233; break; // &NotDo -> &NotDou - case 4255: state = 4256; break; // &NotEq -> &NotEqu - case 4277: state = 4278; break; // &NotGreaterEq -> &NotGreaterEqu - case 4281: state = 4282; break; // &NotGreaterF -> &NotGreaterFu - case 4286: state = 4287; break; // &NotGreaterFullEq -> &NotGreaterFullEqu - case 4307: state = 4308; break; // &NotGreaterSlantEq -> &NotGreaterSlantEqu - case 4316: state = 4317; break; // &NotH -> &NotHu - case 4324: state = 4325; break; // &NotHumpDownH -> &NotHumpDownHu - case 4329: state = 4330; break; // &NotHumpEq -> &NotHumpEqu - case 4359: state = 4360; break; // &NotLeftTriangleEq -> &NotLeftTriangleEqu - case 4366: state = 4367; break; // &NotLessEq -> &NotLessEqu - case 4387: state = 4388; break; // &NotLessSlantEq -> &NotLessSlantEqu - case 4439: state = 4440; break; // &NotPrecedesEq -> &NotPrecedesEqu - case 4449: state = 4450; break; // &NotPrecedesSlantEq -> &NotPrecedesSlantEqu - case 4483: state = 4484; break; // &NotRightTriangleEq -> &NotRightTriangleEqu - case 4487: state = 4515; break; // &NotS -> &NotSu - case 4488: state = 4489; break; // &NotSq -> &NotSqu - case 4493: state = 4494; break; // &NotSquareS -> &NotSquareSu - case 4500: state = 4501; break; // &NotSquareSubsetEq -> &NotSquareSubsetEqu - case 4511: state = 4512; break; // &NotSquareSupersetEq -> &NotSquareSupersetEqu - case 4521: state = 4522; break; // &NotSubsetEq -> &NotSubsetEqu - case 4532: state = 4533; break; // &NotSucceedsEq -> &NotSucceedsEqu - case 4542: state = 4543; break; // &NotSucceedsSlantEq -> &NotSucceedsSlantEqu - case 4558: state = 4559; break; // &NotSupersetEq -> &NotSupersetEqu - case 4568: state = 4569; break; // &NotTildeEq -> &NotTildeEqu - case 4572: state = 4573; break; // &NotTildeF -> &NotTildeFu - case 4577: state = 4578; break; // &NotTildeFullEq -> &NotTildeFullEqu - case 4614: state = 4615; break; // &nprc -> &nprcu - case 4653: state = 4695; break; // &ns -> &nsu - case 4655: state = 4656; break; // &nscc -> &nsccu - case 4689: state = 4690; break; // &nsqs -> &nsqsu - case 4827: state = 5049; break; // &O -> &Ou - case 4829: state = 4830; break; // &Oac -> &Oacu - case 4833: state = 5052; break; // &o -> &ou - case 4835: state = 4836; break; // &oac -> &oacu - case 4948: state = 4949; break; // &omin -> &ominu - case 4963: state = 4964; break; // &OpenC -> &OpenCu - case 4969: state = 4970; break; // &OpenCurlyDo -> &OpenCurlyDou - case 4974: state = 4975; break; // &OpenCurlyDoubleQ -> &OpenCurlyDoubleQu - case 4979: state = 4980; break; // &OpenCurlyQ -> &OpenCurlyQu - case 4987: state = 4988; break; // &opl -> &oplu - case 5083: state = 5343; break; // &p -> &pu - case 5150: state = 5158; break; // &pl -> &plu - case 5168: state = 5170; break; // &plusd -> &plusdu - case 5172: state = 5173; break; // &Pl -> &Plu - case 5177: state = 5178; break; // &PlusMin -> &PlusMinu - case 5201: state = 5212; break; // &po -> &pou - case 5216: state = 5331; break; // &pr -> &pru - case 5219: state = 5220; break; // &prc -> &prcu - case 5231: state = 5232; break; // &precc -> &preccu - case 5245: state = 5246; break; // &PrecedesEq -> &PrecedesEqu - case 5255: state = 5256; break; // &PrecedesSlantEq -> &PrecedesSlantEqu - case 5299: state = 5300; break; // &Prod -> &Produ - case 5312: state = 5313; break; // &profs -> &profsu - case 5351: state = 5374; break; // &q -> &qu - case 5397: state = 5978; break; // &r -> &ru - case 5403: state = 5411; break; // &rac -> &racu - case 5405: state = 5968; break; // &R -> &Ru - case 5407: state = 5408; break; // &Rac -> &Racu - case 5431: state = 5432; break; // &raq -> &raqu - case 5499: state = 5501; break; // &rbrksl -> &rbrkslu - case 5507: state = 5522; break; // &rc -> &rcu - case 5534: state = 5535; break; // &rdq -> &rdqu - case 5569: state = 5570; break; // &ReverseEq -> &ReverseEqu - case 5576: state = 5577; break; // &ReverseEquilibri -> &ReverseEquilibriu - case 5582: state = 5583; break; // &ReverseUpEq -> &ReverseUpEqu - case 5589: state = 5590; break; // &ReverseUpEquilibri -> &ReverseUpEquilibriu - case 5609: state = 5611; break; // &rhar -> &rharu - case 5675: state = 5676; break; // &RightDo -> &RightDou - case 5718: state = 5723; break; // &rightharpoon -> &rightharpoonu - case 5755: state = 5756; break; // &rightsq -> &rightsqu - case 5799: state = 5800; break; // &RightTriangleEq -> &RightTriangleEqu - case 5863: state = 5864; break; // &rmo -> &rmou - case 5887: state = 5899; break; // &Ro -> &Rou - case 5891: state = 5892; break; // &ropl -> &roplu - case 5936: state = 5937; break; // &rsaq -> &rsaqu - case 5946: state = 5948; break; // &rsq -> &rsqu - case 5979: state = 5980; break; // &rul -> &rulu - case 5985: state = 6381; break; // &S -> &Su - case 5987: state = 5988; break; // &Sac -> &Sacu - case 5991: state = 6383; break; // &s -> &su - case 5993: state = 5994; break; // &sac -> &sacu - case 5998: state = 5999; break; // &sbq -> &sbqu - case 6012: state = 6013; break; // &scc -> &sccu - case 6075: state = 6076; break; // &setmin -> &setminu - case 6181: state = 6182; break; // &simpl -> &simplu - case 6211: state = 6212; break; // &smallsetmin -> &smallsetminu - case 6253: state = 6254; break; // &spades -> &spadesu - case 6258: state = 6285; break; // &sq -> &squ - case 6259: state = 6263; break; // &sqc -> &sqcu - case 6266: state = 6286; break; // &Sq -> &Squ - case 6269: state = 6270; break; // &sqs -> &sqsu - case 6305: state = 6306; break; // &SquareS -> &SquareSu - case 6312: state = 6313; break; // &SquareSubsetEq -> &SquareSubsetEqu - case 6323: state = 6324; break; // &SquareSupersetEq -> &SquareSupersetEqu - case 6393: state = 6394; break; // &subm -> &submu - case 6401: state = 6402; break; // &subpl -> &subplu - case 6411: state = 6428; break; // &subs -> &subsu - case 6418: state = 6419; break; // &SubsetEq -> &SubsetEqu - case 6439: state = 6440; break; // &succc -> &succcu - case 6453: state = 6454; break; // &SucceedsEq -> &SucceedsEqu - case 6463: state = 6464; break; // &SucceedsSlantEq -> &SucceedsSlantEqu - case 6507: state = 6508; break; // &supds -> &supdsu - case 6521: state = 6522; break; // &SupersetEq -> &SupersetEqu - case 6526: state = 6529; break; // &suphs -> &suphsu - case 6535: state = 6536; break; // &supm -> &supmu - case 6543: state = 6544; break; // &suppl -> &supplu - case 6549: state = 6561; break; // &sups -> &supsu - case 6584: state = 6592; break; // &Ta -> &Tau - case 6587: state = 6593; break; // &ta -> &tau - case 6705: state = 6706; break; // &TildeEq -> &TildeEqu - case 6709: state = 6710; break; // &TildeF -> &TildeFu - case 6714: state = 6715; break; // &TildeFullEq -> &TildeFullEqu - case 6794: state = 6795; break; // &trimin -> &triminu - case 6806: state = 6807; break; // &tripl -> &triplu - case 6818: state = 6819; break; // &trpezi -> &trpeziu - case 6873: state = 7212; break; // &U -> &Uu - case 6875: state = 6876; break; // &Uac -> &Uacu - case 6879: state = 7208; break; // &u -> &uu - case 6881: state = 6882; break; // &uac -> &uacu - case 7016: state = 7017; break; // &UnionPl -> &UnionPlu - case 7042: state = 7158; break; // &up -> &upu - case 7088: state = 7089; break; // &UpEq -> &UpEqu - case 7095: state = 7096; break; // &UpEquilibri -> &UpEquilibriu - case 7114: state = 7115; break; // &upl -> &uplu - case 7264: state = 7269; break; // &vars -> &varsu - case 7403: state = 7404; break; // &vns -> &vnsu - case 7424: state = 7427; break; // &vs -> &vsu - case 7495: state = 7568; break; // &x -> &xu - case 7496: state = 7502; break; // &xc -> &xcu - case 7544: state = 7545; break; // &xopl -> &xoplu - case 7565: state = 7566; break; // &xsqc -> &xsqcu - case 7570: state = 7571; break; // &xupl -> &xuplu - case 7584: state = 7640; break; // &Y -> &Yu - case 7586: state = 7587; break; // &Yac -> &Yacu - case 7590: state = 7637; break; // &y -> &yu - case 7592: state = 7593; break; // &yac -> &yacu - case 7647: state = 7648; break; // &Zac -> &Zacu - case 7653: state = 7654; break; // &zac -> &zacu - default: return false; - } - break; - case 'v': - switch (state) { - case 0: state = 7223; break; // & -> &v - case 15: state = 16; break; // &Abre -> &Abrev - case 20: state = 21; break; // &abre -> &abrev - case 52: state = 53; break; // &Agra -> &Agrav - case 57: state = 58; break; // &agra -> &agrav - case 91: state = 101; break; // &and -> &andv - case 119: state = 120; break; // &angrt -> &angrtv - case 256: state = 257; break; // &Bar -> &Barv - case 258: state = 259; break; // &bar -> &barv - case 303: state = 304; break; // &bempty -> &bemptyv - case 334: state = 383; break; // &big -> &bigv - case 449: state = 450; break; // &bnequi -> &bnequiv - case 470: state = 519; break; // &box -> &boxv - case 538: state = 539; break; // &Bre -> &Brev - case 541: state = 545; break; // &br -> &brv - case 542: state = 543; break; // &bre -> &brev - case 696: state = 697; break; // &cempty -> &cemptyv - case 987: state = 1070; break; // &cu -> &cuv - case 1026: state = 1054; break; // &cur -> &curv - case 1032: state = 1043; break; // &curly -> &curlyv - case 1115: state = 1119; break; // &dash -> &dashv - case 1117: state = 1118; break; // &Dash -> &Dashv - case 1173: state = 1174; break; // &dempty -> &demptyv - case 1220: state = 1221; break; // &DiacriticalGra -> &DiacriticalGrav - case 1228: state = 1263; break; // &di -> &div - case 1497: state = 1498; break; // &DownBre -> &DownBrev - case 1717: state = 1718; break; // &Egra -> &Egrav - case 1721: state = 1722; break; // &egra -> &egrav - case 1756: state = 1774; break; // &empty -> &emptyv - case 1822: state = 1832; break; // &epsi -> &epsiv - case 1833: state = 1884; break; // &eq -> &eqv - case 1880: state = 1881; break; // &equi -> &equiv - case 2066: state = 2067; break; // &fork -> &forkv - case 2118: state = 2341; break; // &g -> &gv - case 2137: state = 2138; break; // &Gbre -> &Gbrev - case 2142: state = 2143; break; // &gbre -> &gbrev - case 2229: state = 2230; break; // &gra -> &grav - case 2574: state = 2575; break; // &Igra -> &Igrav - case 2579: state = 2580; break; // &igra -> &igrav - case 2656: state = 2693; break; // &In -> &Inv - case 2747: state = 2754; break; // &isin -> &isinv - case 2752: state = 2753; break; // &isins -> &isinsv - case 2834: state = 2835; break; // &kappa -> &kappav - case 2881: state = 3735; break; // &l -> &lv - case 2901: state = 2902; break; // &laempty -> &laemptyv - case 3897: state = 4760; break; // &n -> &nv - case 3988: state = 3989; break; // &Negati -> &Negativ - case 4033: state = 4034; break; // &nequi -> &nequiv - case 4097: state = 4100; break; // &nGt -> &nGtv - case 4111: state = 4114; break; // &ni -> &niv - case 4181: state = 4186; break; // &nLt -> &nLtv - case 4334: state = 4339; break; // ¬in -> ¬inv - case 4425: state = 4426; break; // ¬ni -> ¬niv - case 4454: state = 4455; break; // &NotRe -> &NotRev - case 4827: state = 5059; break; // &O -> &Ov - case 4833: state = 5055; break; // &o -> &ov - case 4864: state = 4865; break; // &odi -> &odiv - case 4892: state = 4893; break; // &Ogra -> &Ograv - case 4896: state = 4897; break; // &ogra -> &ograv - case 4991: state = 5013; break; // &or -> &orv - case 5131: state = 5132; break; // &phi -> &phiv - case 5141: state = 5149; break; // &pi -> &piv - case 5156: state = 5157; break; // &plank -> &plankv - case 5421: state = 5422; break; // &raempty -> &raemptyv - case 5540: state = 5557; break; // &Re -> &Rev - case 5615: state = 5616; break; // &rho -> &rhov - case 6165: state = 6167; break; // &sigma -> &sigmav - case 6649: state = 6653; break; // &theta -> &thetav - case 6904: state = 6905; break; // &Ubre -> &Ubrev - case 6907: state = 6908; break; // &ubre -> &ubrev - case 6946: state = 6947; break; // &Ugra -> &Ugrav - case 6951: state = 6952; break; // &ugra -> &ugrav - case 7307: state = 7436; break; // &V -> &Vv - case 7313: state = 7314; break; // &vBar -> &vBarv - case 7495: state = 7576; break; // &x -> &xv - default: return false; - } - break; - case 'w': - switch (state) { - case 0: state = 7452; break; // & -> &w - case 7: state = 212; break; // &a -> &aw - case 256: state = 262; break; // &Bar -> &Barw - case 258: state = 265; break; // &bar -> &barw - case 322: state = 325; break; // &bet -> &betw - case 334: state = 386; break; // &big -> &bigw - case 373: state = 374; break; // &bigtriangledo -> &bigtriangledow - case 394: state = 395; break; // &bkaro -> &bkarow - case 422: state = 423; break; // &blacktriangledo -> &blacktriangledow - case 459: state = 466; break; // &bo -> &bow - case 589: state = 1076; break; // &c -> &cw - case 742: state = 743; break; // &circlearro -> &circlearrow - case 806: state = 807; break; // &Clock -> &Clockw - case 941: state = 942; break; // &CounterClock -> &CounterClockw - case 987: state = 1073; break; // &cu -> &cuw - case 1032: state = 1046; break; // &curly -> &curlyw - case 1059: state = 1060; break; // &curvearro -> &curvearrow - case 1097: state = 1638; break; // &d -> &dw - case 1124: state = 1125; break; // &dbkaro -> &dbkarow - case 1291: state = 1478; break; // &do -> &dow - case 1296: state = 1466; break; // &Do -> &Dow - case 1337: state = 1338; break; // &doublebar -> &doublebarw - case 1363: state = 1365; break; // &DoubleDo -> &DoubleDow - case 1370: state = 1371; break; // &DoubleDownArro -> &DoubleDownArrow - case 1379: state = 1380; break; // &DoubleLeftArro -> &DoubleLeftArrow - case 1389: state = 1390; break; // &DoubleLeftRightArro -> &DoubleLeftRightArrow - case 1404: state = 1405; break; // &DoubleLongLeftArro -> &DoubleLongLeftArrow - case 1414: state = 1415; break; // &DoubleLongLeftRightArro -> &DoubleLongLeftRightArrow - case 1424: state = 1425; break; // &DoubleLongRightArro -> &DoubleLongRightArrow - case 1434: state = 1435; break; // &DoubleRightArro -> &DoubleRightArrow - case 1444: state = 1445; break; // &DoubleUpArro -> &DoubleUpArrow - case 1447: state = 1448; break; // &DoubleUpDo -> &DoubleUpDow - case 1453: state = 1454; break; // &DoubleUpDownArro -> &DoubleUpDownArrow - case 1471: state = 1472; break; // &DownArro -> &DownArrow - case 1476: state = 1477; break; // &Downarro -> &Downarrow - case 1483: state = 1484; break; // &downarro -> &downarrow - case 1493: state = 1494; break; // &DownArrowUpArro -> &DownArrowUpArrow - case 1501: state = 1502; break; // &downdo -> &downdow - case 1507: state = 1508; break; // &downdownarro -> &downdownarrow - case 1588: state = 1589; break; // &DownTeeArro -> &DownTeeArrow - case 1595: state = 1596; break; // &drbkaro -> &drbkarow - case 2109: state = 2110; break; // &fro -> &frow - case 2380: state = 2384; break; // &harr -> &harrw - case 2429: state = 2435; break; // &hks -> &hksw - case 2433: state = 2434; break; // &hksearo -> &hksearow - case 2438: state = 2439; break; // &hkswaro -> &hkswarow - case 2457: state = 2458; break; // &hookleftarro -> &hookleftarrow - case 2467: state = 2468; break; // &hookrightarro -> &hookrightarrow - case 2512: state = 2513; break; // &HumpDo -> &HumpDow - case 3050: state = 3051; break; // &LeftArro -> &LeftArrow - case 3055: state = 3056; break; // &Leftarro -> &Leftarrow - case 3062: state = 3063; break; // &leftarro -> &leftarrow - case 3075: state = 3076; break; // &LeftArrowRightArro -> &LeftArrowRightArrow - case 3089: state = 3101; break; // &LeftDo -> &LeftDow - case 3134: state = 3135; break; // &leftharpoondo -> &leftharpoondow - case 3146: state = 3147; break; // &leftleftarro -> &leftleftarrow - case 3157: state = 3158; break; // &LeftRightArro -> &LeftRightArrow - case 3167: state = 3168; break; // &Leftrightarro -> &Leftrightarrow - case 3177: state = 3178; break; // &leftrightarro -> &leftrightarrow - case 3196: state = 3197; break; // &leftrightsquigarro -> &leftrightsquigarrow - case 3210: state = 3211; break; // &LeftTeeArro -> &LeftTeeArrow - case 3246: state = 3247; break; // &LeftUpDo -> &LeftUpDow - case 3425: state = 3426; break; // &Lleftarro -> &Lleftarrow - case 3466: state = 3603; break; // &lo -> &low - case 3475: state = 3610; break; // &Lo -> &Low - case 3485: state = 3486; break; // &LongLeftArro -> &LongLeftArrow - case 3494: state = 3495; break; // &Longleftarro -> &Longleftarrow - case 3505: state = 3506; break; // &longleftarro -> &longleftarrow - case 3515: state = 3516; break; // &LongLeftRightArro -> &LongLeftRightArrow - case 3525: state = 3526; break; // &Longleftrightarro -> &Longleftrightarrow - case 3535: state = 3536; break; // &longleftrightarro -> &longleftrightarrow - case 3551: state = 3552; break; // &LongRightArro -> &LongRightArrow - case 3561: state = 3562; break; // &Longrightarro -> &Longrightarrow - case 3571: state = 3572; break; // &longrightarro -> &longrightarrow - case 3578: state = 3579; break; // &looparro -> &looparrow - case 3620: state = 3621; break; // &LowerLeftArro -> &LowerLeftArrow - case 3630: state = 3631; break; // &LowerRightArro -> &LowerRightArrow - case 3763: state = 3764; break; // &mapstodo -> &mapstodow - case 3897: state = 4812; break; // &n -> &nw - case 3979: state = 3980; break; // &nearro -> &nearrow - case 3984: state = 4067; break; // &Ne -> &New - case 4139: state = 4140; break; // &nLeftarro -> &nLeftarrow - case 4146: state = 4147; break; // &nleftarro -> &nleftarrow - case 4156: state = 4157; break; // &nLeftrightarro -> &nLeftrightarrow - case 4166: state = 4167; break; // &nleftrightarro -> &nleftrightarrow - case 4321: state = 4322; break; // &NotHumpDo -> &NotHumpDow - case 4627: state = 4629; break; // &nrarr -> &nrarrw - case 4638: state = 4639; break; // &nRightarro -> &nRightarrow - case 4647: state = 4648; break; // &nrightarro -> &nrightarrow - case 4821: state = 4822; break; // &nwarro -> &nwarrow - case 5185: state = 5186; break; // &plust -> &plustw - case 5439: state = 5461; break; // &rarr -> &rarrw - case 5635: state = 5636; break; // &RightArro -> &RightArrow - case 5640: state = 5641; break; // &Rightarro -> &Rightarrow - case 5649: state = 5650; break; // &rightarro -> &rightarrow - case 5661: state = 5662; break; // &RightArrowLeftArro -> &RightArrowLeftArrow - case 5675: state = 5687; break; // &RightDo -> &RightDow - case 5720: state = 5721; break; // &rightharpoondo -> &rightharpoondow - case 5732: state = 5733; break; // &rightleftarro -> &rightleftarrow - case 5751: state = 5752; break; // &rightrightarro -> &rightrightarrow - case 5762: state = 5763; break; // &rightsquigarro -> &rightsquigarrow - case 5770: state = 5771; break; // &RightTeeArro -> &RightTeeArrow - case 5806: state = 5807; break; // &RightUpDo -> &RightUpDow - case 5932: state = 5933; break; // &Rrightarro -> &Rrightarrow - case 5991: state = 6564; break; // &s -> &sw - case 6062: state = 6063; break; // &searro -> &searrow - case 6068: state = 6069; break; // &ses -> &sesw - case 6085: state = 6086; break; // &sfro -> &sfrow - case 6109: state = 6110; break; // &ShortDo -> &ShortDow - case 6115: state = 6116; break; // &ShortDownArro -> &ShortDownArrow - case 6124: state = 6125; break; // &ShortLeftArro -> &ShortLeftArrow - case 6148: state = 6149; break; // &ShortRightArro -> &ShortRightArrow - case 6155: state = 6156; break; // &ShortUpArro -> &ShortUpArrow - case 6573: state = 6574; break; // &swarro -> &swarrow - case 6575: state = 6576; break; // &swn -> &swnw - case 6586: state = 6845; break; // &t -> &tw - case 6771: state = 6772; break; // &triangledo -> &triangledow - case 6861: state = 6862; break; // &twoheadleftarro -> &twoheadleftarrow - case 6871: state = 6872; break; // &twoheadrightarro -> &twoheadrightarrow - case 6879: state = 7217; break; // &u -> &uw - case 7035: state = 7036; break; // &UpArro -> &UpArrow - case 7040: state = 7041; break; // &Uparro -> &Uparrow - case 7046: state = 7047; break; // &uparro -> &uparrow - case 7052: state = 7053; break; // &UpArrowDo -> &UpArrowDow - case 7058: state = 7059; break; // &UpArrowDownArro -> &UpArrowDownArrow - case 7061: state = 7062; break; // &UpDo -> &UpDow - case 7067: state = 7068; break; // &UpDownArro -> &UpDownArrow - case 7070: state = 7071; break; // &Updo -> &Updow - case 7076: state = 7077; break; // &Updownarro -> &Updownarrow - case 7079: state = 7080; break; // &updo -> &updow - case 7085: state = 7086; break; // &updownarro -> &updownarrow - case 7127: state = 7128; break; // &UpperLeftArro -> &UpperLeftArrow - case 7137: state = 7138; break; // &UpperRightArro -> &UpperRightArrow - case 7156: state = 7157; break; // &UpTeeArro -> &UpTeeArrow - case 7163: state = 7164; break; // &upuparro -> &upuparrow - case 7495: state = 7579; break; // &x -> &xw - case 7651: state = 7725; break; // &z -> &zw - default: return false; - } - break; - case 'x': - switch (state) { - case 0: state = 7495; break; // & -> &x - case 168: state = 169; break; // &appro -> &approx - case 459: state = 470; break; // &bo -> &box - case 472: state = 473; break; // &boxbo -> &boxbox - case 875: state = 880; break; // &comple -> &complex - case 1275: state = 1276; break; // &divon -> &divonx - case 1656: state = 1931; break; // &E -> &Ex - case 1662: state = 1925; break; // &e -> &ex - case 2213: state = 2214; break; // &gnappro -> &gnapprox - case 2316: state = 2317; break; // >rappro -> >rapprox - case 2561: state = 2564; break; // &ie -> &iex - case 3307: state = 3308; break; // &lessappro -> &lessapprox - case 3457: state = 3458; break; // &lnappro -> &lnapprox - case 3922: state = 3923; break; // &nappro -> &napprox - case 3970: state = 4072; break; // &ne -> &nex - case 4248: state = 4264; break; // &NotE -> &NotEx - case 5229: state = 5230; break; // &precappro -> &precapprox - case 5271: state = 5272; break; // &precnappro -> &precnapprox - case 5397: state = 5984; break; // &r -> &rx - case 6053: state = 6079; break; // &se -> &sex - case 6437: state = 6438; break; // &succappro -> &succapprox - case 6479: state = 6480; break; // &succnappro -> &succnapprox - case 6661: state = 6662; break; // &thickappro -> &thickapprox - case 6846: state = 6847; break; // &twi -> &twix - default: return false; - } - break; - case 'y': - switch (state) { - case 0: state = 7590; break; // & -> &y - case 23: state = 37; break; // &ac -> &acy - case 26: state = 36; break; // &Ac -> &Acy - case 63: state = 64; break; // &alefs -> &alefsy - case 156: state = 157; break; // &Appl -> &Apply - case 183: state = 191; break; // &as -> &asy - case 277: state = 283; break; // &bc -> &bcy - case 281: state = 282; break; // &Bc -> &Bcy - case 302: state = 303; break; // &bempt -> &bempty - case 584: state = 636; break; // &Ca -> &Cay - case 589: state = 1086; break; // &c -> &cy - case 638: state = 639; break; // &Cayle -> &Cayley - case 695: state = 696; break; // &cempt -> &cempty - case 717: state = 718; break; // &CHc -> &CHcy - case 720: state = 721; break; // &chc -> &chcy - case 831: state = 832; break; // &CloseCurl -> &CloseCurly - case 915: state = 929; break; // &cop -> © - case 1031: state = 1032; break; // &curl -> &curly - case 1089: state = 1090; break; // &cylct -> &cylcty - case 1129: state = 1139; break; // &Dc -> &Dcy - case 1134: state = 1140; break; // &dc -> &dcy - case 1172: state = 1173; break; // &dempt -> &dempty - case 1278: state = 1279; break; // &DJc -> &DJcy - case 1281: state = 1282; break; // &djc -> &djcy - case 1608: state = 1613; break; // &dsc -> &dscy - case 1611: state = 1612; break; // &DSc -> &DScy - case 1645: state = 1646; break; // &DZc -> &DZcy - case 1648: state = 1649; break; // &dzc -> &dzcy - case 1672: state = 1692; break; // &Ec -> &Ecy - case 1677: state = 1693; break; // &ec -> &ecy - case 1755: state = 1756; break; // &empt -> &empty - case 1761: state = 1762; break; // &Empt -> &Empty - case 1777: state = 1778; break; // &EmptyVer -> &EmptyVery - case 1978: state = 1979; break; // &Fc -> &Fcy - case 1980: state = 1981; break; // &fc -> &fcy - case 2023: state = 2024; break; // &FilledVer -> &FilledVery - case 2145: state = 2157; break; // &Gc -> &Gcy - case 2153: state = 2158; break; // &gc -> &gcy - case 2199: state = 2200; break; // &GJc -> &GJcy - case 2202: state = 2203; break; // &gjc -> &gjcy - case 2356: state = 2524; break; // &h -> &hy - case 2371: state = 2372; break; // &HARDc -> &HARDcy - case 2375: state = 2376; break; // &hardc -> &hardcy - case 2545: state = 2554; break; // &ic -> &icy - case 2546: state = 2553; break; // &Ic -> &Icy - case 2559: state = 2560; break; // &IEc -> &IEcy - case 2562: state = 2563; break; // &iec -> &iecy - case 2618: state = 2619; break; // &Imaginar -> &Imaginary - case 2711: state = 2712; break; // &IOc -> &IOcy - case 2714: state = 2715; break; // &ioc -> &iocy - case 2767: state = 2768; break; // &Iukc -> &Iukcy - case 2771: state = 2772; break; // &iukc -> &iukcy - case 2778: state = 2787; break; // &Jc -> &Jcy - case 2783: state = 2788; break; // &jc -> &jcy - case 2811: state = 2812; break; // &Jserc -> &Jsercy - case 2815: state = 2816; break; // &jserc -> &jsercy - case 2819: state = 2820; break; // &Jukc -> &Jukcy - case 2823: state = 2824; break; // &jukc -> &jukcy - case 2836: state = 2846; break; // &Kc -> &Kcy - case 2841: state = 2847; break; // &kc -> &kcy - case 2858: state = 2859; break; // &KHc -> &KHcy - case 2861: state = 2862; break; // &khc -> &khcy - case 2864: state = 2865; break; // &KJc -> &KJcy - case 2867: state = 2868; break; // &kjc -> &kjcy - case 2900: state = 2901; break; // &laempt -> &laempty - case 2988: state = 3010; break; // &Lc -> &Lcy - case 2993: state = 3011; break; // &lc -> &lcy - case 3403: state = 3404; break; // &LJc -> &LJcy - case 3406: state = 3407; break; // &ljc -> &ljcy - case 3776: state = 3783; break; // &mc -> &mcy - case 3781: state = 3782; break; // &Mc -> &Mcy - case 3937: state = 3965; break; // &nc -> &ncy - case 3940: state = 3964; break; // &Nc -> &Ncy - case 4020: state = 4021; break; // &NegativeVer -> &NegativeVery - case 4116: state = 4117; break; // &NJc -> &NJcy - case 4119: state = 4120; break; // &njc -> &njcy - case 4841: state = 4850; break; // &oc -> &ocy - case 4844: state = 4849; break; // &Oc -> &Ocy - case 4966: state = 4967; break; // &OpenCurl -> &OpenCurly - case 5104: state = 5105; break; // &Pc -> &Pcy - case 5106: state = 5107; break; // &pc -> &pcy - case 5234: state = 5235; break; // &preccurl -> &preccurly - case 5420: state = 5421; break; // &raempt -> &raempty - case 5502: state = 5524; break; // &Rc -> &Rcy - case 5507: state = 5525; break; // &rc -> &rcy - case 5974: state = 5975; break; // &RuleDela -> &RuleDelay - case 6001: state = 6046; break; // &Sc -> &Scy - case 6002: state = 6047; break; // &sc -> &scy - case 6088: state = 6157; break; // &sh -> ­ - case 6095: state = 6096; break; // &SHCHc -> &SHCHcy - case 6097: state = 6103; break; // &shc -> &shcy - case 6099: state = 6100; break; // &shchc -> &shchcy - case 6101: state = 6102; break; // &SHc -> &SHcy - case 6233: state = 6234; break; // &SOFTc -> &SOFTcy - case 6238: state = 6239; break; // &softc -> &softcy - case 6442: state = 6443; break; // &succcurl -> &succcurly - case 6597: state = 6615; break; // &Tc -> &Tcy - case 6602: state = 6616; break; // &tc -> &tcy - case 6650: state = 6651; break; // &thetas -> &thetasy - case 6825: state = 6830; break; // &tsc -> &tscy - case 6828: state = 6829; break; // &TSc -> &TScy - case 6832: state = 6833; break; // &TSHc -> &TSHcy - case 6835: state = 6836; break; // &tshc -> &tshcy - case 6898: state = 6899; break; // &Ubrc -> &Ubrcy - case 6902: state = 6903; break; // &ubrc -> &ubrcy - case 6910: state = 6918; break; // &Uc -> &Ucy - case 6914: state = 6919; break; // &uc -> &ucy - case 7315: state = 7316; break; // &Vc -> &Vcy - case 7317: state = 7318; break; // &vc -> &vcy - case 7349: state = 7384; break; // &Ver -> &Very - case 7592: state = 7599; break; // &yac -> &yacy - case 7597: state = 7598; break; // &YAc -> &YAcy - case 7600: state = 7608; break; // &Yc -> &Ycy - case 7604: state = 7609; break; // &yc -> &ycy - case 7617: state = 7618; break; // &YIc -> &YIcy - case 7620: state = 7621; break; // &yic -> &yicy - case 7635: state = 7636; break; // &YUc -> &YUcy - case 7638: state = 7639; break; // &yuc -> &yucy - case 7657: state = 7667; break; // &Zc -> &Zcy - case 7662: state = 7668; break; // &zc -> &zcy - case 7702: state = 7703; break; // &ZHc -> &ZHcy - case 7705: state = 7706; break; // &zhc -> &zhcy - default: return false; - } - break; - case 'z': - switch (state) { - case 0: state = 7651; break; // & -> &z - case 102: state = 127; break; // &ang -> &angz - case 401: state = 402; break; // &blacklo -> &blackloz - case 1097: state = 1647; break; // &d -> &dz - case 2479: state = 2480; break; // &Hori -> &Horiz - case 3466: state = 3632; break; // &lo -> &loz - case 5991: state = 6579; break; // &s -> &sz - case 6816: state = 6817; break; // &trpe -> &trpez - case 7223: state = 7441; break; // &v -> &vz - case 7443: state = 7444; break; // &vzig -> &vzigz - default: return false; - } - break; + case '1': table = TransitionTable_1; break; + case '2': table = TransitionTable_2; break; + case '3': table = TransitionTable_3; break; + case '4': table = TransitionTable_4; break; + case '5': table = TransitionTable_5; break; + case '6': table = TransitionTable_6; break; + case '7': table = TransitionTable_7; break; + case '8': table = TransitionTable_8; break; + case ';': table = TransitionTable_semicolon; break; + case 'A': table = TransitionTable_A; break; + case 'B': table = TransitionTable_B; break; + case 'C': table = TransitionTable_C; break; + case 'D': table = TransitionTable_D; break; + case 'E': table = TransitionTable_E; break; + case 'F': table = TransitionTable_F; break; + case 'G': table = TransitionTable_G; break; + case 'H': table = TransitionTable_H; break; + case 'I': table = TransitionTable_I; break; + case 'J': table = TransitionTable_J; break; + case 'K': table = TransitionTable_K; break; + case 'L': table = TransitionTable_L; break; + case 'M': table = TransitionTable_M; break; + case 'N': table = TransitionTable_N; break; + case 'O': table = TransitionTable_O; break; + case 'P': table = TransitionTable_P; break; + case 'Q': table = TransitionTable_Q; break; + case 'R': table = TransitionTable_R; break; + case 'S': table = TransitionTable_S; break; + case 'T': table = TransitionTable_T; break; + case 'U': table = TransitionTable_U; break; + case 'V': table = TransitionTable_V; break; + case 'W': table = TransitionTable_W; break; + case 'X': table = TransitionTable_X; break; + case 'Y': table = TransitionTable_Y; break; + case 'Z': table = TransitionTable_Z; break; + case 'a': table = TransitionTable_a; break; + case 'b': table = TransitionTable_b; break; + case 'c': table = TransitionTable_c; break; + case 'd': table = TransitionTable_d; break; + case 'e': table = TransitionTable_e; break; + case 'f': table = TransitionTable_f; break; + case 'g': table = TransitionTable_g; break; + case 'h': table = TransitionTable_h; break; + case 'i': table = TransitionTable_i; break; + case 'j': table = TransitionTable_j; break; + case 'k': table = TransitionTable_k; break; + case 'l': table = TransitionTable_l; break; + case 'm': table = TransitionTable_m; break; + case 'n': table = TransitionTable_n; break; + case 'o': table = TransitionTable_o; break; + case 'p': table = TransitionTable_p; break; + case 'q': table = TransitionTable_q; break; + case 'r': table = TransitionTable_r; break; + case 's': table = TransitionTable_s; break; + case 't': table = TransitionTable_t; break; + case 'u': table = TransitionTable_u; break; + case 'v': table = TransitionTable_v; break; + case 'w': table = TransitionTable_w; break; + case 'x': table = TransitionTable_x; break; + case 'y': table = TransitionTable_y; break; + case 'z': table = TransitionTable_z; break; default: return false; } - states[index] = state; + if ((next = BinarySearchNextState (table, state)) == -1) + return false; + + states[index] = next; pushed[index] = c; index++; return true; } - static string GetNamedEntityValue (int state) - { - switch (state) { - case 6: return "\u00C1"; // Á - case 12: return "\u00E1"; // á - case 17: return "\u0102"; // &Abreve - case 22: return "\u0103"; // &abreve - case 23: return "\u223E"; // &ac - case 24: return "\u223F"; // &acd - case 25: return "\u223E\u0333"; // &acE - case 29: return "\u00C2"; // Â - case 32: return "\u00E2"; // â - case 35: return "\u00B4"; // ´ - case 36: return "\u0410"; // &Acy - case 37: return "\u0430"; // &acy - case 41: return "\u00C6"; // Æ - case 45: return "\u00E6"; // æ - case 46: return "\u2061"; // &af - case 48: return "\uD835\uDD04"; // &Afr - case 49: return "\uD835\uDD1E"; // &afr - case 54: return "\u00C0"; // À - case 59: return "\u00E0"; // à - case 65: return "\u2135"; // &alefsym - case 67: return "\u2135"; // &aleph - case 71: return "\u0391"; // &Alpha - case 74: return "\u03B1"; // &alpha - case 78: return "\u0100"; // &Amacr - case 82: return "\u0101"; // &amacr - case 84: return "\u2A3F"; // &amalg - case 86: return "\u0026"; // & - case 87: return "\u0026"; // & - case 89: return "\u2A53"; // &And - case 91: return "\u2227"; // &and - case 94: return "\u2A55"; // &andand - case 95: return "\u2A5C"; // &andd - case 100: return "\u2A58"; // &andslope - case 101: return "\u2A5A"; // &andv - case 102: return "\u2220"; // &ang - case 103: return "\u29A4"; // &ange - case 105: return "\u2220"; // &angle - case 108: return "\u2221"; // &angmsd - case 110: return "\u29A8"; // &angmsdaa - case 111: return "\u29A9"; // &angmsdab - case 112: return "\u29AA"; // &angmsdac - case 113: return "\u29AB"; // &angmsdad - case 114: return "\u29AC"; // &angmsdae - case 115: return "\u29AD"; // &angmsdaf - case 116: return "\u29AE"; // &angmsdag - case 117: return "\u29AF"; // &angmsdah - case 119: return "\u221F"; // &angrt - case 121: return "\u22BE"; // &angrtvb - case 122: return "\u299D"; // &angrtvbd - case 125: return "\u2222"; // &angsph - case 126: return "\u00C5"; // &angst - case 130: return "\u237C"; // &angzarr - case 134: return "\u0104"; // &Aogon - case 138: return "\u0105"; // &aogon - case 140: return "\uD835\uDD38"; // &Aopf - case 142: return "\uD835\uDD52"; // &aopf - case 143: return "\u2248"; // &ap - case 147: return "\u2A6F"; // &apacir - case 148: return "\u2A70"; // &apE - case 149: return "\u224A"; // &ape - case 151: return "\u224B"; // &apid - case 153: return "\u0027"; // &apos - case 165: return "\u2061"; // &ApplyFunction - case 169: return "\u2248"; // &approx - case 171: return "\u224A"; // &approxeq - case 175: return "\u00C5"; // Å - case 179: return "\u00E5"; // å - case 182: return "\uD835\uDC9C"; // &Ascr - case 185: return "\uD835\uDCB6"; // &ascr - case 189: return "\u2254"; // &Assign - case 190: return "\u002A"; // &ast - case 193: return "\u2248"; // &asymp - case 195: return "\u224D"; // &asympeq - case 200: return "\u00C3"; // Ã - case 205: return "\u00E3"; // ã - case 208: return "\u00C4"; // Ä - case 211: return "\u00E4"; // ä - case 218: return "\u2233"; // &awconint - case 221: return "\u2A11"; // &awint - case 229: return "\u224C"; // &backcong - case 236: return "\u03F6"; // &backepsilon - case 241: return "\u2035"; // &backprime - case 244: return "\u223D"; // &backsim - case 246: return "\u22CD"; // &backsimeq - case 255: return "\u2216"; // &Backslash - case 257: return "\u2AE7"; // &Barv - case 261: return "\u22BD"; // &barvee - case 264: return "\u2306"; // &Barwed - case 267: return "\u2305"; // &barwed - case 269: return "\u2305"; // &barwedge - case 272: return "\u23B5"; // &bbrk - case 276: return "\u23B6"; // &bbrktbrk - case 280: return "\u224C"; // &bcong - case 282: return "\u0411"; // &Bcy - case 283: return "\u0431"; // &bcy - case 287: return "\u201E"; // &bdquo - case 292: return "\u2235"; // &becaus - case 298: return "\u2235"; // &Because - case 299: return "\u2235"; // &because - case 304: return "\u29B0"; // &bemptyv - case 307: return "\u03F6"; // &bepsi - case 311: return "\u212C"; // &bernou - case 319: return "\u212C"; // &Bernoullis - case 321: return "\u0392"; // &Beta - case 323: return "\u03B2"; // &beta - case 324: return "\u2136"; // &beth - case 328: return "\u226C"; // &between - case 330: return "\uD835\uDD05"; // &Bfr - case 332: return "\uD835\uDD1F"; // &bfr - case 337: return "\u22C2"; // &bigcap - case 340: return "\u25EF"; // &bigcirc - case 342: return "\u22C3"; // &bigcup - case 346: return "\u2A00"; // &bigodot - case 350: return "\u2A01"; // &bigoplus - case 355: return "\u2A02"; // &bigotimes - case 360: return "\u2A06"; // &bigsqcup - case 363: return "\u2605"; // &bigstar - case 375: return "\u25BD"; // &bigtriangledown - case 377: return "\u25B3"; // &bigtriangleup - case 382: return "\u2A04"; // &biguplus - case 385: return "\u22C1"; // &bigvee - case 390: return "\u22C0"; // &bigwedge - case 395: return "\u290D"; // &bkarow - case 406: return "\u29EB"; // &blacklozenge - case 412: return "\u25AA"; // &blacksquare - case 420: return "\u25B4"; // &blacktriangle - case 424: return "\u25BE"; // &blacktriangledown - case 428: return "\u25C2"; // &blacktriangleleft - case 433: return "\u25B8"; // &blacktriangleright - case 435: return "\u2423"; // &blank - case 438: return "\u2592"; // &blk12 - case 439: return "\u2591"; // &blk14 - case 441: return "\u2593"; // &blk34 - case 444: return "\u2588"; // &block - case 446: return "\u003D\u20E5"; // &bne - case 450: return "\u2261\u20E5"; // &bnequiv - case 453: return "\u2AED"; // &bNot - case 455: return "\u2310"; // &bnot - case 458: return "\uD835\uDD39"; // &Bopf - case 461: return "\uD835\uDD53"; // &bopf - case 462: return "\u22A5"; // &bot - case 465: return "\u22A5"; // &bottom - case 469: return "\u22C8"; // &bowtie - case 473: return "\u29C9"; // &boxbox - case 475: return "\u2557"; // &boxDL - case 476: return "\u2556"; // &boxDl - case 478: return "\u2555"; // &boxdL - case 479: return "\u2510"; // &boxdl - case 480: return "\u2554"; // &boxDR - case 481: return "\u2553"; // &boxDr - case 482: return "\u2552"; // &boxdR - case 483: return "\u250C"; // &boxdr - case 484: return "\u2550"; // &boxH - case 485: return "\u2500"; // &boxh - case 486: return "\u2566"; // &boxHD - case 487: return "\u2564"; // &boxHd - case 488: return "\u2565"; // &boxhD - case 489: return "\u252C"; // &boxhd - case 490: return "\u2569"; // &boxHU - case 491: return "\u2567"; // &boxHu - case 492: return "\u2568"; // &boxhU - case 493: return "\u2534"; // &boxhu - case 498: return "\u229F"; // &boxminus - case 502: return "\u229E"; // &boxplus - case 507: return "\u22A0"; // &boxtimes - case 509: return "\u255D"; // &boxUL - case 510: return "\u255C"; // &boxUl - case 512: return "\u255B"; // &boxuL - case 513: return "\u2518"; // &boxul - case 514: return "\u255A"; // &boxUR - case 515: return "\u2559"; // &boxUr - case 516: return "\u2558"; // &boxuR - case 517: return "\u2514"; // &boxur - case 518: return "\u2551"; // &boxV - case 519: return "\u2502"; // &boxv - case 520: return "\u256C"; // &boxVH - case 521: return "\u256B"; // &boxVh - case 522: return "\u256A"; // &boxvH - case 523: return "\u253C"; // &boxvh - case 524: return "\u2563"; // &boxVL - case 525: return "\u2562"; // &boxVl - case 526: return "\u2561"; // &boxvL - case 527: return "\u2524"; // &boxvl - case 528: return "\u2560"; // &boxVR - case 529: return "\u255F"; // &boxVr - case 530: return "\u255E"; // &boxvR - case 531: return "\u251C"; // &boxvr - case 536: return "\u2035"; // &bprime - case 540: return "\u02D8"; // &Breve - case 544: return "\u02D8"; // &breve - case 548: return "\u00A6"; // ¦ - case 551: return "\u212C"; // &Bscr - case 554: return "\uD835\uDCB7"; // &bscr - case 557: return "\u204F"; // &bsemi - case 559: return "\u223D"; // &bsim - case 560: return "\u22CD"; // &bsime - case 562: return "\u005C"; // &bsol - case 563: return "\u29C5"; // &bsolb - case 567: return "\u27C8"; // &bsolhsub - case 570: return "\u2022"; // &bull - case 572: return "\u2022"; // &bullet - case 574: return "\u224E"; // &bump - case 575: return "\u2AAE"; // &bumpE - case 576: return "\u224F"; // &bumpe - case 581: return "\u224E"; // &Bumpeq - case 582: return "\u224F"; // &bumpeq - case 588: return "\u0106"; // &Cacute - case 594: return "\u0107"; // &cacute - case 595: return "\u22D2"; // &Cap - case 596: return "\u2229"; // &cap - case 599: return "\u2A44"; // &capand - case 604: return "\u2A49"; // &capbrcup - case 607: return "\u2A4B"; // &capcap - case 609: return "\u2A47"; // &capcup - case 612: return "\u2A40"; // &capdot - case 629: return "\u2145"; // &CapitalDifferentialD - case 630: return "\u2229\uFE00"; // &caps - case 633: return "\u2041"; // &caret - case 635: return "\u02C7"; // &caron - case 640: return "\u212D"; // &Cayleys - case 644: return "\u2A4D"; // &ccaps - case 649: return "\u010C"; // &Ccaron - case 652: return "\u010D"; // &ccaron - case 656: return "\u00C7"; // Ç - case 660: return "\u00E7"; // ç - case 663: return "\u0108"; // &Ccirc - case 666: return "\u0109"; // &ccirc - case 671: return "\u2230"; // &Cconint - case 674: return "\u2A4C"; // &ccups - case 676: return "\u2A50"; // &ccupssm - case 679: return "\u010A"; // &Cdot - case 682: return "\u010B"; // &cdot - case 686: return "\u00B8"; // ¸ - case 692: return "\u00B8"; // &Cedilla - case 697: return "\u29B2"; // &cemptyv - case 699: return "\u00A2"; // ¢ - case 706: return "\u00B7"; // &CenterDot - case 711: return "\u00B7"; // ¢erdot - case 713: return "\u212D"; // &Cfr - case 715: return "\uD835\uDD20"; // &cfr - case 718: return "\u0427"; // &CHcy - case 721: return "\u0447"; // &chcy - case 724: return "\u2713"; // &check - case 728: return "\u2713"; // &checkmark - case 730: return "\u03A7"; // &Chi - case 731: return "\u03C7"; // &chi - case 733: return "\u25CB"; // &cir - case 734: return "\u02C6"; // &circ - case 736: return "\u2257"; // &circeq - case 747: return "\u21BA"; // &circlearrowleft - case 752: return "\u21BB"; // &circlearrowright - case 756: return "\u229B"; // &circledast - case 760: return "\u229A"; // &circledcirc - case 764: return "\u229D"; // &circleddash - case 772: return "\u2299"; // &CircleDot - case 773: return "\u00AE"; // &circledR - case 774: return "\u24C8"; // &circledS - case 779: return "\u2296"; // &CircleMinus - case 783: return "\u2295"; // &CirclePlus - case 788: return "\u2297"; // &CircleTimes - case 789: return "\u29C3"; // &cirE - case 790: return "\u2257"; // &cire - case 795: return "\u2A10"; // &cirfnint - case 798: return "\u2AEF"; // &cirmid - case 802: return "\u29C2"; // &cirscir - case 825: return "\u2232"; // &ClockwiseContourIntegral - case 843: return "\u201D"; // &CloseCurlyDoubleQuote - case 848: return "\u2019"; // &CloseCurlyQuote - case 852: return "\u2663"; // &clubs - case 855: return "\u2663"; // &clubsuit - case 859: return "\u2237"; // &Colon - case 863: return "\u003A"; // &colon - case 864: return "\u2A74"; // &Colone - case 865: return "\u2254"; // &colone - case 866: return "\u2254"; // &coloneq - case 869: return "\u002C"; // &comma - case 870: return "\u0040"; // &commat - case 871: return "\u2201"; // &comp - case 873: return "\u2218"; // &compfn - case 879: return "\u2201"; // &complement - case 882: return "\u2102"; // &complexes - case 884: return "\u2245"; // &cong - case 887: return "\u2A6D"; // &congdot - case 894: return "\u2261"; // &Congruent - case 897: return "\u222F"; // &Conint - case 900: return "\u222E"; // &conint - case 912: return "\u222E"; // &ContourIntegral - case 914: return "\u2102"; // &Copf - case 916: return "\uD835\uDD54"; // &copf - case 919: return "\u2210"; // &coprod - case 925: return "\u2210"; // &Coproduct - case 928: return "\u00A9"; // © - case 929: return "\u00A9"; // © - case 931: return "\u2117"; // ©sr - case 960: return "\u2233"; // &CounterClockwiseContourIntegral - case 964: return "\u21B5"; // &crarr - case 968: return "\u2A2F"; // &Cross - case 971: return "\u2717"; // &cross - case 974: return "\uD835\uDC9E"; // &Cscr - case 977: return "\uD835\uDCB8"; // &cscr - case 979: return "\u2ACF"; // &csub - case 980: return "\u2AD1"; // &csube - case 981: return "\u2AD0"; // &csup - case 982: return "\u2AD2"; // &csupe - case 986: return "\u22EF"; // &ctdot - case 992: return "\u2938"; // &cudarrl - case 993: return "\u2935"; // &cudarrr - case 996: return "\u22DE"; // &cuepr - case 998: return "\u22DF"; // &cuesc - case 1002: return "\u21B6"; // &cularr - case 1003: return "\u293D"; // &cularrp - case 1005: return "\u22D3"; // &Cup - case 1006: return "\u222A"; // &cup - case 1011: return "\u2A48"; // &cupbrcap - case 1014: return "\u224D"; // &CupCap - case 1017: return "\u2A46"; // &cupcap - case 1019: return "\u2A4A"; // &cupcup - case 1022: return "\u228D"; // &cupdot - case 1024: return "\u2A45"; // &cupor - case 1025: return "\u222A\uFE00"; // &cups - case 1029: return "\u21B7"; // &curarr - case 1030: return "\u293C"; // &curarrm - case 1038: return "\u22DE"; // &curlyeqprec - case 1042: return "\u22DF"; // &curlyeqsucc - case 1045: return "\u22CE"; // &curlyvee - case 1050: return "\u22CF"; // &curlywedge - case 1053: return "\u00A4"; // ¤ - case 1064: return "\u21B6"; // &curvearrowleft - case 1069: return "\u21B7"; // &curvearrowright - case 1072: return "\u22CE"; // &cuvee - case 1075: return "\u22CF"; // &cuwed - case 1082: return "\u2232"; // &cwconint - case 1085: return "\u2231"; // &cwint - case 1090: return "\u232D"; // &cylcty - case 1096: return "\u2021"; // &Dagger - case 1102: return "\u2020"; // &dagger - case 1106: return "\u2138"; // &daleth - case 1108: return "\u21A1"; // &Darr - case 1111: return "\u21D3"; // &dArr - case 1113: return "\u2193"; // &darr - case 1115: return "\u2010"; // &dash - case 1118: return "\u2AE4"; // &Dashv - case 1119: return "\u22A3"; // &dashv - case 1125: return "\u290F"; // &dbkarow - case 1128: return "\u02DD"; // &dblac - case 1133: return "\u010E"; // &Dcaron - case 1138: return "\u010F"; // &dcaron - case 1139: return "\u0414"; // &Dcy - case 1140: return "\u0434"; // &dcy - case 1141: return "\u2145"; // &DD - case 1142: return "\u2146"; // &dd - case 1147: return "\u2021"; // &ddagger - case 1149: return "\u21CA"; // &ddarr - case 1155: return "\u2911"; // &DDotrahd - case 1160: return "\u2A77"; // &ddotseq - case 1162: return "\u00B0"; // ° - case 1164: return "\u2207"; // &Del - case 1166: return "\u0394"; // &Delta - case 1169: return "\u03B4"; // &delta - case 1174: return "\u29B1"; // &demptyv - case 1179: return "\u297F"; // &dfisht - case 1181: return "\uD835\uDD07"; // &Dfr - case 1182: return "\uD835\uDD21"; // &dfr - case 1185: return "\u2965"; // &dHar - case 1189: return "\u21C3"; // &dharl - case 1190: return "\u21C2"; // &dharr - case 1205: return "\u00B4"; // &DiacriticalAcute - case 1208: return "\u02D9"; // &DiacriticalDot - case 1217: return "\u02DD"; // &DiacriticalDoubleAcute - case 1222: return "\u0060"; // &DiacriticalGrave - case 1227: return "\u02DC"; // &DiacriticalTilde - case 1230: return "\u22C4"; // &diam - case 1234: return "\u22C4"; // &Diamond - case 1237: return "\u22C4"; // &diamond - case 1241: return "\u2666"; // &diamondsuit - case 1242: return "\u2666"; // &diams - case 1243: return "\u00A8"; // &die - case 1254: return "\u2146"; // &DifferentialD - case 1259: return "\u03DD"; // &digamma - case 1262: return "\u22F2"; // &disin - case 1263: return "\u00F7"; // &div - case 1266: return "\u00F7"; // ÷ - case 1273: return "\u22C7"; // ÷ontimes - case 1276: return "\u22C7"; // &divonx - case 1279: return "\u0402"; // &DJcy - case 1282: return "\u0452"; // &djcy - case 1287: return "\u231E"; // &dlcorn - case 1290: return "\u230D"; // &dlcrop - case 1295: return "\u0024"; // &dollar - case 1298: return "\uD835\uDD3B"; // &Dopf - case 1300: return "\uD835\uDD55"; // &dopf - case 1301: return "\u00A8"; // &Dot - case 1302: return "\u02D9"; // &dot - case 1305: return "\u20DC"; // &DotDot - case 1307: return "\u2250"; // &doteq - case 1310: return "\u2251"; // &doteqdot - case 1315: return "\u2250"; // &DotEqual - case 1320: return "\u2238"; // &dotminus - case 1324: return "\u2214"; // &dotplus - case 1330: return "\u22A1"; // &dotsquare - case 1342: return "\u2306"; // &doublebarwedge - case 1361: return "\u222F"; // &DoubleContourIntegral - case 1364: return "\u00A8"; // &DoubleDot - case 1371: return "\u21D3"; // &DoubleDownArrow - case 1380: return "\u21D0"; // &DoubleLeftArrow - case 1390: return "\u21D4"; // &DoubleLeftRightArrow - case 1393: return "\u2AE4"; // &DoubleLeftTee - case 1405: return "\u27F8"; // &DoubleLongLeftArrow - case 1415: return "\u27FA"; // &DoubleLongLeftRightArrow - case 1425: return "\u27F9"; // &DoubleLongRightArrow - case 1435: return "\u21D2"; // &DoubleRightArrow - case 1438: return "\u22A8"; // &DoubleRightTee - case 1445: return "\u21D1"; // &DoubleUpArrow - case 1454: return "\u21D5"; // &DoubleUpDownArrow - case 1465: return "\u2225"; // &DoubleVerticalBar - case 1472: return "\u2193"; // &DownArrow - case 1477: return "\u21D3"; // &Downarrow - case 1484: return "\u2193"; // &downarrow - case 1487: return "\u2913"; // &DownArrowBar - case 1494: return "\u21F5"; // &DownArrowUpArrow - case 1499: return "\u0311"; // &DownBreve - case 1509: return "\u21CA"; // &downdownarrows - case 1520: return "\u21C3"; // &downharpoonleft - case 1525: return "\u21C2"; // &downharpoonright - case 1540: return "\u2950"; // &DownLeftRightVector - case 1549: return "\u295E"; // &DownLeftTeeVector - case 1555: return "\u21BD"; // &DownLeftVector - case 1558: return "\u2956"; // &DownLeftVectorBar - case 1572: return "\u295F"; // &DownRightTeeVector - case 1578: return "\u21C1"; // &DownRightVector - case 1581: return "\u2957"; // &DownRightVectorBar - case 1584: return "\u22A4"; // &DownTee - case 1589: return "\u21A7"; // &DownTeeArrow - case 1596: return "\u2910"; // &drbkarow - case 1600: return "\u231F"; // &drcorn - case 1603: return "\u230C"; // &drcrop - case 1606: return "\uD835\uDC9F"; // &Dscr - case 1609: return "\uD835\uDCB9"; // &dscr - case 1612: return "\u0405"; // &DScy - case 1613: return "\u0455"; // &dscy - case 1615: return "\u29F6"; // &dsol - case 1619: return "\u0110"; // &Dstrok - case 1623: return "\u0111"; // &dstrok - case 1627: return "\u22F1"; // &dtdot - case 1629: return "\u25BF"; // &dtri - case 1630: return "\u25BE"; // &dtrif - case 1634: return "\u21F5"; // &duarr - case 1637: return "\u296F"; // &duhar - case 1643: return "\u29A6"; // &dwangle - case 1646: return "\u040F"; // &DZcy - case 1649: return "\u045F"; // &dzcy - case 1655: return "\u27FF"; // &dzigrarr - case 1661: return "\u00C9"; // É - case 1667: return "\u00E9"; // é - case 1671: return "\u2A6E"; // &easter - case 1676: return "\u011A"; // &Ecaron - case 1681: return "\u011B"; // &ecaron - case 1683: return "\u2256"; // &ecir - case 1686: return "\u00CA"; // Ê - case 1687: return "\u00EA"; // ê - case 1691: return "\u2255"; // &ecolon - case 1692: return "\u042D"; // &Ecy - case 1693: return "\u044D"; // &ecy - case 1697: return "\u2A77"; // &eDDot - case 1700: return "\u0116"; // &Edot - case 1702: return "\u2251"; // &eDot - case 1705: return "\u0117"; // &edot - case 1706: return "\u2147"; // &ee - case 1710: return "\u2252"; // &efDot - case 1712: return "\uD835\uDD08"; // &Efr - case 1713: return "\uD835\uDD22"; // &efr - case 1714: return "\u2A9A"; // &eg - case 1719: return "\u00C8"; // È - case 1723: return "\u00E8"; // è - case 1724: return "\u2A96"; // &egs - case 1727: return "\u2A98"; // &egsdot - case 1728: return "\u2A99"; // &el - case 1734: return "\u2208"; // &Element - case 1740: return "\u23E7"; // &elinters - case 1741: return "\u2113"; // &ell - case 1742: return "\u2A95"; // &els - case 1745: return "\u2A97"; // &elsdot - case 1749: return "\u0112"; // &Emacr - case 1753: return "\u0113"; // &emacr - case 1756: return "\u2205"; // &empty - case 1759: return "\u2205"; // &emptyset - case 1773: return "\u25FB"; // &EmptySmallSquare - case 1774: return "\u2205"; // &emptyv - case 1789: return "\u25AB"; // &EmptyVerySmallSquare - case 1791: return "\u2003"; // &emsp - case 1793: return "\u2004"; // &emsp13 - case 1794: return "\u2005"; // &emsp14 - case 1796: return "\u014A"; // &ENG - case 1798: return "\u014B"; // &eng - case 1800: return "\u2002"; // &ensp - case 1804: return "\u0118"; // &Eogon - case 1808: return "\u0119"; // &eogon - case 1810: return "\uD835\uDD3C"; // &Eopf - case 1812: return "\uD835\uDD56"; // &eopf - case 1815: return "\u22D5"; // &epar - case 1817: return "\u29E3"; // &eparsl - case 1820: return "\u2A71"; // &eplus - case 1822: return "\u03B5"; // &epsi - case 1828: return "\u0395"; // &Epsilon - case 1831: return "\u03B5"; // &epsilon - case 1832: return "\u03F5"; // &epsiv - case 1837: return "\u2256"; // &eqcirc - case 1841: return "\u2255"; // &eqcolon - case 1844: return "\u2242"; // &eqsim - case 1851: return "\u2A96"; // &eqslantgtr - case 1855: return "\u2A95"; // &eqslantless - case 1859: return "\u2A75"; // &Equal - case 1863: return "\u003D"; // &equals - case 1868: return "\u2242"; // &EqualTilde - case 1871: return "\u225F"; // &equest - case 1879: return "\u21CC"; // &Equilibrium - case 1881: return "\u2261"; // &equiv - case 1883: return "\u2A78"; // &equivDD - case 1889: return "\u29E5"; // &eqvparsl - case 1893: return "\u2971"; // &erarr - case 1896: return "\u2253"; // &erDot - case 1899: return "\u2130"; // &Escr - case 1902: return "\u212F"; // &escr - case 1905: return "\u2250"; // &esdot - case 1907: return "\u2A73"; // &Esim - case 1909: return "\u2242"; // &esim - case 1911: return "\u0397"; // &Eta - case 1913: return "\u03B7"; // &eta - case 1915: return "\u00D0"; // Ð - case 1916: return "\u00F0"; // ð - case 1919: return "\u00CB"; // Ë - case 1922: return "\u00EB"; // ë - case 1924: return "\u20AC"; // &euro - case 1927: return "\u0021"; // &excl - case 1930: return "\u2203"; // &exist - case 1935: return "\u2203"; // &Exists - case 1944: return "\u2130"; // &expectation - case 1954: return "\u2147"; // &ExponentialE - case 1963: return "\u2147"; // &exponentiale - case 1976: return "\u2252"; // &fallingdotseq - case 1979: return "\u0424"; // &Fcy - case 1981: return "\u0444"; // &fcy - case 1986: return "\u2640"; // &female - case 1991: return "\uFB03"; // &ffilig - case 1994: return "\uFB00"; // &fflig - case 1997: return "\uFB04"; // &ffllig - case 1999: return "\uD835\uDD09"; // &Ffr - case 2000: return "\uD835\uDD23"; // &ffr - case 2004: return "\uFB01"; // &filig - case 2020: return "\u25FC"; // &FilledSmallSquare - case 2035: return "\u25AA"; // &FilledVerySmallSquare - case 2039: return "\u0066\u006A"; // &fjlig - case 2042: return "\u266D"; // &flat - case 2045: return "\uFB02"; // &fllig - case 2048: return "\u25B1"; // &fltns - case 2051: return "\u0192"; // &fnof - case 2054: return "\uD835\uDD3D"; // &Fopf - case 2057: return "\uD835\uDD57"; // &fopf - case 2061: return "\u2200"; // &ForAll - case 2065: return "\u2200"; // &forall - case 2066: return "\u22D4"; // &fork - case 2067: return "\u2AD9"; // &forkv - case 2075: return "\u2131"; // &Fouriertrf - case 2082: return "\u2A0D"; // &fpartint - case 2087: return "\u00BD"; // ½ - case 2088: return "\u2153"; // &frac13 - case 2089: return "\u00BC"; // ¼ - case 2090: return "\u2155"; // &frac15 - case 2091: return "\u2159"; // &frac16 - case 2092: return "\u215B"; // &frac18 - case 2094: return "\u2154"; // &frac23 - case 2095: return "\u2156"; // &frac25 - case 2097: return "\u00BE"; // ¾ - case 2098: return "\u2157"; // &frac35 - case 2099: return "\u215C"; // &frac38 - case 2101: return "\u2158"; // &frac45 - case 2103: return "\u215A"; // &frac56 - case 2104: return "\u215D"; // &frac58 - case 2106: return "\u215E"; // &frac78 - case 2108: return "\u2044"; // &frasl - case 2111: return "\u2322"; // &frown - case 2114: return "\u2131"; // &Fscr - case 2117: return "\uD835\uDCBB"; // &fscr - case 2123: return "\u01F5"; // &gacute - case 2128: return "\u0393"; // &Gamma - case 2131: return "\u03B3"; // &gamma - case 2132: return "\u03DC"; // &Gammad - case 2133: return "\u03DD"; // &gammad - case 2134: return "\u2A86"; // &gap - case 2139: return "\u011E"; // &Gbreve - case 2144: return "\u011F"; // &gbreve - case 2149: return "\u0122"; // &Gcedil - case 2152: return "\u011C"; // &Gcirc - case 2156: return "\u011D"; // &gcirc - case 2157: return "\u0413"; // &Gcy - case 2158: return "\u0433"; // &gcy - case 2161: return "\u0120"; // &Gdot - case 2164: return "\u0121"; // &gdot - case 2165: return "\u2267"; // &gE - case 2166: return "\u2265"; // &ge - case 2167: return "\u2A8C"; // &gEl - case 2168: return "\u22DB"; // &gel - case 2169: return "\u2265"; // &geq - case 2170: return "\u2267"; // &geqq - case 2175: return "\u2A7E"; // &geqslant - case 2176: return "\u2A7E"; // &ges - case 2178: return "\u2AA9"; // &gescc - case 2181: return "\u2A80"; // &gesdot - case 2182: return "\u2A82"; // &gesdoto - case 2183: return "\u2A84"; // &gesdotol - case 2184: return "\u22DB\uFE00"; // &gesl - case 2186: return "\u2A94"; // &gesles - case 2188: return "\uD835\uDD0A"; // &Gfr - case 2190: return "\uD835\uDD24"; // &gfr - case 2191: return "\u22D9"; // &Gg - case 2192: return "\u226B"; // &gg - case 2193: return "\u22D9"; // &ggg - case 2197: return "\u2137"; // &gimel - case 2200: return "\u0403"; // &GJcy - case 2203: return "\u0453"; // &gjcy - case 2204: return "\u2277"; // &gl - case 2205: return "\u2AA5"; // &gla - case 2206: return "\u2A92"; // &glE - case 2207: return "\u2AA4"; // &glj - case 2210: return "\u2A8A"; // &gnap - case 2214: return "\u2A8A"; // &gnapprox - case 2215: return "\u2269"; // &gnE - case 2216: return "\u2A88"; // &gne - case 2217: return "\u2A88"; // &gneq - case 2218: return "\u2269"; // &gneqq - case 2221: return "\u22E7"; // &gnsim - case 2224: return "\uD835\uDD3E"; // &Gopf - case 2227: return "\uD835\uDD58"; // &gopf - case 2231: return "\u0060"; // &grave - case 2242: return "\u2265"; // &GreaterEqual - case 2246: return "\u22DB"; // &GreaterEqualLess - case 2255: return "\u2267"; // &GreaterFullEqual - case 2262: return "\u2AA2"; // &GreaterGreater - case 2266: return "\u2277"; // &GreaterLess - case 2276: return "\u2A7E"; // &GreaterSlantEqual - case 2281: return "\u2273"; // &GreaterTilde - case 2284: return "\uD835\uDCA2"; // &Gscr - case 2287: return "\u210A"; // &gscr - case 2289: return "\u2273"; // &gsim - case 2290: return "\u2A8E"; // &gsime - case 2291: return "\u2A90"; // &gsiml - case 2292: return "\u003E"; // > - case 2293: return "\u226B"; // &Gt - case 2294: return "\u003E"; // > - case 2296: return "\u2AA7"; // >cc - case 2298: return "\u2A7A"; // >cir - case 2301: return "\u22D7"; // >dot - case 2305: return "\u2995"; // >lPar - case 2310: return "\u2A7C"; // >quest - case 2317: return "\u2A86"; // >rapprox - case 2319: return "\u2978"; // >rarr - case 2322: return "\u22D7"; // >rdot - case 2328: return "\u22DB"; // >reqless - case 2333: return "\u2A8C"; // >reqqless - case 2337: return "\u2277"; // >rless - case 2340: return "\u2273"; // >rsim - case 2348: return "\u2269\uFE00"; // &gvertneqq - case 2350: return "\u2269\uFE00"; // &gvnE - case 2355: return "\u02C7"; // &Hacek - case 2361: return "\u200A"; // &hairsp - case 2363: return "\u00BD"; // &half - case 2367: return "\u210B"; // &hamilt - case 2372: return "\u042A"; // &HARDcy - case 2376: return "\u044A"; // &hardcy - case 2379: return "\u21D4"; // &hArr - case 2380: return "\u2194"; // &harr - case 2383: return "\u2948"; // &harrcir - case 2384: return "\u21AD"; // &harrw - case 2385: return "\u005E"; // &Hat - case 2388: return "\u210F"; // &hbar - case 2392: return "\u0124"; // &Hcirc - case 2396: return "\u0125"; // &hcirc - case 2401: return "\u2665"; // &hearts - case 2404: return "\u2665"; // &heartsuit - case 2408: return "\u2026"; // &hellip - case 2412: return "\u22B9"; // &hercon - case 2414: return "\u210C"; // &Hfr - case 2416: return "\uD835\uDD25"; // &hfr - case 2427: return "\u210B"; // &HilbertSpace - case 2434: return "\u2925"; // &hksearow - case 2439: return "\u2926"; // &hkswarow - case 2443: return "\u21FF"; // &hoarr - case 2447: return "\u223B"; // &homtht - case 2458: return "\u21A9"; // &hookleftarrow - case 2468: return "\u21AA"; // &hookrightarrow - case 2471: return "\u210D"; // &Hopf - case 2473: return "\uD835\uDD59"; // &hopf - case 2477: return "\u2015"; // &horbar - case 2489: return "\u2500"; // &HorizontalLine - case 2492: return "\u210B"; // &Hscr - case 2495: return "\uD835\uDCBD"; // &hscr - case 2499: return "\u210F"; // &hslash - case 2503: return "\u0126"; // &Hstrok - case 2507: return "\u0127"; // &hstrok - case 2518: return "\u224E"; // &HumpDownHump - case 2523: return "\u224F"; // &HumpEqual - case 2528: return "\u2043"; // &hybull - case 2532: return "\u2010"; // &hyphen - case 2538: return "\u00CD"; // Í - case 2544: return "\u00ED"; // í - case 2545: return "\u2063"; // &ic - case 2549: return "\u00CE"; // Î - case 2552: return "\u00EE"; // î - case 2553: return "\u0418"; // &Icy - case 2554: return "\u0438"; // &icy - case 2557: return "\u0130"; // &Idot - case 2560: return "\u0415"; // &IEcy - case 2563: return "\u0435"; // &iecy - case 2566: return "\u00A1"; // ¡ - case 2568: return "\u21D4"; // &iff - case 2570: return "\u2111"; // &Ifr - case 2571: return "\uD835\uDD26"; // &ifr - case 2576: return "\u00CC"; // Ì - case 2581: return "\u00EC"; // ì - case 2582: return "\u2148"; // &ii - case 2586: return "\u2A0C"; // &iiiint - case 2588: return "\u222D"; // &iiint - case 2592: return "\u29DC"; // &iinfin - case 2595: return "\u2129"; // &iiota - case 2599: return "\u0132"; // &IJlig - case 2603: return "\u0133"; // &ijlig - case 2604: return "\u2111"; // &Im - case 2607: return "\u012A"; // &Imacr - case 2611: return "\u012B"; // &imacr - case 2613: return "\u2111"; // &image - case 2620: return "\u2148"; // &ImaginaryI - case 2624: return "\u2110"; // &imagline - case 2628: return "\u2111"; // &imagpart - case 2630: return "\u0131"; // &imath - case 2632: return "\u22B7"; // &imof - case 2635: return "\u01B5"; // &imped - case 2640: return "\u21D2"; // &Implies - case 2641: return "\u2208"; // &in - case 2645: return "\u2105"; // &incare - case 2648: return "\u221E"; // &infin - case 2651: return "\u29DD"; // &infintie - case 2655: return "\u0131"; // &inodot - case 2657: return "\u222C"; // &Int - case 2658: return "\u222B"; // &int - case 2661: return "\u22BA"; // &intcal - case 2666: return "\u2124"; // &integers - case 2671: return "\u222B"; // &Integral - case 2675: return "\u22BA"; // &intercal - case 2683: return "\u22C2"; // &Intersection - case 2688: return "\u2A17"; // &intlarhk - case 2692: return "\u2A3C"; // &intprod - case 2704: return "\u2063"; // &InvisibleComma - case 2709: return "\u2062"; // &InvisibleTimes - case 2712: return "\u0401"; // &IOcy - case 2715: return "\u0451"; // &iocy - case 2719: return "\u012E"; // &Iogon - case 2722: return "\u012F"; // &iogon - case 2724: return "\uD835\uDD40"; // &Iopf - case 2726: return "\uD835\uDD5A"; // &iopf - case 2728: return "\u0399"; // &Iota - case 2730: return "\u03B9"; // &iota - case 2734: return "\u2A3C"; // &iprod - case 2739: return "\u00BF"; // ¿ - case 2742: return "\u2110"; // &Iscr - case 2745: return "\uD835\uDCBE"; // &iscr - case 2747: return "\u2208"; // &isin - case 2750: return "\u22F5"; // &isindot - case 2751: return "\u22F9"; // &isinE - case 2752: return "\u22F4"; // &isins - case 2753: return "\u22F3"; // &isinsv - case 2754: return "\u2208"; // &isinv - case 2755: return "\u2062"; // &it - case 2760: return "\u0128"; // &Itilde - case 2764: return "\u0129"; // &itilde - case 2768: return "\u0406"; // &Iukcy - case 2772: return "\u0456"; // &iukcy - case 2774: return "\u00CF"; // Ï - case 2776: return "\u00EF"; // ï - case 2781: return "\u0134"; // &Jcirc - case 2786: return "\u0135"; // &jcirc - case 2787: return "\u0419"; // &Jcy - case 2788: return "\u0439"; // &jcy - case 2790: return "\uD835\uDD0D"; // &Jfr - case 2792: return "\uD835\uDD27"; // &jfr - case 2796: return "\u0237"; // &jmath - case 2799: return "\uD835\uDD41"; // &Jopf - case 2802: return "\uD835\uDD5B"; // &jopf - case 2805: return "\uD835\uDCA5"; // &Jscr - case 2808: return "\uD835\uDCBF"; // &jscr - case 2812: return "\u0408"; // &Jsercy - case 2816: return "\u0458"; // &jsercy - case 2820: return "\u0404"; // &Jukcy - case 2824: return "\u0454"; // &jukcy - case 2829: return "\u039A"; // &Kappa - case 2834: return "\u03BA"; // &kappa - case 2835: return "\u03F0"; // &kappav - case 2840: return "\u0136"; // &Kcedil - case 2845: return "\u0137"; // &kcedil - case 2846: return "\u041A"; // &Kcy - case 2847: return "\u043A"; // &kcy - case 2849: return "\uD835\uDD0E"; // &Kfr - case 2851: return "\uD835\uDD28"; // &kfr - case 2856: return "\u0138"; // &kgreen - case 2859: return "\u0425"; // &KHcy - case 2862: return "\u0445"; // &khcy - case 2865: return "\u040C"; // &KJcy - case 2868: return "\u045C"; // &kjcy - case 2871: return "\uD835\uDD42"; // &Kopf - case 2874: return "\uD835\uDD5C"; // &kopf - case 2877: return "\uD835\uDCA6"; // &Kscr - case 2880: return "\uD835\uDCC0"; // &kscr - case 2885: return "\u21DA"; // &lAarr - case 2891: return "\u0139"; // &Lacute - case 2896: return "\u013A"; // &lacute - case 2902: return "\u29B4"; // &laemptyv - case 2906: return "\u2112"; // &lagran - case 2910: return "\u039B"; // &Lambda - case 2914: return "\u03BB"; // &lambda - case 2916: return "\u27EA"; // &Lang - case 2918: return "\u27E8"; // &lang - case 2919: return "\u2991"; // &langd - case 2921: return "\u27E8"; // &langle - case 2922: return "\u2A85"; // &lap - case 2930: return "\u2112"; // &Laplacetrf - case 2933: return "\u00AB"; // « - case 2935: return "\u219E"; // &Larr - case 2937: return "\u21D0"; // &lArr - case 2939: return "\u2190"; // &larr - case 2940: return "\u21E4"; // &larrb - case 2942: return "\u291F"; // &larrbfs - case 2944: return "\u291D"; // &larrfs - case 2946: return "\u21A9"; // &larrhk - case 2948: return "\u21AB"; // &larrlp - case 2950: return "\u2939"; // &larrpl - case 2953: return "\u2973"; // &larrsim - case 2955: return "\u21A2"; // &larrtl - case 2956: return "\u2AAB"; // &lat - case 2960: return "\u291B"; // &lAtail - case 2963: return "\u2919"; // &latail - case 2964: return "\u2AAD"; // &late - case 2965: return "\u2AAD\uFE00"; // &lates - case 2969: return "\u290E"; // &lBarr - case 2973: return "\u290C"; // &lbarr - case 2976: return "\u2772"; // &lbbrk - case 2980: return "\u007B"; // &lbrace - case 2981: return "\u005B"; // &lbrack - case 2983: return "\u298B"; // &lbrke - case 2986: return "\u298F"; // &lbrksld - case 2987: return "\u298D"; // &lbrkslu - case 2992: return "\u013D"; // &Lcaron - case 2997: return "\u013E"; // &lcaron - case 3001: return "\u013B"; // &Lcedil - case 3005: return "\u013C"; // &lcedil - case 3007: return "\u2308"; // &lceil - case 3009: return "\u007B"; // &lcub - case 3010: return "\u041B"; // &Lcy - case 3011: return "\u043B"; // &lcy - case 3014: return "\u2936"; // &ldca - case 3017: return "\u201C"; // &ldquo - case 3018: return "\u201E"; // &ldquor - case 3023: return "\u2967"; // &ldrdhar - case 3028: return "\u294B"; // &ldrushar - case 3030: return "\u21B2"; // &ldsh - case 3031: return "\u2266"; // &lE - case 3032: return "\u2264"; // &le - case 3047: return "\u27E8"; // &LeftAngleBracket - case 3051: return "\u2190"; // &LeftArrow - case 3056: return "\u21D0"; // &Leftarrow - case 3063: return "\u2190"; // &leftarrow - case 3066: return "\u21E4"; // &LeftArrowBar - case 3076: return "\u21C6"; // &LeftArrowRightArrow - case 3080: return "\u21A2"; // &leftarrowtail - case 3087: return "\u2308"; // &LeftCeiling - case 3100: return "\u27E6"; // &LeftDoubleBracket - case 3111: return "\u2961"; // &LeftDownTeeVector - case 3117: return "\u21C3"; // &LeftDownVector - case 3120: return "\u2959"; // &LeftDownVectorBar - case 3125: return "\u230A"; // &LeftFloor - case 3136: return "\u21BD"; // &leftharpoondown - case 3138: return "\u21BC"; // &leftharpoonup - case 3148: return "\u21C7"; // &leftleftarrows - case 3158: return "\u2194"; // &LeftRightArrow - case 3168: return "\u21D4"; // &Leftrightarrow - case 3178: return "\u2194"; // &leftrightarrow - case 3179: return "\u21C6"; // &leftrightarrows - case 3187: return "\u21CB"; // &leftrightharpoons - case 3197: return "\u21AD"; // &leftrightsquigarrow - case 3203: return "\u294E"; // &LeftRightVector - case 3206: return "\u22A3"; // &LeftTee - case 3211: return "\u21A4"; // &LeftTeeArrow - case 3217: return "\u295A"; // &LeftTeeVector - case 3227: return "\u22CB"; // &leftthreetimes - case 3234: return "\u22B2"; // &LeftTriangle - case 3237: return "\u29CF"; // &LeftTriangleBar - case 3242: return "\u22B4"; // &LeftTriangleEqual - case 3254: return "\u2951"; // &LeftUpDownVector - case 3263: return "\u2960"; // &LeftUpTeeVector - case 3269: return "\u21BF"; // &LeftUpVector - case 3272: return "\u2958"; // &LeftUpVectorBar - case 3278: return "\u21BC"; // &LeftVector - case 3281: return "\u2952"; // &LeftVectorBar - case 3282: return "\u2A8B"; // &lEg - case 3283: return "\u22DA"; // &leg - case 3284: return "\u2264"; // &leq - case 3285: return "\u2266"; // &leqq - case 3290: return "\u2A7D"; // &leqslant - case 3291: return "\u2A7D"; // &les - case 3293: return "\u2AA8"; // &lescc - case 3296: return "\u2A7F"; // &lesdot - case 3297: return "\u2A81"; // &lesdoto - case 3298: return "\u2A83"; // &lesdotor - case 3299: return "\u22DA\uFE00"; // &lesg - case 3301: return "\u2A93"; // &lesges - case 3308: return "\u2A85"; // &lessapprox - case 3311: return "\u22D6"; // &lessdot - case 3316: return "\u22DA"; // &lesseqgtr - case 3320: return "\u2A8B"; // &lesseqqgtr - case 3334: return "\u22DA"; // &LessEqualGreater - case 3343: return "\u2266"; // &LessFullEqual - case 3350: return "\u2276"; // &LessGreater - case 3353: return "\u2276"; // &lessgtr - case 3357: return "\u2AA1"; // &LessLess - case 3360: return "\u2272"; // &lesssim - case 3370: return "\u2A7D"; // &LessSlantEqual - case 3375: return "\u2272"; // &LessTilde - case 3380: return "\u297C"; // &lfisht - case 3384: return "\u230A"; // &lfloor - case 3386: return "\uD835\uDD0F"; // &Lfr - case 3387: return "\uD835\uDD29"; // &lfr - case 3388: return "\u2276"; // &lg - case 3389: return "\u2A91"; // &lgE - case 3392: return "\u2962"; // &lHar - case 3396: return "\u21BD"; // &lhard - case 3397: return "\u21BC"; // &lharu - case 3398: return "\u296A"; // &lharul - case 3401: return "\u2584"; // &lhblk - case 3404: return "\u0409"; // &LJcy - case 3407: return "\u0459"; // &ljcy - case 3408: return "\u22D8"; // &Ll - case 3409: return "\u226A"; // &ll - case 3412: return "\u21C7"; // &llarr - case 3418: return "\u231E"; // &llcorner - case 3426: return "\u21DA"; // &Lleftarrow - case 3430: return "\u296B"; // &llhard - case 3433: return "\u25FA"; // &lltri - case 3438: return "\u013F"; // &Lmidot - case 3443: return "\u0140"; // &lmidot - case 3447: return "\u23B0"; // &lmoust - case 3451: return "\u23B0"; // &lmoustache - case 3454: return "\u2A89"; // &lnap - case 3458: return "\u2A89"; // &lnapprox - case 3459: return "\u2268"; // &lnE - case 3460: return "\u2A87"; // &lne - case 3461: return "\u2A87"; // &lneq - case 3462: return "\u2268"; // &lneqq - case 3465: return "\u22E6"; // &lnsim - case 3469: return "\u27EC"; // &loang - case 3471: return "\u21FD"; // &loarr - case 3474: return "\u27E6"; // &lobrk - case 3486: return "\u27F5"; // &LongLeftArrow - case 3495: return "\u27F8"; // &Longleftarrow - case 3506: return "\u27F5"; // &longleftarrow - case 3516: return "\u27F7"; // &LongLeftRightArrow - case 3526: return "\u27FA"; // &Longleftrightarrow - case 3536: return "\u27F7"; // &longleftrightarrow - case 3542: return "\u27FC"; // &longmapsto - case 3552: return "\u27F6"; // &LongRightArrow - case 3562: return "\u27F9"; // &Longrightarrow - case 3572: return "\u27F6"; // &longrightarrow - case 3583: return "\u21AB"; // &looparrowleft - case 3588: return "\u21AC"; // &looparrowright - case 3591: return "\u2985"; // &lopar - case 3593: return "\uD835\uDD43"; // &Lopf - case 3594: return "\uD835\uDD5D"; // &lopf - case 3597: return "\u2A2D"; // &loplus - case 3602: return "\u2A34"; // &lotimes - case 3606: return "\u2217"; // &lowast - case 3609: return "\u005F"; // &lowbar - case 3621: return "\u2199"; // &LowerLeftArrow - case 3631: return "\u2198"; // &LowerRightArrow - case 3632: return "\u25CA"; // &loz - case 3636: return "\u25CA"; // &lozenge - case 3637: return "\u29EB"; // &lozf - case 3640: return "\u0028"; // &lpar - case 3642: return "\u2993"; // &lparlt - case 3646: return "\u21C6"; // &lrarr - case 3652: return "\u231F"; // &lrcorner - case 3655: return "\u21CB"; // &lrhar - case 3656: return "\u296D"; // &lrhard - case 3657: return "\u200E"; // &lrm - case 3660: return "\u22BF"; // &lrtri - case 3665: return "\u2039"; // &lsaquo - case 3668: return "\u2112"; // &Lscr - case 3670: return "\uD835\uDCC1"; // &lscr - case 3671: return "\u21B0"; // &Lsh - case 3672: return "\u21B0"; // &lsh - case 3674: return "\u2272"; // &lsim - case 3675: return "\u2A8D"; // &lsime - case 3676: return "\u2A8F"; // &lsimg - case 3678: return "\u005B"; // &lsqb - case 3680: return "\u2018"; // &lsquo - case 3681: return "\u201A"; // &lsquor - case 3685: return "\u0141"; // &Lstrok - case 3689: return "\u0142"; // &lstrok - case 3690: return "\u003C"; // < - case 3691: return "\u226A"; // &Lt - case 3692: return "\u003C"; // < - case 3694: return "\u2AA6"; // <cc - case 3696: return "\u2A79"; // <cir - case 3699: return "\u22D6"; // <dot - case 3703: return "\u22CB"; // <hree - case 3707: return "\u22C9"; // <imes - case 3711: return "\u2976"; // <larr - case 3716: return "\u2A7B"; // <quest - case 3718: return "\u25C3"; // <ri - case 3719: return "\u22B4"; // <rie - case 3720: return "\u25C2"; // <rif - case 3723: return "\u2996"; // <rPar - case 3730: return "\u294A"; // &lurdshar - case 3734: return "\u2966"; // &luruhar - case 3742: return "\u2268\uFE00"; // &lvertneqq - case 3744: return "\u2268\uFE00"; // &lvnE - case 3748: return "\u00AF"; // ¯ - case 3750: return "\u2642"; // &male - case 3751: return "\u2720"; // &malt - case 3754: return "\u2720"; // &maltese - case 3757: return "\u2905"; // &Map - case 3758: return "\u21A6"; // &map - case 3761: return "\u21A6"; // &mapsto - case 3765: return "\u21A7"; // &mapstodown - case 3769: return "\u21A4"; // &mapstoleft - case 3771: return "\u21A5"; // &mapstoup - case 3775: return "\u25AE"; // &marker - case 3780: return "\u2A29"; // &mcomma - case 3782: return "\u041C"; // &Mcy - case 3783: return "\u043C"; // &mcy - case 3787: return "\u2014"; // &mdash - case 3791: return "\u223A"; // &mDDot - case 3803: return "\u2221"; // &measuredangle - case 3813: return "\u205F"; // &MediumSpace - case 3820: return "\u2133"; // &Mellintrf - case 3822: return "\uD835\uDD10"; // &Mfr - case 3824: return "\uD835\uDD2A"; // &mfr - case 3826: return "\u2127"; // &mho - case 3830: return "\u00B5"; // µ - case 3831: return "\u2223"; // &mid - case 3834: return "\u002A"; // &midast - case 3837: return "\u2AF0"; // &midcir - case 3840: return "\u00B7"; // · - case 3843: return "\u2212"; // &minus - case 3844: return "\u229F"; // &minusb - case 3845: return "\u2238"; // &minusd - case 3846: return "\u2A2A"; // &minusdu - case 3854: return "\u2213"; // &MinusPlus - case 3857: return "\u2ADB"; // &mlcp - case 3859: return "\u2026"; // &mldr - case 3864: return "\u2213"; // &mnplus - case 3869: return "\u22A7"; // &models - case 3872: return "\uD835\uDD44"; // &Mopf - case 3874: return "\uD835\uDD5E"; // &mopf - case 3875: return "\u2213"; // &mp - case 3878: return "\u2133"; // &Mscr - case 3881: return "\uD835\uDCC2"; // &mscr - case 3885: return "\u223E"; // &mstpos - case 3886: return "\u039C"; // &Mu - case 3887: return "\u03BC"; // &mu - case 3893: return "\u22B8"; // &multimap - case 3896: return "\u22B8"; // &mumap - case 3901: return "\u2207"; // &nabla - case 3907: return "\u0143"; // &Nacute - case 3911: return "\u0144"; // &nacute - case 3913: return "\u2220\u20D2"; // &nang - case 3914: return "\u2249"; // &nap - case 3915: return "\u2A70\u0338"; // &napE - case 3917: return "\u224B\u0338"; // &napid - case 3919: return "\u0149"; // &napos - case 3923: return "\u2249"; // &napprox - case 3926: return "\u266E"; // &natur - case 3928: return "\u266E"; // &natural - case 3929: return "\u2115"; // &naturals - case 3932: return "\u00A0"; //   - case 3935: return "\u224E\u0338"; // &nbump - case 3936: return "\u224F\u0338"; // &nbumpe - case 3939: return "\u2A43"; // &ncap - case 3944: return "\u0147"; // &Ncaron - case 3947: return "\u0148"; // &ncaron - case 3951: return "\u0145"; // &Ncedil - case 3955: return "\u0146"; // &ncedil - case 3958: return "\u2247"; // &ncong - case 3961: return "\u2A6D\u0338"; // &ncongdot - case 3963: return "\u2A42"; // &ncup - case 3964: return "\u041D"; // &Ncy - case 3965: return "\u043D"; // &ncy - case 3969: return "\u2013"; // &ndash - case 3970: return "\u2260"; // &ne - case 3974: return "\u2924"; // &nearhk - case 3977: return "\u21D7"; // &neArr - case 3978: return "\u2197"; // &nearr - case 3980: return "\u2197"; // &nearrow - case 3983: return "\u2250\u0338"; // &nedot - case 4001: return "\u200B"; // &NegativeMediumSpace - case 4011: return "\u200B"; // &NegativeThickSpace - case 4017: return "\u200B"; // &NegativeThinSpace - case 4030: return "\u200B"; // &NegativeVeryThinSpace - case 4034: return "\u2262"; // &nequiv - case 4038: return "\u2928"; // &nesear - case 4040: return "\u2242\u0338"; // &nesim - case 4058: return "\u226B"; // &NestedGreaterGreater - case 4066: return "\u226A"; // &NestedLessLess - case 4071: return "\u000A"; // &NewLine - case 4075: return "\u2204"; // &nexist - case 4076: return "\u2204"; // &nexists - case 4078: return "\uD835\uDD11"; // &Nfr - case 4080: return "\uD835\uDD2B"; // &nfr - case 4082: return "\u2267\u0338"; // &ngE - case 4083: return "\u2271"; // &nge - case 4084: return "\u2271"; // &ngeq - case 4085: return "\u2267\u0338"; // &ngeqq - case 4090: return "\u2A7E\u0338"; // &ngeqslant - case 4091: return "\u2A7E\u0338"; // &nges - case 4093: return "\u22D9\u0338"; // &nGg - case 4096: return "\u2275"; // &ngsim - case 4097: return "\u226B\u20D2"; // &nGt - case 4098: return "\u226F"; // &ngt - case 4099: return "\u226F"; // &ngtr - case 4100: return "\u226B\u0338"; // &nGtv - case 4104: return "\u21CE"; // &nhArr - case 4107: return "\u21AE"; // &nharr - case 4110: return "\u2AF2"; // &nhpar - case 4111: return "\u220B"; // &ni - case 4112: return "\u22FC"; // &nis - case 4113: return "\u22FA"; // &nisd - case 4114: return "\u220B"; // &niv - case 4117: return "\u040A"; // &NJcy - case 4120: return "\u045A"; // &njcy - case 4124: return "\u21CD"; // &nlArr - case 4127: return "\u219A"; // &nlarr - case 4129: return "\u2025"; // &nldr - case 4130: return "\u2266\u0338"; // &nlE - case 4131: return "\u2270"; // &nle - case 4140: return "\u21CD"; // &nLeftarrow - case 4147: return "\u219A"; // &nleftarrow - case 4157: return "\u21CE"; // &nLeftrightarrow - case 4167: return "\u21AE"; // &nleftrightarrow - case 4168: return "\u2270"; // &nleq - case 4169: return "\u2266\u0338"; // &nleqq - case 4174: return "\u2A7D\u0338"; // &nleqslant - case 4175: return "\u2A7D\u0338"; // &nles - case 4176: return "\u226E"; // &nless - case 4177: return "\u22D8\u0338"; // &nLl - case 4180: return "\u2274"; // &nlsim - case 4181: return "\u226A\u20D2"; // &nLt - case 4182: return "\u226E"; // &nlt - case 4184: return "\u22EA"; // &nltri - case 4185: return "\u22EC"; // &nltrie - case 4186: return "\u226A\u0338"; // &nLtv - case 4189: return "\u2224"; // &nmid - case 4195: return "\u2060"; // &NoBreak - case 4209: return "\u00A0"; // &NonBreakingSpace - case 4211: return "\u2115"; // &Nopf - case 4214: return "\uD835\uDD5F"; // &nopf - case 4215: return "\u2AEC"; // &Not - case 4216: return "\u00AC"; // ¬ - case 4225: return "\u2262"; // &NotCongruent - case 4230: return "\u226D"; // &NotCupCap - case 4247: return "\u2226"; // &NotDoubleVerticalBar - case 4254: return "\u2209"; // &NotElement - case 4258: return "\u2260"; // &NotEqual - case 4263: return "\u2242\u0338"; // &NotEqualTilde - case 4268: return "\u2204"; // &NotExists - case 4275: return "\u226F"; // &NotGreater - case 4280: return "\u2271"; // &NotGreaterEqual - case 4289: return "\u2267\u0338"; // &NotGreaterFullEqual - case 4296: return "\u226B\u0338"; // &NotGreaterGreater - case 4300: return "\u2279"; // &NotGreaterLess - case 4310: return "\u2A7E\u0338"; // &NotGreaterSlantEqual - case 4315: return "\u2275"; // &NotGreaterTilde - case 4327: return "\u224E\u0338"; // &NotHumpDownHump - case 4332: return "\u224F\u0338"; // &NotHumpEqual - case 4334: return "\u2209"; // ¬in - case 4337: return "\u22F5\u0338"; // ¬indot - case 4338: return "\u22F9\u0338"; // ¬inE - case 4340: return "\u2209"; // ¬inva - case 4341: return "\u22F7"; // ¬invb - case 4342: return "\u22F6"; // ¬invc - case 4354: return "\u22EA"; // &NotLeftTriangle - case 4357: return "\u29CF\u0338"; // &NotLeftTriangleBar - case 4362: return "\u22EC"; // &NotLeftTriangleEqual - case 4364: return "\u226E"; // &NotLess - case 4369: return "\u2270"; // &NotLessEqual - case 4376: return "\u2278"; // &NotLessGreater - case 4380: return "\u226A\u0338"; // &NotLessLess - case 4390: return "\u2A7D\u0338"; // &NotLessSlantEqual - case 4395: return "\u2274"; // &NotLessTilde - case 4415: return "\u2AA2\u0338"; // &NotNestedGreaterGreater - case 4423: return "\u2AA1\u0338"; // &NotNestedLessLess - case 4425: return "\u220C"; // ¬ni - case 4427: return "\u220C"; // ¬niva - case 4428: return "\u22FE"; // ¬nivb - case 4429: return "\u22FD"; // ¬nivc - case 4437: return "\u2280"; // &NotPrecedes - case 4442: return "\u2AAF\u0338"; // &NotPrecedesEqual - case 4452: return "\u22E0"; // &NotPrecedesSlantEqual - case 4466: return "\u220C"; // &NotReverseElement - case 4478: return "\u22EB"; // &NotRightTriangle - case 4481: return "\u29D0\u0338"; // &NotRightTriangleBar - case 4486: return "\u22ED"; // &NotRightTriangleEqual - case 4498: return "\u228F\u0338"; // &NotSquareSubset - case 4503: return "\u22E2"; // &NotSquareSubsetEqual - case 4509: return "\u2290\u0338"; // &NotSquareSuperset - case 4514: return "\u22E3"; // &NotSquareSupersetEqual - case 4519: return "\u2282\u20D2"; // &NotSubset - case 4524: return "\u2288"; // &NotSubsetEqual - case 4530: return "\u2281"; // &NotSucceeds - case 4535: return "\u2AB0\u0338"; // &NotSucceedsEqual - case 4545: return "\u22E1"; // &NotSucceedsSlantEqual - case 4550: return "\u227F\u0338"; // &NotSucceedsTilde - case 4556: return "\u2283\u20D2"; // &NotSuperset - case 4561: return "\u2289"; // &NotSupersetEqual - case 4566: return "\u2241"; // &NotTilde - case 4571: return "\u2244"; // &NotTildeEqual - case 4580: return "\u2247"; // &NotTildeFullEqual - case 4585: return "\u2249"; // &NotTildeTilde - case 4596: return "\u2224"; // &NotVerticalBar - case 4599: return "\u2226"; // &npar - case 4604: return "\u2226"; // &nparallel - case 4606: return "\u2AFD\u20E5"; // &nparsl - case 4607: return "\u2202\u0338"; // &npart - case 4612: return "\u2A14"; // &npolint - case 4613: return "\u2280"; // &npr - case 4616: return "\u22E0"; // &nprcue - case 4617: return "\u2AAF\u0338"; // &npre - case 4618: return "\u2280"; // &nprec - case 4620: return "\u2AAF\u0338"; // &npreceq - case 4624: return "\u21CF"; // &nrArr - case 4627: return "\u219B"; // &nrarr - case 4628: return "\u2933\u0338"; // &nrarrc - case 4629: return "\u219D\u0338"; // &nrarrw - case 4639: return "\u21CF"; // &nRightarrow - case 4648: return "\u219B"; // &nrightarrow - case 4651: return "\u22EB"; // &nrtri - case 4652: return "\u22ED"; // &nrtrie - case 4654: return "\u2281"; // &nsc - case 4657: return "\u22E1"; // &nsccue - case 4658: return "\u2AB0\u0338"; // &nsce - case 4661: return "\uD835\uDCA9"; // &Nscr - case 4662: return "\uD835\uDCC3"; // &nscr - case 4669: return "\u2224"; // &nshortmid - case 4677: return "\u2226"; // &nshortparallel - case 4679: return "\u2241"; // &nsim - case 4680: return "\u2244"; // &nsime - case 4681: return "\u2244"; // &nsimeq - case 4684: return "\u2224"; // &nsmid - case 4687: return "\u2226"; // &nspar - case 4692: return "\u22E2"; // &nsqsube - case 4694: return "\u22E3"; // &nsqsupe - case 4696: return "\u2284"; // &nsub - case 4697: return "\u2AC5\u0338"; // &nsubE - case 4698: return "\u2288"; // &nsube - case 4701: return "\u2282\u20D2"; // &nsubset - case 4703: return "\u2288"; // &nsubseteq - case 4704: return "\u2AC5\u0338"; // &nsubseteqq - case 4706: return "\u2281"; // &nsucc - case 4708: return "\u2AB0\u0338"; // &nsucceq - case 4709: return "\u2285"; // &nsup - case 4710: return "\u2AC6\u0338"; // &nsupE - case 4711: return "\u2289"; // &nsupe - case 4714: return "\u2283\u20D2"; // &nsupset - case 4716: return "\u2289"; // &nsupseteq - case 4717: return "\u2AC6\u0338"; // &nsupseteqq - case 4720: return "\u2279"; // &ntgl - case 4725: return "\u00D1"; // Ñ - case 4729: return "\u00F1"; // ñ - case 4731: return "\u2278"; // &ntlg - case 4742: return "\u22EA"; // &ntriangleleft - case 4744: return "\u22EC"; // &ntrianglelefteq - case 4749: return "\u22EB"; // &ntriangleright - case 4751: return "\u22ED"; // &ntrianglerighteq - case 4752: return "\u039D"; // &Nu - case 4753: return "\u03BD"; // &nu - case 4754: return "\u0023"; // &num - case 4757: return "\u2116"; // &numero - case 4759: return "\u2007"; // &numsp - case 4762: return "\u224D\u20D2"; // &nvap - case 4767: return "\u22AF"; // &nVDash - case 4771: return "\u22AE"; // &nVdash - case 4775: return "\u22AD"; // &nvDash - case 4779: return "\u22AC"; // &nvdash - case 4781: return "\u2265\u20D2"; // &nvge - case 4782: return "\u003E\u20D2"; // &nvgt - case 4786: return "\u2904"; // &nvHarr - case 4791: return "\u29DE"; // &nvinfin - case 4795: return "\u2902"; // &nvlArr - case 4796: return "\u2264\u20D2"; // &nvle - case 4797: return "\u003C\u20D2"; // &nvlt - case 4800: return "\u22B4\u20D2"; // &nvltrie - case 4804: return "\u2903"; // &nvrArr - case 4808: return "\u22B5\u20D2"; // &nvrtrie - case 4811: return "\u223C\u20D2"; // &nvsim - case 4816: return "\u2923"; // &nwarhk - case 4819: return "\u21D6"; // &nwArr - case 4820: return "\u2196"; // &nwarr - case 4822: return "\u2196"; // &nwarrow - case 4826: return "\u2927"; // &nwnear - case 4832: return "\u00D3"; // Ó - case 4838: return "\u00F3"; // ó - case 4840: return "\u229B"; // &oast - case 4843: return "\u229A"; // &ocir - case 4847: return "\u00D4"; // Ô - case 4848: return "\u00F4"; // ô - case 4849: return "\u041E"; // &Ocy - case 4850: return "\u043E"; // &ocy - case 4854: return "\u229D"; // &odash - case 4859: return "\u0150"; // &Odblac - case 4863: return "\u0151"; // &odblac - case 4865: return "\u2A38"; // &odiv - case 4867: return "\u2299"; // &odot - case 4871: return "\u29BC"; // &odsold - case 4875: return "\u0152"; // &OElig - case 4879: return "\u0153"; // &oelig - case 4883: return "\u29BF"; // &ofcir - case 4885: return "\uD835\uDD12"; // &Ofr - case 4886: return "\uD835\uDD2C"; // &ofr - case 4889: return "\u02DB"; // &ogon - case 4894: return "\u00D2"; // Ò - case 4898: return "\u00F2"; // ò - case 4899: return "\u29C1"; // &ogt - case 4903: return "\u29B5"; // &ohbar - case 4904: return "\u03A9"; // &ohm - case 4907: return "\u222E"; // &oint - case 4911: return "\u21BA"; // &olarr - case 4914: return "\u29BE"; // &olcir - case 4918: return "\u29BB"; // &olcross - case 4921: return "\u203E"; // &oline - case 4922: return "\u29C0"; // &olt - case 4926: return "\u014C"; // &Omacr - case 4930: return "\u014D"; // &omacr - case 4933: return "\u03A9"; // &Omega - case 4936: return "\u03C9"; // &omega - case 4941: return "\u039F"; // &Omicron - case 4946: return "\u03BF"; // &omicron - case 4947: return "\u29B6"; // &omid - case 4950: return "\u2296"; // &ominus - case 4953: return "\uD835\uDD46"; // &Oopf - case 4956: return "\uD835\uDD60"; // &oopf - case 4959: return "\u29B7"; // &opar - case 4978: return "\u201C"; // &OpenCurlyDoubleQuote - case 4983: return "\u2018"; // &OpenCurlyQuote - case 4986: return "\u29B9"; // &operp - case 4989: return "\u2295"; // &oplus - case 4990: return "\u2A54"; // &Or - case 4991: return "\u2228"; // &or - case 4994: return "\u21BB"; // &orarr - case 4995: return "\u2A5D"; // &ord - case 4997: return "\u2134"; // &order - case 4999: return "\u2134"; // &orderof - case 5000: return "\u00AA"; // ª - case 5001: return "\u00BA"; // º - case 5005: return "\u22B6"; // &origof - case 5007: return "\u2A56"; // &oror - case 5012: return "\u2A57"; // &orslope - case 5013: return "\u2A5B"; // &orv - case 5014: return "\u24C8"; // &oS - case 5017: return "\uD835\uDCAA"; // &Oscr - case 5020: return "\u2134"; // &oscr - case 5024: return "\u00D8"; // Ø - case 5028: return "\u00F8"; // ø - case 5030: return "\u2298"; // &osol - case 5035: return "\u00D5"; // Õ - case 5040: return "\u00F5"; // õ - case 5043: return "\u2A37"; // &Otimes - case 5046: return "\u2297"; // &otimes - case 5048: return "\u2A36"; // &otimesas - case 5051: return "\u00D6"; // Ö - case 5054: return "\u00F6"; // ö - case 5058: return "\u233D"; // &ovbar - case 5064: return "\u203E"; // &OverBar - case 5068: return "\u23DE"; // &OverBrace - case 5071: return "\u23B4"; // &OverBracket - case 5082: return "\u23DC"; // &OverParenthesis - case 5085: return "\u2225"; // &par - case 5086: return "\u00B6"; // ¶ - case 5090: return "\u2225"; // ¶llel - case 5093: return "\u2AF3"; // &parsim - case 5094: return "\u2AFD"; // &parsl - case 5095: return "\u2202"; // &part - case 5103: return "\u2202"; // &PartialD - case 5105: return "\u041F"; // &Pcy - case 5107: return "\u043F"; // &pcy - case 5112: return "\u0025"; // &percnt - case 5115: return "\u002E"; // &period - case 5118: return "\u2030"; // &permil - case 5119: return "\u22A5"; // &perp - case 5123: return "\u2031"; // &pertenk - case 5125: return "\uD835\uDD13"; // &Pfr - case 5127: return "\uD835\uDD2D"; // &pfr - case 5129: return "\u03A6"; // &Phi - case 5131: return "\u03C6"; // &phi - case 5132: return "\u03D5"; // &phiv - case 5136: return "\u2133"; // &phmmat - case 5139: return "\u260E"; // &phone - case 5140: return "\u03A0"; // &Pi - case 5141: return "\u03C0"; // &pi - case 5148: return "\u22D4"; // &pitchfork - case 5149: return "\u03D6"; // &piv - case 5154: return "\u210F"; // &planck - case 5155: return "\u210E"; // &planckh - case 5157: return "\u210F"; // &plankv - case 5159: return "\u002B"; // &plus - case 5163: return "\u2A23"; // &plusacir - case 5164: return "\u229E"; // &plusb - case 5167: return "\u2A22"; // &pluscir - case 5169: return "\u2214"; // &plusdo - case 5170: return "\u2A25"; // &plusdu - case 5171: return "\u2A72"; // &pluse - case 5179: return "\u00B1"; // &PlusMinus - case 5181: return "\u00B1"; // ± - case 5184: return "\u2A26"; // &plussim - case 5187: return "\u2A27"; // &plustwo - case 5188: return "\u00B1"; // &pm - case 5200: return "\u210C"; // &Poincareplane - case 5207: return "\u2A15"; // &pointint - case 5209: return "\u2119"; // &Popf - case 5211: return "\uD835\uDD61"; // &popf - case 5214: return "\u00A3"; // £ - case 5215: return "\u2ABB"; // &Pr - case 5216: return "\u227A"; // &pr - case 5218: return "\u2AB7"; // &prap - case 5221: return "\u227C"; // &prcue - case 5222: return "\u2AB3"; // &prE - case 5223: return "\u2AAF"; // &pre - case 5224: return "\u227A"; // &prec - case 5230: return "\u2AB7"; // &precapprox - case 5237: return "\u227C"; // &preccurlyeq - case 5243: return "\u227A"; // &Precedes - case 5248: return "\u2AAF"; // &PrecedesEqual - case 5258: return "\u227C"; // &PrecedesSlantEqual - case 5263: return "\u227E"; // &PrecedesTilde - case 5265: return "\u2AAF"; // &preceq - case 5272: return "\u2AB9"; // &precnapprox - case 5275: return "\u2AB5"; // &precneqq - case 5278: return "\u22E8"; // &precnsim - case 5281: return "\u227E"; // &precsim - case 5284: return "\u2033"; // &Prime - case 5287: return "\u2032"; // &prime - case 5288: return "\u2119"; // &primes - case 5291: return "\u2AB9"; // &prnap - case 5292: return "\u2AB5"; // &prnE - case 5295: return "\u22E8"; // &prnsim - case 5297: return "\u220F"; // &prod - case 5302: return "\u220F"; // &Product - case 5307: return "\u232E"; // &profalar - case 5311: return "\u2312"; // &profline - case 5315: return "\u2313"; // &profsurf - case 5316: return "\u221D"; // &prop - case 5323: return "\u2237"; // &Proportion - case 5325: return "\u221D"; // &Proportional - case 5327: return "\u221D"; // &propto - case 5330: return "\u227E"; // &prsim - case 5334: return "\u22B0"; // &prurel - case 5337: return "\uD835\uDCAB"; // &Pscr - case 5340: return "\uD835\uDCC5"; // &pscr - case 5341: return "\u03A8"; // &Psi - case 5342: return "\u03C8"; // &psi - case 5347: return "\u2008"; // &puncsp - case 5350: return "\uD835\uDD14"; // &Qfr - case 5353: return "\uD835\uDD2E"; // &qfr - case 5356: return "\u2A0C"; // &qint - case 5359: return "\u211A"; // &Qopf - case 5362: return "\uD835\uDD62"; // &qopf - case 5367: return "\u2057"; // &qprime - case 5370: return "\uD835\uDCAC"; // &Qscr - case 5373: return "\uD835\uDCC6"; // &qscr - case 5383: return "\u210D"; // &quaternions - case 5386: return "\u2A16"; // &quatint - case 5389: return "\u003F"; // &quest - case 5391: return "\u225F"; // &questeq - case 5394: return "\u0022"; // " - case 5396: return "\u0022"; // " - case 5401: return "\u21DB"; // &rAarr - case 5404: return "\u223D\u0331"; // &race - case 5410: return "\u0154"; // &Racute - case 5413: return "\u0155"; // &racute - case 5416: return "\u221A"; // &radic - case 5422: return "\u29B3"; // &raemptyv - case 5424: return "\u27EB"; // &Rang - case 5426: return "\u27E9"; // &rang - case 5427: return "\u2992"; // &rangd - case 5428: return "\u29A5"; // &range - case 5430: return "\u27E9"; // &rangle - case 5433: return "\u00BB"; // » - case 5435: return "\u21A0"; // &Rarr - case 5437: return "\u21D2"; // &rArr - case 5439: return "\u2192"; // &rarr - case 5441: return "\u2975"; // &rarrap - case 5442: return "\u21E5"; // &rarrb - case 5444: return "\u2920"; // &rarrbfs - case 5445: return "\u2933"; // &rarrc - case 5447: return "\u291E"; // &rarrfs - case 5449: return "\u21AA"; // &rarrhk - case 5451: return "\u21AC"; // &rarrlp - case 5453: return "\u2945"; // &rarrpl - case 5456: return "\u2974"; // &rarrsim - case 5458: return "\u2916"; // &Rarrtl - case 5460: return "\u21A3"; // &rarrtl - case 5461: return "\u219D"; // &rarrw - case 5465: return "\u291C"; // &rAtail - case 5469: return "\u291A"; // &ratail - case 5471: return "\u2236"; // &ratio - case 5475: return "\u211A"; // &rationals - case 5479: return "\u2910"; // &RBarr - case 5483: return "\u290F"; // &rBarr - case 5487: return "\u290D"; // &rbarr - case 5490: return "\u2773"; // &rbbrk - case 5494: return "\u007D"; // &rbrace - case 5495: return "\u005D"; // &rbrack - case 5497: return "\u298C"; // &rbrke - case 5500: return "\u298E"; // &rbrksld - case 5501: return "\u2990"; // &rbrkslu - case 5506: return "\u0158"; // &Rcaron - case 5511: return "\u0159"; // &rcaron - case 5515: return "\u0156"; // &Rcedil - case 5519: return "\u0157"; // &rcedil - case 5521: return "\u2309"; // &rceil - case 5523: return "\u007D"; // &rcub - case 5524: return "\u0420"; // &Rcy - case 5525: return "\u0440"; // &rcy - case 5528: return "\u2937"; // &rdca - case 5533: return "\u2969"; // &rdldhar - case 5536: return "\u201D"; // &rdquo - case 5537: return "\u201D"; // &rdquor - case 5539: return "\u21B3"; // &rdsh - case 5540: return "\u211C"; // &Re - case 5543: return "\u211C"; // &real - case 5546: return "\u211B"; // &realine - case 5550: return "\u211C"; // &realpart - case 5551: return "\u211D"; // &reals - case 5553: return "\u25AD"; // &rect - case 5555: return "\u00AE"; // ® - case 5556: return "\u00AE"; // ® - case 5568: return "\u220B"; // &ReverseElement - case 5578: return "\u21CB"; // &ReverseEquilibrium - case 5591: return "\u296F"; // &ReverseUpEquilibrium - case 5596: return "\u297D"; // &rfisht - case 5600: return "\u230B"; // &rfloor - case 5602: return "\u211C"; // &Rfr - case 5603: return "\uD835\uDD2F"; // &rfr - case 5606: return "\u2964"; // &rHar - case 5610: return "\u21C1"; // &rhard - case 5611: return "\u21C0"; // &rharu - case 5612: return "\u296C"; // &rharul - case 5614: return "\u03A1"; // &Rho - case 5615: return "\u03C1"; // &rho - case 5616: return "\u03F1"; // &rhov - case 5632: return "\u27E9"; // &RightAngleBracket - case 5636: return "\u2192"; // &RightArrow - case 5641: return "\u21D2"; // &Rightarrow - case 5650: return "\u2192"; // &rightarrow - case 5653: return "\u21E5"; // &RightArrowBar - case 5662: return "\u21C4"; // &RightArrowLeftArrow - case 5666: return "\u21A3"; // &rightarrowtail - case 5673: return "\u2309"; // &RightCeiling - case 5686: return "\u27E7"; // &RightDoubleBracket - case 5697: return "\u295D"; // &RightDownTeeVector - case 5703: return "\u21C2"; // &RightDownVector - case 5706: return "\u2955"; // &RightDownVectorBar - case 5711: return "\u230B"; // &RightFloor - case 5722: return "\u21C1"; // &rightharpoondown - case 5724: return "\u21C0"; // &rightharpoonup - case 5734: return "\u21C4"; // &rightleftarrows - case 5742: return "\u21CC"; // &rightleftharpoons - case 5753: return "\u21C9"; // &rightrightarrows - case 5763: return "\u219D"; // &rightsquigarrow - case 5766: return "\u22A2"; // &RightTee - case 5771: return "\u21A6"; // &RightTeeArrow - case 5777: return "\u295B"; // &RightTeeVector - case 5787: return "\u22CC"; // &rightthreetimes - case 5794: return "\u22B3"; // &RightTriangle - case 5797: return "\u29D0"; // &RightTriangleBar - case 5802: return "\u22B5"; // &RightTriangleEqual - case 5814: return "\u294F"; // &RightUpDownVector - case 5823: return "\u295C"; // &RightUpTeeVector - case 5829: return "\u21BE"; // &RightUpVector - case 5832: return "\u2954"; // &RightUpVectorBar - case 5838: return "\u21C0"; // &RightVector - case 5841: return "\u2953"; // &RightVectorBar - case 5843: return "\u02DA"; // &ring - case 5853: return "\u2253"; // &risingdotseq - case 5857: return "\u21C4"; // &rlarr - case 5860: return "\u21CC"; // &rlhar - case 5861: return "\u200F"; // &rlm - case 5866: return "\u23B1"; // &rmoust - case 5870: return "\u23B1"; // &rmoustache - case 5874: return "\u2AEE"; // &rnmid - case 5878: return "\u27ED"; // &roang - case 5880: return "\u21FE"; // &roarr - case 5883: return "\u27E7"; // &robrk - case 5886: return "\u2986"; // &ropar - case 5889: return "\u211D"; // &Ropf - case 5890: return "\uD835\uDD63"; // &ropf - case 5893: return "\u2A2E"; // &roplus - case 5898: return "\u2A35"; // &rotimes - case 5908: return "\u2970"; // &RoundImplies - case 5911: return "\u0029"; // &rpar - case 5913: return "\u2994"; // &rpargt - case 5919: return "\u2A12"; // &rppolint - case 5923: return "\u21C9"; // &rrarr - case 5933: return "\u21DB"; // &Rrightarrow - case 5938: return "\u203A"; // &rsaquo - case 5941: return "\u211B"; // &Rscr - case 5943: return "\uD835\uDCC7"; // &rscr - case 5944: return "\u21B1"; // &Rsh - case 5945: return "\u21B1"; // &rsh - case 5947: return "\u005D"; // &rsqb - case 5949: return "\u2019"; // &rsquo - case 5950: return "\u2019"; // &rsquor - case 5955: return "\u22CC"; // &rthree - case 5959: return "\u22CA"; // &rtimes - case 5961: return "\u25B9"; // &rtri - case 5962: return "\u22B5"; // &rtrie - case 5963: return "\u25B8"; // &rtrif - case 5967: return "\u29CE"; // &rtriltri - case 5977: return "\u29F4"; // &RuleDelayed - case 5983: return "\u2968"; // &ruluhar - case 5984: return "\u211E"; // &rx - case 5990: return "\u015A"; // &Sacute - case 5996: return "\u015B"; // &sacute - case 6000: return "\u201A"; // &sbquo - case 6001: return "\u2ABC"; // &Sc - case 6002: return "\u227B"; // &sc - case 6004: return "\u2AB8"; // &scap - case 6008: return "\u0160"; // &Scaron - case 6011: return "\u0161"; // &scaron - case 6014: return "\u227D"; // &sccue - case 6015: return "\u2AB4"; // &scE - case 6016: return "\u2AB0"; // &sce - case 6020: return "\u015E"; // &Scedil - case 6023: return "\u015F"; // &scedil - case 6026: return "\u015C"; // &Scirc - case 6029: return "\u015D"; // &scirc - case 6032: return "\u2ABA"; // &scnap - case 6033: return "\u2AB6"; // &scnE - case 6036: return "\u22E9"; // &scnsim - case 6042: return "\u2A13"; // &scpolint - case 6045: return "\u227F"; // &scsim - case 6046: return "\u0421"; // &Scy - case 6047: return "\u0441"; // &scy - case 6050: return "\u22C5"; // &sdot - case 6051: return "\u22A1"; // &sdotb - case 6052: return "\u2A66"; // &sdote - case 6057: return "\u2925"; // &searhk - case 6060: return "\u21D8"; // &seArr - case 6061: return "\u2198"; // &searr - case 6063: return "\u2198"; // &searrow - case 6065: return "\u00A7"; // § - case 6067: return "\u003B"; // &semi - case 6071: return "\u2929"; // &seswar - case 6077: return "\u2216"; // &setminus - case 6078: return "\u2216"; // &setmn - case 6080: return "\u2736"; // &sext - case 6082: return "\uD835\uDD16"; // &Sfr - case 6084: return "\uD835\uDD30"; // &sfr - case 6087: return "\u2322"; // &sfrown - case 6091: return "\u266F"; // &sharp - case 6096: return "\u0429"; // &SHCHcy - case 6100: return "\u0449"; // &shchcy - case 6102: return "\u0428"; // &SHcy - case 6103: return "\u0448"; // &shcy - case 6116: return "\u2193"; // &ShortDownArrow - case 6125: return "\u2190"; // &ShortLeftArrow - case 6131: return "\u2223"; // &shortmid - case 6139: return "\u2225"; // &shortparallel - case 6149: return "\u2192"; // &ShortRightArrow - case 6156: return "\u2191"; // &ShortUpArrow - case 6157: return "\u00AD"; // ­ - case 6161: return "\u03A3"; // &Sigma - case 6165: return "\u03C3"; // &sigma - case 6166: return "\u03C2"; // &sigmaf - case 6167: return "\u03C2"; // &sigmav - case 6168: return "\u223C"; // &sim - case 6171: return "\u2A6A"; // &simdot - case 6172: return "\u2243"; // &sime - case 6173: return "\u2243"; // &simeq - case 6174: return "\u2A9E"; // &simg - case 6175: return "\u2AA0"; // &simgE - case 6176: return "\u2A9D"; // &siml - case 6177: return "\u2A9F"; // &simlE - case 6179: return "\u2246"; // &simne - case 6183: return "\u2A24"; // &simplus - case 6187: return "\u2972"; // &simrarr - case 6191: return "\u2190"; // &slarr - case 6201: return "\u2218"; // &SmallCircle - case 6213: return "\u2216"; // &smallsetminus - case 6216: return "\u2A33"; // &smashp - case 6222: return "\u29E4"; // &smeparsl - case 6224: return "\u2223"; // &smid - case 6226: return "\u2323"; // &smile - case 6227: return "\u2AAA"; // &smt - case 6228: return "\u2AAC"; // &smte - case 6229: return "\u2AAC\uFE00"; // &smtes - case 6234: return "\u042C"; // &SOFTcy - case 6239: return "\u044C"; // &softcy - case 6240: return "\u002F"; // &sol - case 6241: return "\u29C4"; // &solb - case 6243: return "\u233F"; // &solbar - case 6246: return "\uD835\uDD4A"; // &Sopf - case 6248: return "\uD835\uDD64"; // &sopf - case 6253: return "\u2660"; // &spades - case 6256: return "\u2660"; // &spadesuit - case 6257: return "\u2225"; // &spar - case 6261: return "\u2293"; // &sqcap - case 6262: return "\u2293\uFE00"; // &sqcaps - case 6264: return "\u2294"; // &sqcup - case 6265: return "\u2294\uFE00"; // &sqcups - case 6268: return "\u221A"; // &Sqrt - case 6271: return "\u228F"; // &sqsub - case 6272: return "\u2291"; // &sqsube - case 6275: return "\u228F"; // &sqsubset - case 6277: return "\u2291"; // &sqsubseteq - case 6278: return "\u2290"; // &sqsup - case 6279: return "\u2292"; // &sqsupe - case 6282: return "\u2290"; // &sqsupset - case 6284: return "\u2292"; // &sqsupseteq - case 6285: return "\u25A1"; // &squ - case 6289: return "\u25A1"; // &Square - case 6292: return "\u25A1"; // &square - case 6304: return "\u2293"; // &SquareIntersection - case 6310: return "\u228F"; // &SquareSubset - case 6315: return "\u2291"; // &SquareSubsetEqual - case 6321: return "\u2290"; // &SquareSuperset - case 6326: return "\u2292"; // &SquareSupersetEqual - case 6331: return "\u2294"; // &SquareUnion - case 6332: return "\u25AA"; // &squarf - case 6333: return "\u25AA"; // &squf - case 6337: return "\u2192"; // &srarr - case 6340: return "\uD835\uDCAE"; // &Sscr - case 6343: return "\uD835\uDCC8"; // &sscr - case 6347: return "\u2216"; // &ssetmn - case 6351: return "\u2323"; // &ssmile - case 6355: return "\u22C6"; // &sstarf - case 6358: return "\u22C6"; // &Star - case 6361: return "\u2606"; // &star - case 6362: return "\u2605"; // &starf - case 6375: return "\u03F5"; // &straightepsilon - case 6378: return "\u03D5"; // &straightphi - case 6380: return "\u00AF"; // &strns - case 6382: return "\u22D0"; // &Sub - case 6384: return "\u2282"; // &sub - case 6387: return "\u2ABD"; // &subdot - case 6388: return "\u2AC5"; // &subE - case 6389: return "\u2286"; // &sube - case 6392: return "\u2AC3"; // &subedot - case 6396: return "\u2AC1"; // &submult - case 6398: return "\u2ACB"; // &subnE - case 6399: return "\u228A"; // &subne - case 6403: return "\u2ABF"; // &subplus - case 6407: return "\u2979"; // &subrarr - case 6410: return "\u22D0"; // &Subset - case 6413: return "\u2282"; // &subset - case 6415: return "\u2286"; // &subseteq - case 6416: return "\u2AC5"; // &subseteqq - case 6421: return "\u2286"; // &SubsetEqual - case 6424: return "\u228A"; // &subsetneq - case 6425: return "\u2ACB"; // &subsetneqq - case 6427: return "\u2AC7"; // &subsim - case 6429: return "\u2AD5"; // &subsub - case 6430: return "\u2AD3"; // &subsup - case 6432: return "\u227B"; // &succ - case 6438: return "\u2AB8"; // &succapprox - case 6445: return "\u227D"; // &succcurlyeq - case 6451: return "\u227B"; // &Succeeds - case 6456: return "\u2AB0"; // &SucceedsEqual - case 6466: return "\u227D"; // &SucceedsSlantEqual - case 6471: return "\u227F"; // &SucceedsTilde - case 6473: return "\u2AB0"; // &succeq - case 6480: return "\u2ABA"; // &succnapprox - case 6483: return "\u2AB6"; // &succneqq - case 6486: return "\u22E9"; // &succnsim - case 6489: return "\u227F"; // &succsim - case 6494: return "\u220B"; // &SuchThat - case 6495: return "\u2211"; // &Sum - case 6496: return "\u2211"; // &sum - case 6498: return "\u266A"; // &sung - case 6499: return "\u22D1"; // &Sup - case 6500: return "\u2283"; // &sup - case 6501: return "\u00B9"; // ¹ - case 6502: return "\u00B2"; // ² - case 6503: return "\u00B3"; // ³ - case 6506: return "\u2ABE"; // &supdot - case 6509: return "\u2AD8"; // &supdsub - case 6510: return "\u2AC6"; // &supE - case 6511: return "\u2287"; // &supe - case 6514: return "\u2AC4"; // &supedot - case 6519: return "\u2283"; // &Superset - case 6524: return "\u2287"; // &SupersetEqual - case 6528: return "\u27C9"; // &suphsol - case 6530: return "\u2AD7"; // &suphsub - case 6534: return "\u297B"; // &suplarr - case 6538: return "\u2AC2"; // &supmult - case 6540: return "\u2ACC"; // &supnE - case 6541: return "\u228B"; // &supne - case 6545: return "\u2AC0"; // &supplus - case 6548: return "\u22D1"; // &Supset - case 6551: return "\u2283"; // &supset - case 6553: return "\u2287"; // &supseteq - case 6554: return "\u2AC6"; // &supseteqq - case 6557: return "\u228B"; // &supsetneq - case 6558: return "\u2ACC"; // &supsetneqq - case 6560: return "\u2AC8"; // &supsim - case 6562: return "\u2AD4"; // &supsub - case 6563: return "\u2AD6"; // &supsup - case 6568: return "\u2926"; // &swarhk - case 6571: return "\u21D9"; // &swArr - case 6572: return "\u2199"; // &swarr - case 6574: return "\u2199"; // &swarrow - case 6578: return "\u292A"; // &swnwar - case 6582: return "\u00DF"; // ß - case 6585: return "\u0009"; // &Tab - case 6591: return "\u2316"; // &target - case 6592: return "\u03A4"; // &Tau - case 6593: return "\u03C4"; // &tau - case 6596: return "\u23B4"; // &tbrk - case 6601: return "\u0164"; // &Tcaron - case 6606: return "\u0165"; // &tcaron - case 6610: return "\u0162"; // &Tcedil - case 6614: return "\u0163"; // &tcedil - case 6615: return "\u0422"; // &Tcy - case 6616: return "\u0442"; // &tcy - case 6619: return "\u20DB"; // &tdot - case 6624: return "\u2315"; // &telrec - case 6626: return "\uD835\uDD17"; // &Tfr - case 6628: return "\uD835\uDD31"; // &tfr - case 6633: return "\u2234"; // &there4 - case 6641: return "\u2234"; // &Therefore - case 6645: return "\u2234"; // &therefore - case 6647: return "\u0398"; // &Theta - case 6649: return "\u03B8"; // &theta - case 6652: return "\u03D1"; // &thetasym - case 6653: return "\u03D1"; // &thetav - case 6662: return "\u2248"; // &thickapprox - case 6665: return "\u223C"; // &thicksim - case 6673: return "\u205F\u200A"; // &ThickSpace - case 6676: return "\u2009"; // &thinsp - case 6682: return "\u2009"; // &ThinSpace - case 6685: return "\u2248"; // &thkap - case 6688: return "\u223C"; // &thksim - case 6692: return "\u00DE"; // Þ - case 6695: return "\u00FE"; // þ - case 6699: return "\u223C"; // &Tilde - case 6703: return "\u02DC"; // &tilde - case 6708: return "\u2243"; // &TildeEqual - case 6717: return "\u2245"; // &TildeFullEqual - case 6722: return "\u2248"; // &TildeTilde - case 6725: return "\u00D7"; // × - case 6726: return "\u22A0"; // ×b - case 6728: return "\u2A31"; // ×bar - case 6729: return "\u2A30"; // ×d - case 6731: return "\u222D"; // &tint - case 6734: return "\u2928"; // &toea - case 6735: return "\u22A4"; // &top - case 6738: return "\u2336"; // &topbot - case 6741: return "\u2AF1"; // &topcir - case 6744: return "\uD835\uDD4B"; // &Topf - case 6745: return "\uD835\uDD65"; // &topf - case 6748: return "\u2ADA"; // &topfork - case 6750: return "\u2929"; // &tosa - case 6755: return "\u2034"; // &tprime - case 6759: return "\u2122"; // &TRADE - case 6763: return "\u2122"; // &trade - case 6769: return "\u25B5"; // &triangle - case 6773: return "\u25BF"; // &triangledown - case 6777: return "\u25C3"; // &triangleleft - case 6779: return "\u22B4"; // &trianglelefteq - case 6780: return "\u225C"; // &triangleq - case 6785: return "\u25B9"; // &triangleright - case 6787: return "\u22B5"; // &trianglerighteq - case 6790: return "\u25EC"; // &tridot - case 6791: return "\u225C"; // &trie - case 6796: return "\u2A3A"; // &triminus - case 6804: return "\u20DB"; // &TripleDot - case 6808: return "\u2A39"; // &triplus - case 6810: return "\u29CD"; // &trisb - case 6814: return "\u2A3B"; // &tritime - case 6820: return "\u23E2"; // &trpezium - case 6823: return "\uD835\uDCAF"; // &Tscr - case 6826: return "\uD835\uDCC9"; // &tscr - case 6829: return "\u0426"; // &TScy - case 6830: return "\u0446"; // &tscy - case 6833: return "\u040B"; // &TSHcy - case 6836: return "\u045B"; // &tshcy - case 6840: return "\u0166"; // &Tstrok - case 6844: return "\u0167"; // &tstrok - case 6848: return "\u226C"; // &twixt - case 6862: return "\u219E"; // &twoheadleftarrow - case 6872: return "\u21A0"; // &twoheadrightarrow - case 6878: return "\u00DA"; // Ú - case 6884: return "\u00FA"; // ú - case 6886: return "\u219F"; // &Uarr - case 6889: return "\u21D1"; // &uArr - case 6891: return "\u2191"; // &uarr - case 6895: return "\u2949"; // &Uarrocir - case 6899: return "\u040E"; // &Ubrcy - case 6903: return "\u045E"; // &ubrcy - case 6906: return "\u016C"; // &Ubreve - case 6909: return "\u016D"; // &ubreve - case 6913: return "\u00DB"; // Û - case 6917: return "\u00FB"; // û - case 6918: return "\u0423"; // &Ucy - case 6919: return "\u0443"; // &ucy - case 6923: return "\u21C5"; // &udarr - case 6928: return "\u0170"; // &Udblac - case 6932: return "\u0171"; // &udblac - case 6935: return "\u296E"; // &udhar - case 6940: return "\u297E"; // &ufisht - case 6942: return "\uD835\uDD18"; // &Ufr - case 6943: return "\uD835\uDD32"; // &ufr - case 6948: return "\u00D9"; // Ù - case 6953: return "\u00F9"; // ù - case 6956: return "\u2963"; // &uHar - case 6960: return "\u21BF"; // &uharl - case 6961: return "\u21BE"; // &uharr - case 6964: return "\u2580"; // &uhblk - case 6969: return "\u231C"; // &ulcorn - case 6971: return "\u231C"; // &ulcorner - case 6974: return "\u230F"; // &ulcrop - case 6977: return "\u25F8"; // &ultri - case 6981: return "\u016A"; // &Umacr - case 6985: return "\u016B"; // &umacr - case 6986: return "\u00A8"; // ¨ - case 6993: return "\u005F"; // &UnderBar - case 6997: return "\u23DF"; // &UnderBrace - case 7000: return "\u23B5"; // &UnderBracket - case 7011: return "\u23DD"; // &UnderParenthesis - case 7014: return "\u22C3"; // &Union - case 7018: return "\u228E"; // &UnionPlus - case 7022: return "\u0172"; // &Uogon - case 7026: return "\u0173"; // &uogon - case 7028: return "\uD835\uDD4C"; // &Uopf - case 7030: return "\uD835\uDD66"; // &uopf - case 7036: return "\u2191"; // &UpArrow - case 7041: return "\u21D1"; // &Uparrow - case 7047: return "\u2191"; // &uparrow - case 7050: return "\u2912"; // &UpArrowBar - case 7059: return "\u21C5"; // &UpArrowDownArrow - case 7068: return "\u2195"; // &UpDownArrow - case 7077: return "\u21D5"; // &Updownarrow - case 7086: return "\u2195"; // &updownarrow - case 7097: return "\u296E"; // &UpEquilibrium - case 7108: return "\u21BF"; // &upharpoonleft - case 7113: return "\u21BE"; // &upharpoonright - case 7116: return "\u228E"; // &uplus - case 7128: return "\u2196"; // &UpperLeftArrow - case 7138: return "\u2197"; // &UpperRightArrow - case 7140: return "\u03D2"; // &Upsi - case 7142: return "\u03C5"; // &upsi - case 7143: return "\u03D2"; // &upsih - case 7146: return "\u03A5"; // &Upsilon - case 7149: return "\u03C5"; // &upsilon - case 7152: return "\u22A5"; // &UpTee - case 7157: return "\u21A5"; // &UpTeeArrow - case 7165: return "\u21C8"; // &upuparrows - case 7170: return "\u231D"; // &urcorn - case 7172: return "\u231D"; // &urcorner - case 7175: return "\u230E"; // &urcrop - case 7179: return "\u016E"; // &Uring - case 7182: return "\u016F"; // &uring - case 7185: return "\u25F9"; // &urtri - case 7188: return "\uD835\uDCB0"; // &Uscr - case 7191: return "\uD835\uDCCA"; // &uscr - case 7195: return "\u22F0"; // &utdot - case 7200: return "\u0168"; // &Utilde - case 7204: return "\u0169"; // &utilde - case 7206: return "\u25B5"; // &utri - case 7207: return "\u25B4"; // &utrif - case 7211: return "\u21C8"; // &uuarr - case 7214: return "\u00DC"; // Ü - case 7216: return "\u00FC"; // ü - case 7222: return "\u29A7"; // &uwangle - case 7228: return "\u299C"; // &vangrt - case 7236: return "\u03F5"; // &varepsilon - case 7241: return "\u03F0"; // &varkappa - case 7248: return "\u2205"; // &varnothing - case 7251: return "\u03D5"; // &varphi - case 7252: return "\u03D6"; // &varpi - case 7257: return "\u221D"; // &varpropto - case 7260: return "\u21D5"; // &vArr - case 7261: return "\u2195"; // &varr - case 7263: return "\u03F1"; // &varrho - case 7268: return "\u03C2"; // &varsigma - case 7276: return "\u228A\uFE00"; // &varsubsetneq - case 7277: return "\u2ACB\uFE00"; // &varsubsetneqq - case 7284: return "\u228B\uFE00"; // &varsupsetneq - case 7285: return "\u2ACC\uFE00"; // &varsupsetneqq - case 7290: return "\u03D1"; // &vartheta - case 7301: return "\u22B2"; // &vartriangleleft - case 7306: return "\u22B3"; // &vartriangleright - case 7310: return "\u2AEB"; // &Vbar - case 7313: return "\u2AE8"; // &vBar - case 7314: return "\u2AE9"; // &vBarv - case 7316: return "\u0412"; // &Vcy - case 7318: return "\u0432"; // &vcy - case 7322: return "\u22AB"; // &VDash - case 7326: return "\u22A9"; // &Vdash - case 7330: return "\u22A8"; // &vDash - case 7334: return "\u22A2"; // &vdash - case 7335: return "\u2AE6"; // &Vdashl - case 7337: return "\u22C1"; // &Vee - case 7339: return "\u2228"; // &vee - case 7342: return "\u22BB"; // &veebar - case 7344: return "\u225A"; // &veeeq - case 7348: return "\u22EE"; // &vellip - case 7352: return "\u2016"; // &Verbar - case 7356: return "\u007C"; // &verbar - case 7357: return "\u2016"; // &Vert - case 7358: return "\u007C"; // &vert - case 7365: return "\u2223"; // &VerticalBar - case 7369: return "\u007C"; // &VerticalLine - case 7378: return "\u2758"; // &VerticalSeparator - case 7383: return "\u2240"; // &VerticalTilde - case 7393: return "\u200A"; // &VeryThinSpace - case 7395: return "\uD835\uDD19"; // &Vfr - case 7397: return "\uD835\uDD33"; // &vfr - case 7401: return "\u22B2"; // &vltri - case 7405: return "\u2282\u20D2"; // &vnsub - case 7406: return "\u2283\u20D2"; // &vnsup - case 7409: return "\uD835\uDD4D"; // &Vopf - case 7412: return "\uD835\uDD67"; // &vopf - case 7416: return "\u221D"; // &vprop - case 7420: return "\u22B3"; // &vrtri - case 7423: return "\uD835\uDCB1"; // &Vscr - case 7426: return "\uD835\uDCCB"; // &vscr - case 7430: return "\u2ACB\uFE00"; // &vsubnE - case 7431: return "\u228A\uFE00"; // &vsubne - case 7434: return "\u2ACC\uFE00"; // &vsupnE - case 7435: return "\u228B\uFE00"; // &vsupne - case 7440: return "\u22AA"; // &Vvdash - case 7446: return "\u299A"; // &vzigzag - case 7451: return "\u0174"; // &Wcirc - case 7456: return "\u0175"; // &wcirc - case 7461: return "\u2A5F"; // &wedbar - case 7465: return "\u22C0"; // &Wedge - case 7467: return "\u2227"; // &wedge - case 7468: return "\u2259"; // &wedgeq - case 7472: return "\u2118"; // &weierp - case 7474: return "\uD835\uDD1A"; // &Wfr - case 7476: return "\uD835\uDD34"; // &wfr - case 7479: return "\uD835\uDD4E"; // &Wopf - case 7482: return "\uD835\uDD68"; // &wopf - case 7483: return "\u2118"; // &wp - case 7484: return "\u2240"; // &wr - case 7488: return "\u2240"; // &wreath - case 7491: return "\uD835\uDCB2"; // &Wscr - case 7494: return "\uD835\uDCCC"; // &wscr - case 7498: return "\u22C2"; // &xcap - case 7501: return "\u25EF"; // &xcirc - case 7503: return "\u22C3"; // &xcup - case 7507: return "\u25BD"; // &xdtri - case 7510: return "\uD835\uDD1B"; // &Xfr - case 7512: return "\uD835\uDD35"; // &xfr - case 7516: return "\u27FA"; // &xhArr - case 7519: return "\u27F7"; // &xharr - case 7520: return "\u039E"; // &Xi - case 7521: return "\u03BE"; // &xi - case 7525: return "\u27F8"; // &xlArr - case 7528: return "\u27F5"; // &xlarr - case 7531: return "\u27FC"; // &xmap - case 7534: return "\u22FB"; // &xnis - case 7538: return "\u2A00"; // &xodot - case 7541: return "\uD835\uDD4F"; // &Xopf - case 7543: return "\uD835\uDD69"; // &xopf - case 7546: return "\u2A01"; // &xoplus - case 7550: return "\u2A02"; // &xotime - case 7554: return "\u27F9"; // &xrArr - case 7557: return "\u27F6"; // &xrarr - case 7560: return "\uD835\uDCB3"; // &Xscr - case 7563: return "\uD835\uDCCD"; // &xscr - case 7567: return "\u2A06"; // &xsqcup - case 7572: return "\u2A04"; // &xuplus - case 7575: return "\u25B3"; // &xutri - case 7578: return "\u22C1"; // &xvee - case 7583: return "\u22C0"; // &xwedge - case 7589: return "\u00DD"; // Ý - case 7595: return "\u00FD"; // ý - case 7598: return "\u042F"; // &YAcy - case 7599: return "\u044F"; // &yacy - case 7603: return "\u0176"; // &Ycirc - case 7607: return "\u0177"; // &ycirc - case 7608: return "\u042B"; // &Ycy - case 7609: return "\u044B"; // &ycy - case 7611: return "\u00A5"; // ¥ - case 7613: return "\uD835\uDD1C"; // &Yfr - case 7615: return "\uD835\uDD36"; // &yfr - case 7618: return "\u0407"; // &YIcy - case 7621: return "\u0457"; // &yicy - case 7624: return "\uD835\uDD50"; // &Yopf - case 7627: return "\uD835\uDD6A"; // &yopf - case 7630: return "\uD835\uDCB4"; // &Yscr - case 7633: return "\uD835\uDCCE"; // &yscr - case 7636: return "\u042E"; // &YUcy - case 7639: return "\u044E"; // &yucy - case 7642: return "\u0178"; // &Yuml - case 7644: return "\u00FF"; // ÿ - case 7650: return "\u0179"; // &Zacute - case 7656: return "\u017A"; // &zacute - case 7661: return "\u017D"; // &Zcaron - case 7666: return "\u017E"; // &zcaron - case 7667: return "\u0417"; // &Zcy - case 7668: return "\u0437"; // &zcy - case 7671: return "\u017B"; // &Zdot - case 7674: return "\u017C"; // &zdot - case 7679: return "\u2128"; // &zeetrf - case 7692: return "\u200B"; // &ZeroWidthSpace - case 7694: return "\u0396"; // &Zeta - case 7696: return "\u03B6"; // &zeta - case 7698: return "\u2128"; // &Zfr - case 7700: return "\uD835\uDD37"; // &zfr - case 7703: return "\u0416"; // &ZHcy - case 7706: return "\u0436"; // &zhcy - case 7712: return "\u21DD"; // &zigrarr - case 7715: return "\u2124"; // &Zopf - case 7718: return "\uD835\uDD6B"; // &zopf - case 7721: return "\uD835\uDCB5"; // &Zscr - case 7724: return "\uD835\uDCCF"; // &zscr - case 7726: return "\u200D"; // &zwj - case 7728: return "\u200C"; // &zwnj - default: return null; - } - } - string GetNamedEntityValue () { int startIndex = index; string decoded = null; while (startIndex > 0) { - if ((decoded = GetNamedEntityValue (states[startIndex - 1])) != null) + if (NamedEntities.TryGetValue (states[startIndex - 1], out decoded)) break; startIndex--; diff --git a/MimeKit/Text/HtmlNamespace.cs b/MimeKit/Text/HtmlNamespace.cs index 70966e8407..ee4d935c72 100644 --- a/MimeKit/Text/HtmlNamespace.cs +++ b/MimeKit/Text/HtmlNamespace.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/HtmlTagCallback.cs b/MimeKit/Text/HtmlTagCallback.cs index ce4e27cb4a..61deac18f1 100644 --- a/MimeKit/Text/HtmlTagCallback.cs +++ b/MimeKit/Text/HtmlTagCallback.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/HtmlTagContext.cs b/MimeKit/Text/HtmlTagContext.cs index 052e7ce103..ac36b76639 100644 --- a/MimeKit/Text/HtmlTagContext.cs +++ b/MimeKit/Text/HtmlTagContext.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,7 +39,7 @@ namespace MimeKit.Text { public abstract class HtmlTagContext { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Text/HtmlTagId.cs b/MimeKit/Text/HtmlTagId.cs index ea480e6fa7..a6f57ce06a 100644 --- a/MimeKit/Text/HtmlTagId.cs +++ b/MimeKit/Text/HtmlTagId.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -654,9 +654,9 @@ public enum HtmlTagId { TH, /// - /// The HTML <thread> tag. + /// The HTML <thead> tag. /// - Thread, + THead, /// /// The HTML <time> tag. @@ -766,7 +766,7 @@ public static string ToHtmlTagName (this HtmlTagId value) var name = value.ToString (); -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 var field = typeof (HtmlTagId).GetTypeInfo ().GetDeclaredField (name); var attrs = field.GetCustomAttributes (typeof (HtmlTagNameAttribute), false).ToArray (); #else diff --git a/MimeKit/Text/HtmlTextPreviewer.cs b/MimeKit/Text/HtmlTextPreviewer.cs new file mode 100644 index 0000000000..b3e2e11943 --- /dev/null +++ b/MimeKit/Text/HtmlTextPreviewer.cs @@ -0,0 +1,253 @@ +// +// HtmlTextPreviewer.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; + +namespace MimeKit.Text { + /// + /// A text previewer for HTML content. + /// + /// + /// A text previewer for HTML content. + /// + public class HtmlTextPreviewer : TextPreviewer + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new previewer for HTML. + /// + public HtmlTextPreviewer () + { + } + + /// + /// Get the input format. + /// + /// + /// Gets the input format. + /// + /// The input format. + public override TextFormat InputFormat { + get { return TextFormat.Html; } + } + + static bool IsWhiteSpace (char c) + { + return char.IsWhiteSpace (c) || (c >= 0x200B && c <= 0x200D); + } + + static bool Append (char[] preview, ref int previewLength, string value, ref bool lwsp) + { + int i; + + for (i = 0; i < value.Length && previewLength < preview.Length; i++) { + if (IsWhiteSpace (value[i])) { + if (!lwsp) { + preview[previewLength++] = ' '; + lwsp = true; + } + } else { + preview[previewLength++] = value[i]; + lwsp = false; + } + } + + if (i < value.Length) { + if (lwsp) + previewLength--; + + preview[previewLength - 1] = '\u2026'; + lwsp = false; + return true; + } + + return false; + } + + sealed class HtmlTagContext + { + public HtmlTagContext (HtmlTagId id) + { + TagId = id; + } + + public HtmlTagId TagId { + get; + } + + public int ListIndex { + get; set; + } + + public bool SuppressInnerContent { + get; set; + } + } + + static void Pop (IList stack, HtmlTagId id) + { + for (int i = stack.Count; i > 0; i--) { + if (stack[i - 1].TagId == id) { + stack.RemoveAt (i - 1); + break; + } + } + } + + static bool ShouldSuppressInnerContent (HtmlTagId id) + { + switch (id) { + case HtmlTagId.OL: + case HtmlTagId.Script: + case HtmlTagId.Style: + case HtmlTagId.Table: + case HtmlTagId.TBody: + case HtmlTagId.THead: + case HtmlTagId.TR: + case HtmlTagId.UL: + return true; + default: + return false; + } + } + + static bool SuppressContent (IList stack) + { + int lastIndex = stack.Count - 1; + + return lastIndex >= 0 && stack[lastIndex].SuppressInnerContent; + } + + HtmlTagContext GetListItemContext (IList stack) + { + for (int i = stack.Count; i > 0; i--) { + var ctx = stack[i - 1]; + + if (ctx.TagId == HtmlTagId.OL || ctx.TagId == HtmlTagId.UL) + return ctx; + } + + return null; + } + + /// + /// Get a text preview of a stream of text. + /// + /// + /// Gets a text preview of a stream of text. + /// + /// The original text stream. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public override string GetPreviewText (TextReader reader) + { + if (reader == null) + throw new ArgumentNullException (nameof (reader)); + + var tokenizer = new HtmlTokenizer (reader) { IgnoreTruncatedTags = true }; + var preview = new char[MaximumPreviewLength]; + var stack = new List (); + var prefix = string.Empty; + int previewLength = 0; + HtmlTagContext ctx; + HtmlAttribute attr; + bool body = false; + bool full = false; + bool lwsp = true; + HtmlToken token; + + while (!full && tokenizer.ReadNextToken (out token)) { + switch (token.Kind) { + case HtmlTokenKind.Tag: + var tag = (HtmlTagToken) token; + + if (!tag.IsEndTag) { + if (body) { + switch (tag.Id) { + case HtmlTagId.Image: + if ((attr = tag.Attributes.FirstOrDefault (x => x.Id == HtmlAttributeId.Alt)) != null) { + full = Append (preview, ref previewLength, prefix + attr.Value, ref lwsp); + prefix = string.Empty; + } + break; + case HtmlTagId.LI: + if ((ctx = GetListItemContext (stack)) != null) { + if (ctx.TagId == HtmlTagId.OL) { + full = Append (preview, ref previewLength, $" {++ctx.ListIndex}. ", ref lwsp); + prefix = string.Empty; + } else { + //full = Append (preview, ref previewLength, " \u2022 ", ref lwsp); + prefix = " "; + } + } + break; + case HtmlTagId.Br: + case HtmlTagId.P: + prefix = " "; + break; + } + + if (!tag.IsEmptyElement) { + ctx = new HtmlTagContext (tag.Id) { + SuppressInnerContent = ShouldSuppressInnerContent (tag.Id) + }; + stack.Add (ctx); + } + } else if (tag.Id == HtmlTagId.Body && !tag.IsEmptyElement) { + body = true; + } + } else if (tag.Id == HtmlTagId.Body) { + stack.Clear (); + body = false; + } else { + Pop (stack, tag.Id); + } + break; + case HtmlTokenKind.Data: + if (body && !SuppressContent (stack)) { + var data = (HtmlDataToken) token; + + full = Append (preview, ref previewLength, prefix + data.Data, ref lwsp); + prefix = string.Empty; + } + break; + } + } + + if (lwsp && previewLength > 0) + previewLength--; + + return new string (preview, 0, previewLength); + } + } +} diff --git a/MimeKit/Text/HtmlToHtml.cs b/MimeKit/Text/HtmlToHtml.cs index 4a94f9deea..c9b4abf9d6 100644 --- a/MimeKit/Text/HtmlToHtml.cs +++ b/MimeKit/Text/HtmlToHtml.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -54,7 +54,7 @@ public class HtmlToHtml : TextConverter //} /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new HTML to HTML converter. @@ -107,18 +107,6 @@ public bool FilterHtml { get; set; } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - /// /// Get or set the footer format. /// @@ -130,18 +118,6 @@ public HeaderFooterFormat FooterFormat { get; set; } - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - /// /// Get or set the header format. /// @@ -276,7 +252,7 @@ public override void Convert (TextReader reader, TextWriter writer) if (!string.IsNullOrEmpty (Header)) { if (HeaderFormat == HeaderFooterFormat.Text) { - var converter = new TextToHtml (); + var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader (Header)) converter.Convert (sr, writer); @@ -368,7 +344,7 @@ public override void Convert (TextReader reader, TextWriter writer) if (!string.IsNullOrEmpty (Footer)) { if (FooterFormat == HeaderFooterFormat.Text) { - var converter = new TextToHtml (); + var converter = new TextToHtml { OutputHtmlFragment = true }; using (var sr = new StringReader (Footer)) converter.Convert (sr, writer); diff --git a/MimeKit/Text/HtmlToken.cs b/MimeKit/Text/HtmlToken.cs index 7d6edda7f6..fd85943a79 100644 --- a/MimeKit/Text/HtmlToken.cs +++ b/MimeKit/Text/HtmlToken.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,7 @@ namespace MimeKit.Text { public abstract class HtmlToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -73,12 +73,12 @@ public HtmlTokenKind Kind { public abstract void WriteTo (TextWriter output); /// - /// Returns a that represents the current . + /// Returns a that represents the current . /// /// - /// Returns a that represents the current . + /// Returns a that represents the current . /// - /// A that represents the current . + /// A that represents the current . public override string ToString () { using (var output = new StringWriter ()) { @@ -98,7 +98,7 @@ public override string ToString () public class HtmlCommentToken : HtmlToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -181,7 +181,7 @@ public override void WriteTo (TextWriter output) public class HtmlDataToken : HtmlToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -211,7 +211,7 @@ protected HtmlDataToken (HtmlTokenKind kind, string data) : base (kind) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -277,7 +277,7 @@ public override void WriteTo (TextWriter output) public class HtmlCDataToken : HtmlDataToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -321,7 +321,7 @@ public override void WriteTo (TextWriter output) public class HtmlScriptDataToken : HtmlDataToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -363,7 +363,7 @@ public override void WriteTo (TextWriter output) public class HtmlTagToken : HtmlToken { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -391,7 +391,7 @@ public HtmlTagToken (string name, IEnumerable attributes, bool is } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -512,7 +512,7 @@ public class HtmlDocTypeToken : HtmlToken string systemIdentifier; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . diff --git a/MimeKit/Text/HtmlTokenKind.cs b/MimeKit/Text/HtmlTokenKind.cs index 83e0a32b2e..0ff55fa49b 100644 --- a/MimeKit/Text/HtmlTokenKind.cs +++ b/MimeKit/Text/HtmlTokenKind.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/HtmlTokenizer.cs b/MimeKit/Text/HtmlTokenizer.cs index 48f8374642..b414052c58 100644 --- a/MimeKit/Text/HtmlTokenizer.cs +++ b/MimeKit/Text/HtmlTokenizer.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,7 @@ // using System.IO; -using System.Text; +using System.Runtime.CompilerServices; namespace MimeKit.Text { /// @@ -36,13 +36,15 @@ namespace MimeKit.Text { /// public class HtmlTokenizer { + // Specification: https://dev.w3.org/html5/spec-LC/tokenization.html const string DocType = "doctype"; const string CData = "[CDATA["; readonly HtmlEntityDecoder entity = new HtmlEntityDecoder (); - readonly StringBuilder data = new StringBuilder (); - readonly StringBuilder name = new StringBuilder (); + readonly CharBuffer data = new CharBuffer (2048); + readonly CharBuffer name = new CharBuffer (32); readonly char[] cdata = new char[3]; + readonly TextReader text; HtmlDocTypeToken doctype; HtmlAttribute attribute; string activeTagName; @@ -52,10 +54,8 @@ public class HtmlTokenizer bool bang; char quote; - TextReader text; - /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -74,8 +74,8 @@ public HtmlTokenizer (TextReader reader) /// /// /// Gets or sets whether or not the tokenizer should decode character references. - /// Character references in attribute values will still be decoded - /// even if this value is set to false. + /// Character references in attribute values will still be decoded + /// even if this value is set to false. /// /// true if character references should be decoded; otherwise, false. public bool DecodeCharacterReferences { @@ -93,6 +93,19 @@ public HtmlNamespace HtmlNamespace { get; private set; } + /// + /// Get or set whether or not the tokenizer should ignore truncated tags. + /// + /// + /// Gets or sets whether or not the tokenizer should ignore truncated tags. + /// If false and the stream abrubtly ends in the middle of an HTML tag, it will be + /// treated as an instead. + /// + /// true if truncated tags should be ignored; otherwise, false. + public bool IgnoreTruncatedTags { + get; set; + } + /// /// Gets the current line number. /// @@ -116,7 +129,7 @@ public int LineNumber { /// Combined with , a value of 1,1 indicates /// the start of the document. /// - /// The current line number. + /// The column position of the current line. public int LinePosition { get; private set; } @@ -231,19 +244,26 @@ protected virtual HtmlAttribute CreateAttribute (string name) return new HtmlAttribute (name); } - static bool IsAlphaNumeric (char c) + [MethodImpl (MethodImplOptions.AggressiveInlining)] + static bool IsAlphaNumeric (int c) { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); + return ((uint) (c - 'A') <= 'Z' - 'A') || ((uint) (c - 'a') <= 'z' - 'a') || ((uint) (c - '0') <= '9' - '0'); } - static bool IsAsciiLetter (char c) + [MethodImpl (MethodImplOptions.AggressiveInlining)] + static bool IsAsciiLetter (int c) { - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + return ((uint) (c - 'A') <= 'Z' - 'A') || ((uint) (c - 'a') <= 'z' - 'a'); } - static char ToLower (char c) + [MethodImpl (MethodImplOptions.AggressiveInlining)] + static char ToLower (int c) { - return (c >= 'A' && c <= 'Z') ? (char) (c + 0x20) : c; + // check if the char is within the uppercase range + if ((uint) (c - 'A') <= 'Z' - 'A') + return (char) (c + 0x20); + + return (char) c; } int Peek () @@ -299,7 +319,7 @@ HtmlToken EmitCommentToken (string comment, bool bogus = false) return token; } - HtmlToken EmitCommentToken (StringBuilder comment, bool bogus = false) + HtmlToken EmitCommentToken (CharBuffer comment, bool bogus = false) { return EmitCommentToken (comment.ToString (), bogus); } @@ -312,11 +332,16 @@ HtmlToken EmitDocType () return token; } - HtmlToken EmitDataToken (bool encodeEntities) + HtmlToken EmitDataToken (bool encodeEntities, bool truncated) { if (data.Length == 0) return null; + if (truncated && IgnoreTruncatedTags) { + data.Length = 0; + return null; + } + var token = CreateDataToken (data.ToString ()); token.EncodeEntities = encodeEntities; data.Length = 0; @@ -406,7 +431,7 @@ HtmlToken ReadCharacterReference (HtmlTokenizerState next) TokenizerState = HtmlTokenizerState.EndOfFile; data.Append ('&'); - return EmitDataToken (true); + return EmitDataToken (true, false); } c = (char) nc; @@ -424,12 +449,15 @@ HtmlToken ReadCharacterReference (HtmlTokenizerState next) while (entity.Push (c)) { Read (); + if (c == ';') + break; + if ((nc = Peek ()) == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; data.Append (entity.GetPushedInput ()); entity.Reset (); - return EmitDataToken (true); + return EmitDataToken (true, false); } c = (char) nc; @@ -440,11 +468,6 @@ HtmlToken ReadCharacterReference (HtmlTokenizerState next) data.Append (entity.GetValue ()); entity.Reset (); - if (c == ';') { - // consume the ';' - Read (); - } - return null; } @@ -476,7 +499,7 @@ HtmlToken ReadGenericRawTextEndTagOpen (bool decoded, HtmlTokenizerState rawText if (nc == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (decoded); + return EmitDataToken (decoded, true); } c = (char) nc; @@ -505,7 +528,7 @@ HtmlToken ReadGenericRawTextEndTagName (bool decoded, HtmlTokenizerState rawText TokenizerState = HtmlTokenizerState.EndOfFile; name.Length = 0; - return EmitDataToken (decoded); + return EmitDataToken (decoded, true); } c = (char) nc; @@ -585,7 +608,7 @@ HtmlToken ReadData () } } while (TokenizerState == HtmlTokenizerState.Data); - return EmitDataToken (DecodeCharacterReferences); + return EmitDataToken (DecodeCharacterReferences, false); } // 8.2.4.2 Character reference in data state @@ -618,14 +641,14 @@ HtmlToken ReadRcData () goto default; case '<': TokenizerState = HtmlTokenizerState.RcDataLessThan; - return EmitDataToken (DecodeCharacterReferences); + return EmitDataToken (DecodeCharacterReferences, false); default: data.Append (c == '\0' ? '\uFFFD' : c); break; } } while (TokenizerState == HtmlTokenizerState.RcData); - return EmitDataToken (DecodeCharacterReferences); + return EmitDataToken (DecodeCharacterReferences, false); } // 8.2.4.4 Character reference in RCDATA state @@ -651,14 +674,14 @@ HtmlToken ReadRawText () switch (c) { case '<': TokenizerState = HtmlTokenizerState.RawTextLessThan; - return EmitDataToken (false); + return EmitDataToken (false, false); default: data.Append (c == '\0' ? '\uFFFD' : c); break; } } while (TokenizerState == HtmlTokenizerState.RawText); - return EmitDataToken (false); + return EmitDataToken (false, false); } // 8.2.4.6 Script data state @@ -702,7 +725,7 @@ HtmlToken ReadPlainText () TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, false); } // 8.2.4.8 Tag open state @@ -712,8 +735,8 @@ HtmlToken ReadTagOpen () char c; if (nc == -1) { + var token = IgnoreTruncatedTags ? null : CreateDataToken ("<"); TokenizerState = HtmlTokenizerState.EndOfFile; - var token = CreateDataToken ("<"); return token; } @@ -757,7 +780,7 @@ HtmlToken ReadEndTagOpen () if (nc == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -797,7 +820,7 @@ HtmlToken ReadTagName () TokenizerState = HtmlTokenizerState.EndOfFile; name.Length = 0; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1416,7 +1439,7 @@ HtmlToken ReadBeforeAttributeName () TokenizerState = HtmlTokenizerState.EndOfFile; tag = null; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1455,7 +1478,7 @@ HtmlToken ReadAttributeName () name.Length = 0; tag = null; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1499,7 +1522,7 @@ HtmlToken ReadAfterAttributeName () TokenizerState = HtmlTokenizerState.EndOfFile; tag = null; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1540,7 +1563,7 @@ HtmlToken ReadBeforeAttributeValue () TokenizerState = HtmlTokenizerState.EndOfFile; tag = null; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1585,7 +1608,7 @@ HtmlToken ReadAttributeValueQuoted () TokenizerState = HtmlTokenizerState.EndOfFile; name.Length = 0; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1626,7 +1649,7 @@ HtmlToken ReadAttributeValueUnquoted () TokenizerState = HtmlTokenizerState.EndOfFile; name.Length = 0; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1666,14 +1689,13 @@ HtmlToken ReadCharacterReferenceInAttributeValue () { char additionalAllowedCharacter = quote == '\0' ? '>' : quote; int nc = Peek (); - bool consume; char c; if (nc == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; name.Length = 0; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1682,13 +1704,11 @@ HtmlToken ReadCharacterReferenceInAttributeValue () case '\t': case '\r': case '\n': case '\f': case ' ': case '<': case '&': // no character is consumed, emit '&' name.Append ('&'); - consume = false; break; default: if (c == additionalAllowedCharacter) { // this is not a character reference, nothing is consumed name.Append ('&'); - consume = false; break; } @@ -1697,13 +1717,16 @@ HtmlToken ReadCharacterReferenceInAttributeValue () while (entity.Push (c)) { Read (); + if (c == ';') + break; + if ((nc = Peek ()) == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; data.Length--; data.Append (entity.GetPushedInput ()); entity.Reset (); - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1720,7 +1743,6 @@ HtmlToken ReadCharacterReferenceInAttributeValue () data.Length--; data.Append (pushed); name.Append (value); - consume = c == ';'; entity.Reset (); break; } @@ -1730,9 +1752,6 @@ HtmlToken ReadCharacterReferenceInAttributeValue () else TokenizerState = HtmlTokenizerState.AttributeValueQuoted; - if (consume) - Read (); - return null; } @@ -1746,7 +1765,7 @@ HtmlToken ReadAfterAttributeValueQuoted () if (nc == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1786,7 +1805,7 @@ HtmlToken ReadSelfClosingStartTag () if (nc == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1838,7 +1857,7 @@ HtmlToken ReadMarkupDeclarationOpen () while (count < 2) { if ((nc = Peek ()) == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } if ((c = (char) nc) != '-') @@ -1869,7 +1888,7 @@ HtmlToken ReadMarkupDeclarationOpen () while (count < 7) { if ((nc = Read ()) == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; @@ -1901,7 +1920,7 @@ HtmlToken ReadMarkupDeclarationOpen () while (count < 7) { if ((nc = Read ()) == -1) { TokenizerState = HtmlTokenizerState.EndOfFile; - return EmitDataToken (false); + return EmitDataToken (false, true); } c = (char) nc; diff --git a/MimeKit/Text/HtmlTokenizerState.cs b/MimeKit/Text/HtmlTokenizerState.cs index adde2a09f2..9737df10be 100644 --- a/MimeKit/Text/HtmlTokenizerState.cs +++ b/MimeKit/Text/HtmlTokenizerState.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/HtmlUtils.cs b/MimeKit/Text/HtmlUtils.cs index 7ccb4a490b..17dce53993 100644 --- a/MimeKit/Text/HtmlUtils.cs +++ b/MimeKit/Text/HtmlUtils.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -110,7 +110,7 @@ static void HtmlAttributeEncode (TextWriter output, ICharArray value, int startI } if (c > 255 && char.IsSurrogate (c)) { - if (index + 1 < endIndex && char.IsSurrogatePair (c, value[index])) { + if (index < endIndex && char.IsSurrogatePair (c, value[index])) { unichar = char.ConvertToUtf32 (c, value[index]); index++; } else { @@ -171,7 +171,7 @@ public static void HtmlAttributeEncode (TextWriter output, char[] value, int sta throw new ArgumentOutOfRangeException (nameof (count)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); HtmlAttributeEncode (output, new CharArray (value), startIndex, count, quote); } @@ -209,7 +209,7 @@ public static string HtmlAttributeEncode (char[] value, int startIndex, int coun throw new ArgumentOutOfRangeException (nameof (count)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); var encoded = new StringBuilder (); @@ -257,7 +257,7 @@ public static void HtmlAttributeEncode (TextWriter output, string value, int sta throw new ArgumentOutOfRangeException (nameof (count)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); HtmlAttributeEncode (output, new CharString (value), startIndex, count, quote); } @@ -288,7 +288,7 @@ public static void HtmlAttributeEncode (TextWriter output, string value, char qu throw new ArgumentNullException (nameof (value)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); HtmlAttributeEncode (output, new CharString (value), 0, value.Length, quote); } @@ -326,7 +326,7 @@ public static string HtmlAttributeEncode (string value, int startIndex, int coun throw new ArgumentOutOfRangeException (nameof (count)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); var encoded = new StringBuilder (); @@ -357,7 +357,7 @@ public static string HtmlAttributeEncode (string value, char quote = '"') throw new ArgumentNullException (nameof (value)); if (quote != '"' && quote != '\'') - throw new ArgumentException ("quote"); + throw new ArgumentException ("The quote character must either be '\"' or '\''.", nameof (quote)); var encoded = new StringBuilder (); @@ -414,7 +414,7 @@ static void HtmlEncode (TextWriter output, ICharArray data, int startIndex, int } if (c > 255 && char.IsSurrogate (c)) { - if (index + 1 < endIndex && char.IsSurrogatePair (c, data[index])) { + if (index < endIndex && char.IsSurrogatePair (c, data[index])) { unichar = char.ConvertToUtf32 (c, data[index]); index++; } else { @@ -667,9 +667,6 @@ public static void HtmlDecode (TextWriter output, string data, int startIndex, i output.Write (entity.GetValue ()); entity.Reset (); - - if (index < endIndex && data[index] == ';') - index++; } else { output.Write (data[index++]); } diff --git a/MimeKit/Text/HtmlWriter.cs b/MimeKit/Text/HtmlWriter.cs index c173954dc1..ee7cee8e9e 100644 --- a/MimeKit/Text/HtmlWriter.cs +++ b/MimeKit/Text/HtmlWriter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,12 +28,6 @@ using System.IO; using System.Text; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#else -using Encoding = System.Text.Encoding; -#endif - namespace MimeKit.Text { /// /// An HTML writer. @@ -50,7 +44,7 @@ public class HtmlWriter : IDisposable bool empty; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -74,7 +68,7 @@ public HtmlWriter (Stream stream, Encoding encoding) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -93,11 +87,11 @@ public HtmlWriter (TextWriter output) /// /// Releas unmanaged resources and perform other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// ~HtmlWriter () { @@ -918,12 +912,12 @@ protected virtual void Dispose (bool disposing) } /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After calling - /// , you must release all references to the so the garbage - /// collector can reclaim the memory that the was occupying. + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After calling + /// , you must release all references to the so the garbage + /// collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); diff --git a/MimeKit/Text/HtmlWriterState.cs b/MimeKit/Text/HtmlWriterState.cs index f7dcf57239..2836a8d91a 100644 --- a/MimeKit/Text/HtmlWriterState.cs +++ b/MimeKit/Text/HtmlWriterState.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/ICharArray.cs b/MimeKit/Text/ICharArray.cs index 7c5d62556a..cefb92b9c0 100644 --- a/MimeKit/Text/ICharArray.cs +++ b/MimeKit/Text/ICharArray.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/PlainTextPreviewer.cs b/MimeKit/Text/PlainTextPreviewer.cs new file mode 100644 index 0000000000..9adffd091f --- /dev/null +++ b/MimeKit/Text/PlainTextPreviewer.cs @@ -0,0 +1,158 @@ +// +// PlainTextPreviewer.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +namespace MimeKit.Text { + /// + /// A text previewer for plain text. + /// + /// + /// A text previewer for plain text. + /// + public class PlainTextPreviewer : TextPreviewer + { + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new previewer for plain text. + /// + public PlainTextPreviewer () + { + } + + /// + /// Get the input format. + /// + /// + /// Gets the input format. + /// + /// The input format. + public override TextFormat InputFormat { + get { return TextFormat.Plain; } + } + + static bool IsWhiteSpace (char c) + { + return char.IsWhiteSpace (c) || (c >= 0x200B && c <= 0x200D); + } + + /// + /// Get a text preview of a string of text. + /// + /// + /// Gets a text preview of a string of text. + /// + /// The original text. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public override string GetPreviewText (string text) + { + if (text == null) + throw new ArgumentNullException (nameof (text)); + + if (text.Length == 0) + return string.Empty; + + var preview = new char[Math.Min (MaximumPreviewLength, text.Length)]; + int previewLength = 0; + var lwsp = true; + int i; + + for (i = 0; i < text.Length && previewLength < preview.Length; i++) { + if (IsWhiteSpace (text[i])) { + if (!lwsp) { + preview[previewLength++] = ' '; + lwsp = true; + } + } else { + preview[previewLength++] = text[i]; + lwsp = false; + } + } + + if (lwsp && previewLength > 0) + previewLength--; + + if (i < text.Length) + preview[previewLength - 1] = '\u2026'; + + return new string (preview, 0, previewLength); + } + + /// + /// Get a text preview of a stream of text. + /// + /// + /// Gets a text preview of a stream of text. + /// + /// The original text stream. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public override string GetPreviewText (TextReader reader) + { + if (reader == null) + throw new ArgumentNullException (nameof (reader)); + + var preview = new char[MaximumPreviewLength]; + var buffer = new char[4096]; + int previewLength = 0; + var lwsp = true; + int nread, i; + + while ((nread = reader.ReadBlock (buffer, 0, buffer.Length)) > 0) { + for (i = 0; i < nread && previewLength < preview.Length; i++) { + if (char.IsWhiteSpace (buffer[i])) { + if (!lwsp) { + preview[previewLength++] = ' '; + lwsp = true; + } + } else { + preview[previewLength++] = buffer[i]; + lwsp = false; + } + } + + if (i < nread) { + preview[previewLength - 1] = '\u2026'; + lwsp = false; + break; + } + } + + if (lwsp && previewLength > 0) + previewLength--; + + return new string (preview, 0, previewLength); + } + } +} diff --git a/MimeKit/Text/TextConverter.cs b/MimeKit/Text/TextConverter.cs index 78e5633e93..2003c39185 100644 --- a/MimeKit/Text/TextConverter.cs +++ b/MimeKit/Text/TextConverter.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,16 +29,6 @@ using System.Text; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#else -using Encoding = System.Text.Encoding; -using Encoder = System.Text.Encoder; -using Decoder = System.Text.Decoder; -#endif - namespace MimeKit.Text { /// /// An abstract class for converting text from one format to another. @@ -80,10 +70,10 @@ static TextConverter () } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// protected TextConverter () { @@ -204,14 +194,38 @@ public int OutputStreamBufferSize { } } + /// + /// Get or set the text that will be appended to the end of the output. + /// + /// + /// Gets or sets the text that will be appended to the end of the output. + /// The footer must be set before conversion begins. + /// + /// The footer. + public string Footer { + get; set; + } + + /// + /// Get or set text that will be prepended to the beginning of the output. + /// + /// + /// Gets or sets the text that will be prepended to the beginning of the output. + /// The header must be set before conversion begins. + /// + /// The header. + public string Header { + get; set; + } + TextReader CreateReader (Stream stream) { - return new StreamReader (stream, InputEncoding, DetectEncodingFromByteOrderMark, InputStreamBufferSize); + return new StreamReader (stream, InputEncoding, DetectEncodingFromByteOrderMark, InputStreamBufferSize, true); } TextWriter CreateWriter (Stream stream) { - return new StreamWriter (stream, OutputEncoding, OutputStreamBufferSize); + return new StreamWriter (stream, OutputEncoding, OutputStreamBufferSize, true); } /// @@ -237,7 +251,11 @@ public virtual void Convert (Stream source, Stream destination) if (destination == null) throw new ArgumentNullException (nameof (destination)); - Convert (CreateReader (source), CreateWriter (destination)); + using (var writer = CreateWriter (destination)) { + using (var reader = CreateReader (source)) + Convert (reader, writer); + writer.Flush (); + } } /// @@ -263,7 +281,8 @@ public virtual void Convert (Stream source, TextWriter writer) if (writer == null) throw new ArgumentNullException (nameof (writer)); - Convert (CreateReader (source), writer); + using (var reader = CreateReader (source)) + Convert (reader, writer); } /// @@ -289,7 +308,10 @@ public virtual void Convert (TextReader reader, Stream destination) if (destination == null) throw new ArgumentNullException (nameof (destination)); - Convert (reader, CreateWriter (destination)); + using (var writer = CreateWriter (destination)) { + Convert (reader, writer); + writer.Flush (); + } } /// diff --git a/MimeKit/Text/TextFormat.cs b/MimeKit/Text/TextFormat.cs index 3c394c0386..673f2a2ffb 100644 --- a/MimeKit/Text/TextFormat.cs +++ b/MimeKit/Text/TextFormat.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Text/TextPreviewer.cs b/MimeKit/Text/TextPreviewer.cs new file mode 100644 index 0000000000..b0b195cb3c --- /dev/null +++ b/MimeKit/Text/TextPreviewer.cs @@ -0,0 +1,239 @@ +// +// PreviewGenerator.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit.Utils; + +namespace MimeKit.Text { + /// + /// An abstract class for generating a text preview of a message. + /// + /// + /// An abstract class for generating a text preview of a message. + /// + public abstract class TextPreviewer + { + int maximumPreviewLength; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Initialize a new instance of the class. + /// + protected TextPreviewer () + { + maximumPreviewLength = 230; + } + + /// + /// Get the input format. + /// + /// + /// Gets the input format. + /// + /// The input format. + public abstract TextFormat InputFormat { + get; + } + + /// + /// Get or set the maximum text preview length. + /// + /// + /// Gets or sets the maximum text preview length. + /// The default value is 230 which is what the GMail web API seems to use. + /// + /// The maximum text preview length. + /// + /// is less than 1 or greater than 1024. + /// + public int MaximumPreviewLength { + get { return maximumPreviewLength; } + set { + if (value < 1 || value > 1024) + throw new ArgumentOutOfRangeException (nameof (value)); + + maximumPreviewLength = value; + } + } + + static TextPreviewer Create (TextFormat format) + { + switch (format) { + case TextFormat.Html: return new HtmlTextPreviewer (); + default: return new PlainTextPreviewer (); + } + } + + /// + /// Get a text preview of the text part. + /// + /// + /// Gets a text preview of the text part. + /// + /// The text part. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public static string GetPreviewText (TextPart body) + { + if (body == null) + throw new ArgumentNullException (nameof (body)); + + if (body.Content == null) + return string.Empty; + + var encoding = body.ContentType.CharsetEncoding; + var buffer = new byte[16 * 1024]; + int nread = 0; + + using (var content = body.Content.Open ()) { + int n; + + do { + if ((n = content.Read (buffer, nread, buffer.Length - nread)) <= 0) + break; + + nread += n; + } while (nread < buffer.Length); + } + + if (encoding == null) { + if (!CharsetUtils.TryGetBomEncoding (buffer, nread, out encoding)) + encoding = CharsetUtils.UTF8; + } + + using (var stream = new MemoryStream (buffer, 0, nread, false)) { + var previewer = Create (body.Format); + + try { + return previewer.GetPreviewText (stream, encoding); + } catch (DecoderFallbackException) { + stream.Position = 0; + + return previewer.GetPreviewText (stream, CharsetUtils.Latin1); + } + } + } + + /// + /// Get a text preview of a string of text. + /// + /// + /// Gets a text preview of a string of text. + /// + /// The original text. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public virtual string GetPreviewText (string text) + { + if (text == null) + throw new ArgumentNullException (nameof (text)); + + using (var reader = new StringReader (text)) + return GetPreviewText (reader); + } + + /// + /// Get a text preview of a stream of text in the specified charset. + /// + /// + /// Get a text preview of a stream of text in the specified charset. + /// + /// The original text stream. + /// The charset encoding of the stream. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// -or- + /// is null. + /// + public virtual string GetPreviewText (Stream stream, string charset) + { + if (stream == null) + throw new ArgumentNullException (nameof (stream)); + + if (charset == null) + throw new ArgumentNullException (nameof (charset)); + + Encoding encoding; + + try { + encoding = CharsetUtils.GetEncoding (charset); + } catch (NotSupportedException) { + encoding = CharsetUtils.UTF8; + } + + return GetPreviewText (stream, encoding); + } + + /// + /// Get a text preview of a stream of text in the specified encoding. + /// + /// + /// Get a text preview of a stream of text in the specified encoding. + /// + /// The original text stream. + /// The encoding of the stream. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// -or- + /// is null. + /// + public virtual string GetPreviewText (Stream stream, Encoding encoding) + { + if (stream == null) + throw new ArgumentNullException (nameof (stream)); + + if (encoding == null) + throw new ArgumentNullException (nameof (encoding)); + + using (var reader = new StreamReader (stream, encoding, false, 4096, true)) + return GetPreviewText (reader); + } + + /// + /// Get a text preview of a stream of text. + /// + /// + /// Gets a text preview of a stream of text. + /// + /// The original text stream. + /// A string representing a shortened preview of the original text. + /// + /// is null. + /// + public abstract string GetPreviewText (TextReader reader); + } +} diff --git a/MimeKit/Text/TextToFlowed.cs b/MimeKit/Text/TextToFlowed.cs index 7423a1dafa..c3263376a0 100644 --- a/MimeKit/Text/TextToFlowed.cs +++ b/MimeKit/Text/TextToFlowed.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,11 +39,10 @@ namespace MimeKit.Text { /// public class TextToFlowed : TextConverter { - const int OptimalLineLength = 66; const int MaxLineLength = 78; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new text to flowed text converter. @@ -74,30 +73,6 @@ public override TextFormat OutputFormat { get { return TextFormat.Flowed; } } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - static string Unquote (string line, out int quoteDepth) { int index = 0; @@ -139,7 +114,7 @@ static string GetFlowedLine (StringBuilder flowed, string line, ref int index, i flowed.Append ('>', quoteDepth); // Space-stuffed lines which start with a space, "From ", or ">". - if (quoteDepth > 0 || StartsWith (line, index, "From ")) + if (quoteDepth > 0 || (line.Length > index && line[index] == ' ') || StartsWith (line, index, "From ")) flowed.Append (' '); if (flowed.Length + (line.Length - index) <= MaxLineLength) { @@ -150,18 +125,34 @@ static string GetFlowedLine (StringBuilder flowed, string line, ref int index, i } do { - do { - flowed.Append (line[index++]); - } while (flowed.Length + 1 < MaxLineLength && index < line.Length && line[index] != ' '); - - if (flowed.Length >= OptimalLineLength) { - flowed.Append (' '); + int nextSpace = line.IndexOf (' ', index); + int wordEnd = nextSpace == -1 ? line.Length : nextSpace; + int softBreak = nextSpace == -1 ? 0 : 2; // 2 = space + soft-break space + int wordLength = wordEnd - index; + + if (flowed.Length + wordLength + softBreak <= MaxLineLength) { + // The entire word will fit on the remainder of the line. + flowed.Append (line, index, wordLength); + index = wordEnd; + } else if (wordLength > MaxLineLength - (quoteDepth + 1)) { + // Even if we insert a soft-break here, the word is longer than what will fit on its own line. + // No matter what we do, we will need to break the word apart. + wordLength = MaxLineLength - (flowed.Length + 1); + flowed.Append (line, index, wordLength); + index += wordLength; + break; + } else { + // Only part of the word will fit on the remainder of this line, but it will easily fit + // on its own line. Insert a soft-break so that we don't break apart this word. break; } while (flowed.Length + 1 < MaxLineLength && index < line.Length && line[index] == ' ') flowed.Append (line[index++]); - } while (index < line.Length && flowed.Length < OptimalLineLength); + } while (index < line.Length && flowed.Length + 1 < MaxLineLength); + + if (index < line.Length) + flowed.Append (' '); return flowed.ToString (); } @@ -198,18 +189,17 @@ public override void Convert (TextReader reader, TextWriter writer) flowed = new StringBuilder (MaxLineLength); while ((line = reader.ReadLine ()) != null) { - int quoteDepth; - int index = 0; - // Trim spaces before user-inserted hard line breaks. line = line.TrimEnd (' '); - line = Unquote (line, out quoteDepth); + line = Unquote (line, out var quoteDepth); // Ensure all lines (fixed and flowed) are 78 characters or fewer in // length, counting any trailing space as well as a space added as // stuffing, but not counting the CRLF, unless a word by itself // exceeds 78 characters. + int index = 0; + do { var flowedLine = GetFlowedLine (flowed, line, ref index, quoteDepth); writer.WriteLine (flowedLine); diff --git a/MimeKit/Text/TextToHtml.cs b/MimeKit/Text/TextToHtml.cs index c7721289da..8613630cf5 100644 --- a/MimeKit/Text/TextToHtml.cs +++ b/MimeKit/Text/TextToHtml.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,7 +43,7 @@ public class TextToHtml : TextConverter readonly UrlScanner scanner; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new text to HTML converter. @@ -78,18 +78,6 @@ public override TextFormat OutputFormat { get { return TextFormat.Html; } } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - /// /// Get or set the footer format. /// @@ -101,18 +89,6 @@ public HeaderFooterFormat FooterFormat { get; set; } - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - /// /// Get or set the header format. /// diff --git a/MimeKit/Text/TextToText.cs b/MimeKit/Text/TextToText.cs index dede8cd6c2..5df0bf1fdd 100644 --- a/MimeKit/Text/TextToText.cs +++ b/MimeKit/Text/TextToText.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,7 @@ namespace MimeKit.Text { public class TextToText : TextConverter { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new text to text converter. @@ -68,41 +68,6 @@ public override TextFormat OutputFormat { get { return TextFormat.Plain; } } - /// - /// Get or set the text that will be appended to the end of the output. - /// - /// - /// Gets or sets the text that will be appended to the end of the output. - /// The footer must be set before conversion begins. - /// - /// The footer. - public string Footer { - get; set; - } - - /// - /// Get or set the footer format. - /// - /// - /// Gets or sets the footer format. - /// - /// The footer format. - public HeaderFooterFormat FooterFormat { - get; set; - } - - /// - /// Get or set text that will be prepended to the beginning of the output. - /// - /// - /// Gets or sets the text that will be prepended to the beginning of the output. - /// The header must be set before conversion begins. - /// - /// The header. - public string Header { - get; set; - } - /// /// Convert the contents of from the to the /// and uses the to write the resulting text. diff --git a/MimeKit/Text/Trie.cs b/MimeKit/Text/Trie.cs index d03df99989..0862261477 100644 --- a/MimeKit/Text/Trie.cs +++ b/MimeKit/Text/Trie.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -66,7 +66,7 @@ public TrieMatch (char value) bool icase; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -80,7 +80,7 @@ public Trie (bool ignoreCase) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -324,6 +324,9 @@ public int Search (char[] text, int startIndex, int count, out string pattern) /// public int Search (char[] text, int startIndex, out string pattern) { + if (text == null) + throw new ArgumentNullException (nameof (text)); + return Search (text, startIndex, text.Length - startIndex, out pattern); } @@ -341,6 +344,9 @@ public int Search (char[] text, int startIndex, out string pattern) /// public int Search (char[] text, out string pattern) { + if (text == null) + throw new ArgumentNullException (nameof (text)); + return Search (text, 0, text.Length, out pattern); } } diff --git a/MimeKit/Text/UrlScanner.cs b/MimeKit/Text/UrlScanner.cs index a3ef00c51c..3b0dda748a 100644 --- a/MimeKit/Text/UrlScanner.cs +++ b/MimeKit/Text/UrlScanner.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -70,7 +70,7 @@ class UrlScanner const string AtomCharacters = "!#$%&'*+-/=?^_`{|}~"; const string UrlSafeCharacters = "$-_.+!*'(),{}|\\^~[]`#%\";/?:@&="; - readonly Dictionary patterns = new Dictionary (); + readonly Dictionary patterns = new Dictionary (StringComparer.Ordinal); readonly Trie trie = new Trie (true); public UrlScanner () diff --git a/MimeKit/TextPart.cs b/MimeKit/TextPart.cs index 2fcb633688..1f0cd42870 100644 --- a/MimeKit/TextPart.cs +++ b/MimeKit/TextPart.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,22 +28,10 @@ using System.IO; using System.Text; -#if PORTABLE -using EncoderReplacementFallback = Portable.Text.EncoderReplacementFallback; -using DecoderReplacementFallback = Portable.Text.DecoderReplacementFallback; -using EncoderExceptionFallback = Portable.Text.EncoderExceptionFallback; -using DecoderExceptionFallback = Portable.Text.DecoderExceptionFallback; -using EncoderFallbackException = Portable.Text.EncoderFallbackException; -using DecoderFallbackException = Portable.Text.DecoderFallbackException; -using DecoderFallbackBuffer = Portable.Text.DecoderFallbackBuffer; -using DecoderFallback = Portable.Text.DecoderFallback; -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - +using MimeKit.IO; using MimeKit.Text; using MimeKit.Utils; +using MimeKit.IO.Filters; namespace MimeKit { /// @@ -61,10 +49,10 @@ namespace MimeKit { public class TextPart : MimePart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -75,7 +63,7 @@ public TextPart (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with the specified text subtype. /// /// @@ -114,8 +102,7 @@ public TextPart (string subtype, params object[] args) : this (subtype) if (obj == null || TryInit (obj)) continue; - var enc = obj as Encoding; - if (enc != null) { + if (obj is Encoding enc) { if (encoding != null) throw new ArgumentException ("An encoding should not be specified more than once."); @@ -123,8 +110,7 @@ public TextPart (string subtype, params object[] args) : this (subtype) continue; } - var str = obj as string; - if (str != null) { + if (obj is string str) { if (text != null) throw new ArgumentException ("The text should not be specified more than once."); @@ -146,7 +132,7 @@ internal TextPart (ContentType contentType) : base (contentType) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with the specified text subtype. /// /// @@ -185,7 +171,7 @@ static string GetMediaSubtype (TextFormat format) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with the specified text format. /// /// @@ -202,7 +188,7 @@ public TextPart (TextFormat format) : base ("text", GetMediaSubtype (format)) } /// - /// Initializes a new instance of the + /// Initialize a new instance of the /// class with a Content-Type of text/plain. /// /// @@ -212,6 +198,42 @@ public TextPart () : base ("text", "plain") { } + /// + /// Get the text format of the content. + /// + /// + /// Gets the text format of the content. + /// + /// The text format of the content. + public TextFormat Format { + get { + if (ContentType.MediaType.Equals ("text", StringComparison.OrdinalIgnoreCase)) { + if (ContentType.MediaSubtype.Equals ("plain")) { + string format; + + if (ContentType.Parameters.TryGetValue ("format", out format)) { + format = format.Trim (); + + if (format.Equals ("flowed", StringComparison.OrdinalIgnoreCase)) + return TextFormat.Flowed; + } + } else if (ContentType.MediaSubtype.Equals ("html", StringComparison.OrdinalIgnoreCase)) { + return TextFormat.Html; + } else if (ContentType.MediaSubtype.Equals ("rtf", StringComparison.OrdinalIgnoreCase)) { + return TextFormat.RichText; + } else if (ContentType.MediaSubtype.Equals ("enriched", StringComparison.OrdinalIgnoreCase)) { + return TextFormat.Enriched; + } else if (ContentType.MediaSubtype.Equals ("richtext", StringComparison.OrdinalIgnoreCase)) { + return TextFormat.Enriched; + } + } else if (ContentType.IsMimeType ("application", "rtf")) { + return TextFormat.RichText; + } + + return TextFormat.Plain; + } + } + /// /// Gets whether or not this text part contains enriched text. /// @@ -220,7 +242,7 @@ public TextPart () : base ("text", "plain") /// predecessor, text/richtext (not to be confused with text/rtf). /// /// true if the text is enriched; otherwise, false. - bool IsEnriched { + public bool IsEnriched { get { return ContentType.IsMimeType ("text", "enriched") || ContentType.IsMimeType ("text", "richtext"); } } @@ -244,7 +266,7 @@ public bool IsFlowed { format = format.Trim (); - return format.ToLowerInvariant () == "flowed"; + return format.Equals ("flowed", StringComparison.OrdinalIgnoreCase); } } @@ -285,52 +307,22 @@ public bool IsRichText { } /// - /// Gets the decoded text content. + /// Get the decoded text content. /// /// /// If the charset parameter on the /// is set, it will be used in order to convert the raw content into unicode. - /// If that fails or if the charset parameter is not set, iso-8859-1 will be - /// used instead. + /// If that fails or if the charset parameter is not set, the first 2 bytes of + /// the content will be checked for a unicode BOM. If a BOM exists, then that + /// will be used for conversion. If no BOM is found, then UTF-8 is attempted. + /// If conversion fails, then iso-8859-1 will be used as the final fallback. /// For more control, use /// or . /// - /// The text. + /// The decocded text. public string Text { get { - if (Content == null) - return string.Empty; - - var charset = ContentType.Parameters["charset"]; - - using (var memory = new MemoryStream ()) { - Content.DecodeTo (memory); - -#if !PORTABLE && !NETSTANDARD - var content = memory.GetBuffer (); -#else - var content = memory.ToArray (); -#endif - Encoding encoding = null; - - if (charset != null) { - try { - encoding = CharsetUtils.GetEncoding (charset); - } catch (NotSupportedException) { - } - } - - if (encoding == null) { - try { - return CharsetUtils.UTF8.GetString (content, 0, (int) memory.Length); - } catch (DecoderFallbackException) { - // fall back to iso-8859-1 - encoding = CharsetUtils.Latin1; - } - } - - return encoding.GetString (content, 0, (int) memory.Length); - } + return GetText (out Encoding encoding); } set { SetText (Encoding.UTF8, value); @@ -341,12 +333,12 @@ public string Text { /// Dispatches to the specific visit method for this MIME entity. /// /// - /// This default implementation for nodes - /// calls . Override this + /// This default implementation for nodes + /// calls . Override this /// method to call into a more specific method on a derived visitor class - /// of the class. However, it should still + /// of the class. However, it should still /// support unknown visitors by calling - /// . + /// . /// /// The visitor. /// @@ -380,6 +372,47 @@ internal bool IsFormat (TextFormat format) } } + /// + /// Get the decoded text and the encoding used to convert it into unicode. + /// + /// + /// If the charset parameter on the + /// is set, it will be used in order to convert the raw content into unicode. + /// If that fails or if the charset parameter is not set, the first 2 bytes of + /// the content will be checked for a unicode BOM. If a BOM exists, then that + /// will be used for conversion. If no BOM is found, then UTF-8 is attempted. + /// If conversion fails, then iso-8859-1 will be used as the final fallback. + /// For more control, use + /// or . + /// + /// The encoding used to convert the text into unicode. + /// The decoded text. + public string GetText (out Encoding encoding) + { + if (Content == null) { + encoding = Encoding.ASCII; + return string.Empty; + } + + encoding = ContentType.CharsetEncoding; + + if (encoding == null) { + try { + using (var content = Content.Open ()) { + if (!CharsetUtils.TryGetBomEncoding (content, out encoding)) + encoding = CharsetUtils.UTF8; + } + + return GetText (encoding); + } catch (DecoderFallbackException) { + // fall back to iso-8859-1 + encoding = CharsetUtils.Latin1; + } + } + + return GetText (encoding); + } + /// /// Gets the decoded text content using the provided charset encoding to /// override the charset specified in the Content-Type parameters. @@ -403,15 +436,20 @@ public string GetText (Encoding encoding) return string.Empty; using (var memory = new MemoryStream ()) { - Content.DecodeTo (memory); + using (var filtered = new FilteredStream (memory)) { + filtered.Add (new CharsetFilter (encoding, CharsetUtils.UTF8)); + filtered.Add (FormatOptions.Default.CreateNewLineFilter ()); + Content.DecodeTo (filtered); + filtered.Flush (); + } -#if !PORTABLE && !NETSTANDARD +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 var buffer = memory.GetBuffer (); #else var buffer = memory.ToArray (); #endif - return encoding.GetString (buffer, 0, (int) memory.Length); + return CharsetUtils.UTF8.GetString (buffer, 0, (int) memory.Length); } } @@ -463,8 +501,8 @@ public void SetText (Encoding encoding, string text) if (text == null) throw new ArgumentNullException (nameof (text)); - ContentType.Parameters["charset"] = CharsetUtils.GetMimeCharset (encoding); var content = new MemoryStream (encoding.GetBytes (text)); + ContentType.CharsetEncoding = encoding; Content = new MimeContent (content); } diff --git a/MimeKit/TextRfc822Headers.cs b/MimeKit/TextRfc822Headers.cs new file mode 100644 index 0000000000..6312345114 --- /dev/null +++ b/MimeKit/TextRfc822Headers.cs @@ -0,0 +1,123 @@ +// +// TextRfc822Headers.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +namespace MimeKit { + /// + /// A MIME part containing message headers as its content. + /// + /// + /// Represents MIME entities with a Content-Type of text/rfc822-headers. + /// + public class TextRfc822Headers : MessagePart + { + /// + /// Initialize a new instance of the class. + /// + /// + /// This constructor is used by . + /// + /// Information used by the constructor. + /// + /// is null. + /// + public TextRfc822Headers (MimeEntityConstructorArgs args) : base (args) + { + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new . + /// + /// An array of initialization parameters: headers and message parts. + /// + /// is null. + /// + /// + /// contains more than one . + /// -or- + /// contains one or more arguments of an unknown type. + /// + public TextRfc822Headers (params object[] args) : this () + { + MimeMessage message = null; + + foreach (object obj in args) { + if (obj == null || TryInit (obj)) + continue; + + if (obj is MimeMessage mesg) { + if (message != null) + throw new ArgumentException ("MimeMessage should not be specified more than once."); + + message = mesg; + continue; + } + + throw new ArgumentException ("Unknown initialization parameter: " + obj.GetType ()); + } + + if (message != null) + Message = message; + } + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new text/rfc822-headers MIME entity. + /// + public TextRfc822Headers () : base ("text", "rfc822-headers") + { + } + + /// + /// Dispatches to the specific visit method for this MIME entity. + /// + /// + /// This default implementation for nodes + /// calls . Override this + /// method to call into a more specific method on a derived visitor class + /// of the class. However, it should still + /// support unknown visitors by calling + /// . + /// + /// The visitor. + /// + /// is null. + /// + public override void Accept (MimeVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException (nameof (visitor)); + + visitor.VisitTextRfc822Headers (this); + } + } +} diff --git a/MimeKit/Tnef/RtfCompressedToRtf.cs b/MimeKit/Tnef/RtfCompressedToRtf.cs index 67a4b479ea..773c96f27c 100644 --- a/MimeKit/Tnef/RtfCompressedToRtf.cs +++ b/MimeKit/Tnef/RtfCompressedToRtf.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,16 +25,11 @@ // using System; +using System.Text; using MimeKit.IO.Filters; using MimeKit.Utils; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#else -using Encoding = System.Text.Encoding; -#endif - namespace MimeKit.Tnef { /// /// A filter to decompress a compressed RTF stream. @@ -76,10 +71,10 @@ enum FilterState { int size; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// Creates a new converter filter. + /// Creates a new converter filter. /// public RtfCompressedToRtf () { @@ -112,6 +107,11 @@ public bool IsValidCrc32 { bool TryReadInt32 (byte[] buffer, ref int index, int endIndex, out int value) { + if (index == endIndex) { + value = saved; + return false; + } + int nread = (saved >> 24) & 0xFF; saved &= 0x00FFFFFF; @@ -242,7 +242,7 @@ protected override byte[] Filter (byte[] input, int startIndex, int length, out outputLength = 0; outputIndex = 0; - while (index < endIndex) { + while (index < endIndex && state != FilterState.Complete) { byte value = input[index++]; crc32.Update (value); @@ -314,8 +314,6 @@ protected override byte[] Filter (byte[] input, int startIndex, int length, out state = FilterState.BeginControlRun; } break; - case FilterState.Complete: - break; } } diff --git a/MimeKit/Tnef/RtfCompressionMode.cs b/MimeKit/Tnef/RtfCompressionMode.cs index 37c463c303..8949c0c630 100644 --- a/MimeKit/Tnef/RtfCompressionMode.cs +++ b/MimeKit/Tnef/RtfCompressionMode.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefAttachFlags.cs b/MimeKit/Tnef/TnefAttachFlags.cs index be8321782f..7ec444b88c 100644 --- a/MimeKit/Tnef/TnefAttachFlags.cs +++ b/MimeKit/Tnef/TnefAttachFlags.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefAttachMethod.cs b/MimeKit/Tnef/TnefAttachMethod.cs index 751b0f48d4..558e394c40 100644 --- a/MimeKit/Tnef/TnefAttachMethod.cs +++ b/MimeKit/Tnef/TnefAttachMethod.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefAttributeLevel.cs b/MimeKit/Tnef/TnefAttributeLevel.cs index 52ca004ea1..8f8fe1e1c3 100644 --- a/MimeKit/Tnef/TnefAttributeLevel.cs +++ b/MimeKit/Tnef/TnefAttributeLevel.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefAttributeTag.cs b/MimeKit/Tnef/TnefAttributeTag.cs index a831574daf..66bbee38ba 100644 --- a/MimeKit/Tnef/TnefAttributeTag.cs +++ b/MimeKit/Tnef/TnefAttributeTag.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefComplianceMode.cs b/MimeKit/Tnef/TnefComplianceMode.cs index f7a4bbd01f..8466abc7f0 100644 --- a/MimeKit/Tnef/TnefComplianceMode.cs +++ b/MimeKit/Tnef/TnefComplianceMode.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefComplianceStatus.cs b/MimeKit/Tnef/TnefComplianceStatus.cs index bb9360712a..201f953953 100644 --- a/MimeKit/Tnef/TnefComplianceStatus.cs +++ b/MimeKit/Tnef/TnefComplianceStatus.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefException.cs b/MimeKit/Tnef/TnefException.cs index 559e2b01ba..5b8f2d9093 100644 --- a/MimeKit/Tnef/TnefException.cs +++ b/MimeKit/Tnef/TnefException.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ public class TnefException : FormatException { #if SERIALIZABLE /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -63,7 +63,7 @@ protected TnefException (SerializationInfo info, StreamingContext context) : bas #endif /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -77,7 +77,7 @@ public TnefException (TnefComplianceStatus error, string message, Exception inne } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -106,12 +106,9 @@ public TnefException (TnefComplianceStatus error, string message) : base (messag [SecurityCritical] public override void GetObjectData (SerializationInfo info, StreamingContext context) { - if (info == null) - throw new ArgumentNullException (nameof (info)); + base.GetObjectData (info, context); info.AddValue ("Error", Error); - - base.GetObjectData (info, context); } #endif diff --git a/MimeKit/Tnef/TnefNameId.cs b/MimeKit/Tnef/TnefNameId.cs index 35dc8d2961..201b0a95e2 100644 --- a/MimeKit/Tnef/TnefNameId.cs +++ b/MimeKit/Tnef/TnefNameId.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -85,7 +85,7 @@ public int Id { } /// - /// Initializes a new instance of the struct. + /// Initialize a new instance of the struct. /// /// /// Creates a new with the specified integer identifier. @@ -101,7 +101,7 @@ public TnefNameId (Guid propertySetGuid, int id) } /// - /// Initializes a new instance of the struct. + /// Initialize a new instance of the struct. /// /// /// Creates a new with the specified string identifier. @@ -117,10 +117,10 @@ public TnefNameId (Guid propertySetGuid, string name) } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// /// A hash code for this instance that is suitable for use in hashing algorithms /// and data structures such as a hash table. @@ -132,14 +132,14 @@ public override int GetHashCode () } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// - /// The to compare with the current . + /// The to compare with the current . /// true if the specified is equal to the current - /// ; otherwise, false. + /// ; otherwise, false. public override bool Equals (object obj) { if (!(obj is TnefNameId)) diff --git a/MimeKit/Tnef/TnefNameIdKind.cs b/MimeKit/Tnef/TnefNameIdKind.cs index bb7d4af9eb..ff1c580e10 100644 --- a/MimeKit/Tnef/TnefNameIdKind.cs +++ b/MimeKit/Tnef/TnefNameIdKind.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefPart.cs b/MimeKit/Tnef/TnefPart.cs index 5e3219fea8..c43663a200 100644 --- a/MimeKit/Tnef/TnefPart.cs +++ b/MimeKit/Tnef/TnefPart.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,14 +26,9 @@ using System; using System.IO; +using System.Text; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#else -using Encoding = System.Text.Encoding; -#endif - using MimeKit.IO; using MimeKit.Utils; using MimeKit.IO.Filters; @@ -50,10 +45,10 @@ namespace MimeKit.Tnef { public class TnefPart : MimePart { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// - /// This constructor is used by . + /// This constructor is used by . /// /// Information used by the constructor. /// @@ -64,7 +59,7 @@ public TnefPart (MimeEntityConstructorArgs args) : base (args) } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new with a Content-Type of application/vnd.ms-tnef @@ -76,14 +71,40 @@ public TnefPart () : base ("application", "vnd.ms-tnef") FileName = "winmail.dat"; } + /// + /// Dispatches to the specific visit method for this MIME entity. + /// + /// + /// This default implementation for nodes + /// calls . Override this + /// method to call into a more specific method on a derived visitor class + /// of the class. However, it should still + /// support unknown visitors by calling + /// . + /// + /// The visitor. + /// + /// is null. + /// + public override void Accept (MimeVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException (nameof (visitor)); + + visitor.VisitTnefPart (this); + } + static void ExtractRecipientTable (TnefReader reader, MimeMessage message) { var prop = reader.TnefPropertyReader; // Note: The RecipientTable uses rows of properties... while (prop.ReadNextRow ()) { + string transmitableDisplayName = null; + string recipientDisplayName = null; + string displayName = string.Empty; InternetAddressList list = null; - string name = null, addr = null; + string addr = null; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { @@ -96,11 +117,13 @@ static void ExtractRecipientTable (TnefReader reader, MimeMessage message) } break; case TnefPropertyId.TransmitableDisplayName: - if (string.IsNullOrEmpty (name)) - name = prop.ReadValueAsString (); + transmitableDisplayName = prop.ReadValueAsString (); + break; + case TnefPropertyId.RecipientDisplayName: + recipientDisplayName = prop.ReadValueAsString (); break; case TnefPropertyId.DisplayName: - name = prop.ReadValueAsString (); + displayName = prop.ReadValueAsString (); break; case TnefPropertyId.EmailAddress: if (string.IsNullOrEmpty (addr)) @@ -114,14 +137,64 @@ static void ExtractRecipientTable (TnefReader reader, MimeMessage message) } } - if (list != null && !string.IsNullOrEmpty (addr)) + if (list != null && !string.IsNullOrEmpty (addr)) { + var name = recipientDisplayName ?? transmitableDisplayName ?? displayName; + list.Add (new MailboxAddress (name, addr)); + } + } + } + + class EmailAddress + { + public string AddrType = "SMTP"; + public string SearchKey; + public string Name; + public string Addr; + + bool CanUseSearchKey { + get { + return SearchKey != null && SearchKey.Equals ("SMTP", StringComparison.OrdinalIgnoreCase) && + SearchKey.Length > AddrType.Length && SearchKey.StartsWith (AddrType, StringComparison.Ordinal) && + SearchKey[AddrType.Length] == ':'; + } + } + + //public bool IsComplete { + // get { + // return !string.IsNullOrEmpty (Addr) || CanUseSearchKey; + // } + //} + + public bool TryGetMailboxAddress (out MailboxAddress mailbox) + { + string addr; + + if (string.IsNullOrEmpty (Addr) && CanUseSearchKey) + addr = SearchKey.Substring (AddrType.Length + 1); + else + addr = Addr; + + if (string.IsNullOrEmpty (addr) || !MailboxAddress.TryParse (addr, out mailbox)) { + mailbox = null; + return false; + } + + mailbox.Name = Name; + + return true; } } static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyBuilder builder) { var prop = reader.TnefPropertyReader; + var recipient = new EmailAddress (); + var sender = new EmailAddress (); + string normalizedSubject = null; + string subjectPrefix = null; + MailboxAddress mailbox; + var msgid = false; while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { @@ -129,6 +202,25 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { message.MessageId = prop.ReadValueAsString (); + msgid = true; + } + break; + case TnefPropertyId.TnefCorrelationKey: + // According to MSDN, PidTagTnefCorrelationKey is a unique key that is + // meant to be used to tie the TNEF attachment to the encapsulating + // message. It can be a string or a binary blob. It seems that most + // implementations use the Message-Id string, so if this property + // value looks like a Message-Id, then us it as one (unless we get a + // InternetMessageId property, in which case we use that instead. + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { + if (!msgid) { + var value = prop.ReadValueAsString (); + + if (value.Length > 5 && value[0] == '<' && value[value.Length - 1] == '>' && value.IndexOf ('@') != -1) + message.MessageId = value; + } } break; case TnefPropertyId.Subject: @@ -137,12 +229,73 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB message.Subject = prop.ReadValueAsString (); } break; + case TnefPropertyId.SubjectPrefix: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + subjectPrefix = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.NormalizedSubject: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + normalizedSubject = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.SenderName: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + sender.Name = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.SenderEmailAddress: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + sender.Addr = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.SenderSearchKey: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { + sender.SearchKey = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.SenderAddrtype: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + sender.AddrType = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.ReceivedByName: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + recipient.Name = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.ReceivedByEmailAddress: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + recipient.Addr = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.ReceivedBySearchKey: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { + recipient.SearchKey = prop.ReadValueAsString (); + } + break; + case TnefPropertyId.ReceivedByAddrtype: + if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || + prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode) { + recipient.AddrType = prop.ReadValueAsString (); + } + break; case TnefPropertyId.RtfCompressed: if (prop.PropertyTag.ValueTnefType == TnefPropertyType.String8 || prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var rtf = new TextPart ("rtf"); - rtf.ContentType.Name = "body.rtf"; var converter = new RtfCompressedToRtf (); var content = new MemoryBlockStream (); @@ -167,7 +320,6 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var html = new TextPart ("html"); - html.ContentType.Name = "body.html"; Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) @@ -185,7 +337,6 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB prop.PropertyTag.ValueTnefType == TnefPropertyType.Unicode || prop.PropertyTag.ValueTnefType == TnefPropertyType.Binary) { var plain = new TextPart ("plain"); - plain.ContentType.Name = "body.txt"; Encoding encoding; if (prop.PropertyTag.ValueTnefType != TnefPropertyType.Unicode) @@ -199,19 +350,61 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB } break; case TnefPropertyId.Importance: + // https://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx switch (prop.ReadValueAsInt32 ()) { case 2: message.Importance = MessageImportance.High; break; + case 1: message.Importance = MessageImportance.Normal; break; case 0: message.Importance = MessageImportance.Low; break; } break; case TnefPropertyId.Priority: + // https://msdn.microsoft.com/en-us/library/ee159473(v=exchg.80).aspx switch (prop.ReadValueAsInt32 ()) { - case 2: message.Priority = MessagePriority.Urgent; break; - case 0: message.Priority = MessagePriority.NonUrgent; break; + case 1: message.Priority = MessagePriority.Urgent; break; + case 0: message.Priority = MessagePriority.Normal; break; + case -1: message.Priority = MessagePriority.NonUrgent; break; + } + break; + case TnefPropertyId.Sensitivity: + // https://msdn.microsoft.com/en-us/library/ee217353(v=exchg.80).aspx + // https://tools.ietf.org/html/rfc2156#section-5.3.4 + switch (prop.ReadValueAsInt32 ()) { + case 1: message.Headers[HeaderId.Sensitivity] = "Personal"; break; + case 2: message.Headers[HeaderId.Sensitivity] = "Private"; break; + case 3: message.Headers[HeaderId.Sensitivity] = "Company-Confidential"; break; + case 0: message.Headers.Remove (HeaderId.Sensitivity); break; } break; } } + + if (string.IsNullOrEmpty (message.Subject) && !string.IsNullOrEmpty (normalizedSubject)) { + if (!string.IsNullOrEmpty (subjectPrefix)) + message.Subject = subjectPrefix + normalizedSubject; + else + message.Subject = normalizedSubject; + } + + if (sender.TryGetMailboxAddress (out mailbox)) + message.From.Add (mailbox); + + if (recipient.TryGetMailboxAddress (out mailbox)) + message.To.Add (mailbox); + } + + static TnefPart PromoteToTnefPart (MimePart part) + { + var tnef = new TnefPart (); + + foreach (var param in part.ContentType.Parameters) + tnef.ContentType.Parameters[param.Name] = param.Value; + + if (part.ContentDisposition != null) + tnef.ContentDisposition = part.ContentDisposition; + + tnef.ContentTransferEncoding = part.ContentTransferEncoding; + + return tnef; } static void ExtractAttachments (TnefReader reader, BodyBuilder builder) @@ -239,6 +432,8 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) if (attachment == null) break; + attachData = null; + while (prop.ReadNextProperty ()) { switch (prop.PropertyTag.Id) { case TnefPropertyId.AttachLongFilename: @@ -249,60 +444,27 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) attachment.FileName = prop.ReadValueAsString (); break; case TnefPropertyId.AttachContentLocation: - text = prop.ReadValueAsString (); - if (Uri.IsWellFormedUriString (text, UriKind.Absolute)) - attachment.ContentLocation = new Uri (text, UriKind.Absolute); - else if (Uri.IsWellFormedUriString (text, UriKind.Relative)) - attachment.ContentLocation = new Uri (text, UriKind.Relative); + attachment.ContentLocation = prop.ReadValueAsUri (); break; case TnefPropertyId.AttachContentBase: - text = prop.ReadValueAsString (); - attachment.ContentBase = new Uri (text, UriKind.Absolute); + attachment.ContentBase = prop.ReadValueAsUri (); break; case TnefPropertyId.AttachContentId: - attachment.ContentId = prop.ReadValueAsString (); + text = prop.ReadValueAsString (); + + var buffer = CharsetUtils.UTF8.GetBytes (text); + int index = 0; + + if (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out string msgid)) + attachment.ContentId = msgid; break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); - if (attachment.ContentDisposition == null) - attachment.ContentDisposition = new ContentDisposition (text); - else - attachment.ContentDisposition.Disposition = text; + if (ContentDisposition.TryParse (text, out ContentDisposition disposition)) + attachment.ContentDisposition = disposition; break; case TnefPropertyId.AttachData: - var stream = prop.GetRawValueReadStream (); - var content = new MemoryStream (); - var guid = new byte[16]; - - if (attachMethod == TnefAttachMethod.EmbeddedMessage) { - var tnef = new TnefPart (); - - foreach (var param in attachment.ContentType.Parameters) - tnef.ContentType.Parameters[param.Name] = param.Value; - - if (attachment.ContentDisposition != null) - tnef.ContentDisposition = attachment.ContentDisposition; - - attachment = tnef; - } - - // read the GUID - stream.Read (guid, 0, 16); - - // the rest is content - using (var filtered = new FilteredStream (content)) { - filtered.Add (filter); - stream.CopyTo (filtered, 4096); - filtered.Flush (); - } - - content.Position = 0; - - attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); - attachment.Content = new MimeContent (content); - filter.Reset (); - - builder.Attachments.Add (attachment); + attachData = prop.ReadValueAsBytes (); break; case TnefPropertyId.AttachMethod: attachMethod = (TnefAttachMethod) prop.ReadValueAsInt32 (); @@ -334,6 +496,27 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) break; } } + + if (attachData != null) { + int count = attachData.Length; + int index = 0; + + if (attachMethod == TnefAttachMethod.EmbeddedMessage) { + attachment.ContentTransferEncoding = ContentEncoding.Base64; + attachment = PromoteToTnefPart (attachment); + count -= 16; + index = 16; + } else if (attachment.ContentType.IsMimeType ("text", "*")) { + filter.Flush (attachData, index, count, out outIndex, out outLength); + attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); + filter.Reset (); + } else { + attachment.ContentTransferEncoding = ContentEncoding.Base64; + } + + attachment.Content = new MimeContent (new MemoryStream (attachData, index, count, false)); + builder.Attachments.Add (attachment); + } break; case TnefAttributeTag.AttachCreateDate: if (attachment != null) { @@ -366,11 +549,16 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) break; attachData = prop.ReadValueAsBytes (); - filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); - attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.EightBit); - attachment.Content = new MimeContent (new MemoryStream (attachData, false)); - filter.Reset (); + if (attachment.ContentType.IsMimeType ("text", "*")) { + filter.Flush (attachData, 0, attachData.Length, out outIndex, out outLength); + attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); + filter.Reset (); + } else { + attachment.ContentTransferEncoding = ContentEncoding.Base64; + } + + attachment.Content = new MimeContent (new MemoryStream (attachData, false)); builder.Attachments.Add (attachment); break; } @@ -382,6 +570,8 @@ static MimeMessage ExtractTnefMessage (TnefReader reader) var builder = new BodyBuilder (); var message = new MimeMessage (); + message.Headers.Remove (HeaderId.Date); + while (reader.ReadNextAttribute ()) { if (reader.AttributeLevel == TnefAttributeLevel.Attachment) break; @@ -413,16 +603,16 @@ static MimeMessage ExtractTnefMessage (TnefReader reader) } /// - /// Converts the TNEF content into a . + /// Converts the TNEF content into a . /// /// - /// TNEF data often contains properties that map to + /// TNEF data often contains properties that map to /// headers. TNEF data also often contains file attachments which will be /// mapped to MIME parts. /// /// A message representing the TNEF data in MIME format. /// - /// The property is null. + /// The property is null. /// public MimeMessage ConvertToMessage () { @@ -449,7 +639,7 @@ public MimeMessage ConvertToMessage () /// /// The attachments. /// - /// The property is null. + /// The property is null. /// public IEnumerable ExtractAttachments () { diff --git a/MimeKit/Tnef/TnefPropertyId.cs b/MimeKit/Tnef/TnefPropertyId.cs index 381e109dac..d4405fb330 100644 --- a/MimeKit/Tnef/TnefPropertyId.cs +++ b/MimeKit/Tnef/TnefPropertyId.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -177,6 +177,26 @@ public enum TnefPropertyId : short { /// AttachLongPathname = 0x370D, + /// + /// The MAPI property PR_ATTACHMENT_CONTACTPHOTO. + /// + AttachmentContactPhoto = 0x7FFF, + + /// + /// The MAPI property PR_ATTACHMENT_FLAGS. + /// + AttachmentFlags = 0x7FFD, + + /// + /// The MAPI property PR_ATTACHMENT_HIDDEN. + /// + AttachmentHidden = 0x7FFE, + + /// + /// The MAPI property PR_ATTACHMENT_LINKID. + /// + AttachmentLinkId = 0x7FFA, + /// /// The MAPI property PR_ATTACHMENT_X400_PARAMETERS. /// @@ -727,6 +747,16 @@ public enum TnefPropertyId : short { /// EntryId = 0x0FFF, + /// + /// The MAPI property PR_EXCEPTION_STARTTIME. + /// + ExceptionStartTime = 0x7FFB, + + /// + /// The MAPI property PR_EXCEPTION_ENDTIME. + /// + ExceptionEndTime = 0x7FFC, + /// /// The MAPI property PR_EXPAND_BEGIN_TIME. /// @@ -1117,6 +1147,11 @@ public enum TnefPropertyId : short { /// LastModificationTime = 0x3008, + /// + /// The MAPI property PR_LAST_MODIFIER_NAME. + /// + LastModifierName = 0x3FFA, + /// /// The MAPI property PR_LATEST_DELIVERY_TIME. /// @@ -1952,6 +1987,11 @@ public enum TnefPropertyId : short { /// RecipientCertificate = 0x0C13, + /// + /// The MAPI property PR_RECIPIENT_DISPLAY_NAME. + /// + RecipientDisplayName = 0x5FF6, + /// /// The MAPI property PR_RECIPIENT_NUMBER_FOR_ADVICE. /// @@ -2027,6 +2067,11 @@ public enum TnefPropertyId : short { /// ReplyRecipientNames = 0x0050, + /// + /// The MAPI property PR_REPLY_RECIPIENT_SMTP_PROXIES. + /// + ReplyRecipientSmtpProxies = 0x3FFC, + /// /// The MAPI property PR_REPLY_REQUESTED. /// @@ -2207,6 +2252,11 @@ public enum TnefPropertyId : short { /// SenderSearchKey = 0x0C1D, + /// + /// The MAPI property PR_SENDER_SIMPLE_DISP_NAME. + /// + SenderSimpleDispName = 0x4030, + /// /// The MAPI property PR_SEND_INTERNET_ENCODING. /// @@ -2257,6 +2307,11 @@ public enum TnefPropertyId : short { /// SentRepresentingSearchKey = 0x003B, + /// + /// The MAPI property PR_SENT_REPRESENTING_SIMPLE_DISP_NAME. + /// + SentRepresentingSimpleDispName = 0x4031, + /// /// The MAPI property PR_SERVICE_DELETE_FILES. /// diff --git a/MimeKit/Tnef/TnefPropertyReader.cs b/MimeKit/Tnef/TnefPropertyReader.cs index d8bbcbd443..ee7d10a428 100644 --- a/MimeKit/Tnef/TnefPropertyReader.cs +++ b/MimeKit/Tnef/TnefPropertyReader.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,20 +28,6 @@ using System.IO; using System.Text; -#if PORTABLE -using EncoderReplacementFallback = Portable.Text.EncoderReplacementFallback; -using DecoderReplacementFallback = Portable.Text.DecoderReplacementFallback; -using EncoderExceptionFallback = Portable.Text.EncoderExceptionFallback; -using DecoderExceptionFallback = Portable.Text.DecoderExceptionFallback; -using EncoderFallbackException = Portable.Text.EncoderFallbackException; -using DecoderFallbackException = Portable.Text.DecoderFallbackException; -using DecoderFallbackBuffer = Portable.Text.DecoderFallbackBuffer; -using DecoderFallback = Portable.Text.DecoderFallback; -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - namespace MimeKit.Tnef { /// /// A TNEF property reader. @@ -329,7 +315,8 @@ public Stream GetRawValueReadStream () if (valueIndex >= valueCount) throw new InvalidOperationException (); - int end = RawValueStreamOffset + RawValueLength; + int startOffset = RawValueStreamOffset; + int length = RawValueLength; if (propertyCount > 0 && reader.StreamOffset == RawValueStreamOffset) { switch (propertyTag.ValueTnefType) { @@ -337,14 +324,19 @@ public Stream GetRawValueReadStream () case TnefPropertyType.String8: case TnefPropertyType.Binary: case TnefPropertyType.Object: - ReadInt32 (); + int n = ReadInt32 (); + if (n >= 0 && n + 4 < length) + length = n + 4; break; } } valueIndex++; - return new TnefReaderStream (reader, end); + int valueEndOffset = startOffset + RawValueLength; + int dataEndOffset = startOffset + length; + + return new TnefReaderStream (reader, dataEndOffset, valueEndOffset); } bool CheckRawValueLength () @@ -413,7 +405,7 @@ static long DoubleDateToTicks (double value) { // The check done this way will take care of NaN if (!(value < OADateMaxAsDouble) || !(value > OADateMinAsDouble)) - throw new ArgumentException ("Invalid OLE Automation Date."); + throw new ArgumentException ("Invalid OLE Automation Date.", nameof (value)); long millis = (long) (value * MillisPerDay + (value >= 0 ? 0.5 : -0.5)); @@ -423,7 +415,7 @@ static long DoubleDateToTicks (double value) millis += DoubleDateOffset / TicksPerMillisecond; if (millis < 0 || millis >= MaxMillis) - throw new ArgumentException ("Invalid OLE Automation Date."); + throw new ArgumentException ("Invalid OLE Automation Date.", nameof (value)); return millis * TicksPerMillisecond; } @@ -487,7 +479,7 @@ Encoding GetMessageEncoding () if (codepage != 0 && codepage != 1252) { try { - return Encoding.GetEncoding (codepage, new EncoderExceptionFallback (), new DecoderExceptionFallback ()); + return Encoding.GetEncoding (codepage); } catch { return DefaultEncoding; } @@ -584,13 +576,13 @@ void LoadPropertyName () /// public bool ReadNextProperty () { - if (propertyIndex >= propertyCount) - return false; - while (ReadNextValue ()) { - // skip over the value... + // skip over the remaining value(s) for the current property... } + if (propertyIndex >= propertyCount) + return false; + try { var type = (TnefPropertyType) ReadInt16 (); var id = (TnefPropertyId) ReadInt16 (); @@ -632,13 +624,13 @@ public bool ReadNextProperty () /// public bool ReadNextRow () { - if (rowIndex >= rowCount) - return false; - while (ReadNextProperty ()) { - // skip over the property... + // skip over the remaining property/properties in the current row... } + if (rowIndex >= rowCount) + return false; + try { LoadPropertyCount (); rowIndex++; @@ -797,7 +789,7 @@ public int ReadTextValue (char[] buffer, int offset, int count) var bytes = new byte[n]; - n = reader.ReadAttributeRawValue (bytes, 0, bytes.Length); + n = reader.ReadAttributeRawValue (bytes, 0, n); var flush = reader.StreamOffset >= valueEndOffset; @@ -1518,10 +1510,36 @@ public string ReadValueAsString () } /// - /// Serves as a hash function for a object. + /// Reads the value as a Uri. + /// + /// + /// Reads any string or binary blob values as a Uri. + /// + /// The value as a Uri. + /// + /// There are no more values to read or the value could not be read as a string. + /// + /// + /// The TNEF stream is truncated and the value could not be read. + /// + internal Uri ReadValueAsUri () + { + var value = ReadValueAsString (); + + if (Uri.IsWellFormedUriString (value, UriKind.Absolute)) + return new Uri (value, UriKind.Absolute); + + if (Uri.IsWellFormedUriString (value, UriKind.Relative)) + return new Uri (value, UriKind.Relative); + + return null; + } + + /// + /// Serves as a hash function for a object. /// /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// /// A hash code for this instance that is suitable for use in hashing algorithms /// and data structures such as a hash table. @@ -1531,14 +1549,14 @@ public override int GetHashCode () } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// - /// The to compare with the current . + /// The to compare with the current . /// true if the specified is equal to the current - /// ; otherwise, false. + /// ; otherwise, false. public override bool Equals (object obj) { var prop = obj as TnefPropertyReader; diff --git a/MimeKit/Tnef/TnefPropertyTag.cs b/MimeKit/Tnef/TnefPropertyTag.cs index 577ac1c684..a72d50cbd2 100644 --- a/MimeKit/Tnef/TnefPropertyTag.cs +++ b/MimeKit/Tnef/TnefPropertyTag.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -379,6 +379,38 @@ public struct TnefPropertyTag /// public static readonly TnefPropertyTag AttachLongPathnameW = new TnefPropertyTag (TnefPropertyId.AttachLongPathname, TnefPropertyType.Unicode); + /// + /// The MAPI property PR_ATTACHMENT_CONTACTPHOTO. + /// + /// + /// The MAPI property PR_ATTACHMENT_CONTACTPHOTO. + /// + public static readonly TnefPropertyTag AttachmentContactPhoto = new TnefPropertyTag (TnefPropertyId.AttachmentContactPhoto, TnefPropertyType.Boolean); + + /// + /// The MAPI property PR_ATTACHMENT_FLAGS. + /// + /// + /// The MAPI property PR_ATTACHMENT_FLAGS. + /// + public static readonly TnefPropertyTag AttachmentFlags = new TnefPropertyTag (TnefPropertyId.AttachmentFlags, TnefPropertyType.Long); + + /// + /// The MAPI property PR_ATTACHMENT_HIDDEN. + /// + /// + /// The MAPI property PR_ATTACHMENT_HIDDEN. + /// + public static readonly TnefPropertyTag AttachmentHidden = new TnefPropertyTag (TnefPropertyId.AttachmentHidden, TnefPropertyType.Boolean); + + /// + /// The MAPI property PR_ATTACHMENT_LINKID. + /// + /// + /// The MAPI property PR_ATTACHMENT_LINKID. + /// + public static readonly TnefPropertyTag AttachmentLinkId = new TnefPropertyTag (TnefPropertyId.AttachmentLinkId, TnefPropertyType.Long); + /// /// The MAPI property PR_ATTACHMENT_X400_PARAMETERS. /// @@ -2483,6 +2515,22 @@ public struct TnefPropertyTag /// public static readonly TnefPropertyTag LastModificationTime = new TnefPropertyTag (TnefPropertyId.LastModificationTime, TnefPropertyType.SysTime); + /// + /// The MAPI property PR_LAST_MODIFIER_NAME. + /// + /// + /// The MAPI property PR_LAST_MODIFIER_NAME. + /// + public static readonly TnefPropertyTag LastModifierNameA = new TnefPropertyTag (TnefPropertyId.LastModifierName, TnefPropertyType.String8); + + /// + /// The MAPI property PR_LAST_MODIFIER_NAME. + /// + /// + /// The MAPI property PR_LAST_MODIFIER_NAME. + /// + public static readonly TnefPropertyTag LastModifierNameW = new TnefPropertyTag (TnefPropertyId.LastModifierName, TnefPropertyType.Unicode); + /// /// The MAPI property PR_LATEST_DELIVERY_TIME. /// @@ -4308,6 +4356,22 @@ public struct TnefPropertyTag /// public static readonly TnefPropertyTag RecipientCertificate = new TnefPropertyTag (TnefPropertyId.RecipientCertificate, TnefPropertyType.Binary); + /// + /// The MAPI property PR_RECIPIENT_DISPLAY_NAME. + /// + /// + /// The MAPI property PR_RECIPIENT_DISPLAY_NAME. + /// + public static readonly TnefPropertyTag RecipientDisplayNameA = new TnefPropertyTag (TnefPropertyId.RecipientDisplayName, TnefPropertyType.String8); + + /// + /// The MAPI property PR_RECIPIENT_DISPLAY_NAME. + /// + /// + /// The MAPI property PR_RECIPIENT_DISPLAY_NAME. + /// + public static readonly TnefPropertyTag RecipientDisplayNameW = new TnefPropertyTag (TnefPropertyId.RecipientDisplayName, TnefPropertyType.Unicode); + /// /// The MAPI property PR_RECIPIENT_NUMBER_FOR_ADVICE. /// @@ -5556,7 +5620,7 @@ public TnefPropertyType ValueTnefType { } /// - /// Initializes a new instance of the struct. + /// Initialize a new instance of the struct. /// /// /// Creates a new based on a 32-bit integer tag as read from @@ -5576,7 +5640,7 @@ public TnefPropertyTag (int tag) } /// - /// Initializes a new instance of the struct. + /// Initialize a new instance of the struct. /// /// /// Creates a new based on a @@ -5617,10 +5681,10 @@ public static implicit operator int (TnefPropertyTag tag) } /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// /// - /// Serves as a hash function for a object. + /// Serves as a hash function for a object. /// /// A hash code for this instance that is suitable for use in hashing algorithms /// and data structures such as a hash table. @@ -5630,14 +5694,14 @@ public override int GetHashCode () } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// - /// The to compare with the current . + /// The to compare with the current . /// true if the specified is equal to the current - /// ; otherwise, false. + /// ; otherwise, false. public override bool Equals (object obj) { if (!(obj is TnefPropertyTag)) @@ -5649,12 +5713,12 @@ public override bool Equals (object obj) } /// - /// Returns a that represents the current . + /// Returns a that represents the current . /// /// - /// Returns a that represents the current . + /// Returns a that represents the current . /// - /// A that represents the current . + /// A that represents the current . public override string ToString () { return string.Format ("{0} ({1})", Id, ValueTnefType); diff --git a/MimeKit/Tnef/TnefPropertyType.cs b/MimeKit/Tnef/TnefPropertyType.cs index 175ea65e82..b0270a6538 100644 --- a/MimeKit/Tnef/TnefPropertyType.cs +++ b/MimeKit/Tnef/TnefPropertyType.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Tnef/TnefReader.cs b/MimeKit/Tnef/TnefReader.cs index 6644a2d2cf..60717d2b26 100644 --- a/MimeKit/Tnef/TnefReader.cs +++ b/MimeKit/Tnef/TnefReader.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,10 +27,7 @@ using System; using System.IO; using System.Text; - -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif +using System.Globalization; namespace MimeKit.Tnef { /// @@ -162,15 +159,10 @@ private set { try { var encoding = Encoding.GetEncoding (value); codepage = encoding.CodePage; - } catch (ArgumentOutOfRangeException ex) { - ComplianceStatus |= TnefComplianceStatus.InvalidMessageCodepage; - if (ComplianceMode == TnefComplianceMode.Strict) - throw new TnefException (TnefComplianceStatus.InvalidMessageCodepage, string.Format ("Invalid message codepage: {0}", value), ex); - codepage = 1252; - } catch (NotSupportedException ex) { + } catch (Exception ex) { ComplianceStatus |= TnefComplianceStatus.InvalidMessageCodepage; if (ComplianceMode == TnefComplianceMode.Strict) - throw new TnefException (TnefComplianceStatus.InvalidMessageCodepage, string.Format ("Unsupported message codepage: {0}", value), ex); + throw new TnefException (TnefComplianceStatus.InvalidMessageCodepage, string.Format (CultureInfo.InvariantCulture, "Invalid message codepage: {0}", value), ex); codepage = 1252; } } @@ -211,7 +203,7 @@ private set { if (value != 0x00010000) { ComplianceStatus |= TnefComplianceStatus.InvalidTnefVersion; if (ComplianceMode == TnefComplianceMode.Strict) - throw new TnefException (TnefComplianceStatus.InvalidTnefVersion, string.Format ("Invalid TNEF version: {0}", value)); + throw new TnefException (TnefComplianceStatus.InvalidTnefVersion, string.Format (CultureInfo.InvariantCulture, "Invalid TNEF version: {0}", value)); } version = value; @@ -219,7 +211,7 @@ private set { } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// When reading a TNEF stream using the mode, @@ -268,7 +260,7 @@ public TnefReader (Stream inputStream, int defaultMessageCodepage, TnefComplianc } /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new for the specified input stream. @@ -283,19 +275,27 @@ public TnefReader (Stream inputStream) : this (inputStream, 0, TnefComplianceMod /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// /// /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// is reclaimed by garbage collection. /// ~TnefReader () { Dispose (false); } + void CheckDisposed () + { + if (closed) + throw new ObjectDisposedException ("TnefReader"); + } + internal int ReadAhead (int atleast) { + CheckDisposed (); + int left = inputEnd - inputIndex; if (left >= atleast || eos) @@ -384,16 +384,9 @@ void DecodeHeader () AttachmentKey = ReadInt16 (); } catch (EndOfStreamException) { SetComplianceError (TnefComplianceStatus.StreamTruncated); - throw; } } - void CheckDisposed () - { - if (closed) - throw new ObjectDisposedException ("TnefReader"); - } - void CheckAttributeLevel () { switch (AttributeLevel) { @@ -455,32 +448,6 @@ void CheckAttributeTag () } } - static unsafe void Load32BitValue (byte *dest, byte[] src, int startIndex) - { - if (BitConverter.IsLittleEndian) { - dest[0] = src[startIndex]; - dest[1] = src[startIndex + 1]; - dest[2] = src[startIndex + 2]; - dest[3] = src[startIndex + 3]; - } else { - dest[0] = src[startIndex + 3]; - dest[1] = src[startIndex + 2]; - dest[2] = src[startIndex + 1]; - dest[3] = src[startIndex]; - } - } - - static unsafe void Load64BitValue (byte *dest, byte[] src, int startIndex) - { - if (BitConverter.IsLittleEndian) { - for (int i = 0; i < 8; i++) - dest[i] = src[startIndex + i]; - } else { - for (int i = 0; i < 8; i++) - dest[i] = src[startIndex + (7 - i)]; - } - } - internal byte ReadByte () { if (ReadAhead (1) < 1) @@ -521,50 +488,47 @@ internal int PeekInt32 () (input[inputIndex + 2] << 16) | (input[inputIndex + 3] << 24); } - internal unsafe long ReadInt64 () + internal long ReadInt64 () { if (ReadAhead (8) < 8) throw new EndOfStreamException (); - long value; - - Load32BitValue ((byte *) &value, input, inputIndex); UpdateChecksum (input, inputIndex, 8); - inputIndex += 8; - return value; + return (long) input[inputIndex++] | ((long) input[inputIndex++] << 8) | + ((long) input[inputIndex++] << 16) | ((long) input[inputIndex++] << 24) | + ((long) input[inputIndex++] << 32) | ((long) input[inputIndex++] << 40) | + ((long) input[inputIndex++] << 48) | ((long) input[inputIndex++] << 56); } - internal unsafe float ReadSingle () + static unsafe float Int32BitsToSingle (int value) { - if (ReadAhead (4) < 4) - throw new EndOfStreamException (); - - float value; + return *((float*) &value); + } - Load32BitValue ((byte *) &value, input, inputIndex); - UpdateChecksum (input, inputIndex, 4); - inputIndex += 4; + internal float ReadSingle () + { + var value = ReadInt32 (); - return value; + return Int32BitsToSingle (value); } - internal unsafe double ReadDouble () + static unsafe double Int64BitsToDouble (long value) { - if (ReadAhead (8) < 8) - throw new EndOfStreamException (); - - double value; + return *((double*) &value); + } - Load64BitValue ((byte *) &value, input, inputIndex); - UpdateChecksum (input, inputIndex, 8); - inputIndex += 8; + internal double ReadDouble () + { + var value = ReadInt64 (); - return value; + return Int64BitsToDouble (value); } internal bool Seek (int offset) { + CheckDisposed (); + int left = offset - StreamOffset; if (left <= 0) @@ -625,6 +589,8 @@ bool SkipAttributeRawValue () /// public bool ReadNextAttribute () { + CheckDisposed (); + if (AttributeRawValueStreamOffset != 0 && !SkipAttributeRawValue ()) return false; @@ -648,8 +614,10 @@ public bool ReadNextAttribute () CheckAttributeTag (); - if (AttributeRawValueLength < 0) + if (AttributeRawValueLength < 0) { SetComplianceError (TnefComplianceStatus.InvalidAttributeLength); + return false; + } try { TnefPropertyReader.Load (); @@ -705,6 +673,8 @@ public int ReadAttributeRawValue (byte[] buffer, int offset, int count) if (count < 0 || count > (buffer.Length - offset)) throw new ArgumentOutOfRangeException (nameof (count)); + CheckDisposed (); + int dataEndOffset = AttributeRawValueStreamOffset + AttributeRawValueLength; int dataLeft = dataEndOffset - StreamOffset; @@ -766,16 +736,17 @@ public void Close () /// false to release only the unmanaged resources. protected virtual void Dispose (bool disposing) { - InputStream.Dispose (); + if (disposing && !closed) + InputStream.Dispose (); } /// - /// Releases all resource used by the object. + /// Releases all resource used by the object. /// - /// Call when you are finished using the . The - /// method leaves the in an unusable state. After calling - /// , you must release all references to the so the garbage - /// collector can reclaim the memory that the was occupying. + /// Call when you are finished using the . The + /// method leaves the in an unusable state. After calling + /// , you must release all references to the so the garbage + /// collector can reclaim the memory that the was occupying. public void Dispose () { Dispose (true); diff --git a/MimeKit/Tnef/TnefReaderStream.cs b/MimeKit/Tnef/TnefReaderStream.cs index 22f27c7687..006f3c4f3b 100644 --- a/MimeKit/Tnef/TnefReaderStream.cs +++ b/MimeKit/Tnef/TnefReaderStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -36,21 +36,23 @@ namespace MimeKit.Tnef { /// class TnefReaderStream : Stream { - readonly int valueEndOffset; + readonly int valueEndOffset, dataEndOffset; readonly TnefReader reader; bool disposed; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a stream for reading a raw value from the . /// /// The . - /// The end offset. - public TnefReaderStream (TnefReader tnefReader, int endOffset) + /// The end offset of the data. + /// The end offset of the container value. + public TnefReaderStream (TnefReader tnefReader, int dataEndOffset, int valueEndOffset) { - valueEndOffset = endOffset; + this.valueEndOffset = valueEndOffset; + this.dataEndOffset = dataEndOffset; reader = tnefReader; } @@ -168,10 +170,21 @@ public override int Read (byte[] buffer, int offset, int count) CheckDisposed (); - int valueLeft = valueEndOffset - reader.StreamOffset; - int n = Math.Min (valueLeft, count); + int dataLeft = dataEndOffset - reader.StreamOffset; + int n = Math.Min (dataLeft, count); - return n > 0 ? reader.ReadAttributeRawValue (buffer, offset, n) : 0; + int nread = n > 0 ? reader.ReadAttributeRawValue (buffer, offset, n) : 0; + + dataLeft -= nread; + + if (dataLeft == 0 && valueEndOffset > reader.StreamOffset) { + int valueLeft = valueEndOffset - reader.StreamOffset; + var buf = new byte[valueLeft]; + + reader.ReadAttributeRawValue (buf, 0, valueLeft); + } + + return nread; } /// diff --git a/MimeKit/Utils/BufferPool.cs b/MimeKit/Utils/BufferPool.cs new file mode 100644 index 0000000000..eb831583ad --- /dev/null +++ b/MimeKit/Utils/BufferPool.cs @@ -0,0 +1,180 @@ +// +// BufferPool.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +// Code based on Microsoft's System.Buffer.DefaultArrayPoolBucket class located at +// https://github.com/dotnet/corefx/blob/master/src/System.Buffers/src/System/Buffers/DefaultArrayPoolBucket.cs + +using System; +using System.Threading; +using System.Diagnostics; + +namespace MimeKit.Utils +{ + /// + /// Provides a pool of reusable buffers. + /// + /// + /// + /// Renting and returning buffers with a can increase performance + /// in situations where buffers are created and destroyed frequently, resulting in significant + /// memory pressure on the garbage collector. + /// + /// + /// This class is thread-safe. All members may be used by multiple threads concurrently. + /// + /// + class BufferPool + { + readonly byte[][] buffers; + SpinLock spinLock; + int index; + + /// + /// Initialize a new instance of the class. + /// + /// + /// Creates a new buffer pool. + /// + /// The buffer size. + /// The maximum number of buffers that should be retained by the pool. + /// + /// is less than 1. + /// -or- + /// is less than 1. + /// + public BufferPool (int bufferSize, int maxBufferCount) + { + if (bufferSize < 1) + throw new ArgumentOutOfRangeException (nameof (bufferSize)); + + if (maxBufferCount < 1) + throw new ArgumentOutOfRangeException (nameof (maxBufferCount)); + + buffers = new byte[maxBufferCount][]; + MaxBufferCount = maxBufferCount; + BufferSize = bufferSize; + + spinLock = new SpinLock (Debugger.IsAttached); + } + + /// + /// Get the size of the buffers returned and/or retained by the pool. + /// + /// + /// Gets the size of the buffers returned and/or retained by the pool. + /// + /// The size of the buffer. + public int BufferSize { + get; private set; + } + + /// + /// Get the maximum number of buffers that the pool should retain. + /// + /// + /// Gets the maximum number of buffers that the pool should retain. + /// + /// The max buffer count. + public int MaxBufferCount { + get; private set; + } + + /// + /// Rent a buffer from the pool. + /// + /// + /// Returns a buffer from the pool. This buffer should later be returned back to the pool using + /// when the caller is finished using it so that it may be reused + /// in subsequent uses of . + /// + /// The rented buffer. + /// true if the buffer should be cleared; otherwise, false. + public byte[] Rent (bool clear = false) + { + byte[] buffer = null; + bool locked = false; + + try { + spinLock.Enter (ref locked); + + if (index < buffers.Length) { + buffer = buffers[index]; + buffers[index] = null; + index++; + } + } finally { + if (locked) + spinLock.Exit (false); + } + + if (buffer == null) + buffer = new byte[BufferSize]; + else if (clear) + Array.Clear (buffer, 0, BufferSize); + + return buffer; + } + + /// + /// Return the specified buffer to the pool. + /// + /// + /// Once a buffer has been returned to the pool, the caller gives up all ownership of the buffer + /// and must not use it. The reference returned from a given call to must + /// only be returned via once. The default + /// may hold onto the returned buffer in order to rent it again, or it may release the returned buffer + /// if it is determined that the pool already contains the maximum number of buffers as specified by + /// . + /// + /// The buffer. + /// + /// is null. + /// + /// + /// The size of the does not match . + /// + public void Return (byte[] buffer) + { + bool locked = false; + + if (buffer == null) + throw new ArgumentNullException (nameof (buffer)); + + if (buffer.Length != BufferSize) + throw new ArgumentException ("The size of the buffer does not match the size used by the pool.", nameof (buffer)); + + try { + spinLock.Enter (ref locked); + + if (index > 0) + buffers[--index] = buffer; + } finally { + if (locked) + spinLock.Exit (false); + } + } + } +} diff --git a/MimeKit/Utils/ByteExtensions.cs b/MimeKit/Utils/ByteExtensions.cs index ffceaad8f0..8edd7a1bb1 100644 --- a/MimeKit/Utils/ByteExtensions.cs +++ b/MimeKit/Utils/ByteExtensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -44,6 +44,7 @@ enum CharType : ushort { IsTokenSpecial = (1 << 11), IsWhitespace = (1 << 12), IsXDigit = (1 << 13), + IsPhraseAtom = (1 << 14), IsAsciiAtom = IsAscii | IsAtom, } @@ -56,8 +57,8 @@ static class ByteExtensions const string DomainSpecials = "[]\\\r \t"; // not allowed in domains const string EncodedWordSpecials = "()<>@,;:\"/[]?.=_"; // rfc2047 5.1 const string EncodedPhraseSpecials = "!*+-/=_"; // rfc2047 5.3 - const string Specials = "()<>@,;:\\\".[]"; - internal const string TokenSpecials = "()<>@,;:\\\"/[]?="; + const string Specials = "()<>[]:;@\\,.\""; // rfc5322 3.2.3 + internal const string TokenSpecials = "()<>@,;:\\\"/[]?="; // rfc2045 5.1 const string Whitespace = " \t\r\n"; static readonly CharType[] table = new CharType[256]; @@ -110,7 +111,7 @@ static ByteExtensions () if ((i >= 33 && i <= 60) || (i >= 62 && i <= 126) || i == 32) table[i] |= (CharType.IsQuotedPrintableSafe | CharType.IsEncodedWordSafe); if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')) - table[i] |= CharType.IsEncodedPhraseSafe | CharType.IsAtom; + table[i] |= CharType.IsEncodedPhraseSafe | CharType.IsAtom | CharType.IsPhraseAtom; if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) table[i] |= CharType.IsXDigit; @@ -119,7 +120,7 @@ static ByteExtensions () if (i == 127) table[i] |= CharType.IsAscii; else - table[i] |= CharType.IsAtom; + table[i] |= CharType.IsAtom | CharType.IsPhraseAtom; table[i] |= CharType.IsControl; } @@ -129,14 +130,18 @@ static ByteExtensions () table[' '] |= CharType.IsSpace | CharType.IsBlank; SetFlags (Whitespace, CharType.IsWhitespace, CharType.None, false); - SetFlags (AtomSafeCharacters, CharType.IsAtom, CharType.None, false); + SetFlags (AtomSafeCharacters, CharType.IsAtom | CharType.IsPhraseAtom, CharType.None, false); SetFlags (TokenSpecials, CharType.IsTokenSpecial, CharType.IsControl, false); SetFlags (Specials, CharType.IsSpecial, CharType.None, false); SetFlags (DomainSpecials, CharType.IsDomainSafe, CharType.None, true); - RemoveFlags (Specials, CharType.IsAtom); + RemoveFlags (Specials, CharType.IsAtom | CharType.IsPhraseAtom); RemoveFlags (EncodedWordSpecials, CharType.IsEncodedWordSafe); RemoveFlags (AttributeSpecials + TokenSpecials, CharType.IsAttrChar); SetFlags (EncodedPhraseSpecials, CharType.IsEncodedPhraseSafe, CharType.None, false); + + // Note: Allow '[' and ']' in the display-name of a mailbox address + table['['] |= CharType.IsPhraseAtom; + table[']'] |= CharType.IsPhraseAtom; } //public static bool IsAscii (this byte c) @@ -149,6 +154,11 @@ public static bool IsAsciiAtom (this byte c) return (table[c] & CharType.IsAsciiAtom) == CharType.IsAsciiAtom; } + public static bool IsPhraseAtom (this byte c) + { + return (table[c] & CharType.IsPhraseAtom) != 0; + } + public static bool IsAtom (this byte c) { return (table[c] & CharType.IsAtom) != 0; diff --git a/MimeKit/Utils/CharsetUtils.cs b/MimeKit/Utils/CharsetUtils.cs index bb08ad15a0..408179b164 100644 --- a/MimeKit/Utils/CharsetUtils.cs +++ b/MimeKit/Utils/CharsetUtils.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,23 +25,10 @@ // using System; +using System.IO; using System.Text; using System.Collections.Generic; -#if PORTABLE -using EncoderReplacementFallback = Portable.Text.EncoderReplacementFallback; -using DecoderReplacementFallback = Portable.Text.DecoderReplacementFallback; -using EncoderExceptionFallback = Portable.Text.EncoderExceptionFallback; -using DecoderExceptionFallback = Portable.Text.DecoderExceptionFallback; -using EncoderFallbackException = Portable.Text.EncoderFallbackException; -using DecoderFallbackException = Portable.Text.DecoderFallbackException; -using DecoderFallbackBuffer = Portable.Text.DecoderFallbackBuffer; -using DecoderFallback = Portable.Text.DecoderFallback; -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif - namespace MimeKit.Utils { public static class External { @@ -599,5 +586,28 @@ public static string ConvertToUnicode (Encoding encoding, byte[] buffer, int sta return new string (ConvertToUnicode (encoding, buffer, startIndex, length, out count), 0, count); } + + public static bool TryGetBomEncoding (byte[] buffer, int length, out Encoding encoding) + { + if (length >= 2 && buffer[0] == 0xFF && buffer[1] == 0xFE) + encoding = Encoding.Unicode; // UTF-16LE + else if (length >= 2 && buffer[0] == 0xFE && buffer[1] == 0xFF) + encoding = Encoding.BigEndianUnicode; // UTF-16BE + else if (length >= 3 && buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF) + encoding = UTF8; // UTF-8 + else + encoding = null; + + return encoding != null; + } + + public static bool TryGetBomEncoding (Stream stream, out Encoding encoding) + { + var bom = new byte[3]; + + int n = stream.Read (bom, 0, bom.Length); + + return TryGetBomEncoding (bom, n, out encoding); + } } } diff --git a/MimeKit/Utils/Crc32.cs b/MimeKit/Utils/Crc32.cs index 55aeed495e..63730f642f 100644 --- a/MimeKit/Utils/Crc32.cs +++ b/MimeKit/Utils/Crc32.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -75,7 +75,7 @@ class Crc32 int crc; /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new CRC32 context. diff --git a/MimeKit/Utils/DateUtils.cs b/MimeKit/Utils/DateUtils.cs index a1f8d34aff..931fb0885f 100644 --- a/MimeKit/Utils/DateUtils.cs +++ b/MimeKit/Utils/DateUtils.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,12 +26,9 @@ using System; using System.Text; +using System.Globalization; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - namespace MimeKit.Utils { [Flags] enum DateTokenFlags : byte @@ -119,7 +116,7 @@ public static class DateUtils static DateUtils () { - timezones = new Dictionary { + timezones = new Dictionary (StringComparer.Ordinal) { { "UT", 0 }, { "UTC", 0 }, { "GMT", 0 }, { "EDT", -400 }, { "EST", -500 }, { "CDT", -500 }, { "CST", -600 }, @@ -177,10 +174,7 @@ static bool TryGetWeekday (DateToken token, byte[] text, out DayOfWeek weekday) if (!token.IsWeekday || token.Length < 3) return false; - var name = Encoding.ASCII.GetString (text, token.StartIndex, token.Length); - - if (name.Length > 3) - name = name.Substring (0, 3); + var name = Encoding.ASCII.GetString (text, token.StartIndex, 3); for (int day = 0; day < WeekDays.Length; day++) { if (WeekDays[day].Equals (name, StringComparison.OrdinalIgnoreCase)) { @@ -218,10 +212,7 @@ static bool TryGetMonth (DateToken token, byte[] text, out int month) if (!token.IsMonth || token.Length < 3) return false; - var name = Encoding.ASCII.GetString (text, token.StartIndex, token.Length); - - if (name.Length > 3) - name = name.Substring (0, 3); + var name = Encoding.ASCII.GetString (text, token.StartIndex, 3); for (int i = 0; i < Months.Length; i++) { if (Months[i].Equals (name, StringComparison.OrdinalIgnoreCase)) { @@ -530,7 +521,7 @@ static bool TryParseUnknownDateFormat (IList tokens, byte[] text, out } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses an rfc822 date and time from the supplied buffer starting at the given index @@ -573,7 +564,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Date } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses an rfc822 date and time from the supplied buffer starting at the specified index. @@ -611,7 +602,7 @@ public static bool TryParse (byte[] buffer, int startIndex, out DateTimeOffset d } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses an rfc822 date and time from the specified buffer. @@ -641,7 +632,7 @@ public static bool TryParse (byte[] buffer, out DateTimeOffset date) } /// - /// Tries to parse the given input buffer into a new instance. + /// Try to parse the given input buffer into a new instance. /// /// /// Parses an rfc822 date and time from the specified text. @@ -725,7 +716,7 @@ internal static DateTime Parse (string text, string format) /// The date. public static string FormatDate (DateTimeOffset date) { - return string.Format ("{0}, {1:00} {2} {3:0000} {4:00}:{5:00}:{6:00} {7:+00;-00}{8:00}", + return string.Format (CultureInfo.InvariantCulture, "{0}, {1:00} {2} {3:0000} {4:00}:{5:00}:{6:00} {7:+00;-00}{8:00}", WeekDays[(int) date.DayOfWeek], date.Day, Months[date.Month - 1], date.Year, date.Hour, date.Minute, date.Second, date.Offset.Hours, date.Offset.Minutes); } diff --git a/MimeKit/Utils/MimeUtils.cs b/MimeKit/Utils/MimeUtils.cs index 8610955f56..f67fe14d47 100644 --- a/MimeKit/Utils/MimeUtils.cs +++ b/MimeKit/Utils/MimeUtils.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,11 +27,8 @@ using System; using System.Text; using System.Collections.Generic; - -#if !PORTABLE using System.Net.NetworkInformation; using System.Security.Cryptography; -#endif namespace MimeKit.Utils { /// @@ -42,10 +39,10 @@ namespace MimeKit.Utils { /// public static class MimeUtils { -#if PORTABLE - static readonly Random random = new Random ((int) DateTime.Now.Ticks); -#endif const string base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#if !NETSTANDARD1_3 && !NETSTANDARD1_6 + static string DefaultHostName = null; +#endif /// /// A string comparer that performs a case-insensitive ordinal string comparison. @@ -57,14 +54,8 @@ public static class MimeUtils internal static void GetRandomBytes (byte[] buffer) { -#if !PORTABLE using (var random = RandomNumberGenerator.Create ()) random.GetBytes (buffer); -#else - lock (random) { - random.NextBytes (buffer); - } -#endif } /// @@ -111,7 +102,7 @@ public static string GenerateMessageId (string domain) value /= 36; } while (value != 0); - id.Append ('@').Append (domain); + id.Append ('@').Append (ParseUtils.IdnEncode (domain)); return id.ToString (); } @@ -125,12 +116,16 @@ public static string GenerateMessageId (string domain) /// The message identifier. public static string GenerateMessageId () { -#if PORTABLE || NETSTANDARD +#if NETSTANDARD1_3 || NETSTANDARD1_6 return GenerateMessageId ("localhost.localdomain"); #else - var properties = IPGlobalProperties.GetIPGlobalProperties (); + if (DefaultHostName == null) { + var properties = IPGlobalProperties.GetIPGlobalProperties (); - return GenerateMessageId (properties.HostName); + DefaultHostName = properties.HostName; + } + + return GenerateMessageId (DefaultHostName); #endif } @@ -158,10 +153,8 @@ public static IEnumerable EnumerateReferences (byte[] buffer, int startI { ParseUtils.ValidateArguments (buffer, startIndex, length); - byte[] sentinels = { (byte) '>' }; int endIndex = startIndex + length; int index = startIndex; - string msgid; do { if (!ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, false)) @@ -171,74 +164,8 @@ public static IEnumerable EnumerateReferences (byte[] buffer, int startI break; if (buffer[index] == '<') { - // skip over the '<' - index++; - - if (index >= endIndex) - break; - - string localpart; - if (!InternetAddress.TryParseLocalPart (buffer, ref index, endIndex, false, out localpart)) - continue; - - if (index >= endIndex) - break; - - if (buffer[index] == (byte) '>') { - // The msgid token did not contain an @domain. Technically this is illegal, but for the - // sake of maximum compatibility, I guess we have no choice but to accept it... - index++; - - yield return localpart; - continue; - } - - if (buffer[index] != (byte) '@') { - // who the hell knows what we have here... ignore it and continue on? - continue; - } - - // skip over the '@' - index++; - - if (!ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, false)) - break; - - if (index >= endIndex) - break; - - if (buffer[index] == (byte) '>') { - // The msgid token was in the form "". Technically this is illegal, but for - // the sake of maximum compatibility, I guess we have no choice but to accept it... - // https://github.com/jstedfast/MimeKit/issues/102 - index++; - - yield return localpart + "@"; - continue; - } - - string domain; - if (!ParseUtils.TryParseDomain (buffer, ref index, endIndex, sentinels, false, out domain)) - continue; - - msgid = localpart + "@" + domain; - - // Note: some Message-Id's are broken and in the form "" - // https://github.com/jstedfast/MailKit/issues/138 - while (index < endIndex && buffer[index] == (byte) '@') { - int saved = index; - - index++; - - if (!ParseUtils.TryParseDomain (buffer, ref index, endIndex, sentinels, false, out domain)) { - index = saved; - break; - } - - msgid += "@" + domain; - } - - yield return msgid; + if (ParseUtils.TryParseMsgId (buffer, ref index, endIndex, true, false, out string msgid)) + yield return msgid; } else if (!ParseUtils.SkipWord (buffer, ref index, endIndex, false)) { index++; } @@ -291,75 +218,11 @@ public static string ParseMessageId (byte[] buffer, int startIndex, int length) { ParseUtils.ValidateArguments (buffer, startIndex, length); - byte[] sentinels = { (byte) '>' }; int endIndex = startIndex + length; int index = startIndex; string msgid; - if (!ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, false)) - return null; - - if (index >= endIndex) - return null; - - if (buffer[index] == '<') { - // skip over the '<' - index++; - - if (index >= endIndex) - return null; - } - - string localpart; - if (!InternetAddress.TryParseLocalPart (buffer, ref index, endIndex, false, out localpart)) - return null; - - if (index >= endIndex) - return null; - - if (buffer[index] == (byte) '>') { - // The msgid token did not contain an @domain. Technically this is illegal, but for the - // sake of maximum compatibility, I guess we have no choice but to accept it... - return localpart; - } - - if (buffer[index] != (byte) '@') { - // who the hell knows what we have here... - return null; - } - - // skip over the '@' - index++; - - if (!ParseUtils.SkipCommentsAndWhiteSpace (buffer, ref index, endIndex, false)) - return null; - - if (index >= endIndex) - return null; - - if (buffer[index] == (byte) '>') { - // The msgid token was in the form "". Technically this is illegal, but for - // the sake of maximum compatibility, I guess we have no choice but to accept it... - // https://github.com/jstedfast/MimeKit/issues/102 - return localpart + "@"; - } - - string domain; - if (!ParseUtils.TryParseDomain (buffer, ref index, endIndex, sentinels, false, out domain)) - return null; - - msgid = localpart + "@" + domain; - - // Note: some Message-Id's are broken and in the form "" - // https://github.com/jstedfast/MailKit/issues/138 - while (index < endIndex && buffer[index] == (byte) '@') { - index++; - - if (!ParseUtils.TryParseDomain (buffer, ref index, endIndex, sentinels, false, out domain)) - break; - - msgid += "@" + domain; - } + ParseUtils.TryParseMsgId (buffer, ref index, endIndex, false, false, out msgid); return msgid; } @@ -386,7 +249,7 @@ public static string ParseMessageId (string text) } /// - /// Tries to parse a version from a header such as Mime-Version. + /// Try to parse a version from a header such as Mime-Version. /// /// /// Parses a MIME version string from the supplied buffer starting at the given index @@ -445,7 +308,7 @@ public static bool TryParse (byte[] buffer, int startIndex, int length, out Vers } /// - /// Tries to parse a version from a header such as Mime-Version. + /// Try to parse a version from a header such as Mime-Version. /// /// /// Parses a MIME version string from the specified text. @@ -467,7 +330,7 @@ public static bool TryParse (string text, out Version version) } /// - /// Tries to parse the value of a Content-Transfer-Encoding header. + /// Try to parse the value of a Content-Transfer-Encoding header. /// /// /// Parses a Content-Transfer-Encoding header value. @@ -507,6 +370,7 @@ public static bool TryParse (string text, out ContentEncoding encoding) case "quoted-printable": encoding = ContentEncoding.QuotedPrintable; break; case "x-uuencode": encoding = ContentEncoding.UUEncode; break; case "uuencode": encoding = ContentEncoding.UUEncode; break; + case "x-uue": encoding = ContentEncoding.UUEncode; break; default: encoding = ContentEncoding.Default; break; } @@ -564,7 +428,7 @@ public static string Unquote (string text) if (index == -1) return text; - var builder = new StringBuilder (); + var builder = new StringBuilder (text.Length); bool escaped = false; bool quoted = false; diff --git a/MimeKit/Utils/OptimizedOrdinalComparer.cs b/MimeKit/Utils/OptimizedOrdinalComparer.cs index dd0a69fc94..b5ba6d3047 100644 --- a/MimeKit/Utils/OptimizedOrdinalComparer.cs +++ b/MimeKit/Utils/OptimizedOrdinalComparer.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace MimeKit.Utils { /// @@ -34,10 +35,10 @@ namespace MimeKit.Utils { /// /// An optimized version of StringComparer.OrdinalIgnoreCase. /// - class OptimizedOrdinalIgnoreCaseComparer : IEqualityComparer + sealed class OptimizedOrdinalIgnoreCaseComparer : IEqualityComparer { /// - /// Initializes a new instance of the class. + /// Initialize a new instance of the class. /// /// /// Creates a new . @@ -46,9 +47,11 @@ public OptimizedOrdinalIgnoreCaseComparer () { } + [MethodImpl (MethodImplOptions.AggressiveInlining)] static int ToUpper (int c) { - if (c >= 0x61 && c <= 0x7A) + // check if the char is within the lowercase range + if ((uint) (c - 'a') <= 'z' - 'a') return c - 0x20; return c; @@ -85,7 +88,8 @@ public bool Equals (string x, string y) if (x.Length != y.Length) return false; - for (int i = 0; i < x.Length; i++) { + int length = x.Length; + for (int i = 0; i < length; i++) { if (ToUpper (x[i]) != ToUpper (y[i])) return false; } diff --git a/MimeKit/Utils/PackedByteArray.cs b/MimeKit/Utils/PackedByteArray.cs index 8f7be02e7d..5ea52ac4b8 100644 --- a/MimeKit/Utils/PackedByteArray.cs +++ b/MimeKit/Utils/PackedByteArray.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/Utils/ParseUtils.cs b/MimeKit/Utils/ParseUtils.cs index 25020e74ef..3ee7a5ab08 100644 --- a/MimeKit/Utils/ParseUtils.cs +++ b/MimeKit/Utils/ParseUtils.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,28 +26,12 @@ using System; using System.Text; -#if !PORTABLE using System.Globalization; -#else -using EncoderReplacementFallback = Portable.Text.EncoderReplacementFallback; -using DecoderReplacementFallback = Portable.Text.DecoderReplacementFallback; -using EncoderExceptionFallback = Portable.Text.EncoderExceptionFallback; -using DecoderExceptionFallback = Portable.Text.DecoderExceptionFallback; -using EncoderFallbackException = Portable.Text.EncoderFallbackException; -using DecoderFallbackException = Portable.Text.DecoderFallbackException; -using DecoderFallbackBuffer = Portable.Text.DecoderFallbackBuffer; -using DecoderFallback = Portable.Text.DecoderFallback; -using Encoding = Portable.Text.Encoding; -using Encoder = Portable.Text.Encoder; -using Decoder = Portable.Text.Decoder; -#endif namespace MimeKit.Utils { static class ParseUtils { -#if !PORTABLE static readonly IdnMapping idn = new IdnMapping (); -#endif public static void ValidateArguments (ParserOptions options, byte[] buffer, int startIndex, int length) { @@ -177,7 +161,7 @@ public static bool SkipCommentsAndWhiteSpace (byte[] text, ref int index, int en if (!SkipComment (text, ref index, endIndex)) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete comment token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete comment token at offset {0}", startIndex), startIndex, index); return false; } @@ -211,7 +195,7 @@ public static bool SkipQuoted (byte[] text, ref int index, int endIndex, bool th if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete quoted-string token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete quoted-string token at offset {0}", startIndex), startIndex, index); return false; } @@ -244,6 +228,17 @@ public static bool SkipAtom (byte[] text, ref int index, int endIndex) return index > start; } + // Note: a "phrase atom" is a more lenient atom (e.g. mailbox display-name phrase atom) + public static bool SkipPhraseAtom (byte[] text, ref int index, int endIndex) + { + int start = index; + + while (index < endIndex && text[index].IsPhraseAtom ()) + index++; + + return index > start; + } + public static bool SkipToken (byte[] text, ref int index, int endIndex) { int start = index; @@ -300,7 +295,7 @@ static bool TryParseDotAtom (byte[] text, ref int index, int endIndex, byte[] se do { if (!text[index].IsAtom ()) { if (throwOnError) - throw new ParseException (string.Format ("Invalid {0} token at offset {1}", tokenType, startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid {0} token at offset {1}", tokenType, startIndex), startIndex, index); return false; } @@ -364,7 +359,7 @@ static bool TryParseDomainLiteral (byte[] text, ref int index, int endIndex, boo if (index >= endIndex) { if (throwOnError) - throw new ParseException (string.Format ("Incomplete domain literal token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete domain literal token at offset {0}", startIndex), startIndex, index); return false; } @@ -374,7 +369,7 @@ static bool TryParseDomainLiteral (byte[] text, ref int index, int endIndex, boo if (!text[index].IsDomain ()) { if (throwOnError) - throw new ParseException (string.Format ("Invalid domain literal token at offset {0}", startIndex), startIndex, index); + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid domain literal token at offset {0}", startIndex), startIndex, index); return false; } @@ -396,6 +391,160 @@ public static bool TryParseDomain (byte[] text, ref int index, int endIndex, byt return TryParseDotAtom (text, ref index, endIndex, sentinels, throwOnError, "domain", out domain); } + static readonly byte[] GreaterThanOrAt = { (byte) '>', (byte) '@' }; + + public static bool TryParseMsgId (byte[] text, ref int index, int endIndex, bool requireAngleAddr, bool throwOnError, out string msgid) + { + //const CharType SpaceOrControl = CharType.IsWhitespace | CharType.IsControl; + var angleAddr = false; + + msgid = null; + + if (!SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex || (requireAngleAddr && text[index] != '<')) { + if (throwOnError) + throw new ParseException ("No msg-id token found.", index, index); + + return false; + } + + int tokenIndex = index; + + if (text[index] == '<') { + angleAddr = true; + index++; + } + + SkipWhiteSpace (text, ref index, endIndex); + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete msg-id token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + var token = new StringBuilder (); + + // consume the local-part of the msg-id using a very loose definition of 'local-part' + // + // See https://github.com/jstedfast/MimeKit/issues/472 for the reasons why. + do { + int start = index; + + if (text[index] == '"') { + if (!SkipQuoted (text, ref index, endIndex, throwOnError)) + return false; + } else { + while (index < endIndex && text[index] != (byte) '.' && text[index] != (byte) '@' && text[index] != '>' && !text[index].IsWhitespace ()) + index++; + } + + try { + token.Append (CharsetUtils.UTF8.GetString (text, start, index - start)); + } catch (DecoderFallbackException ex) { + if (throwOnError) + throw new ParseException ("Internationalized local-part tokens may only contain UTF-8 characters.", start, start, ex); + + return false; + } + + if (!SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (angleAddr) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete msg-id token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + // since the msg-id token did not start with a '<', we do not need a '>' + break; + } + + if (text[index] == (byte) '@' || text[index] == (byte) '>') + break; + + if (text[index] != (byte) '.') { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Invalid msg-id token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + token.Append ('.'); + index++; + + if (!SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index >= endIndex) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete msg-id at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + } while (true); + + if (index < endIndex && text[index] == (byte) '@') { + token.Append ('@'); + index++; + + if (!SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + + if (index < endIndex && text[index] != (byte) '>') { + // Note: some Message-Id's are broken and in the form "" + // https://github.com/jstedfast/MailKit/issues/138 + do { + if (!TryParseDomain (text, ref index, endIndex, GreaterThanOrAt, throwOnError, out string domain)) + return false; + + if (IsIdnEncoded (domain)) + domain = IdnDecode (domain); + + token.Append (domain); + + if (index >= endIndex || text[index] != (byte) '@') + break; + + token.Append ('@'); + index++; + } while (true); + + if (!SkipCommentsAndWhiteSpace (text, ref index, endIndex, throwOnError)) + return false; + } else { + // The msgid token was in the form "". Technically this is illegal, but for + // the sake of maximum compatibility, I guess we have no choice but to accept it... + // https://github.com/jstedfast/MimeKit/issues/102 + + //if (throwOnError) + // throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete msg-id token at offset {0}", tokenIndex), tokenIndex, index); + + //return false; + } + } + + if (angleAddr && (index >= endIndex || text[index] != '>')) { + if (throwOnError) + throw new ParseException (string.Format (CultureInfo.InvariantCulture, "Incomplete msg-id token at offset {0}", tokenIndex), tokenIndex, index); + + return false; + } + + if (index < endIndex && text[index] == (byte) '>') + index++; + + msgid = token.ToString (); + + return true; + } + public static bool IsInternational (string value) { for (int i = 0; i < value.Length; i++) { @@ -414,7 +563,6 @@ public static bool IsIdnEncoded (string value) return value.IndexOf (".xn--", StringComparison.Ordinal) != -1; } -#if !PORTABLE public static string IdnEncode (string unicode) { try { @@ -432,16 +580,5 @@ public static string IdnDecode (string ascii) return ascii; } } -#else - public static string IdnEncode (string unicode) - { - return unicode; - } - - public static string IdnDecode (string ascii) - { - return ascii; - } -#endif } } diff --git a/MimeKit/Utils/Rfc2047.cs b/MimeKit/Utils/Rfc2047.cs index 80638c827c..948ec353ee 100644 --- a/MimeKit/Utils/Rfc2047.cs +++ b/MimeKit/Utils/Rfc2047.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,6 @@ using System.Text; using System.Collections.Generic; -#if PORTABLE -using Encoding = Portable.Text.Encoding; -#endif - using MimeKit.Encodings; namespace MimeKit.Utils { @@ -813,8 +809,9 @@ public static string DecodeText (byte[] text) static byte[] FoldTokens (FormatOptions options, IList tokens, string field, byte[] input) { - var output = new StringBuilder (input.Length + 2); + var output = new StringBuilder (input.Length + ((input.Length / options.MaxLineLength) * 2) + 2); int lineLength = field.Length + 2; + var firstToken = true; int lwsp = 0, tab = 0; Token token; @@ -845,6 +842,8 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie output.Append (' '); lineLength = 1; } + + firstToken = false; } else if (token.Encoding != ContentEncoding.Default) { string charset = token.CharsetCulture; @@ -857,7 +856,7 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie // break just before the last lwsp character output.Insert (lwsp, options.NewLine); lineLength = 1; - } else if (lineLength > 1) { + } else if (lineLength > 1 && !firstToken) { // force a line break... output.Append (options.NewLine); output.Append (' '); @@ -875,6 +874,7 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie output.Append ("?="); lineLength += token.Length + charset.Length + 7; + firstToken = false; lwsp = 0; tab = 0; } else if (lineLength + token.Length > options.MaxLineLength) { @@ -886,7 +886,7 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie // break just before the last lwsp character output.Insert (lwsp, options.NewLine); lineLength = 1; - } else if (lineLength > 1) { + } else if (lineLength > 1 && !firstToken) { // force a line break... output.Append (options.NewLine); output.Append (' '); @@ -913,6 +913,7 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie lineLength += token.Length; } + firstToken = false; lwsp = 0; tab = 0; } else { @@ -920,6 +921,7 @@ static byte[] FoldTokens (FormatOptions options, IList tokens, string fie output.Append ((char) input[n]); lineLength += token.Length; + firstToken = false; lwsp = 0; tab = 0; } @@ -1039,11 +1041,17 @@ enum WordType { EncodedWord } + enum WordEncoding { + Ascii, + Latin1, + UserSpecified + } + class Word { public WordType Type; public int StartIndex; public int CharCount; - public int Encoding; // 0 => ASCII, 1 => iso-8859-1, 2 => custom + public WordEncoding Encoding; public int ByteCount; public int EncodeCount; public int QuotedPairs; @@ -1105,10 +1113,10 @@ static bool ExceedsMaxLineLength (FormatOptions options, Encoding charset, Word switch (word.Type) { case WordType.EncodedWord: switch (word.Encoding) { - case 1: + case WordEncoding.Latin1: length = EstimateEncodedWordLength ("iso-8859-1", word.ByteCount, word.EncodeCount); break; - case 0: + case WordEncoding.Ascii: length = EstimateEncodedWordLength ("us-ascii", word.ByteCount, word.EncodeCount); break; default: @@ -1153,7 +1161,7 @@ static IList GetRfc822Words (FormatOptions options, Encoding charset, stri if (c < 127) { if (IsCtrl (c)) { - word.Encoding = Math.Max (word.Encoding, 1); + word.Encoding = (WordEncoding) Math.Max ((int) word.Encoding, (int) WordEncoding.Latin1); word.Type = WordType.EncodedWord; word.EncodeCount++; } else if (phrase && !IsAtom (c)) { @@ -1170,7 +1178,7 @@ static IList GetRfc822Words (FormatOptions options, Encoding charset, stri nchars = 1; } else if (c < 256) { // iso-8859-1 - word.Encoding = Math.Max (word.Encoding, 1); + word.Encoding = (WordEncoding) Math.Max ((int) word.Encoding, (int) WordEncoding.Latin1); word.Type = WordType.EncodedWord; word.EncodeCount++; word.ByteCount++; @@ -1192,11 +1200,11 @@ static IList GetRfc822Words (FormatOptions options, Encoding charset, stri n = 3; } + word.Encoding = WordEncoding.UserSpecified; word.Type = WordType.EncodedWord; word.CharCount += nchars; word.EncodeCount += n; word.ByteCount += n; - word.Encoding = 2; } if (ExceedsMaxLineLength (options, charset, word)) { @@ -1282,11 +1290,11 @@ static bool ShouldMergeWords (FormatOptions options, Encoding charset, IList Merge (FormatOptions options, Encoding charset, IList w if (words.Count < 2) return words; - int lwspCount, encoding, encoded, quoted, byteCount, length; + int lwspCount, encoded, quoted, byteCount, length; var merged = new List (); + WordEncoding encoding; Word word, next; word = words[0]; @@ -1317,18 +1326,18 @@ static IList Merge (FormatOptions options, Encoding charset, IList w next = words[i]; if (word.Type != WordType.Atom && word.Type == next.Type) { + encoding = (WordEncoding) Math.Max ((int) word.Encoding, (int) next.Encoding); lwspCount = next.StartIndex - (word.StartIndex + word.CharCount); byteCount = word.ByteCount + lwspCount + next.ByteCount; - encoding = Math.Max (word.Encoding, next.Encoding); encoded = word.EncodeCount + next.EncodeCount; quoted = word.QuotedPairs + next.QuotedPairs; if (word.Type == WordType.EncodedWord) { switch (encoding) { - case 1: + case WordEncoding.Latin1: length = EstimateEncodedWordLength ("iso-8859-1", byteCount, encoded); break; - case 0: + case WordEncoding.Ascii: length = EstimateEncodedWordLength ("us-ascii", byteCount, encoded); break; default: @@ -1370,7 +1379,7 @@ static IList Merge (FormatOptions options, Encoding charset, IList w word.Type = (WordType) Math.Max ((int) word.Type, (int) next.Type); word.CharCount = (next.StartIndex + next.CharCount) - word.StartIndex; word.ByteCount = word.ByteCount + lwspCount + next.ByteCount; - word.Encoding = Math.Max (word.Encoding, next.Encoding); + word.Encoding = (WordEncoding) Math.Max ((int) word.Encoding, (int) next.Encoding); word.EncodeCount = word.EncodeCount + next.EncodeCount; word.QuotedPairs = word.QuotedPairs + next.QuotedPairs; } else { @@ -1392,23 +1401,9 @@ static byte[] Encode (FormatOptions options, Encoding charset, string text, bool byte[] encoded; if (!options.AllowMixedHeaderCharsets) { - int maxEncoding = 0; - for (int i = 0; i < words.Count; i++) { - if (words[i].Type != WordType.EncodedWord || words[i].Encoding == maxEncoding) - continue; - - if (words[i].Encoding > maxEncoding) { - maxEncoding = words[i].Encoding; - for (int j = 0; j < i; j++) { - if (words[j].Type != WordType.EncodedWord) - continue; - - words[j].Encoding = maxEncoding; - } - } else { - words[i].Encoding = maxEncoding; - } + if (words[i].Type == WordType.EncodedWord) + words[i].Encoding = WordEncoding.UserSpecified; } } @@ -1441,10 +1436,10 @@ static byte[] Encode (FormatOptions options, Encoding charset, string text, bool } switch (word.Encoding) { - case 0: // us-ascii + case WordEncoding.Ascii: AppendEncodedWord (str, Encoding.ASCII, text, start, length, mode); break; - case 1: // iso-8859-1 + case WordEncoding.Latin1: AppendEncodedWord (str, CharsetUtils.Latin1, text, start, length, mode); break; default: // custom charset diff --git a/MimeKit/Utils/StringBuilderExtensions.cs b/MimeKit/Utils/StringBuilderExtensions.cs index 31c6fcf288..c9f90fd462 100644 --- a/MimeKit/Utils/StringBuilderExtensions.cs +++ b/MimeKit/Utils/StringBuilderExtensions.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ // using System.Text; +using System.Collections.Generic; namespace MimeKit.Utils { static class StringBuilderExtensions @@ -44,7 +45,33 @@ public static StringBuilder LineWrap (this StringBuilder text, FormatOptions opt return text; } - public static StringBuilder AppendFolded (this StringBuilder text, FormatOptions options, string value, ref int lineLength) + public static void AppendTokens (this StringBuilder text, FormatOptions options, ref int lineLength, List tokens) + { + var spaces = string.Empty; + + foreach (var token in tokens) { + if (string.IsNullOrWhiteSpace (token)) { + spaces = token; + continue; + } + + if (lineLength + spaces.Length + token.Length > options.MaxLineLength) { + text.Append (options.NewLine); + spaces = string.Empty; + text.Append ('\t'); + lineLength = 1; + } else { + lineLength += spaces.Length; + text.Append (spaces); + spaces = string.Empty; + } + + lineLength += token.Length; + text.Append (token); + } + } + + public static StringBuilder AppendFolded (this StringBuilder text, FormatOptions options, bool firstToken, string value, ref int lineLength) { int wordIndex = 0; int lwspIndex; @@ -66,6 +93,10 @@ public static StringBuilder AppendFolded (this StringBuilder text, FormatOptions lwspIndex++; } } + + // consume the end-quote + if (lwspIndex < value.Length) + lwspIndex++; } else { // normal word while (lwspIndex < value.Length && !char.IsWhiteSpace (value[lwspIndex])) @@ -73,13 +104,14 @@ public static StringBuilder AppendFolded (this StringBuilder text, FormatOptions } int length = lwspIndex - wordIndex; - if (lineLength > 1 && (lineLength + length) > options.MaxLineLength) { + if (!firstToken && lineLength > 1 && (lineLength + length) > options.MaxLineLength) { text.LineWrap (options); lineLength = 1; } text.Append (value, wordIndex, length); lineLength += length; + firstToken = false; wordIndex = lwspIndex; while (wordIndex < value.Length && char.IsWhiteSpace (value[wordIndex])) @@ -106,7 +138,7 @@ public static void AppendCStringByte (this StringBuilder text, byte c) case 0x0B: text.Append ("\\v"); break; case 0x0D: text.Append ("\\r"); break; default: - if (c < 020 || c > 0x7e) { + if (c < 0x20 || c > 0x7e) { text.AppendFormat ("\\x{0:x2}", c); } else { text.Append ((char) c); diff --git a/MimeKit/XMessagePriority.cs b/MimeKit/XMessagePriority.cs index 03b4926fa2..cf4a84ced8 100644 --- a/MimeKit/XMessagePriority.cs +++ b/MimeKit/XMessagePriority.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/MimeKit/packages.MimeKit.Mac.config b/MimeKit/packages.MimeKit.Mac.config deleted file mode 100644 index 3baddc3a52..0000000000 --- a/MimeKit/packages.MimeKit.Mac.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MimeKit/packages.MimeKit.Net45.config b/MimeKit/packages.MimeKit.Net45.config deleted file mode 100644 index 730a601e5f..0000000000 --- a/MimeKit/packages.MimeKit.Net45.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/MimeKit/packages.MimeKit.Portable.config b/MimeKit/packages.MimeKit.Portable.config deleted file mode 100644 index 100af68f8f..0000000000 --- a/MimeKit/packages.MimeKit.Portable.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/MimeKit/packages.MimeKit.TvOS.config b/MimeKit/packages.MimeKit.TvOS.config deleted file mode 100644 index 3baddc3a52..0000000000 --- a/MimeKit/packages.MimeKit.TvOS.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MimeKit/packages.MimeKit.WatchOS.config b/MimeKit/packages.MimeKit.WatchOS.config deleted file mode 100644 index 3baddc3a52..0000000000 --- a/MimeKit/packages.MimeKit.WatchOS.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MimeKit/packages.MimeKit.WindowsUniversal81.config b/MimeKit/packages.MimeKit.WindowsUniversal81.config deleted file mode 100644 index c56390c4e2..0000000000 --- a/MimeKit/packages.MimeKit.WindowsUniversal81.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/MimeKitLite.sln b/MimeKitLite.sln index e75ca7a2fc..c3a067b93f 100644 --- a/MimeKitLite.sln +++ b/MimeKitLite.sln @@ -1,23 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.12 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.Net45", "MimeKit\MimeKitLite.Net45.csproj", "{B4DA3323-F83C-4731-BE30-B1DA19B8C3E7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A56B6ECE-F1EE-41A2-A92B-18D2BDAFB6A2}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.Android", "MimeKit\MimeKitLite.Android.csproj", "{D95A2734-2A81-4C75-985E-A33B15CC62BC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.iOS", "MimeKit\MimeKitLite.iOS.csproj", "{5F211544-940D-46C9-98EB-4FD8F62506AD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.Text.Encoding", "submodules\Portable.Text.Encoding\Portable.Text.Encoding\Portable.Text.Encoding.csproj", "{EEE48C75-11BE-4B50-B759-F85B5052D473}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portable.Text.Encoding.WindowsUniversal81", "submodules\Portable.Text.Encoding\Portable.Text.Encoding\Portable.Text.Encoding.WindowsUniversal81.csproj", "{B76A64F9-B00E-4243-AE89-5D024CA3B436}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.Portable", "MimeKit\MimeKitLite.Portable.csproj", "{25C2DD3E-ED14-494F-9BD4-75536911C1BD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.WindowsUniversal81", "MimeKit\MimeKitLite.WindowsUniversal81.csproj", "{5EB9F403-45B4-4F3A-B64E-0ECC94D14167}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MimeKitLite.NetStandard", "MimeKit\MimeKitLite.NetStandard.csproj", "{23F999AF-CF50-42FF-A011-D56D68E60FB9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MimeKitLite", "MimeKit\MimeKitLite.csproj", "{23F999AF-CF50-42FF-A011-D56D68E60FB9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,34 +16,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B4DA3323-F83C-4731-BE30-B1DA19B8C3E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4DA3323-F83C-4731-BE30-B1DA19B8C3E7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4DA3323-F83C-4731-BE30-B1DA19B8C3E7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B4DA3323-F83C-4731-BE30-B1DA19B8C3E7}.Release|Any CPU.Build.0 = Release|Any CPU - {D95A2734-2A81-4C75-985E-A33B15CC62BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D95A2734-2A81-4C75-985E-A33B15CC62BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D95A2734-2A81-4C75-985E-A33B15CC62BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D95A2734-2A81-4C75-985E-A33B15CC62BC}.Release|Any CPU.Build.0 = Release|Any CPU - {5F211544-940D-46C9-98EB-4FD8F62506AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F211544-940D-46C9-98EB-4FD8F62506AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F211544-940D-46C9-98EB-4FD8F62506AD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F211544-940D-46C9-98EB-4FD8F62506AD}.Release|Any CPU.Build.0 = Release|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EEE48C75-11BE-4B50-B759-F85B5052D473}.Release|Any CPU.Build.0 = Release|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B76A64F9-B00E-4243-AE89-5D024CA3B436}.Release|Any CPU.Build.0 = Release|Any CPU - {25C2DD3E-ED14-494F-9BD4-75536911C1BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {25C2DD3E-ED14-494F-9BD4-75536911C1BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25C2DD3E-ED14-494F-9BD4-75536911C1BD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {25C2DD3E-ED14-494F-9BD4-75536911C1BD}.Release|Any CPU.Build.0 = Release|Any CPU - {5EB9F403-45B4-4F3A-B64E-0ECC94D14167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5EB9F403-45B4-4F3A-B64E-0ECC94D14167}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5EB9F403-45B4-4F3A-B64E-0ECC94D14167}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5EB9F403-45B4-4F3A-B64E-0ECC94D14167}.Release|Any CPU.Build.0 = Release|Any CPU {23F999AF-CF50-42FF-A011-D56D68E60FB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {23F999AF-CF50-42FF-A011-D56D68E60FB9}.Debug|Any CPU.Build.0 = Debug|Any CPU {23F999AF-CF50-42FF-A011-D56D68E60FB9}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -61,11 +24,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = MimeKit\MimeKitLite.Net45.csproj - Policies = $0 - $0.StandardHeader = $1 - $1.Text = @\n${FileName}\n \nAuthor: ${AuthorName} <${AuthorEmail}>\n\nCopyright (c) ${Year} ${CopyrightHolder}\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n - $0.TextStylePolicy = $4 + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3E07F961-6E08-4E6A-AF55-EC1428E15EAD} EndGlobalSection EndGlobal diff --git a/Mono.Data.Sqlite/Mono.Data.Sqlite.csproj b/Mono.Data.Sqlite/Mono.Data.Sqlite.csproj index e1f871b380..a929528ca4 100644 --- a/Mono.Data.Sqlite/Mono.Data.Sqlite.csproj +++ b/Mono.Data.Sqlite/Mono.Data.Sqlite.csproj @@ -1,4 +1,4 @@ - + Debug @@ -45,18 +45,28 @@ - + + Component + - - - + + Component + + + Component + + + Component + - + + Component + @@ -81,9 +91,7 @@ - - - + - + \ No newline at end of file diff --git a/README.md b/README.md index ea33b100be..24b30477ce 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,32 @@ [![Join the chat at https://gitter.im/jstedfast/MimeKit](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jstedfast/MimeKit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Issue Stats](http://www.issuestats.com/github/jstedfast/MimeKit/badge/pr)](http://www.issuestats.com/github/jstedfast/MimeKit) -[![Issue Stats](http://www.issuestats.com/github/jstedfast/MimeKit/badge/issue)](http://www.issuestats.com/github/jstedfast/MimeKit) +| Package |Latest Release|Latest Build| +|:--------------|:------------:|:----------:| +|**MimeKit** |[![NuGet Badge MimeKit](https://buildstats.info/nuget/MimeKit)](https://www.nuget.org/packages/MimeKit)|[![MyGet Badge MimeKit](https://buildstats.info/myget/mimekit/MimeKit)](https://www.myget.org/feed/mimekit/package/nuget/MimeKit)| +|**MimeKitLite**|[![NuGet Badge MimeKitLite](https://buildstats.info/nuget/MimeKitLite)](https://www.nuget.org/packages/MimeKitLite)|| -| |Build Status|Code Coverage|Static Analysis| -|-------------|:----------:|:-----------:|:-------------:| -|**Linux/Mac**|[![Build Status](https://travis-ci.org/jstedfast/MimeKit.svg)](https://travis-ci.org/jstedfast/MimeKit)|[![Code Coverage](https://coveralls.io/repos/jstedfast/MimeKit/badge.svg?branch=HEAD&service=github)](https://coveralls.io/r/jstedfast/MimeKit?branch=HEAD)|[![Static Analysis](https://scan.coverity.com/projects/3201/badge.svg)](https://scan.coverity.com/projects/3201)| -|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/07h7cobihqficw3s/branch/master?svg=true)](https://ci.appveyor.com/project/jstedfast/mimekit/branch/master)|[![Code Coverage](https://coveralls.io/repos/jstedfast/MimeKit/badge.svg?branch=HEAD&service=github)](https://coveralls.io/r/jstedfast/MimeKit?branch=HEAD)|[![Static Analysis](https://scan.coverity.com/projects/3201/badge.svg)](https://scan.coverity.com/projects/3201)| +| Platform |Build Status|Code Coverage|Static Analysis| +|:-------------|:----------:|:-----------:|:-------------:| +|**Linux/Mac**|[![Build Status](https://travis-ci.org/jstedfast/MimeKit.svg)](https://travis-ci.org/jstedfast/MimeKit)|[![Code Coverage](https://coveralls.io/repos/jstedfast/MimeKit/badge.svg?branch=master)](https://coveralls.io/r/jstedfast/MimeKit?branch=master)|[![Static Analysis](https://scan.coverity.com/projects/3201/badge.svg)](https://scan.coverity.com/projects/3201)| +|**Windows** |[![Build Status](https://ci.appveyor.com/api/projects/status/07h7cobihqficw3s/branch/master?svg=true)](https://ci.appveyor.com/project/jstedfast/mimekit/branch/master)|[![Code Coverage](https://coveralls.io/repos/jstedfast/MimeKit/badge.svg?branch=master)](https://coveralls.io/r/jstedfast/MimeKit?branch=master)|[![Static Analysis](https://scan.coverity.com/projects/3201/badge.svg)](https://scan.coverity.com/projects/3201)| ## What is MimeKit? MimeKit is a C# library which may be used for the creation and parsing of messages using the Multipurpose Internet Mail Extension (MIME), as defined by [numerous IETF specifications](https://github.com/jstedfast/MimeKit/blob/master/RFCs.md). +## Donate + +MimeKit is a personal open source project that I have put thousands of hours into perfecting with the +goal of making it the very best MIME parser framework for .NET. I need your help to achieve this. + +Donating helps pay for things such as web hosting, domain registration and licenses for developer tools +such as a performance profiler, memory profiler, a static code analysis tool, and more. It also helps +motivate me to continue working on the project. + +Click here to lend your support to MimeKit by making a donation! + ## History As a developer and user of email clients, I had come to realize that the vast majority of email client @@ -73,32 +86,36 @@ How does your MIME parser compare? ## License Information -MimeKit is Copyright (C) 2012-2017 Xamarin Inc. and is licensed under the MIT license: - - 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. +``` +MIT License + +Copyright (C) 2012-2020 .NET Foundation and Contributors + +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. +``` ## Installing via NuGet The easiest way to install MimeKit is via [NuGet](https://www.nuget.org/packages/MimeKit/). In Visual Studio's [Package Manager Console](http://docs.nuget.org/docs/start-here/using-the-package-manager-console), -simply enter the following command: +enter the following command: Install-Package MimeKit @@ -136,16 +153,16 @@ directory and select **Git Sync...** in the menu. Once you do that, you'll need In the top-level MimeKit directory, there are a number of solution files; they are: -* **MimeKit.sln** - includes projects for .NET 4.5, .NETStandard, PCL (Profile7 and Profile111), - Xamarin.Android, and Xamarin.iOS as well as the unit tests. -* **MimeKit.Mobile.sln** - includes only the Xamarin.Android and Xamarin.iOS projects. -* **MimeKit.Net45.sln** - includes only the .NET 4.5 project and the unit tests. +* **MimeKit.sln** - includes projects for .NET 4.5/4.6/4.7/4.8, .NETStandard 1.3/1.6/2.0 as well as the unit tests. +* **MimeKitLite.sln** - includes projects for the stripped-down versions of MimeKit that drop support for crypto. -If you don't have the Xamarin products, you'll probably want to open the MimeKit.Net45.sln instead of MimeKit.sln. +Once you've opened the appropriate MimeKit solution file in [Visual Studio](https://www.visualstudio.com/downloads/), +you can choose the **Debug** or **Release** build configuration and then build. -Once you've opened the appropriate MimeKit solution file in either [Xamarin Studio](https://www.xamarin.com/download) -or [Visual Studio 2017](https://www.visualstudio.com/downloads/), you can simply choose the **Debug** or **Release** -build configuration and then build. +Both Visual Studio 2017 and Visual Studio 2019 should be able to build MimeKit without any issues, but older versions such as +Visual Studio 2015 will require modifications to the projects in order to build correctly. It has been reported that adding +NuGet package references to [Microsoft.Net.Compilers](https://www.nuget.org/packages/Microsoft.Net.Compilers/) >= 3.6.0 +and [System.ValueTuple](https://www.nuget.org/packages/System.ValueTuple/) >= 4.5.0 will allow MimeKit to build successfully. Note: The **Release** build will generate the xml API documentation, but the **Debug** build will not. @@ -731,7 +748,7 @@ would use an OpenPGP cryptography context. For example, you might use a subclass use `GnuPGContext` directly because it has no way of prompting the user for their passphrase). For the sake of this example, let's pretend that you've written a minimal subclass of -`MimeKit.Cryptography.GnuPGContext` that simply overrides the `GetPassword()` method and +`MimeKit.Cryptography.GnuPGContext` that only overrides the `GetPassword()` method and that this subclass is called `MyGnuPGContext`. ```csharp @@ -825,10 +842,9 @@ file called **privatekey.pem**: ```csharp var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }; -var headerAlgorithm = DkimCanonicalizationAlgorithm.Simple; -var bodyAlgorithm = DkimCanonicalizationAlgorithm.Simple; -var signer = new DkimSigner ("privatekey.pem") { - SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha1, +var signer = new DkimSigner ("privatekey.pem", "example.com", "brisbane", DkimSignatureAlgorithm.RsaSha256) { + HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, + BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Simple, AgentOrUserIdentifier = "@eng.example.com", QueryMethod = "dns/txt", }; @@ -838,7 +854,7 @@ var signer = new DkimSigner ("privatekey.pem") { // then you can use `EncodingConstraint.EightBit` instead. message.Prepare (EncodingConstraint.SevenBit); -message.Sign (signer, headers, headerAlgorithm, bodyAlgorithm); +signer.Sign (message, headers); ``` As you can see, it's fairly straight forward. @@ -859,19 +875,21 @@ using System; using System.IO; using System.Text; using System.Threading; +using System.Threading.Tasks; using System.Collections.Generic; using Heijden.DNS; using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.OpenSsl; using MimeKit; using MimeKit.Cryptography; -namespace DkimVerifier +namespace DkimVerifierExample { - class DkimPublicKeyLocator : IDkimPublicKeyLocator + // Note: By using the DkimPublicKeyLocatorBase, we avoid having to parse the DNS TXT records + // in order to get the public key ourselves. + class DkimPublicKeyLocator : DkimPublicKeyLocatorBase { readonly Dictionary cache; readonly Resolver resolver; @@ -907,66 +925,13 @@ namespace DkimVerifier } var txt = builder.ToString (); - string k = null, p = null; - int index = 0; - - // parse the response (will look something like: "k=rsa; p=") - while (index < txt.Length) { - while (index < txt.Length && char.IsWhiteSpace (txt[index])) - index++; - - if (index == txt.Length) - break; - - // find the end of the key - int startIndex = index; - while (index < txt.Length && txt[index] != '=') - index++; - - if (index == txt.Length) - break; - - var key = txt.Substring (startIndex, index - startIndex); - - // skip over the '=' - index++; - - // find the end of the value - startIndex = index; - while (index < txt.Length && txt[index] != ';') - index++; - - var value = txt.Substring (startIndex, index - startIndex); - - switch (key) { - case "k": k = value; break; - case "p": p = value; break; - } - - // skip over the ';' - index++; - } - - if (k != null && p != null) { - var data = "-----BEGIN PUBLIC KEY-----\r\n" + p + "\r\n-----END PUBLIC KEY-----\r\n"; - var rawData = Encoding.ASCII.GetBytes (data); - - using (var stream = new MemoryStream (rawData, false)) { - using (var reader = new StreamReader (stream)) { - var pem = new PemReader (reader); - - pubkey = pem.ReadObject () as AsymmetricKeyParameter; - - if (pubkey != null) { - cache.Add (query, pubkey); - - return pubkey; - } - } - } - } - throw new Exception (string.Format ("Failed to look up public key for: {0}", domain)); + // DkimPublicKeyLocatorBase provides us with this helpful method. + pubkey = GetPublicKey (txt); + + cache.Add (query, pubkey); + + return pubkey; } public AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) @@ -979,6 +944,13 @@ namespace DkimVerifier throw new NotSupportedException (string.Format ("{0} does not include any suported lookup methods.", methods)); } + + public Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + return Task.Run (() => { + return LocatePublicKey (methods, domain, selector, cancellationToken); + }, cancellationToken); + } } class Program @@ -998,6 +970,7 @@ namespace DkimVerifier } var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); for (int i = 0; i < args.Length; i++) { if (!File.Exists (args[i])) { @@ -1017,7 +990,7 @@ namespace DkimVerifier var dkim = message.Headers[index]; - if (message.Verify (dkim, locator)) { + if (verifier.Verify (message, dkim)) { // the DKIM-Signature header is valid! Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine ("VALID"); @@ -1042,45 +1015,229 @@ namespace DkimVerifier } ``` +### Signing Messages with ARC + +Signing with ARC is similar to DKIM but quite a bit more involved. In order to sign with +ARC, you must first validate that the existing message is authentictic and produce +an ARC-Authentication-Results header containing the methods that you used to +authenticate the message as well as their results. + +The abstract [ArcSigner](http://www.mimekit.net/docs/html/T_MimeKit_Cryptography_ArcSigner.htm) +class provided by MimeKit will need to be subclassed before it can be used. An example subclass +that provides 2 different implementations for generating the ARC-Authentication-Results header +can be seen below: + +```csharp +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using MimeKit; +using MimeKit.Cryptography; + +namespace ArcSignerExample +{ + class MyArcSigner : ArcSigner + { + public MyArcSigner (string fileName, string domain, string selector, DkimSigningAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) + : base (fileName, domain, selector, algorithm) + { + } + + /// + /// Generate the ARC-Authentication-Results header. + /// + /// + /// The ARC-Authentication-Results header contains information detailing the results of + /// authenticating/verifying the message via ARC, DKIM, SPF, etc. + /// + /// In the following implementation, we assume that all of these authentication results + /// have already been determined by other mail software that has added some Authentication-Results + /// headers containing this information. + /// + /// Note: This method is used when ArcSigner.Sign() is called instead of ArcSigner.SignAsync(). + /// + protected override AuthenticationResults GenerateArcAuthenticationResults (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + const string AuthenticationServiceIdentifier = "lists.example.com"; + + var results = new AuthenticationResults (AuthenticationServiceIdentifier); + + for (int i = 0; i < message.Headers.Count; i++) { + var header = message.Headers[i]; + + if (header.Id != HeaderId.AuthenticationResults) + continue; + + if (!AuthenticationResults.TryParse (header.RawValue, out AuthenticationResults authres)) + continue; + + if (authres.AuthenticationServiceIdentifier != AuthenticationServiceIdentifier) + continue; + + // Merge any authentication results that aren't already known. + foreach (var result in authres.Results) { + if (!results.Results.Any (r => r.Method == result.Method)) + results.Results.Add (result); + } + } + + return results; + } + + /// + /// Generate the ARC-Authentication-Results asynchronously. + /// + /// + /// The ARC-Authentication-Results header contains information detailing the results of + /// authenticating/verifying the message via ARC, DKIM, SPF, etc. + /// + /// In the following implementation, we assume that we have to verify all of the various + /// authentication methods ourselves. + /// + /// Note: This method is used when ArcSigner.SignAsync() is called instead of ArcSigner.Sign(). + /// + protected override async Task GenerateArcAuthenticationResultsAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + const string AuthenticationServiceIdentifier = "lists.example.com"; + + var results = new AuthenticationResults (AuthenticationServiceIdentifier); + var locator = new DkimPublicKeyLocator (); // from the DKIM example above + var dkimVerifier = new DkimVerifier (locator); + var arcVerifier = new ArcVerifier (locator); + AuthenticationMethodResult method; + + // Add the ARC authentication results + try { + var arc = await arcVerifier.VerifyAsync (message, cancellationToken); + var result = arc.Chain.ToString ().ToLowerInvariant (); + + method = new AuthenticationMethodResult ("arc", result); + results.Results.Add (method); + } catch { + // Likely a DNS error + method = new AuthenticationMethodResult ("arc", "fail"); + method.Reason = "DNS error"; + results.Results.Add (method); + } + + // Add authentication results for each DKIM signature + foreach (var dkimHeader in message.Headers.Where (h => h.Id == HeaderId.DkimSignature)) { + string result; + + try { + if (await dkimVerifier.VerifyAsync (message, cancellationToken)) { + result = "pass"; + } else { + result = "fail"; + } + } catch { + result = "fail"; + } + + method = new AuthenticationMethodResult ("dkim", result); + + // Parse the DKIM-Signature header so that we can add some + // properties to our method result. + var params = dkimHeader.Value.Replace (" ", "").Split (new char[] { ';' }); + var i = params.FirstOrDefault (p => p.StartsWith ("i=", StringComparison.Ordinal)); + var b = params.FirstOrDefault (p => p.StartsWith ("b=", StringComparison.Ordinal)); + + if (i != null) + method.Parameters.Add ("header.i", i.Substring (2)); + + if (b != null) + method.Parameters.Add ("header.b", b.Substring (2, 8)); + + results.Results.Add (method); + } + + return results; + } + } +} +``` + +Once you have a custom `ArcSigner` class, the actual logic for signing is almost identical to DKIM. + +Note: As with the DKIM signing example above, assume that the private key is saved in a +file called **privatekey.pem**: + +```csharp +var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }; +var signer = new MyArcSigner ("privatekey.pem", "example.com", "brisbane", DkimSignatureAlgorithm.RsaSha256) { + HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed, + BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed, + AgentOrUserIdentifier = "@eng.example.com" +}; + +// Prepare the message body to be sent over a 7bit transport (such as older versions of SMTP). +// Note: If the SMTP server you will be sending the message over supports the 8BITMIME extension, +// then you can use `EncodingConstraint.EightBit` instead. +message.Prepare (EncodingConstraint.SevenBit); + +signer.Sign (message, headers); // or SignAsync +``` + +### Verifying ARC Signatures + +Just like with verifying DKIM signatures, you will need to implement the `IDkimPublicKeyLocator` +interface. To see an example of how to implement this interface, see the DKIM signature verification +example above. + +The `ArcVerifier` works exactly the same as the `DkimVerifier` except that it is not necessary +to provide a `Header` argument to the `Verify` or `VerifyAsync` method. + +```csharp +var verifier = new ArcVerifier (new DkimPublicKeyLocator ()); +var results = await verifier.VerifyAsync (message); + +// The Chain results are the only real important results. +Console.WriteLine ("ARC results: {0}", results.Chain); +``` + ## Contributing The first thing you'll need to do is fork MimeKit to your own GitHub repository. For instructions on how to do that, see the section titled **Getting the Source Code**. -If you use [Xamarin Studio](http://xamarin.com/studio) or [MonoDevelop](http://monodevelop.com), all of the -solution files are configured with the coding style used by MimeKit. If you use Visual Studio or some -other editor, please try to maintain the existing coding style as best as you can. +If you use [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/) or [MonoDevelop](http://monodevelop.com), +all of the solution files are configured with the coding style used by MimeKit. If you use Visual Studio on Windows or +some other editor, please try to maintain the existing coding style as best as you can. Once you've got some changes that you'd like to submit upstream to the official MimeKit repository, -simply send me a **Pull Request** and I will try to review your changes in a timely manner. +send me a **Pull Request** and I will try to review your changes in a timely manner. If you'd like to contribute but don't have any particular features in mind to work on, check out the issue tracker and look for something that might pique your interest! -## Donate +## Reporting Bugs -MimeKit is a personal open source project that I have put thousands of hours into perfecting with the -goal of making it not only the very best MIME parser framework for .NET, but the best MIME parser -framework for any programming language. I need your help to achieve this. +Have a bug or a feature request? Please open a new +[bug report](https://github.com/jstedfast/MimeKit/issues/new?template=bug_report.md) +or +[feature request](https://github.com/jstedfast/MimeKit/issues/new?template=feature_request.md). -Donating helps pay for things such as web hosting and licenses for developer tools such as a -performance profiler, memory profiler, a static code analysis tool, and more. +Before opening a new issue, please search through any [existing issues](https://github.com/jstedfast/MimeKit/issues) +to avoid submitting duplicates. It may also be worth checking the +[FAQ](https://github.com/jstedfast/MimeKit/blob/master/FAQ.md) for common questions that other developers +have had. - - Click here to lend your support to MimeKit and MailKit by making a donation via pledgie.com! - +If you are getting an exception from somewhere within MimeKit, don't just provide the `Exception.Message` +string. Please include the `Exception.StackTrace` as well. The `Message`, by itself, is often useless. -## Reporting Bugs +## Documentation -Have a bug or a feature request? [Please open a new issue](https://github.com/jstedfast/MimeKit/issues). +API documentation can be found at [http://www.mimekit.net/docs](http://www.mimekit.net/docs). -Before opening a new issue, please search for existing issues to avoid submitting duplicates. +A copy of the XML-formatted API reference documentation is also included in the NuGet package. -## Documentation +## .NET Foundation + +MimeKit is a [.NET Foundation](https://www.dotnetfoundation.org/projects) project. -API documentation can be found at [http://mimekit.net/docs](http://mimekit.net/docs). +This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct). -A copy of the xml formatted API documentation is also included in the NuGet and/or -Xamarin Component package. +General .NET OSS discussions: [.NET Foundation forums](https://forums.dotnetfoundation.org) diff --git a/RFCs.md b/RFCs.md index 2cc789353c..500676104f 100644 --- a/RFCs.md +++ b/RFCs.md @@ -45,16 +45,27 @@ MimeKit implements the following IETF specifications defining Internet Mail and * [4262](http://www.ietf.org/rfc/rfc4262.txt): X.509 Certificate Extension for S/MIME Capabilities * [4871](http://www.ietf.org/rfc/rfc4871.txt): DomainKeys Identified Mail (DKIM) Signatures * [5322](http://www.ietf.org/rfc/rfc5322.txt): Internet Message Format (Obsoletes rfc2822) +* [5451](http://www.ietf.org/rfc/rfc5451.txt): Message Header Field for Indicating Message Authentication Status * [5672](http://www.ietf.org/rfc/rfc5672.txt): RFC 4871 DomainKeys Identified Mail (DKIM) Signatures -- Update * [5750](http://www.ietf.org/rfc/rfc5750.txt): S/MIME Version 3.2 Certificate Handling (Obsoletes rfc3850) * [5751](http://www.ietf.org/rfc/rfc5751.txt): S/MIME Version 3.2 Message Specification (Obsoletes rfc3851) * [6376](http://www.ietf.org/rfc/rfc6376.txt): DomainKeys Identified Mail (DKIM) Signatures (Obsoletes rfc4871) * [6522](http://www.ietf.org/rfc/rfc6522.txt): The Multipart/Report Media Type for the Reporting of Mail System Administrative Messages (Obsoletes rfc3462) * [6532](http://www.ietf.org/rfc/rfc6532.txt): Internationalized Email Headers +* [6533](http://www.ietf.org/rfc/rfc6533.txt): Internationalized Delivery Status and Disposition Notifications +* [7001](http://www.ietf.org/rfc/rfc7001.txt): Message Header Field for Indicating Message Authentication Status (Obsoletes rfc5451) +* [7601](http://www.ietf.org/rfc/rfc7601.txt): Message Header Field for Indicating Message Authentication Status (Obsoletes rfc7001) +* [8301](http://www.ietf.org/rfc/rfc8301.txt): Cryptographic Algorithm and Key Usage Update to DomainKeys Identified Mail (DKIM) +* [8463](http://www.ietf.org/rfc/rfc8463.txt): A New Cryptographic Signature Method for DomainKeys Identified Mail (DKIM) #### Other RFCs of interest: * [1523](http://www.ietf.org/rfc/rfc1523.txt): The text/enriched MIME Content-type * [1927](http://www.ietf.org/rfc/rfc1927.txt): Suggested Additional MIME Types for Associating Documents +* [2369](http://www.ietf.org/rfc/rfc2369.txt): The Use of URLs as Meta-Syntax for Core Mail List Commands and their Transport through Message Header Fields * [2388](http://www.ietf.org/rfc/rfc2388.txt): Returning Values from Forms: multipart/form-data +* [6577](http://www.ietf.org/rfc/rfc6577.txt): Authentication-Results Registration Update for Sender Policy Framework (SPF) Results * [7103](http://www.ietf.org/rfc/rfc7103.txt): Advice for Safe Handling of Malformed Messages +* [7410](http://www.ietf.org/rfc/rfc7410.txt): A Property Types Registry for the Authentication-Results Header Field +* [8550](http://www.ietf.org/rfc/rfc8550.txt): S/MIME Version 4.0 Certificate Handling (Obsoletes rfc5750) +* [8551](http://www.ietf.org/rfc/rfc8551.txt): S/MIME Version 4.0 Message Specification (Obsoletes rfc5751) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index e4fbb7351d..044403a256 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,6 +1,397 @@ # Release Notes -### MimeKit 2.0.1 +### MimeKit 2.10.1 (2020-12-05) + +* Treat message/disposition-notification and message/delivery-status the same as text/* + when preparing for signing. (issue [#626](https://github.com/jstedfast/MimeKit/issues/626)) +* Always set Content-Disposition: inline for BodyBuilder.LinkedResources. This fixes a + regression introduced in 2.10.0. + (issue [#627](https://github.com/jstedfast/MimeKit/issues/627)) +* Fixed NuGet package references to System.Data.DataSetExtensions for netstandard2.1 and + net4x. + +### MimeKit 2.10.0 (2020-11-20) + +* Added SQL Server support. (issue [#619](https://github.com/jstedfast/MimeKit/issues/619)) +* Fixed a leak in SqlCertificateDatabase when creating the certificates database. +* Bumped BouncyCastle dependency to v1.8.8. (issue [#610](https://github.com/jstedfast/MimeKit/issues/610)) +* Exposed some ArcVerifier and DkimVerifier internal methods. + (issue [#601](https://github.com/jstedfast/MimeKit/issues/601)) +* Improved MimeParser performance. +* Fixed potential leaks in MimeParser when loading MimePart content in exception cases. +* Made use of ArrayPools for various buffers which may help performance. + (issue [#616](https://github.com/jstedfast/MimeKit/issues/616)) +* Fixed MimeUtils.GenerateMessageId() to encode international domain names. +* Fixed MimeUtils.GenerateMessageId() to cache the local hostname. + (issue [#612](https://github.com/jstedfast/MimeKit/issues/612)) +* Modified AttachmentCollection to use a custom implementation of Path.GetFileName() + that allows illegal path characters. +* Only generate a ContentId for the MultipartRelated Root if it is not the first part. + +### MimeKit 2.9.2 (2020-09-12) + +* Include WindowsSecureMimeContext in the .NET Standard 2.x build. + (issue [#600](https://github.com/jstedfast/MimeKit/issues/600)) +* Fixed message.Prepare() to never choose the quoted-printable encoding + for non-text based MimeParts. + (issue [#598](https://github.com/jstedfast/MimeKit/issues/598)) +* Added work-around for mailers that don't use a ';' between Content-Type + and Content-Disposition parameters. + (issue [#595](https://github.com/jstedfast/MimeKit/issues/595)) +* Added improved error reporting for ArcVerifier. + (issue [#591](https://github.com/jstedfast/MimeKit/issues/591)) +* Added another work-around for parsing Authentication-Results headers. + (issue [#590](https://github.com/jstedfast/MimeKit/issues/590)) +* MimeMessage.ToString() now adds an X-MimeKit-Warning header to the + beginning of the output string to make it clear to developers doing this + that they are Doing it Wrong(tm). +* Added a TLS-Required HeaderId enum value. + +### MimeKit 2.9.1 (2020-07-11) + +* Refactored OpenPgpContext to separate out key storage implementation. + (issue [#576](https://github.com/jstedfast/MimeKit/issues/576)) +* Fixed the TextToFlowed converter. + (issue [#580](https://github.com/jstedfast/MimeKit/issues/580)) +* Protect against ABRs in AuthenticationResults.TryParse(). + (issue [#581](https://github.com/jstedfast/MimeKit/issues/581)) +* The net45 version of MimeKit now depends on Portable.BouncyCastle instead of official + BouncyCastle. +* Added MimeParser events to report stream offsets for MimeMessages and MimeEntities. + (issue [#582](https://github.com/jstedfast/MimeKit/issues/582)) +* Fixed DkimPublicKeyLocatorBase to treat unspecified 'k' values in DKIM DNS records as + "k=rsa". + (issue [#583](https://github.com/jstedfast/MimeKit/issues/583)) +* Fixed date format serializer to use CultureInfo.InvariantCulture. +* Fixed AuthenticationResults parser to allow '_' characters in method results. + (issue [#584](https://github.com/jstedfast/MimeKit/issues/584)) +* Improved RSACng and DSACng support. + +### MimeKit 2.8.0 (2020-05-30) + +* Improved logic for verifying signatures for MimeParts containing mixed line endings. + (issue [#569](https://github.com/jstedfast/MimeKit/issues/569)) +* Fixed MailboxAddress parser to decode IDN-encoded local-parts of email addresses. + (MailKit issue [#1026](https://github.com/jstedfast/MailKit/issues/1026)) +* Added new MailboxAddress.GetAddress(bool idnEncode) method. +* Improved subclassability of OpenPgpContext by making a number of methods virtual. + (issue [#571](https://github.com/jstedfast/MimeKit/issues/571)) +* Added support for RSACng and DSACng. + (issue [#567](https://github.com/jstedfast/MimeKit/issues/567)) +* Dropped Xamarin platforms since they are compatible with netstandard2.0. + +### MimeKit 2.7.0 (2020-05-19) + +* Fixed InternetAddressList.Insert() to allow inserting at the end of the list. + (issue [#559](https://github.com/jstedfast/MimeKit/issues/559)) +* Added ParserOptions.MaxMimeDepth to allow developers to set the max nesting depth + allowed by the parser. +* Added logic to handle multipart children without any headers or content. +* Added a new Verify(bool verifySignatureOnly) method to IDigitalSignature for + developers who just want to be able to verify the signature without worrying + about the certificate chain. +* Fixed MimePart.WriteTo() to avoid canonicalizing line endings for MimeParts that + do not define a Content-Transfer-Encoding. + (issue [#569](https://github.com/jstedfast/MimeKit/issues/569)) +* NuGet packages now include the portable pdb's. + +### MimeKit 2.6.0 (2020-04-03) + +* Fixed the MimeEntity.ContentId setter to use ParseUtils.TryParseMsgId() instead of + MailboxAddress.TryParse() so that it is more lenient in what it accepts. + (issue [#542](https://github.com/jstedfast/MimeKit/issues/542)) +* Added an HtmlTokenizer.IgnoreTruncatedTags property which is useful when working with + truncated HTML. +* Optimized the heck out of HtmlEntityDecoder. +* Added a TextPart.Format property for a quick way to determine the type of text it + contains. +* Added text/plain and text/html preview/snippet generators (PlainTextPreviewer and + HtmlTextPreviewer, respectively). This is part of a larger improvement to MailKit's + text preview feature for IMAP. + (MailKit issue [#1001](https://github.com/jstedfast/MailKit/issues/1001)) +* Fixed SqlCertificateDatabase to accept null SubjectKeyIdentifiers. +* Changed Header.FormatRawValue() to be protected virtual and added Header.SetRawValue() + to allow developers to override the default formatting behavior by either subclassing + Header or by calling header.SetRawValue(). + (issue [#546](https://github.com/jstedfast/MimeKit/issues/546)) +* Switched MimeKit for Android and iOS over to using Portable.BouncyCastle. +* Added MimeTypes.Register() to allow developers to register their own mime-type mappings + to file extensions. + +### MimeKit 2.5.2 (2020-03-14) + +* Updated net46, net47, and net48 builds to reference Portable.BouncyCastle instead of + the standard BouncyCastle package, just like the netstandard builds. + (issue [#540](https://github.com/jstedfast/MimeKit/issues/540)) +* Fixed extraction of TNEF EmbeddedMessage attachment data to skip the leading GUID. + (issue [#538](https://github.com/jstedfast/MimeKit/issues/538)) +* Added a few more TNEF property tags. +* Fixed the HtmlEntityDecoder to require some named attributes to end with a `;`. + +### MimeKit 2.5.1 (2020-02-15) + +* Fixed parsing of email addresses containing unicode or other types of 8-bit text. + (issue [#536](https://github.com/jstedfast/MimeKit/issues/536)) +* Added a MimeTypes.TryGetExtension() method to try and get a file name extension + based on a mime-type. + (issue [#534](https://github.com/jstedfast/MimeKit/issues/534)) +* Updated mime-type mappings. + +### MimeKit 2.5.0 (2020-01-18) + +* Fixed message reserialization after prepending headers. + (issue [#524](https://github.com/jstedfast/MimeKit/issues/524)) +* Added a ContentType.CharsetEncoding property. + (issue [#526](https://github.com/jstedfast/MimeKit/issues/526)) +* Allow empty prop-spec token values in Authentication-Results headers. + (issue [#527](https://github.com/jstedfast/MimeKit/issues/527)) +* Added logic to quote Authentication-Results pvalue tokens if needed. +* Added support for converting RSACng keys into BouncyCastle keys for + net4x versions that support it. +* Added support for RSAES-OAEP for the BouncyCastle backend. + (issue [#528](https://github.com/jstedfast/MimeKit/issues/528)) +* Updated and changed the API for RSASSA-PSS. CmsSigner now has a + RsaSignaturePadding property which obsoletes the previous + RsaSignaturePaddingScheme property. +* Added more columns to the default SQLite database CERTIFICATES table + that allow more optimal SQL searches for certificates given various + matching criteria. +* Fixed WindowsSecureMimeContext.Decrypt() to make sure it doesn't stop + at the first failed recipient. + (issue [#530](https://github.com/jstedfast/MimeKit/issues/530)) +* Fixed splitting and reassembly of message/partial messages. +* Improved handling of Office365 Authentication-Results headers by adding + a Office365AuthenticationServiceIdentifier property to the + AuthenticationMethodResult class. +* Fixed mailbox address parser to be more lenient about `"["` and `"]"` + characters in the display-name. + (issue [#532](https://github.com/jstedfast/MimeKit/issues/532)) + +### MimeKit 2.4.1 (2019-11-10) + +* Don't use PublicSign on non-Windows NT machines when building. + (issue [#516](https://github.com/jstedfast/MimeKit/issues/516)) +* Improved BouncyCastleSecureMimeContext logic for building certificate chains so that + certificate chains are included in the S/MIME signature. + (issue [#515](https://github.com/jstedfast/MimeKit/issues/515)) +* Improved SqlCertificateDatabase.Find() by using more IX509Selector properties. +* Relaxed the Authentication-Results header parser a bit to allow '/' in pvalue tokens. + (issue [#518](https://github.com/jstedfast/MimeKit/issues/518)) + +### MimeKit 2.4.0 (2019-11-02) + +* Added the `text/csv` mime-type to the `MimeTypes` mapping table for files with a .csv extension. +* Expanded the .NETStandard API to match the .NET 4.5 API, so .NETStandard is now complete. +* Dropped support for .NETPortable and WindowsPhone/Universal v8.1. +* Added a net48 assembly to the NuGet package. +* Improved HTML tokenizer performance. +* Fixed X509Crl.IsDelta for CRLs without extensions. + (issue [#513](https://github.com/jstedfast/MimeKit/issues/513)) +* Added support for `message/global-delivery-status`, `message/global-disposition-notification`, + and `message/global-headers` to `MimeParser`. + (issue [#514](https://github.com/jstedfast/MimeKit/issues/514)) +* Fixed S/MIME signatures generated by a TemporarySecureMimeContext to include the certificate chain. + (issue [#515](https://github.com/jstedfast/MimeKit/issues/515)) + +### MimeKit 2.3.2 (2019-10-12) + +* Fixed reserialization of message/rfc822 parts to not add an extra new-line sequence + to the end of the message. (issue [#510](https://github.com/jstedfast/MimeKit/issues/510)) +* Fixed DefaultSecureMimeContext to build the cert chain outside of the private key query. + (issue [#508](https://github.com/jstedfast/MimeKit/issues/508)) +* Modified the Message-Id parser to gobble ctrl chars in the local-part. +* Fixed some buglets in the TextToFlowed converter involving space-stuffing lines. +* Fixed BodyBuilder logic for constructing a body with an HtmlBody set to string.Empty. + (issue [#506](https://github.com/jstedfast/MimeKit/issues/506)) +* Fixed potential memory leaks in WindowsSecureMimeContext and BouncyCastleSecureMimeContext + in the Export() methods in cases where an exception is throw while adding certificates. +* Removed MimeKit.Cryptography.NpgsqlCertificateDatabase. It is unlikely anyone actually + uses this. + +### MimeKit 2.3.1 (2019-09-08) + +* Updated CmsSigner's default DigestAlgorithm to Sha256 instead of Sha1 to match + System.Security.Cryptography.Pkcs.CmsSigner's default. +* Updated WindowsSecureMimeContext to default to IssuerAndSerialNumber for + System.Security.Cryptography.Pkcs.CmsSigner. +* Added support for the RSASSA-PSS signature padding algorithm when using the + BouncyCastle backend. +* Improved robustness of TNEF processing of email address fields. +* Modified FilteredStream.Flush*() to not flush the source stream. + (MailKit issue [#904](https://github.com/jstedfast/MailKit/issues/904)) +* Added net46 and net47 assemblies to the NuGet package. + +### MimeKit 2.3.0 (2019-08-24) + +* Fixed MultipartRelated to fall back to the multipart/related type parameter when + locating the Root. (issue [#489](https://github.com/jstedfast/MimeKit/issues/489)) +* Improved Authentication-Results parser to handle non-standard syntax. + (issue [#490](https://github.com/jstedfast/MimeKit/issues/490)) +* When FormatOptions.AllowMixedHeaderCharsets is disabled, always use the user-specified + charset. Previously this could/would still use us-ascii and/or iso-8859-1 if the entire + header could fit within one of those charsets. + (issue [#493](https://github.com/jstedfast/MimeKit/issues/493)) +* Fixed the line length calculations in the BestEncodingFilter. + (issue [#497](https://github.com/jstedfast/MimeKit/issues/497)) +* Fixed Multipart to properly ensure the epilogue ends w/ a new-line when + FormatOptions.EnsureNewLine is true. + (issue [#499](https://github.com/jstedfast/MimeKit/issues/499)) +* Modified Multipart.WriteTo[Async] to not ensure that a Content-Type boundary parameter + has been set. This code-path was only hit if the multipart was parsed by the parser and + did not have a boundary parameter in the first place. In the interest of preserving + byte-for-byte compatibility with the original input, this sanity check has been removed. + (issue [#499](https://github.com/jstedfast/MimeKit/issues/499)) + +### MimeKit 2.2.0 (2019-06-11) + +* Added support for [ARC](https://arc-spec.org). +* Added AuthenticationResults class for parsing and constructing Authentication-Results and + ARC-Authentication-Results headers. +* Added support for the Ed25519-SHA256 DKIM signature algorithm. +* Obsoleted MimeMessage DKIM API's in favor of the newer DKIM API's: + - MimeMessage.Sign (DkimSigner, ...) has been replaced by DkimSigner.Sign (MimeMessage, ...). + - MimeMessage.Verify (Header, ...) has been replaced by DkimVerifier.Verify (MimeMessage, Header, ...). +* Added DkimPublicKeyLocatorBase to help simplify implementing IDkimPublicKeyLocator. + +### MimeKit 2.1.5 (2019-05-13) + +* Updated the BouncyCastle assemblies to version 1.8.5 for iOS and Android. +* Fixed a possible NullReferenceException when decoding S/MIME digital signatures. +* Fixed the netstandard2.0 dependencies to no longer explicitly include System.Net.Http. + (issue [#482](https://github.com/jstedfast/MimeKit/issues/482)) +* Override Equals(object) and GetHashCode() for InternetAddress and InternetAddressList. + (issue [#481](https://github.com/jstedfast/MimeKit/issues/481)) +* Fixed TnefReader.Dispose() to avoid a potential NullReferenceException if double disposed. +* Fixed the Message-Id, Content-Id, References and In-Reply-To parsers to be more liberal + in what they accept in terms of the `msg-id` token. +* Changed the Header encoding logic for the In-Reply-To header to not rfc2047 encode the value + even if it is longer than the suggested line-length. + (issue [#479](https://github.com/jstedfast/MimeKit/issues/479)) +* Reduced netstandard dependencies. (issue [#475](https://github.com/jstedfast/MimeKit/issues/475)) + +### MimeKit 2.1.4 (2019-04-13) + +* Added a setter for FormatOptions.MaxLineLength, allowing developers to override this value. +* Improved TNEF handling of Content-Disposition and Content-Id properties. + (issue [#470](https://github.com/jstedfast/MimeKit/pull/470) and + issue [#471](https://github.com/jstedfast/MimeKit/pull/471)) +* Improved Content-Id parser to be more forgiving with improperly formatted IDs. + (issue [#472](https://github.com/jstedfast/MimeKit/issue/472)) +* Added support for the text/rfc822-headers MIME-type via the new TextRfc822Headers class. + (issue [#474](https://github.com/jstedfast/MimeKit/issue/474)) +* Added fallback logic for international email addresses that are not properly encoded in UTF-8. + (issue [#477](https://github.com/jstedfast/MimeKit/issue/477)) + +### MimeKit 2.1.3 (2019-02-24) + +* Fixed an NRE in X509CertificateDatabase.Dispose(). +* Fixed TextPart.Text and GetText() to properly canonicalize EOLN for multi-byte charsets + such as UTF-16. (issue [#442](https://github.com/jstedfast/MimeKit/issues/442)) +* Fixed System.Net.Mail.MailMessage cast to MimeMessage when the ContentStream of + the attachments has not been rewound to the beginning of the stream. + (issue [#467](https://github.com/jstedfast/MimeKit/issues/467)) +* Changed ParserOptions.AllowAddressesWithoutDomain to work as users expected and + moved the old logic into ParserOptions.AllowUnquotedCommasInAddresses. + (issue [#465](https://github.com/jstedfast/MimeKit/issues/465)) + +### MimeKit 2.1.2 (2018-12-30) + +* Fixed WindowsSecureMimeDigitalCertificate logic for ECDsa. +* Added X509Certificate.GetPublicKeyAlgorithm() extension method. +* Modified ApplicationPkcs7Mime to be less strict about the smime-type. + +### MimeKit 2.1.1 (2018-12-16) + +* Mapped the TNEF Sensitivity property to the Sensitivity message header when calling + TnefPart.ConvertToMessage(). +* Fixed the TNEF Importance and Priority mappings when calling TnefPart.ConvertToMessage(). +* Added more TnefPropertyId's that have been identified. +* Map PidTagTnefCorrelationKey to the Message-Id message header. +* When the TNEF data does not have a SentDate property, set the MimeMessage.Date property + to DateTimeOffset.MinValue instead of DateTimeOffset.Now. +* Fixed TnefPart.ConvertToMessage() to check the TNEF SubjectPrefix and NormalizedSubject + properties and use them if a TNEF Subject property is not available. +* Fixed TNEF logic for extracting attachment content to not truncate some bytes from the beginning + of the content. +* Added more fallbacks for attempting to extract the sender information out of the TNEF data. +* Bumped Android and iOS versions of BouncyCastle to v1.8.4. + +### MimeKit 2.1.0 (2018-12-01) + +* Optimized SecureMimeCryptographyContext.Supports() and OpenPgpCryptographyContext.Supports() + implementations. +* Optimized the OptimizedOrdinalIgnoreCaseComparer even more. +* Fixed OpenPgpDigitalCertificate.ExpirationDate for PGP keys that never expire. +* Reduced string allocations in MultipartSigned.Verify() and MultipartEncrypted.Decrypt(). +* Fixed OpenPgpContext.Decrypt() to make sure to always clean up MemoryBlockStreams. +* Added a bunch more HeaderId enum values. +* Improved header folding logic for headers with long words. + (issue [#451](https://github.com/jstedfast/MimeKit/issues/451)) + +### MimeKit 2.0.7 (2018-10-28) + +* Fixed a bug in the UUEncoder. +* Fixed a bug in MimeIterator.MoveTo(). +* Modified BodyBuilder.ToMessageBody() to avoid returning a multipart/mixed with only a single + child. (issue [#441](https://github.com/jstedfast/MimeKit/issues/441)) +* Modified TnefPart to no longer set the name parameter on the Content-Type header of + extracted message bodies. (issue [#435](https://github.com/jstedfast/MimeKit/issues/435)) +* Fixed various locations that loaded content from files to use FileShare.Read so as to avoid file + sharing violations if the application already has that file opened elsewhere. (issue [#426](https://github.com/jstedfast/MimeKit/issues/426)) +* Improved address parser to handle "local-part (User Name)" style addresses. +* Updated the iOS and Android BouncyCastle dependency to 1.8.3. +* Modified TextPart.Text and GetText() to canonicalize the newlines. (issue [#442](https://github.com/jstedfast/MimeKit/issues/442)) +* Fixed WindowsSecureMimeContext.EncapsulatedSign (CmsSigner, ...) and Sign (CmsSigner, ...). +* Added SecureMimeContext.Import(string, string) to import passworded pk12 files. +* Improved MimeParser's support of Content-Length. +* Fixed MimeParser.ParseEntity() and MimeEntity.Load() to throw a FormatException if the + stream does not have properly formatted headers. (issue [#443](https://github.com/jstedfast/MimeKit/issues/443)) +* Added support for message/global. + +### MimeKit 2.0.6 (2018-08-04) + +* Added more bounds checking for parsing mailbox addresses to fix IndexOutOfRangeExceptions + given an incomplete address like "Name <". (issue [#421](https://github.com/jstedfast/MimeKit/issues/421)) +* Fixed support for parsing mbox files using Content-Length. +* Modified the TextPart.Text getter property to check for a UTF-16 BOM and use an appropriate + UTF-16 System.Text.Encoding if found instead of simply assuming UTF-8 and falling back to + iso-8859-1. (issue [#417](https://github.com/jstedfast/MimeKit/issues/417)) +* Minor optimizations. + +### MimeKit 2.0.5 (2018-07-07) + +* Make sure messages created from System.Net.Mail.MailMessages have a Date header. (MailKit issue [#710](https://github.com/jstedfast/MailKit/issues/710)) +* Allow developers to pass in their own SecureRandom when generating PGP key pairs. (issue [#404](https://github.com/jstedfast/MimeKit/issues/404)) +* Modified MemoryBlockStream to use a shared buffer pool to relieve pressure on the GC. (MailKit issue [#725](https://github.com/jstedfast/MailKit/issues/725)) + +### MimeKit 2.0.4 (2018-05-21) + +* The default value of the `CheckCertificateRevocation` property located on the + `BouncyCastleSecureMimeContext` has been changed to `false` due to privacy concerns noted + in the Efail document published in May of 2018. Clients that + wish to continue automatic downloads of S/MIME CRLs can manually set the property to `true`. +* Properly wrap long mailbox names with quoted phrases. +* Fixed parsing of header blocks that span across read boundaries. (issue [#395](https://github.com/jstedfast/MimeKit/issues/395)) +* Added FormatOptions.EnsureNewLine property (MailKit issue [#251](https://github.com/jstedfast/MailKit/issues/251)) +* Enable System.Net.Mail support for .NET Core 2.0. (issue [#393](https://github.com/jstedfast/MimeKit/issues/393)) + +### MimeKit 2.0.3 (2018-04-15) + +* Allow empty TextBody and HtmlBody properties for BodyBuilder. (issue [#391](https://github.com/jstedfast/MimeKit/issues/391)) +* Fixed BodyBuilder.Attachments.Add() to properly handle message/rfc822 attachments. +* Fixed HTML entity encoder logic when a surrogate pair is at the end of the input. (issue [#385](https://github.com/jstedfast/MimeKit/issues/385)) + +### MimeKit 2.0.2 (2018-03-18) + +* IDN encode/decode the local part of mailbox addresses as well. (MailKit issue [#649](https://github.com/jstedfast/MailKit/issues/649)) +* Added a record for .epub to the MimeTypes database. (issue [#376](https://github.com/jstedfast/MimeKit/issues/376)) +* Explicitly pass 'false' as the silent argument to SignedCms.ComputeSignature(). (issue [#374](https://github.com/jstedfast/MimeKit/issues/374)) +* Make sure the MimeParser does not hang if the last header line is truncated before CRLF. +* Don't use Encoder/DecoderExceptionFallbacks in the TNEF reader. (issue [#370](https://github.com/jstedfast/MimeKit/issues/370)) +* Provide a better error message when the cert within a pkcs12 cannot digital sign. (issue [#367](https://github.com/jstedfast/MimeKit/issues/367)) +* Fixed TemporarySecureMimeContext to key off the certificate's fingerprint. + +### MimeKit 2.0.1 (2018-01-06) * Improved the HTML parser logic to better handle a number of edge cases. * MimeKit will now automatically download CRLs based on the CRL Distribution Point @@ -17,7 +408,7 @@ specifying the symmetric key algorithm to use in generating the key pair. This defaults to AES-256, which is the same value used in older versions of MimeKit. -### MimeKit 2.0.0 +### MimeKit 2.0.0 (2017-12-22) * Added IDkimPublicKeyLocator.LookupPublicKeyAsync() and MimeMessage.VerifyAsync() to support asynchronous DNS lookups of DKIM public keys. @@ -33,17 +424,17 @@ * Renamed the MimePart.ContentObject property to MimePart.Content. * Dropped support for .NET 3.5 and .NET 4.0. -### MimeKit 1.22.0 +### MimeKit 1.22.0 (2017-11-24) -* Fixed a buffering bug in MimeParser's header parser. (issue #358) -* Set the TnefReader charset on extracted text/plain and text/html bodies. (issue #357) +* Fixed a buffering bug in MimeParser's header parser. (issue [#358](https://github.com/jstedfast/MimeKit/issues/358)) +* Set the TnefReader charset on extracted text/plain and text/html bodies. (issue [#357](https://github.com/jstedfast/MimeKit/issues/357)) * Added safeguard to protect against malformed nested group addresses which could cause a stack overflow in the parser. ParserOptions now has a way of limiting the recursive - depth of rfc822 group addresses using the MaxAddressGroupDepth property. (issue #355) + depth of rfc822 group addresses using the MaxAddressGroupDepth property. (issue [#355](https://github.com/jstedfast/MimeKit/issues/355)) * Fixed the S/MIME certificate database for .NETStandard by using GetFieldValue() instead - of GetBytes() which is not supported on .NETStandard. (issue #351) + of GetBytes() which is not supported on .NETStandard. (issue [#351](https://github.com/jstedfast/MimeKit/issues/351)) -### MimeKit 1.20.0 +### MimeKit 1.20.0 (2017-10-28) * Added async support for writing MimeMessage, MimeEntity, HeaderList and ContentObject. * Added async support for parsing MimeMessage, MimeEntity, and HeaderList. @@ -51,16 +442,16 @@ * Removed methods marked [Obsolete] (which have been marked obsolete for several years now). * Improved performance of writing messages by a small amount. * Fixed SecureMimeDigitalSignature to capture the signature digest algorithm used by the sending - client. (issue #341) + client. (issue [#341](https://github.com/jstedfast/MimeKit/issues/341)) * Fixed the S/MIME decoder to correctly determine the RC2 algorithm used by the sending client. - (issue #337) + (issue [#337](https://github.com/jstedfast/MimeKit/issues/337)) * Fixed a bug in BoundStream.Seek(). -### MimeKit 1.18.1 +### MimeKit 1.18.1 (2017-09-03) * Added CanSign() and CanEncrypt() methods to CryptographyContext for checking - whether or not a mailbox can be used for signing or be encrypted to. (issue #325) -* Automatically register the CodePagesEncodingProvider when running on .NETStandard. (issue #330) + whether or not a mailbox can be used for signing or be encrypted to. (issue [#325](https://github.com/jstedfast/MimeKit/issues/325)) +* Automatically register the CodePagesEncodingProvider when running on .NETStandard. (issue [#330](https://github.com/jstedfast/MimeKit/issues/330)) * Fixed MimeMessage.TextBody to return null when the top-level MIME part is a TextPart marked as an attachment. * Fixed the HtmlToHtml converter to suppress comments if the HtmlTagContext's SuppressInnerContent @@ -68,35 +459,35 @@ * Documented OpenPgpContext.GenerateKeyPair() which was added in 1.18.0. * Added OpenPgpContext.Delete() methods to delete public and secret keyrings. * Added OpenPgpContext.SignKey(). -* Remove "Version:" header from armored OpenPGP output. (issue #319) +* Remove "Version:" header from armored OpenPGP output. (issue [#319](https://github.com/jstedfast/MimeKit/issues/319)) -### MimeKit 1.18.0 +### MimeKit 1.18.0 (2017-08-07) -* Allow importing of known PGP keys (needed when re-importing keys after signing them). (issue #315) +* Allow importing of known PGP keys (needed when re-importing keys after signing them). (issue [#315](https://github.com/jstedfast/MimeKit/issues/315)) * Added APIs to enumerate public and secret PGP keys. * Added an OpenPgpDetectionFilter to detect OpenPGP blocks and their stream offsets. * Added a MimeMessage.WriteTo() overload that takes a bool headersOnly argument. * Pushed SecureMimeContext's EncryptionAlgorithm preferences down into CryptographyContext. * Updated GnuPGContext to load algorithm preferences from gpg.conf. * Fixed TemporarySecureMimeContext to use the fingerprint in the certificate lookup methods - when the MailboxAddress argument is a SecureMailboxAddress. (issue #322) -* Fall back to using the Subject Alternative Rfc822 Name if the SubjectEmailAddress fails. (issue #323) + when the MailboxAddress argument is a SecureMailboxAddress. (issue [#322](https://github.com/jstedfast/MimeKit/issues/322)) +* Fall back to using the Subject Alternative Rfc822 Name if the SubjectEmailAddress fails. (issue [#323](https://github.com/jstedfast/MimeKit/issues/323)) -### MimeKit 1.16.2 +### MimeKit 1.16.2 (2017-07-01) -* Fixed a bug in the MailMessage to MimeMessage conversion which corrupted the Subject string. (issue #306) +* Fixed a bug in the MailMessage to MimeMessage conversion which corrupted the Subject string. (issue [#306](https://github.com/jstedfast/MimeKit/issues/306)) * If no KeyUsage extension exists for an X509 certificate, assume no restrictions on key usage. * Throw an exception if there is a problem building an X509 certificate chain when verifying S/MIME signatures. -### MimeKit 1.16.1 +### MimeKit 1.16.1 (2017-05-05) * Fixed TextToHtml and FlowedToHtml's OutputHtmlFragment property to work. -* Fixed EncodeAddrspec and DecodeAddrspec to handle string.Empty. (issue #302) -* Allow string.Empty as a valid addrspec for MailboxAddress. (issue #302) -* Catch exceptions trying to import CRLs and Certs when verifying S/MIME signatures. (issue #304) +* Fixed EncodeAddrspec and DecodeAddrspec to handle string.Empty. (issue [#302](https://github.com/jstedfast/MimeKit/issues/302)) +* Allow string.Empty as a valid addrspec for MailboxAddress. (issue [#302](https://github.com/jstedfast/MimeKit/issues/302)) +* Catch exceptions trying to import CRLs and Certs when verifying S/MIME signatures. (issue [#304](https://github.com/jstedfast/MimeKit/issues/304)) -### MimeKit 1.16.0 +### MimeKit 1.16.0 (2017-04-21) * Added new ParserOptions option to allow local-only mailbox addresses (e.g. no @domain). * Improved address parser to interpret unquoted names containing commas in email addresses @@ -104,7 +495,7 @@ * Greatly improved the WindowsSecureMimeContext backend. * A number of fixes to bugs exposed by an ever-increasing set of unit tests (up to 87% coverage). -### MimeKit 1.14.0 +### MimeKit 1.14.0 (2017-04-09) * Added International Domain Name support for email addresses. * Added a work-around for mailers that didn't provide a disposition value in a @@ -113,14 +504,14 @@ header. * Added automatic key retrieval functionality for the GnuPG crypto context. * Added a virtual DigestSigner property to DkimSigner so that consumers can hook into services - such as Azure. (issue #296) + such as Azure. (issue [#296](https://github.com/jstedfast/MimeKit/issues/296)) * Fixed a bug in the MimeFilterBase.SaveRemainingInput() logic. * Preserve munged From-lines at the start of message/rfc822 parts. * Map code page 50220 to iso-2022-jp. * Format Reply-To and Sender headers as address headers when using Header.SetValue(). -* Fixed MimeMessage.CreateFromMailMessage() to set MimeVersion. (issue #290) +* Fixed MimeMessage.CreateFromMailMessage() to set MimeVersion. (issue [#290](https://github.com/jstedfast/MimeKit/issues/290)) -### MimeKit 1.12.0 +### MimeKit 1.12.0 (2017-03-12) * Added new DKIM MimeMessage.Sign() methods that take an IList of header field names to sign. @@ -130,43 +521,43 @@ mailbox and group addresses. * Added support for CryptographyContext factories by adding new Register() methods that take function callbacks that return a SecureMimeContext or OpenPgpContext. Thanks to - Christoph Enzmann for this feature. (issue #283) + Christoph Enzmann for this feature. (issue [#283](https://github.com/jstedfast/MimeKit/issues/283)) * Fixed DefaultSecureMimeContext..cctor() to not call Directory.CreateDirectory() on the default database directory. Instead, let the .ctor() create it instead if and when - an instance of the DefaultSecureMimeContext is created. (issue #285) + an instance of the DefaultSecureMimeContext is created. (issue [#285](https://github.com/jstedfast/MimeKit/issues/285)) * Store DBNull in S/MIME SQL backends for null values (SQLite handles `null` but - databases such as Postgres do not). (issue #286) + databases such as Postgres do not). (issue [#286](https://github.com/jstedfast/MimeKit/issues/286)) -### MimeKit 1.10.1 +### MimeKit 1.10.1 (2017-01-28) * Fixed the Content-Type and Content-Disposition parameter parser to remove trailing lwsp from - unquoted parameter values. (issue #278) + unquoted parameter values. (issue [#278](https://github.com/jstedfast/MimeKit/issues/278)) * Fixed MimePart.WriteTo() to not necessarily force the content to end with a new-line. -### MimeKit 1.10.0 +### MimeKit 1.10.0 (2016-10-31) * Fixed OpenPgpContext.Verify() to throw FormatException if no data packets found. -* Added new MailboxAddress constructors that do not take a 'name' argument. (issue #267) -* Added an HtmlToHtml.FilterComments property to remove comments. (issue #271) +* Added new MailboxAddress constructors that do not take a 'name' argument. (issue [#267](https://github.com/jstedfast/MimeKit/issues/267)) +* Added an HtmlToHtml.FilterComments property to remove comments. (issue [#271](https://github.com/jstedfast/MimeKit/issues/271)) * Modified address parser to handle invalid addresses like "user@example.com ". -### MimeKit 1.8.0 +### MimeKit 1.8.0 (2016-09-25) * Improved parsing of malformed mailbox addresses. * Added DecompressTo() and DecryptTo() methods to SecureMimeContext. * Fixed MessagePartial.Split(). -### MimeKit 1.6.0 +### MimeKit 1.6.0 (2016-09-11) * Use RandomNumberGenerator.Create() for .NET Core instead of System.Random when generating multipart boundaries. -### MimeKit 1.4.2 +### MimeKit 1.4.2 (2016-08-14) * Strong-name the .NET Core assemblies. -* Fixed logic for selecting certificates from the Windows X.509 Store. (issue #262) +* Fixed logic for selecting certificates from the Windows X.509 Store. (issue [#262](https://github.com/jstedfast/MimeKit/issues/262)) -### MimeKit 1.4.1 +### MimeKit 1.4.1 (2016-07-17) * Fixed QuotedPrintableDecoder to handle soft breaks that fall on a buffer boundary. * Fixed MimeMessage.WriteTo() to properly respect the FormatOptions when writing the @@ -176,38 +567,38 @@ * Added new TextPart .ctor that takes a TextFormat argument so that developers that don't understand mime-types can more easily intuit what that argument should be. -### MimeKit 1.4.0 +### MimeKit 1.4.0 (2016-07-01) * Added support for .NET Core 1.0 * Changed the default value of FormatOptions.AllowMixedHeaderCharsets to false. -* Added a new DkimSigner .ctor that takes a stream of key data. (issue #255) +* Added a new DkimSigner .ctor that takes a stream of key data. (issue [#255](https://github.com/jstedfast/MimeKit/issues/255)) -### MimeKit 1.2.25 +### MimeKit 1.2.25 (2016-06-16) -* Fixed parsing bugs in MessageDeliveryStatus.StatusGroups. (issue #253) -* Fixed MimeParser.ParseHeaders() to handle header blocks that do not end with a blank line. (issue #250) +* Fixed parsing bugs in MessageDeliveryStatus.StatusGroups. (issue [#253](https://github.com/jstedfast/MimeKit/issues/253)) +* Fixed MimeParser.ParseHeaders() to handle header blocks that do not end with a blank line. (issue [#250](https://github.com/jstedfast/MimeKit/issues/250)) * Fixed the MailboxAddress parser to handle whitespace between '<' and the addr-spec. -* Fixed TemporarySecureMimeContext to handle certificates with null email addresses. (issue #252) +* Fixed TemporarySecureMimeContext to handle certificates with null email addresses. (issue [#252](https://github.com/jstedfast/MimeKit/issues/252)) -### MimeKit 1.2.24 +### MimeKit 1.2.24 (2016-05-22) -* Modified MimeMessage .ctor to not add an empty To: header by default. (issue #241) +* Modified MimeMessage .ctor to not add an empty To: header by default. (issue [#241](https://github.com/jstedfast/MimeKit/issues/241)) * Modified MimeMessage to remove address headers when all addresses in that field are removed. * Properly apply SecurityCriticalAttribute to GetObjectData() on custom Exceptions. * Fixed TnefPropertyReader to convert APPTIME values into DateTimes from the OLE Automation - Date format. (issue #245) + Date format. (issue [#245](https://github.com/jstedfast/MimeKit/issues/245)) -### MimeKit 1.2.23 +### MimeKit 1.2.23 (2016-05-07) -* Modified ParamaterList.TryParse() to handle quoted rfc2231-encoded param values. (issue #239) +* Modified ParamaterList.TryParse() to handle quoted rfc2231-encoded param values. (issue [#239](https://github.com/jstedfast/MimeKit/issues/239)) * Updated to reference BouncyCastle via NuGet packages rather than bundling the assemblies. * Fixed MimeParser to set a multipart's raw epilogue to null instead of an empty byte array. Fixes some issues with digital signature verification (as well as DKIM verification). * Added an HtmlWriter.WriteText() override with Console.WriteLine() style params. * Added convenience MimeMessage property for the X-Priority header. -* Fixed MimeMessage.ConvertFromMailMessage() to use appropriate MimeEntity subclasses. (issue #232) +* Fixed MimeMessage.ConvertFromMailMessage() to use appropriate MimeEntity subclasses. (issue [#232](https://github.com/jstedfast/MimeKit/issues/232)) -### MimeKit 1.2.22 +### MimeKit 1.2.22 (2016-02-28) * Added a new SecureMimeContext.Verify() overload that returns the extracted content stream. * Exposed the SecureMimeContext.GetDigitalSignatures() method as protected, allowing custom @@ -221,22 +612,22 @@ file or stream. * Fixed UrlScanner to properly deal with IPv6 literals in email addresses. -### MimeKit 1.2.21 +### MimeKit 1.2.21 (2016-02-13) * Added a MultipartReport class for multipart/report. -* Fixed serialization for embedded message/* parts. (issue #228) +* Fixed serialization for embedded message/* parts. (issue [#228](https://github.com/jstedfast/MimeKit/issues/228)) * Fixed MimeMessage.WriteTo() to only make sure that the stream ends with a newline if it - wasn't parsed. (issue #227) + wasn't parsed. (issue [#227](https://github.com/jstedfast/MimeKit/issues/227)) * Fixed MimeMessage to only set a MIME-Version if the message was not produced by the parser. * Ignore timezones outside the range of -1200 to +1400. * Added InternetAddress.Clone() to allow addresses to be cloned. * Properly serialize message/rfc822 parts that contain an mbox marker. -* Fixed MimeMessage.DkimSign() to not enforce 7bit encoding of the body. (issue #224) +* Fixed MimeMessage.DkimSign() to not enforce 7bit encoding of the body. (issue [#224](https://github.com/jstedfast/MimeKit/issues/224)) * Fixed ParameterList.IndexOf(string) to be case insensitive. -### MimeKit 1.2.20 +### MimeKit 1.2.20 (2016-01-24) -* Fixed serialization of mime parts with empty content. (issue #221) +* Fixed serialization of mime parts with empty content. (issue [#221](https://github.com/jstedfast/MimeKit/issues/221)) * Fixed a bug in the TnefPropertyReader that would break when not all properties were read by the consumer of the API. * Fixed the InternetAddress parser to throw a more informative error when parsing broken @@ -247,7 +638,7 @@ * Fixed HtmlUtils.HtmlAttributeEncode() to properly encode non-ascii characters as entities. * Fixed HtmlUtils.HtmlEncode() to properly encode non-ascii characters as entities. * Fixed MimeParser to track whether or not each multipart had an end boundary so that - when they get reserialized, they match the original. (issue #218) + when they get reserialized, they match the original. (issue [#218](https://github.com/jstedfast/MimeKit/issues/218)) * Implemented an optimized OrdinalIgnoreCase string comparer which improves the performance of the MimeParser slightly. * Fixed QuotedPrintableDecoder to properly handle "==" sequences. @@ -256,100 +647,100 @@ * Fixed MimeParser to trim the CR from the mbox From marker. * Fixed SqlCertificateDatabase to properly chain Dispose. -### MimeKit 1.2.19 +### MimeKit 1.2.19 (2016-01-01) -* Handle illegal Content-Id headers that do not enclose their values in <>'s. (issue #215) -* Fixed reserialization of MimeParts with empty content. (issue #213) +* Handle illegal Content-Id headers that do not enclose their values in <>'s. (issue [#215](https://github.com/jstedfast/MimeKit/issues/215)) +* Fixed reserialization of MimeParts with empty content. (issue [#213](https://github.com/jstedfast/MimeKit/issues/213)) * Improved parsing logic for malformed Content-Type headers. * Fixed HtmlTokenizer to work properly when some closing tags were not lowercase. * Bumped Bouncy Castle to v1.8.1. -### MimeKit 1.2.18 +### MimeKit 1.2.18 (2015-12-16) * Removed unimplemented TNEF APIs. * Use DateTime.UtcNow for S/MIME certificate validity checks. * Added ToString() methods on ContentType/Disposition that take FormatOptions. -* Added a new ToString() method to InternetAddress that takes a FormatOptions. (issue #208) -* Added a MimeEntity.WriteTo() method that takes a bool contentOnly parameter. (issue #207) +* Added a new ToString() method to InternetAddress that takes a FormatOptions. (issue [#208](https://github.com/jstedfast/MimeKit/issues/208)) +* Added a MimeEntity.WriteTo() method that takes a bool contentOnly parameter. (issue [#207](https://github.com/jstedfast/MimeKit/issues/207)) * Added support for encoding parameter values using rfc2047 encoded-words instead of the standard rfc2231 encoding. * Fixed SecureMailboxAddress's Fingerprint property to work with both the PGP key ID - *and* the fingerprint. Previously only worked with the PGP key id. (issue #203) -* Added GroupAddress.Parse() and MailboxAddress.Parse() methods. (issue #197) -* Set a default filename when generating application/pgp-signature parts. (issue #195) + *and* the fingerprint. Previously only worked with the PGP key id. (issue [#203](https://github.com/jstedfast/MimeKit/issues/203)) +* Added GroupAddress.Parse() and MailboxAddress.Parse() methods. (issue [#197](https://github.com/jstedfast/MimeKit/issues/197)) +* Set a default filename when generating application/pgp-signature parts. (issue [#195](https://github.com/jstedfast/MimeKit/issues/195)) -### MimeKit 1.2.17 +### MimeKit 1.2.17 (2015-12-05) * Fixed DkimRelaxedBodyFilter to properly handle CRLF split across buffers. * Added ContentType.IsMimeType method to replace CongtentType.Matches. * Added S/MIME, PGP and DKIM support to the PCL and WindowsUniversal versions of MimeKit. -* Fixed PGP key expiration calculation when encrypting. (issue #194) +* Fixed PGP key expiration calculation when encrypting. (issue [#194](https://github.com/jstedfast/MimeKit/issues/194)) -### MimeKit 1.2.16 +### MimeKit 1.2.16 (2015-11-29) -* Fixed relaxed body canonicalization logic for DKIM signatures. (issue #190) +* Fixed relaxed body canonicalization logic for DKIM signatures. (issue [#190](https://github.com/jstedfast/MimeKit/issues/190)) -### MimeKit 1.2.15 +### MimeKit 1.2.15 (2015-11-22) * Fixed the Date parser to catch exceptions thrown by the DateTimeOffset .ctor if any of the fields are out of range. -* Fixed logic for trimming trailing blank lines for the DKIM relaxed body algorithm. (issue #187) -* Fixed DKIM body filters to reserve extra space in the output buffer. (issue #188) +* Fixed logic for trimming trailing blank lines for the DKIM relaxed body algorithm. (issue [#187](https://github.com/jstedfast/MimeKit/issues/187)) +* Fixed DKIM body filters to reserve extra space in the output buffer. (issue [#188](https://github.com/jstedfast/MimeKit/issues/188)) * Allow specifying a charset encoding for each Content-Type/Disposition parameter. -### MimeKit 1.2.14 +### MimeKit 1.2.14 (2015-10-18) * Fixed DKIM-Signature signing logic to use a UTC-based timestamp value rather than a - timestamp based on the local-time. (issue #180) + timestamp based on the local-time. (issue [#180](https://github.com/jstedfast/MimeKit/issues/180)) * Fixed Multipart epilogue parsing and serialization logic to make sure that serializing a multipart is properly byte-for-byte identical to the original text. This fixes a corner-case that affected all types of digital signatures (DKIM, PGP, and S/MIME) - spanning across nested multiparts. (issue #181) + spanning across nested multiparts. (issue [#181](https://github.com/jstedfast/MimeKit/issues/181)) * Fixed MimeMessage.WriteTo() to ensure that the output stream always ends with a new-line. -### MimeKit 1.2.13 +### MimeKit 1.2.13 (2015-10-11) * Modified Base64Encoder's .ctor to allow specifying a maxLineLength. -* Fixed DKIM signing logic for multipart/alternative messages. (issue #178) +* Fixed DKIM signing logic for multipart/alternative messages. (issue [#178](https://github.com/jstedfast/MimeKit/issues/178)) -### MimeKit 1.2.12 +### MimeKit 1.2.12 (2015-09-20) * Prevent infinite loop when flushing CharsetFilter when there is no input data left. -### MimeKit 1.2.11 +### MimeKit 1.2.11 (2015-09-06) -* Fixed an IndexOutOfRangeException bug in the TextToHTML converter logic. (issue #165) +* Fixed an IndexOutOfRangeException bug in the TextToHTML converter logic. (issue [#165](https://github.com/jstedfast/MimeKit/issues/165)) * Fixed the DKIM-Signature verification logic to be more lenient in parsing DKIM-Signature - headers. (issue #166) + headers. (issue [#166](https://github.com/jstedfast/MimeKit/issues/166)) * Fixed the DKIM-Signature verification logic to error-out if the h= parameter does not - include the From header. (issue #167) + include the From header. (issue [#167](https://github.com/jstedfast/MimeKit/issues/167)) * Fixed the DKIM-Signature verification logic to make sure that the domain-name in the i= - param matches (or is a subdomain of) the d= value. (issue #169) + param matches (or is a subdomain of) the d= value. (issue [#169](https://github.com/jstedfast/MimeKit/issues/169)) * Fixed the CharsetFilter to avoid calling Convert() on empty input. * Fixed logic for canonicalizing header values using the relaxed DKIM algorithm. - (issue #171) + (issue [#171](https://github.com/jstedfast/MimeKit/issues/171)) * Fixed AttachmentCollection to mark embedded parts as inline instead of attachment. * Fixed the DKIM-Signature logic (both signing and verifying) to properly canonicalize the - body content. (issue #172) + body content. (issue [#172](https://github.com/jstedfast/MimeKit/issues/172)) -### MimeKit 1.2.10 +### MimeKit 1.2.10 (2015-08-16) * Added public Stream property to IContentObject. * Implemented a better fix for illegal unquoted multi-line Content-Type and - Content-Disposition parameter values. (issue #159) + Content-Disposition parameter values. (issue [#159](https://github.com/jstedfast/MimeKit/issues/159)) * Fixed the UrlScanner to properly handle "ftp." at the very end of the message text. - (issue #161) + (issue [#161](https://github.com/jstedfast/MimeKit/issues/161)) * Fixed charset handling logic to not override charset aliases already in the cache. -### MimeKit 1.2.9 +### MimeKit 1.2.9 (2015-08-08) -* Fixed WriteTo(string fileName) methods to overwrite the existing file. (issue #154) +* Fixed WriteTo(string fileName) methods to overwrite the existing file. (issue [#154](https://github.com/jstedfast/MimeKit/issues/154)) * Updated InternetAddressList to implement IComparable. * Fixed DKIM-Signature generation and verification. * Added support for Message-Id headers that do not properly use encapsulate the value with angle brackets. -### MimeKit 1.2.8 +### MimeKit 1.2.8 (2015-07-19) * Added a new MessageDeliveryStatus MimePart subclass to make message/delivery-status MIME parts easier to deal with. @@ -359,52 +750,52 @@ * Fixed MimeParser to handle a message stream of just "\r\n". * Add a leading space in the Sender and Resent-Sender header values. -### MimeKit 1.2.7 +### MimeKit 1.2.7 (2015-07-05) * Fixed encoding GroupAddress with multiple mailbox addresses. * Fixed MessageIdList to be less strict in what it will accept. * Fixed logic for DKIM-Signature header folding. -### MimeKit 1.2.6 +### MimeKit 1.2.6 (2015-06-25) * Fixed a bug in the HTML tokenizer to handle some weird HTML created by Outlook 15.0. -* Added CmsRecipient .ctor overloads that accept X509Certificate2. (issue #149) +* Added CmsRecipient .ctor overloads that accept X509Certificate2. (issue [#149](https://github.com/jstedfast/MimeKit/issues/149)) -### MimeKit 1.2.5 +### MimeKit 1.2.5 (2015-06-22) * Changed BodyParts and Attachments to be IEnumerable - - WARNING! This is an API change! (issue #148) + WARNING! This is an API change! (issue [#148](https://github.com/jstedfast/MimeKit/issues/148)) * Moved the IsAttachment property from MimePart down into MimeEntity. * Added MimeMessage.Importance and MimeMessage.Priority properties. * Vastly improved the HtmlToHtml text converter with a w3 compliant HTML tokenizer. -### MimeKit 1.2.4 +### MimeKit 1.2.4 (2015-06-14) * Added support for generating and verifying DKIM-Signature headers. * Improved error handling for Encoding.GetEncoding() in CharsetFilter constructors. * Fixed buffering in the HTML parser. * Fixed Windows and Temporary S/MIME contexts to use case-insensitive address - comparisons like the other backends do. (issue #146). + comparisons like the other backends do. (issue [#146](https://github.com/jstedfast/MimeKit/issues/146)). * Added HeaderList.LastIndexOf() convenience methods. * Added a new Prepare() method to prepare a message or entity for transport and/or signing (used by MultipartSigned and MailKit.SmtpClient) to reduce duplicated code. * Fixed FilteredStream.Flush() to flush filters even when no data has been written. -* Fixed the ChainedStream.Read() logic. (issue #143) +* Fixed the ChainedStream.Read() logic. (issue [#143](https://github.com/jstedfast/MimeKit/issues/143)) * Added EncoderFilter and DecoderFilter.Create() overloads that take an encoding name (string). * HeaderList.WriteTo() now adds a blank line to the end of the output instead of leaving this up to the MimeEntity.WriteTo() method. This was needed for the DKIM-Signatures feature. -### MimeKit 1.2.3 +### MimeKit 1.2.3 (2015-06-01) * Fixed TextToFlowed logic that stripped trailing spaces. * Switched to PCL Profile78 to support Xamarin.Forms. -### MimeKit 1.2.2 +### MimeKit 1.2.2 (2015-05-31) * Added a MultipartAlternative class which adds some useful convenience methods and properties for use with the multipart/alternative mime-type. @@ -417,7 +808,7 @@ * Added a MimeVisitor class that implements the visitor pattern for visiting MIME nodes. -### MimeKit 1.2.1 +### MimeKit 1.2.1 (2015-05-25) * Added a Format property to ContentType. * Added a TryGetValue() method to ParameterList. @@ -425,21 +816,21 @@ * Fixed the HtmlToHtml converter to properly handle HTML text that begins with leading text data. * Fixed MimeParser.ParseHeaders() to handle input that does not end with a - blank line. (issue #142) + blank line. (issue [#142](https://github.com/jstedfast/MimeKit/issues/142)) * Renamed MimeEntityConstructorInfo to MimeEntityConstructorArgs. * Modified the MimeParser to use TextPart to represent application/rtf. -### MimeKit 1.2.0 +### MimeKit 1.2.0 (2015-05-24) -* Force the use of the rfc2047 "B" encoding for ISO-2022-JP. (issue #139) +* Force the use of the rfc2047 "B" encoding for ISO-2022-JP. (issue [#139](https://github.com/jstedfast/MimeKit/issues/139)) * Added some text converters to convert between various text formats including format=flowed and HTML. -### MimeKit 1.0.15 +### MimeKit 1.0.15 (2015-05-12) -* Fixed MimeMessage.WriteTo() to be thread-safe. (issue #138) +* Fixed MimeMessage.WriteTo() to be thread-safe. (issue [#138](https://github.com/jstedfast/MimeKit/issues/138)) -### MimeKit 1.0.14 +### MimeKit 1.0.14 (2015-05-09) * Added support for .NET 3.5. * Added a convenience CmsSigner .ctor that takes an X509Certificate2 argument. @@ -447,70 +838,70 @@ * Fixed TextPart.GetText() to protect against NullReferenceExceptions if the ContentObject is null. * Fixed MimeFilterBase.EnsureOutputSize() to initialize OutputBuffer if it is - null. Prevents NullReferenceExceptions in obscure corner cases. (issue #135) + null. Prevents NullReferenceExceptions in obscure corner cases. (issue [#135](https://github.com/jstedfast/MimeKit/issues/135)) * Added a TnefAttachFlags enum which is used to determine if image attachments in MS-TNEF data are meant to have a Content-Disposition of "inline" when - extracted as MIME attachments. (issue #129) + extracted as MIME attachments. (issue [#129](https://github.com/jstedfast/MimeKit/issues/129)) * Fixed TnefPart.ConvertToMessage() and ExtractAttachments() to use the PR_ATTACH_MIME_TAG property to determine the intended mime-type for extracted attachments. * Catch DecoderFallbackExceptions in MimeMessage.ToString() and fall back to - Latin1. (issue #137) + Latin1. (issue [#137](https://github.com/jstedfast/MimeKit/issues/137)) -### MimeKit 1.0.13 +### MimeKit 1.0.13 (2015-04-11) * Added a work-around for a bug in Thunderbird's multipart/related implementation. - (issue #124) + (issue [#124](https://github.com/jstedfast/MimeKit/issues/124)) * Improved MimeMessage.CreateFromMailMessage() a bit more to avoid creating empty From, Reply-To, To, Cc and/or Bcc headers. * Modified the HeaderIdExtensions to only be available for the HeaderId enum values. -### MimeKit 1.0.12 +### MimeKit 1.0.12 (2015-03-29) * Modified InternetAddressList.Equals() to return true if the lists contain the same - addresses even if they are in different orders. (issue #118) + addresses even if they are in different orders. (issue [#118](https://github.com/jstedfast/MimeKit/issues/118)) * Allow S/MIME certificates with the NonRepudiation key usage to be used for signing. - (issue #119) + (issue [#119](https://github.com/jstedfast/MimeKit/issues/119)) * Don't change the Content-Transfer-Encoding of MIME parts being encrypted as part of - a multipart/encrypted. (issue #122) -* Fixed logic to decide if a PGP secret key is expired. (issue #120) + a multipart/encrypted. (issue [#122](https://github.com/jstedfast/MimeKit/issues/122)) +* Fixed logic to decide if a PGP secret key is expired. (issue [#120](https://github.com/jstedfast/MimeKit/issues/120)) * Added support for SecureMailboxAddresses to OpenPgpContext to allow key lookups by fingerprints instead of email addresses. -### MimeKit 1.0.11 +### MimeKit 1.0.11 (2015-03-21) * Added the ContentDisposition.FormData string constant. * Allow the ContentDisposition.Disposition property to be set to values other than - "attachment" and "inline". (issue #112) + "attachment" and "inline". (issue [#112](https://github.com/jstedfast/MimeKit/issues/112)) * Shortened the length of the local-part of auto-generated Message-Ids. * Fixed MimeMessage.CreateFromMailMessage() to not duplicate From/To/Cc/etc addresses if the System.Net.Mail.MailMessage has been sent via System.Net.Mail.SmtpClient - prior to calling MimeMessage.CreateFromMailMessage(). (issue #115) + prior to calling MimeMessage.CreateFromMailMessage(). (issue [#115](https://github.com/jstedfast/MimeKit/issues/115)) * When parsing S/MIME digital signatures, don't import the full certificate chain. - (issue #110) + (issue [#110](https://github.com/jstedfast/MimeKit/issues/110)) * Added immutability-friendly .ctor to MimeMessage for use with languages such as F#. - (issue #116) + (issue [#116](https://github.com/jstedfast/MimeKit/issues/116)) -### MimeKit 1.0.10 +### MimeKit 1.0.10 (2015-03-14) * Ignore semi-colons in Content-Transfer-Encoding headers to work around broken mailers. * Added ParserOptions.ParameterComplianceMode (defaults to RfcComoplianceMode.Loose) which works around unquoted parameter values in Content-Type and Content-Disposition - headers. (issue #106) + headers. (issue [#106](https://github.com/jstedfast/MimeKit/issues/106)) * Modified the MimeParser to handle whitespace between header field names and the ':'. * Probe to make sure that various System.Text.Encodings are available before adding aliases for them (some may not be available depending on the platform). * Added a MimePart.GetBestEncoding() overload that takes a maxLineLength argument. * Modified MultipartSigned to use 78 characters as the max line length rather than 998 - characters. (issue #107) + characters. (issue [#107](https://github.com/jstedfast/MimeKit/issues/107)) -### MimeKit 1.0.9 +### MimeKit 1.0.9 (2015-03-08) * Added a new MessageDispositionNotification MimePart subclass to represent message/disposition-notification parts. * Fixed the TNEF parser to gracefully deal with duplicate attachment properties. -### MimeKit 1.0.8 +### MimeKit 1.0.8 (2015-03-02) * Modified the parser to accept Message-Id values without a domain (i.e. ""). * Fixed a NullReferenceException in MimeMessage.BodyParts in cases where a MessagePart @@ -520,19 +911,19 @@ * Renamed MimeUtils.TryParseVersion() to MimeUtils.TryParse() (the old API still exists but has been marked [Obsolete]). * Fixed S/MIME support to gracefully deal with badly formatted signature timestamps - which incrorectly use leap seconds. (issue #103) + which incrorectly use leap seconds. (issue [#103](https://github.com/jstedfast/MimeKit/issues/103)) -### MimeKit 1.0.7 +### MimeKit 1.0.7 (2015-02-17) * Fixed TnefPropertyReader.GetEmbeddedMessageReader() to skip the Guid. * When decrypting PGP data, iterate over all encrypted packets to find one that can be decrypted (i.e. the private key exists in the user's keychain). * Updated WindowsSecureMimeContext to respect SecureMailboxAddresses like the - other backends. (issue #100) + other backends. (issue [#100](https://github.com/jstedfast/MimeKit/issues/100)) * Added a Pkcs9SigningTime attribute to the CmsSigner for WindowsSecureMimeContext. - (issue #101) + (issue [#101](https://github.com/jstedfast/MimeKit/issues/101)) -### MimeKit 1.0.6 +### MimeKit 1.0.6 (2015-01-18) * Vastly improved MS-TNEF support. In addition to being fixed to properly extract the AttachData property of an Attachment attribute, more metadata is captured @@ -544,38 +935,38 @@ Note: If you are not yet ready to port your iOS application to the Unified API, you will need to stick with the 1.0.5 release. The Classic MonoTouch API is no longer supported. -### MimeKit 1.0.5 +### MimeKit 1.0.5 (2015-01-10) * Fixed out-of-memory error when encoding some long non-ASCII parameter values in Content-Type and Content-Disposition headers. -### MimeKit 1.0.4 +### MimeKit 1.0.4 (2015-01-08) * Added workaround for msg-id tokens with multiple domains (e.g. id@domain1@domain2). * Added convenience methods to Header to allow the use of charset strings. * Added more HeaderList.Replace() method overloads for convenience. * Added a FormatOptions property to disallow the use of mixed charsets when - encoding headers (issue #139). + encoding headers (issue [#139](https://github.com/jstedfast/MimeKit/issues/139)). -### MimeKit 1.0.3 +### MimeKit 1.0.3 (2014-12-13) -* Improved MimeMessage.TextBody and MimeMessage.HtmlBody logic. (issue #87) +* Improved MimeMessage.TextBody and MimeMessage.HtmlBody logic. (issue [#87](https://github.com/jstedfast/MimeKit/issues/87)) * Added new overrides of TextPart.GetText() and SetText() methods that take a charset string argument instead of a System.Text.Encoding. * Fixed charset fallback logic to work properly (it incorrectly assumed that by default, Encoding.UTF8.GetString() would throw an exception when it - encountered illegal byte sequences). (issue #88) + encountered illegal byte sequences). (issue [#88](https://github.com/jstedfast/MimeKit/issues/88)) * Fixed S/MIME logic for finding X.509 certificates to use for encipherment. - (issue #89) + (issue [#89](https://github.com/jstedfast/MimeKit/issues/89)) -### MimeKit 1.0.2 +### MimeKit 1.0.2 (2014-12-05) * Fixed MimeMessage.HtmlBody and MimeMessage.TextBody to properly handle nested multipart/alternatives (only generated by automated mailers). -### MimeKit 1.0.1 +### MimeKit 1.0.1 (2014-11-23) * Added MimeMessage.HtmlBody and MimeMessage.TextBody convenience properties. * Added TextPart.IsPlain and TextPart.IsHtml convenience properties. diff --git a/TODO.md b/TODO.md index 58ee18df41..a8f4da4219 100644 --- a/TODO.md +++ b/TODO.md @@ -4,22 +4,14 @@ * It would be nice to make DKIM support not depend on BouncyCastle at all so that DKIM support could be added to MimeKitLite. See: https://github.com/jstedfast/MimeKit/pull/296#issuecomment-355656935 - * Replace the DkimSigner.DigestSigner property with a method called - CreateSigningContext() or some such that returns an IDisposable replacement - for ISigner. - * The returned context should be IDisposable because System.Security-based - implementations need to be able to dispose the RSACryptoServiceProvider. - * This would also help facilitate dropping the dependency on BouncyCastle - since we could create a new IDkimSigningContext interface to replace the - use of ISigner. - * Or maybe DkimSigner could *be* the signing context instead of having a - CreateSigningContext() method? * If we had a nice DNS library that supported async/await, we could drop the IDkimPublicKeyLocator interface or at least provide a default implementation. Is it time for me to write DnsKit?? * S/MIME * BouncyCastleSecureMimeContext * Add support for downloading CRLs via FTP? Is this needed or at all common? + * Add a RECORDVERSION table column to the SQL database so we can add columns + in the future and work around gaps in the row data? ### Pie-in-the-sky Ideas diff --git a/UnitTests/ArgumentExceptionTests.cs b/UnitTests/ArgumentExceptionTests.cs index 51523faccf..a09ae6b269 100644 --- a/UnitTests/ArgumentExceptionTests.cs +++ b/UnitTests/ArgumentExceptionTests.cs @@ -1,9 +1,9 @@ -// +// // ArgumentExceptionTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -233,6 +233,17 @@ public void TestParseArguments () AssertParseArguments (typeof (MimeUtils)); } + [Test] + public void TestBufferPoolArguments () + { + Assert.Throws (() => new BufferPool (-1, 16)); + Assert.Throws (() => new BufferPool (1024, -1)); + + var pool = new BufferPool (16, 2); + Assert.Throws (() => pool.Return (null)); + Assert.Throws (() => pool.Return (new byte[8])); + } + static void AssertStreamArguments (Stream stream) { var buffer = new byte[1024]; @@ -259,30 +270,30 @@ static void AssertStreamArguments (Stream stream) "{0}.Read() does not throw an ArgumentOutOfRangeException when count > buffer length.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); - ex = Assert.Throws (async () => await stream.ReadAsync (null, 0, 0), + ex = Assert.ThrowsAsync (async () => await stream.ReadAsync (null, 0, 0), "{0}.ReadAsync() does not throw an ArgumentNullException when buffer is null.", stream.GetType ().Name); Assert.AreEqual ("buffer", ex.ParamName); - ex = Assert.Throws (async () => await stream.ReadAsync (buffer, -1, 0), + ex = Assert.ThrowsAsync (async () => await stream.ReadAsync (buffer, -1, 0), "{0}.ReadAsync() does not throw an ArgumentOutOfRangeException when offset is -1.", stream.GetType ().Name); Assert.AreEqual ("offset", ex.ParamName); - ex = Assert.Throws (async () => await stream.ReadAsync (buffer, buffer.Length + 1, 0), + ex = Assert.ThrowsAsync (async () => await stream.ReadAsync (buffer, buffer.Length + 1, 0), "{0}.ReadAsync() does not throw an ArgumentOutOfRangeException when offset > buffer length.", stream.GetType ().Name); Assert.AreEqual ("offset", ex.ParamName); - ex = Assert.Throws (async () => await stream.ReadAsync (buffer, 0, -1), + ex = Assert.ThrowsAsync (async () => await stream.ReadAsync (buffer, 0, -1), "{0}.ReadAsync() does not throw an ArgumentOutOfRangeException when count is -1.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); - ex = Assert.Throws (async () => await stream.ReadAsync (buffer, 0, buffer.Length + 1), + ex = Assert.ThrowsAsync (async () => await stream.ReadAsync (buffer, 0, buffer.Length + 1), "{0}.ReadAsync() does not throw an ArgumentOutOfRangeException when count > buffer length.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); } else { Assert.Throws (() => stream.Read (buffer, 0, buffer.Length), "{0}.Read() does not throw a NotSupportedException when CanRead is false.", stream.GetType ().Name); - Assert.Throws (async () => await stream.ReadAsync (buffer, 0, buffer.Length), + Assert.ThrowsAsync (async () => await stream.ReadAsync (buffer, 0, buffer.Length), "{0}.ReadAsync() does not throw a NotSupportedException when CanRead is false.", stream.GetType ().Name); } @@ -307,30 +318,30 @@ static void AssertStreamArguments (Stream stream) "{0}.Write() does not throw an ArgumentOutOfRangeException when count > buffer length.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); - ex = Assert.Throws (async () => await stream.WriteAsync (null, 0, 0), + ex = Assert.ThrowsAsync (async () => await stream.WriteAsync (null, 0, 0), "{0}.WriteAsync() does not throw an ArgumentNullException when buffer is null.", stream.GetType ().Name); Assert.AreEqual ("buffer", ex.ParamName); - ex = Assert.Throws (async () => await stream.WriteAsync (buffer, -1, 0), + ex = Assert.ThrowsAsync (async () => await stream.WriteAsync (buffer, -1, 0), "{0}.WriteAsync() does not throw an ArgumentOutOfRangeException when offset is -1.", stream.GetType ().Name); Assert.AreEqual ("offset", ex.ParamName); - ex = Assert.Throws (async () => await stream.WriteAsync (buffer, buffer.Length + 1, 0), + ex = Assert.ThrowsAsync (async () => await stream.WriteAsync (buffer, buffer.Length + 1, 0), "{0}.WriteAsync() does not throw an ArgumentOutOfRangeException when offset > buffer length.", stream.GetType ().Name); Assert.AreEqual ("offset", ex.ParamName); - ex = Assert.Throws (async () => await stream.WriteAsync (buffer, 0, -1), + ex = Assert.ThrowsAsync (async () => await stream.WriteAsync (buffer, 0, -1), "{0}.WriteAsync() does not throw an ArgumentOutOfRangeException when count is -1.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); - ex = Assert.Throws (async () => await stream.WriteAsync (buffer, 0, buffer.Length + 1), + ex = Assert.ThrowsAsync (async () => await stream.WriteAsync (buffer, 0, buffer.Length + 1), "{0}.WriteAsync() does not throw an ArgumentOutOfRangeException when count > buffer length.", stream.GetType ().Name); Assert.AreEqual ("count", ex.ParamName); } else { Assert.Throws (() => stream.Write (buffer, 0, buffer.Length), "{0}.Write() does not throw a NotSupportedException when CanWrite is false.", stream.GetType ().Name); - Assert.Throws (async () => await stream.WriteAsync (buffer, 0, buffer.Length), + Assert.ThrowsAsync (async () => await stream.WriteAsync (buffer, 0, buffer.Length), "{0}.WriteAsync() does not throw a NotSupportedException when CanWrite is false.", stream.GetType ().Name); } @@ -354,6 +365,8 @@ public void TestStreamArguments () AssertStreamArguments (stream); using (var memory = new MemoryStream ()) { + Assert.Throws (() => new FilteredStream (null)); + using (var stream = new FilteredStream (memory)) AssertStreamArguments (stream); } @@ -411,21 +424,39 @@ public void TestHeaderListCollectionArguments () collection.Add (new HeaderList ()); Assert.Throws (() => collection[0] = null); + Assert.DoesNotThrow (() => collection[0] = new HeaderList ()); + } + + [Test] + public void TestMimeMessageBeginEventArgs () + { + Assert.Throws (() => new MimeMessageBeginEventArgs (null)); + Assert.Throws (() => new MimeMessageBeginEventArgs (null, new MessagePart ())); + Assert.Throws (() => new MimeMessageBeginEventArgs (new MimeMessage (), null)); + } + + [Test] + public void TestMimeMessageEndEventArgs () + { + Assert.Throws (() => new MimeMessageEndEventArgs (null)); + Assert.Throws (() => new MimeMessageEndEventArgs (null, new MessagePart ())); + Assert.Throws (() => new MimeMessageEndEventArgs (new MimeMessage (), null)); + } + + [Test] + public void TestMimeEntityBeginEventArgs () + { + Assert.Throws (() => new MimeEntityBeginEventArgs (null)); + Assert.Throws (() => new MimeEntityBeginEventArgs (null, new Multipart ())); + Assert.Throws (() => new MimeEntityBeginEventArgs (new MimePart (), null)); } [Test] - public void TestMimeIteratorArguments () + public void TestMimeEntityEndEventArgs () { - var iter = new MimeIterator (new MimeMessage { Body = new TextPart ("plain") }); - - Assert.Throws (() => new MimeIterator (null)); - Assert.Throws (() => { var x = iter.Depth; }); - Assert.Throws (() => { var x = iter.Current; }); - Assert.Throws (() => { var x = iter.Parent; }); - Assert.Throws (() => { var x = iter.PathSpecifier; }); - Assert.Throws (() => iter.MoveTo (null)); - Assert.Throws (() => iter.MoveTo (string.Empty)); - Assert.Throws (() => iter.MoveTo ("xyz")); + Assert.Throws (() => new MimeEntityEndEventArgs (null)); + Assert.Throws (() => new MimeEntityEndEventArgs (null, new Multipart ())); + Assert.Throws (() => new MimeEntityEndEventArgs (new MimePart (), null)); } } } diff --git a/UnitTests/AssortedTests.cs b/UnitTests/AssortedTests.cs index 1801908b11..ed8c15e0e0 100644 --- a/UnitTests/AssortedTests.cs +++ b/UnitTests/AssortedTests.cs @@ -1,9 +1,9 @@ -// +// // AssortedTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Globalization; using NUnit.Framework; @@ -201,7 +202,7 @@ public void TestCharsetUtilsGetCodePage () int expected, codepage; string name; - name = string.Format ("iso-8859-{0}", i); + name = string.Format (CultureInfo.InvariantCulture, "iso-8859-{0}", i); codepage = CharsetUtils.GetCodePage (name); switch (i) { @@ -233,17 +234,17 @@ public void TestCharsetUtilsGetCodePage () else expected = -1; - name = string.Format ("windows-125{0}", i); + name = string.Format (CultureInfo.InvariantCulture, "windows-125{0}", i); codepage = CharsetUtils.GetCodePage (name); Assert.AreEqual (expected, codepage, "Invalid codepage for: {0}", name); - name = string.Format ("windows-cp125{0}", i); + name = string.Format (CultureInfo.InvariantCulture, "windows-cp125{0}", i); codepage = CharsetUtils.GetCodePage (name); Assert.AreEqual (expected, codepage, "Invalid codepage for: {0}", name); - name = string.Format ("cp125{0}", i); + name = string.Format (CultureInfo.InvariantCulture, "cp125{0}", i); codepage = CharsetUtils.GetCodePage (name); Assert.AreEqual (expected, codepage, "Invalid codepage for: {0}", name); @@ -253,7 +254,7 @@ public void TestCharsetUtilsGetCodePage () int codepage; string name; - name = string.Format ("ibm-{0}", ibm); + name = string.Format (CultureInfo.InvariantCulture, "ibm-{0}", ibm); codepage = CharsetUtils.GetCodePage (name); Assert.AreEqual (ibm, codepage, "Invalid codepage for: {0}", name); diff --git a/UnitTests/AttachmentCollectionTests.cs b/UnitTests/AttachmentCollectionTests.cs index 335bfcfd3e..bc1df038fb 100644 --- a/UnitTests/AttachmentCollectionTests.cs +++ b/UnitTests/AttachmentCollectionTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -87,5 +87,252 @@ public void TestArgumentExceptions () Assert.Throws (() => attachments.Insert (0, null)); } } + + [Test] + public void TestAddFileName () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName); + Assert.AreEqual ("image/jpeg", attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddInlineFileName () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (true); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName); + Assert.AreEqual ("image/jpeg", attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("inline", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddFileNameContentType () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var contentType = new ContentType ("image", "gif"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName, contentType); + Assert.AreEqual (contentType.MimeType, attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddData () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName, File.ReadAllBytes (fileName)); + Assert.AreEqual ("image/jpeg", attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddDataContentType () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var contentType = new ContentType ("image", "gif"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName, File.ReadAllBytes (fileName), contentType); + Assert.AreEqual (contentType.MimeType, attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddStream () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = (MimePart) attachments.Add (fileName, stream); + + Assert.AreEqual ("image/jpeg", attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddStreamContentType () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); + var contentType = new ContentType ("image", "gif"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = (MimePart) attachments.Add (fileName, stream, contentType); + + Assert.AreEqual (contentType.MimeType, attachment.ContentType.MimeType); + Assert.AreEqual ("girl.jpg", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("girl.jpg", attachment.ContentDisposition.FileName); + Assert.AreEqual ("girl.jpg", attachment.FileName); + Assert.AreEqual (ContentEncoding.Base64, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddTextFileName () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "lorem-ipsum.txt"); + var attachments = new AttachmentCollection (); + MimePart attachment; + + attachment = (MimePart) attachments.Add (fileName); + Assert.AreEqual ("text/plain", attachment.ContentType.MimeType); + Assert.AreEqual ("lorem-ipsum.txt", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("lorem-ipsum.txt", attachment.ContentDisposition.FileName); + Assert.AreEqual ("lorem-ipsum.txt", attachment.FileName); + Assert.AreEqual (ContentEncoding.SevenBit, attachment.ContentTransferEncoding); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddEmailMessage () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.1.txt"); + var attachments = new AttachmentCollection (); + MimeEntity attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = attachments.Add ("message.eml", stream); + + Assert.AreEqual ("message/rfc822", attachment.ContentType.MimeType); + Assert.AreEqual ("message.eml", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("attachment", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("message.eml", attachment.ContentDisposition.FileName); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } + + [Test] + public void TestAddInlineEmailMessage () + { + var fileName = Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.1.txt"); + var attachments = new AttachmentCollection (true); + MimeEntity attachment; + + using (var stream = File.OpenRead (fileName)) + attachment = attachments.Add ("message.eml", stream); + + Assert.AreEqual ("message/rfc822", attachment.ContentType.MimeType); + Assert.AreEqual ("message.eml", attachment.ContentType.Name); + Assert.NotNull (attachment.ContentDisposition); + Assert.AreEqual ("inline", attachment.ContentDisposition.Disposition); + Assert.AreEqual ("message.eml", attachment.ContentDisposition.FileName); + Assert.AreEqual (1, attachments.Count); + + Assert.IsTrue (attachments.Contains (attachment), "Contains"); + Assert.AreEqual (0, attachments.IndexOf (attachment), "IndexOf"); + Assert.IsTrue (attachments.Remove (attachment), "Remove"); + Assert.AreEqual (0, attachments.Count); + attachments.Clear (); + } } } diff --git a/UnitTests/ConstructorTests.cs b/UnitTests/ConstructorTests.cs index a3c4e2c6c6..cb5da4db5d 100644 --- a/UnitTests/ConstructorTests.cs +++ b/UnitTests/ConstructorTests.cs @@ -1,9 +1,9 @@ -// +// // ConstructorTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -52,6 +52,7 @@ public void TestArgumentExceptions () Assert.Throws (() => new MessagePart ("rfc822", (object[]) null)); Assert.Throws (() => new MessagePart ("rfc822", message, null, message)); Assert.Throws (() => new MessagePart ("rfc822", 5)); + Assert.DoesNotThrow (() => new MessagePart ("rfc822", message)); Assert.Throws (() => new MimePart ("text", "plain", (object[]) null)); Assert.Throws (() => new MimePart ("text", "plain", body.Content, body.Content.Stream)); diff --git a/UnitTests/ContentDispositionTests.cs b/UnitTests/ContentDispositionTests.cs index 143924653c..1360488026 100644 --- a/UnitTests/ContentDispositionTests.cs +++ b/UnitTests/ContentDispositionTests.cs @@ -1,9 +1,9 @@ -// +// // ContentDispositionTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/ContentObjectTests.cs b/UnitTests/ContentObjectTests.cs index eda4e796f0..8b11c1f20b 100644 --- a/UnitTests/ContentObjectTests.cs +++ b/UnitTests/ContentObjectTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,6 @@ using NUnit.Framework; using MimeKit; -using MimeKit.IO; namespace UnitTests { [TestFixture] @@ -45,9 +44,9 @@ public void TestArgumentExceptions () Assert.Throws (() => new MimeContent (null)); Assert.Throws (() => content.WriteTo (null)); - Assert.Throws (async () => await content.WriteToAsync (null)); + Assert.ThrowsAsync (async () => await content.WriteToAsync (null)); Assert.Throws (() => content.DecodeTo (null)); - Assert.Throws (async () => await content.DecodeToAsync (null)); + Assert.ThrowsAsync (async () => await content.DecodeToAsync (null)); } [Test] @@ -62,7 +61,7 @@ public void TestCancellation () Assert.Throws (() => content.WriteTo (dest, source.Token)); Assert.AreEqual (0, dest.Length); - Assert.Throws (async () => await content.WriteToAsync (dest, source.Token)); + Assert.ThrowsAsync (async () => await content.WriteToAsync (dest, source.Token)); Assert.AreEqual (0, dest.Length); } } diff --git a/UnitTests/ContentTypeTests.cs b/UnitTests/ContentTypeTests.cs index 0e2bb56284..ed7654e471 100644 --- a/UnitTests/ContentTypeTests.cs +++ b/UnitTests/ContentTypeTests.cs @@ -1,9 +1,9 @@ -// +// // ContentTypeTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -252,6 +252,17 @@ public void TestContentTypeWithEmptyParameter () AssertParse (text, expected); } + // Tests the work-around for issue #595 + [Test] + public void TestContentTypeWithoutSemicolonBetweenParameters () + { + const string text = "application/x-pkcs7-mime;\n name=\"smime.p7m\"\n smime-type=enveloped-data"; + var expected = new ContentType ("application", "x-pkcs7-mime") { Name = "smime.p7m" }; + expected.Parameters.Add ("smime-type", "enveloped-data"); + + AssertParse (text, expected, true); + } + [Test] public void TestContentTypeAndContentTrafserEncodingOnOneLine () { @@ -260,7 +271,7 @@ public void TestContentTypeAndContentTrafserEncodingOnOneLine () // TryParse should "fail", but still produce a usable ContentType. // Parse will throw ParseException. - AssertParse (text, expected, false, 35, 35); + AssertParse (text, expected, false, 35, 60); } [Test] @@ -508,6 +519,69 @@ public void TestInvalidDataAfterMimeType () AssertParse (text, expected, false, 25, 25); } + [Test] + public void TestEmptyParameterName () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; ="; + + AssertParse (text, expected, false, 12, 12); + } + + [Test] + public void TestIncompleteParameterName () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name"; + + AssertParse (text, expected, false, 12, 16); + } + + [Test] + public void TestIncompleteParameterNameWithStar () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name*"; + + AssertParse (text, expected, false, 12, 17); + } + + [Test] + public void TestIncompleteParameterNameWithPartId () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name*0"; + + AssertParse (text, expected, false, 12, 18); + } + + [Test] + public void TestIncompleteParameterNameWithPartIdStar () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name*0*"; + + AssertParse (text, expected, false, 12, 19); + } + + [Test] + public void TestInvalidParameterNameWithPartId () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name*0*x"; + + AssertParse (text, expected, false, 12, 19); + } + + [Test] + public void TestInncompleteParameterNameWithPartIdStarEqual () + { + var expected = new ContentType ("text", "plain"); + const string text = "text/plain; name*0*="; + + AssertParse (text, expected, false, 12, 20); + } + [Test] public void TestProperties () { @@ -539,5 +613,39 @@ public void TestProperties () type.Name = null; Assert.IsNull (type.Name); } + + [Test] + public void TestToString () + { + const string expected = "Content-Type: text/plain; format=\"flowed\"; charset=\"iso-8859-1\"; name=\"filename.txt\""; + var type = new ContentType ("text", "plain") { Format = "flowed", Charset = "iso-8859-1", Name = "filename.txt" }; + var value = type.ToString ().Replace ("\r\n", "\n"); + + Assert.AreEqual (expected, value); + } + + [Test] + public void TestToStringEncode () + { + const string rfc2231 = "Content-Type: text/plain; format=flowed; charset=utf-8;\n\tname*0*=utf-8''%D0%AD%D1%82%D0%BE%20%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE;\n\tname*1*=%D0%B5%20%D0%B8%D0%BC%D1%8F%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B0.txt"; + const string rfc2047 = "Content-Type: text/plain; format=flowed; charset=utf-8;\n\tname=\"=?utf-8?b?0K3RgtC+INGA0YPRgdGB0LrQvtC1INC40LzRjyDRhNCw0LnQu9CwLnR4?=\n\t=?utf-8?q?t?=\""; + var type = new ContentType ("text", "plain") { Format = "flowed", Charset = "utf-8", Name = "Это русское имя файла.txt" }; + string value; + + value = type.ToString (Encoding.UTF8, true).Replace ("\r\n", "\n"); + Assert.AreEqual (rfc2231, value, "Default"); + + foreach (var parameter in type.Parameters) + parameter.EncodingMethod = ParameterEncodingMethod.Rfc2231; + + value = type.ToString (Encoding.UTF8, true).Replace ("\r\n", "\n"); + Assert.AreEqual (rfc2231, value, "Rfc2231"); + + foreach (var parameter in type.Parameters) + parameter.EncodingMethod = ParameterEncodingMethod.Rfc2047; + + value = type.ToString (Encoding.UTF8, true).Replace ("\r\n", "\n"); + Assert.AreEqual (rfc2047, value, "Rfc2047"); + } } } diff --git a/UnitTests/Cryptography/ApplicationPkcs7MimeTests.cs b/UnitTests/Cryptography/ApplicationPkcs7MimeTests.cs index 2115df1bd4..301801f006 100644 --- a/UnitTests/Cryptography/ApplicationPkcs7MimeTests.cs +++ b/UnitTests/Cryptography/ApplicationPkcs7MimeTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -42,7 +42,7 @@ public class ApplicationPkcs7MimeTests [Test] public void TestArgumentExceptions () { - var path = Path.Combine ("..", "..", "TestData", "smime", "smime.p12"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"); var entity = new TextPart ("plain") { Text = "This is some text..." }; var mailbox = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); var recipients = new CmsRecipientCollection (); @@ -52,8 +52,7 @@ public void TestArgumentExceptions () recipients.Add (new CmsRecipient (signer.Certificate)); using (var ctx = new TemporarySecureMimeContext ()) { - using (var file = File.OpenRead (path)) - ctx.Import (file, "no.secret"); + ctx.Import (path, "no.secret"); // Compress Assert.Throws (() => ApplicationPkcs7Mime.Compress (null, entity)); diff --git a/UnitTests/Cryptography/ArcSignerTests.cs b/UnitTests/Cryptography/ArcSignerTests.cs new file mode 100644 index 0000000000..722535b48c --- /dev/null +++ b/UnitTests/Cryptography/ArcSignerTests.cs @@ -0,0 +1,1394 @@ +// +// ArcSignerTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Crypto.Parameters; + +using MimeKit; +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class ArcSignerTests + { + [Test] + public void TestArcSignerCtors () + { + Assert.DoesNotThrow (() => { + var signer = new DummyArcSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"), "example.com", "1433868189.example") { + SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha256 + }; + }); + + AsymmetricCipherKeyPair keys; + + using (var stream = new StreamReader (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) { + var reader = new PemReader (stream); + + keys = reader.ReadObject () as AsymmetricCipherKeyPair; + } + + Assert.DoesNotThrow (() => { + var signer = new DummyArcSigner (keys.Private, "example.com", "1433868189.example") { + SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha256 + }; + }); + } + + [Test] + public void TestArcSignerDefaults () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"); + AsymmetricCipherKeyPair keys; + ArcSigner signer; + + using (var stream = new StreamReader (path)) { + var reader = new PemReader (stream); + + keys = reader.ReadObject () as AsymmetricCipherKeyPair; + } + + signer = new DummyArcSigner (keys.Private, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #1"); + + signer = new DummyArcSigner (path, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #2"); + + using (var stream = File.OpenRead (path)) { + signer = new DummyArcSigner (stream, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #3"); + } + } + + [Test] + public void TestArgumentExceptions () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"); + var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); + var dkimHeader = new Header (HeaderId.DkimSignature, "value"); + var arcHeader = new Header (HeaderId.ArcMessageSignature, "value"); + var options = FormatOptions.Default; + var message = new MimeMessage (); + AsymmetricCipherKeyPair keys; + ArcSigner signer; + + using (var stream = new StreamReader (path)) { + var reader = new PemReader (stream); + + keys = reader.ReadObject () as AsymmetricCipherKeyPair; + } + + Assert.Throws (() => new DummyArcSigner ((AsymmetricKeyParameter) null, "domain", "selector")); + Assert.Throws (() => new DummyArcSigner (keys.Public, "domain", "selector")); + Assert.Throws (() => new DummyArcSigner (keys.Private, null, "selector")); + Assert.Throws (() => new DummyArcSigner (keys.Private, "domain", null)); + Assert.Throws (() => new DummyArcSigner ((string) null, "domain", "selector")); + Assert.Throws (() => new DummyArcSigner ("fileName", null, "selector")); + Assert.Throws (() => new DummyArcSigner ("fileName", "domain", null)); + Assert.Throws (() => new DummyArcSigner (string.Empty, "domain", "selector")); + Assert.Throws (() => new DummyArcSigner ((Stream) null, "domain", "selector")); + using (var stream = File.OpenRead (path)) { + Assert.Throws (() => new DummyArcSigner (stream, null, "selector")); + Assert.Throws (() => new DummyArcSigner (stream, "domain", null)); + + signer = new DummyArcSigner (stream, "example.com", "1433868189.example") { + SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha1 + }; + } + + // Sign + + Assert.Throws (() => signer.Sign (null, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (message, (IList) null)); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.Unknown, HeaderId.From })); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.Received, HeaderId.From })); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.ContentType })); + Assert.Throws (() => signer.Sign (null, new string[] { "From" })); + Assert.Throws (() => signer.Sign (message, (IList) null)); + Assert.Throws (() => signer.Sign (message, new string[] { "", "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { null, "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { "Received", "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { "Content-Type" })); + + Assert.Throws (() => signer.Sign (null, message, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (options, null, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (options, message, new HeaderId[] { HeaderId.From, HeaderId.Unknown })); + Assert.Throws (() => signer.Sign (options, message, (IList) null)); + + Assert.Throws (() => signer.Sign (null, message, new string[] { "From" })); + Assert.Throws (() => signer.Sign (options, null, new string[] { "From" })); + Assert.Throws (() => signer.Sign (options, message, new string[] { "From", null })); + Assert.Throws (() => signer.Sign (options, message, (IList) null)); + + // SignAsync + + Assert.ThrowsAsync (async () => await signer.SignAsync (null, new HeaderId[] { HeaderId.From })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, (IList) null)); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new HeaderId[] { HeaderId.Unknown, HeaderId.From })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new HeaderId[] { HeaderId.Received, HeaderId.From })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new HeaderId[] { HeaderId.ContentType })); + Assert.ThrowsAsync (async () => await signer.SignAsync (null, new string[] { "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, (IList) null)); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new string[] { "", "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new string[] { null, "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new string[] { "Received", "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (message, new string[] { "Content-Type" })); + + Assert.ThrowsAsync (async () => await signer.SignAsync (null, message, new HeaderId[] { HeaderId.From })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, null, new HeaderId[] { HeaderId.From })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, message, new HeaderId[] { HeaderId.From, HeaderId.Unknown })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, message, (IList) null)); + + Assert.ThrowsAsync (async () => await signer.SignAsync (null, message, new string[] { "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, null, new string[] { "From" })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, message, new string[] { "From", null })); + Assert.ThrowsAsync (async () => await signer.SignAsync (options, message, (IList) null)); + } + + static void AssertHeadersEqual (string description, HeaderId id, string expected, string actual) + { + var expectedTags = DkimVerifierBase.ParseParameterTags (id, expected); + var actualTags = DkimVerifierBase.ParseParameterTags (id, actual); + + Assert.AreEqual (expectedTags.Count, actualTags.Count, "{0} parameter counts do not match", id.ToHeaderName ()); + foreach (var tag in expectedTags) { + string value; + + if (tag.Key == "b") { + // Note: these values are affected by tag order, so MimeKit's results *will* differ + // from the results produced by the library that the tests are based on... + // + // We'll validate that these values are correct by using the ArcVerifier. + continue; + } + + Assert.IsTrue (actualTags.TryGetValue (tag.Key, out value), tag.Key); + Assert.AreEqual (tag.Value, value, "{0} {1}= values do not match", id.ToHeaderName (), tag.Key); + } + } + + static void AssertSignResults (string description, MimeMessage message, DkimPublicKeyLocator locator, DkimSignatureAlgorithm algorithm, string aar, string ams, string seal) + { + Header header; + int index; + + if (string.IsNullOrEmpty (seal)) { + index = message.Headers.IndexOf (HeaderId.ArcSeal); + + Assert.AreNotEqual (0, index, "Message should not have been signed."); + } else { + index = message.Headers.IndexOf (HeaderId.ArcAuthenticationResults); + Assert.AreEqual (2, index, "IndexOf ARC-Authentication-Results header"); + header = message.Headers[index]; + Assert.AreEqual (aar, header.Value, "ARC-Authentication-Results headers do not match"); + + index = message.Headers.IndexOf (HeaderId.ArcMessageSignature); + Assert.AreEqual (1, index, "IndexOf ARC-Message-Signature header"); + header = message.Headers[index]; + AssertHeadersEqual (description, HeaderId.ArcMessageSignature, ams, header.Value); + + index = message.Headers.IndexOf (HeaderId.ArcSeal); + Assert.AreEqual (0, index, "IndexOf ARC-Seal header"); + header = message.Headers[index]; + AssertHeadersEqual (description, HeaderId.ArcSeal, seal, header.Value); + + var expected = ArcSignatureValidationResult.Pass; + if (header.Value.Contains ("cv=fail;")) + expected = ArcSignatureValidationResult.Fail; + var verifier = new ArcVerifier (locator); + ArcValidationResult result; + + if (!verifier.IsEnabled (algorithm)) { + result = verifier.Verify (message); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, result.Chain, "Disabled algorithm should fail"); + + verifier.Enable (algorithm); + } + + result = verifier.Verify (message); + + Assert.AreEqual (expected, result.Chain, "ArcSigner validation failed"); + } + } + + static void Sign (string description, string input, DkimPublicKeyLocator locator, string srvid, string domain, string selector, + string privateKey, long t, string[] hdrs, string aar, string ams, string seal, + DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256, + DkimCanonicalizationAlgorithm headerAlgorithm = DkimCanonicalizationAlgorithm.Relaxed, + DkimCanonicalizationAlgorithm bodyAlgorithm = DkimCanonicalizationAlgorithm.Relaxed) + { + DummyArcSigner signer; + + if (algorithm == DkimSignatureAlgorithm.Ed25519Sha256) { + var rawData = Convert.FromBase64String (privateKey); + var key = new Ed25519PrivateKeyParameters (rawData, 0); + + signer = new DummyArcSigner (key, domain, selector, algorithm); + } else { + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (privateKey), false)) { + signer = new DummyArcSigner (stream, domain, selector, algorithm); + } + } + + signer.HeaderCanonicalizationAlgorithm = headerAlgorithm; + signer.BodyCanonicalizationAlgorithm = bodyAlgorithm; + signer.PublicKeyLocator = locator; + signer.Timestamp = t; + signer.SrvId = srvid; + + using (var stream = new MemoryStream (Encoding.UTF8.GetBytes (input), false)) { + var message = MimeMessage.Load (stream); + + // Test Sign(..., string[] headers, ...) + signer.Sign (message, hdrs); + AssertSignResults (description, message, locator, algorithm, aar, ams, seal); + + stream.Position = 0; + message = MimeMessage.Load (stream); + + // Test SignAsync(..., string[] headers, ...) + signer.SignAsync (message, hdrs).GetAwaiter ().GetResult (); + AssertSignResults (description, message, locator, algorithm, aar, ams, seal); + + var ids = new HeaderId[hdrs.Length]; + for (int i = 0; i < hdrs.Length; i++) + ids[i] = hdrs[i].ToHeaderId (); + + stream.Position = 0; + message = MimeMessage.Load (stream); + + // Test Sign(..., HeaderId[] headers, ...) + signer.Sign (message, ids); + AssertSignResults (description, message, locator, algorithm, aar, ams, seal); + + stream.Position = 0; + message = MimeMessage.Load (stream); + + // Test SignAsync(..., HeaderId[] headers, ...) + signer.SignAsync (message, ids).GetAwaiter ().GetResult (); + AssertSignResults (description, message, locator, algorithm, aar, ams, seal); + } + } + + [Test] + public void sig_alg_rsa_sha1 () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "i=1; a=rsa-sha1; cv=none; d=example.org; s=dummy; t=12345; b=eF3i/65gJXfQu4kMAiK+EusLS0irqv6gIyJYEcpJTaASwWZd+vt6+nN7pjP7kDZYwno8gVFS5vFrkc959FBjJr1oWVVbVdrJenYqCvBBnFmrYyhG137vV+7RziHerQCJ44VkrF1VEaj7TQ+rp5rmwUMZQlpxdqUYWTIT9DpYAFs="; + const string ams = "i=1; a=rsa-sha1; d=example.org; s=dummy; c=relaxed/relaxed; t=12345; h=mime-version:date:from:to:subject; bh=bIxxaeIQvmOBdTAitYfSNFgzPP4=; b=qh2z8AFVMdUI4pG3EBTn9+3Af3KU0tmlLUOeUnCsWuigUdE7TTGLirz2ZOeFUAjAeHuKFxJjEPbtYtQh9ptuxZ8Mn9sE/AfIBd85q2yHWu3WOGQFwRrEuLekiH/zXG3d7VUhf8PNveHEXx/NI40qBpPLjXF4o8qxoApGEQZ6CjA="; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("a=rsa-sha1", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal, DkimSignatureAlgorithm.RsaSha1); + } + + [Test] + public void sig_alg_ed25519_sha256 () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = "nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A="; + const string seal = "i=1; a=ed25519-sha256; cv=none; d=example.org; s=dummy; t=12345; b=1VlNt2DJiRslGH64VEByTy/rviHk9vVjzaFb6Jd4C5V01Uy9pyrZwa6vwPdUZgrnymXzbz2qgtGyHKd3oYHABg=="; + const string ams = "i=1; a=ed25519-sha256; d=example.org; s=dummy; c=relaxed/relaxed; t=12345; h=mime-version:date:from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b=f3EEIg6djos7u74HzwTwQaZmCt3jhoQe/PnDsLfnOd5i6slE0MJdoR4lgBOAZMh+nTLF7YfsHF/qopJwoPBQDg=="; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="); + + Sign ("a=ed25519-sha256", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal, DkimSignatureAlgorithm.Ed25519Sha256); + } + + [Test] + public void c_simple_simple () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "i=1; a=rsa-sha256; cv=none; d=example.org; s=dummy; t=12345; b=utRLvF0lNhc2EUk27iMDUrE7jKP4eGWRy9iUKvmgcZtXY8f4x7r5zz8WzLzOUKo8KyUSgnzVWyyxtMqoAcGzzb/1HtwsEiT+B79pCkZDNqcH2E5dHHq7z8/QBwjScZWu3qFaFDtnMktVs13AMc6W1vgAueOyFjH3mdHmAbQBQaY="; + const string ams = "i=1; a=rsa-sha256; d=example.org; s=dummy; c=simple/simple; t=12345; h=mime-version:date:from:to:subject; bh=hhFbTjokraRYc/Af+8v4zyKm/9ApHGkBSLO129NtPbo=; b=GTpRE34Ud8TOECxNCRNw4jSncvc1nTlLNr6OJC6AjxmumsW2dvQglYIYJK5NO7zPKwzTVUlVB6ZznpIzaKJzsy5oBxV2frl5p5ZBFKGeiU94O0byPiATdwHe4lQiYUK5hBQV0Ei2sxSSlbQPXqjDymnZDcMPp/fLhDQETrjE6AI="; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("a=rsa-sha256", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal, DkimSignatureAlgorithm.RsaSha256, DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm.Simple); + } + + #region Canonicalization + + [Test] + public void message_body_eol_wsp () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("message body eol whitespace ignored", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void message_body_inl_wsp () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("message body inline whitespace reduced", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void message_body_end_lines () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("message body ignore trailing empty lines", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void message_body_trail_crlf () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("message body add crlf to end if na", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void headers_field_name_case () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +FROM: John Q Doe +to: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("header field names case insensitive", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void headers_field_unfold () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe + +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("header", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void headers_eol_wsp () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("headers ignore eol whitespace", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void headers_inl_wsp () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("header reduce inline whitespace", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void headers_col_wsp () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("headers whitespace surrounding colon ignored", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + #endregion + #region Existant Seal Headers + + [Test] + public void i0_base () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=0 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void i1_base () + { + const string input = @"Authentication-Results: lists.example.org; arc=pass; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=KalMXVkx0O4PZIytFfe3i6B/c64408LkuF6rYR9HzBsTazolbsFg/nTah+zh9xmVnylcbg + gZnvu+Rte97HXb9fCK6/rAJQJ97NvYVgzwnEiAzCDts/3dS3SO+PyoAV2HxGMQlUgNeqidAc + mpm7kE3NbSpgq8Z/rsK5FZ7ADceXw=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm + 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v + rCB4wHD9GADeUKVfHzmpZhFuYOa88=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=KiRMwS+rbu4ScgsYQGrZdW72DMVPKRnmkXigPU2FpNPTRViMIRIclMAa48kvbOJ/APWJuG eX3uW2PfI3u2EKtDitHFLvlU2LlCkHhyp8HSO5VJFr0aAk9Z3aQhcoE5hWJ061NXe8C1nafG 4ctcT8p0xkTjVrL9EVsz26o0mRlXY=; cv=pass; d=example.org; i=2; s=dummy; t=12346"; + const string ams = "a=rsa-sha256; b=UaNJhLFAa56Gpc+wKk0SL2Jq/LJgT9CYSZl59wcGYkpG0D5bjhDdj3qers6hD+3BpljNgn mFxq8zWssoPon3ydvTSCSjVwPRNgLol9zBP+FZo/QGQQbj74ZcGv04jOVe8TKDTFSaVe41L7 mH16ZdoLgRdSa2Ys+p9f0+DVFYTO4=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=2; s=dummy; t=12346"; + const string aar = "i=2; lists.example.org; arc=pass; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=1 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12346, hdrs, aar, ams, seal); + } + + [Test] + public void i2_base () + { + const string input = @"Authentication-Results: lists.example.org; arc=pass; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=I8bdOhGPwqIRyhSYZysZdwFJmD/gRxZR3Dn8BQdKkv3fOsWG8A2aftWwnAHKsNreVi6MUF + W4M3tVxsG+pF52qzl3zQGn3bkQIS1N700fbu0z0Lg8IW/gcxziGJlLgK5Bk70uN1egGgdLwn + SiywwvouD7BX1ZlkxFk9i84SDf8/w=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=UaNJhLFAa56Gpc+wKk0SL2Jq/LJgT9CYSZl59wcGYkpG0D5bjhDdj3qers6hD+3BpljNgn + mFxq8zWssoPon3ydvTSCSjVwPRNgLol9zBP+FZo/QGQQbj74ZcGv04jOVe8TKDTFSaVe41L7 + mH16ZdoLgRdSa2Ys+p9f0+DVFYTO4=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; arc=pass; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=KalMXVkx0O4PZIytFfe3i6B/c64408LkuF6rYR9HzBsTazolbsFg/nTah+zh9xmVnylcbg + gZnvu+Rte97HXb9fCK6/rAJQJ97NvYVgzwnEiAzCDts/3dS3SO+PyoAV2HxGMQlUgNeqidAc + mpm7kE3NbSpgq8Z/rsK5FZ7ADceXw=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm + 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v + rCB4wHD9GADeUKVfHzmpZhFuYOa88=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=amYobvirySPk39Y45uHWIsJOGQ0pDhn3D8ncaOew7h+9cddITDFGght2qHYE0GLdpDtLUG J1CwEoM6hdVhG6BkJ80vHzy09Wj2id7B3DMpytPm9MjU7K6Le9VGdewFItwhmG+c15l8krp6 sKw7wUlgM60lSZT0EYTC2x8NXjNDI=; cv=pass; d=example.org; i=3; s=dummy; t=12347"; + const string ams = "a=rsa-sha256; b=QmCd8uJdwnr6wMmniYA/VHCuWButAIlcPZSpNWvk8KHgTuFMZlCPQToT2qVpf2BUfdNpnC mSCED02aLfV6Grc6caqO4PIaxyu3Z+/HNxh0NugIW2JVHT1cZicWkwlgZa4V9i+CYFBAYmzb L0n4ibTxSX8XPxR9ffZdknwiLmYsA=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=3; s=dummy; t=12347"; + const string aar = "i=3; lists.example.org; arc=pass; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=2 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12347, hdrs, aar, ams, seal); + } + + [Test] + public void i1_base_fail () + { + const string input = @"Authentication-Results: lists.example.org; arc=fail; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=kalMXVkx0O4PZIytFfe3i6B/c64408LkuF6rYR9HzBsTazolbsFg/nTah+zh9xmVnylcbg + gZnvu+Rte97HXb9fCK6/rAJQJ97NvYVgzwnEiAzCDts/3dS3SO+PyoAV2HxGMQlUgNeqidAc + mpm7kE3NbSpgq8Z/rsK5FZ7ADceXw=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm + 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v + rCB4wHD9GADeUKVfHzmpZhFuYOa88=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=1NUXYB6dkzvHNNuAxkPWkze6te3YkN29XbS1WtqXGPKmwZujBYH8Au3eMW+pKUnCFSK4Bj tyh0/cTU4jKwxE7sVnGV7BbwW8FdRsYSOgT5RCq3GBuWq5SAW5jDzTIoSMU5joN+jU55xw8a mcpcAZse7+iQbftRJflGDEyHZH8s4=; cv=fail; d=example.org; i=2; s=dummy; t=12346"; + const string ams = "a=rsa-sha256; b=UaNJhLFAa56Gpc+wKk0SL2Jq/LJgT9CYSZl59wcGYkpG0D5bjhDdj3qers6hD+3BpljNgn mFxq8zWssoPon3ydvTSCSjVwPRNgLol9zBP+FZo/QGQQbj74ZcGv04jOVe8TKDTFSaVe41L7 mH16ZdoLgRdSa2Ys+p9f0+DVFYTO4=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=2; s=dummy; t=12346"; + const string aar = "i=2; lists.example.org; arc=fail; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=1 basic test with failing arc set", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12346, hdrs, aar, ams, seal); + } + + [Test] + public void i2_base_fail () + { + const string input = @"Authentication-Results: lists.example.org; arc=fail; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=i8bdOhGPwqIRyhSYZysZdwFJmD/gRxZR3Dn8BQdKkv3fOsWG8A2aftWwnAHKsNreVi6MUF + W4M3tVxsG+pF52qzl3zQGn3bkQIS1N700fbu0z0Lg8IW/gcxziGJlLgK5Bk70uN1egGgdLwn + SiywwvouD7BX1ZlkxFk9i84SDf8/w=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=UaNJhLFAa56Gpc+wKk0SL2Jq/LJgT9CYSZl59wcGYkpG0D5bjhDdj3qers6hD+3BpljNgn + mFxq8zWssoPon3ydvTSCSjVwPRNgLol9zBP+FZo/QGQQbj74ZcGv04jOVe8TKDTFSaVe41L7 + mH16ZdoLgRdSa2Ys+p9f0+DVFYTO4=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; arc=pass; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=KalMXVkx0O4PZIytFfe3i6B/c64408LkuF6rYR9HzBsTazolbsFg/nTah+zh9xmVnylcbg + gZnvu+Rte97HXb9fCK6/rAJQJ97NvYVgzwnEiAzCDts/3dS3SO+PyoAV2HxGMQlUgNeqidAc + mpm7kE3NbSpgq8Z/rsK5FZ7ADceXw=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm + 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v + rCB4wHD9GADeUKVfHzmpZhFuYOa88=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.organ> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=P3oIsF0qE5VDD1XPP0oH5XkvpG20k9jmkREcWvi1I9uy6P4UP9Y7mVYTAsNdi8XOg+AMiG CT1CUTmR5+MyYC4mqFW6943PIyzDrDvhZb8DLoy5/tM2cztpSzS0SItqM2XRh0YGp0yMA1sz obc7WTpkgtqFz5beCQC/PjnQ3ZkRw=; cv=fail; d=example.org; i=3; s=dummy; t=12347"; + const string ams = "a=rsa-sha256; b=QmCd8uJdwnr6wMmniYA/VHCuWButAIlcPZSpNWvk8KHgTuFMZlCPQToT2qVpf2BUfdNpnC mSCED02aLfV6Grc6caqO4PIaxyu3Z+/HNxh0NugIW2JVHT1cZicWkwlgZa4V9i+CYFBAYmzb L0n4ibTxSX8XPxR9ffZdknwiLmYsA=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=3; s=dummy; t=12347"; + const string aar = "i=3; lists.example.org; arc=fail; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=1 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12347, hdrs, aar, ams, seal); + } + + [Test] + public void no_additional_sig () + { + const string input = @"Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=OrYKWzAKrroSe2lCeF+/5QJOSzJi/RSTggVcdINMmJ8TO8wfkRLaJkAnhLhNts5lnJIDI7 + ZFUmsbtZ6ZhBK5l6WzaE5+iDofcUTjKMFw7keblIE6Frp8Evsb2ShKQZDIseXZxcNHr/Oz0t + pSKS2JwAriD3rkXm6WVR0Jv+wDFQo=; cv=fail; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=UaNJhLFAa56Gpc+wKk0SL2Jq/LJgT9CYSZl59wcGYkpG0D5bjhDdj3qers6hD+3BpljNgn + mFxq8zWssoPon3ydvTSCSjVwPRNgLol9zBP+FZo/QGQQbj74ZcGv04jOVe8TKDTFSaVe41L7 + mH16ZdoLgRdSa2Ys+p9f0+DVFYTO4=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=fOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=mime-version:date:from:to:subject; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = ""; + const string ams = ""; + const string aar = ""; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("if a chain is failing, dont add another set", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12346, hdrs, aar, ams, seal); + } + + [Test] + public void ar_merged1 () + { + const string input = @"Authentication-Results: lists.example.org; arc=none +Authentication-Results: lists.example.org; spf=pass smtp.mfrom=jqd@d1.example +Authentication-Results: lists.example.org; dkim=pass (1024-bit key) header.i=@d1.example +Authentication-Results: lists.example.org; dmarc=pass +Authentication-Results: nobody.example.org; something=ignored +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=0 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + [Test] + public void ar_merged2 () + { + const string input = @"Authentication-Results: lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example +Authentication-Results: lists.example.org; dkim=pass (1024-bit key) header.i=@d1.example +Authentication-Results: lists.example.org; dmarc=pass +Authentication-Results: nobody.example.org; something=ignored +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + const string keyblock = @"-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi +Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM +KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB +AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm +6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe +zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy +6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc +uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy +WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd +WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a +licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst +o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe +uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL +-----END RSA PRIVATE KEY----- +"; + const string seal = "a=rsa-sha256; b=Pg8Yyk1AgYy2l+kb6iy+mY106AXm5EdgDwJhLP7+XyT6yaS38ZUho+bmgSDorV+LyARH4A 967A/oWMX3coyC7pAGyI+hA3+JifL7P3/aIVP4ooRJ/WUgT79snPuulxE15jg6FgQE68ObA1 /hy77BxdbD9EQxFGNcr/wCKQoeKJ8=; cv=none; d=example.org; i=1; s=dummy; t=12345"; + const string ams = "a=rsa-sha256; b=XWeK9DxQ8MUm+Me5GLZ5lQ3L49RdoFv7m7VlrAkKb3/C7jjw33TrTY0KYI5lkowvEGnAtm 5lAqLz67FxA/VrJc2JiYFQR/mBoJLLz/hh9y77byYmSO9tLfIDe2A83+6QsXHO3K6PxTz7+v rCB4wHD9GADeUKVfHzmpZhFuYOa88=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; d=example.org; h=mime-version:date:from:to:subject; i=1; s=dummy; t=12345"; + const string aar = "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"; + var hdrs = new string[] { "mime-version", "date", "from", "to", "subject" }; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Sign ("i=0 basic test", input, locator, "lists.example.org", "example.org", "dummy", keyblock, 12345, hdrs, aar, ams, seal); + } + + #endregion + } +} diff --git a/UnitTests/Cryptography/ArcVerifierTests.cs b/UnitTests/Cryptography/ArcVerifierTests.cs new file mode 100644 index 0000000000..469edc010d --- /dev/null +++ b/UnitTests/Cryptography/ArcVerifierTests.cs @@ -0,0 +1,9930 @@ +// +// ArcVerifierTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using NUnit.Framework; + +using MimeKit; +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography +{ + [TestFixture] + public class ArcVerifierTests + { + [Test] + public void TestArgumentExceptions () + { + var locator = new DkimPublicKeyLocator (); + var verifier = new ArcVerifier (locator); + var message = new MimeMessage (); + + Assert.Throws (() => new ArcVerifier (null)); + Assert.Throws (() => new ArcHeaderValidationResult (null)); + Assert.Throws (() => new ArcHeaderValidationResult (null, ArcSignatureValidationResult.Fail)); + + Assert.Throws (() => verifier.Verify (null)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (null)); + + Assert.Throws (() => verifier.Verify (null, message)); + Assert.Throws (() => verifier.Verify (FormatOptions.Default, null)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (null, message)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (FormatOptions.Default, null)); + } + + [Test] + public void TestArcHeaderValidationResult () + { + var header = new Header (HeaderId.ArcMessageSignature, "i=1; a=rsa-sha256; ..."); + var result = new ArcHeaderValidationResult (header, ArcSignatureValidationResult.Fail); + + Assert.AreEqual (header, result.Header, "Header"); + Assert.AreEqual (ArcSignatureValidationResult.Fail, result.Signature); + } + + [Test] + public void TestArcValidationResult () + { + var header = new Header (HeaderId.ArcMessageSignature, "i=1; a=rsa-sha256; ..."); + var ams = new ArcHeaderValidationResult (header, ArcSignatureValidationResult.Pass); + + header = new Header (HeaderId.ArcSeal, "i=1; a=rsa-sha256; ..."); + var seal = new ArcHeaderValidationResult (header, ArcSignatureValidationResult.Pass); + + var result = new ArcValidationResult (ArcSignatureValidationResult.Pass, ams, new[] { seal }); + + Assert.AreEqual (ArcSignatureValidationResult.Pass, result.Chain, "Chain"); + Assert.IsNotNull (result.MessageSignature, "MessageSignature != null"); + Assert.AreEqual (HeaderId.ArcMessageSignature, result.MessageSignature.Header.Id, "MessageSignature.Header.Id"); + Assert.AreEqual (ArcSignatureValidationResult.Pass, result.MessageSignature.Signature, "MessageSignature.Signature"); + Assert.IsNotNull (result.Seals, "Seals != null"); + Assert.AreEqual (1, result.Seals.Length, "Seals.Length"); + Assert.AreEqual (HeaderId.ArcSeal, result.Seals[0].Header.Id, "Seals[0].Header.Id"); + Assert.AreEqual (ArcSignatureValidationResult.Pass, result.Seals[0].Signature, "Seals[0].Signature"); + } + + [Test] + public void TestGetArcHeaderSetsBrokenAAR () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input), false)) { + var message = MimeMessage.Load (stream); + ArcValidationErrors errors; + ArcHeaderSet[] sets; + Header broken, aar; + int index, count; + + // first, get a copy of the original ARC-Authentication-Results header + index = message.Headers.IndexOf (HeaderId.ArcAuthenticationResults); + aar = message.Headers[index]; + + // create and set completely broken AAR: + broken = new Header (HeaderId.ArcAuthenticationResults, "this should be unparsable..."); + message.Headers[index] = broken; + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Broken AAR"); + Assert.AreEqual (ArcValidationErrors.InvalidArcAuthenticationResults, errors, "Errors"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Broken AAR should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Broken AAR throwOnError unexpected exception"); + } + + // set an AAR that is missing the instance value + broken.Value = aar.Value.Replace ("i=1; ", ""); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AAR missing i=1"); + Assert.AreEqual (ArcValidationErrors.InvalidArcAuthenticationResults, errors, "Errors missing i=1"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AAR missing i=1 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AAR missing i=1 throwOnError unexpected exception"); + } + + // set an AAR that has an invalid instance value + broken.Value = aar.Value.Replace ("i=1; ", "i=0; "); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AAR i=0"); + Assert.AreEqual (ArcValidationErrors.InvalidArcAuthenticationResults, errors, "Errors i=0"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AAR i=0 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AAR i=0 throwOnError unexpected exception"); + } + + // remove the AAR completely + message.Headers.RemoveAt (index); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Missing AAR"); + Assert.AreEqual (ArcValidationErrors.MissingArcAuthenticationResults, errors, "Errors removed AAR"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Missing AAR should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Missing AAR throwOnError unexpected exception"); + } + } + } + + [Test] + public void TestGetArcHeaderSetsBrokenAMS () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input), false)) { + var message = MimeMessage.Load (stream); + ArcValidationErrors errors; + ArcHeaderSet[] sets; + Header broken, ams; + int index, count; + + // first, get a copy of the original ARC-Message-Signature header + index = message.Headers.IndexOf (HeaderId.ArcMessageSignature); + ams = message.Headers[index]; + + // create and set completely broken AMS: + broken = new Header (HeaderId.ArcMessageSignature, "this should be unparsable..."); + message.Headers[index] = broken; + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Broken AMS"); + Assert.AreEqual (ArcValidationErrors.InvalidArcMessageSignature, errors, "Errors"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Broken AMS should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Broken AMS throwOnError unexpected exception"); + } + + // set an AMS that is missing the instance value + broken.Value = ams.Value.Replace ("i=1; ", ""); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AMS missing i=1"); + Assert.AreEqual (ArcValidationErrors.InvalidArcMessageSignature, errors, "Errors missing i=1"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AMS missing i=1 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AMS missing i=1 throwOnError unexpected exception"); + } + + // set an AMS that has an invalid instance value + broken.Value = ams.Value.Replace ("i=1; ", "i=0; "); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AMS i=0"); + Assert.AreEqual (ArcValidationErrors.InvalidArcMessageSignature, errors, "Errors i=0"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AMS i=0 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AMS i=0 throwOnError unexpected exception"); + } + + // remove the AMS completely + message.Headers.RemoveAt (index); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Missing AMS"); + Assert.AreEqual (ArcValidationErrors.MissingArcMessageSignature, errors, "Errors removed AMS"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Missing AMS should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Missing AMS throwOnError unexpected exception"); + } + } + } + + [Test] + public void TestGetArcHeaderSetsBrokenAS () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input), false)) { + var message = MimeMessage.Load (stream); + ArcValidationErrors errors; + ArcHeaderSet[] sets; + Header broken, seal; + int index, count; + + // first, get a copy of the original ARC-Seal header + index = message.Headers.IndexOf (HeaderId.ArcSeal); + seal = message.Headers[index]; + + // create and set completely broken AS: + broken = new Header (HeaderId.ArcSeal, "this should be unparsable..."); + message.Headers[index] = broken; + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Broken AS"); + Assert.AreEqual (ArcValidationErrors.InvalidArcSeal, errors, "Errors"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Broken AS should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Broken AS throwOnError unexpected exception"); + } + + // set an AS that is missing the instance value + broken.Value = seal.Value.Replace ("i=1; ", ""); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AS missing i=1"); + Assert.AreEqual (ArcValidationErrors.InvalidArcSeal, errors, "Errors missing i=1"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AS missing i=1 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AS missing i=1 throwOnError unexpected exception"); + } + + // set an AS that has an invalid instance value + broken.Value = seal.Value.Replace ("i=1; ", "i=0; "); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "AS i=0"); + Assert.AreEqual (ArcValidationErrors.InvalidArcSeal, errors, "Errors i=0"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("AS i=0 should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("AS i=0 throwOnError unexpected exception"); + } + + // remove the AS completely + message.Headers.RemoveAt (index); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Missing AS"); + Assert.AreEqual (ArcValidationErrors.MissingArcSeal, errors, "Errors removed AS"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Missing AS should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Missing AS throwOnError unexpected exception"); + } + } + } + + [Test] + public void TestGetArcHeaderSetsMissingSet () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input), false)) { + var message = MimeMessage.Load (stream); + ArcValidationErrors errors; + ArcHeaderSet[] sets; + int index, count; + + // Remove the oldest ARC set + index = message.Headers.LastIndexOf (HeaderId.ArcSeal); + message.Headers.RemoveAt (index); + + index = message.Headers.LastIndexOf (HeaderId.ArcMessageSignature); + message.Headers.RemoveAt (index); + + index = message.Headers.LastIndexOf (HeaderId.ArcAuthenticationResults); + message.Headers.RemoveAt (index); + + Assert.AreEqual (ArcSignatureValidationResult.Fail, ArcVerifier.GetArcHeaderSets (message, false, out sets, out count, out errors), "Missing set"); + Assert.AreEqual (ArcValidationErrors.MissingArcAuthenticationResults | ArcValidationErrors.MissingArcMessageSignature | ArcValidationErrors.MissingArcSeal, errors, "Errors"); + + try { + ArcVerifier.GetArcHeaderSets (message, true, out sets, out count, out errors); + Assert.Fail ("Missing set should throwOnError"); + } catch (FormatException) { + } catch { + Assert.Fail ("Missing set throwOnError unexpected exception"); + } + } + } + + static void Validate (string description, string input, DkimPublicKeyLocator locator, ArcSignatureValidationResult expected, ArcValidationErrors expectedErrors = ArcValidationErrors.None) + { + if (string.IsNullOrEmpty (input)) { + Assert.AreEqual (expected, ArcSignatureValidationResult.None, description); + return; + } + + var buffer = Encoding.UTF8.GetBytes (input); + + using (var stream = new MemoryStream (buffer, false)) { + var verifier = new ArcVerifier (locator); + var message = MimeMessage.Load (stream); + ArcValidationResult result; + + // Test Verify + result = verifier.Verify (message); + Assert.AreEqual (expected, result.Chain, description); + Assert.AreEqual (expectedErrors, result.ChainErrors, "chain errors"); + + // Test VerifyAsync + result = verifier.VerifyAsync (message).GetAwaiter ().GetResult (); + Assert.AreEqual (expected, result.Chain, description); + Assert.AreEqual (expectedErrors, result.ChainErrors, "async chain errors"); + } + } + + #region Chain Validation + + [Test] + public void cv_empty () + { + const string input = @""; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("empty message", input, locator, ArcSignatureValidationResult.None); + } + + [Test] + public void cv_no_headers () + { + const string input = @" +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("message with no headers", input, locator, ArcSignatureValidationResult.None); + } + + [Test] + public void cv_no_body () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("message with no body", input, locator, ArcSignatureValidationResult.None); + } + + [Test] + public void cv_base1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("base test message1", input, locator, ArcSignatureValidationResult.None); + } + + [Test] + public void cv_base2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Tue, 3 Jan 2017 12:31:41 -080 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("base test message2", input, locator, ArcSignatureValidationResult.None); + } + + [Test] + public void cv_pass_i1_1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=1 base1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i1_2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=1 base2", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i2_1 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=2 base1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i2_2 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=CiZp+ZloBeWiIyjY+Eq0lKt20KQDF3QIJNw7+/jdjtQ1XTSMhHsli7H/ocIXsiU/kLF5pn + pABQiZPvAWfCaEcCA9lyb/7i3q2i72GLdK1vdrdD2nIM5e7L3u/5Z56SJdKTu46SyoFQve9b + Cp7qoQB9/TUTxxvkDoapsSjDCDqZ0=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=A2OCip1Cf9z6X7ML9/bRajnToeCD3H7IkP7YqmSKqDtn8Yu8oaJdwP0lZfCTjX++Qas9nj + tGWMojFpj8Wd2rzdyMXwUWF3xlcFBD2gApO9xbehIASIF4lFQMyP6D80LjsjdtpstgwGZl9P + y6WTyD1Kw/bNPZadxvNeDg3LVcQpo=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=2 base2", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i2_1_ams1_invalid () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=TKrRvbWMQbGHGQSIMlStVE/2vKjY5E8kVSSXJmEyOL1OjexNoNSfnYpjklVVaG9O4Hsbc5 + ZEbLSkpDIOKlnb+XlLNL5xvYntBNamjtH0e9et3DpyPQUIZ2gyZsuFwPzN/m96BU5iv+blU0 + XLjgABkBLyfaFlEPsQ0SUs8gZjM7Y=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=ZFJ9p6LT/KerwWPXp+WzznYAbt+cF4R/3l5nfSeNZSi38hhtpLkoJi/2R1FXdnnznKa3mQ + gk3WCEaxLNmHEl90TDHGL5vhViJ57OSS0X7ZgyKzZrNbVSDYj416pFR356MMXdaV8WVq9mD4 + yATaaWBkVi8eOh287Qbqj0k93H/+U=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 modified from header, ams(1) no longer valid", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i3_1 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=EcI6PD1XFx7uTngsG2JZQzTaAyhIGafcKJO+aTb4+PV1QKFHrLLrSv++W872urw2WnEsWJ + Hs+YPSVbRGJXbHp4rSM0VasdFb6lf2UUJf8Lxy17f3CzqQQz5CGMO++75t+cManzaOmnjq/Z + gGaqK7euJwWo6hzF3pNZYdTJ6JZOo=; cv=pass; d=example.org; i=3; s=dummy; + t=12347 +ARC-Message-Signature: a=rsa-sha256; + b=FEp53xrAEL1qQfytTEmR+Lp/ZpX4bXQvtj/peHauDtix/tlBN2v841lm72vOjK6WfqGB4E + X/9vRfV7ZiSRMFvXAWlnDKw5wzoZFyQ3xebnvqraYnq9OA1CrDIFQVLqqGIaZrcZ+fTXt7Kp + TBMU/BzIBERwfWXqBG1DqZGYXrHFw=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=3; s=dummy; t=12347 +ARC-Authentication-Results: i=3; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 15:38:12 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=3 base1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i4_1 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=lf+5z/QtA3SZRY8Bz60La2HmprfbE1Q2vUmiP/4Db3Ma3KqpZmnS9/d/wDr3dXgC0TpT4X + +bUAQ0iK2hWXtvr9bfs0x7s2skzdyeX/Zzvin2NE/a0uhxIOMfO6Fqcr8YNT9hKQa4qHJxE/ + Qpr0aO4ypt+tGkNHf+4gCLoDWss0M=; cv=pass; d=example.org; i=4; s=dummy; + t=12348 +ARC-Message-Signature: a=rsa-sha256; + b=aqlCYqV7+A1U0pg3Fc3WayaB8cQOH2QBEbwqzJ82ghIERQnLAPMXKR/LfUo27lNbLi+Hfs + wo3ZOCJOoaC6kvHpMTmgOdq1SWBgl4WjwDhVXSarxZS40HxzF25Gi2O1jn0ke7vj1IyKceiF + 9W6deMSsxrlDqD+1Bas4XUfFeC03M=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=4; s=dummy; t=12348 +ARC-Authentication-Results: i=4; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=EcI6PD1XFx7uTngsG2JZQzTaAyhIGafcKJO+aTb4+PV1QKFHrLLrSv++W872urw2WnEsWJ + Hs+YPSVbRGJXbHp4rSM0VasdFb6lf2UUJf8Lxy17f3CzqQQz5CGMO++75t+cManzaOmnjq/Z + gGaqK7euJwWo6hzF3pNZYdTJ6JZOo=; cv=pass; d=example.org; i=3; s=dummy; + t=12347 +ARC-Message-Signature: a=rsa-sha256; + b=FEp53xrAEL1qQfytTEmR+Lp/ZpX4bXQvtj/peHauDtix/tlBN2v841lm72vOjK6WfqGB4E + X/9vRfV7ZiSRMFvXAWlnDKw5wzoZFyQ3xebnvqraYnq9OA1CrDIFQVLqqGIaZrcZ+fTXt7Kp + TBMU/BzIBERwfWXqBG1DqZGYXrHFw=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=3; s=dummy; t=12347 +ARC-Authentication-Results: i=3; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 15:38:12 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=4 base1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_pass_i5_1 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=0Kw2RaoquhI2id5WxefhIq+DMaZGXa0iEtjT7oRpCpLhLxH0sofldiwSpVJMh1qZo5k7pk + JW/uah4CWdln95BAm3AikTH7Bu0gM6To4qzCgFKulTbnvRK3Q7jT4xflPf8M4PAkw3OAN2+k + d4dsvyOoo3ait+oNeXyFAEuZ4RoD8=; cv=pass; d=example.org; i=5; s=dummy; + t=12349 +ARC-Message-Signature: a=rsa-sha256; + b=j50SIOsFwO/hXR//iEpwzqDIVtC4qwIdReAesDFZaTvfxzYB6TshuR7u7LqE8PjsUNz6CX + urhvUkCOMGi2q9vQn3lqh67m3roWzIPivbUDoO0KAd9FghBI3QKbQAJe85gV7jbaTsURM9WZ + ygbRURxwTz42PatPu9LNGo2QUwaNU=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=5; s=dummy; t=12349 +ARC-Authentication-Results: i=5; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=lf+5z/QtA3SZRY8Bz60La2HmprfbE1Q2vUmiP/4Db3Ma3KqpZmnS9/d/wDr3dXgC0TpT4X + +bUAQ0iK2hWXtvr9bfs0x7s2skzdyeX/Zzvin2NE/a0uhxIOMfO6Fqcr8YNT9hKQa4qHJxE/ + Qpr0aO4ypt+tGkNHf+4gCLoDWss0M=; cv=pass; d=example.org; i=4; s=dummy; + t=12348 +ARC-Message-Signature: a=rsa-sha256; + b=aqlCYqV7+A1U0pg3Fc3WayaB8cQOH2QBEbwqzJ82ghIERQnLAPMXKR/LfUo27lNbLi+Hfs + wo3ZOCJOoaC6kvHpMTmgOdq1SWBgl4WjwDhVXSarxZS40HxzF25Gi2O1jn0ke7vj1IyKceiF + 9W6deMSsxrlDqD+1Bas4XUfFeC03M=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=4; s=dummy; t=12348 +ARC-Authentication-Results: i=4; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=EcI6PD1XFx7uTngsG2JZQzTaAyhIGafcKJO+aTb4+PV1QKFHrLLrSv++W872urw2WnEsWJ + Hs+YPSVbRGJXbHp4rSM0VasdFb6lf2UUJf8Lxy17f3CzqQQz5CGMO++75t+cManzaOmnjq/Z + gGaqK7euJwWo6hzF3pNZYdTJ6JZOo=; cv=pass; d=example.org; i=3; s=dummy; + t=12347 +ARC-Message-Signature: a=rsa-sha256; + b=FEp53xrAEL1qQfytTEmR+Lp/ZpX4bXQvtj/peHauDtix/tlBN2v841lm72vOjK6WfqGB4E + X/9vRfV7ZiSRMFvXAWlnDKw5wzoZFyQ3xebnvqraYnq9OA1CrDIFQVLqqGIaZrcZ+fTXt7Kp + TBMU/BzIBERwfWXqBG1DqZGYXrHFw=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=3; s=dummy; t=12347 +ARC-Authentication-Results: i=3; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 15:38:12 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("passing message i=5 base1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void cv_fail_i1_ams_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i no ams", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcMessageSignature); + } + + [Test] + public void cv_fail_i1_ams_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is an invalid test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i invalid ams", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void cv_fail_i1_as_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i no as", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcSeal); + } + + [Test] + public void cv_fail_i1_as_pass () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=PhxOTCxMOzOkfccg/YXFn+e5FdMyjQK+QXNt9lYytimVUpntsBbAAtBQT5XgYQDRsM3YR+ + vBsf1oJ+kL221cv9qQWYUC3DP3xaE0nZ3vjNR1+//uZpMcTT3k6NYZnlzexAzYMoXByQkrS6 + 0Om4kNir1fUo5SOlGXpXf8NRSmU70=; cv=pass; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i as cv=Pass", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void cv_fail_i1_as_cv_fail () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=wddf4DzBcl11ICrYWjYC78s246KGCG4D3XBmouE2PVdLr4LWqyTWTQDvZ7TWrtEDkRsmz+ + wbaMVAWdj2XgewkwQu5qxQ82D5dGiLcNQXfQDRbd8dO1+PZVWlw0wmeM7nRhNb/5tT0BvNQO + xrrb4oEs4LIFDNYtKgTvCMyCVLzuw=; cv=fail; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i as cv=fail", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void cv_fail_i1_as_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=OdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("failing message i=i invalid as b=", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void cv_fail_i2_ams_na () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 missing AMS(2)", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcMessageSignature); + } + + [Test] + public void cv_fail_i2_ams_invalid () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=jsR4La5CWj4665VQZEjoLgxdNhdaE1mZFpkL8jsfEm938sd9TWr/keRkfZQaRFLuFjTxI4 + vg8/D4bUx3UW0G6CngHmcx0kBi375aRfxmD5ad+esDyc5Dw/s6GapOpb4JFrss1n6x4MGOtY + GQAQi7b0FPUdlXVbKQYIQovi7ZjGU=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=CnX/07HnYNoqdjrn4mE9if486SWqYAytX0weObYC+UCp+ht1qId6MPsQa3QWSWZt3buX+E + kCwFMMfnBeo1gQ9rPfPEcQtUI5/3D/RYqtBmaZTP1Vpcgj5qw3mQxNJJh0kl57z5holdQ5I0 + g0S02+/k61c6cJzmoDKYsQP/VjebI=; + bh=invalid; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 AMS(2) invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void cv_fail_i2_as2_na () + { + const string input = @"MIME-Version: 1.0 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 AS(1) NA", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcSeal); + } + + [Test] + public void cv_fail_i2_as2_invalid () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=JAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 AS(2) invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void cv_fail_i2_as2_none () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=o0fxNS9D87SVRYy2tkq7rXntZWYLuInRCzW2Jx9U8Px0XEGyD4SdwRIpS+RJ4qK6ufvuuc + qYLmF9M9aV0tvbe8mp78+qhN8RImVPehz6AFPY7NGy563MQDPDAynBWQyp4EXodlmmzQoEGB + iMar9e9AuWSwyAok1BDkUFsajLRIA=; cv=none; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 cv2=none", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void cv_fail_i2_as2_fail () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=1mXrddJKGqZTDDgnoDP1IYTu5g4ij0kxFZ8dSsSjo13+vDuoBEa4aKbYWlG4Ij2IAwjaLR + CDYddDXDBZ5Cpnzrq7fDSVmmUhwQanAAd9aah4TpZeervt3/tOqFnpckUtOus1hq9yr5lvLA + 1umDZf50sOb6AygAm/k8xCco9rDp0=; cv=fail; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 cv2=fail", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void cv_fail_i2_as1_na () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=1JtiDdajC4yqlIqokR/uaPI/KdST9EsS2oPhDdQAe4E96IXwQwkgRZLJF9OODSux9JCWXh + Z/sCh3yLmcTOKPuBQAwtAfll+PUePsuHh0gRYECVIkY3bGfAr+3hVdrmNpr7B6/Zcq8mjQEt + u/5q+XkkocYaUxT+ODnGGHwMI/8Q8=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 as(1) not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcSeal); + } + + [Test] + public void cv_fail_i2_as1_invalid () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=gifscOcADiR9JpJLFaCULS2DPnnk89AxF3tIfanEQV5PQWJvRSWrDs8hMwLDdDDZRKBWNq + I1+lBro3Nd9RmUt6YsMNdGYK7XIG5ME9FwamoqqFxq++1jST6wg1gS1YrFExuHreNlICZ9yT + xSmufAj9mJS2CLuOxYh6YIo6bHj1Q=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=OdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 as(1) invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void cv_fail_i2_as1_pass () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=1p687XiKxG2/cjtpO3A+Qkt/B7Q49iMgcq1CutOBxLs2TXcO5CUozwxFbY9YvEaOyXxf6Q + EnSvZ4UpYIkKGNrm0PLSbgI0y3cY4Waa/fFlT+/7oJUQmsnN8MreOfcHZRpGrSRU6bu5uOyp + 5mSlxgTwnti4Ua4vAjl+ayFOn0hC0=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=PhxOTCxMOzOkfccg/YXFn+e5FdMyjQK+QXNt9lYytimVUpntsBbAAtBQT5XgYQDRsM3YR+ + vBsf1oJ+kL221cv9qQWYUC3DP3xaE0nZ3vjNR1+//uZpMcTT3k6NYZnlzexAzYMoXByQkrS6 + 0Om4kNir1fUo5SOlGXpXf8NRSmU70=; cv=pass; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 as(1) cv=pass", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void cv_fail_i2_as1_fail () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=uMD7AJfyGb+OHxrGSOB3Vbt7nBnEZn0RMBoq8GgyRbz4Xar+BmAIR766rEvlwgLkkKU21u + GY8S0HK2GgR5lhpcrezkwD9/L+bfe7uyuFDrr4b50mt4oI9FTfwR0MuHpW91gAvR4ZYnwTRy + PoMy3AaapPFnlY38n+HjseH0JACTo=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=wddf4DzBcl11ICrYWjYC78s246KGCG4D3XBmouE2PVdLr4LWqyTWTQDvZ7TWrtEDkRsmz+ + wbaMVAWdj2XgewkwQu5qxQ82D5dGiLcNQXfQDRbd8dO1+PZVWlw0wmeM7nRhNb/5tT0BvNQO + xrrb4oEs4LIFDNYtKgTvCMyCVLzuw=; cv=fail; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("i=2 base1 as(1) cv=fail", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + #endregion + #region AMS Set Structure + + [Test] + public void ams_struct_i_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=UeCu1SBJupH/8Xp4vCLTNWJAvhmj7xgawvWq/GsnIiqXrrYVg/OvwcqGqGD1kNZHWvZuXH + W0AIl1z/3vycIGYQdrT22+oy/s0bJjHhcHQWo2iZt/4mP094fecbT/soJv6mERLw74pRwkei + /skva76UKGLq1xHXzvQkew5RwhgMo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=mmLqaSDJ2CFu1lXO7s26aXT3MrFC1pfi9ZjuVysKjleXUX3N1+pX+GchfuzHniUGpuQQRQ + 1J7CL7EG6Rd8SzWIM3ghBfhN+G6jjXzv+uVtm89kbNodrVZ1mVtEtUoEo/8BvOCfeNotyGyj + NyHGzPyAc+kv/zimFml7MKn2By4KI=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AMS i= NA", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_struct_i_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=Je7FiPu5s4SChzn1rIOwQd9kAjZodFrZwqsoomdw0TGZsQbL2djL2E160MND7eGKIRe1IP + hu0WqhhZ3OD9LGFa/JUOoSeTgTA+kGx0Acan9wp+ksw9UeCLtpmRs00FOYiHe4mpl8i1QLVG + aLcewyizL1HdM1U3N+S+eeOzBtdwk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=l3O/xWb0Bu0DKaKiwlQrD85VsESQyWPV6fS5r9fou680YgQGIk8ycfBXt0kJLKMf6I7gtC + AZZ3eypnAjIqiP1o3QNaajeicN5str9K+miibqwANe0/SIPR4/fOqs5oS8/9309wzwqPflUt + nL5/nuDJt/5KHqXc2jMw8GZfdAf7M=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AMS i= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_struct_i_zero () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=1BHrrrHUNLNWyocFdPKW6qGOt7Y3TaD8n0pI4pVOKi9hfRljZKQ3xENWzYCPNXiwp9p0ww + gOt2mC/YtjrGCi+Yco4DoStThYcEkoXKUZVPDSa8AIOE/sH32wTYfhaspKr9A2zvScG91zfI + EGC1qF4qHAoxnJBPWfHhuzqH2ELk4=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=hbcwQf/Mg+hXbDyGiBN828o/d7O4WzqVD3r4Zym8u02Flc53mO0N3ElghteOiIw4YG2Sa/ + WbfxPpbWAVsdtYprjevGNOvl1hpF4d+xqX7h+GVxaEwEN65GFK3trxJF2BaHQ8F4hc5a6Fmf + Is8OV3B+2ZW7iegJdH2CVlvusajys=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=0; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AMS i= zero", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_struct_i_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=gzFG4vgfOas2UvRlmaw3UKLF+bfZLP2RoFnIysRRMQHFDz62uhEUoM/U8MAm4N8DLl3Bw9 + 3TcPxmd6zV5sbciSc7zXuMxIAmj3/vyfv4vlTDNZ4n/pHXGfxNhXkDndJcoh+2U2Ia14ARkP + /v2n677wgmOPcbzq27YL5+DJFEG4o=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=eXN9vsCoo/HcGaJ4yAdXfbaW3zKsIFETZAJcHuD7xRi8BttnxkZTCiFn7zp+AOUIuga+/Q + w1mGFP5tDK2U+mcKoEXvXIxGBS4CSKueUHDxTyCxdWas4LFYkGd4fKM7XK604RqByh+301RA + eNU/3uCcRitftaLemX/R089S2HETU=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=a; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AMS i= invalid value", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_struct_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Duplicate AMS i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcMessageSignature); + } + + [Test] + public void ams_struct_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Missing AMS i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcMessageSignature); + } + + #endregion + #region Arc Message Signature Format + + [Test] + public void ams_format_sc_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=OeNJ7p2NdW3mKv4hyenx+QbRuqqq8iwGAyY1WVX/EJiPHS2vNB5lEI/YmVB3diTkKPHWe8 + ZOq18DTVtOVuahLqM7s/4K/gvx3zal0vcedPL/mtRW4A1Ct0/wyLuFADX2HZ815cELx81SuX + 3fEbbym1br+0JArsz6n8798lidnWY=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=NOLE9bNh30qiTx35h5yKbHlDPahxvhXUWjv8Yiy5L7Ks3NNznK54dmUPZ4D/80tkRYiil0 + 8sCqFTh7OH5ZTXXEfArxBMQQl3DAqTjOJQ1c3jPYwaDliWqCLLueSsH+ovaFGRGNPm2O41o0 + J8xUmyji1bXXLKMinB+Adv9ALXsw8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ= ; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams format tag whitespace around semicolon ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_format_eq_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=CcoQW04QZ7n7OTPACcP26R0vJtjEwVmcFpj4+PJnvT1kVeOMfcqwt7FEGlCjeJ0QIYMeNW + TY6kND0fe0WJDVnWvhCyeOb5JjwllbJJ/ThP74I5UPgQ0Cwp1h/O9HIrUJkrje6HQ3nD6Dok + la2keL/t4R7YtMyAmn9sPWuAOwSrE=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=KLZ8Io9rZzsWt0Q/Mrx8sYO7HPLptFwGoCdabHuyrQsek+1c5yo5tOQidcTc8ksw5PoAZH + PNOIoyGVte9jMk0LdA1IYjjvvUmEANMZCJf0wm66exDWJ30xMrgbosLN2XvsRk3BDkoCg2AY + HkR11isMdIhrefd7AHw9YEDTnohQw=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c = relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams format tag whitespace around equals ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_format_tags_trail_sc () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=Q3iCsG7zmlydzz8zFIm4X+Nyr2636znsyGh+lRhCFtcWbw3m3v8fFrtK3uNvqSM+WW3Cmf + TbteHFaG9YL34KUMi/ThuPoG8sOwJ18BPjXrdBS5EiXYBBFalkVRV0ktqyiNi57LBVS+VGWV + FwOD85C/V/Fju2wETdy0ly1VjfLBg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=H+XsRP2HBJwygQonE/YquKr2y1KqjjlhBQ/hEkIGFjjNhOIvMfuuO054H4+kxMmvHFdwk8 + a8Uwy1MxQBC3a4b0jAQ77rOn5VFhO1tAmCkfZP1bJSxewRfC2Eo7j/07+r8ZLuyuAzlQIW+n + DPJtOhnIIEOGhLgPNlcTwc9R/XKiE=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345; +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams trailing semi colon no effect", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_format_tags_unknown () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=hnT0gH/efgds1eGi2XgAPK5ts+d6QZHc910SN6Xpr1TmDPXpNoRlq8F4eeMTj8VMgLWOza + HeMe4quPmcWlZm0vRkiUxK3Q9HJlclElB9ehd+qPKzE92zWdSnkQN3kpyoA9mSAn6eTUmX9d + ZFCA8DnXTQSl3T7V4GWwO9byXtHmg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=jHH5JVvEmO5RMAl5NlbOHuIgc72768gwRv2MjCvgh83McNt2Ogx7yFZTPfcyO9F0jT5EIz + bOzMeH+vIBJjJZz1/FVpBUxXJ7Ir5jQ6rjDGCvztrqeSMkhyF2pdiGIQPn6HuA0qDjMY6IfM + wGoYUNqNE0+2s5p+DuxXMbT0tZBv4=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345; w=flarp +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("unknown tags still valid", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_format_inv_tag_key () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ= ; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; ==; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams format invalid tag key", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_format_tags_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("tags are not de duplicated", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + [Test] + public void ams_format_tags_key_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; H=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("tag keys are case sensitive", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_format_tags_val_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=From:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("tag values are case sensitive", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_format_tags_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=1 2345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams tag values whitespace sensitive", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_format_tags_sc () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy;; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("additional semicolons are invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcMessageSignature); + } + + #endregion + #region Arc Message Signature Fields + + [Test] + public void ams_fields_i_dup1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("duplicate ams i=1 order 1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcMessageSignature); + } + + [Test] + public void ams_fields_i_dup2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("duplicate ams i=1 order 2", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcMessageSignature); + } + + [Test] + public void ams_fields_a_sha1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=wO65QnQIWl6SnCuXSzaqpFWd1Iz5y/VneN5oorqP3XDWkXh6SYZ/CCIgdzBYqDX6zzKXAW + /qC29Xl3klg9mg6Epteb3Ie/nmUDCNiGoBF2ZGWW4w3CgYYBJU2nGitvR9ytKZ9VaNJkXqr/ + iWEc+fuCSNgwbAXMe4WeyT1LjU0QU=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha1; + b=JxQvoennMmz4+A7Strpsa5XUkbwuHHwNZW30eUytxb+M28y/01pkSXPKpsbLuZItfjJw4h + AIiLraxKMj+Ene95MTUa1Xqk1fzlKTo+mhfpPOwn4pBmZaJilCx25pRNgSrs4uGX79vVcf51 + xiN7GF0ns2hGx7Jg/YTeBsVL9ckd4=; + bh=bIxxaeIQvmOBdTAitYfSNFgzPP4=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("a= unknown algorithm", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_a_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=xOHf2jEcVrFDvr1gDUYPzfVj90l2aTOJmU3pQXz7FT9tp86svuVyCZqh5laLPdunneTVgg + wgejwf9PP8A8wCO+HHjMwZF16ZUE4Yqg4ZMjfzUCmK9fv2iT5qx/k4Hl4F6aBstcNhODcTpg + bN/qhpMAtJqP1+Nk+SxDgLEZPqwNU=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: + b=iu9yW2jX7187Y2/yKW8Z3a/8lIsaKvek4h5lscx18jk45kfztcCuR6adEtBx3/szzN5bVW + iU6qZgimS7l2VjfRhNFEOTzhpxXO20Pd9lJ9O07Jk0CzdYd6PqB+anrPz9+g7+3Bqn+MzhEi + j5+z3fy6/xMhdmISrSWwpGbT6Jp98=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("a= not avaliable", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_a_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ErVcYmPHoKhcv4cUMAAlK9Z5tZ2G66c1PD6uaqj09ab7YOmLJ/4SJNH16m51n6oRv6uBtO + Qp0ikKw9DAG/ZFm550lnr0xwDxgo7C8b26FC7187QlNoW1/we0SFutFo6XqJGgmQsly1glDi + uyECgQHiR2C+S1DHpYqSMGhl/yehg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=; + b=zVPKQ3zrtroGYfUFOyR2TJFk/T+2BorYCDkmE6KSBjbhNFtvx0W+5z+Rnz5gvnQJA7K1Ob + CdP9IlCJGU9w5vYfsw0hL2nksu+1b1sgS0FZv5N2AqT07Xc+B4xxjUnddUojOdTp33k5rpES + /F6U0YUFq29+Oec8F/+849FdJIFo4=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("a= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_a_unknown () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ZIVn4O02gVZZM69shdqjhGG21S6N8/WPCWKj+NQgoDtMuUYmgIaKkWJ8MyzdiCH+09lKlC + OeftQqHOztn7eqsqG1+JkY03J0WR1IKcyEJ01mKrKD1FEm5FlCAYfk0zl+S58GDXNC70d7EU + Ht3EPiXZ237m5+ZELA9ER1wDP8NDY=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-poptart; + b=kHGBG8KmUtKvaOluO64HVWcSrN7/F02NkxyoDqkfZaoF3brrCj8PWNf9njKc03EKNScVgH + /77ZoYr06Fsv+cT352CerOJn48/Rg2k/OZFv2j7Cg4b4BOAH0XYfNIw0c3wh3h8P6ML7qk0P + zE086JAU7m/JHXCmeWdGMOWxAgtDA=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("a= unknown algorithm", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_b_ignores_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=L8GsQ6v/7miEWKMGu16QVCPF6IT8j9+DV/ZHzgm86gi5m2JYAq+BlkmiIDofRPW+QzAq85 + 2UlxwI2NZrhyAKgtM4FKO7+84P1eYwJKh57DZfCyUpqRx1Je2+vzT8ZggXQWYjFEu36MTDFX + fRKVqPV3omyP+CFBzjJFFDLehJaPk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR /UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= ignores whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_head_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +FROM: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= canonicalization header key case insensitive", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_head_unfold () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe + +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= canonicalization headers unfolded", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_eol_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= canonicalization eol whitespace stripped", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_inl_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= canonicalization inline whitespace reduced", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_col_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= canonicalization colon whitespace removed", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_b_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=OzRrkSWsUTrQ14yM/vnwnE3FBgXOC8u2KaiR+kqtJ3fZRudMM3gZm815dG/TaYTIw9Ia22 + voygKoSBc/48fUYFcmfKgwHHW/mlqHqP/eLSQ2/tQR/R+eG0ldsqj9nWhMfqRs6eNU32LMOd + fpk9IcVRPAx8Uf306RgvfMmwKrwzk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_b_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=4Crgst3Y5S/zOuKhpV14MKa5UBleFxBwmEeGMfTBptTZ+Pr9UcLFTmbWBCP2XkD0l4++kz + LISbCEDLFFzPBXxi3p1TxUa/i7Ib1/F4oDSIwu4r4dGYoC2aR9ah4f1zjj2JM++V7PuFcn+Q + +wETBwEKIM/uP4VabDjLAwhLfuvR4=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_b_base64 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=DMVLxkygsAo8oIVh698NtvdqZ0RspPu/YPQqcSNFWFjjsfcF4hZXE3eGkrze4nTfz5XB6p + s/210+6vqYSJIxMVxRJxO8wd7xQn0MyG/1NeNoW9qQdBuajHIPhgjCvJe2jnnvHn3MvaAjXR + oh+Jco1pmRfeoLBPqPJmEvDW1/9F8=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=not_base_64; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b=", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); // FIXME: better error reporting? + } + + [Test] + public void ams_fields_b_mod_sig () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ukwKeUuHm+O5bA374QNtQMipl6EYfgWlGGfgTGznPEaIFiTmV3A5lhOnCEGP8tr1CDYDl4 + yo32S/rA3I0Z+GHWpo6pzcnh3+tvCBuwoxHZ5srbrTwOFNQWmPC2Bfwu4fetM8d73/wN8uKm + ZziB/Gd1VTLLCRa4xx2C9QM+nYEQU=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=7sRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= w/ modified value", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_b_mod_headers1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= w/ modified headers 1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_b_mod_headers2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 (Mod) + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams b= w/ modified headers 2", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_bh_ignores_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=E8x7AZqCzrIuoNF9dWTyteDmtDLHk3J6CSXj1DfRHjk2cd0oeHUIXvtrNtMhYs2sFHoZRR + NuVvgDUIwPcbtr2Bz9eYvUTuOToBRn9FZFqnpR/rHl5VbPAIhSwE98WT6PJt8pqNCyKyZU3I + szoWq5cB3OWUv6QJ8ctb6rCZLbk3g=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=xWBIUyGnx5WlX005xU8TYkieptAqvslDc7lkuqyFpACyOklw0t4cAONgr6qUavTnRJyZoJ + mXXIvvPk/7xgH9eT9lCFYk49vpo+fqZACxJwpRk6WbB3fwbfeZe8C2aL6X/G40ROlh4EVcy2 + +NjgNS2X9ZEmxKuGEehFLqaJnx8yM=; + bh=K WSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= ignores wsp", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_sim_base () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=d6sLFV7dCrZT/WzJil6ZyWcA/W5tJGLkP+yx1Fln+uZdjkswYMjvPkO2V2kvMrh2GBgjee + j9QiqfGHsJvGqAKrFVzxHEsgVA0IYN6tI5wTKMLgu09b8BeHUr49/XnBEemjbgO8W9n9SCyX + hKjsZK5b5ZIYBqjCSDZUwWRWfJywk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=c+pRG+RBumfEVWDAjHVupy4hZHN2F/AMLHoj6Vha9px35oo6eoyMxxOFUvBgVIUVphuSwV + 198baYTV6Of9DHw44VS5rf6MDZNtVc8lwm8ei8aSAgzSnuhnr0jW2j134QTsEL1TK1bWfs+l + QGXDBN5AUDsbk4jN5akoDqmH7gNlc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/simple; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= simple canonicalization", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_sim_end_lines () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=d6sLFV7dCrZT/WzJil6ZyWcA/W5tJGLkP+yx1Fln+uZdjkswYMjvPkO2V2kvMrh2GBgjee + j9QiqfGHsJvGqAKrFVzxHEsgVA0IYN6tI5wTKMLgu09b8BeHUr49/XnBEemjbgO8W9n9SCyX + hKjsZK5b5ZIYBqjCSDZUwWRWfJywk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=c+pRG+RBumfEVWDAjHVupy4hZHN2F/AMLHoj6Vha9px35oo6eoyMxxOFUvBgVIUVphuSwV + 198baYTV6Of9DHw44VS5rf6MDZNtVc8lwm8ei8aSAgzSnuhnr0jW2j134QTsEL1TK1bWfs+l + QGXDBN5AUDsbk4jN5akoDqmH7gNlc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/simple; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= simple canonicalization ignores ending empty lines", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_sim_inl_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=d6sLFV7dCrZT/WzJil6ZyWcA/W5tJGLkP+yx1Fln+uZdjkswYMjvPkO2V2kvMrh2GBgjee + j9QiqfGHsJvGqAKrFVzxHEsgVA0IYN6tI5wTKMLgu09b8BeHUr49/XnBEemjbgO8W9n9SCyX + hKjsZK5b5ZIYBqjCSDZUwWRWfJywk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=c+pRG+RBumfEVWDAjHVupy4hZHN2F/AMLHoj6Vha9px35oo6eoyMxxOFUvBgVIUVphuSwV + 198baYTV6Of9DHw44VS5rf6MDZNtVc8lwm8ei8aSAgzSnuhnr0jW2j134QTsEL1TK1bWfs+l + QGXDBN5AUDsbk4jN5akoDqmH7gNlc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/simple; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= simple canonicalization doesnt reduce wsp", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_bh_rel_eol_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= relaxed canonicalization deletes trailing whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_rel_inl_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= relaxed canonicalization reduces inline whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_rel_end_lines () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= relaxed canonicalization ignores end of body empty lines", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_rel_trail_crlf () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= relaxed canonicalization adds crlf at end of body if non existant", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_bh_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YoXbDMNRVADrsGTtqAuMLWVnRIj62jQOSDFCX875c5ksVoWcKstnor+cGw/PJnz0cPuFGH + +vjw3y+tcgBDDbK1qBVyMUpHrahTLL/0IY2jMzoLgPYz7Yawv/gpn7GlyXL72Vdr58s/nEfk + le/2NmfPZjlUezbwsw+UHbuqT5V38=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=m5y+bcsy0duHt1KxJ2EakY2mOpwIrFaHD60tlw1PmqNdy4M7XLGTnA10R7k1OsFAQNQdZM + n1aKsKDpYuRX21avSuDxximXFwkcWYevOqUmaklFXiWyJVXd9fHId0sEtNt0L28HInLwHeCf + IPYbUuddJ8wRWei04RZjqdybh4f2o=; + c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_bh_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YoXbDMNRVADrsGTtqAuMLWVnRIj62jQOSDFCX875c5ksVoWcKstnor+cGw/PJnz0cPuFGH + +vjw3y+tcgBDDbK1qBVyMUpHrahTLL/0IY2jMzoLgPYz7Yawv/gpn7GlyXL72Vdr58s/nEfk + le/2NmfPZjlUezbwsw+UHbuqT5V38=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=m5y+bcsy0duHt1KxJ2EakY2mOpwIrFaHD60tlw1PmqNdy4M7XLGTnA10R7k1OsFAQNQdZM + n1aKsKDpYuRX21avSuDxximXFwkcWYevOqUmaklFXiWyJVXd9fHId0sEtNt0L28HInLwHeCf + IPYbUuddJ8wRWei04RZjqdybh4f2o=; + bh=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_bh_base64 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YoXbDMNRVADrsGTtqAuMLWVnRIj62jQOSDFCX875c5ksVoWcKstnor+cGw/PJnz0cPuFGH + +vjw3y+tcgBDDbK1qBVyMUpHrahTLL/0IY2jMzoLgPYz7Yawv/gpn7GlyXL72Vdr58s/nEfk + le/2NmfPZjlUezbwsw+UHbuqT5V38=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=m5y+bcsy0duHt1KxJ2EakY2mOpwIrFaHD60tlw1PmqNdy4M7XLGTnA10R7k1OsFAQNQdZM + n1aKsKDpYuRX21avSuDxximXFwkcWYevOqUmaklFXiWyJVXd9fHId0sEtNt0L28HInLwHeCf + IPYbUuddJ8wRWei04RZjqdybh4f2o=; + bh=not_base_64; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= not base64", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_bh_mod_sig () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YoXbDMNRVADrsGTtqAuMLWVnRIj62jQOSDFCX875c5ksVoWcKstnor+cGw/PJnz0cPuFGH + +vjw3y+tcgBDDbK1qBVyMUpHrahTLL/0IY2jMzoLgPYz7Yawv/gpn7GlyXL72Vdr58s/nEfk + le/2NmfPZjlUezbwsw+UHbuqT5V38=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=m5y+bcsy0duHt1KxJ2EakY2mOpwIrFaHD60tlw1PmqNdy4M7XLGTnA10R7k1OsFAQNQdZM + n1aKsKDpYuRX21avSuDxximXFwkcWYevOqUmaklFXiWyJVXd9fHId0sEtNt0L28HInLwHeCf + IPYbUuddJ8wRWei04RZjqdybh4f2o=; + bh=Z3JlbWxpbnM=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= modified sig", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_bh_mod_body () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a modified test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams bh= modified body", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + [Ignore ("This test assumes that if the c property is missing, it should assume c=relaxed/relaxed. MimeKit defaults to simple/simple like https://www.ietf.org/rfc/rfc6376.txt says.")] + + public void ams_fields_c_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ygcIhWO/8u3FP5h+7kQH7X9Yqxs0MIHuMUA6PapmNf+8CP5Fb/mY/mZ5aUcLxJNozQ2oUU + ukkGEysRaqm5uTJMhiy4YjZgJqMRVka3xMGeIaSw1PiugVu015l8wKR1ollDSN7POJaajQBC + /4mUnAUFfND8OqfE/VimB6flYiUJ8=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=1+WHHTxU+XLWVsbRsvjlW2kMRRhmGE+OE9jxnmLt4ryEa/AezAflCMmVzM7r1dKwxJA1oc + YmkN0ga0CO/nxSvB9XR0dsg/TH7TTSQKIllCRxsmGLt+jG/9Mw5yTRxtBOOuFK4xbHbFbCLU + vRCry9p9YZpoAemnEb24tm9vjlrsQ=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= not available", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_c_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=eTLQqvFomQqHaOc36izhl5UMp6wVe8vGsLLuPCraumms100F7tOUhRpAII90YkwX0AK+RT + 5ij+3Ngk2sQRpMupfFTgeF1olGU+jt943VkFbmSYXYp0AwBe4TGsLugWmfkUy2sGBSC1Rv7n + ZaC9m6Y2bNMJcwix1EAuFFV6ck1Wg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QdAvD1bnatYxK/JQCvI1uSuKxOYC+oR7wqg/twCt+zAFm8Tvu+fZpO79+TSx+cLAETXKNT + 6mgQLaLROfq3sNf8tP0f/4oqzMUb6Ybz2syHL7hkmC6Za5Ii8RDKwMSc8lmvJk6HXUKgsndZ + vWsQCfv+jyLmfDfCI8v9WP7xa2UEU=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_c_rr () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= relaxed/relaxed", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_c_rs () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=d6sLFV7dCrZT/WzJil6ZyWcA/W5tJGLkP+yx1Fln+uZdjkswYMjvPkO2V2kvMrh2GBgjee + j9QiqfGHsJvGqAKrFVzxHEsgVA0IYN6tI5wTKMLgu09b8BeHUr49/XnBEemjbgO8W9n9SCyX + hKjsZK5b5ZIYBqjCSDZUwWRWfJywk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=c+pRG+RBumfEVWDAjHVupy4hZHN2F/AMLHoj6Vha9px35oo6eoyMxxOFUvBgVIUVphuSwV + 198baYTV6Of9DHw44VS5rf6MDZNtVc8lwm8ei8aSAgzSnuhnr0jW2j134QTsEL1TK1bWfs+l + QGXDBN5AUDsbk4jN5akoDqmH7gNlc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/simple; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= relaxed/simple", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_c_sr () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=rhXdX7jNW4wMS/SjYKBYC9eW6q5KnnQ7UGICE45CsYhwEoi38c3nM+91lvM3zhUILxo51X + htsrMDLw5TJeZdiCqgXhQZmSEzR+KEdnu2oidezrK/hUzYPlKdO59EQgGIiDAmIRoKZ6+rGV + fUCltnyjA07a9KpIpeXRKT3WDCE6A=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; b=RWHWmB6euT01CXN0PJKCrmmoPPGc+pxxurfyJBjnNzkTizZKD7XwHLqTuNPaRG7PULU6ffq8FQ7IivdffwqXNj4L3ttpKNIjfsndMFvn5lpKZGfvJZfjTmbTJMhF4CCJZZm7l1xy7LbYMaMb12WY47vXOe9RNjW7jQyw8iqctcA=; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=simple/relaxed; d=example.org; h=From:To:Date:Subject:MIME-Version:ARC-Authentication-Results; i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= simple/relaxed", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_c_ss () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=X9qtjasr0URzC564MZz0bwckcIVnBW9yUZP+xt4rStU7MIuuo266KZ1V/e5tbg/MOCZJ2m + 3hvKRsVy1fMeIus2RVBg88zwfjyRMsJBC+zKV8oONpIcxriN8imZcaeWdcfsghbAFBM3viCE + MdvebSvInMfz0vZsD1DJBYTjPel8w=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; b=fv7KIaPfZRTQynzpQ7Gkg3thdZn78iGc5L1hTQoWrY1nSaE3pqQTHsGDW7+FRquewwFoakGLSERxBnC67Sdvw9Exv+/CEs/spqRrDjNygkCf/BIZcURb2nXXFHqPy31X6r2bufWKj6Lbo+5MCyaS2tWkV+KoZhUpolYSo0CoGfk=; bh=hhFbTjokraRYc/Af+8v4zyKm/9ApHGkBSLO129NtPbo=; c=simple/simple; d=example.org; h=From:To:Date:Subject:MIME-Version:ARC-Authentication-Results; i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= simple/simple", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_c_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YYGtMgeVAGSLLMZ0k9D0yRRzsfKpbHCoqfLAKz+Du2++GE82Dvz2OT60ebG9m6vmT6nT1t + D+rMJnTXIZDUPZ6BLH8rLo8jMb33cBV5NzBD3SDYqWA7OOkYrMGRGmoMfxpcGV8m77YykscT + +cpxxA2Ytld+YTd0mTtxdOCN3T1M4=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=DJZENNFBf+SwDthFmU1ztUBIsKRAAaUdY9CjuGXejv8T29jf3q3EDUz6OnMevRWiSLj4ED + gymMDJNGSTUaz3N85KmzWrTJ7QOLNke1H9L9kkfEFowatF8fW5cV/7Y6Ubzh0e1626TELeE+ + kvczpXT7prdjJZZjQAbDuHsWXkOys=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=pancake/waffle; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams c= invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_d_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=xPtYeQQruf8zzJ9kUrMESmH9ooORAIArDB3MhPcaL+0fgmuc99fprb+aMaSqY6OdZvAEoO + EBczyfdtlGKcqLqa5qpXYlukRfG3q8mlOd+8UU1u1bikCzfT/JI8PNerzaoxlksJfmt8zJT0 + f40IWBJnoRpPNqJSBFb8acvLVZFcQ=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=iDLI16Dzhtt9CmHLpkUXy7d5legcVvxkPMStdfrYQfNfpwVia165ca2lGI7Sx79pCoMmy3 + sSWBrLHsTQkKylsGswc0br0ycquKhxHgQh0WChxQd6ITVGQvFO/wZJd2jtE5E/KDbPKDjEio + qLfCWpVe2KT1UZ89V+E9tg0T5TgwY=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams d= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_d_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=Nn38++8Vf80guievTz8fSFN9VjbPdeRVR5LmvzRt0IMRzZ75FThtzO1VM0grGeUj+D39ri + 0ZwIgNyVtZXfG17FEO5BGQq4ZddLQoWHLKTeOWXL59FPhGRJkxiKNefS2c5YqZQ0NI8VkKY0 + HQlX6AeD/CHHE/bpcg7fFB5/WWnLE=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=yKCB5xEcyzGr2+mbXWsVDHDZB1PYe9MqqTWySS7Y32uFObEA/MNJmt5yPnZLScwQUhzeTc + WL701aDMyPmlYlGnqxl2/QkvEw5hZNfOmD5gltxTlIabWyRrC1Qq/1RS2zDqvF2Qf8SJL1U7 + gL6jf82iBTT61ckhPraYGIdgI9hlo=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams d= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_d_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=G8wYXXsNzfrmW5ob/HLkPkg0hz37d0O01HmLr8E8IQUPAa4lywxmOekn0bmKfOvK5p77Dz + JEue+awK3gHG7/obHdRLamg8cYxmj4qfR6Ay0baikigUF4Wyt77JsVUqCC1qedRNcRN3IGPx + 7rrNSyzVlIWYPal3pQZc3E1ClpG2I=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=rllEQ7rbed0w+ixVEkL/jiUZrjyDdTQ1d+qnNGEvpzzjh2xFla14BKDcXo7q/aX25lxl0e + yzw6yf5PFJC6JWqj5h3sFtLO6hS+E0DXyPZx0ok9tNiv7QV4YqY9fWeA64OZD183DKISDZnD + mx/r0Svb5thGZvzvyfuAQapHke/Rk=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example...; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams d= not valid domain name", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_h_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=V/iPFUptKaruDTBpwKcf5i6nu54GxrG3ss2bfPqqT3I5MGMyRmtE+J0kOVtU9qtHIhXUng + Iezv5+gCOIf2jP1eYGvhN2Wmkf2zsShG6+Rfpnp9fih71C1f6fh6Qp4tTUhB6ww4ZOTKtVdv + H0C2s/5in4RLMxS0FUWge8CvlTnGs=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=ex6hirqdOz1yO1SZE3ALisw3dj1La5L4qHcv8/ttCs1qGajzw0zEtUyMnskTPQnt9cxxF3 + T74KRXlPVN/4Aqn+K/Q4NHtOW9vyuLt9ek9Vm6/xvZ10KTMrxv24u0eLnsigC6NfablL4wAM + epZDlyjf/HPBd0yVLQL8yFDtQ5fE0=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= empty", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_cws1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=0+WA3Dpt9Y1lJ5wkoOZsh6KXEQFv0YE+ykvXAdS5t1toEui1UWzLyKWxSD/H/Xc6eCaQZM + ji4IxybZ4OrIdV0yRe1fGqYN/bJ3KnkuzrHpaikXRWxXdX8tiIu5+I+HmERxuGzGqHdNv2zj + 5L8PNAsGs4LDg3xQXEe3FQAvis9OA=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=Lq5Sy1R3C0RaTxKWfggKBJ2MOdgAHeFy1nELK1c+CFnxdvSL+OxuvSxk8HYv7YMJDTR4Na + 1D5GaFedB1uYVQsz1T5e3p9B+54W4bObByD14WvTGKV3ys8FlOf4MdRIlD4o6N3INfHrNbYX + zwPKjkoYbteAEQ/kTpjESOpm131io=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from : to : date : subject : mime-version : arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= colon folding whitspace ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_cws2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=0+WA3Dpt9Y1lJ5wkoOZsh6KXEQFv0YE+ykvXAdS5t1toEui1UWzLyKWxSD/H/Xc6eCaQZM + ji4IxybZ4OrIdV0yRe1fGqYN/bJ3KnkuzrHpaikXRWxXdX8tiIu5+I+HmERxuGzGqHdNv2zj + 5L8PNAsGs4LDg3xQXEe3FQAvis9OA=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=Lq5Sy1R3C0RaTxKWfggKBJ2MOdgAHeFy1nELK1c+CFnxdvSL+OxuvSxk8HYv7YMJDTR4Na + 1D5GaFedB1uYVQsz1T5e3p9B+54W4bObByD14WvTGKV3ys8FlOf4MdRIlD4o6N3INfHrNbYX + zwPKjkoYbteAEQ/kTpjESOpm131io=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from : to : date : subject : mime-version : + arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= colon folding whitspace ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=me1uYrnpt5Cdjkfj+bqK8X6abs8TET4r5Wp6e6ZuZ2FAtSzfx8WdnHCnBLUj7t/PR+EGne + h4auyljzkm2gz09I0MbaYkd+xDmkRoN2WrFotceq+iROoDLf2NgZJb3SfDcVFp8emRMyyaGL + WAtshPjJWnjoNfm+3clEpXzPw4WM4=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=OCzwOGeJy6YL07Rh1A970C9pAK2YJeXr0rDVVbsd/aOxTeKbrIxOfQsJ5hYaze0aeE5U0p + y/45cz4Jg07Ch61xZ0G3R3ne4eXxPauAU6QKPwr45HxO2gDywmNruiJP0JPTzcC9SVV/YjyL + OGobZNIwUWR1hEkd5/UuAXHk23Q4g=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=From:To:Date:Subject:Mime-version:Arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= case insensitive", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_dup1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=tv8fgth8OQw5DylJlW253wBM12VcMvjFLj+TwonVXPiSPJ1hV7F24q0rgmYeVhSBK/+4Ou + kPW3e9oqILXx95sXrE4fiiz46//FtZK7z0YVzy/B3QpR7fGxzzA5uVoUh4WNd0oQEejwDKss + ILrzkyu6fDUZ1kLeKyk3clE7b/NJo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=rGZpmx8nA8Fe0yQ319Ns+DPmwx9ToC7Z5Ba5NNGYtmXF87xboR0Cy7yxlJ2ek6j8WqCRXI + jKV32tgZBXu5upoveTLBGzSe+NPTL2SkU2nFnktJjjPwTiPAYyXVBY1Uy7uSv9dT+wfB4Hvg + Hm/nSrzqTBOxPsND1F1b2rzE1elQo=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: morty@dmarc.org +To: evil_morty@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= with duplicated header correct order(bottom up)", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_non_existant () + { + const string input = @"Return-Path: +ARC-Seal: a=rsa-sha256; + b=cEfCkdG3zAUpq2XMYEvcI8e+nD53NUuUr/NQ74UBTzSVJBOsNQKADtUWqYirSlB9AFeEIq + VGstwfXqh5TiMv1Uk9O04vM7WxrmMsqZI+GiRQvtaanfZQMcaYME1pCURdkDbMK/MOUGV+W2 + j9anSPB91SOQruKUDtqgwq8z87Ajc=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QHma3KzZiiP6Yq5jWp+mLznldNAMpK9ffvI87mbvEFFd1YSfoJu9JrxtBgv3/MEBFHLPm9 + qTii8g+94xOLgp/LEC/dM2E/u7yPAKKMz5fMzJfwqSGAGyBg2f12Mkyaqs3dzv97nZTZFkj8 + mHCV6SHNfnC+lkIs5XpJNRtddvolQ=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= signing non-existant header field", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_mis_hdr () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=FCq5UA4xGNozfvMgZkQ0Wpu4Q0dkGbrNvMKc0SNQnbObHCA84DNwUUp+I41h5ZvwQBAGxf + hvUfjmsMFHBtsYj/aQ5kkehVPkOZ/6hengnO0IJs78Ab/5eivdD7MRLuShcTWd9qx32dVFJD + yx8qIaRZplvJYl30ry7sOJQu4qSZk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=4TbROXpBlHvYUMMvecTyaEqk0DtgISmfrz9L7QEizbAaI6vgDPu1xD8LSj4CfHpak6GMde + zpqtfiITgVTBKbkZi2kuFQwmu5xWsReExZEiNq7Tr6L5iObGjL0A27RIBj4znEmO6mk2Umnl + +c6LR5XzyE65FGLZ+9nSH2U12klzI=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to::date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= blank sig-header", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_non_existant_dup () + { + const string input = @"Return-Path: +ARC-Seal: a=rsa-sha256; + b=akTog4W3hR16mF9pNZIhHzcceyST1LHWaIsDPobRX6iy5jBRbpb+lyKlcyZmS02T2kFYG9 + iOWQ6UZruiQXQu/u/GSkn0RSCwHWTfb25YqrQBLwH7pki4bDGHrTSrGbuYnFEHadYl2B8Gxo + UXYn2/XBBil6Dkku2SswdN6RZhhoM=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=CvqFe5bB3kFEFvITOTVx7VcrJQBT5aAtUJjX0h1L1Gh0MtUQofgKfOakgKr5kUIxv2foZY + KJzwNSuUNnDyY87HJeT02j4JlpYnj0+PzB8xjW2Kj4/4TrLMkcJsfC2wujZClzXW65uCsFEb + 0ht8EEQis3581f6/S2V+2pHxvqRiM=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results:mime-version; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= duplicated non-existant header field", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_includes_ams () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=XSOc6bESO7Ek4iCPyVXVE7aR8HUBBOXdOKmFpJO/3DI8rLRHHfRT9XAML3OsBE2RYj+0yd + ypsBg8UQEewpY6Z5KEUhxfzwaBGObKr1pgwjkYiOBpPTV1Xfv1lGT+1qlJtBR2AGJauCEs7G + fNzwa3MI+iO9E8g6aO/m9Mk1BlLHY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=vpypMlcZNGmeVETFS/+v/Uk9npQE1LhY8tha0XTaeeNMgK1fzWaxvUHY0cuumuzK2pU25O + uWTt08QEXczUR/BLmiZaYUWQV8qGOAv5umtEshqjB+0KPg5W09N20vQp8OXMQrenjZz0YPsy + VweEidqd3HAcWSbZgW3jAFKXHGSXc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:arc-message-signature:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams fields h includes AMS1", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_h_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=O9vrOnKLOdZXxa46F8RDPTzqW14JYE7idGn0AfedcpWh58mPFE9jXHeaMda5L59thiQrJN + T7Smno713R6DU9CfvnOvq8rQXCJ6D7GzWFhhOn6wEbjTaFQQ3jHn67XVDVnb4yjLElVhixob + pG5ouN8U1TPqPWf+41wrIrCd5Mocw=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=RidA92CmsCgK81At2aPnlGuFlbvNT5IdWz7Z/6j765oabi0LEDkpB+2q+C5TJfc28Gj0Ok + gghf2ykPbb7WniSvCue66fvUYaABU5m84urSzGd3MG3F47vTzCQ5qLah7E0UssP2QbP2b1Rt + Hry/RlkOzlWeSlxpCcPvArmmcADTc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_h_dup2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=tv8fgth8OQw5DylJlW253wBM12VcMvjFLj+TwonVXPiSPJ1hV7F24q0rgmYeVhSBK/+4Ou + kPW3e9oqILXx95sXrE4fiiz46//FtZK7z0YVzy/B3QpR7fGxzzA5uVoUh4WNd0oQEejwDKss + ILrzkyu6fDUZ1kLeKyk3clE7b/NJo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=rGZpmx8nA8Fe0yQ319Ns+DPmwx9ToC7Z5Ba5NNGYtmXF87xboR0Cy7yxlJ2ek6j8WqCRXI + jKV32tgZBXu5upoveTLBGzSe+NPTL2SkU2nFnktJjjPwTiPAYyXVBY1Uy7uSv9dT+wfB4Hvg + Hm/nSrzqTBOxPsND1F1b2rzE1elQo=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: evil_morty@dmarc.org +To: morty@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= with duplicated header not correct order(bottom up)", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_h_order () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=vTCiDmh8p+YFqH8WSxCrLVT3IS1Xmt35hs9y2Fb4EriRTTEmD7lWa0UrCe9j/a3yftcMAb + 8W01KgTrdIhmUMF7YrElyT1cGc0ChGHmdkuA2MpVBnLJMCgtXEQkWcVRne38KB9P+GLvr5uD + nBOjOJNoBt4Nt+Y8zCKG/tN2RetKk=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=2o+Wl1gzbDmg4Hv5q52M7V+E6KBhMISVmqTDrk1HfOgMJwJ+0v8Nl18EjbL+iOTu6Vxz9+ + 1m64cPsNr1Tgm79jjqugOKDI/yaU7h4DaFMmN54tGX8j1ElMXSl8ghcfaknApLU060vKVUoo + F2GfD1qo+SSox3wkZNkPQdGKjNmQM=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= mis ordered", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_h_empty_added () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=cEfCkdG3zAUpq2XMYEvcI8e+nD53NUuUr/NQ74UBTzSVJBOsNQKADtUWqYirSlB9AFeEIq + VGstwfXqh5TiMv1Uk9O04vM7WxrmMsqZI+GiRQvtaanfZQMcaYME1pCURdkDbMK/MOUGV+W2 + j9anSPB91SOQruKUDtqgwq8z87Ajc=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QHma3KzZiiP6Yq5jWp+mLznldNAMpK9ffvI87mbvEFFd1YSfoJu9JrxtBgv3/MEBFHLPm9 + qTii8g+94xOLgp/LEC/dM2E/u7yPAKKMz5fMzJfwqSGAGyBg2f12Mkyaqs3dzv97nZTZFkj8 + mHCV6SHNfnC+lkIs5XpJNRtddvolQ=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams h= signing non-existant header field is then added(MIME-Version)", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + [Ignore ("I think this is expected to fail because AMS2's h= includes arc-seal, but MimeKit passes because the signature is valid")] + + public void ams_fields_h_includes_as () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=OuFcuRk6CdaxxeBmCdvzoFxM6G0xmA3XNh1F243uPQsstHJ+T0csqD6PADig/UPV/Aj6fQ + kAOsyZOzIK1X9ZCZLB2idFymnyWtYc2spNgCiSfwQiQuS3SFVUtr+Y7v58PtyAy2HCb2pA5I + OIY1WjbK1Pd4SrJbZ4/M0d0wgFt7g=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=T5uPa/aCBkG1PK5dsSgO5US5yVvKnf/DAsyxMDCLVgw3auULB52XaLkZbc5KAcbGwz4KQZ + H8TTB1qbdHGyUpA/1Tq4QveM4z1x/s/2gK/thnoW0wWEHu5frgmd3tVg8kEjrmU6HOJ1SNYq + Qgjxvsd/OwpjYsfOjODwgyGDR/doE=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:arc-seal:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams fields h includes AS(1)", input, locator, ArcSignatureValidationResult.Fail); + } + + [Test] + public void ams_fields_s_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=zlVnN6R6lixbru5oAlqBAalgQAcbqVJi0fZe8u57TJTTLHNl+LRLeQRsLQ4OcZ2n5XLTSZ + ZAEsfzFQWeFruAnDpA7yT7/YTUYvQM7KdVzx4vl4FSTllt1wb0UJ0SNjlNGiudA94D43LOsx + CsESqhYaVWRz4gLkD2P6FfqZLGCZg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=1yhACoFkMMv54Xwy9PCxFazQ8BtUb99MhAUEk4Xwq7gVqDoyND9X+pa8CGMYSNUOn2I4tx + 4PyDzLhPNf+a4AciBNvFhHwK4lljIQAS514NuaNfv3PR0KDkkoXYv8J1EkI9yAyvOzl5Ka2B + 2yNTkGi6GucEwUlu2Qrk0RYhOYOVM=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams s= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_s_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=iUyd0NGqGiWwg11FiLSmb+053tfp1baKV04kpufd+RESTCeMHlAHj/N2ZyLCHnCZSfgDTb + hJy5KSpxO1nsSOlG/FsI6zwfEWCEP91aNjzEQxrX9iCg/zihZ9uv3wgmSOasjjt2kVGCcJUM + iLpzGuccZW6C0S8QyOA8ClL0cHnrs=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=DMnmzfNSgbRhHJmeSr5Ahc9FzG0ZFQxd7FVPrmmbpB78dtA4tjLUywkekiqhABliJzs0ut + zzkNYHyP0hlxGTaYOQ6OgV+1loymJCJDin9FhPV62CGOBXznuaRxFI+aWKHjW6SFFrZplQHG + UQcAeHg8Dd8tdKV4dgUnuW+aphtiQ=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams s= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed); + } + + [Test] + public void ams_fields_t_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=rx+UjBcicBZ6s5/J7S5oMw3YVWAWg+q4Sb4XqR0tMmhOyhjLq7702sEFlEDHJjdTuTVMg+ + c2qwv/XucEGW8/i4AMzNgkzpwk1Icsr0GHGbR7Jm8V+k6Z08tvQ4x1UaYgrTKmSQeyKq8rQQ + rRdzsqqX73OFp/cKLa42T3JVTrQpc=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=iRbmo9I0Qn8ZELD2xJ754eoEATUfoRxli5qMUi3AQTwGLHU6oaLFsAP7JDYjRm6al3XGp8 + 73NpnbncM6dnqlBvKK5OmekgztBKiyo7w0Uj6NZbq2KJXYiVW2vAbVkNwy4vPNhMHVTbD/xB + PWROiovFOL0q2mHDT1KKLiSzEfrWA=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams t= not available", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void ams_fields_t_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=J1fBm2GXu8CCXApvRsyBIITcTcJ4MdgwPIUK2e+vU57BId7RYv2i7/ORWrImxasfuFD17v + oU0TUpKqBmD/o6ZdLcgxg72iaYN7CoN9uK9Vr1llrVHuhJa4WUW0XG+a3XqKB2PXJh0LckJu + 215qpJ4wqx+/6aGVuxQp5LXwktEDM=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=GO1zQzqzWlsUbs6Rag7bYFPB2LgxCLkex8PRM+4/IbysgHm1TVtsPCVAAYp8+MK8UDyuuR + s3wgba6Zgh08O4F3MGn5ouJmplCkS/mF1MTAuWF1BiBkzYTdNmwhESK3GBTDNgTzBwa0upsw + aYiT87hDd1aqIKekvR3ZyEtZAN0Bc=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t= +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams t= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_fields_t_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=g1Xr4aSSeSDH0CUBae/NLjI30AgmGDwAdG5BC2c/OuTKGROcimWkt3ikql9YlvBv/3O8AQ + fe1XJqEq8EwFpKgk2YvMiWV4YKWPGb4DVNn/N2nk79o2KH/DlXNU4fLGvae9leiu1E+KJERC + /sYt7EA0rffMCWMjfHivWEx1swomo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=B9XbvvEBkWcBoOY6hBRGeJLsADsuzM0ZRvpeBWgF/nx8itykfMZmdeVPzVY5SI7MRCi8jp + +RtfP938tY75D6wfNd4+mrDkHyEQFAiE+UlYWjZOGx69go2UQyN5+wocPHHps4n9j279es08 + zmmxQXWG8wuoq53Y1CfrwNyniO824=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=icecream +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("ams t= invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + #endregion + #region Arc Seal Set Structure + + [Test] + public void as_struct_i_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=2ScmNq/nw+PcTFaRUZr6ynujs8zh0C1dJiZhO7XwXZ1Wgqjgql0NJzCEPlZ8JLT1EF9vx0 + iCa9BPPYBmopN0d2UcZVRS3rkrioxlCXfCA9bFi287v/mZCAYY0vkEJqpb60oAuOTL4CImqd + FRzkc52yZZEYC4U/gPyluWJQ6P29M=; cv=none; d=example.org; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AS i= NA", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_struct_i_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=HDF/3ZvQV+3g1pPoOxLwCgVUgalgi68PMmydT4JHPFEq36jEkMwATstQulCu4Qexedp55d + 3SX7YupWVg0nkl13bghp7ax+EvGREVTqPCLjawLFp6rLkM24ryiJb4xwF9WtXHWZlZCJUfTl + kPUpNHxi52l0u75XeSe69lB4rCWOA=; cv=none; d=example.org; i=; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AS i= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_struct_i_zero () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ATiDsxkI1nXV+hpjshT3uFaKndUOSdfMdrGgmZvHEDmTWR2oWB6bNbG6K83D/C/JKKDs1G + 4XLhmWn+5wGAMMkFCdxkuqIxjco4UHJkBj+6KwlvJv5/1yxAyZXdBR+aF9eKrz9YXyrNgMsi + CADCxXR/5RV8W6sB+Wxrgr1CPkitU=; cv=none; d=example.org; i=0; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AS i= 0", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_struct_i_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=EcQ16Bmi1GglUN2XnzTmixnR74rMt6K2VhtnHiH3o5+nLA7IPD/e9EbMjnhWK+IKw6WTdY + MrNju5/13Hy9aUnUNDKRZrFbZx8bQzHk232QjFs1KLaUOwFUarbBEdHGmLRxLvSGzzYDXxFR + ISrT+Q+55ZN0f5zjJbkeNNr6TraBU=; cv=none; d=example.org; i=blorp; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AS i= invalid value", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_struct_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Duplicate AS for i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcSeal); + } + + [Test] + public void as_struct_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Missing AS for i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcSeal); + } + + #endregion + #region Arc Seal Format + + [Test] + public void as_format_sc_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=sQHCWC9A8lAbvcPG+3jfih4lRJY/A0OI/GBGE4AYHf8u9cgsxOvyCqDWF3mr91HE5PhNh4 + RZW95NC6qhxEhnXLaXswqco2JXMVR6/rM5Q49bDE2RtlNen7wubw56NoJD2A7IGUSOzHaAiJ + QhRTSoyG5OwNBC8+GlugUJi5mmZNU=; cv=none; d=example.org; i=1 ; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as format tag whitespace around semicolon ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_format_eq_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=u4XUza5aJKdMCwCMffAieua1x4N9tZpKlx7UwMcdgV+BuIZc48C3rF8xu6BnoRQCaulZmW + 4EYspmshC6cGg+kmYaWR/sbW712Ag8W33enEcoh35XLTg9QHg7zWvftk746RrVFb5Ch8iRsU + PJ0gkAieomzXwlqCIBZQD5Yz2LB38=; cv=none; d=example.org; i = 1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as format tag whitespace around equals ignored", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_format_tags_trail_sc () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=AcBD4PAxYztV5R8jYyYXKuMBWBRja89F6yBTQVtQ1FFUxQVYGOrFlnh3/r8/YtFt13NELg + FpYeY3gnzudk30PoZZvM2MG9h07ByTgl0lSEsRLhN+ZtqoHRq1QGdW8oqOXntI51FbKwBdoe + cHtLh18GzKAvazRWzv8//vQInYp/Y=; cv=none; d=example.org; i=1; s=dummy; + t=12345; +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as trailing ; no effect", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_format_tags_unknown () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=FriX6cOxgBHhZwNYHn0KXSWVqwHPNV6sRAKUy9iN1OqwvAK9USwMsg/P08yXrUH8LRaijm + msJjp0KUFYiffoQrhsxHwv1hJIGceJZB7lOFeZn7Z5aym4eBp7q7idwNyIaGKL7E0WzVkeAT + RQ5LhtOInN23gugfmW6z8MUUvow5Y=; cv=none; d=example.org; i=1; s=dummy; + t=12345; w=catparty +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as unknown tags no effect", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_format_inv_tag_key () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=f0DaIeWMnbbdvwQoBVCi3pw8hmSBdK4xfQvJH2BM0qG22MkQwBAsDkD/dnAML6bvVeMFjq + aaLsCccFC3IZGvOzTsxbJTmbV0gHdPdYcsfhctXtrHfc/KdG1sgnqp+oGjrkveFTYUBO6UdX + ncJFPHoSnLp6foW3V6zUO9mcuDmeM=; cv=none; d=example.org; i=1; s=dummy; _=; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as format invalid tag key", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_format_tags_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=IO43AZIKhbGLyWUCD6LAC3GeO+S9ET5T2SFkq/QCjOT5aChUgUziIlm2REH9SDMP6EfWwL + ex6l4ndFMruyh+ReaORg3wOaXyf9nM21VO/9GyWpNkfMnVIzxspuNhkPsEJz8QglmQdp1Yww + OItIuEZpAwkFDMzWFuenMY0RnncmE=; cv=none; d=example.org; i=1; s=dummy; + s=dummy; t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as dup tag error", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_format_tags_key_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=3RAGO9q/6XejhXohu4h3a1at+M3SQzh3NvUB6/9n2fWdnCAF/Y8fvEgul01qPYOVm75+sV + DzX8LwZ9M8xvbpW02HPpiwJdSfMaSHfLFl7Eyz/X+iV/JhOovv9YoDfpkToqbisARZ6Zo4p+ + Ctok9hM0WxtmOjXqyOfFXfpMZRqI8=; cv=none; d=example.org; i=1; S=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as tag key case", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_format_tags_val_case () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=Example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as tag value case", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_format_tags_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=C7Te2RjPpFj3iKc4sPOTP80VHV2B/IeAl3AmyBOETgmdWrOe+q2lQ631QpI2ur/d5i9C6x + gJvRBbqlGya23VwHyaJPrP6IfWnXokjrcvdnyWX9kvhPCVTMrco+1ouNkKrn/5Rf8OTAYCzZ + daX8nbXMUANlFgBEQ+tvhb4PEMANc=; cv=none; d=example.org; i=1; s=dummy; + t=12 345 +ARC-Message-Signature: a=rsa-sha256; + b=Wy3KTYHj5wd/cRfKjr5Or0eOK0YXjU4HH27PRGwY8prB01CRav1Zh4Q+tOZRrTLbYDrPUH + QKwwxuKQ3IuS5+R9ugvuONhvNHLncIDvvjmK0dQV/9c+/ewkHBU9jZRfDxNMcot+eKUpZduO + xzUR/tDACt1ZkT1SOwRDAxaMs6+js=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as whitespace sensitive", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_format_tags_sc () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=qfPkkUJh95JfdvuR67QiOVg0n+krrwlShqIFXu03EvgP+1wJHVJy6M497OPlK1QC3FGXBL + k2Af5aTM9pyRO4bDX7N21jvGLoF2soMk9r6Er78OFalImdz7rRdFu33PR3dMCFe2cjGkPmAO + 94UKj789r5lfy2+QQwQskXQX/r3pw=; cv=none; d=example.org; i=1; s=dummy;; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("as random semi colon error", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + #endregion + #region Arc Seal Fields + + [Test] + public void as_fields_i_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("duplicate as", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcSeal); + } + + [Test] + public void as_fields_i_dup2 () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Seal: a=rsa-sha256; + b=IAqZJ5HwfNxxsrn9R4ayQgiu9RibPKEUVevbt7XFTkSh1baJ533D2Z6IZ2NaBreUhDBb2e + K9Gtcv+eyUhWkD8VTmE6fq/F8CDIK3ScIiJykF8hNL1wpa/mGwWWwBnkozIJGAbTAAX7AgnH + knAehnSW99TeU0lmib0XmOt4TN3sY=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=2cDGNznUmp4YSSThCe9nrQIH2Gpd5qPFw3OU8sWFzZgEQ5UZtaVQifVUXUrsSyEzjro3Ul + YPPDx+C1K+LbKRlOZ06il4ws2zlPafsrx1piKsKSCUq0KjFs01hYCDBa3tfdyITSfoWu2HHY + pCjrhPMPH1jruIdBV/5Gk2Fvy+mW8=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("duplicate AS i=2", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcSeal); + } + + [Test] + public void as_fields_i_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=uQtcSwvWdWWtq6seWx/+hrglo0DIevtxBse073F81rkPD9R2U9I11RE+rTyP1f49VmtxOX + dQQY3hMLr+174d1LdaOrO7w98KKt/sAHkuVGaeUrNCsaPWSVyECdoQwEIh140FzHkW+6DGcC + KYTb3l2Kb0/AH9RdhJ1kOft2hrOeY=; cv=none; d=example.org; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as fields i= missing", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSeal); + } + + [Test] + public void as_fields_a_sha1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha1; + b=4aSdpG91pnuWdSUXPchtTfnFSWkenWJh1zIKLwT2EVkCNJ+/5clRA5sFonDxmdOrcEgzrh + jiJuxnZVYXdIkvW9rMe5BOG5walucWYuNkuO7ph0kRX8DRITxwiZYhFgk8OkCITDYNF6h5vr + rMF5vOKCaWnpiGTUlPqBOgakyN9F0=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as a= is sha1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_a_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: + b=gwz9qNZBYlrJY6xGdb0IUhGEwAlOmJsjSfyp8FmWwlJs9URrrikXoFcJ5dJkYbFAZNfXU4 + 58XhxWSgJ8x2PMN2lkZ1TkL29SRhgdn5VAjnjHpr4xE/2i1hHcZ23Nj/bhXe0TOJq1n5hoKk + Atsos2ADb7r+Nf0AOnNle+/vTnS+4=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as a= not avaliable", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_a_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=; + b=ZVTTqGNJFz60CcTjJvJ2TBUgObDEGLOzdYTh+abJ+DiXUWfUJWxM5WD/dU3C0vjBu6Qcke + 8swPTOsTL3lL1v0ywSQCN+ZuFbEn7fy9AMvXadmDgEuht5qrtSQG9rsuF9m0VePnf6k45HlX + 3nICQtx7sQY16JBG4CTrBQWYSpaDU=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as a= is empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_a_unknown () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha42; + b=cTOOMtw0jXisFRCtFshIVNExbNgtOyrGNUqWObVvJPmMYBNbAfG3y1101xcd4nrfZ2skNr + xn12jM1JPwHBu5Ps4qjEeHDvxJK09vbxiOxviu5SDNhVUJS5V3l2VBagMpyuO5BL1OG6wjy/ + Xuzt1Iuhk23cJ5S98SqOVik9CCblE=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as a= unknown", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_ignores_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NV E6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT6 5S0+ vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= ignores whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_head_case1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-SEAL: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization ignores header case", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_head_unfold1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization headers unfolded", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_eol_wsp1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization strips eol whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_inl_wsp1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization reduces inline whitespace", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_col_wsp () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization strips whitespace around colon", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_head_case2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-SEAL: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization header key case insensitive", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_head_unfold2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization headers unfolded", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_eol_wsp2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization eol whitespace stripped", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_inl_wsp2 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= canonicalization inline whitespace reduced", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_512 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=DCbMvnfI7UzqahO9GFjYXa7DAcon0abOMQ7mWykqtdkEe+rqeQmsy1/pV9oAeSrT9giBqP + +cBNepG4Nycj93KQ==; cv=none; d=example.org; i=1; s=512; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=BFnboE5xz5OBBIZeB04CaX0QVCRysZesZNKLQLDbq3ohfHL0eIkMWyt/ZkP3+bg7wVEtyb + QfqbbfDRTQYC3GBA==; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=512; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= with 512 bit key", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_1024 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=JZIhBQD/1SCIn7IUrIoqCDFZ4k2tDd5joLebC7dCEbEXy6HURnayDygFjEiVwoVjF8XZPo + tDSWEVj18YLFQ08HZigNNDmhAdtIAeHs5bTfhz3ZDKGISGSrVbUqvS5QaL2dwaY5V3FhH1QC + VEohhbx3rJKMBiFCbQoCRo555WNL0=; cv=none; d=example.org; i=1; s=1024; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=jCTMZoXkSSVEusJyP9cbvAoKEDLphi95R/yaX9+gWw2t/RduqINzxPSVJZUq8uVCbKdB5F + BlBb2m7zbwaq6/oemTqI1tcnRaAt66Z0cyOKfPjRINTm9C8E3hUoI9DzplkwEoqmhR0wOjcJ + H6ASJr96Kl5qLu092VFaQYYxkwh2I=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=1024; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= with 1024 bit key", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_2048 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=R6I8tV4Y0pBQWId+r4W9L3TDi82iVPot9d+ux5u69ET/VUTQUPFAiRfTBqMKAm0dY1HCdU + JZggmlvj9BwZMOO9pFi8O1EXqkJ1CpNtFyNn76Get96owYXh7LlcP/C/a5AmxZMmvKblloh5 + 1rL2cNWicsp8/y3NS8jO0KWpSis2jK2yMn+r9gJ5gM2sUiBsKDwiYAhFBhjD8SFQOaG6DzLa + mJzCw9FkuGdpLfQoNDq2lLQq6APq8GihFJai7o/s8M4FItAMoteuqxIfyYuH60oX4qNOsaIT + B/6DnRCFshABODpSHRRIH4EvCu2fYYo6YDIU3VvDH2wOO5fQMcgvUoNw==; cv=none; + d=example.org; i=1; s=2048; t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=M0YyrXMDoG5zJ0ZjFzUqFNoDFatu/QxWTjyAH5wPvPRiSqw2Vvd4A1Al8VjYfmgbP4Jd8f + TFDZg1kWwLYk2IO/th/P6iYPfyDg5qp6mgao/V8NBW9P/Mqlb+xhkn4R8c44vmen9atIUV3Z + 04QzziVeuBxj+NFqxprbxf42Faxv5XymGmW3ZWVhOLEpwfcjy933drLsfZQezhyYlx4klptI + v3hKM76++GaIUc1nWXvmkeKKjEQLiUzqxd9Om7SRNArNe/q5xnVIaufxSfZNUtTT/o7Ic1Br + t7ZV8qwmj37sYpdZUo6H7QN+dp8E/J0jnbI0ZQU2mv8Gj3FqGOGzKwGQ==; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=2048; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= with 2048 bit key", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_b_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; b=; + cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_base64 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; b=yo-mama; + cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= not base64", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_mod_sig () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=kKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= with modified signature", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_aar1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=yo-mama; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= modified aar1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void as_fields_b_ams1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=I+Px9EfvrAFqYUnYPrC+egeUwxCg1LdNSIJ6v5sQfwua0Ox37z2S5GdknSdfjYKVDju/3p + 49rDu1wy6xLD5byG2qV2IDUCKmNH4QY6yGhb7ADmfrHDdICMYf7UDIBL6nUQsZHPeAUn5HbK + e/PCXEu9m+wpAEuDKvZxUNbNMWdQM=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= modified ams1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_b_asb1 () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy2; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as b= modified asb1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_cv_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=u92e/TiZvqtkvgZxGLd6EF9fZvoFJ5mqvwEkb3m5lXbgo8/wN+iliOx07lU/rOIsHa9YqL + QYUapWkkowhdKKFkixhefUUoeo9n9SIcpV8wywx3szGOhrwyHJIBCWr7nqaEQAS4prJzVZCi + 4eEkPPQ5OdzZGMu7j53QCVzdmWsdo=; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as cv= not avaliable", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcSealChainValidationValue); + } + + [Test] + public void as_fields_cv_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=EhiACA5ymmD9SeCvreg2D+83hTBtus1JsP2KC0CUBOgmdMeiGuCIHiJG5WAWpXhd9RQhRo + nxTU8kGfPl2sF2GAOujiie2cenkejRgwYQv+MLeRCT1MALEvrOsytShDl5reRltuX9ULPomS + GBagChWg+NI9bZGMxnntr38QPFj5A=; cv=; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as cv= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void as_fields_cv_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=cqTZxmxNU17ZUNfRJp6FvTfpkak6t2MCK65F3ppS018sPBGTyupD5q8GHdozKW5iCIaFhE + rZQmKOD2z33Z/h2eiFY101fFxesgDJpMgbeo0zGfgmJcj1v6nDXgq1FrUNPaauBOJV8Nb5vs + B0H2qSdtArOeD0mlATMKfESPA5mGw=; cv=:); d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as cv= invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcSealChainValidationValue); + } + + [Test] + public void as_fields_d_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=YPZ23nGkCxrMd1193xVDIR5/J9Kz0AOanbuHATqRJUDT+KkiB8z6+vk+3qsUiH8/7+YyI/ + Qqmd5O66qPq/ntXMaPnUhpQgKTj33KcGtD7j9m59imfosbjwTWrVatHo8okYmeh61ZxI8LGF + ivZFDrqRI2YLfIG313PtmdUqZJFcY=; cv=none; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as d= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_d_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=pp0092UMeSYNP/NMoINT5QeuCXJ/LKOw4Sotuzu+XM4RFHL8CbHLWT/stFYpif9tVsVaEu + h0SgrYexYI+lvEqslpSdCIgvVanRoSVC2bn58OSVVpZ/8r6/8iIXdN/upGPZRhbJLtSwuRk/ + kbKzXfLTY9yy1SMSAqLXAG2MWBQpg=; cv=none; d=; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as d= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_d_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=e44ivGolh5WOt+GK0xvrRrWcEQnLTpbmx4VqK+osiYiEceAJl6RdIuaG5Sdvl8JLbUcHJf + 7Z1nOuA71nrpTSGEh4kE5bgR/XAtxElq4czlU2B21nDUI5iO5IJTZx5uxYuhVh500OfFxKvP + vk/65F1L8kU45uMhTjih304WuYZ7w=; cv=none; d=***; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as d= invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_h_present () + { + const string input = @"Return-Path: +ARC-Seal: i=1; cv=none; a=rsa-sha256; d=example.com; s=test; t=12345; + h=message-id : date : from : to : subject : from; + b=mIurIuLl0/wAxWhA4DBS1wsUE15IBnmJ7o3sH15hIuesdD4smz1cCLXVhRtxQE + rVtVLv4OgNCgdFsB5zbSOUao2bSSYP6y0BGyCWvr+hU4tai5axIc1Kfwbtv/0Mqg + waiGJPreOAAeZOJ4vPfdaAbSXlN5MI4PHW89U82FSIBKI= +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; + d=example.com; s=test; t=12345; h=message-id : + date : from : to : subject : from; + bh=wE7NXSkgnx9PGiavN4OZhJztvkqPDlemV3OGuEnLwNo=; + b=a0f6qc3k9eECTSR155A0TQS+LjqPFWfI/brQBA83EUz00SNxj + 1wmWykvs1hhBVeM0r1kEQc6CKbzRYaBNSiFj4q8JBpRIujLz1qL + yGmPuAI6ddu/Z/1hQxgpVcp/odmI1UMV2R+d+yQ7tUp3EQxF/GY + Nt22rV4rNmDmANZVqJ90= +ARC-Authentication-Results: i=1; lists.example.org; arc=none; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Authentication-Results: lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass +Received: from localhost +Message-ID: +Date: Mon, 01 Jan 2011 01:02:03 +0400 +From: Test User +To: somebody@example.com +Subject: Testing + +This is a test message. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as has h= which is invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_s_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=P6fYgm79ZAak3Jov/xVCFA565vivmIK1TRc3a5bXLaK0ITMGov8fPDfBSlkicrEA7+klCS + U+N4M70a873UxJAhtbW8aTgFfGA71WeXTJtsUO9k221Xg3TosedH0Pv7Hw6H5+xwfREaHwzW + 609JaRP4xYSgiRQwbV53oJLXsUBA4=; cv=none; d=example.org; i=1; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as s= not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_s_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=s5XP6OVPaP6aRAUllKkgklTcVFSRt0BuJ/KsHSBkzUlu8tlc8xHNLLQh8kSj93G91Nzrht + 2TSNCGbDv2n+fTkUBvUw0Gv+rS+w/cGv3487x/0D3kKMY/AsnmbmKYy7demRQZueTjZg4oBd + ictli/7xMAt6WUmqpssBKMK5wsfp0=; cv=none; d=example.org; i=1; s=; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as s= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_t_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=JBVkqSG5Cg5D7lzXzyoLhk5/SMvhUeqxndqDKDjLQSici34r5d+fQIkUosiU17/jueiGc9 + UpZl2Gv6wPs7TkgwxfK7GG/1d4P+/cYE6efo8xuPSZGxoSQEZhKTjXL9Apup8Up3e/J2xBjs + veRG7RbXqMc/vL/tmGxsJ9aSjSIKI=; cv=none; d=example.org; i=1; s=dummy +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as t= na", input, locator, ArcSignatureValidationResult.Pass); + } + + [Test] + public void as_fields_t_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=s8yFqRcEb3EBxbl8zc3/Q7Yni59wWhj7+NDrxRaVvVJ2f/e4FKJTIcz+0i9z+VhmX41Zu5 + Rh2CQwD6bnkOvtHIuHoxI4LxOhs/lvhkcBieiqGR4ZeZlOy8n6mmnbuHIi151pNXK79ZxRdr + 2axc4DYl57RmQKI+jVPwiMygli/f0=; cv=none; d=example.org; i=1; s=dummy; + t= +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as t= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void as_fields_t_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=K4NE5fZ5bskXwVAbySXpU9ys/ls+gL97+qh/HSFgSAkBzAxQ355pWkGTKLG3SX95OEljIO + tFiBuwYKIiBXwYbl6vpsZpjS3AwwdtV+rFqwVT0oCwRv2SU8v+wvg/2uzgUMciit+WNI0sYr + +HgFzkt6yR3Jpg8Y/49qKPXZcYR3I=; cv=none; d=example.org; i=1; s=dummy; + t=-123.4 +ARC-Message-Signature: a=rsa-sha256; + b=uB8ov69KIWfAiTqT9UOTg9p4m0u8Zi01NUVf0iyzeNBpJR9VecE81x2VzQBxfPnp5p3uSd + H7A/ExuHutPbPzSJh62u0HpIIoSoxzZtSeESFwIJJe81Iv8SiuIuwCtih+wcNxPEoou7G0F3 + fRI+n99QEFryjk9dsPBGW4NFxNzIA=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("512._domainkey.example.org", "v=DKIM1; k=rsa; p= MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="); + locator.Add ("1024._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368 C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"); + locator.Add ("2048._domainkey.example.org", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/ +beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi BU+QIDAQAB"); + + Validate ("as t= invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MessageSignatureValidationFailed | ArcValidationErrors.SealValidationFailed); + } + + #endregion + #region AAR Set Structure + + [Test] + public void aar_struct_i_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=XPyfGHSOsXbhiqnRuLe8aUcX7VI+ULipPwkVdyFW3vrDgWis0ZGj5Exi7MVCEZqHCPRrz6 + cE/MCiMIKvLKaNOoN2RiMmGxReyuMqxB1cFgrlYSsY2juOuKruRwnyvdojfJKxkZtuwbCbEI + oP7AxLlImiJh8dL65hcqiVYYwkCVo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=pT/KGdemFeMECKnNp/zUgBi7JEBkqLYi6OiuMNFk1lu9MvIVAphMo5Qd+HwcmduHcKnTuE + BR6G1f+FvrikTsz71tFpmz7YMQDVfnd889YqzIMfkrHVmYz3Tqkm/leEozN+3QSDthphCGja + elxeYITZ88vPyJgjqeB1RZbZA8w1w=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AAR i= NA", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_struct_i_empty () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=2bCJqMNBHeHfGn4ydivoDNuXl5l4/uFJRjSq20B1IFuEwXRBItAHyrnJ2kAeKyN2vDyF38 + aeVMW3JpEr6YYbdWz/QIbn9PfQRLJw8mDAdIWIeDf77ckQL9pBS9u4KnPzSRlvBrMvTJcHI0 + X78AQ+sF7GHuW+TQE3w76leY5chNg=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=ssDGg3IC3l9eIU0QVB6442p+icX6zrpaCDc6MdnR9waROdPPl4ThcRHhU19nHBlEqvc6Nj + heWBORRpH93dQ2gC1dh/kYpOu7GUr7rbTzO3FYICnbTCbZWHHkyRPjKGUDLKZxt2zOnT1g+I + FiLSqI5zVyKX98w5q0cUroUaFYyOg=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AAR i= empty", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_struct_i_zero () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=KylBhAsgxwZcei83U8RCLOL6VAKrUTEqgMRFrfs4wdvOfJhb4QLzeJoNuL0rru8pWd/y9/ + zEYgBxCGpOGkoEXyzrDE+2wbNPn04kjJuTpMfRbHljy6kjHXRf8jgy44iDS6zx2dkV+YRP4n + STyZLdj+YcIrTvl/DSzidIX+QF8tE=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=G459JFdl2PXVaqhTFJwqpBaOCUiASVtWpkiQrIPiLPDpPoGT3AhaoPDpM3ogUhURRBAkQD + bJqcY2XJ2F2NAWf260C7T/q0DlO6D0/E6IsqiY5seqiBCPIGf4B2yMjnQXf1qTHFNbbJGICi + k6bE4r1ZCT7Cu9CWFCCq9TWEthhfw=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=0; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AAR i=0", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_struct_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=ye9OTXk3fAWUMwhQFsBSTjaDkrXXFzifyP5c7No0TriPbeFK0cayi6FgudLVsSFLvibCAJ + txOi+Zfx9rn0TyhsNspRg/PY8+VSZJZtxOW7cJ/6nLZPh3XKfhx39QDQPjyc3dd03bpAckRH + b6vJuM9vmpgB4y3WnnvWH9H05wfMo=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=fusc8GIuNpkjd8jbi8g5feEaRugmDELIl/M3u+QCZjF4Sw4SVFS8tRy8DI8XA/49D4mfmc + NuClgRzBZJSeyd1w6tDyt0mebBKMAWqJXK25B6ON3QTeXTudB5447VckaoUn0k+U75fkyiKk + l2ZmwWGNx0jBif2Py0gSwhFajD77g=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=squanch; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("AAR i= invalid value", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_struct_dup () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Duplicated AAR for i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.DuplicateArcAuthenticationResults); + } + + [Test] + public void aar_struct_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ + 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn + QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("Missing AAR for i=1", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcAuthenticationResults); + } + + #endregion + #region Arc Authentication Results + + [Test] + public void aar_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("missing arc authentication results", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcAuthenticationResults); + } + + [Test] + public void aar_i_missing () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("arc authentication results no i= tag", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_i_wrong () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=2; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("arc authentication results wrong i= tag", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcAuthenticationResults | ArcValidationErrors.MissingArcMessageSignature | ArcValidationErrors.MissingArcSeal); + } + + [Test] + public void aar_i_not_prefixed () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: lists.example.org; i=1; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("arc authentication results i= not prefixed", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar_i_no_semi () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1 lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("arc authentication results i= no semicolon", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.InvalidArcAuthenticationResults); + } + + [Test] + public void aar2_missing () + { + const string input = @"MIME-Version: 1.0 +ARC-Seal: a=rsa-sha256; + b=CiZp+ZloBeWiIyjY+Eq0lKt20KQDF3QIJNw7+/jdjtQ1XTSMhHsli7H/ocIXsiU/kLF5pn + pABQiZPvAWfCaEcCA9lyb/7i3q2i72GLdK1vdrdD2nIM5e7L3u/5Z56SJdKTu46SyoFQve9b + Cp7qoQB9/TUTxxvkDoapsSjDCDqZ0=; cv=pass; d=example.org; i=2; s=dummy; + t=12346 +ARC-Message-Signature: a=rsa-sha256; + b=A2OCip1Cf9z6X7ML9/bRajnToeCD3H7IkP7YqmSKqDtn8Yu8oaJdwP0lZfCTjX++Qas9nj + tGWMojFpj8Wd2rzdyMXwUWF3xlcFBD2gApO9xbehIASIF4lFQMyP6D80LjsjdtpstgwGZl9P + y6WTyD1Kw/bNPZadxvNeDg3LVcQpo=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=2; s=dummy; t=12346 +Received: by 10.157.11.240 with SMTP id 103csp420860oth; + Fri, 6 Jan 2017 14:27:31 -0800 (PST) +Return-Path: +ARC-Seal: a=rsa-sha256; + b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr + QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh + GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou + ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z + sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=; + bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +MIME-Version: 1.0 +Return-Path: +Received: by 10.157.52.162 with SMTP id g31csp5274520otc; + Tue, 3 Jan 2017 12:32:02 -0800 (PST) +X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271; + Tue, 03 Jan 2017 12:32:02 -0800 (PST) +Message-ID: +Date: Thu, 5 Jan 2017 14:39:01 -0800 +From: Gene Q Doe +To: arc@dmarc.org +Subject: Example 2 +Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/plain; charset=UTF-8 + +This is a test message + +--001a113e15fcdd0f9e0545366e8f +Content-Type: text/html; charset=UTF-8 + +
This is a test message
+ +--001a113e15fcdd0f9e0545366e8f-- +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Validate ("aar missing for i=2", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.MissingArcAuthenticationResults); + } + + #endregion + #region Public Key + + [Test] + public void public_key_na () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=xEoL/6DZn2+/oIsSIAFRrnQdhyrH/aSGdRqBphcyZvTLhDyd8sPHIqNsr0HROjIybe3lUG + /YlYIftmAUP3E7kWbfU7HrolZ/5f4eB0tciltpSyBUPzM2D30IxGmqUvQxk5ATb7WxKAUs4x + XiTmx1MaAUKAExlm45pwp5wEoU/D8=; cv=none; d=example.org; i=1; s=na; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example2.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR3lRpGZS+xO96Znv/BPNQxi m7ZD0v6yFmZa9Rni5FHCeWuQwcp+PH/XXOyF6JsmB+kS0ybxJnx594ulqH2KvLMNsGAD+yRl2bJSXbBH ea7K9C5WX8Vjx3oPoGgw7QCONptnjUsbIIoxUZBEUe17eG44H/PbDqGwCBiyI20KEC/wIDAQAB"); + locator.Add ("invalid._domainkey.example.org", "v=DKIM1; k=rsa; omgwhatsgoingon"); + + Validate ("public key not available", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void public_key_invalid () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=G6sqFlzmC87EiD80V9Da8JURM2MUxp1tK3iUxrQdSJ6odUYPT8ApwE1GWodzs8UDuKemL+ + qn7E29nhcK8pwjLjWNilPTZJ1Bt1TS8QersJsEe4tD+rcbGd8ZU8C2UcUpv0TFv3m4GrNbwx + JFFf9r1x5VkXulzTwIo1VW6avKShw=; cv=none; d=example.org; i=1; s=invalid; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example2.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR3lRpGZS+xO96Znv/BPNQxi m7ZD0v6yFmZa9Rni5FHCeWuQwcp+PH/XXOyF6JsmB+kS0ybxJnx594ulqH2KvLMNsGAD+yRl2bJSXbBH ea7K9C5WX8Vjx3oPoGgw7QCONptnjUsbIIoxUZBEUe17eG44H/PbDqGwCBiyI20KEC/wIDAQAB"); + locator.Add ("invalid._domainkey.example.org", "v=DKIM1; k=rsa; omgwhatsgoingon"); + + Validate ("public key invalid", input, locator, ArcSignatureValidationResult.Fail, ArcValidationErrors.SealValidationFailed); + } + + [Test] + public void ams_as_diff_s_d () + { + const string input = @"MIME-Version: 1.0 +Return-Path: +ARC-Seal: a=rsa-sha256; + b=Q6K/T+/5h+nkCtO8UVhb5uwy5ozplfBvOV0lSOCIuzDoTlPNg1chaN+04US/AWxvOrBTZf + hzXXdVjXMv2sX4+4ebSegZN7GTakDCd+vfBtF30jR4csBqlhW25NSyLeleZnIMf5I5G4vu5+ + Ab38xWCoKnMKTPsPebT273ALMfzOw=; cv=none; d=example2.org; i=1; s=dummy2; + t=12345 +ARC-Message-Signature: a=rsa-sha256; + b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm + 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE + cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed; + d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results; + i=1; s=dummy; t=12345 +ARC-Authentication-Results: i=1; lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Authentication-Results: lists.example.org; + spf=pass smtp.mfrom=jqd@d1.example; + dkim=pass (1024-bit key) header.i=@d1.example; + dmarc=pass +Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example.org> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.org +Subject: Example 1 + +Hey gang, +This is a test message. +--J. +"; + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("dummy2._domainkey.example2.org", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR3lRpGZS+xO96Znv/BPNQxi m7ZD0v6yFmZa9Rni5FHCeWuQwcp+PH/XXOyF6JsmB+kS0ybxJnx594ulqH2KvLMNsGAD+yRl2bJSXbBH ea7K9C5WX8Vjx3oPoGgw7QCONptnjUsbIIoxUZBEUe17eG44H/PbDqGwCBiyI20KEC/wIDAQAB"); + locator.Add ("invalid._domainkey.example.org", "v=DKIM1; k=rsa; omgwhatsgoingon"); + + Validate ("differing domains & selectors across ams & as", input, locator, ArcSignatureValidationResult.Pass); + } + + #endregion + } +} diff --git a/UnitTests/Cryptography/AsymmetricAlgorithmExtensionTests.cs b/UnitTests/Cryptography/AsymmetricAlgorithmExtensionTests.cs index 4450dac664..fcfd7fda99 100644 --- a/UnitTests/Cryptography/AsymmetricAlgorithmExtensionTests.cs +++ b/UnitTests/Cryptography/AsymmetricAlgorithmExtensionTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,7 @@ using Org.BouncyCastle.Math; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Parameters; using MimeKit.Cryptography; @@ -65,107 +66,146 @@ static void AssertAreEqual (byte[] expected, byte[] actual, string paramName) Assert.AreEqual (expectedBigInteger, actualBigInteger, "{0} are not equal", paramName); } - [Test] - public void TestDsa () + static void AssertDSA (DSA dsa) { - using (var dsa = new DSACryptoServiceProvider (1024)) { - // first, check private key conversion - var expected = dsa.ExportParameters (true); - var keyParameter = dsa.AsAsymmetricKeyParameter (); - var windows = keyParameter.AsAsymmetricAlgorithm () as DSACryptoServiceProvider; - var actual = windows.ExportParameters (true); - - Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); - AssertAreEqual (expected.Seed, actual.Seed, "Seed"); - AssertAreEqual (expected.G, actual.G, "G"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.X, actual.X, "X"); - AssertAreEqual (expected.Y, actual.Y, "Y"); - - // test AsymmetricCipherKeyPair conversion - var keyPair = dsa.AsAsymmetricCipherKeyPair (); - windows = keyPair.AsAsymmetricAlgorithm () as DSACryptoServiceProvider; - actual = windows.ExportParameters (true); - - Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); - AssertAreEqual (expected.Seed, actual.Seed, "Seed"); - AssertAreEqual (expected.G, actual.G, "G"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.X, actual.X, "X"); - AssertAreEqual (expected.Y, actual.Y, "Y"); - - // test public key conversion - expected = dsa.ExportParameters (false); - var pubdsa = new DSACryptoServiceProvider (); - pubdsa.ImportParameters (expected); - - keyParameter = pubdsa.AsAsymmetricKeyParameter (); - windows = keyParameter.AsAsymmetricAlgorithm () as DSACryptoServiceProvider; - actual = windows.ExportParameters (false); - - Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); - AssertAreEqual (expected.Seed, actual.Seed, "Seed"); - AssertAreEqual (expected.G, actual.G, "G"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.X, actual.X, "X"); - AssertAreEqual (expected.Y, actual.Y, "Y"); + // first, check private key conversion + var expected = dsa.ExportParameters (true); + var keyParameter = dsa.AsAsymmetricKeyParameter (); + DSA asymmetricAlgorithm; + + try { + asymmetricAlgorithm = keyParameter.AsAsymmetricAlgorithm () as DSA; + } catch { + Console.WriteLine ("System.Security DSA X parameter = {0}", expected.X.AsHex ()); + Console.WriteLine ("Bouncy Castle DSA X parameter = {0}", ((DsaPrivateKeyParameters) keyParameter).X.ToByteArrayUnsigned ().AsHex ()); + throw; } + + var actual = asymmetricAlgorithm.ExportParameters (true); + + Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); + AssertAreEqual (expected.Seed, actual.Seed, "Seed"); + AssertAreEqual (expected.G, actual.G, "G"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.X, actual.X, "X"); + AssertAreEqual (expected.Y, actual.Y, "Y"); + + // test AsymmetricCipherKeyPair conversion + var keyPair = dsa.AsAsymmetricCipherKeyPair (); + asymmetricAlgorithm = keyPair.AsAsymmetricAlgorithm () as DSA; + actual = asymmetricAlgorithm.ExportParameters (true); + + Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); + AssertAreEqual (expected.Seed, actual.Seed, "Seed"); + AssertAreEqual (expected.G, actual.G, "G"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.X, actual.X, "X"); + AssertAreEqual (expected.Y, actual.Y, "Y"); + + // test public key conversion + expected = dsa.ExportParameters (false); + var pubdsa = new DSACryptoServiceProvider (); + pubdsa.ImportParameters (expected); + + keyParameter = pubdsa.AsAsymmetricKeyParameter (); + asymmetricAlgorithm = keyParameter.AsAsymmetricAlgorithm () as DSA; + actual = asymmetricAlgorithm.ExportParameters (false); + + Assert.AreEqual (expected.Counter, actual.Counter, "Counter"); + AssertAreEqual (expected.Seed, actual.Seed, "Seed"); + AssertAreEqual (expected.G, actual.G, "G"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.X, actual.X, "X"); + AssertAreEqual (expected.Y, actual.Y, "Y"); } [Test] - public void TestRsa () + public void TestDSACryptoServiceProvider () { - using (var rsa = new RSACryptoServiceProvider (1024)) { - // first, check private key conversion - var expected = rsa.ExportParameters (true); - var keyParameter = rsa.AsAsymmetricKeyParameter (); - var windows = keyParameter.AsAsymmetricAlgorithm () as RSACryptoServiceProvider; - var actual = windows.ExportParameters (true); - - AssertAreEqual (expected.D, actual.D, "D"); - AssertAreEqual (expected.DP, actual.DP, "DP"); - AssertAreEqual (expected.DQ, actual.DQ, "DQ"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); - AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); - AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); - - // test AsymmetricCipherKeyPair conversion - var keyPair = rsa.AsAsymmetricCipherKeyPair (); - windows = keyPair.AsAsymmetricAlgorithm () as RSACryptoServiceProvider; - actual = windows.ExportParameters (true); - - AssertAreEqual (expected.D, actual.D, "D"); - AssertAreEqual (expected.DP, actual.DP, "DP"); - AssertAreEqual (expected.DQ, actual.DQ, "DQ"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); - AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); - AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); - - // test public key conversion - expected = rsa.ExportParameters (false); - var pubrsa = new RSACryptoServiceProvider (); - pubrsa.ImportParameters (expected); - - keyParameter = pubrsa.AsAsymmetricKeyParameter (); - windows = keyParameter.AsAsymmetricAlgorithm () as RSACryptoServiceProvider; - actual = windows.ExportParameters (false); - - AssertAreEqual (expected.D, actual.D, "D"); - AssertAreEqual (expected.DP, actual.DP, "DP"); - AssertAreEqual (expected.DQ, actual.DQ, "DQ"); - AssertAreEqual (expected.P, actual.P, "P"); - AssertAreEqual (expected.Q, actual.Q, "Q"); - AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); - AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); - AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); - } + using (var dsa = new DSACryptoServiceProvider (1024)) + AssertDSA (dsa); + } + + [Test] + public void TestDSACng () + { +#if !MONO + using (var dsa = new DSACng (1024)) + AssertDSA (dsa); +#else + Assert.Ignore ("Mono does not implement DSACng"); +#endif + } + + static void AssertRSA (RSA rsa) + { + // first, check private key conversion + var expected = rsa.ExportParameters (true); + var keyParameter = rsa.AsAsymmetricKeyParameter (); + var asymmetricAlgorithm = keyParameter.AsAsymmetricAlgorithm () as RSA; + var actual = asymmetricAlgorithm.ExportParameters (true); + + AssertAreEqual (expected.D, actual.D, "D"); + AssertAreEqual (expected.DP, actual.DP, "DP"); + AssertAreEqual (expected.DQ, actual.DQ, "DQ"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); + AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); + AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); + + // test AsymmetricCipherKeyPair conversion + var keyPair = rsa.AsAsymmetricCipherKeyPair (); + asymmetricAlgorithm = keyPair.AsAsymmetricAlgorithm () as RSA; + actual = asymmetricAlgorithm.ExportParameters (true); + + AssertAreEqual (expected.D, actual.D, "D"); + AssertAreEqual (expected.DP, actual.DP, "DP"); + AssertAreEqual (expected.DQ, actual.DQ, "DQ"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); + AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); + AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); + + // test public key conversion + expected = rsa.ExportParameters (false); + var pubrsa = new RSACryptoServiceProvider (); + pubrsa.ImportParameters (expected); + + keyParameter = pubrsa.AsAsymmetricKeyParameter (); + asymmetricAlgorithm = keyParameter.AsAsymmetricAlgorithm () as RSA; + actual = asymmetricAlgorithm.ExportParameters (false); + + AssertAreEqual (expected.D, actual.D, "D"); + AssertAreEqual (expected.DP, actual.DP, "DP"); + AssertAreEqual (expected.DQ, actual.DQ, "DQ"); + AssertAreEqual (expected.P, actual.P, "P"); + AssertAreEqual (expected.Q, actual.Q, "Q"); + AssertAreEqual (expected.Exponent, actual.Exponent, "Exponent"); + AssertAreEqual (expected.InverseQ, actual.InverseQ, "InverseQ"); + AssertAreEqual (expected.Modulus, actual.Modulus, "Modulus"); + } + + [Test] + public void TestRSACryptoServiceProvider () + { + using (var rsa = new RSACryptoServiceProvider (1024)) + AssertRSA (rsa); + } + + [Test] + public void TestRSACng () + { +#if !MONO + using (var rsa = new RSACng (1024)) + AssertRSA (rsa); +#else + Assert.Ignore ("Mono does not implement RSACng"); +#endif } } } diff --git a/UnitTests/Cryptography/AuthenticationResultsTests.cs b/UnitTests/Cryptography/AuthenticationResultsTests.cs new file mode 100644 index 0000000000..23e49351c1 --- /dev/null +++ b/UnitTests/Cryptography/AuthenticationResultsTests.cs @@ -0,0 +1,1452 @@ +// +// AuthenticationResultsTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Text; + +using NUnit.Framework; + +using MimeKit; +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class AuthenticationResultsTests + { + [Test] + public void TestArgumentExceptions () + { + AuthenticationResults authres; + var buffer = new byte[16]; + + Assert.Throws (() => new AuthenticationResults (null)); + + Assert.Throws (() => new AuthenticationMethodResult (null)); + Assert.Throws (() => new AuthenticationMethodResult (null, "result")); + Assert.Throws (() => new AuthenticationMethodResult ("method", null)); + + Assert.Throws (() => new AuthenticationMethodProperty (null, "property", "value")); + Assert.Throws (() => new AuthenticationMethodProperty ("ptype", null, "value")); + Assert.Throws (() => new AuthenticationMethodProperty ("ptype", "Property", null)); + + Assert.Throws (() => AuthenticationResults.Parse (null)); + Assert.Throws (() => AuthenticationResults.Parse (null, 0, 0)); + Assert.Throws (() => AuthenticationResults.Parse (buffer, -1, 0)); + Assert.Throws (() => AuthenticationResults.Parse (buffer, 0, -1)); + + Assert.Throws (() => AuthenticationResults.TryParse (null, out authres)); + Assert.Throws (() => AuthenticationResults.TryParse (null, 0, 0, out authres)); + Assert.Throws (() => AuthenticationResults.TryParse (buffer, -1, 0, out authres)); + Assert.Throws (() => AuthenticationResults.TryParse (buffer, 0, -1, out authres)); + } + + [Test] + public void TestEncodeLongAuthServId () + { + const string authservid = "this-is-a-really-really-really-long-authserv-identifier-that-is-78-octets-long"; + const string expected = "Authentication-Results:\n\t" + authservid + ";\n\tdkim=pass; spf=pass\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults (authservid); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("dkim", "pass")); + authres.Results.Add (new AuthenticationMethodResult ("spf", "pass")); + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeLongAuthServIdWithVersion () + { + const string authservid = "this-is-a-really-really-really-long-authserv-identifier-that-is-78-octets-long"; + const string expected = "Authentication-Results:\n\t" + authservid + "\n\t1; dkim=pass; spf=pass\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults (authservid); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("dkim", "pass")); + authres.Results.Add (new AuthenticationMethodResult ("spf", "pass")); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeLongResultMethod () + { + const string expected = "Authentication-Results: lists.example.com 1;\n\treally-long-method-name=really-long-value\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults ("lists.example.com"); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("really-long-method-name", "really-long-value")); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeLongResultMethodWithVersion () + { + const string expected = "Authentication-Results: lists.example.com 1;\n\treally-long-method-name/1=really-long-value\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults ("lists.example.com"); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("really-long-method-name", "really-long-value") { + Version = 1 + }); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeQuotedPropertyValue () + { + const string expected = "Authentication-Results: lists.example.com 1;\n\tfoo=pass (2 of 3 tests OK) ptype.prop=\"value1;value2\"\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults ("lists.example.com"); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("foo", "pass")); + authres.Results[0].ResultComment = "2 of 3 tests OK"; + authres.Results[0].Properties.Add (new AuthenticationMethodProperty ("ptype", "prop", "value1;value2")); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeLongResultMethodWithVersionAndComment () + { + const string expected = "Authentication-Results: lists.example.com 1;\n\treally-long-method-name/1=really-long-value\n\t(this is a really long result comment)\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults ("lists.example.com"); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("really-long-method-name", "really-long-value") { + ResultComment = "this is a really long result comment", + Version = 1 + }); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestEncodeLongResultMethodWithVersionAndCommentAndReason () + { + const string expected = "Authentication-Results: lists.example.com 1;\n\treally-really-really-long-method-name/214748367=\n\treally-really-really-long-value (this is a really really long result comment)\n\treason=\"this is a really really really long reason\"\n\tthis-is-a-really-really-long-ptype.this-is-a-really-really-long-property=\n\tthis-is-a-really-really-long-value\n"; + var encoded = new StringBuilder ("Authentication-Results:"); + var authres = new AuthenticationResults ("lists.example.com"); + var options = FormatOptions.Default.Clone (); + + authres.Results.Add (new AuthenticationMethodResult ("really-really-really-long-method-name", "really-really-really-long-value") { + ResultComment = "this is a really really long result comment", + Reason = "this is a really really really long reason", + Version = 214748367 + }); + authres.Results[0].Properties.Add (new AuthenticationMethodProperty ("this-is-a-really-really-long-ptype", "this-is-a-really-really-long-property", "this-is-a-really-really-long-value")); + authres.Version = 1; + + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, encoded.Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseArcAuthenticationResults () + { + const string input = "i=1; example.com; foo=pass"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Instance.Value, "instance"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("foo", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " i=1; example.com; foo=pass\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "ARC-Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseAuthServId () + { + var buffer = Encoding.ASCII.GetBytes ("example.org"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.org", authres.AuthenticationServiceIdentifier, "authserv-id"); + + Assert.AreEqual ("example.org; none", authres.ToString ()); + + const string expected = " example.org; none\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseAuthServIdSemicolon () + { + var buffer = Encoding.ASCII.GetBytes ("example.org;"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.org", authres.AuthenticationServiceIdentifier, "authserv-id"); + + Assert.AreEqual ("example.org; none", authres.ToString ()); + + const string expected = " example.org; none\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseAuthServIdWithVersion () + { + const string input = "example.org 1"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.org", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Version.Value, "authres-version"); + + Assert.AreEqual ("example.org 1; none", authres.ToString ()); + + const string expected = " example.org 1; none\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseAuthServIdWithVersionAndSemicolon () + { + var buffer = Encoding.ASCII.GetBytes ("example.org 1;"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.org", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Version.Value, "authres-version"); + + Assert.AreEqual ("example.org 1; none", authres.ToString ()); + + const string expected = " example.org 1; none\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseNoAuthServId () + { + const string input = "spf=fail (sender IP is 1.1.1.1) smtp.mailfrom=eu-west-1.amazonses.com; dkim=pass (signature was verified) header.d=domain.com; dmarc=bestguesspass header.from=domain.com"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.IsNull (authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("fail", authres.Results[0].Result); + Assert.AreEqual ("sender IP is 1.1.1.1", authres.Results[0].ResultComment); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("eu-west-1.amazonses.com", authres.Results[0].Properties[0].Value); + + Assert.AreEqual ("dkim", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual ("signature was verified", authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("d", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("domain.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("dmarc", authres.Results[2].Method); + Assert.AreEqual ("bestguesspass", authres.Results[2].Result); + Assert.AreEqual (null, authres.Results[2].ResultComment); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "dmarc properties"); + Assert.AreEqual ("header", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("domain.com", authres.Results[2].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = "\n\tspf=fail (sender IP is 1.1.1.1) smtp.mailfrom=eu-west-1.amazonses.com;\n\tdkim=pass (signature was verified) header.d=domain.com;\n\tdmarc=bestguesspass header.from=domain.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseNoResults () + { + var buffer = Encoding.ASCII.GetBytes ("example.org 1; none"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.org", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Version.Value, "authres-version"); + Assert.AreEqual (0, authres.Results.Count, "no-results"); + + Assert.AreEqual ("example.org 1; none", authres.ToString ()); + + const string expected = " example.org 1; none\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimple () + { + const string input = "example.com; foo=pass"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("foo", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; foo=pass\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithComment () + { + const string input = "example.com; foo=pass (2 of 3 tests OK)"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("foo", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("2 of 3 tests OK", authres.Results[0].ResultComment); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; foo=pass (2 of 3 tests OK)\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithProperty1 () + { + const string input = "example.com; spf=pass smtp.mailfrom=example.net"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("example.net", authres.Results[0].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; spf=pass smtp.mailfrom=example.net\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithProperty2 () + { + const string input = "example.com; spf=pass smtp.mailfrom=@example.net"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("@example.net", authres.Results[0].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; spf=pass smtp.mailfrom=@example.net\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithProperty3 () + { + const string input = "example.com; spf=pass smtp.mailfrom=local-part@example.net"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("local-part@example.net", authres.Results[0].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com;\n\tspf=pass smtp.mailfrom=local-part@example.net\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithQuotedPropertyValue () + { + const string input = "example.com; method=pass ptype.prop=\"value1;value2\""; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("method", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "properties"); + Assert.AreEqual ("ptype", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("prop", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("value1;value2", authres.Results[0].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; method=pass ptype.prop=\"value1;value2\"\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithReason () + { + const string input = "example.com; spf=pass reason=good"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("good", authres.Results[0].Reason); + Assert.AreEqual (0, authres.Results[0].Properties.Count, "properties"); + + Assert.AreEqual ("example.com; spf=pass reason=\"good\"", authres.ToString ()); + + const string expected = " example.com; spf=pass reason=\"good\"\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithReasonSemiColon () + { + const string input = "example.com; spf=pass reason=good; "; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("good", authres.Results[0].Reason); + Assert.AreEqual (0, authres.Results[0].Properties.Count, "properties"); + + Assert.AreEqual ("example.com; spf=pass reason=\"good\"", authres.ToString ()); + + const string expected = " example.com; spf=pass reason=\"good\"\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithQuotedReason () + { + const string input = "example.com; spf=pass reason=\"good stuff\""; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("good stuff", authres.Results[0].Reason); + Assert.AreEqual (0, authres.Results[0].Properties.Count, "properties"); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; spf=pass reason=\"good stuff\"\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseSimpleWithQuotedReasonSemiColon () + { + const string input = "example.com; spf=pass reason=\"good stuff\""; + var buffer = Encoding.ASCII.GetBytes (input + "; "); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("good stuff", authres.Results[0].Reason); + Assert.AreEqual (0, authres.Results[0].Properties.Count, "properties"); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com; spf=pass reason=\"good stuff\"\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseMethodWithMultipleProperties () + { + const string input = "example.com; spf=pass ptype1.prop1=value1 ptype2.prop2=value2"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (2, authres.Results[0].Properties.Count, "properties"); + Assert.AreEqual ("ptype1", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("prop1", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("value1", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("ptype2", authres.Results[0].Properties[1].PropertyType); + Assert.AreEqual ("prop2", authres.Results[0].Properties[1].Property); + Assert.AreEqual ("value2", authres.Results[0].Properties[1].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com;\n\tspf=pass ptype1.prop1=value1 ptype2.prop2=value2\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseMultipleMethods () + { + const string input = "example.com; auth=pass (cram-md5) smtp.auth=sender@example.net; spf=pass smtp.mailfrom=example.net; sender-id=pass header.from=example.net"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("auth", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("cram-md5", authres.Results[0].ResultComment); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "auth properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("auth", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("sender@example.net", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("spf", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("example.net", authres.Results[1].Properties[0].Value); + Assert.AreEqual ("sender-id", authres.Results[2].Method); + Assert.AreEqual ("pass", authres.Results[2].Result); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "sender-id properties"); + Assert.AreEqual ("header", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("example.net", authres.Results[2].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com;\n\tauth=pass (cram-md5) smtp.auth=sender@example.net;\n\tspf=pass smtp.mailfrom=example.net; sender-id=pass header.from=example.net\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseMultipleMethodsWithReasons () + { + const string input = "example.com; dkim=pass reason=\"good signature\" header.i=@mail-router.example.net; dkim=fail reason=\"bad signature\" header.i=@newyork.example.com"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("example.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (2, authres.Results.Count, "methods"); + Assert.AreEqual ("dkim", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual ("good signature", authres.Results[0].Reason); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("i", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("@mail-router.example.net", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("dkim", authres.Results[1].Method); + Assert.AreEqual ("fail", authres.Results[1].Result); + Assert.AreEqual ("bad signature", authres.Results[1].Reason); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("i", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("@newyork.example.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " example.com;\n\tdkim=pass reason=\"good signature\" header.i=@mail-router.example.net;\n\tdkim=fail reason=\"bad signature\" header.i=@newyork.example.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + [Test] + public void TestParseHeavilyCommentedExample () + { + var buffer = Encoding.ASCII.GetBytes ("foo.example.net (foobar) 1 (baz); dkim (Because I like it) / 1 (One yay) = (wait for it) fail policy (A dot can go here) . (like that) expired (this surprised me) = (as I wasn't expecting it) 1362471462"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("foo.example.net", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (1, authres.Version.Value, "authres-version"); + Assert.AreEqual (1, authres.Results.Count, "methods"); + Assert.AreEqual ("dkim", authres.Results[0].Method); + Assert.AreEqual (1, authres.Results[0].Version.Value, "method-version"); + Assert.AreEqual ("fail", authres.Results[0].Result); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "dkim properties"); + Assert.AreEqual ("policy", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("expired", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("1362471462", authres.Results[0].Properties[0].Value); + + Assert.AreEqual ("foo.example.net 1; dkim/1=fail policy.expired=1362471462", authres.ToString ()); + + const string expected = " foo.example.net 1;\n\tdkim/1=fail policy.expired=1362471462\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + // Tests work-around for https://github.com/jstedfast/MimeKit/issues/518 + [Test] + public void TestParseMethodPropertyValueWithSlash () + { + const string input = "i=2; test.com; dkim=pass header.d=test.com header.s=selector1 header.b=Iww3/TIUS; dmarc=pass (policy=reject) header.from=test.com; spf=pass (test.com: domain of no-reply@test.com designates 1.1.1.1 as permitted sender) smtp.mailfrom=no-reply@test.com"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("test.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("dkim", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (3, authres.Results[0].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("d", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("test.com", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("header", authres.Results[0].Properties[1].PropertyType); + Assert.AreEqual ("s", authres.Results[0].Properties[1].Property); + Assert.AreEqual ("selector1", authres.Results[0].Properties[1].Value); + Assert.AreEqual ("header", authres.Results[0].Properties[2].PropertyType); + Assert.AreEqual ("b", authres.Results[0].Properties[2].Property); + Assert.AreEqual ("Iww3/TIUS", authres.Results[0].Properties[2].Value); + + Assert.AreEqual ("dmarc", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual ("policy=reject", authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "dmarc properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("test.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("spf", authres.Results[2].Method); + Assert.AreEqual ("pass", authres.Results[2].Result); + Assert.AreEqual ("test.com: domain of no-reply@test.com designates 1.1.1.1 as permitted sender", authres.Results[2].ResultComment); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("no-reply@test.com", authres.Results[2].Properties[0].Value); + + Assert.AreEqual (input, authres.ToString ()); + + const string expected = " i=2; test.com;\n\tdkim=pass header.d=test.com header.s=selector1 header.b=Iww3/TIUS;\n\tdmarc=pass (policy=reject) header.from=test.com; spf=pass\n\t(test.com: domain of no-reply@test.com designates 1.1.1.1 as permitted sender)\n\tsmtp.mailfrom=no-reply@test.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + // Tests work-around for https://github.com/jstedfast/MimeKit/issues/490 + [Test] + public void TestParseOffice365RandomDomainTokensAndAction () + { + var buffer = Encoding.ASCII.GetBytes ("spf=fail (sender IP is 1.1.1.1) smtp.mailfrom=eu-west-1.amazonses.com; receivingdomain.com; dkim=pass (signature was verified) header.d=domain.com;domain1.com; dmarc=bestguesspass action=none header.from=domain.com;"); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.IsNull (authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("fail", authres.Results[0].Result); + Assert.AreEqual ("sender IP is 1.1.1.1", authres.Results[0].ResultComment); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("eu-west-1.amazonses.com", authres.Results[0].Properties[0].Value); + + Assert.AreEqual ("receivingdomain.com", authres.Results[1].Office365AuthenticationServiceIdentifier); + Assert.AreEqual ("dkim", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual ("signature was verified", authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("d", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("domain.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("domain1.com", authres.Results[2].Office365AuthenticationServiceIdentifier); + Assert.AreEqual ("dmarc", authres.Results[2].Method); + Assert.AreEqual ("bestguesspass", authres.Results[2].Result); + Assert.AreEqual (null, authres.Results[2].ResultComment); + Assert.AreEqual ("none", authres.Results[2].Action); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "dmarc properties"); + Assert.AreEqual ("header", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("domain.com", authres.Results[2].Properties[0].Value); + + Assert.AreEqual ("spf=fail (sender IP is 1.1.1.1) smtp.mailfrom=eu-west-1.amazonses.com; receivingdomain.com; dkim=pass (signature was verified) header.d=domain.com; domain1.com; dmarc=bestguesspass action=\"none\" header.from=domain.com", authres.ToString ()); + + const string expected = "\n\tspf=fail (sender IP is 1.1.1.1) smtp.mailfrom=eu-west-1.amazonses.com;\n\treceivingdomain.com; dkim=pass (signature was verified) header.d=domain.com;\n\tdomain1.com; dmarc=bestguesspass action=\"none\" header.from=domain.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + // Tests work-around for https://github.com/jstedfast/MimeKit/issues/527 + [Test] + public void TestParseOffice365RandomDomainTokensAndEmptyPropertyValue () + { + const string input = "spf=temperror (sender IP is 1.1.1.1) smtp.helo=tes.test.ru; mydomain.com; dkim=none (message not signed) header.d=none;mydomain.com; dmarc=none action=none header.from=;"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual (null, authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("spf", authres.Results[0].Method); + Assert.AreEqual ("temperror", authres.Results[0].Result); + Assert.AreEqual ("sender IP is 1.1.1.1", authres.Results[0].ResultComment); + Assert.AreEqual (1, authres.Results[0].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("helo", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("tes.test.ru", authres.Results[0].Properties[0].Value); + + Assert.AreEqual ("mydomain.com", authres.Results[1].Office365AuthenticationServiceIdentifier); + Assert.AreEqual ("dkim", authres.Results[1].Method); + Assert.AreEqual ("none", authres.Results[1].Result); + Assert.AreEqual ("message not signed", authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("d", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("none", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("mydomain.com", authres.Results[2].Office365AuthenticationServiceIdentifier); + Assert.AreEqual ("dmarc", authres.Results[2].Method); + Assert.AreEqual ("none", authres.Results[2].Result); + Assert.AreEqual (null, authres.Results[2].ResultComment); + Assert.AreEqual ("none", authres.Results[2].Action); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "dmarc properties"); + Assert.AreEqual ("header", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("", authres.Results[2].Properties[0].Value); + + Assert.AreEqual ("spf=temperror (sender IP is 1.1.1.1) smtp.helo=tes.test.ru; mydomain.com; dkim=none (message not signed) header.d=none; mydomain.com; dmarc=none action=\"none\" header.from=", authres.ToString ()); + + const string expected = "\n\tspf=temperror (sender IP is 1.1.1.1) smtp.helo=tes.test.ru;\n\tmydomain.com; dkim=none (message not signed) header.d=none;\n\tmydomain.com; dmarc=none action=\"none\" header.from=\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + // Tests work-around for https://github.com/jstedfast/MimeKit/issues/584 + [Test] + public void TestParseMethodResultWithUnderscore () + { + const string input = " atlas122.free.mail.gq1.yahoo.com; dkim=dkim_pass header.i=@news.aegeanair.com header.s=@aegeanair2; spf=pass smtp.mailfrom=news.aegeanair.com; dmarc=success(p=REJECT) header.from=news.aegeanair.com;"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual ("atlas122.free.mail.gq1.yahoo.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("dkim", authres.Results[0].Method); + Assert.AreEqual ("dkim_pass", authres.Results[0].Result); + Assert.AreEqual (null, authres.Results[0].ResultComment); + Assert.AreEqual (2, authres.Results[0].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("i", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("@news.aegeanair.com", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("header", authres.Results[0].Properties[1].PropertyType); + Assert.AreEqual ("s", authres.Results[0].Properties[1].Property); + Assert.AreEqual ("@aegeanair2", authres.Results[0].Properties[1].Value); + + Assert.AreEqual ("spf", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual (null, authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "spf properties"); + Assert.AreEqual ("smtp", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("news.aegeanair.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("dmarc", authres.Results[2].Method); + Assert.AreEqual ("success", authres.Results[2].Result); + Assert.AreEqual ("p=REJECT", authres.Results[2].ResultComment); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "dmarc properties"); + Assert.AreEqual ("header", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("news.aegeanair.com", authres.Results[2].Properties[0].Value); + + Assert.AreEqual ("atlas122.free.mail.gq1.yahoo.com; dkim=dkim_pass header.i=@news.aegeanair.com header.s=@aegeanair2; spf=pass smtp.mailfrom=news.aegeanair.com; dmarc=success (p=REJECT) header.from=news.aegeanair.com", authres.ToString ()); + + const string expected = " atlas122.free.mail.gq1.yahoo.com;\n\tdkim=dkim_pass header.i=@news.aegeanair.com header.s=@aegeanair2;\n\tspf=pass smtp.mailfrom=news.aegeanair.com;\n\tdmarc=success (p=REJECT) header.from=news.aegeanair.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + // Tests work-around for https://github.com/jstedfast/MimeKit/issues/590 + [Test] + public void TestParsePropertyWithEqualSignInValue () + { + const string input = "i=1; relay.mailrelay.com; dkim=pass header.d=domaina.com header.s=sfdc header.b=abcefg; dmarc=pass (policy=quarantine) header.from=domaina.com; spf=pass (relay.mailrelay.com: domain of support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com designates 1.1.1.1 as permitted sender) smtp.mailfrom=support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com"; + var buffer = Encoding.ASCII.GetBytes (input); + AuthenticationResults authres; + + Assert.IsTrue (AuthenticationResults.TryParse (buffer, 0, buffer.Length, out authres)); + Assert.AreEqual (1, authres.Instance.Value, "i"); + Assert.AreEqual ("relay.mailrelay.com", authres.AuthenticationServiceIdentifier, "authserv-id"); + Assert.AreEqual (3, authres.Results.Count, "methods"); + Assert.AreEqual ("dkim", authres.Results[0].Method); + Assert.AreEqual ("pass", authres.Results[0].Result); + Assert.AreEqual (null, authres.Results[0].ResultComment); + Assert.AreEqual (3, authres.Results[0].Properties.Count, "dkim properties"); + Assert.AreEqual ("header", authres.Results[0].Properties[0].PropertyType); + Assert.AreEqual ("d", authres.Results[0].Properties[0].Property); + Assert.AreEqual ("domaina.com", authres.Results[0].Properties[0].Value); + Assert.AreEqual ("header", authres.Results[0].Properties[1].PropertyType); + Assert.AreEqual ("s", authres.Results[0].Properties[1].Property); + Assert.AreEqual ("sfdc", authres.Results[0].Properties[1].Value); + Assert.AreEqual ("header", authres.Results[0].Properties[2].PropertyType); + Assert.AreEqual ("b", authres.Results[0].Properties[2].Property); + Assert.AreEqual ("abcefg", authres.Results[0].Properties[2].Value); + + Assert.AreEqual ("dmarc", authres.Results[1].Method); + Assert.AreEqual ("pass", authres.Results[1].Result); + Assert.AreEqual ("policy=quarantine", authres.Results[1].ResultComment); + Assert.AreEqual (1, authres.Results[1].Properties.Count, "spf properties"); + Assert.AreEqual ("header", authres.Results[1].Properties[0].PropertyType); + Assert.AreEqual ("from", authres.Results[1].Properties[0].Property); + Assert.AreEqual ("domaina.com", authres.Results[1].Properties[0].Value); + + Assert.AreEqual ("spf", authres.Results[2].Method); + Assert.AreEqual ("pass", authres.Results[2].Result); + Assert.AreEqual ("relay.mailrelay.com: domain of support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com designates 1.1.1.1 as permitted sender", authres.Results[2].ResultComment); + Assert.AreEqual (1, authres.Results[2].Properties.Count, "dmarc properties"); + Assert.AreEqual ("smtp", authres.Results[2].Properties[0].PropertyType); + Assert.AreEqual ("mailfrom", authres.Results[2].Properties[0].Property); + Assert.AreEqual ("support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com", authres.Results[2].Properties[0].Value); + + Assert.AreEqual ("i=1; relay.mailrelay.com; dkim=pass header.d=domaina.com header.s=sfdc header.b=abcefg; dmarc=pass (policy=quarantine) header.from=domaina.com; spf=pass (relay.mailrelay.com: domain of support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com designates 1.1.1.1 as permitted sender) smtp.mailfrom=support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com", authres.ToString ()); + + const string expected = " i=1; relay.mailrelay.com;\n\tdkim=pass header.d=domaina.com header.s=sfdc header.b=abcefg;\n\tdmarc=pass (policy=quarantine) header.from=domaina.com; spf=pass\n\t(relay.mailrelay.com: domain of support=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com designates 1.1.1.1 as permitted sender)\n\tsmtp.mailfrom=\n\tsupport=domaina.com__0-1q6woix34obtbu@823lwd90ky2ahf.mail_sender.com\n"; + var encoded = new StringBuilder (); + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + authres.Encode (options, encoded, "Authentication-Results:".Length); + + Assert.AreEqual (expected, encoded.ToString ()); + } + + static void AssertParseFailure (string input, int tokenIndex, int errorIndex) + { + var buffer = Encoding.ASCII.GetBytes (input); + + Assert.IsFalse (AuthenticationResults.TryParse (buffer, out AuthenticationResults authres)); + + try { + AuthenticationResults.Parse (buffer); + Assert.Fail ("Expected parse error."); + } catch (ParseException ex) { + Assert.AreEqual (tokenIndex, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (errorIndex, ex.ErrorIndex, "ErrorIndex"); + } + + try { + AuthenticationResults.Parse (buffer, 0, buffer.Length); + Assert.Fail ("Expected parse error."); + } catch (ParseException ex) { + Assert.AreEqual (tokenIndex, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (errorIndex, ex.ErrorIndex, "ErrorIndex"); + } + } + + [Test] + public void TestParseFailureAuthServIdIncompleteQString () + { + AssertParseFailure (" \"quoted-authserv-id", 1, 20); + } + + [Test] + public void TestParseFailureIncompleteComment () + { + AssertParseFailure (" (truncated comment", 1, 19); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterAuthServId () + { + AssertParseFailure (" authserv-id (truncated comment", 13, 31); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterAuthServIdVersion () + { + AssertParseFailure (" authserv-id 1 (truncated comment", 15, 33); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterInstanceEquals () + { + AssertParseFailure (" i= (truncated comment", 4, 22); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterInstanceEqualsValue () + { + AssertParseFailure (" i=1 (truncated comment", 5, 23); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterInstanceEqualsValueSemiColon () + { + AssertParseFailure (" i=1; (truncated comment", 6, 24); + } + + [Test] + public void TestParseFailureIncompleteCommentBeforeMethod () + { + AssertParseFailure (" authserv-id; (incomplete comment", 14, 33); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethod () + { + AssertParseFailure (" authserv-id; method (incomplete comment", 21, 40); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodEquals () + { + AssertParseFailure (" authserv-id; method= (incomplete comment", 22, 41); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodEqualsResult () + { + AssertParseFailure (" authserv-id; method=result (incomplete comment", 28, 47); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodEqualsResultComment () + { + AssertParseFailure (" authserv-id; method=result (comment) (incomplete comment", 38, 57); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodSlash () + { + AssertParseFailure (" authserv-id; method/ (incomplete comment", 22, 41); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodVersion () + { + AssertParseFailure (" authserv-id; method/1 (incomplete comment", 23, 42); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterMethodVersionEquals () + { + AssertParseFailure (" authserv-id; method/1= (incomplete comment", 24, 43); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterReason () + { + AssertParseFailure ("authserv-id; method=pass reason (truncated comment", 32, 50); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterReasonEquals () + { + AssertParseFailure ("authserv-id; method=pass reason= (truncated comment", 33, 51); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterReasonEqualsValue () + { + AssertParseFailure ("authserv-id; method=pass reason=value (truncated comment", 38, 56); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterPType () + { + AssertParseFailure ("authserv-id; method=pass ptype (truncated comment", 31, 49); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterPTypeDot () + { + AssertParseFailure ("authserv-id; method=pass ptype. (truncated comment", 32, 50); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterPTypeDotProp () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop (truncated comment", 36, 54); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterPTypeDotPropEquals () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop= (truncated comment", 37, 55); + } + + [Test] + public void TestParseFailureIncompleteCommentAfterPTypeDotPropEqualsValue () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop=value (truncated comment", 42, 60); + } + + [Test] + public void TestParseFailureIncompleteArcInstance () + { + AssertParseFailure ("i=", 2, 2); + } + + [Test] + public void TestParseFailureInvalidArcInstance () + { + AssertParseFailure ("i=abc; authserv-id", 2, 2); + } + + [Test] + public void TestParseFailureUnexpectedTokenAfterArcInstance () + { + AssertParseFailure ("i=1: authserv-id", 3, 3); + } + + [Test] + public void TestParseFailureOnlyArcInstance () + { + AssertParseFailure ("i=5", 2, 3); + } + + [Test] + public void TestParseFailureOnlyArcInstanceSemicolon () + { + AssertParseFailure ("i=5;", 4, 4); + } + + [Test] + public void TestParseFailureMultipleLeadingArcInstance () + { + AssertParseFailure ("i=5; i=1", 5, 6); + } + + [Test] + public void TestParseFailureInvalidVersion () + { + AssertParseFailure ("authserv-id x", 12, 12); + } + + [Test] + public void TestParseFailureInvalidTokenAfterVersion () + { + AssertParseFailure ("authserv-id 1 x", 14, 14); + } + + [Test] + public void TestParseFailureInvalidMethod1 () + { + AssertParseFailure ("authserv-id; .", 13, 13); + } + + [Test] + public void TestParseFailureInvalidMethod2 () + { + AssertParseFailure ("authserv-id; abc", 13, 16); + } + + [Test] + public void TestParseFailureInvalidMethod3 () + { + AssertParseFailure ("authserv-id; abc def", 13, 17); + } + + [Test] + public void TestParseFailureInvalidMethodVersion1 () + { + AssertParseFailure ("authserv-id; abc/1 ", 13, 19); + } + + [Test] + public void TestParseFailureInvalidMethodVersion2 () + { + AssertParseFailure ("authserv-id; abc/1.0=pass", 13, 18); + } + + [Test] + public void TestParseFailureInvalidMethodVersion3 () + { + AssertParseFailure ("authserv-id; abc/def=pass", 17, 17); + } + + [Test] + public void TestParseFailureIncompleteMethod () + { + AssertParseFailure ("authserv-id; abc=", 13, 17); + } + + [Test] + public void TestParseFailureMethodEqualNonKeyword () + { + AssertParseFailure ("authserv-id; abc=.", 17, 17); + } + + [Test] + public void TestParseFailureNoResultWithMore () + { + AssertParseFailure ("authserv-id; none; method=pass", 13, 17); + } + + [Test] + public void TestParseFailureNoResultAfterMethods () + { + AssertParseFailure ("authserv-id; method=pass; none", 26, 30); + } + + [Test] + public void TestParseFailureIncompleteResultComment () + { + AssertParseFailure ("authserv-id; method=pass (truncated comment", 25, 43); + } + + [Test] + public void TestParseFailureInvalidTokenAfterResult () + { + AssertParseFailure ("authserv-id; method=pass .", 25, 25); + } + + [Test] + public void TestParseFailureIncompleteReason1 () + { + AssertParseFailure ("authserv-id; method=pass reason", 25, 31); + } + + [Test] + public void TestParseFailureIncompleteReason2 () + { + AssertParseFailure ("authserv-id; method=pass reason=", 32, 32); + } + + [Test] + public void TestParseFailureIncompleteReason3 () + { + AssertParseFailure ("authserv-id; method=pass reason=\"this is some text", 32, 50); + } + + [Test] + public void TestParseFailureIncompleteReason4 () + { + AssertParseFailure ("authserv-id; method=pass reason=;", 32, 32); + } + + [Test] + public void TestParseFailureInvalidReason () + { + AssertParseFailure ("authserv-id; method=pass reason .", 25, 32); + } + + [Test] + public void TestParseFailureInvalidPropTypeAfterReason () + { + AssertParseFailure ("authserv-id; method=pass reason=\"because I said so\" .;", 52, 52); + } + + [Test] + public void TestParseFailureIncompleteProperty1 () + { + AssertParseFailure ("authserv-id; method=pass ptype", 25, 30); + } + + [Test] + public void TestParseFailureIncompleteProperty2 () + { + AssertParseFailure ("authserv-id; method=pass ptype.", 25, 31); + } + + [Test] + public void TestParseFailureIncompleteProperty3 () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop", 25, 35); + } + + // Note: TestParseFailureIncompleteProperty4 and 5 are commented out because of + // https://github.com/jstedfast/MimeKit/issues/527 where we have "header.from=;" + + //[Test] + //public void TestParseFailureIncompleteProperty4 () + //{ + // AssertParseFailure ("authserv-id; method=pass ptype.prop=", 25, 36); + //} + + //[Test] + //public void TestParseFailureIncompleteProperty5 () + //{ + // AssertParseFailure ("authserv-id; method=pass ptype.prop=;", 25, 36); + //} + + [Test] + public void TestParseFailureInvalidProperty1 () + { + AssertParseFailure ("authserv-id; method=pass ptype;", 25, 30); + } + + [Test] + public void TestParseFailureInvalidProperty2 () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop;", 25, 35); + } + + [Test] + public void TestParseFailureInvalidProperty3 () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop=value .", 42, 42); + } + + [Test] + public void TestParseFailureInvalidProperty4 () + { + AssertParseFailure ("authserv-id; method=pass ptype..", 31, 31); + } + + [Test] + public void TestParseFailureInvalidOffice365AuthServId () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop=pvalue; invalid.office365.domain..; method=pass", 44, 69); + } + + [Test] + public void TestParseFailureTruncatedOffice365AuthServId () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop=pvalue; truncated.office365.domain", 44, 70); + } + + [Test] + public void TestParseFailureUnexpectedTokenAfterOffice365AuthServId () + { + AssertParseFailure ("authserv-id; method=pass ptype.prop=pvalue; office365.domain :", 61, 61); + } + } +} diff --git a/UnitTests/Cryptography/CertificateExtensionTests.cs b/UnitTests/Cryptography/CertificateExtensionTests.cs new file mode 100644 index 0000000000..5d43df15af --- /dev/null +++ b/UnitTests/Cryptography/CertificateExtensionTests.cs @@ -0,0 +1,102 @@ +// +// BouncyCastleCertificateExtensionTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; + +using MimeKit; +using MimeKit.Cryptography; + +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1.X509; + +using X509Certificate = Org.BouncyCastle.X509.X509Certificate; +using X509KeyUsageFlags = MimeKit.Cryptography.X509KeyUsageFlags; + +using NUnit.Framework; + +namespace UnitTests.Cryptography { + [TestFixture] + public class CertificateExtensionTests + { + [Test] + public void TestArgumentExceptions () + { + Assert.Throws (() => BouncyCastleCertificateExtensions.AsX509Certificate2 (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetIssuerNameInfo (null, X509Name.CN)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetSubjectNameInfo (null, X509Name.CN)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetCommonName (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetSubjectName (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetSubjectEmailAddress (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetFingerprint (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetKeyUsageFlags ((X509Certificate) null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetEncryptionAlgorithms (null)); + Assert.Throws (() => BouncyCastleCertificateExtensions.GetPublicKeyAlgorithm (null)); + + Assert.Throws (() => X509Certificate2Extensions.AsBouncyCastleCertificate (null)); + Assert.Throws (() => X509Certificate2Extensions.GetEncryptionAlgorithms (null)); + Assert.Throws (() => X509Certificate2Extensions.GetPublicKeyAlgorithm (null)); + } + + X509KeyUsageFlags GetX509Certificate2KeyUsageFlags (X509Certificate2 certificate) + { + var usage = certificate.Extensions[X509Extensions.KeyUsage.Id] as X509KeyUsageExtension; + + if (usage == null) + return BouncyCastleCertificateExtensions.GetKeyUsageFlags ((bool[]) null); + + return (X509KeyUsageFlags) usage.KeyUsages; + } + + [Test] + public void TestCertificateConversion () + { + var fileNames = new string[] { "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" }; + var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "smime"); + var parser = new X509CertificateParser (); + + foreach (var fileName in fileNames) { + using (var stream = File.OpenRead (Path.Combine (dataDir, fileName))) { + foreach (X509Certificate certificate in parser.ReadCertificates (stream)) { + var certificate2 = certificate.AsX509Certificate2 (); + var certificate1 = certificate2.AsBouncyCastleCertificate (); + + Assert.AreEqual (certificate2.Thumbprint, certificate1.GetFingerprint ().ToUpperInvariant (), "Fingerprint"); + Assert.AreEqual (certificate2.GetNameInfo (X509NameType.EmailName, true), certificate1.GetIssuerNameInfo (X509Name.EmailAddress), "Issuer Email"); + Assert.AreEqual (certificate2.GetNameInfo (X509NameType.EmailName, false), certificate1.GetSubjectEmailAddress (), "Subject Email"); + Assert.AreEqual (certificate2.GetNameInfo (X509NameType.SimpleName, false), certificate1.GetCommonName (), "Common Name"); + + var usage2 = GetX509Certificate2KeyUsageFlags (certificate2); + var usage1 = certificate1.GetKeyUsageFlags (); + + Assert.AreEqual (usage2, usage1, "KeyUsageFlags"); + } + } + } + } + } +} diff --git a/UnitTests/Cryptography/CmsRecipientTests.cs b/UnitTests/Cryptography/CmsRecipientTests.cs index 890388c027..779610ef71 100644 --- a/UnitTests/Cryptography/CmsRecipientTests.cs +++ b/UnitTests/Cryptography/CmsRecipientTests.cs @@ -1,9 +1,9 @@ -// +// // CmsRecipientTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -49,6 +49,7 @@ public void TestArgumentExceptions () Assert.Throws (() => new CmsRecipient ((string) null)); var recipients = new CmsRecipientCollection (); + Assert.AreEqual (0, recipients.Count); Assert.IsFalse (recipients.IsReadOnly); Assert.Throws (() => recipients.Add (null)); @@ -61,16 +62,17 @@ public void TestArgumentExceptions () static void AssertDefaultValues (CmsRecipient recipient, X509Certificate certificate) { - Assert.AreEqual (certificate, recipient.Certificate); - Assert.AreEqual (1, recipient.EncryptionAlgorithms.Length); - Assert.AreEqual (EncryptionAlgorithm.TripleDes, recipient.EncryptionAlgorithms[0]); - Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, recipient.RecipientIdentifierType); + Assert.AreEqual (certificate, recipient.Certificate, "Certificate"); + Assert.AreEqual (1, recipient.EncryptionAlgorithms.Length, "EncryptionAlgorithms"); + Assert.AreEqual (EncryptionAlgorithm.TripleDes, recipient.EncryptionAlgorithms[0], "EncryptionAlgorithm"); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, recipient.RecipientIdentifierType, "RecipientIdentifierType"); + Assert.IsNull (recipient.RsaEncryptionPadding, "RsaEncryptionPadding"); } [Test] public void TestDefaultValues () { - var path = Path.Combine ("..", "..", "TestData", "smime", "certificate-authority.crt"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "StartComCertificationAuthority.crt"); var recipient = new CmsRecipient (path); var certificate = recipient.Certificate; @@ -89,5 +91,51 @@ public void TestDefaultValues () AssertDefaultValues (recipient, certificate); } + + [Test] + public void TestRecipientIdentifierType () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "StartComCertificationAuthority.crt"); + var recipient = new CmsRecipient (path, SubjectIdentifierType.SubjectKeyIdentifier); + var certificate = recipient.Certificate; + + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, recipient.RecipientIdentifierType); + + using (var stream = File.OpenRead (path)) + recipient = new CmsRecipient (stream, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, recipient.RecipientIdentifierType); + + recipient = new CmsRecipient (certificate, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, recipient.RecipientIdentifierType); + + recipient = new CmsRecipient (new X509Certificate2 (File.ReadAllBytes (path)), SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, recipient.RecipientIdentifierType); + } + + [Test] + public void TestCollectionAddRemove () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "StartComCertificationAuthority.crt"); + var recipients = new CmsRecipientCollection (); + var recipient = new CmsRecipient (path); + var array = new CmsRecipient[1]; + + Assert.IsFalse (recipients.Contains (recipient), "Contains: False"); + Assert.IsFalse (recipients.Remove (recipient), "Remove: False"); + + recipients.Add (recipient); + + Assert.AreEqual (1, recipients.Count, "Count"); + Assert.IsTrue (recipients.Contains (recipient), "Contains: True"); + + recipients.CopyTo (array, 0); + Assert.AreEqual (recipient, array[0], "CopyTo"); + + Assert.IsTrue (recipients.Remove (recipient), "Remove: True"); + + Assert.AreEqual (0, recipients.Count, "Count"); + + recipients.Clear (); + } } } diff --git a/UnitTests/Cryptography/CmsSignerTests.cs b/UnitTests/Cryptography/CmsSignerTests.cs index 771a595411..3bc847351d 100644 --- a/UnitTests/Cryptography/CmsSignerTests.cs +++ b/UnitTests/Cryptography/CmsSignerTests.cs @@ -1,9 +1,9 @@ -// +// // CmsSignerTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,12 +48,12 @@ public class CmsSignerTests [Test] public void TestArgumentExceptions () { - var signer = new CmsSigner (Path.Combine ("..", "..", "TestData", "smime", "smime.p12"), "no.secret"); + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"), "no.secret"); var certificate = new X509Certificate2 (signer.Certificate.GetEncoded ()); var chain = new[] { DotNetUtilities.FromX509Certificate (certificate) }; AsymmetricCipherKeyPair keyPair; - using (var stream = new StreamReader (Path.Combine ("..", "..", "TestData", "dkim", "example.pem"))) { + using (var stream = new StreamReader (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) { var reader = new PemReader (stream); keyPair = reader.ReadObject () as AsymmetricCipherKeyPair; @@ -118,7 +118,7 @@ static void LoadPkcs12 (string path, string password, out List [Test] public void TestConstructors () { - var path = Path.Combine ("..", "..", "TestData", "smime", "smime.p12"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"); List certificates; AsymmetricKeyParameter key; var password = "no.secret"; @@ -157,5 +157,109 @@ public void TestConstructors () Assert.Fail (".ctor (X509Certificate2): {0}", ex); } } + + [Test] + public void TestDefaultValues () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"); + List certificates; + AsymmetricKeyParameter key; + var password = "no.secret"; + CmsSigner signer; + + signer = new CmsSigner (path, password); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, signer.SignerIdentifierType, "new CmsSigner (string, string)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + using (var stream = File.OpenRead (path)) + signer = new CmsSigner (stream, password); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, signer.SignerIdentifierType, "new CmsSigner (Stream, string)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + LoadPkcs12 (path, password, out certificates, out key); + + signer = new CmsSigner (certificates, key); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, signer.SignerIdentifierType, "new CmsSigner (chain, key)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + signer = new CmsSigner (certificates[0], key); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, signer.SignerIdentifierType, "new CmsSigner (certificate, key)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + signer = new CmsSigner (new X509Certificate2 (path, password, X509KeyStorageFlags.Exportable)); + Assert.AreEqual (SubjectIdentifierType.IssuerAndSerialNumber, signer.SignerIdentifierType, "new CmsSigner (X509Certificate2)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + } + + [Test] + public void TestSignerIdentifierType () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"); + List certificates; + AsymmetricKeyParameter key; + var password = "no.secret"; + CmsSigner signer; + + signer = new CmsSigner (path, password, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, signer.SignerIdentifierType, "new CmsSigner (string, string)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + using (var stream = File.OpenRead (path)) + signer = new CmsSigner (stream, password, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, signer.SignerIdentifierType, "new CmsSigner (Stream, string)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + LoadPkcs12 (path, password, out certificates, out key); + + signer = new CmsSigner (certificates, key, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, signer.SignerIdentifierType, "new CmsSigner (chain, key)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + signer = new CmsSigner (certificates[0], key, SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, signer.SignerIdentifierType, "new CmsSigner (certificate, key)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + + signer = new CmsSigner (new X509Certificate2 (path, password, X509KeyStorageFlags.Exportable), SubjectIdentifierType.SubjectKeyIdentifier); + Assert.AreEqual (SubjectIdentifierType.SubjectKeyIdentifier, signer.SignerIdentifierType, "new CmsSigner (X509Certificate2)"); + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "RsaSignaturePadding"); + } + + [Test] + public void TestRsaSignaturePadding () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"); + var signer = new CmsSigner (path, "no.secret"); + + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "Default RsaSignaturePaddingScheme"); + Assert.IsNull (signer.RsaSignaturePadding, "Default RsaSignaturePadding"); + + Assert.Throws (() => signer.RsaSignaturePaddingScheme = (RsaSignaturePaddingScheme) 555); + + signer.RsaSignaturePaddingScheme = RsaSignaturePaddingScheme.Pkcs1; + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme #1"); + Assert.AreEqual (RsaSignaturePadding.Pkcs1, signer.RsaSignaturePadding, "RsaSignaturePadding #1"); + + signer.RsaSignaturePaddingScheme = RsaSignaturePaddingScheme.Pss; + Assert.AreEqual (RsaSignaturePaddingScheme.Pss, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme #2"); + Assert.AreEqual (RsaSignaturePadding.Pss, signer.RsaSignaturePadding, "RsaSignaturePadding #2"); + + signer.RsaSignaturePadding = RsaSignaturePadding.Pkcs1; + Assert.AreEqual (RsaSignaturePaddingScheme.Pkcs1, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme #3"); + Assert.AreEqual (RsaSignaturePadding.Pkcs1, signer.RsaSignaturePadding, "RsaSignaturePadding #3"); + + signer.RsaSignaturePadding = RsaSignaturePadding.Pss; + Assert.AreEqual (RsaSignaturePaddingScheme.Pss, signer.RsaSignaturePaddingScheme, "RsaSignaturePaddingScheme #4"); + Assert.AreEqual (RsaSignaturePadding.Pss, signer.RsaSignaturePadding, "RsaSignaturePadding #4"); + } } } diff --git a/UnitTests/Cryptography/DefaultSecureMimeContextTests.cs b/UnitTests/Cryptography/DefaultSecureMimeContextTests.cs index af9f8b6002..179688bed0 100644 --- a/UnitTests/Cryptography/DefaultSecureMimeContextTests.cs +++ b/UnitTests/Cryptography/DefaultSecureMimeContextTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,12 +27,13 @@ using System; using System.IO; using System.Linq; +using System.Data.Common; using System.Collections.Generic; -using System.Security.Cryptography.X509Certificates; - -using NUnit.Framework; using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1.X509; + +using NUnit.Framework; using MimeKit; using MimeKit.Cryptography; @@ -43,6 +44,16 @@ namespace UnitTests.Cryptography { [TestFixture] public class DefaultSecureMimeContextTests { + static readonly string[] CertificateAuthorities = { + "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" + }; + + static DefaultSecureMimeContextTests () + { + if (File.Exists ("smime.db")) + File.Delete ("smime.db"); + } + [Test] public void TestArgumentExceptions () { @@ -52,6 +63,59 @@ public void TestArgumentExceptions () Assert.Throws (() => new DefaultSecureMimeContext (null, "password")); Assert.Throws (() => new DefaultSecureMimeContext ("fileName", null)); + Assert.Throws (() => new SqliteCertificateDatabase ((DbConnection) null, "password")); + Assert.Throws (() => new SqliteCertificateDatabase ((string) null, "password")); + Assert.Throws (() => new SqliteCertificateDatabase (string.Empty, "password")); + Assert.Throws (() => new SqliteCertificateDatabase ("smime.db", null)); + + var database = new SqliteCertificateDatabase ("smime.db", "no.secret"); + + Assert.Throws (() => database.Add ((X509CrlRecord) null)); + Assert.Throws (() => database.Remove ((X509CrlRecord) null)); + Assert.Throws (() => database.Update ((X509CrlRecord) null)); + Assert.Throws (() => database.Add ((X509CertificateRecord) null)); + Assert.Throws (() => database.Remove ((X509CertificateRecord) null)); + Assert.Throws (() => database.Update ((X509CertificateRecord) null, X509CertificateRecordFields.Algorithms)); + Assert.Throws (() => database.Find ((X509Crl) null, X509CrlRecordFields.IsDelta)); + Assert.Throws (() => database.Find ((X509Name) null, X509CrlRecordFields.IsDelta).FirstOrDefault ()); + Assert.Throws (() => database.Find ((X509Certificate) null, X509CertificateRecordFields.Id)); + Assert.Throws (() => database.Find ((MailboxAddress) null, DateTime.Now, true, X509CertificateRecordFields.PrivateKey).FirstOrDefault ()); + + using (var ctx = new DefaultSecureMimeContext (database)) { + Assert.Throws (() => ctx.Import ((Stream) null, true)); + } + } + + [Test] + public void TestImportCertificates () + { + var database = new SqliteCertificateDatabase ("smime.db", "no.secret"); + var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "smime"); + var certificates = new List (); + + using (var ctx = new DefaultSecureMimeContext (database)) { + foreach (var filename in CertificateAuthorities) { + var path = Path.Combine (dataDir, filename); + + using (var stream = File.OpenRead (path)) { + var parser = new X509CertificateParser (); + + foreach (X509Certificate certificate in parser.ReadCertificates (stream)) { + certificates.Add (certificate); + ctx.Import (certificate); + } + } + } + + // make sure each certificate is there and then delete them... + foreach (var certificate in certificates) { + var record = database.Find (certificate, X509CertificateRecordFields.Id); + + Assert.IsNotNull (record, "Find"); + + database.Remove (record); + } + } } } } diff --git a/UnitTests/Cryptography/DkimPublicKeyLocator.cs b/UnitTests/Cryptography/DkimPublicKeyLocator.cs new file mode 100644 index 0000000000..f59d899906 --- /dev/null +++ b/UnitTests/Cryptography/DkimPublicKeyLocator.cs @@ -0,0 +1,67 @@ +// +// DkimPublicKeyLocator.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; + +using Org.BouncyCastle.Crypto; + +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography +{ + class DkimPublicKeyLocator : DkimPublicKeyLocatorBase + { + readonly Dictionary keys; + + public DkimPublicKeyLocator () + { + keys = new Dictionary (); + } + + public void Add (string key, string value) + { + keys.Add (key, value); + } + + public override AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + var query = selector + "._domainkey." + domain; + + if (keys.TryGetValue (query, out string txt)) + return GetPublicKey (txt); + + throw new Exception (string.Format ("Failed to look up public key for: {0}", domain)); + } + + public override Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + return Task.FromResult (LocatePublicKey (methods, domain, selector, cancellationToken)); + } + } +} diff --git a/UnitTests/Cryptography/DkimPublicKeyLocatorBaseTests.cs b/UnitTests/Cryptography/DkimPublicKeyLocatorBaseTests.cs new file mode 100644 index 0000000000..d0a0b90ba3 --- /dev/null +++ b/UnitTests/Cryptography/DkimPublicKeyLocatorBaseTests.cs @@ -0,0 +1,81 @@ +// +// DkimPublicKeyLocatorBaseTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +using NUnit.Framework; + +using MimeKit; +using Org.BouncyCastle.Crypto.Parameters; + +namespace UnitTests.Cryptography { + [TestFixture] + public class DkimPublicKeyLocatorBaseTests + { + [Test] + public void TestArgumentExceptions () + { + var locator = new DkimPublicKeyLocator (); + + locator.Add ("dummy._domainkey.example.org", null); + + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "dummy")); + Assert.ThrowsAsync (async () => await locator.LocatePublicKeyAsync ("dns/txt", "example.org", "dummy")); + } + + [Test] + public void TestParseExceptions () + { + var locator = new DkimPublicKeyLocator (); + + locator.Add ("empty._domainkey.example.org", string.Empty); + locator.Add ("whitespace._domainkey.example.org", " "); + locator.Add ("no-k-or-p-params._domainkey.example.org", "v=DKIM1; x=abc; y=def"); + //locator.Add ("no-k-param._domainkey.example.org", "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + locator.Add ("no-p-param._domainkey.example.org", "v=DKIM1; k=rsa"); + locator.Add ("unknown-algorithm._domainkey.example.org", "v=DKIM1; k=dummy; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id"); + + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "empty")); + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "whitespace")); + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "no-k-or-p-params")); + //Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "no-k-param")); + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "no-p-param")); + Assert.Throws (() => locator.LocatePublicKey ("dns/txt", "example.org", "unknown-algorithm")); + } + + [Test] + public void TestParseMissingKParamDefaultsToRsa () + { + var locator = new DkimPublicKeyLocator (); + + locator.Add ("no-k-param._domainkey.example.org", "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + var key = locator.LocatePublicKey ("dns/txt", "example.org", "no-k-param"); + + Assert.IsInstanceOf (key); + } + } +} diff --git a/UnitTests/Cryptography/DkimRelaxedBodyFilterTests.cs b/UnitTests/Cryptography/DkimRelaxedBodyFilterTests.cs index 327507b8bc..053d4276fd 100644 --- a/UnitTests/Cryptography/DkimRelaxedBodyFilterTests.cs +++ b/UnitTests/Cryptography/DkimRelaxedBodyFilterTests.cs @@ -1,9 +1,9 @@ -// +// // DkimRelaxedBodyFilterTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Cryptography/DkimTests.cs b/UnitTests/Cryptography/DkimTests.cs index fce912b139..c6299d9dca 100644 --- a/UnitTests/Cryptography/DkimTests.cs +++ b/UnitTests/Cryptography/DkimTests.cs @@ -1,9 +1,9 @@ -// +// // DkimTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ using Org.BouncyCastle.Crypto; using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Crypto.Parameters; using MimeKit; using MimeKit.Cryptography; @@ -43,6 +44,7 @@ namespace UnitTests.Cryptography { public class DkimTests { static readonly AsymmetricKeyParameter GMailDkimPublicKey; + static readonly AsymmetricKeyParameter Ed25519PrivateKey; static readonly AsymmetricCipherKeyPair DkimKeys; class DummyPublicKeyLocator : IDkimPublicKeyLocator @@ -67,38 +69,134 @@ public DummyPublicKeyLocator (AsymmetricKeyParameter publicKey) static DkimTests () { - using (var stream = new StreamReader (Path.Combine ("..", "..", "TestData", "dkim", "example.pem"))) { + using (var stream = new StreamReader (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) { var reader = new PemReader (stream); DkimKeys = reader.ReadObject () as AsymmetricCipherKeyPair; } // Note: you can use http://dkimcore.org/tools/dkimrecordcheck.html to get public keys manually - using (var stream = new StreamReader (Path.Combine ("..", "..", "TestData", "dkim", "gmail.pub"))) { + using (var stream = new StreamReader (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "gmail.pub"))) { var reader = new PemReader (stream); GMailDkimPublicKey = reader.ReadObject () as AsymmetricKeyParameter; } + + var rawData = Convert.FromBase64String ("nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A="); + Ed25519PrivateKey = new Ed25519PrivateKeyParameters (rawData, 0); } - static DkimSigner CreateSigner (DkimSignatureAlgorithm algorithm) + static DkimSigner CreateSigner (DkimSignatureAlgorithm algorithm, DkimCanonicalizationAlgorithm headerAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm) { - return new DkimSigner (Path.Combine ("..", "..", "TestData", "dkim", "example.pem"), "example.com", "1433868189.example") { + return new DkimSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"), "example.com", "1433868189.example") { + BodyCanonicalizationAlgorithm = bodyAlgorithm, + HeaderCanonicalizationAlgorithm = headerAlgorithm, SignatureAlgorithm = algorithm, AgentOrUserIdentifier = "@eng.example.com", - QueryMethod = "dns/txt", + QueryMethod = "dns/txt" }; } + [Test] + public void TestDkimSignerCtors () + { + Assert.DoesNotThrow (() => { + var signer = new DkimSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"), "example.com", "1433868189.example") { + SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha256, + AgentOrUserIdentifier = "@eng.example.com", + QueryMethod = "dns/txt" + }; + }); + + Assert.DoesNotThrow (() => { + var signer = new DkimSigner (DkimKeys.Private, "example.com", "1433868189.example") { + SignatureAlgorithm = DkimSignatureAlgorithm.RsaSha256, + AgentOrUserIdentifier = "@eng.example.com", + QueryMethod = "dns/txt" + }; + }); + } + + [Test] + public void TestDkimSignerDefaults () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"); + DkimSigner signer; + + signer = new DkimSigner (DkimKeys.Private, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #1"); + + signer = new DkimSigner (path, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #2"); + + using (var stream = File.OpenRead (path)) { + signer = new DkimSigner (stream, "example.com", "1433868189.example"); + Assert.AreEqual (DkimSignatureAlgorithm.RsaSha256, signer.SignatureAlgorithm, "SignatureAlgorithm #3"); + } + } + + [Test] + public void TestDkimVerifierDefaults () + { + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); + + Assert.AreEqual (1024, verifier.MinimumRsaKeyLength, "MinimumRsaKeyLength"); + Assert.IsFalse (verifier.IsEnabled (DkimSignatureAlgorithm.RsaSha1), "rsa-sha1"); + Assert.IsTrue (verifier.IsEnabled (DkimSignatureAlgorithm.RsaSha256), "rsa-sha256"); + } + + [Test] + public void TestDkimVerifierEnableDisable () + { + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); + + Assert.IsFalse (verifier.IsEnabled (DkimSignatureAlgorithm.RsaSha1), "initial value"); + + verifier.Enable (DkimSignatureAlgorithm.RsaSha1); + Assert.IsTrue (verifier.IsEnabled (DkimSignatureAlgorithm.RsaSha1), "rsa-sha1 enabled"); + + verifier.Disable (DkimSignatureAlgorithm.RsaSha1); + Assert.IsFalse (verifier.IsEnabled (DkimSignatureAlgorithm.RsaSha1), "rsa-sha1 disabled"); + } + + [Test] + public void TestDkimHashStream () + { + var buffer = new byte[128]; + + using (var stream = new DkimHashStream (DkimSignatureAlgorithm.RsaSha1)) { + Assert.IsFalse (stream.CanRead); + Assert.IsTrue (stream.CanWrite); + Assert.IsFalse (stream.CanSeek); + Assert.IsFalse (stream.CanTimeout); + + Assert.Throws (() => stream.Read (buffer, 0, buffer.Length)); + + Assert.Throws (() => stream.Write (null, 0, 0)); + Assert.Throws (() => stream.Write (buffer, -1, 0)); + Assert.Throws (() => stream.Write (buffer, 0, -1)); + + Assert.AreEqual (0, stream.Position); + Assert.AreEqual (0, stream.Length); + + Assert.Throws (() => stream.Position = 64); + + Assert.Throws (() => stream.Seek (64, SeekOrigin.Begin)); + Assert.Throws (() => stream.SetLength (256)); + + stream.Flush (); + } + } + [Test] public void TestDkimSignatureStream () { - var signer = CreateSigner (DkimSignatureAlgorithm.RsaSha1); + var signer = CreateSigner (DkimSignatureAlgorithm.RsaSha1, DkimCanonicalizationAlgorithm.Simple, DkimCanonicalizationAlgorithm.Simple); var buffer = new byte[128]; Assert.Throws (() => new DkimSignatureStream (null)); - using (var stream = new DkimSignatureStream (signer.DigestSigner)) { + using (var stream = new DkimSignatureStream (signer.CreateSigningContext ())) { Assert.IsFalse (stream.CanRead); Assert.IsTrue (stream.CanWrite); Assert.IsFalse (stream.CanSeek); @@ -110,6 +208,7 @@ public void TestDkimSignatureStream () Assert.Throws (() => stream.Write (buffer, -1, 0)); Assert.Throws (() => stream.Write (buffer, 0, -1)); + Assert.AreEqual (0, stream.Position); Assert.AreEqual (0, stream.Length); Assert.Throws (() => stream.Position = 64); @@ -118,6 +217,8 @@ public void TestDkimSignatureStream () Assert.Throws (() => stream.SetLength (256)); Assert.Throws (() => stream.VerifySignature (null)); + + stream.Flush (); } } @@ -141,8 +242,9 @@ static void VerifyDkimBodyHash (MimeMessage message, DkimSignatureAlgorithm algo static void TestEmptyBody (DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash) { + var signer = CreateSigner (signatureAlgorithm, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm); var headers = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date }; - var signer = CreateSigner (signatureAlgorithm); + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); var message = new MimeMessage (); message.From.Add (new MailboxAddress ("", "mimekit@example.com")); @@ -152,22 +254,31 @@ static void TestEmptyBody (DkimSignatureAlgorithm signatureAlgorithm, DkimCanoni message.Body = new TextPart ("plain") { Text = "" }; - message.Body.Prepare (EncodingConstraint.SevenBit); + message.Prepare (EncodingConstraint.SevenBit); - message.Sign (signer, headers, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm); + signer.Sign (message, headers); VerifyDkimBodyHash (message, signatureAlgorithm, expectedHash); var dkim = message.Headers[0]; - Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature."); + if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1) { + Assert.IsFalse (verifier.Verify (message, dkim), "DKIM-Signature using rsa-sha1 should not verify."); + + // now enable rsa-sha1 to verify again, this time it should pass... + verifier.Enable (DkimSignatureAlgorithm.RsaSha1); + } + + Assert.IsTrue (verifier.Verify (message, dkim), "Failed to verify DKIM-Signature."); } [Test] public void TestArgumentExceptions () { var locator = new DummyPublicKeyLocator (DkimKeys.Public); + var verifier = new DkimVerifier (locator); var dkimHeader = new Header (HeaderId.DkimSignature, "value"); + var arcHeader = new Header (HeaderId.ArcMessageSignature, "value"); var options = FormatOptions.Default; var message = new MimeMessage (); DkimSigner signer; @@ -181,7 +292,7 @@ public void TestArgumentExceptions () Assert.Throws (() => new DkimSigner ("fileName", "domain", null)); Assert.Throws (() => new DkimSigner (string.Empty, "domain", "selector")); Assert.Throws (() => new DkimSigner ((Stream) null, "domain", "selector")); - using (var stream = File.OpenRead (Path.Combine ("..", "..", "TestData", "dkim", "example.pem"))) { + using (var stream = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) { Assert.Throws (() => new DkimSigner (stream, null, "selector")); Assert.Throws (() => new DkimSigner (stream, "domain", null)); @@ -192,6 +303,44 @@ public void TestArgumentExceptions () }; } + Assert.Throws (() => signer.Sign (null, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (message, (IList) null)); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.Unknown, HeaderId.From })); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.Received, HeaderId.From })); + Assert.Throws (() => signer.Sign (message, new HeaderId[] { HeaderId.ContentType })); + Assert.Throws (() => signer.Sign (null, new string[] { "From" })); + Assert.Throws (() => signer.Sign (message, (IList) null)); + Assert.Throws (() => signer.Sign (message, new string[] { "", "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { null, "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { "Received", "From" })); + Assert.Throws (() => signer.Sign (message, new string[] { "Content-Type" })); + + Assert.Throws (() => signer.Sign (null, message, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (options, null, new HeaderId[] { HeaderId.From })); + Assert.Throws (() => signer.Sign (options, message, new HeaderId[] { HeaderId.From, HeaderId.Unknown })); + Assert.Throws (() => signer.Sign (options, message, (IList) null)); + + Assert.Throws (() => signer.Sign (null, message, new string[] { "From" })); + Assert.Throws (() => signer.Sign (options, null, new string[] { "From" })); + Assert.Throws (() => signer.Sign (options, message, new string[] { "From", null })); + Assert.Throws (() => signer.Sign (options, message, (IList) null)); + + Assert.Throws (() => new DkimVerifier (null)); + + Assert.Throws (() => verifier.Verify (null, dkimHeader)); + Assert.Throws (() => verifier.Verify (message, null)); + Assert.Throws (() => verifier.Verify (null, message, dkimHeader)); + Assert.Throws (() => verifier.Verify (FormatOptions.Default, null, dkimHeader)); + Assert.Throws (() => verifier.Verify (FormatOptions.Default, message, null)); + Assert.Throws (() => verifier.Verify (FormatOptions.Default, message, arcHeader)); + + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (null, dkimHeader)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (message, null)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (null, message, dkimHeader)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (FormatOptions.Default, null, dkimHeader)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (FormatOptions.Default, message, null)); + Assert.ThrowsAsync (async () => await verifier.VerifyAsync (FormatOptions.Default, message, arcHeader)); + Assert.Throws (() => message.Sign (null, new HeaderId[] { HeaderId.From })); Assert.Throws (() => message.Sign (signer, (IList) null)); Assert.Throws (() => message.Sign (signer, new HeaderId[] { HeaderId.Unknown, HeaderId.From })); @@ -219,36 +368,100 @@ public void TestArgumentExceptions () Assert.Throws (() => message.Verify (null, dkimHeader, locator)); Assert.Throws (() => message.Verify (FormatOptions.Default, null, locator)); Assert.Throws (() => message.Verify (FormatOptions.Default, dkimHeader, null)); + Assert.Throws (() => message.Verify (FormatOptions.Default, arcHeader, locator)); + + Assert.ThrowsAsync (async () => await message.VerifyAsync (null, locator)); + Assert.ThrowsAsync (async () => await message.VerifyAsync (dkimHeader, null)); + Assert.ThrowsAsync (async () => await message.VerifyAsync (null, dkimHeader, locator)); + Assert.ThrowsAsync (async () => await message.VerifyAsync (FormatOptions.Default, null, locator)); + Assert.ThrowsAsync (async () => await message.VerifyAsync (FormatOptions.Default, dkimHeader, null)); + Assert.ThrowsAsync (async () => await message.VerifyAsync (FormatOptions.Default, arcHeader, locator)); } [Test] - public void TestEmptySimpleBodySha1 () + public void TestFormatExceptions () + { + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "gmail.msg")); + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); + var index = message.Headers.IndexOf (HeaderId.DkimSignature); + var dkim = message.Headers[index]; + var original = dkim.Value; + + // first, remove the 'v' tag and its value + dkim.Value = dkim.Value.Substring (4); + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for missing v=1;"); + + // add back a 'v' tag with an invalid value + dkim.Value = "v=x; " + dkim.Value; + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for v=x;"); + + // remove "from:" + dkim.Value = original.Replace ("from:", ""); + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for missing from header"); + + // add an invalid i= value w/o an '@' + dkim.Value = "i=1; " + original; + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid i= value (missing '@')"); + + // add an invalid i= value that does not match the domain + dkim.Value = "i=user@domain; " + original; + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid i= that does not contain the domain"); + + // add an invalid l= value + dkim.Value = "l=abc; " + original; + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid l= value"); + + // set an invalid body canonicalization algorithm + dkim.Value = original.Replace ("c=relaxed/relaxed;", "c=simple/complex;"); + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid body canonicalization value"); + + // set an invalid c= value + dkim.Value = original.Replace ("c=relaxed/relaxed;", "c=;"); + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid c= value (empty)"); + + // set an invalid c= value + dkim.Value = original.Replace ("c=relaxed/relaxed;", "c=relaxed/relaxed/extra;"); + + Assert.Throws (() => verifier.Verify (message, dkim), "Expected FormatException for an invalid c= value (3 values)"); + } + + [Test] + public void TestEmptySimpleBodyRsaSha1 () { TestEmptyBody (DkimSignatureAlgorithm.RsaSha1, DkimCanonicalizationAlgorithm.Simple, "uoq1oCgLlTqpdDX/iUbLy7J1Wic="); } [Test] - public void TestEmptySimpleBodySha256 () + public void TestEmptySimpleBodyRsaSha256 () { TestEmptyBody (DkimSignatureAlgorithm.RsaSha256, DkimCanonicalizationAlgorithm.Simple, "frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY="); } [Test] - public void TestEmptyRelaxedBodySha1 () + public void TestEmptyRelaxedBodyRsaSha1 () { TestEmptyBody (DkimSignatureAlgorithm.RsaSha1, DkimCanonicalizationAlgorithm.Relaxed, "2jmj7l5rSw0yVb/vlWAYkK/YBwk="); } [Test] - public void TestEmptyRelaxedBodySha256 () + public void TestEmptyRelaxedBodyRsaSha256 () { TestEmptyBody (DkimSignatureAlgorithm.RsaSha256, DkimCanonicalizationAlgorithm.Relaxed, "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="); } static void TestUnicode (DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm, string expectedHash) { + var signer = CreateSigner (signatureAlgorithm, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm); var headers = new [] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date }; - var signer = CreateSigner (signatureAlgorithm); + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); var message = new MimeMessage (); message.From.Add (new MailboxAddress ("", "mimekit@example.com")); @@ -264,37 +477,44 @@ static void TestUnicode (DkimSignatureAlgorithm signatureAlgorithm, DkimCanonica ((Multipart) message.Body).Boundary = "=-MultipartAlternativeBoundary"; ((Multipart) message.Body)[1].ContentId = null; - message.Body.Prepare (EncodingConstraint.EightBit); + message.Prepare (EncodingConstraint.EightBit); - message.Sign (signer, headers, DkimCanonicalizationAlgorithm.Simple, bodyAlgorithm); + signer.Sign (message, headers); var dkim = message.Headers[0]; VerifyDkimBodyHash (message, signatureAlgorithm, expectedHash); - Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature."); + if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1) { + Assert.IsFalse (verifier.Verify (message, dkim), "DKIM-Signature using rsa-sha1 should not verify."); + + // now enable rsa-sha1 to verify again, this time it should pass... + verifier.Enable (DkimSignatureAlgorithm.RsaSha1); + } + + Assert.IsTrue (verifier.Verify (message, dkim), "Failed to verify DKIM-Signature."); } [Test] - public void TestUnicodeSimpleBodySha1 () + public void TestUnicodeSimpleBodyRsaSha1 () { TestUnicode (DkimSignatureAlgorithm.RsaSha1, DkimCanonicalizationAlgorithm.Simple, "6GV1ZoyaprYbwRLXsr5+8zY5Jh0="); } [Test] - public void TestUnicodeSimpleBodySha256 () + public void TestUnicodeSimpleBodyRsaSha256 () { TestUnicode (DkimSignatureAlgorithm.RsaSha256, DkimCanonicalizationAlgorithm.Simple, "BuW/GpCA9rAVDfStp0Dc2duuFhmwcxhy5jOeL+Xn+ew="); } [Test] - public void TestUnicodeRelaxedBodySha1 () + public void TestUnicodeRelaxedBodyRsaSha1 () { TestUnicode (DkimSignatureAlgorithm.RsaSha1, DkimCanonicalizationAlgorithm.Relaxed, "bbT6nP0aAiAP5OMguA+mHgpzgh4="); } [Test] - public void TestUnicodeRelaxedBodySha256 () + public void TestUnicodeRelaxedBodyRsaSha256 () { TestUnicode (DkimSignatureAlgorithm.RsaSha256, DkimCanonicalizationAlgorithm.Relaxed, "PEaN3fYH5NdIg4QzgaSS+ceYlSMRnYbqCPMxncx6gy0="); } @@ -302,73 +522,151 @@ public void TestUnicodeRelaxedBodySha256 () [Test] public void TestVerifyGoogleMailDkimSignature () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "gmail.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "gmail.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); - Assert.IsTrue (message.Verify (message.Headers[index], locator), "Failed to verify GMail signature."); + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify GMail signature."); } [Test] - public async void TestVerifyGoogleMailDkimSignatureAsync () + public async Task TestVerifyGoogleMailDkimSignatureAsync () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "gmail.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "gmail.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); - Assert.IsTrue (await message.VerifyAsync (message.Headers[index], locator), "Failed to verify GMail signature."); + Assert.IsTrue (await verifier.VerifyAsync (message, message.Headers[index]), "Failed to verify GMail signature."); } [Test] public void TestVerifyGoogleMultipartRelatedDkimSignature () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "related.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "related.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); - Assert.IsTrue (message.Verify (message.Headers[index], locator), "Failed to verify GMail signature."); + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify GMail signature."); } [Test] - public async void TestVerifyGoogleMultipartRelatedDkimSignatureAsync () + public async Task TestVerifyGoogleMultipartRelatedDkimSignatureAsync () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "related.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "related.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); - Assert.IsTrue (await message.VerifyAsync (message.Headers[index], locator), "Failed to verify GMail signature."); + Assert.IsTrue (await verifier.VerifyAsync (message, message.Headers[index]), "Failed to verify GMail signature."); } [Test] public void TestVerifyGoogleMultipartWithoutEndBoundaryDkimSignature () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "multipart-no-end-boundary.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "multipart-no-end-boundary.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); - Assert.IsTrue (message.Verify (message.Headers[index], locator), "Failed to verify GMail signature."); + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify GMail signature."); } [Test] - public async void TestVerifyGoogleMultipartWithoutEndBoundaryDkimSignatureAsync () + public async Task TestVerifyGoogleMultipartWithoutEndBoundaryDkimSignatureAsync () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "dkim", "multipart-no-end-boundary.msg")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "multipart-no-end-boundary.msg")); int index = message.Headers.IndexOf (HeaderId.DkimSignature); var locator = new DummyPublicKeyLocator (GMailDkimPublicKey); + var verifier = new DkimVerifier (locator); + + Assert.IsTrue (await verifier.VerifyAsync (message, message.Headers[index]), "Failed to verify GMail signature."); + } + + [Test] + public void TestSignRfc8463Example () + { + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "rfc8463-example.msg")); + var signer = new DkimSigner (Ed25519PrivateKey, "football.example.com", "brisbane", DkimSignatureAlgorithm.Ed25519Sha256) { + HeaderCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed, + BodyCanonicalizationAlgorithm = DkimCanonicalizationAlgorithm.Relaxed, + AgentOrUserIdentifier = "@football.example.com" + }; + var headers = new string[] { "from", "to", "subject", "date", "message-id", "from", "subject", "date" }; + + signer.Sign (message, headers); + + int index = message.Headers.IndexOf (HeaderId.DkimSignature); + var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); + var dkim = message.Headers[index]; + + locator.Add ("brisbane._domainkey.football.example.com", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="); + locator.Add ("test._domainkey.football.example.com", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify ed25519-sha256"); + } + + [Test] + public void TestVerifyRfc8463Example () + { + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "rfc8463-example.msg")); + var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); + int index; + + locator.Add ("brisbane._domainkey.football.example.com", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="); + locator.Add ("test._domainkey.football.example.com", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + // the last DKIM-Signature uses rsa-sha256 + index = message.Headers.LastIndexOf (HeaderId.DkimSignature); + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify rsa-sha256"); + + // the first DKIM-Signature uses ed25519-sha256 + index = message.Headers.IndexOf (HeaderId.DkimSignature); + Assert.IsTrue (verifier.Verify (message, message.Headers[index]), "Failed to verify ed25519-sha256"); + } + + [Test] + public async Task TestVerifyRfc8463ExampleAsync () + { + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "rfc8463-example.msg")); + var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); + int index; + + locator.Add ("brisbane._domainkey.football.example.com", "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="); + locator.Add ("test._domainkey.football.example.com", "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"); + + // the last DKIM-Signature uses rsa-sha256 + index = message.Headers.LastIndexOf (HeaderId.DkimSignature); + Assert.IsTrue (await verifier.VerifyAsync (message, message.Headers[index]), "Failed to verify rsa-sha256"); - Assert.IsTrue (await message.VerifyAsync (message.Headers[index], locator), "Failed to verify GMail signature."); + // the first DKIM-Signature uses ed25519-sha256 + index = message.Headers.IndexOf (HeaderId.DkimSignature); + Assert.IsTrue (await verifier.VerifyAsync (message, message.Headers[index]), "Failed to verify ed25519-sha256"); } static void TestDkimSignVerify (MimeMessage message, DkimSignatureAlgorithm signatureAlgorithm, DkimCanonicalizationAlgorithm headerAlgorithm, DkimCanonicalizationAlgorithm bodyAlgorithm) { var headers = new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date }; - var signer = CreateSigner (signatureAlgorithm); + var verifier = new DkimVerifier (new DummyPublicKeyLocator (DkimKeys.Public)); + var signer = CreateSigner (signatureAlgorithm, headerAlgorithm, bodyAlgorithm); - message.Sign (signer, headers, headerAlgorithm, bodyAlgorithm); + signer.Sign (message, headers); var dkim = message.Headers[0]; - Assert.IsTrue (message.Verify (dkim, new DummyPublicKeyLocator (DkimKeys.Public)), "Failed to verify DKIM-Signature."); + if (signatureAlgorithm == DkimSignatureAlgorithm.RsaSha1) { + Assert.IsFalse (verifier.Verify (message, dkim), "DKIM-Signature using rsa-sha1 should not verify."); + + // now enable rsa-sha1 to verify again, this time it should pass... + verifier.Enable (DkimSignatureAlgorithm.RsaSha1); + } + + Assert.IsTrue (verifier.Verify (message, dkim), "Failed to verify DKIM-Signature."); message.Headers.RemoveAt (0); } @@ -377,7 +675,7 @@ static void TestDkimSignVerify (MimeMessage message, DkimSignatureAlgorithm sign //[Ignore] public void TestDkimSignVerifyJwzMbox () { - using (var stream = File.OpenRead ("../../TestData/mbox/jwz.mbox.txt")) { + using (var stream = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "mbox", "jwz.mbox.txt"))) { var parser = new MimeParser (stream, MimeFormat.Mbox); int i = 0; diff --git a/UnitTests/Cryptography/DummyArcSigner.cs b/UnitTests/Cryptography/DummyArcSigner.cs new file mode 100644 index 0000000000..29ed69bd79 --- /dev/null +++ b/UnitTests/Cryptography/DummyArcSigner.cs @@ -0,0 +1,102 @@ +// +// DummyArcSigner.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Org.BouncyCastle.Crypto; + +using MimeKit; +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + public class DummyArcSigner : ArcSigner + { + public DummyArcSigner (Stream stream, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (stream, domain, selector, algorithm) + { + } + + public DummyArcSigner (string fileName, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (fileName, domain, selector, algorithm) + { + } + + public DummyArcSigner (AsymmetricKeyParameter key, string domain, string selector, DkimSignatureAlgorithm algorithm = DkimSignatureAlgorithm.RsaSha256) : base (key, domain, selector, algorithm) + { + } + + public IDkimPublicKeyLocator PublicKeyLocator { + get; set; + } + + public string SrvId { + get; set; + } + + public long Timestamp { + get; set; + } + + protected override AuthenticationResults GenerateArcAuthenticationResults (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + var results = new AuthenticationResults (SrvId); + + for (int i = 0; i < message.Headers.Count; i++) { + var header = message.Headers[i]; + + if (header.Id != HeaderId.AuthenticationResults) + continue; + + if (!AuthenticationResults.TryParse (header.RawValue, out AuthenticationResults authres)) + continue; + + if (authres.AuthenticationServiceIdentifier != SrvId) + continue; + + foreach (var result in authres.Results) { + if (!results.Results.Any (r => r.Method == result.Method)) + results.Results.Add (result); + } + } + + return results; + } + + protected override Task GenerateArcAuthenticationResultsAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken) + { + return Task.FromResult (GenerateArcAuthenticationResults (options, message, cancellationToken)); + } + + protected override long GetTimestamp () + { + base.GetTimestamp (); + + return Timestamp; + } + } +} diff --git a/UnitTests/Cryptography/DummyOpenPgpContext.cs b/UnitTests/Cryptography/DummyOpenPgpContext.cs index f0161a665c..c0602e9381 100644 --- a/UnitTests/Cryptography/DummyOpenPgpContext.cs +++ b/UnitTests/Cryptography/DummyOpenPgpContext.cs @@ -1,9 +1,9 @@ -// +// // DummyOpenPgpContext.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Cryptography/DummySecureMimeContext.cs b/UnitTests/Cryptography/DummySecureMimeContext.cs deleted file mode 100644 index 900629d34c..0000000000 --- a/UnitTests/Cryptography/DummySecureMimeContext.cs +++ /dev/null @@ -1,363 +0,0 @@ -// -// DummySecureMimeContext.cs -// -// Author: Jeffrey Stedfast -// -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) -// -// 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. -// - -using System; -using System.IO; -using System.Collections.Generic; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Pkcs; -using Org.BouncyCastle.Pkix; -using Org.BouncyCastle.X509; -using Org.BouncyCastle.X509.Store; -using Org.BouncyCastle.Asn1.X509; - -using MimeKit; -using MimeKit.Cryptography; - -namespace UnitTests.Cryptography { - public class DummySecureMimeContext : BouncyCastleSecureMimeContext - { - readonly Dictionary capabilities = new Dictionary (); - internal readonly Dictionary keys = new Dictionary (); - internal readonly List certificates = new List (); - internal readonly List crls = new List (); - - /// - /// Check whether or not a particular mailbox address can be used for signing. - /// - /// - /// Checks whether or not as particular mailbocx address can be used for signing. - /// - /// true if the mailbox address can be used for signing; otherwise, false. - /// The signer. - /// - /// is null. - /// - public override bool CanSign (MailboxAddress signer) - { - if (signer == null) - throw new ArgumentNullException (nameof (signer)); - - AsymmetricKeyParameter key; - - return GetCmsSignerCertificate (signer, out key) != null; - } - - /// - /// Check whether or not the cryptography context can encrypt to a particular recipient. - /// - /// - /// Checks whether or not the cryptography context can be used to encrypt to a particular recipient. - /// - /// true if the cryptography context can be used to encrypt to the designated recipient; otherwise, false. - /// The recipient's mailbox address. - /// - /// is null. - /// - public override bool CanEncrypt (MailboxAddress mailbox) - { - if (mailbox == null) - throw new ArgumentNullException (nameof (mailbox)); - - return GetCmsRecipientCertificate (mailbox) != null; - } - - #region implemented abstract members of SecureMimeContext - - /// - /// Gets the X.509 certificate based on the selector. - /// - /// The certificate on success; otherwise null. - /// The search criteria for the certificate. - protected override X509Certificate GetCertificate (IX509Selector selector) - { - if (selector == null && certificates.Count > 0) - return certificates[0]; - - foreach (var certificate in certificates) { - if (selector.Match (certificate)) - return certificate; - } - - return null; - } - - /// - /// Gets the private key based on the provided selector. - /// - /// The private key on success; otherwise null. - /// The search criteria for the private key. - protected override AsymmetricKeyParameter GetPrivateKey (IX509Selector selector) - { - foreach (var certificate in certificates) { - AsymmetricKeyParameter key; - - if (!keys.TryGetValue (certificate, out key)) - continue; - - if (selector != null && !selector.Match (certificate)) - continue; - - return key; - } - - return null; - } - - /// - /// Gets the trusted anchors. - /// - /// The trusted anchors. - protected override Org.BouncyCastle.Utilities.Collections.HashSet GetTrustedAnchors () - { - var anchors = new Org.BouncyCastle.Utilities.Collections.HashSet (); - - foreach (var certificate in certificates) { - anchors.Add (new TrustAnchor (certificate, null)); - } - - return anchors; - } - - /// - /// Gets the intermediate certificates. - /// - /// The intermediate certificates. - protected override IX509Store GetIntermediateCertificates () - { - var store = new X509CertificateStore (); - - foreach (var certificate in certificates) { - store.Add (certificate); - } - - return store; - } - - /// - /// Gets the certificate revocation lists. - /// - /// The certificate revocation lists. - protected override IX509Store GetCertificateRevocationLists () - { - return X509StoreFactory.Create ("Crl/Collection", new X509CollectionStoreParameters (crls)); - } - - /// - /// Get the date & time for the next scheduled certificate revocation list update for the specified issuer. - /// - /// - /// Gets the date & time for the next scheduled certificate revocation list update for the specified issuer. - /// - /// The date & time for the next update. - /// The issuer. - protected override DateTime GetNextCertificateRevocationListUpdate (X509Name issuer) - { - var nextUpdate = DateTime.MinValue.ToUniversalTime (); - - foreach (var crl in crls) { - if (!crl.IssuerDN.Equals (issuer)) - continue; - - nextUpdate = crl.NextUpdate.Value > nextUpdate ? crl.NextUpdate.Value : nextUpdate; - } - - return nextUpdate; - } - - X509Certificate GetCmsRecipientCertificate (MailboxAddress mailbox) - { - var now = DateTime.UtcNow; - - foreach (var certificate in certificates) { - if (certificate.NotBefore > now || certificate.NotAfter < now) - continue; - - var keyUsage = certificate.GetKeyUsageFlags (); - if (keyUsage != 0 && (keyUsage & X509KeyUsageFlags.KeyEncipherment) == 0) - continue; - - if (certificate.GetSubjectEmailAddress () == mailbox.Address) - return certificate; - } - - return null; - } - - /// - /// Gets the for the specified mailbox. - /// - /// A . - /// The mailbox. - /// - /// A certificate for the specified could not be found. - /// - protected override CmsRecipient GetCmsRecipient (MailboxAddress mailbox) - { - X509Certificate certificate; - - if ((certificate = GetCmsRecipientCertificate (mailbox)) == null) - throw new CertificateNotFoundException (mailbox, "A valid certificate could not be found."); - - var recipient = new CmsRecipient (certificate); - EncryptionAlgorithm[] algorithms; - - if (capabilities.TryGetValue (certificate, out algorithms)) - recipient.EncryptionAlgorithms = algorithms; - - return recipient; - } - - X509Certificate GetCmsSignerCertificate (MailboxAddress mailbox, out AsymmetricKeyParameter key) - { - var now = DateTime.UtcNow; - - foreach (var certificate in certificates) { - if (certificate.NotBefore > now || certificate.NotAfter < now) - continue; - - var keyUsage = certificate.GetKeyUsageFlags (); - if (keyUsage != 0 && (keyUsage & SecureMimeContext.DigitalSignatureKeyUsageFlags) == 0) - continue; - - if (!keys.TryGetValue (certificate, out key)) - continue; - - if (certificate.GetSubjectEmailAddress () == mailbox.Address) - return certificate; - } - - key = null; - - return null; - } - - /// - /// Gets the for the specified mailbox. - /// - /// A . - /// The mailbox. - /// The preferred digest algorithm. - /// - /// A certificate for the specified could not be found. - /// - protected override CmsSigner GetCmsSigner (MailboxAddress mailbox, DigestAlgorithm digestAlgo) - { - X509Certificate certificate; - AsymmetricKeyParameter key; - - if ((certificate = GetCmsSignerCertificate (mailbox, out key)) == null) - throw new CertificateNotFoundException (mailbox, "A valid signing certificate could not be found."); - - var signer = new CmsSigner (certificate, key); - signer.DigestAlgorithm = digestAlgo; - return signer; - } - - /// - /// Updates the known S/MIME capabilities of the client used by the recipient that owns the specified certificate. - /// - /// The certificate. - /// The encryption algorithm capabilities of the client (in preferred order). - /// The timestamp. - protected override void UpdateSecureMimeCapabilities (X509Certificate certificate, EncryptionAlgorithm[] algorithms, DateTime timestamp) - { - capabilities[certificate] = algorithms; - } - - /// - /// Import the specified certificate. - /// - /// The certificate. - /// - /// is null. - /// - public override void Import (X509Certificate certificate) - { - if (certificate == null) - throw new ArgumentNullException ("certificate"); - - certificates.Add (certificate); - } - - /// - /// Import the specified certificate revocation list. - /// - /// The certificate revocation list. - /// - /// is null. - /// - public override void Import (X509Crl crl) - { - if (crl == null) - throw new ArgumentNullException ("crl"); - - crls.Add (crl); - } - - /// - /// Imports certificates and keys from a pkcs12-encoded stream. - /// - /// The raw certificate and key data. - /// The password to unlock the data. - /// - /// is null. - /// -or- - /// is null. - /// - /// - /// Importing keys is not supported by this cryptography context. - /// - public override void Import (Stream stream, string password) - { - if (stream == null) - throw new ArgumentNullException ("stream"); - - if (password == null) - throw new ArgumentNullException ("password"); - - var pkcs12 = new Pkcs12Store (stream, password.ToCharArray ()); - - foreach (string alias in pkcs12.Aliases) { - if (pkcs12.IsKeyEntry (alias)) { - var chain = pkcs12.GetCertificateChain (alias); - var entry = pkcs12.GetKey (alias); - - for (int i = 0; i < chain.Length; i++) - certificates.Add (chain[i].Certificate); - - keys.Add (chain[0].Certificate, entry.Key); - } else if (pkcs12.IsCertificateEntry (alias)) { - var entry = pkcs12.GetCertificate (alias); - certificates.Add (entry.Certificate); - } - } - } - - #endregion - } -} diff --git a/UnitTests/Cryptography/LdapUriTests.cs b/UnitTests/Cryptography/LdapUriTests.cs index 812a4fb38b..50ac20d27b 100644 --- a/UnitTests/Cryptography/LdapUriTests.cs +++ b/UnitTests/Cryptography/LdapUriTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2018 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Cryptography/PgpMimeTests.cs b/UnitTests/Cryptography/PgpMimeTests.cs index bd8276fb27..1039bb918e 100644 --- a/UnitTests/Cryptography/PgpMimeTests.cs +++ b/UnitTests/Cryptography/PgpMimeTests.cs @@ -1,9 +1,9 @@ -// +// // PgpMimeTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ public class PgpMimeTests static PgpMimeTests () { Environment.SetEnvironmentVariable ("GNUPGHOME", Path.GetFullPath (".")); - var dataDir = Path.Combine ("..", "..", "TestData", "openpgp"); + var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "openpgp"); CryptographyContext.Register (typeof (DummyOpenPgpContext)); @@ -231,20 +231,28 @@ public void TestMimeMessageSign () var signatures = multipart.Verify (ctx); Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); - foreach (var signature in signatures) { - try { - bool valid = signature.Verify (); - Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); - } catch (DigitalSignatureVerifyException ex) { - Assert.Fail ("Failed to verify signature: {0}", ex); - } + var signature = signatures[0]; + + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual ("44CD48EEC90D8849961F36BA50DCD107AB0821A2", signature.SignerCertificate.Fingerprint); + Assert.AreEqual (new DateTime (2013, 11, 3, 18, 32, 27), signature.SignerCertificate.CreationDate, "CreationDate"); + Assert.AreEqual (DateTime.MaxValue, signature.SignerCertificate.ExpirationDate, "ExpirationDate"); + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, signature.SignerCertificate.PublicKeyAlgorithm); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + Assert.Fail ("Failed to verify signature: {0}", ex); } } } [Test] - public async void TestMimeMessageSignAsync () + public async Task TestMimeMessageSignAsync () { var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); @@ -278,14 +286,22 @@ public async void TestMimeMessageSignAsync () var signatures = await multipart.VerifyAsync (ctx); Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); - foreach (var signature in signatures) { - try { - bool valid = signature.Verify (); - Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); - } catch (DigitalSignatureVerifyException ex) { - Assert.Fail ("Failed to verify signature: {0}", ex); - } + var signature = signatures[0]; + + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual ("44CD48EEC90D8849961F36BA50DCD107AB0821A2", signature.SignerCertificate.Fingerprint); + Assert.AreEqual (new DateTime (2013, 11, 3, 18, 32, 27), signature.SignerCertificate.CreationDate, "CreationDate"); + Assert.AreEqual (DateTime.MaxValue, signature.SignerCertificate.ExpirationDate, "ExpirationDate"); + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, signature.SignerCertificate.PublicKeyAlgorithm); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + Assert.Fail ("Failed to verify signature: {0}", ex); } } } @@ -339,7 +355,7 @@ public void TestMultipartSignedSignUsingKeys () } [Test] - public async void TestMultipartSignedSignUsingKeysAsync () + public async Task TestMultipartSignedSignUsingKeysAsync () { var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; var self = new SecureMailboxAddress ("MimeKit UnitTests", "mimekit@example.com", "44CD48EEC90D8849961F36BA50DCD107AB0821A2"); @@ -454,8 +470,20 @@ public void TestMultipartEncryptedEncrypt () var encrypted = MultipartEncrypted.Encrypt (new [] { self }, body); - //using (var file = File.Create ("pgp-encrypted.asc")) - // encrypted.WriteTo (file); + using (var stream = new MemoryStream ()) { + encrypted.WriteTo (stream); + stream.Position = 0; + + var entity = MimeEntity.Load (stream); + + Assert.IsInstanceOf (entity, "Encrypted part is not the expected type"); + + encrypted = (MultipartEncrypted) entity; + + Assert.IsInstanceOf (encrypted[0], "First child of multipart/encrypted is not the expected type"); + Assert.IsInstanceOf (encrypted[1], "Second child of multipart/encrypted is not the expected type"); + Assert.AreEqual ("application/octet-stream", encrypted[1].ContentType.MimeType, "Second child of multipart/encrypted is not the expected mime-type"); + } var decrypted = encrypted.Decrypt (); @@ -752,7 +780,7 @@ public void TestMultipartEncryptedSignAndEncryptALgorithmUsingKeys () [Test] public void TestAutoKeyRetrieve () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "openpgp", "[Announce] GnuPG 2.1.20 released.eml")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "openpgp", "[Announce] GnuPG 2.1.20 released.eml")); var multipart = (MultipartSigned) ((Multipart) message.Body)[0]; Assert.AreEqual (2, multipart.Count, "The multipart/signed has an unexpected number of children."); @@ -767,7 +795,19 @@ public void TestAutoKeyRetrieve () Assert.IsInstanceOf (multipart[0], "The first child is not a text part."); Assert.IsInstanceOf (multipart[1], "The second child is not a detached signature."); - var signatures = multipart.Verify (); + DigitalSignatureCollection signatures; + + try { + signatures = multipart.Verify (); + } catch (IOException ex) { + if (ex.Message == "unknown signature key algorithm: EdDsa") { + Assert.Ignore ("Known issue: {0}", ex.Message); + return; + } + + throw; + } + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); foreach (var signature in signatures) { try { @@ -986,8 +1026,8 @@ public void TestArgumentExceptions () Assert.Throws (() => ctx.DecryptTo (stream, null), "DecryptTo"); // DecryptToAsync - Assert.Throws (async () => await ctx.DecryptToAsync (null, stream), "DecryptToAsync"); - Assert.Throws (async () => await ctx.DecryptToAsync (stream, null), "DecryptToAsync"); + Assert.ThrowsAsync (async () => await ctx.DecryptToAsync (null, stream), "DecryptToAsync"); + Assert.ThrowsAsync (async () => await ctx.DecryptToAsync (stream, null), "DecryptToAsync"); // GetDigestAlgorithmName Assert.Throws (() => ctx.GetDigestAlgorithmName (DigestAlgorithm.None), "GetDigestAlgorithmName"); @@ -1035,9 +1075,9 @@ public void TestArgumentExceptions () Assert.Throws (() => ctx.Verify (null, stream), "Verify"); Assert.Throws (() => ctx.Verify (stream, null), "Verify"); - // Verify - Assert.Throws (async () => await ctx.VerifyAsync (null, stream), "VerifyAsync"); - Assert.Throws (async () => await ctx.VerifyAsync (stream, null), "VerifyAsync"); + // VerifyAsync + Assert.ThrowsAsync (async () => await ctx.VerifyAsync (null, stream), "VerifyAsync"); + Assert.ThrowsAsync (async () => await ctx.VerifyAsync (stream, null), "VerifyAsync"); // MultipartEncrypted @@ -1147,7 +1187,7 @@ public void TestArgumentExceptions () Assert.Throws (() => signed.Accept (null)); Assert.Throws (() => signed.Verify (null)); - Assert.Throws (async () => await signed.VerifyAsync (null)); + Assert.ThrowsAsync (async () => await signed.VerifyAsync (null)); } } @@ -1176,14 +1216,14 @@ public void TestOpenPgpDetectionFilter () { var filter = new OpenPgpDetectionFilter (); - PumpDataThroughFilter (filter, Path.Combine ("..", "..", "TestData", "openpgp", "mimekit.gpg.pub"), true); + PumpDataThroughFilter (filter, Path.Combine (TestHelper.ProjectDir, "TestData", "openpgp", "mimekit.gpg.pub"), true); Assert.AreEqual (OpenPgpDataType.PublicKey, filter.DataType); Assert.AreEqual (0, filter.BeginOffset); Assert.AreEqual (1754, filter.EndOffset); filter.Reset (); - PumpDataThroughFilter (filter, Path.Combine ("..", "..", "TestData", "openpgp", "mimekit.gpg.sec"), true); + PumpDataThroughFilter (filter, Path.Combine (TestHelper.ProjectDir, "TestData", "openpgp", "mimekit.gpg.sec"), true); Assert.AreEqual (OpenPgpDataType.PrivateKey, filter.DataType); Assert.AreEqual (0, filter.BeginOffset); Assert.AreEqual (3650, filter.EndOffset); diff --git a/UnitTests/Cryptography/RsaEncryptionPaddingTests.cs b/UnitTests/Cryptography/RsaEncryptionPaddingTests.cs new file mode 100644 index 0000000000..45ff33dc9c --- /dev/null +++ b/UnitTests/Cryptography/RsaEncryptionPaddingTests.cs @@ -0,0 +1,147 @@ +// +// RsaEncryptionPaddingTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Reflection; +using System.Collections.Generic; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; + +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class RsaEncryptionPaddingTests + { + [Test] + public void TestEquality () + { + Assert.AreEqual (RsaEncryptionPadding.OaepSha1, RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha1), "CreateOaep(SHA-1)"); + Assert.AreEqual (RsaEncryptionPadding.OaepSha256, RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha256), "CreateOaep(SHA-256)"); + Assert.AreEqual (RsaEncryptionPadding.OaepSha384, RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha384), "CreateOaep(SHA-384)"); + Assert.AreEqual (RsaEncryptionPadding.OaepSha512, RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha512), "CreateOaep(SHA-512)"); + + Assert.AreNotEqual (RsaEncryptionPadding.Pkcs1, RsaEncryptionPadding.OaepSha1, "PKCS1 !Equals SHA-1"); + Assert.AreNotEqual (RsaEncryptionPadding.Pkcs1, RsaEncryptionPadding.OaepSha256, "PKCS1 !Equals SHA-256"); + Assert.AreNotEqual (RsaEncryptionPadding.OaepSha1, RsaEncryptionPadding.OaepSha256, "SHA-1 !Equals SHA-256"); + + Assert.AreNotEqual (RsaEncryptionPadding.Pkcs1, new object (), "PKCS1 !Equals object"); + + Assert.IsTrue (RsaEncryptionPadding.OaepSha1 == RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha1), "SHA-1 == SHA-1"); + Assert.IsFalse (RsaEncryptionPadding.OaepSha1 == RsaEncryptionPadding.OaepSha256, "SHA-1 == SHA-256"); + Assert.IsFalse (RsaEncryptionPadding.OaepSha1 == null, "SHA-1 == null"); + Assert.IsFalse (null == RsaEncryptionPadding.OaepSha1, "null == SHA-1"); + + Assert.IsFalse (RsaEncryptionPadding.OaepSha1 != RsaEncryptionPadding.CreateOaep (DigestAlgorithm.Sha1), "SHA-1 != SHA-1"); + Assert.IsTrue (RsaEncryptionPadding.OaepSha1 != RsaEncryptionPadding.OaepSha256, "SHA-1 != SHA-256"); + Assert.IsTrue (RsaEncryptionPadding.OaepSha1 != null, "SHA-1 != null"); + Assert.IsTrue (null != RsaEncryptionPadding.OaepSha1, "null != SHA-1"); + } + + [Test] + public void TestGetHashCode () + { + var hashCodes = new Dictionary (); + + foreach (var field in typeof (RsaEncryptionPadding).GetFields (BindingFlags.Public | BindingFlags.Static)) { + if (field.FieldType != typeof (RsaEncryptionPadding)) + continue; + + var padding = (RsaEncryptionPadding) field.GetValue (null); + int hashCode = padding.GetHashCode (); + + if (hashCodes.TryGetValue (hashCode, out var other)) + Assert.Fail ($"{padding.Scheme} shares the same hash code as {other.Scheme}"); + + hashCodes.Add (hashCode, padding); + } + } + + [Test] + public void TestNotSupportedException () + { + var supported = new HashSet (); + + foreach (var field in typeof (RsaEncryptionPadding).GetFields (BindingFlags.Public | BindingFlags.Static)) { + if (field.FieldType != typeof (RsaEncryptionPadding)) + continue; + + var padding = (RsaEncryptionPadding) field.GetValue (null); + + if (padding.Scheme == RsaEncryptionPaddingScheme.Oaep) + supported.Add (padding.OaepHashAlgorithm); + } + + foreach (DigestAlgorithm hashAlgorithm in Enum.GetValues (typeof (DigestAlgorithm))) { + if (!supported.Contains (hashAlgorithm)) + Assert.Throws (() => RsaEncryptionPadding.CreateOaep (hashAlgorithm)); + else + Assert.DoesNotThrow (() => RsaEncryptionPadding.CreateOaep (hashAlgorithm)); + } + } + + [Test] + public void TestToString () + { + Assert.AreEqual ("Pkcs1", RsaEncryptionPadding.Pkcs1.ToString (), "Pkcs1"); + Assert.AreEqual ("OaepSha1", RsaEncryptionPadding.OaepSha1.ToString (), "OaepSha1"); + Assert.AreEqual ("OaepSha256", RsaEncryptionPadding.OaepSha256.ToString (), "OaepSha256"); + Assert.AreEqual ("OaepSha384", RsaEncryptionPadding.OaepSha384.ToString (), "OaepSha384"); + Assert.AreEqual ("OaepSha512", RsaEncryptionPadding.OaepSha512.ToString (), "OaepSha512"); + } + + static void AssertOaepAlgorithmIdentifier (RsaEncryptionPadding padding, DerObjectIdentifier hashAlgorithm) + { + var name = $"Oaep{padding.Scheme}"; + + var algorithm = padding.GetAlgorithmIdentifier (); + Assert.IsNotNull (algorithm, $"{name} != null"); + Assert.AreEqual (PkcsObjectIdentifiers.IdRsaesOaep, algorithm.Algorithm, $"{name}.Algorithm == RSAES-OAEP"); + var parameters = (RsaesOaepParameters) algorithm.Parameters; + Assert.AreEqual (hashAlgorithm, parameters.HashAlgorithm.Algorithm, $"{name}.HashAlgorithm == {padding.OaepHashAlgorithm}"); + Assert.AreEqual (PkcsObjectIdentifiers.IdMgf1, parameters.MaskGenAlgorithm.Algorithm, $"{name}.MaskGenAlgorithm == MGF1"); + var mgf1hash = (AlgorithmIdentifier) parameters.MaskGenAlgorithm.Parameters; + Assert.AreEqual (hashAlgorithm, mgf1hash.Algorithm, $"{name}.MaskGenHashAlgorithm == {padding.OaepHashAlgorithm}"); + } + + [Test] + public void TestGetAlgorithmIdentifier () + { + Assert.IsNull (RsaEncryptionPadding.Pkcs1.GetAlgorithmIdentifier (), "Pkcs1"); + + AssertOaepAlgorithmIdentifier (RsaEncryptionPadding.OaepSha1, OiwObjectIdentifiers.IdSha1); + AssertOaepAlgorithmIdentifier (RsaEncryptionPadding.OaepSha256, NistObjectIdentifiers.IdSha256); + AssertOaepAlgorithmIdentifier (RsaEncryptionPadding.OaepSha384, NistObjectIdentifiers.IdSha384); + AssertOaepAlgorithmIdentifier (RsaEncryptionPadding.OaepSha512, NistObjectIdentifiers.IdSha512); + } + } +} diff --git a/UnitTests/Cryptography/RsaSignaturePaddingTests.cs b/UnitTests/Cryptography/RsaSignaturePaddingTests.cs new file mode 100644 index 0000000000..85d351418d --- /dev/null +++ b/UnitTests/Cryptography/RsaSignaturePaddingTests.cs @@ -0,0 +1,102 @@ +// +// RsaSignaturePaddingTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Reflection; +using System.Collections.Generic; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Asn1.Oiw; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; + +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class RsaSignaturePaddingTests + { + [Test] + public void TestEquality () + { + var pkcs1 = RsaSignaturePadding.Pkcs1; + var pss = RsaSignaturePadding.Pss; + + Assert.AreEqual (RsaSignaturePadding.Pkcs1, pkcs1, "Pkcs1 Equals Pkcs1"); + Assert.AreEqual (RsaSignaturePadding.Pss, pss, "Pss Equals Pss"); + + Assert.AreNotEqual (RsaSignaturePadding.Pkcs1, RsaSignaturePadding.Pss, "Pkcs1 !Equals Pss"); + Assert.AreNotEqual (RsaSignaturePadding.Pss, RsaSignaturePadding.Pkcs1, "Pss !Equals Pkcs1"); + + Assert.AreNotEqual (RsaSignaturePadding.Pkcs1, new object (), "Pkcs1 !Equals object"); + Assert.AreNotEqual (RsaSignaturePadding.Pss, new object (), "Pss !Equals object"); + + Assert.IsTrue (pkcs1 == RsaSignaturePadding.Pkcs1, "Pkcs1 == Pkcs1"); + Assert.IsTrue (pss == RsaSignaturePadding.Pss, "Pss == Pss"); + Assert.IsFalse (pkcs1 == pss, "Pkcs1 == Pss"); + Assert.IsFalse (pss == pkcs1, "Pss == Pkcs1"); + Assert.IsFalse (pkcs1 == null, "Pkcs1 == null"); + Assert.IsFalse (null == pkcs1, "null == Pkcs1"); + + Assert.IsFalse (pkcs1 != RsaSignaturePadding.Pkcs1, "Pkcs1 != Pkcs1"); + Assert.IsFalse (pss != RsaSignaturePadding.Pss, "Pss != Pss"); + Assert.IsTrue (pkcs1 != pss, "Pkcs1 != Pss"); + Assert.IsTrue (pss != pkcs1, "Pss != Pkcs1"); + Assert.IsTrue (pkcs1 != null, "Pkcs1 != null"); + Assert.IsTrue (null != pkcs1, "null != Pkcs1"); + } + + [Test] + public void TestGetHashCode () + { + var hashCodes = new Dictionary (); + + foreach (var field in typeof (RsaSignaturePadding).GetFields (BindingFlags.Public | BindingFlags.Static)) { + if (field.FieldType != typeof (RsaSignaturePadding)) + continue; + + var padding = (RsaSignaturePadding) field.GetValue (null); + int hashCode = padding.GetHashCode (); + + if (hashCodes.TryGetValue (hashCode, out var other)) + Assert.Fail ($"{padding.Scheme} shares the same hash code as {other.Scheme}"); + + hashCodes.Add (hashCode, padding); + } + } + + [Test] + public void TestToString () + { + Assert.AreEqual ("Pkcs1", RsaSignaturePadding.Pkcs1.ToString (), "Pkcs1"); + Assert.AreEqual ("Pss", RsaSignaturePadding.Pss.ToString (), "Pss"); + } + } +} diff --git a/UnitTests/Cryptography/SecureMimeDigitalCertificateTests.cs b/UnitTests/Cryptography/SecureMimeDigitalCertificateTests.cs new file mode 100644 index 0000000000..6a41b55f14 --- /dev/null +++ b/UnitTests/Cryptography/SecureMimeDigitalCertificateTests.cs @@ -0,0 +1,133 @@ +// +// SecureMimeDigitalCertificateTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Security.Cryptography.X509Certificates; + +using Org.BouncyCastle.OpenSsl; + +using NUnit.Framework; + +using MimeKit.Cryptography; + +using X509Certificate = Org.BouncyCastle.X509.X509Certificate; + +namespace UnitTests.Cryptography { + [TestFixture] + public class SecureMimeDigitalCertificateTests + { + [Test] + public void TestArgumentExceptions () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"), "no.secret"); + + Assert.Throws (() => new SecureMimeDigitalCertificate (null)); + Assert.Throws (() => new SecureMimeDigitalSignature (null, signer.Certificate)); + + Assert.Throws (() => new WindowsSecureMimeDigitalCertificate (null)); + Assert.Throws (() => new WindowsSecureMimeDigitalSignature (null)); + } + + static X509Certificate GetCertificate (string fileName) + { + using (var stream = File.OpenText (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", fileName))) { + var reader = new PemReader (stream); + object item; + + while ((item = reader.ReadObject ()) != null) { + var certificate = item as X509Certificate; + + if (certificate != null) + return certificate; + } + } + + return null; + } + + [Test] + public void TestPublicKeyAlgorithmDetection () + { + var dsa = new string[] { "smdsa1.pem", "smdsa2.pem", "smdsa3.pem" }; + var rsa = new string[] { "smrsa1.pem", "smrsa2.pem", "smrsa3.pem" }; + var ec = new string[] { "smec1.pem", "smec2.pem", "smec3.pem" }; + //var dh = new string[] { "smdh.pem" }; + WindowsSecureMimeDigitalCertificate digital2; + SecureMimeDigitalCertificate digital; + X509Certificate2 certificate2; + X509Certificate certificate; + + foreach (var fileName in dsa) { + certificate = GetCertificate (fileName); + digital = new SecureMimeDigitalCertificate (certificate); + + Assert.AreEqual (PublicKeyAlgorithm.Dsa, digital.PublicKeyAlgorithm, "PublicKeyAlgorithm: {0}", fileName); + + certificate2 = certificate.AsX509Certificate2 (); + digital2 = new WindowsSecureMimeDigitalCertificate (certificate2); + + Assert.AreEqual (PublicKeyAlgorithm.Dsa, digital2.PublicKeyAlgorithm, "Windows PublicKeyAlgorithm {0}", fileName); + } + + foreach (var fileName in rsa) { + certificate = GetCertificate (fileName); + digital = new SecureMimeDigitalCertificate (certificate); + + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, digital.PublicKeyAlgorithm, "PublicKeyAlgorithm: {0}", fileName); + + certificate2 = certificate.AsX509Certificate2 (); + digital2 = new WindowsSecureMimeDigitalCertificate (certificate2); + + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, digital2.PublicKeyAlgorithm, "Windows PublicKeyAlgorithm {0}", fileName); + } + + foreach (var fileName in ec) { + certificate = GetCertificate (fileName); + digital = new SecureMimeDigitalCertificate (certificate); + + Assert.AreEqual (PublicKeyAlgorithm.EllipticCurve, digital.PublicKeyAlgorithm, "PublicKeyAlgorithm: {0}", fileName); + + certificate2 = certificate.AsX509Certificate2 (); + digital2 = new WindowsSecureMimeDigitalCertificate (certificate2); + + Assert.AreEqual (PublicKeyAlgorithm.EllipticCurve, digital2.PublicKeyAlgorithm, "Windows PublicKeyAlgorithm {0}", fileName); + } + + //foreach (var fileName in dh) { + // certificate = GetCertificate (fileName); + // digital = new SecureMimeDigitalCertificate (certificate); + + // Assert.AreEqual (PublicKeyAlgorithm.DiffieHellman, digital.PublicKeyAlgorithm, "PublicKeyAlgorithm: {0}", fileName); + + // certificate2 = certificate.AsX509Certificate2 (); + // digital2 = new WindowsSecureMimeDigitalCertificate (certificate2); + + // Assert.AreEqual (PublicKeyAlgorithm.DiffieHellman, digital2.PublicKeyAlgorithm, "Windows PublicKeyAlgorithm {0}", fileName); + //} + } + } +} diff --git a/UnitTests/Cryptography/SecureMimeTests.cs b/UnitTests/Cryptography/SecureMimeTests.cs index d99cdd42da..6949198d6e 100644 --- a/UnitTests/Cryptography/SecureMimeTests.cs +++ b/UnitTests/Cryptography/SecureMimeTests.cs @@ -1,9 +1,9 @@ -// +// // SecureMimeTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,9 @@ using NUnit.Framework; +using Org.BouncyCastle.Cms; using Org.BouncyCastle.X509; +using Org.BouncyCastle.Pkcs; using MimeKit; using MimeKit.Cryptography; @@ -44,40 +46,45 @@ namespace UnitTests.Cryptography { public abstract class SecureMimeTestsBase { - const string ExpiredCertificateMessage = "A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file.\r\n"; + //const string ExpiredCertificateMessage = "A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file.\r\n"; + const string ExpiredCertificateMessage = "The certificate is revoked.\r\n"; const string UntrustedRootCertificateMessage = "A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.\r\n"; const string ThunderbirdFingerprint = "354ea4dcf98166639b58ec5df06a65de0cd8a95c"; - const string MimeKitFingerprint = "2c29c66e281c9c515cc16a91ac87c4da988dbadf"; + const string MimeKitFingerprint = "ba4403cd3d876ae8cd261575820330086cc3cbc8"; const string ThunderbirdName = "fejj@gnome.org"; - static readonly string[] CertificateAuthorities = { - "certificate-authority.crt", "intermediate.crt", "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" + static readonly DateTime MimeKitCreationDate = new DateTime (2019, 11, 05, 03, 00, 15); + static readonly DateTime MimeKitExpirationDate = new DateTime (2029, 11, 02, 03, 00, 15); + readonly X509Certificate MimeKitCertificate; + + static readonly string[] StartComCertificates = { + "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" }; + protected virtual bool IsEnabled { get { return true; } } protected abstract SecureMimeContext CreateContext (); protected SecureMimeTestsBase () { + if (!IsEnabled) + return; + using (var ctx = CreateContext ()) { - var dataDir = Path.Combine ("..", "..", "TestData", "smime"); + var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "smime"); string path; - CryptographyContext.Register (ctx.GetType ()); + if (ctx is TemporarySecureMimeContext) + CryptographyContext.Register (() => CreateContext ()); + else + CryptographyContext.Register (ctx.GetType ()); + + var chain = LoadPkcs12CertificateChain (Path.Combine (dataDir, "smime.pfx"), "no.secret"); + MimeKitCertificate = chain[0]; if (ctx is WindowsSecureMimeContext) { var windows = (WindowsSecureMimeContext) ctx; var parser = new X509CertificateParser (); - using (var stream = File.OpenRead (Path.Combine (dataDir, "certificate-authority.crt"))) { - foreach (X509Certificate certificate in parser.ReadCertificates (stream)) - windows.Import (StoreName.AuthRoot, certificate); - } - - using (var stream = File.OpenRead (Path.Combine (dataDir, "intermediate.crt"))) { - foreach (X509Certificate certificate in parser.ReadCertificates (stream)) - windows.Import (StoreName.CertificateAuthority, certificate); - } - using (var stream = File.OpenRead (Path.Combine (dataDir, "StartComCertificationAuthority.crt"))) { foreach (X509Certificate certificate in parser.ReadCertificates (stream)) windows.Import (StoreName.AuthRoot, certificate); @@ -87,8 +94,15 @@ protected SecureMimeTestsBase () foreach (X509Certificate certificate in parser.ReadCertificates (stream)) windows.Import (StoreName.CertificateAuthority, certificate); } + + // import the root & intermediate certificates from the smime.pfx file + var store = StoreName.AuthRoot; + for (int i = chain.Length - 1; i > 0; i--) { + windows.Import (store, chain[i]); + store = StoreName.CertificateAuthority; + } } else { - foreach (var filename in CertificateAuthorities) { + foreach (var filename in StartComCertificates) { path = Path.Combine (dataDir, filename); using (var stream = File.OpenRead (path)) { if (ctx is DefaultSecureMimeContext) { @@ -100,12 +114,56 @@ protected SecureMimeTestsBase () } } } + + // import the root & intermediate certificates from the smime.pfx file + for (int i = chain.Length - 1; i > 0; i--) { + if (ctx is DefaultSecureMimeContext) { + ((DefaultSecureMimeContext) ctx).Import (chain[i], true); + } else { + ctx.Import (chain[i]); + } + } } - path = Path.Combine (dataDir, "smime.p12"); + path = Path.Combine (dataDir, "smime.pfx"); + ctx.Import (path, "no.secret"); - using (var file = File.OpenRead (path)) - ctx.Import (file, "no.secret"); + // import a second time to cover the case where the certificate & private key already exist + Assert.DoesNotThrow (() => ctx.Import (path, "no.secret")); + } + } + + public static X509Certificate LoadCertificate (string path) + { + using (var stream = File.OpenRead (path)) { + var parser = new X509CertificateParser (); + + return parser.ReadCertificate (stream); + } + } + + public static X509Certificate[] LoadPkcs12CertificateChain (string fileName, string password) + { + using (var stream = File.OpenRead (fileName)) { + var pkcs12 = new Pkcs12Store (stream, password.ToCharArray ()); + + foreach (string alias in pkcs12.Aliases) { + if (pkcs12.IsKeyEntry (alias)) { + var chain = pkcs12.GetCertificateChain (alias); + var entry = pkcs12.GetKey (alias); + + if (!entry.Key.IsPrivate) + continue; + + var certificates = new X509Certificate[chain.Length]; + for (int i = 0; i < chain.Length; i++) + certificates[i] = chain[i].Certificate; + + return certificates; + } + } + + return new X509Certificate[0]; } } @@ -128,18 +186,23 @@ public void TestArgumentExceptions () Assert.Throws (() => SecureMimeContext.GetDigestOid (DigestAlgorithm.Tiger192)); using (var ctx = CreateContext ()) { - var signer = new CmsSigner (Path.Combine ("..", "..", "TestData", "smime", "smime.p12"), "no.secret"); + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret"); var mailbox = new MailboxAddress ("Unit Tests", "example@mimekit.net"); var recipients = new CmsRecipientCollection (); DigitalSignatureCollection signatures; MimeEntity entity; Assert.IsFalse (ctx.Supports ("text/plain"), "Should not support text/plain"); + Assert.IsFalse (ctx.Supports ("application/octet-stream"), "Should not support application/octet-stream"); Assert.IsTrue (ctx.Supports ("application/pkcs7-mime"), "Should support application/pkcs7-mime"); Assert.IsTrue (ctx.Supports ("application/x-pkcs7-mime"), "Should support application/x-pkcs7-mime"); Assert.IsTrue (ctx.Supports ("application/pkcs7-signature"), "Should support application/pkcs7-signature"); Assert.IsTrue (ctx.Supports ("application/x-pkcs7-signature"), "Should support application/x-pkcs7-signature"); + Assert.AreEqual ("application/pkcs7-signature", ctx.SignatureProtocol); + Assert.AreEqual ("application/pkcs7-mime", ctx.EncryptionProtocol); + Assert.AreEqual ("application/pkcs7-mime", ctx.KeyExchangeProtocol); + Assert.Throws (() => ctx.Supports (null)); Assert.Throws (() => ctx.CanSign (null)); Assert.Throws (() => ctx.CanEncrypt (null)); @@ -158,10 +221,14 @@ public void TestArgumentExceptions () Assert.Throws (() => ctx.Encrypt (recipients, null)); Assert.Throws (() => ctx.Encrypt ((IEnumerable) null, stream)); Assert.Throws (() => ctx.Encrypt (new MailboxAddress[0], null)); + Assert.Throws (() => ctx.Encrypt (new MailboxAddress[0], stream)); Assert.Throws (() => ctx.Export (null)); Assert.Throws (() => ctx.GetDigestAlgorithm (null)); Assert.Throws (() => ctx.Import ((Stream) null)); + Assert.Throws (() => ctx.Import ((Stream) null, "password")); Assert.Throws (() => ctx.Import (stream, null)); + Assert.Throws (() => ctx.Import ((string) null, "password")); + Assert.Throws (() => ctx.Import ("fileName", null)); Assert.Throws (() => ctx.Import ((X509Crl) null)); Assert.Throws (() => ctx.Import ((X509Certificate) null)); Assert.Throws (() => ctx.Sign (null, stream)); @@ -172,8 +239,8 @@ public void TestArgumentExceptions () Assert.Throws (() => ctx.Verify (stream, null)); Assert.Throws (() => ctx.Verify (null, out signatures)); Assert.Throws (() => ctx.Verify (null, out entity)); - Assert.Throws (async () => await ctx.VerifyAsync (null, stream)); - Assert.Throws (async () => await ctx.VerifyAsync (stream, null)); + Assert.ThrowsAsync (async () => await ctx.VerifyAsync (null, stream)); + Assert.ThrowsAsync (async () => await ctx.VerifyAsync (stream, null)); entity = new MimePart { Content = new MimeContent (stream) }; @@ -197,6 +264,12 @@ public virtual void TestCanSignAndEncrypt () Assert.IsTrue (ctx.CanSign (valid), "{0} should be able to sign.", valid); Assert.IsTrue (ctx.CanEncrypt (valid), "{0} should be able to encrypt.", valid); + + using (var content = new MemoryStream ()) { + Assert.Throws (() => ctx.Encrypt (new[] { invalid }, content)); + Assert.Throws (() => ctx.Sign (invalid, DigestAlgorithm.Sha1, content)); + Assert.Throws (() => ctx.EncapsulatedSign (invalid, DigestAlgorithm.Sha1, content)); + } } } @@ -222,6 +295,12 @@ public void TestDigestAlgorithmMappings () } catch (NotSupportedException) { } } + + Assert.Throws (() => ctx.GetDigestAlgorithmName (DigestAlgorithm.DoubleSha)); + Assert.Throws (() => ctx.GetDigestAlgorithmName (DigestAlgorithm.None)); + + Assert.AreEqual (DigestAlgorithm.None, ctx.GetDigestAlgorithm ("blahblahblah")); + Assert.IsFalse (SecureMimeContext.TryGetDigestAlgorithm ("blahblahblah", out DigestAlgorithm algo)); } } @@ -231,6 +310,22 @@ public void TestSecureMimeCompression () var original = new TextPart ("plain"); original.Text = "This is some text that we'll end up compressing..."; + var compressed = ApplicationPkcs7Mime.Compress (original); + + Assert.AreEqual (SecureMimeType.CompressedData, compressed.SecureMimeType, "S/MIME type did not match."); + + var decompressed = compressed.Decompress (); + + Assert.IsInstanceOf (decompressed, "Decompressed part is not the expected type."); + Assert.AreEqual (original.Text, ((TextPart) decompressed).Text, "Decompressed content is not the same as the original."); + } + + [Test] + public void TestSecureMimeCompressionWithContext () + { + var original = new TextPart ("plain"); + original.Text = "This is some text that we'll end up compressing..."; + using (var ctx = CreateContext ()) { var compressed = ApplicationPkcs7Mime.Compress (ctx, original); @@ -240,6 +335,20 @@ public void TestSecureMimeCompression () Assert.IsInstanceOf (decompressed, "Decompressed part is not the expected type."); Assert.AreEqual (original.Text, ((TextPart) decompressed).Text, "Decompressed content is not the same as the original."); + + using (var stream = new MemoryStream ()) { + using (var decoded = new MemoryStream ()) { + compressed.Content.DecodeTo (decoded); + decoded.Position = 0; + ctx.DecompressTo (decoded, stream); + } + + stream.Position = 0; + decompressed = MimeEntity.Load (stream); + + Assert.IsInstanceOf (decompressed, "Decompressed part is not the expected type."); + Assert.AreEqual (original.Text, ((TextPart) decompressed).Text, "Decompressed content is not the same as the original."); + } } } @@ -251,10 +360,101 @@ protected virtual EncryptionAlgorithm[] GetEncryptionAlgorithms (IDigitalSignatu [Test] public virtual void TestSecureMimeEncapsulatedSigning () { + var cleartext = new TextPart ("plain") { Text = "This is some text that we'll end up signing..." }; var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); - var cleartext = new TextPart ("plain"); - cleartext.Text = "This is some text that we'll end up signing..."; + var signed = ApplicationPkcs7Mime.Sign (self, DigestAlgorithm.Sha1, cleartext); + MimeEntity extracted; + + Assert.AreEqual (SecureMimeType.SignedData, signed.SecureMimeType, "S/MIME type did not match."); + + var signatures = signed.Verify (out extracted); + + Assert.IsInstanceOf (extracted, "Extracted part is not the expected type."); + Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); + + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + + var signature = signatures[0]; + + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual (MimeKitFingerprint, signature.SignerCertificate.Fingerprint.ToLowerInvariant ()); + Assert.AreEqual (MimeKitCreationDate, signature.SignerCertificate.CreationDate, "CreationDate"); + Assert.AreEqual (MimeKitExpirationDate, signature.SignerCertificate.ExpirationDate, "ExpirationDate"); + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, signature.SignerCertificate.PublicKeyAlgorithm); + Assert.AreEqual (PublicKeyAlgorithm.RsaGeneral, signature.PublicKeyAlgorithm); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + using (var ctx = CreateContext ()) { + if (ctx is WindowsSecureMimeContext) { + // AppVeyor gets an exception about the root certificate not being trusted + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); + } else { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + } + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + } + + void AssertValidSignatures (SecureMimeContext ctx, DigitalSignatureCollection signatures) + { + foreach (var signature in signatures) { + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + if (ctx is WindowsSecureMimeContext) { + // AppVeyor gets an exception about the root certificate not being trusted + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); + } else { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Seed)) + Assert.AreEqual (EncryptionAlgorithm.Seed, algorithms[i++], "Expected SEED capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia256)) + Assert.AreEqual (EncryptionAlgorithm.Camellia256, algorithms[i++], "Expected Camellia-256 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia192)) + Assert.AreEqual (EncryptionAlgorithm.Camellia192, algorithms[i++], "Expected Camellia-192 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia128)) + Assert.AreEqual (EncryptionAlgorithm.Camellia128, algorithms[i++], "Expected Camellia-128 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Cast5)) + Assert.AreEqual (EncryptionAlgorithm.Cast5, algorithms[i++], "Expected Cast5 capability"); + Assert.AreEqual (EncryptionAlgorithm.TripleDes, algorithms[i++], "Expected Triple-DES capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Idea)) + Assert.AreEqual (EncryptionAlgorithm.Idea, algorithms[i++], "Expected IDEA capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC2128, algorithms[i++], "Expected RC2-128 capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC264, algorithms[i++], "Expected RC2-64 capability"); + //Assert.AreEqual (EncryptionAlgorithm.Des, algorithms[i++], "Expected DES capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC240, algorithms[i++], "Expected RC2-40 capability"); + } + } + + [Test] + public virtual void TestSecureMimeEncapsulatedSigningWithContext () + { + var cleartext = new TextPart ("plain") { Text = "This is some text that we'll end up signing..." }; + var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); using (var ctx = CreateContext ()) { var signed = ApplicationPkcs7Mime.Sign (ctx, self, DigestAlgorithm.Sha1, cleartext); @@ -268,49 +468,272 @@ public virtual void TestSecureMimeEncapsulatedSigning () Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); - foreach (var signature in signatures) { - try { - bool valid = signature.Verify (); + AssertValidSignatures (ctx, signatures); - Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); - } catch (DigitalSignatureVerifyException ex) { + using (var signedData = signed.Content.Open ()) { + using (var stream = ctx.Verify (signedData, out signatures)) + extracted = MimeEntity.Load (stream); + + Assert.IsInstanceOf (extracted, "Extracted part is not the expected type."); + Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); + + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + AssertValidSignatures (ctx, signatures); + } + } + } + + [Test] + public virtual void TestSecureMimeEncapsulatedSigningWithCmsSigner () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret", SubjectIdentifierType.SubjectKeyIdentifier); + var cleartext = new TextPart ("plain") { Text = "This is some text that we'll end up signing..." }; + + var signed = ApplicationPkcs7Mime.Sign (signer, cleartext); + MimeEntity extracted; + + Assert.AreEqual (SecureMimeType.SignedData, signed.SecureMimeType, "S/MIME type did not match."); + + var signatures = signed.Verify (out extracted); + + Assert.IsInstanceOf (extracted, "Extracted part is not the expected type."); + Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); + + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + foreach (var signature in signatures) { + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + using (var ctx = CreateContext ()) { if (ctx is WindowsSecureMimeContext) { // AppVeyor gets an exception about the root certificate not being trusted - Assert.AreEqual (ex.InnerException.Message, UntrustedRootCertificateMessage); + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } } + } + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + } + } + + [Test] + public virtual void TestSecureMimeEncapsulatedSigningWithContextAndCmsSigner () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret", SubjectIdentifierType.SubjectKeyIdentifier); + var cleartext = new TextPart ("plain") { Text = "This is some text that we'll end up signing..." }; + + using (var ctx = CreateContext ()) { + var signed = ApplicationPkcs7Mime.Sign (ctx, signer, cleartext); + MimeEntity extracted; + + Assert.AreEqual (SecureMimeType.SignedData, signed.SecureMimeType, "S/MIME type did not match."); + + var signatures = signed.Verify (ctx, out extracted); + + Assert.IsInstanceOf (extracted, "Extracted part is not the expected type."); + Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); + + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + AssertValidSignatures (ctx, signatures); + + using (var signedData = signed.Content.Open ()) { + using (var stream = ctx.Verify (signedData, out signatures)) + extracted = MimeEntity.Load (stream); + + Assert.IsInstanceOf (extracted, "Extracted part is not the expected type."); + Assert.AreEqual (cleartext.Text, ((TextPart) extracted).Text, "Extracted content is not the same as the original."); + + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + AssertValidSignatures (ctx, signatures); + } + } + } + + [Test] + public virtual void TestSecureMimeSigningWithCmsSigner () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret"); + var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; + + var multipart = MultipartSigned.Create (signer, body); + + Assert.AreEqual (2, multipart.Count, "The multipart/signed has an unexpected number of children."); + + var protocol = multipart.ContentType.Parameters["protocol"]; + Assert.AreEqual ("application/pkcs7-signature", protocol, "The multipart/signed protocol does not match."); + + Assert.IsInstanceOf (multipart[0], "The first child is not a text part."); + Assert.IsInstanceOf (multipart[1], "The second child is not a detached signature."); + + var signatures = multipart.Verify (); + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + + var signature = signatures[0]; + + using (var ctx = CreateContext ()) { + if (!(ctx is WindowsSecureMimeContext) || Path.DirectorySeparatorChar == '\\') + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual (MimeKitFingerprint, signature.SignerCertificate.Fingerprint.ToLowerInvariant ()); + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + if (ctx is WindowsSecureMimeContext) { + // AppVeyor gets an exception about the root certificate not being trusted + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); + } else { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + } + } + + [Test] + public virtual void TestSecureMimeSigningWithContextAndCmsSigner () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret"); + var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; + + using (var ctx = CreateContext ()) { + var multipart = MultipartSigned.Create (ctx, signer, body); + + Assert.AreEqual (2, multipart.Count, "The multipart/signed has an unexpected number of children."); + + var protocol = multipart.ContentType.Parameters["protocol"]; + Assert.AreEqual (ctx.SignatureProtocol, protocol, "The multipart/signed protocol does not match."); + + Assert.IsInstanceOf (multipart[0], "The first child is not a text part."); + Assert.IsInstanceOf (multipart[1], "The second child is not a detached signature."); + + var signatures = multipart.Verify (ctx); + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + + var signature = signatures[0]; + + if (!(ctx is WindowsSecureMimeContext) || Path.DirectorySeparatorChar == '\\') + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual (MimeKitFingerprint, signature.SignerCertificate.Fingerprint.ToLowerInvariant ()); + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Seed)) + Assert.AreEqual (EncryptionAlgorithm.Seed, algorithms[i++], "Expected SEED capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia256)) + Assert.AreEqual (EncryptionAlgorithm.Camellia256, algorithms[i++], "Expected Camellia-256 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia192)) + Assert.AreEqual (EncryptionAlgorithm.Camellia192, algorithms[i++], "Expected Camellia-192 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Camellia128)) + Assert.AreEqual (EncryptionAlgorithm.Camellia128, algorithms[i++], "Expected Camellia-128 capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Cast5)) + Assert.AreEqual (EncryptionAlgorithm.Cast5, algorithms[i++], "Expected Cast5 capability"); + Assert.AreEqual (EncryptionAlgorithm.TripleDes, algorithms[i++], "Expected Triple-DES capability"); + if (ctx.IsEnabled (EncryptionAlgorithm.Idea)) + Assert.AreEqual (EncryptionAlgorithm.Idea, algorithms[i++], "Expected IDEA capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC2128, algorithms[i++], "Expected RC2-128 capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC264, algorithms[i++], "Expected RC2-64 capability"); + //Assert.AreEqual (EncryptionAlgorithm.Des, algorithms[i++], "Expected DES capability"); + //Assert.AreEqual (EncryptionAlgorithm.RC240, algorithms[i++], "Expected RC2-40 capability"); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + if (ctx is WindowsSecureMimeContext) { + // AppVeyor gets an exception about the root certificate not being trusted + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); + } else { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + } + } - var algorithms = GetEncryptionAlgorithms (signature); - int i = 0; - - Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); - Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); - Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Seed)) - Assert.AreEqual (EncryptionAlgorithm.Seed, algorithms[i++], "Expected SEED capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Camellia256)) - Assert.AreEqual (EncryptionAlgorithm.Camellia256, algorithms[i++], "Expected Camellia-256 capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Camellia192)) - Assert.AreEqual (EncryptionAlgorithm.Camellia192, algorithms[i++], "Expected Camellia-192 capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Camellia128)) - Assert.AreEqual (EncryptionAlgorithm.Camellia128, algorithms[i++], "Expected Camellia-128 capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Cast5)) - Assert.AreEqual (EncryptionAlgorithm.Cast5, algorithms[i++], "Expected Cast5 capability"); - Assert.AreEqual (EncryptionAlgorithm.TripleDes, algorithms[i++], "Expected Triple-DES capability"); - if (ctx.IsEnabled (EncryptionAlgorithm.Idea)) - Assert.AreEqual (EncryptionAlgorithm.Idea, algorithms[i++], "Expected IDEA capability"); - //Assert.AreEqual (EncryptionAlgorithm.RC2128, algorithms[i++], "Expected RC2-128 capability"); - //Assert.AreEqual (EncryptionAlgorithm.RC264, algorithms[i++], "Expected RC2-64 capability"); - //Assert.AreEqual (EncryptionAlgorithm.Des, algorithms[i++], "Expected DES capability"); - //Assert.AreEqual (EncryptionAlgorithm.RC240, algorithms[i++], "Expected RC2-40 capability"); + [Test] + public virtual void TestSecureMimeSigningWithRsaSsaPss () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.pfx"), "no.secret") { + RsaSignaturePadding = RsaSignaturePadding.Pss + }; + var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; + + using (var ctx = CreateContext ()) { + MultipartSigned multipart; + + try { + multipart = MultipartSigned.Create (signer, body); + } catch (NotSupportedException) { + if (!(ctx is WindowsSecureMimeContext)) + Assert.Fail ("RSASSA-PSS should be supported."); + return; + } + + Assert.AreEqual (2, multipart.Count, "The multipart/signed has an unexpected number of children."); + + var protocol = multipart.ContentType.Parameters["protocol"]; + Assert.AreEqual ("application/pkcs7-signature", protocol, "The multipart/signed protocol does not match."); + + Assert.IsInstanceOf (multipart[0], "The first child is not a text part."); + Assert.IsInstanceOf (multipart[1], "The second child is not a detached signature."); + + var signatures = multipart.Verify (); + Assert.AreEqual (1, signatures.Count, "Verify returned an unexpected number of signatures."); + + var signature = signatures[0]; + + if (!(ctx is WindowsSecureMimeContext) || Path.DirectorySeparatorChar == '\\') + Assert.AreEqual ("MimeKit UnitTests", signature.SignerCertificate.Name); + Assert.AreEqual ("mimekit@example.com", signature.SignerCertificate.Email); + Assert.AreEqual (MimeKitFingerprint, signature.SignerCertificate.Fingerprint.ToLowerInvariant ()); + + var algorithms = GetEncryptionAlgorithms (signature); + int i = 0; + + Assert.AreEqual (EncryptionAlgorithm.Aes256, algorithms[i++], "Expected AES-256 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes192, algorithms[i++], "Expected AES-192 capability"); + Assert.AreEqual (EncryptionAlgorithm.Aes128, algorithms[i++], "Expected AES-128 capability"); + + try { + bool valid = signature.Verify (); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + if (ctx is WindowsSecureMimeContext) { + // AppVeyor gets an exception about the root certificate not being trusted + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); + } else { + Assert.Fail ("Failed to verify signature: {0}", ex); + } } } } [Test] - public virtual void TestSecureMimeSigning () + public virtual void TestSecureMimeMessageSigning () { var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); @@ -377,7 +800,7 @@ public virtual void TestSecureMimeSigning () } catch (DigitalSignatureVerifyException ex) { if (ctx is WindowsSecureMimeContext) { // AppVeyor gets an exception about the root certificate not being trusted - Assert.AreEqual (ex.InnerException.Message, UntrustedRootCertificateMessage); + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } @@ -386,7 +809,7 @@ public virtual void TestSecureMimeSigning () } [Test] - public virtual async Task TestSecureMimeSigningAsync () + public virtual async Task TestSecureMimeMessageSigningAsync () { var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up signing..." }; var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); @@ -453,7 +876,7 @@ public virtual async Task TestSecureMimeSigningAsync () } catch (DigitalSignatureVerifyException ex) { if (ctx is WindowsSecureMimeContext) { // AppVeyor gets an exception about the root certificate not being trusted - Assert.AreEqual (ex.InnerException.Message, UntrustedRootCertificateMessage); + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } @@ -466,7 +889,7 @@ public virtual void TestSecureMimeVerifyThunderbird () { MimeMessage message; - using (var file = File.OpenRead (Path.Combine ("..", "..", "TestData", "smime", "thunderbird-signed.txt"))) { + using (var file = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "thunderbird-signed.txt"))) { var parser = new MimeParser (file, MimeFormat.Default); message = parser.ParseMessage (); } @@ -476,7 +899,7 @@ public virtual void TestSecureMimeVerifyThunderbird () var multipart = (MultipartSigned) message.Body; - var protocol = multipart.ContentType.Parameters["protocol"]; + var protocol = multipart.ContentType.Parameters["protocol"]?.Trim (); Assert.IsTrue (ctx.Supports (protocol), "The multipart/signed protocol is not supported."); Assert.IsInstanceOf (multipart[1], "The second child is not a detached signature."); @@ -511,7 +934,7 @@ public virtual void TestSecureMimeVerifyThunderbird () if (Path.DirectorySeparatorChar == '/') Assert.IsInstanceOf (ex.InnerException); else - Assert.AreEqual (ex.InnerException.Message, ExpiredCertificateMessage); + Assert.AreEqual (ExpiredCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } @@ -551,13 +974,34 @@ public virtual void TestSecureMimeMessageEncryption () [Test] public virtual void TestSecureMimeEncryption () { - var certificate = new X509Certificate2 (Path.Combine ("..", "..", "TestData", "smime", "smime.p12"), "no.secret"); var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up encrypting..." }; var recipients = new CmsRecipientCollection (); - recipients.Add (new CmsRecipient (certificate, SubjectIdentifierType.SubjectKeyIdentifier)); + recipients.Add (new CmsRecipient (MimeKitCertificate, SubjectIdentifierType.SubjectKeyIdentifier)); + + var encrypted = ApplicationPkcs7Mime.Encrypt (recipients, body); + + Assert.AreEqual (SecureMimeType.EnvelopedData, encrypted.SecureMimeType, "S/MIME type did not match."); + + var decrypted = encrypted.Decrypt (); + + Assert.IsInstanceOf (decrypted, "Decrypted part is not the expected type."); + Assert.AreEqual (body.Text, ((TextPart) decrypted).Text, "Decrypted content is not the same as the original."); + } + + [Test] + public virtual void TestSecureMimeEncryptionWithContext () + { + var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up encrypting..." }; using (var ctx = CreateContext ()) { + var recipients = new CmsRecipientCollection (); + + if (ctx is WindowsSecureMimeContext) + recipients.Add (new CmsRecipient (MimeKitCertificate.AsX509Certificate2 (), SubjectIdentifierType.SubjectKeyIdentifier)); + else + recipients.Add (new CmsRecipient (MimeKitCertificate, SubjectIdentifierType.SubjectKeyIdentifier)); + var encrypted = ApplicationPkcs7Mime.Encrypt (ctx, recipients, body); Assert.AreEqual (SecureMimeType.EnvelopedData, encrypted.SecureMimeType, "S/MIME type did not match."); @@ -577,13 +1021,16 @@ public virtual void TestSecureMimeEncryption () [Test] public virtual void TestSecureMimeEncryptionWithAlgorithm () { - var certificate = new X509Certificate2 (Path.Combine ("..", "..", "TestData", "smime", "smime.p12"), "no.secret"); var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up encrypting..." }; - var recipients = new CmsRecipientCollection (); - - recipients.Add (new CmsRecipient (certificate, SubjectIdentifierType.SubjectKeyIdentifier)); using (var ctx = CreateContext ()) { + var recipients = new CmsRecipientCollection (); + + if (ctx is WindowsSecureMimeContext) + recipients.Add (new CmsRecipient (MimeKitCertificate.AsX509Certificate2 (), SubjectIdentifierType.SubjectKeyIdentifier)); + else + recipients.Add (new CmsRecipient (MimeKitCertificate, SubjectIdentifierType.SubjectKeyIdentifier)); + foreach (EncryptionAlgorithm algorithm in Enum.GetValues (typeof (EncryptionAlgorithm))) { foreach (var recipient in recipients) recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] { algorithm }; @@ -655,16 +1102,56 @@ public virtual void TestSecureMimeEncryptionWithAlgorithm () } } + [TestCase (DigestAlgorithm.Sha1)] + [TestCase (DigestAlgorithm.Sha256)] + [TestCase (DigestAlgorithm.Sha384)] + [TestCase (DigestAlgorithm.Sha512)] + public virtual void TestSecureMimeEncryptionWithRsaesOaep (DigestAlgorithm hashAlgorithm) + { + var body = new TextPart ("plain") { Text = "This is some cleartext that we'll end up encrypting..." }; + + using (var ctx = CreateContext ()) { + var recipients = new CmsRecipientCollection (); + + var recipient = new CmsRecipient (MimeKitCertificate, SubjectIdentifierType.IssuerAndSerialNumber); + recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] { EncryptionAlgorithm.Aes128 }; + recipient.RsaEncryptionPadding = RsaEncryptionPadding.CreateOaep (hashAlgorithm); + recipients.Add (recipient); + + ApplicationPkcs7Mime encrypted; + + try { + encrypted = ApplicationPkcs7Mime.Encrypt (ctx, recipients, body); + } catch (NotSupportedException) { + if (!(ctx is WindowsSecureMimeContext)) + Assert.Fail ("RSAES-OAEP should be supported."); + return; + } + + Assert.AreEqual (SecureMimeType.EnvelopedData, encrypted.SecureMimeType, "S/MIME type did not match."); + + using (var stream = new MemoryStream ()) { + ctx.DecryptTo (encrypted.Content.Open (), stream); + stream.Position = 0; + + var decrypted = MimeEntity.Load (stream); + + Assert.IsInstanceOf (decrypted, "Decrypted part is not the expected type."); + Assert.AreEqual (body.Text, ((TextPart) decrypted).Text, "Decrypted content is not the same as the original."); + } + } + } + [Test] public void TestSecureMimeDecryptThunderbird () { - var p12 = Path.Combine ("..", "..", "TestData", "smime", "gnome.p12"); + var p12 = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "gnome.p12"); MimeMessage message; if (!File.Exists (p12)) return; - using (var file = File.OpenRead (Path.Combine ("..", "..", "TestData", "smime", "thunderbird-encrypted.txt"))) { + using (var file = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "thunderbird-encrypted.txt"))) { var parser = new MimeParser (file, MimeFormat.Default); message = parser.ParseMessage (); } @@ -774,7 +1261,7 @@ public virtual void TestSecureMimeSignAndEncrypt () } catch (DigitalSignatureVerifyException ex) { if (ctx is WindowsSecureMimeContext) { // AppVeyor gets an exception about the root certificate not being trusted - Assert.AreEqual (ex.InnerException.Message, UntrustedRootCertificateMessage); + Assert.AreEqual (UntrustedRootCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } @@ -785,13 +1272,13 @@ public virtual void TestSecureMimeSignAndEncrypt () [Test] public void TestSecureMimeDecryptVerifyThunderbird () { - var p12 = Path.Combine ("..", "..", "TestData", "smime", "gnome.p12"); + var p12 = Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "gnome.p12"); MimeMessage message; if (!File.Exists (p12)) return; - using (var file = File.OpenRead (Path.Combine ("..", "..", "TestData", "smime", "thunderbird-signed-encrypted.txt"))) { + using (var file = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "thunderbird-signed-encrypted.txt"))) { var parser = new MimeParser (file, MimeFormat.Default); message = parser.ParseMessage (); } @@ -859,7 +1346,7 @@ public void TestSecureMimeDecryptVerifyThunderbird () if (Path.DirectorySeparatorChar == '/') Assert.IsInstanceOf (ex.InnerException); else - Assert.AreEqual (ex.InnerException.Message, ExpiredCertificateMessage); + Assert.AreEqual (ExpiredCertificateMessage, ex.InnerException.Message); } else { Assert.Fail ("Failed to verify signature: {0}", ex); } @@ -868,7 +1355,7 @@ public void TestSecureMimeDecryptVerifyThunderbird () } [Test] - public void TestSecureMimeImportExport () + public virtual void TestSecureMimeImportExport () { var self = new MailboxAddress ("MimeKit UnitTests", "mimekit@example.com"); var mailboxes = new List (); @@ -886,7 +1373,7 @@ public void TestSecureMimeImportExport () Assert.AreEqual (SecureMimeType.CertsOnly, pkcs7mime.SecureMimeType, "S/MIME type did not match."); - using (var imported = new DummySecureMimeContext ()) { + using (var imported = new TemporarySecureMimeContext ()) { pkcs7mime.Import (imported); Assert.AreEqual (1, imported.certificates.Count, "Unexpected number of imported certificates."); @@ -894,12 +1381,66 @@ public void TestSecureMimeImportExport () } } } + + [Test] + public void TestSecureMimeVerifyMixedLineEndings () + { + MimeMessage message; + + using (var file = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "octet-stream-with-mixed-line-endings.dat"))) { + var parser = new MimeParser (file, MimeFormat.Default); + message = parser.ParseMessage (); + } + + Assert.IsInstanceOf (message.Body, "THe message body is not multipart/signed as expected."); + + var signed = (MultipartSigned) message.Body; + + using (var ctx = CreateContext ()) { + foreach (var signature in signed.Verify (ctx)) { + try { + bool valid = signature.Verify (true); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + } + } + + [Test] + public async Task TestSecureMimeVerifyMixedLineEndingsAsync () + { + MimeMessage message; + + using (var file = File.OpenRead (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "octet-stream-with-mixed-line-endings.dat"))) { + var parser = new MimeParser (file, MimeFormat.Default); + message = await parser.ParseMessageAsync (); + } + + Assert.IsInstanceOf (message.Body, "THe message body is not multipart/signed as expected."); + + var signed = (MultipartSigned) message.Body; + + using (var ctx = CreateContext ()) { + foreach (var signature in await signed.VerifyAsync (ctx)) { + try { + bool valid = signature.Verify (true); + + Assert.IsTrue (valid, "Bad signature from {0}", signature.SignerCertificate.Email); + } catch (DigitalSignatureVerifyException ex) { + Assert.Fail ("Failed to verify signature: {0}", ex); + } + } + } + } } [TestFixture] public class SecureMimeTests : SecureMimeTestsBase { - readonly TemporarySecureMimeContext ctx = new TemporarySecureMimeContext (); + readonly TemporarySecureMimeContext ctx = new TemporarySecureMimeContext { CheckCertificateRevocation = true }; protected override SecureMimeContext CreateContext () { @@ -914,6 +1455,7 @@ class MySecureMimeContext : DefaultSecureMimeContext { public MySecureMimeContext () : base ("smime.db", "no.secret") { + CheckCertificateRevocation = true; } } @@ -921,6 +1463,12 @@ protected override SecureMimeContext CreateContext () { return new MySecureMimeContext (); } + + static SecureMimeSqliteTests () + { + if (File.Exists ("smime.db")) + File.Delete ("smime.db"); + } } #if false @@ -946,6 +1494,12 @@ protected override SecureMimeContext CreateContext () [TestFixture] public class WindowsSecureMimeTests : SecureMimeTestsBase { + protected override bool IsEnabled { + get { + return Path.DirectorySeparatorChar == '\\'; + } + } + protected override SecureMimeContext CreateContext () { return new WindowsSecureMimeContext (); @@ -975,21 +1529,75 @@ public override void TestSecureMimeEncapsulatedSigning () } [Test] - public override void TestSecureMimeSigning () + public override void TestSecureMimeEncapsulatedSigningWithContext () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeEncapsulatedSigningWithContext (); + } + + [Test] + public override void TestSecureMimeEncapsulatedSigningWithCmsSigner () { if (Path.DirectorySeparatorChar != '\\') return; - base.TestSecureMimeSigning (); + base.TestSecureMimeEncapsulatedSigningWithCmsSigner (); } [Test] - public override async Task TestSecureMimeSigningAsync () + public override void TestSecureMimeEncapsulatedSigningWithContextAndCmsSigner () { if (Path.DirectorySeparatorChar != '\\') return; - await base.TestSecureMimeSigningAsync (); + base.TestSecureMimeEncapsulatedSigningWithContextAndCmsSigner (); + } + + [Test] + public override void TestSecureMimeSigningWithCmsSigner () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeSigningWithCmsSigner (); + } + + [Test] + public override void TestSecureMimeSigningWithContextAndCmsSigner () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeSigningWithContextAndCmsSigner (); + } + + [Test] + public override void TestSecureMimeSigningWithRsaSsaPss () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeSigningWithRsaSsaPss (); + } + + [Test] + public override void TestSecureMimeMessageSigning () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeMessageSigning (); + } + + [Test] + public override async Task TestSecureMimeMessageSigningAsync () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + await base.TestSecureMimeMessageSigningAsync (); } [Test] @@ -1019,6 +1627,15 @@ public override void TestSecureMimeEncryption () base.TestSecureMimeEncryption (); } + [Test] + public override void TestSecureMimeEncryptionWithContext () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeEncryptionWithContext (); + } + [Test] public override void TestSecureMimeEncryptionWithAlgorithm () { @@ -1028,6 +1645,18 @@ public override void TestSecureMimeEncryptionWithAlgorithm () base.TestSecureMimeEncryptionWithAlgorithm (); } + [TestCase (DigestAlgorithm.Sha1)] + [TestCase (DigestAlgorithm.Sha256)] + [TestCase (DigestAlgorithm.Sha384)] + [TestCase (DigestAlgorithm.Sha512)] + public override void TestSecureMimeEncryptionWithRsaesOaep (DigestAlgorithm hashAlgorithm) + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeEncryptionWithRsaesOaep (hashAlgorithm); + } + [Test] public override void TestSecureMimeSignAndEncrypt () { @@ -1036,5 +1665,14 @@ public override void TestSecureMimeSignAndEncrypt () base.TestSecureMimeSignAndEncrypt (); } + + [Test] + public override void TestSecureMimeImportExport () + { + if (Path.DirectorySeparatorChar != '\\') + return; + + base.TestSecureMimeImportExport (); + } } } diff --git a/UnitTests/Cryptography/SqliteCertificateDatabaseTests.cs b/UnitTests/Cryptography/SqliteCertificateDatabaseTests.cs new file mode 100644 index 0000000000..737b4c0504 --- /dev/null +++ b/UnitTests/Cryptography/SqliteCertificateDatabaseTests.cs @@ -0,0 +1,158 @@ +// +// SqliteCertificateDatabaseTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.X509.Store; +using Org.BouncyCastle.Utilities.Date; + +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class SqliteCertificateDatabaseTests + { + static readonly string[] StartComCertificates = { + "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" + }; + + readonly X509Certificate[] chain; + readonly string dataDir; + + public SqliteCertificateDatabaseTests () + { + dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "smime"); + var path = Path.Combine (dataDir, "smime.pfx"); + + if (File.Exists ("sqlite.db")) + File.Delete ("sqlite.db"); + + chain = SecureMimeTestsBase.LoadPkcs12CertificateChain (path, "no.secret"); + + using (var ctx = new DefaultSecureMimeContext ("sqlite.db", "no.secret")) { + foreach (var filename in StartComCertificates) { + path = Path.Combine (dataDir, filename); + using (var stream = File.OpenRead (path)) + ctx.Import (stream, true); + } + + path = Path.Combine (dataDir, "smime.pfx"); + ctx.Import (path, "no.secret"); + } + } + + [Test] + public void TestAutoUpgrade () + { + var path = Path.Combine (dataDir, "smimev0.db"); + const string tmp = "smimev0-tmp.db"; + + if (File.Exists (tmp)) + File.Delete (tmp); + + File.Copy (path, tmp); + + using (var dbase = new SqliteCertificateDatabase (tmp, "no.secret")) { + var root = chain[chain.Length - 1]; + + // Verify that we can select the Root Certificate + bool trustedAnchor = false; + foreach (var record in dbase.Find (null, true, X509CertificateRecordFields.Certificate)) { + if (record.Certificate.Equals (root)) { + trustedAnchor = true; + break; + } + } + + Assert.IsTrue (trustedAnchor, "Did not find the MimeKit UnitTests trusted anchor"); + } + } + + void AssertFindBy (IX509Selector selector, X509Certificate expected) + { + using (var dbase = new SqliteCertificateDatabase ("sqlite.db", "no.secret")) { + // Verify that we can select the Root Certificate + bool found = false; + foreach (var record in dbase.Find (selector, false, X509CertificateRecordFields.Certificate)) { + if (record.Certificate.Equals (expected)) { + found = true; + break; + } + } + + Assert.IsTrue (found, "Did not find the expected certificate"); + } + } + + [Test] + public void TestFindByBasicConstraints () + { + foreach (var certificate in chain) { + var basicConstraints = certificate.GetBasicConstraints (); + if (basicConstraints == -1) + basicConstraints = -2; + + var selector = new X509CertStoreSelector (); + selector.BasicConstraints = basicConstraints; + + AssertFindBy (selector, certificate); + } + } + + [Test] + public void TestFindByCertificateValid () + { + var selector = new X509CertStoreSelector (); + selector.CertificateValid = new DateTimeObject (chain[0].NotBefore.AddDays (10)); + + AssertFindBy (selector, chain[0]); + } + + [Test] + public void TestFindBySubjectName () + { + var selector = new X509CertStoreSelector (); + selector.Subject = chain[0].SubjectDN; + + AssertFindBy (selector, chain[0]); + } + + [Test] + public void TestFindBySubjectKeyIdentifier () + { + var subjectKeyIdentifier = chain[0].GetExtensionValue (X509Extensions.SubjectKeyIdentifier); + var selector = new X509CertStoreSelector (); + selector.SubjectKeyIdentifier = subjectKeyIdentifier.GetOctets (); + + AssertFindBy (selector, chain[0]); + } + } +} diff --git a/UnitTests/Cryptography/X509CertificateChainTests.cs b/UnitTests/Cryptography/X509CertificateChainTests.cs index 9262cb3c55..afce0edcd4 100644 --- a/UnitTests/Cryptography/X509CertificateChainTests.cs +++ b/UnitTests/Cryptography/X509CertificateChainTests.cs @@ -1,9 +1,9 @@ -// +// // X509CertificateChainTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,30 +26,33 @@ using System; using System.IO; - -using NUnit.Framework; +using System.Linq; +using System.Collections; +using System.Collections.Generic; using Org.BouncyCastle.X509; +using NUnit.Framework; + using MimeKit.Cryptography; namespace UnitTests.Cryptography { [TestFixture] public class X509CertificateChainTests { - static X509Certificate LoadCertificate (string path) - { - using (var stream = File.OpenRead (path)) { - var parser = new X509CertificateParser (); + static readonly string[] CertificateAuthorities = new string[] { + "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" + }; - return parser.ReadCertificate (stream); - } + static string GetTestDataPath (string relative) + { + return Path.Combine (TestHelper.ProjectDir, "TestData", "smime", relative); } [Test] public void TestArgumentExceptions () { - var path = Path.Combine ("..", "..", "TestData", "smime", "smime.p12"); + var path = GetTestDataPath ("smime.p12"); var chain = new X509CertificateChain (); CmsSigner signer; @@ -71,34 +74,62 @@ public void TestArgumentExceptions () } [Test] - public void TestBasicFunctionality () + public void TestAddRemoveRange () { - var dataDir = Path.Combine ("..", "..", "TestData", "smime"); + var certificates = new List (); var chain = new X509CertificateChain (); - X509Certificate cert1, cert2, cert3; - cert1 = LoadCertificate (Path.Combine (dataDir, "StartComClass1PrimaryIntermediateClientCA.crt")); - cert2 = LoadCertificate (Path.Combine (dataDir, "StartComCertificationAuthority.crt")); - cert3 = LoadCertificate (Path.Combine (dataDir, "certificate-authority.crt")); + foreach (var authority in CertificateAuthorities) { + var certificate = SecureMimeTestsBase.LoadCertificate (GetTestDataPath (authority)); + + certificates.Add (certificate); + } + + Assert.Throws (() => chain.AddRange (null)); + + chain.AddRange (certificates); + + Assert.AreEqual (CertificateAuthorities.Length, chain.Count, "Unexpected number of certificates after AddRange."); + + int index = 0; + foreach (var certificate in chain) + Assert.AreEqual (certificates[index++], certificate, "GetEnumerator"); + + index = 0; + foreach (X509Certificate certificate in ((IEnumerable) chain)) + Assert.AreEqual (certificates[index++], certificate, "GetEnumerator"); + + Assert.Throws (() => chain.RemoveRange (null)); + + chain.RemoveRange (certificates); + + Assert.AreEqual (0, chain.Count, "Unexpected number of certificates after RemoveRange."); + } + + [Test] + public void TestBasicFunctionality () + { + var certs = SecureMimeTestsBase.LoadPkcs12CertificateChain (GetTestDataPath ("smime.pfx"), "no.secret"); + var chain = new X509CertificateChain (); Assert.IsFalse (chain.IsReadOnly); Assert.AreEqual (0, chain.Count, "Initial count"); - chain.Add (cert3); + chain.Add (certs[2]); Assert.AreEqual (1, chain.Count); - Assert.AreEqual (cert3, chain[0]); + Assert.AreEqual (certs[2], chain[0]); - chain.Insert (0, cert1); - chain.Insert (1, cert2); + chain.Insert (0, certs[0]); + chain.Insert (1, certs[1]); Assert.AreEqual (3, chain.Count); - Assert.AreEqual (cert1, chain[0]); - Assert.AreEqual (cert2, chain[1]); - Assert.AreEqual (cert3, chain[2]); + Assert.AreEqual (certs[0], chain[0]); + Assert.AreEqual (certs[1], chain[1]); + Assert.AreEqual (certs[2], chain[2]); - Assert.IsTrue (chain.Contains (cert2), "Contains"); - Assert.AreEqual (1, chain.IndexOf (cert2), "IndexOf"); + Assert.IsTrue (chain.Contains (certs[1]), "Contains"); + Assert.AreEqual (1, chain.IndexOf (certs[1]), "IndexOf"); var array = new X509Certificate[chain.Count]; chain.CopyTo (array, 0); @@ -111,20 +142,20 @@ public void TestBasicFunctionality () Assert.AreEqual (array.Length, chain.Count); - Assert.IsTrue (chain.Remove (cert3)); + Assert.IsTrue (chain.Remove (certs[2])); Assert.AreEqual (2, chain.Count); - Assert.AreEqual (cert1, chain[0]); - Assert.AreEqual (cert2, chain[1]); + Assert.AreEqual (certs[0], chain[0]); + Assert.AreEqual (certs[1], chain[1]); chain.RemoveAt (0); Assert.AreEqual (1, chain.Count); - Assert.AreEqual (cert2, chain[0]); + Assert.AreEqual (certs[1], chain[0]); - chain[0] = cert3; + chain[0] = certs[2]; Assert.AreEqual (1, chain.Count); - Assert.AreEqual (cert3, chain[0]); + Assert.AreEqual (certs[2], chain[0]); } } } diff --git a/UnitTests/Cryptography/X509CertificateRecordTests.cs b/UnitTests/Cryptography/X509CertificateRecordTests.cs new file mode 100644 index 0000000000..20449bce61 --- /dev/null +++ b/UnitTests/Cryptography/X509CertificateRecordTests.cs @@ -0,0 +1,60 @@ +// +// X509CertificateRecordTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; + +using NUnit.Framework; + +using MimeKit.Cryptography; + +namespace UnitTests.Cryptography { + [TestFixture] + public class X509CertificateRecordTests + { + [Test] + public void TestArgumentExceptions () + { + var signer = new CmsSigner (Path.Combine (TestHelper.ProjectDir, "TestData", "smime", "smime.p12"), "no.secret"); + AsymmetricCipherKeyPair keyPair; + + using (var stream = new StreamReader (Path.Combine (TestHelper.ProjectDir, "TestData", "dkim", "example.pem"))) { + var reader = new PemReader (stream); + + keyPair = reader.ReadObject () as AsymmetricCipherKeyPair; + } + + Assert.Throws (() => new X509CrlRecord (null)); + Assert.Throws (() => new X509CertificateRecord (null)); + Assert.Throws (() => new X509CertificateRecord (null, keyPair.Private)); + Assert.Throws (() => new X509CertificateRecord (signer.Certificate, null)); + Assert.Throws (() => new X509CertificateRecord (signer.Certificate, keyPair.Public)); + } + } +} diff --git a/UnitTests/Cryptography/X509CertificateStoreTests.cs b/UnitTests/Cryptography/X509CertificateStoreTests.cs index 02f7bedcc7..3c81ae05c8 100644 --- a/UnitTests/Cryptography/X509CertificateStoreTests.cs +++ b/UnitTests/Cryptography/X509CertificateStoreTests.cs @@ -1,9 +1,9 @@ -// +// // X509CertificateStoreTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,9 @@ using System; using System.IO; using System.Linq; +using System.Collections.Generic; + +using Org.BouncyCastle.X509; using NUnit.Framework; @@ -37,12 +40,12 @@ namespace UnitTests.Cryptography { public class X509CertificateStoreTests { static readonly string[] CertificateAuthorities = new string[] { - "certificate-authority.crt", "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" + "StartComCertificationAuthority.crt", "StartComClass1PrimaryIntermediateClientCA.crt" }; static string GetTestDataPath (string relative) { - return Path.Combine ("..", "..", "TestData", "smime", relative); + return Path.Combine (TestHelper.ProjectDir, "TestData", "smime", relative); } [Test] @@ -72,6 +75,87 @@ public void TestArgumentExceptions () Assert.Throws (() => store.RemoveRange (null)); } + [Test] + public void TestAddRemove () + { + var certificates = new List (); + var parser = new X509CertificateParser (); + var store = new X509CertificateStore (); + + foreach (var authority in CertificateAuthorities) { + var path = GetTestDataPath (authority); + + using (var stream = File.OpenRead (path)) { + foreach (X509Certificate certificate in parser.ReadCertificates (stream)) + certificates.Add (certificate); + } + } + + foreach (var certificate in certificates) + store.Add (certificate); + + var count = store.Certificates.Count (); + + Assert.AreEqual (CertificateAuthorities.Length, count, "Unexpected number of certificates after Add."); + + foreach (var certificate in certificates) { + var key = store.GetPrivateKey (certificate); + Assert.IsNull (key, "GetPrivateKey"); + store.Remove (certificate); + } + + count = store.Certificates.Count (); + + Assert.AreEqual (0, count, "Unexpected number of certificates after Remove."); + } + + [Test] + public void TestAddRemoveRange () + { + var certificates = new List (); + var parser = new X509CertificateParser (); + var store = new X509CertificateStore (); + + foreach (var authority in CertificateAuthorities) { + var path = GetTestDataPath (authority); + + using (var stream = File.OpenRead (path)) { + foreach (X509Certificate certificate in parser.ReadCertificates (stream)) + certificates.Add (certificate); + } + } + + store.AddRange (certificates); + + var count = store.Certificates.Count (); + + Assert.AreEqual (CertificateAuthorities.Length, count, "Unexpected number of certificates after AddRange."); + + foreach (var certificate in certificates) { + var key = store.GetPrivateKey (certificate); + Assert.IsNull (key, "GetPrivateKey"); + } + + store.RemoveRange (certificates); + + count = store.Certificates.Count (); + + Assert.AreEqual (0, count, "Unexpected number of certificates after RemoveRange."); + } + + [Test] + public void TestImportData () + { + var store = new X509CertificateStore (); + + store.Import (File.ReadAllBytes (GetTestDataPath (CertificateAuthorities[0]))); + var certificate = store.Certificates.FirstOrDefault (); + var count = store.Certificates.Count (); + + Assert.AreEqual (1, count, "Unexpected number of certificates imported."); + Assert.AreEqual ("StartCom Certification Authority", certificate.GetCommonName (), "Unexpected CN for certificate."); + } + [Test] public void TestImportSingleCertificate () { @@ -82,7 +166,7 @@ public void TestImportSingleCertificate () var count = store.Certificates.Count (); Assert.AreEqual (1, count, "Unexpected number of certificates imported."); - Assert.AreEqual ("root@example.com", certificate.GetSubjectEmailAddress (), "Unexpected email address for certificate."); + Assert.AreEqual ("StartCom Certification Authority", certificate.GetCommonName (), "Unexpected CN for certificate."); } [Test] diff --git a/UnitTests/DomainListTests.cs b/UnitTests/DomainListTests.cs index 0fb5105cc6..0168972f01 100644 --- a/UnitTests/DomainListTests.cs +++ b/UnitTests/DomainListTests.cs @@ -1,9 +1,9 @@ -// +// // DomainListTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -111,6 +111,7 @@ public void TestBasicListFunctionality () Assert.AreEqual (array.Length, list.Count); + Assert.IsFalse (list.Remove ("not-in-the-list")); Assert.IsTrue (list.Remove ("domain2")); Assert.AreEqual (2, list.Count); Assert.AreEqual ("domain0", list[0]); @@ -170,5 +171,16 @@ public void TestParseEmptyDomains () AssertParse ("@domain1,,@domain2", expected); } + + [Test] + public void TestToString () + { + var route = new DomainList (); + route.Add ("route1"); + route.Add (" \t\t "); + route.Add ("route2"); + + Assert.AreEqual ("@route1,@route2", route.ToString ()); + } } } diff --git a/UnitTests/Encodings/EncoderTests.cs b/UnitTests/Encodings/EncoderTests.cs index d17f08de3f..3c8c0f1eca 100644 --- a/UnitTests/Encodings/EncoderTests.cs +++ b/UnitTests/Encodings/EncoderTests.cs @@ -1,9 +1,9 @@ -// +// // EncoderTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -58,85 +58,73 @@ public class EncoderTests "This is the plain text message!" }; static readonly string[] base64EncodedLongPatterns = { - "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCU" - + "mJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0" - + "xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bxc" - + "nN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeY" - + "mZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6" - + "/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5O" - + "Xm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", - - "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSY" - + "nKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE" - + "1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc" - + "3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZ" - + "mpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/" - + "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5e" - + "bn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AA==", - - "AgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJic" - + "oKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU" - + "5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzd" - + "HV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJma" - + "m5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8D" - + "BwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5u" - + "fo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQ==" + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCU" + + "mJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0" + + "xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bxc" + + "nN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeY" + + "mZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6" + + "/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5O" + + "Xm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", + + "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSY" + + "nKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE" + + "1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc" + + "3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZ" + + "mpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/" + + "AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5e" + + "bn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AA==", + + "AgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJic" + + "oKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU" + + "5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzd" + + "HV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJma" + + "m5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8D" + + "BwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5u" + + "fo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQ==" }; - [Test] - public void TestBase64Decode () - { - using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) - file.CopyTo (original, 4096); - - using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { - using (var filtered = new FilteredStream (file)) { - filtered.Add (DecoderFilter.Create (ContentEncoding.Base64)); - filtered.CopyTo (decoded, 4096); - } - } + static readonly string dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "encoders"); + static readonly byte[] wikipedia_unix; + static readonly byte[] wikipedia_dos; + static readonly byte[] photo; - var buf0 = original.GetBuffer (); - var buf1 = decoded.GetBuffer (); - int n = (int) original.Length; + static EncoderTests () + { + using (var memory = new MemoryStream ()) { + using (var filtered = new FilteredStream (memory)) { + filtered.Add (new Dos2UnixFilter ()); - Assert.AreEqual (original.Length, decoded.Length, "Decoded length is incorrect."); + using (var file = File.OpenRead (Path.Combine (dataDir, "wikipedia.txt"))) + file.CopyTo (filtered, 4096); - for (int i = 0; i < n; i++) - Assert.AreEqual (buf0[i], buf1[i], "The byte at offset {0} does not match.", i); + filtered.Flush (); } - } - var decoder = new Base64Decoder (); - var output = new byte[4096]; + wikipedia_unix = memory.ToArray (); + } - Assert.AreEqual (ContentEncoding.Base64, decoder.Encoding); + using (var memory = new MemoryStream ()) { + using (var filtered = new FilteredStream (memory)) { + filtered.Add (new Unix2DosFilter ()); - for (int i = 0; i < base64EncodedPatterns.Length; i++) { - decoder.Reset (); - var buf = Encoding.ASCII.GetBytes (base64EncodedPatterns[i]); - int n = decoder.Decode (buf, 0, buf.Length, output); - var actual = Encoding.ASCII.GetString (output, 0, n); - Assert.AreEqual (base64DecodedPatterns[i], actual, "Failed to decode base64EncodedPatterns[{0}]", i); - } + using (var file = File.OpenRead (Path.Combine (dataDir, "wikipedia.txt"))) + file.CopyTo (filtered, 4096); - for (int i = 0; i < base64EncodedLongPatterns.Length; i++) { - decoder.Reset (); - var buf = Encoding.ASCII.GetBytes (base64EncodedLongPatterns[i]); - int n = decoder.Decode (buf, 0, buf.Length, output); + filtered.Flush (); + } - for (int j = 0; j < n; j++) - Assert.AreEqual (output[j], (byte) (j + i), "Failed to decode base64EncodedLongPatterns[{0}]", i); + wikipedia_dos = memory.ToArray (); } + + photo = File.ReadAllBytes (Path.Combine (dataDir, "photo.jpg")); } - [Test] - public void TestBase64Encode () + void TestEncoder (ContentEncoding encoding, byte[] rawData, string encodedFile, int bufferSize) { + int n; + using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { + using (var file = File.OpenRead (Path.Combine (dataDir, encodedFile))) { using (var filtered = new FilteredStream (original)) { filtered.Add (new Dos2UnixFilter ()); file.CopyTo (filtered, 4096); @@ -145,18 +133,32 @@ public void TestBase64Encode () } using (var encoded = new MemoryStream ()) { + if (encoding == ContentEncoding.UUEncode) { + var begin = Encoding.ASCII.GetBytes ("begin 644 photo.jpg\n"); + encoded.Write (begin, 0, begin.Length); + } + using (var filtered = new FilteredStream (encoded)) { - filtered.Add (EncoderFilter.Create (ContentEncoding.Base64)); + filtered.Add (EncoderFilter.Create (encoding)); + + using (var memory = new MemoryStream (rawData, false)) { + var buffer = new byte[bufferSize]; - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) - file.CopyTo (filtered, 4096); + while ((n = memory.Read (buffer, 0, bufferSize)) > 0) + filtered.Write (buffer, 0, n); + } filtered.Flush (); } + if (encoding == ContentEncoding.UUEncode) { + var end = Encoding.ASCII.GetBytes ("end\n"); + encoded.Write (end, 0, end.Length); + } + var buf0 = original.GetBuffer (); var buf1 = encoded.GetBuffer (); - int n = (int) original.Length; + n = (int) original.Length; Assert.AreEqual (original.Length, encoded.Length, "Encoded length is incorrect."); @@ -166,72 +168,106 @@ public void TestBase64Encode () } } - [Test] - public void TestUUDecode () + void TestDecoder (ContentEncoding encoding, byte[] rawData, string encodedFile, int bufferSize, bool unix = false) { - using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) - file.CopyTo (original, 4096); - - using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.uu")) { - using (var filtered = new FilteredStream (file)) { - filtered.Add (DecoderFilter.Create (ContentEncoding.UUEncode)); - filtered.CopyTo (decoded, 4096); - } - } + int n; - var buf0 = original.GetBuffer (); - var buf1 = decoded.GetBuffer (); - int n = (int) original.Length; + using (var decoded = new MemoryStream ()) { + using (var filtered = new FilteredStream (decoded)) { + filtered.Add (DecoderFilter.Create (encoding)); + + if (unix) + filtered.Add (new Dos2UnixFilter ()); - Assert.AreEqual (original.Length, decoded.Length, "Decoded length is incorrect."); + using (var file = File.OpenRead (Path.Combine (dataDir, encodedFile))) { + var buffer = new byte[bufferSize]; - for (int i = 0; i < n; i++) - Assert.AreEqual (buf0[i], buf1[i], "The byte at offset {0} does not match.", i); + while ((n = file.Read (buffer, 0, bufferSize)) > 0) + filtered.Write (buffer, 0, n); + } + + filtered.Flush (); } + + var buf = decoded.GetBuffer (); + n = rawData.Length; + + Assert.AreEqual (rawData.Length, decoded.Length, "Decoded length is incorrect."); + + for (int i = 0; i < n; i++) + Assert.AreEqual (rawData[i], buf[i], "The byte at offset {0} does not match.", i); } } [Test] - public void TestUUEncode () + public void TestBase64DecodePatterns () { - using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.uu")) { - using (var filtered = new FilteredStream (original)) { - filtered.Add (new Dos2UnixFilter ()); - file.CopyTo (filtered, 4096); - filtered.Flush (); - } - } + var decoder = new Base64Decoder (); + var output = new byte[4096]; - using (var encoded = new MemoryStream ()) { - var begin = Encoding.ASCII.GetBytes ("begin 644 photo.jpg\n"); - var end = Encoding.ASCII.GetBytes ("end\n"); + Assert.AreEqual (ContentEncoding.Base64, decoder.Encoding); - encoded.Write (begin, 0, begin.Length); + for (int i = 0; i < base64EncodedPatterns.Length; i++) { + decoder.Reset (); + var buf = Encoding.ASCII.GetBytes (base64EncodedPatterns[i]); + int n = decoder.Decode (buf, 0, buf.Length, output); + var actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (base64DecodedPatterns[i], actual, "Failed to decode base64EncodedPatterns[{0}]", i); + } - using (var filtered = new FilteredStream (encoded)) { - filtered.Add (EncoderFilter.Create (ContentEncoding.UUEncode)); + for (int i = 0; i < base64EncodedLongPatterns.Length; i++) { + decoder.Reset (); + var buf = Encoding.ASCII.GetBytes (base64EncodedLongPatterns[i]); + int n = decoder.Decode (buf, 0, buf.Length, output); - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) - file.CopyTo (filtered, 4096); + for (int j = 0; j < n; j++) + Assert.AreEqual (output[j], (byte) (j + i), "Failed to decode base64EncodedLongPatterns[{0}]", i); + } + } - filtered.Flush (); - } + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestBase64Encode (int bufferSize) + { + TestEncoder (ContentEncoding.Base64, photo, "photo.b64", bufferSize); + } - encoded.Write (end, 0, end.Length); + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestBase64Decode (int bufferSize) + { + TestDecoder (ContentEncoding.Base64, photo, "photo.b64", bufferSize); + } - var buf0 = original.GetBuffer (); - var buf1 = encoded.GetBuffer (); - int n = (int) original.Length; + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestUUEncode (int bufferSize) + { + TestEncoder (ContentEncoding.UUEncode, photo, "photo.uu", bufferSize); + } - Assert.AreEqual (original.Length, encoded.Length, "Encoded length is incorrect."); + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestUUDecode (int bufferSize) + { + TestDecoder (ContentEncoding.UUEncode, photo, "photo.uu", bufferSize); + } - for (int i = 0; i < n; i++) - Assert.AreEqual (buf0[i], buf1[i], "The byte at offset {0} does not match.", i); - } - } + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestUUDecodeBeginStateChanges (int bufferSize) + { + TestDecoder (ContentEncoding.UUEncode, photo, "photo.uu-states", bufferSize); } static readonly string[] qpEncodedPatterns = { @@ -253,7 +289,135 @@ public void TestUUEncode () }; [Test] - public void TestQuotedPrintableDecode () + public void TestQuotedPrintableDecodePatterns () + { + var decoder = new QuotedPrintableDecoder (); + var encoding = CharsetUtils.Latin1; + var output = new byte[4096]; + string actual; + byte[] buf; + int n; + + for (int i = 0; i < qpEncodedPatterns.Length; i++) { + decoder.Reset (); + buf = encoding.GetBytes (qpEncodedPatterns[i]); + n = decoder.Decode (buf, 0, buf.Length, output); + actual = encoding.GetString (output, 0, n); + Assert.AreEqual (qpDecodedPatterns[i], actual, "Failed to decode qpEncodedPatterns[{0}]", i); + } + } + + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestQuotedPrintableEncodeDos (int bufferSize) + { + TestEncoder (ContentEncoding.QuotedPrintable, wikipedia_dos, "wikipedia.qp", bufferSize); + } + + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestQuotedPrintableEncodeUnix (int bufferSize) + { + TestEncoder (ContentEncoding.QuotedPrintable, wikipedia_unix, "wikipedia.qp", bufferSize); + } + + [TestCase (4096)] + [TestCase (1024)] + [TestCase (16)] + [TestCase (1)] + public void TestQuotedPrintableDecode (int bufferSize) + { + TestDecoder (ContentEncoding.QuotedPrintable, wikipedia_unix, "wikipedia.qp", bufferSize, true); + } + + [Test] + public void TestQuotedPrintableEncodeSpaceDosLineBreak () + { + const string input = "This line ends with a space \r\nbefore a line break."; + const string expected = "This line ends with a space=20\nbefore a line break."; + var encoder = new QuotedPrintableEncoder (); + var output = new byte[1024]; + string actual; + byte[] buf; + int n; + + Assert.AreEqual (ContentEncoding.QuotedPrintable, encoder.Encoding); + + buf = Encoding.ASCII.GetBytes (input); + n = encoder.Flush (buf, 0, buf.Length, output); + actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (expected, actual); + } + + [Test] + public void TestQuotedPrintableEncodeSpaceUnixLineBreak () + { + const string input = "This line ends with a space \nbefore a line break."; + const string expected = "This line ends with a space=20\nbefore a line break."; + var encoder = new QuotedPrintableEncoder (); + var output = new byte[1024]; + string actual; + byte[] buf; + int n; + + Assert.AreEqual (ContentEncoding.QuotedPrintable, encoder.Encoding); + + buf = Encoding.ASCII.GetBytes (input); + n = encoder.Flush (buf, 0, buf.Length, output); + actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (expected, actual); + } + + [Test] + public void TestQuotedPrintableEncodeFlush () + { + const string input = "This line ends with a space "; + const string expected = "This line ends with a space=20=\n"; + var encoder = new QuotedPrintableEncoder (); + var decoder = new QuotedPrintableDecoder (); + var output = new byte[1024]; + string actual; + byte[] buf; + int n; + + Assert.AreEqual (ContentEncoding.QuotedPrintable, encoder.Encoding); + + buf = Encoding.ASCII.GetBytes (input); + n = encoder.Flush (buf, 0, buf.Length, output); + actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (expected, actual); + + buf = Encoding.ASCII.GetBytes (expected); + n = decoder.Decode (buf, 0, buf.Length, output); + actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (input, actual); + } + + [Test] + public void TestQuotedPrintableDecodeInvalidSoftBreak () + { + const string input = "This is an invalid=\rsoft break."; + const string expected = "This is an invalid=\rsoft break."; + var decoder = new QuotedPrintableDecoder (); + var output = new byte[1024]; + string actual; + byte[] buf; + int n; + + Assert.AreEqual (ContentEncoding.QuotedPrintable, decoder.Encoding); + + buf = Encoding.ASCII.GetBytes (input); + n = decoder.Decode (buf, 0, buf.Length, output); + actual = Encoding.ASCII.GetString (output, 0, n); + Assert.AreEqual (expected, actual); + } + + [Test] + public void TestQuotedPrintableDecode2 () { const string input = "This is an ordinary text message in which my name (=ED=E5=EC=F9 =EF=E1 =E9=EC=E8=F4=F0)\nis in Hebrew (=FA=E9=F8=E1=F2)."; const string expected = "This is an ordinary text message in which my name (םולש ןב ילטפנ)\nis in Hebrew (תירבע)."; @@ -270,26 +434,16 @@ public void TestQuotedPrintableDecode () n = decoder.Decode (buf, 0, buf.Length, output); actual = encoding.GetString (output, 0, n); Assert.AreEqual (expected, actual); - - encoding = CharsetUtils.Latin1; - - for (int i = 0; i < qpEncodedPatterns.Length; i++) { - decoder.Reset (); - buf = encoding.GetBytes (qpEncodedPatterns[i]); - n = decoder.Decode (buf, 0, buf.Length, output); - actual = encoding.GetString (output, 0, n); - Assert.AreEqual (qpDecodedPatterns[i], actual, "Failed to decode qpEncodedPatterns[{0}]", i); - } } [Test] - public void TestQuotedPrintableEncode () + public void TestQuotedPrintableEncode2 () { const string expected = "This is an ordinary text message in which my name (=ED=E5=EC=F9 =EF=E1=\n =E9=EC=E8=F4=F0)\nis in Hebrew (=FA=E9=F8=E1=F2).\n"; const string input = "This is an ordinary text message in which my name (םולש ןב ילטפנ)\nis in Hebrew (תירבע).\n"; var encoding = Encoding.GetEncoding ("iso-8859-8"); var encoder = new QuotedPrintableEncoder (); - var output = new byte[4096]; + var output = new byte[1024]; Assert.AreEqual (ContentEncoding.QuotedPrintable, encoder.Encoding); @@ -300,6 +454,24 @@ public void TestQuotedPrintableEncode () Assert.AreEqual (expected, actual); } + [Test] + public void TestHexDecoder () + { + const string input = "This should decode: (%ED%E5%EC%F9 %EF%E1 %E9%EC%E8%F4%F0) while %X1%S1%Z1 should not"; + const string expected = "This should decode: (םולש ןב ילטפנ) while %X1%S1%Z1 should not"; + var encoding = Encoding.GetEncoding ("iso-8859-8"); + var decoder = new HexDecoder (); + var output = new byte[1024]; + + Assert.AreEqual (ContentEncoding.Default, decoder.Encoding); + + var buf = Encoding.ASCII.GetBytes (input); + int n = decoder.Decode (buf, 0, buf.Length, output); + var actual = encoding.GetString (output, 0, n); + + Assert.AreEqual (expected, actual); + } + [Test] public void TestPassThroughEncoder () { diff --git a/UnitTests/Encodings/YEncodingTests.cs b/UnitTests/Encodings/YEncodingTests.cs index 294966462e..e749154a5e 100644 --- a/UnitTests/Encodings/YEncodingTests.cs +++ b/UnitTests/Encodings/YEncodingTests.cs @@ -1,9 +1,9 @@ -// +// // YEncodingTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -39,6 +39,8 @@ namespace UnitTests.Encodings { [TestFixture] public class YEncodingTests { + static readonly string DataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "yenc"); + [Test] public void TestArgumentExceptions () { @@ -48,7 +50,7 @@ public void TestArgumentExceptions () [Test] public void TestYDecodeSimpleMessage () { - using (var file = File.OpenRead ("../../TestData/yenc/simple.msg")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "simple.msg"))) { var message = MimeMessage.Load (file); using (var decoded = new MemoryStream ()) { @@ -112,10 +114,10 @@ public void TestYDecodeSimpleMessage () [Test] public void TestYDecodeMultiPart () { - var expected = File.ReadAllBytes ("../../TestData/yenc/joystick.jpg"); + var expected = File.ReadAllBytes (Path.Combine (DataDir, "joystick.jpg")); using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/yenc/00000020.ntx")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "00000020.ntx"))) { var ydec = new YDecoder (); using (var filtered = new FilteredStream (decoded)) { @@ -128,7 +130,7 @@ public void TestYDecodeMultiPart () Assert.AreEqual (0xbfae5c0b, ydec.Checksum ^ 0xffffffff, "The decoded checksum does not match (part 1)."); } - using (var file = File.OpenRead ("../../TestData/yenc/00000021.ntx")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "00000021.ntx"))) { var ydec = new YDecoder (); using (var filtered = new FilteredStream (decoded)) { @@ -151,7 +153,7 @@ public void TestYDecodeMultiPart () [Test] public void TestYDecodeStateTransitions () { - using (var file = File.OpenRead ("../../TestData/yenc/state-changes.ntx")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "state-changes.ntx"))) { using (var decoded = new MemoryStream ()) { var ydec = new YDecoder (); @@ -166,5 +168,49 @@ public void TestYDecodeStateTransitions () } } } + + static readonly string[] YPartTransitionInputs = { + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=xcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=yxcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=ypxcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=ypaxcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=yparxcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=ypartxcontent", + "=ybegin part=1 line=128 size=19338 name=joystick.jpg\n=ypart begin=1 end=11250\ncontent", + }; + + static readonly string[] YPartTransitionOutputs = { + "xcontent", + string.Empty, + string.Empty, + string.Empty, + string.Empty, + string.Empty, + "content" + }; + + [Test] + public void TestYDecodeYPartStateTransitions () + { + var ydec = new YDecoder (); + var decoded = new byte[1024]; + + for (int i = 0; i < YPartTransitionInputs.Length; i++) { + var input = Encoding.ASCII.GetBytes (YPartTransitionInputs[i]); + var chars = YPartTransitionOutputs[i].ToCharArray (); + + for (int j = 0; j < chars.Length; j++) + chars[j] -= (char) 42; + + var expected = new string (chars); + + int n = ydec.Decode (input, 0, input.Length, decoded); + var actual = Encoding.ASCII.GetString (decoded, 0, n); + + Assert.AreEqual (expected, actual, YPartTransitionInputs[i]); + + ydec.Reset (); + } + } } } diff --git a/UnitTests/ExceptionTests.cs b/UnitTests/ExceptionTests.cs index a3f0dc1615..aeb3b2c3f8 100644 --- a/UnitTests/ExceptionTests.cs +++ b/UnitTests/ExceptionTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -136,6 +136,9 @@ public void TestPrivateKeyNotFoundException () TestPrivateKeyNotFoundException (new PrivateKeyNotFoundException (new MailboxAddress ("Unit Tests", "example@mimekit.net"), "Message")); TestPrivateKeyNotFoundException (new PrivateKeyNotFoundException ("DEADBEEF", "Message")); TestPrivateKeyNotFoundException (new PrivateKeyNotFoundException (0xdeadbeef, "Message")); + + Assert.Throws (() => new PrivateKeyNotFoundException ((string) null, "Message")); + Assert.Throws (() => new PrivateKeyNotFoundException ((MailboxAddress) null, "Message")); } [Test] diff --git a/UnitTests/FormatOptionsTests.cs b/UnitTests/FormatOptionsTests.cs new file mode 100644 index 0000000000..979425c31e --- /dev/null +++ b/UnitTests/FormatOptionsTests.cs @@ -0,0 +1,60 @@ +// +// FormatOptionsTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +using NUnit.Framework; + +using MimeKit; + +namespace UnitTests { + [TestFixture] + public class FormatOptionsTests + { + [Test] + public void TestArgumentExceptions () + { + var format = FormatOptions.Default.Clone (); + + Assert.Throws (() => format.ParameterEncodingMethod = (ParameterEncodingMethod) 100, "ParameterEncodingMethod"); + Assert.Throws (() => format.MaxLineLength = 999, "MaxLineLength too large"); + Assert.Throws (() => format.MaxLineLength = 59, "MaxLineLength too small"); + + Assert.DoesNotThrow (() => format.MaxLineLength = 72); + } + + [Test] + public void TestInvalidOperationExceptions () + { + Assert.Throws (() => FormatOptions.Default.MaxLineLength = 998, "MaxLineLength"); + Assert.Throws (() => FormatOptions.Default.EnsureNewLine = true, "EnsureNewLine"); + Assert.Throws (() => FormatOptions.Default.International = true, "International"); + Assert.Throws (() => FormatOptions.Default.NewLineFormat = NewLineFormat.Dos, "NewLineFormat"); + Assert.Throws (() => FormatOptions.Default.AllowMixedHeaderCharsets = true, "AllowMixedHeaderCharsets"); + Assert.Throws (() => FormatOptions.Default.ParameterEncodingMethod = ParameterEncodingMethod.Rfc2047, "ParameterEncodingMethod"); + } + } +} diff --git a/UnitTests/GroupAddressTests.cs b/UnitTests/GroupAddressTests.cs index 9011e8ed06..982e8a0c02 100644 --- a/UnitTests/GroupAddressTests.cs +++ b/UnitTests/GroupAddressTests.cs @@ -1,9 +1,9 @@ -// +// // GroupAddressTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -140,6 +140,33 @@ static void AssertParse (string text) } } + [Test] + public void TestClone () + { + const string encoded = "Group Name: First Name , Second Name ,\n Inner Group Name: First Inner Name ,\n Second Inner Name ;, Third Name ;"; + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.International = true; + + var inner = new GroupAddress ("Inner Group Name"); + inner.Members.Add (new MailboxAddress ("First Inner Name", "first-inner@address.com")); + inner.Members.Add (new MailboxAddress ("Second Inner Name", "second-inner@address.com")); + + var group = new GroupAddress ("Group Name"); + group.Members.Add (new MailboxAddress ("First Name", "first@address.com")); + group.Members.Add (new MailboxAddress ("Second Name", "second@address.com")); + group.Members.Add (inner); + group.Members.Add (new MailboxAddress ("Third Name", "third@address.com")); + + var clone = group.Clone (); + + Assert.AreEqual (0, group.CompareTo (clone), "CompareTo"); + + var actual = clone.ToString (options, true); + + Assert.AreEqual (encoded, actual, "Encode"); + } + [Test] public void TestParseEmpty () { diff --git a/UnitTests/HeaderListTests.cs b/UnitTests/HeaderListTests.cs index cef1ab85e9..fb88312b99 100644 --- a/UnitTests/HeaderListTests.cs +++ b/UnitTests/HeaderListTests.cs @@ -1,9 +1,9 @@ -// +// // HeaderListTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -50,11 +50,11 @@ public void TestArgumentExceptions () Assert.Throws (() => HeaderList.Load (null, stream)); Assert.Throws (() => HeaderList.Load (ParserOptions.Default, (Stream) null)); - Assert.Throws (async () => await HeaderList.LoadAsync (null, "filename.txt")); - Assert.Throws (async () => await HeaderList.LoadAsync (ParserOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (null, "filename.txt")); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (ParserOptions.Default, (string) null)); - Assert.Throws (async () => await HeaderList.LoadAsync (null, stream)); - Assert.Throws (async () => await HeaderList.LoadAsync (ParserOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (null, stream)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (ParserOptions.Default, (Stream) null)); } // Add @@ -138,11 +138,11 @@ public void TestArgumentExceptions () Assert.Throws (() => HeaderList.Load ((string) null)); // LoadAsync - Assert.Throws (async () => await HeaderList.LoadAsync (ParserOptions.Default, (Stream) null)); - Assert.Throws (async () => await HeaderList.LoadAsync (ParserOptions.Default, (string) null)); - Assert.Throws (async () => await HeaderList.LoadAsync (null, stream)); - Assert.Throws (async () => await HeaderList.LoadAsync ((Stream) null)); - Assert.Throws (async () => await HeaderList.LoadAsync ((string) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (ParserOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (ParserOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync (null, stream)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await HeaderList.LoadAsync ((string) null)); // WriteTo Assert.Throws (() => list.WriteTo (FormatOptions.Default, null)); @@ -150,9 +150,9 @@ public void TestArgumentExceptions () Assert.Throws (() => list.WriteTo (null)); // WriteToAsync - Assert.Throws (async () => await list.WriteToAsync (FormatOptions.Default, null)); - Assert.Throws (async () => await list.WriteToAsync (null, stream)); - Assert.Throws (async () => await list.WriteToAsync (null)); + Assert.ThrowsAsync (async () => await list.WriteToAsync (FormatOptions.Default, null)); + Assert.ThrowsAsync (async () => await list.WriteToAsync (null, stream)); + Assert.ThrowsAsync (async () => await list.WriteToAsync (null)); } // Indexers diff --git a/UnitTests/HeaderTests.cs b/UnitTests/HeaderTests.cs index aab2279b01..7d01084828 100644 --- a/UnitTests/HeaderTests.cs +++ b/UnitTests/HeaderTests.cs @@ -1,9 +1,9 @@ -// +// // HeaderTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -105,6 +105,11 @@ public void TestArgumentExceptions () Assert.Throws (() => header.SetValue (Encoding.UTF8, null)); Assert.Throws (() => header.SetValue ((string) null, "value")); Assert.Throws (() => header.SetValue ("utf-8", null)); + + // SetRawValue + Assert.Throws (() => header.SetRawValue (null)); + Assert.Throws (() => header.SetRawValue (new byte[0])); + Assert.Throws (() => header.SetRawValue (Encoding.ASCII.GetBytes ("abc"))); } [Test] @@ -135,6 +140,28 @@ public void TestAddressHeaderFolding () Assert.AreEqual (expected, raw, "The folded address header does not match the expected value."); } + static readonly string[] ArcAuthenticationResultsHeaderValues = { + " i=1; lists.example.org;" + FormatOptions.Default.NewLine + "\tspf=pass smtp.mfrom=jqd@d1.example;" + FormatOptions.Default.NewLine + "\tdkim=pass (1024 - bit key) header.i=@d1.example; dmarc=pass", + " i=2; gmail.example;" + FormatOptions.Default.NewLine + "\tspf=fail smtp.from=jqd@d1.example;" + FormatOptions.Default.NewLine + "\tdkim=fail (512-bit key) header.i=@example.org; dmarc=fail;" + FormatOptions.Default.NewLine + "\tarc=pass (as.1.lists.example.org=pass, ams.1.lists.example.org=pass)", + " i=3; gmail.example;" + FormatOptions.Default.NewLine + "\tspf=fail smtp.from=jqd@d1.example;" + FormatOptions.Default.NewLine + "\tdkim=fail (512-bit key) header.i=@example.org; dmarc=fail"+ FormatOptions.Default.NewLine + "\t(this-is-a-really-really-really-long-unbroken-comment-that-will-be-on-a-line-by-itself);" + FormatOptions.Default.NewLine + "\tarc=pass (as.1.lists.example.org=pass, ams.1.lists.example.org=pass)" + }; + + [Test] + public void TestArcAuthenticationResultsHeaderFolding () + { + var header = new Header ("ARC-Authentication-Results", ""); + + foreach (var authResults in ArcAuthenticationResultsHeaderValues) { + header.SetValue (Encoding.ASCII, authResults.Replace (FormatOptions.Default.NewLine + "\t", " ").Trim ()); + + var raw = ByteArrayToString (header.RawValue); + + Assert.IsTrue (raw[raw.Length - 1] == '\n', "The RawValue does not end with a new line."); + + Assert.AreEqual (authResults + FormatOptions.Default.NewLine, raw, "The folded ARC-Authentication-Results header does not match the expected value."); + } + } + [Test] public void TestMessageIdHeaderFolding () { @@ -147,6 +174,16 @@ public void TestMessageIdHeaderFolding () Assert.AreEqual (expected, raw, "The folded Message-Id header does not match the expected value."); } + [Test] + public void TestSubjectHeaderFolding () + { + const string expected = " =?utf-8?b?0KLQtdGB0YLQvtCy0YvQuSDQt9Cw0LPQvtC70L7QstC+0Log0L/QuNGB0YzQvNCw?=\n"; + var header = new Header ("Subject", "Тестовый заголовок письма"); + var actual = ByteArrayToString (header.RawValue).Replace ("\r", ""); + + Assert.AreEqual (expected, actual); + } + static readonly string[] ReceivedHeaderValues = { " from thumper.bellcore.com by greenbush.bellcore.com (4.1/4.7)" + FormatOptions.Default.NewLine + "\tid for nsb; Fri, 29 Nov 91 07:13:33 EST", " from joyce.cs.su.oz.au by thumper.bellcore.com (4.1/4.7)" + FormatOptions.Default.NewLine + "\tid for nsb@greenbush; Fri, 29 Nov 91 07:11:57 EST", @@ -343,5 +380,21 @@ public void TestToHeaderId () Assert.AreEqual (HeaderId.Unknown, parsed, "Failed to parse the made-up header value"); } + + [Test] + public void TestSetRawValue () + { + var header = new Header (HeaderId.Subject, "This is the subject"); + var rawValue = Encoding.ASCII.GetBytes ("This is the\n raw subject\n"); + var format = FormatOptions.Default.Clone (); + format.International = true; + + header.SetRawValue (rawValue); + + var value = header.GetRawValue (format); + Assert.AreEqual (rawValue.Length, value.Length, "Length"); + for (int i = 0; i < rawValue.Length; i++) + Assert.AreEqual (rawValue[i], value[i], "rawValue[{0}]", i); + } } } diff --git a/UnitTests/HtmlPreviewVisitor.cs b/UnitTests/HtmlPreviewVisitor.cs index ba23a2ed6a..55020dfb20 100644 --- a/UnitTests/HtmlPreviewVisitor.cs +++ b/UnitTests/HtmlPreviewVisitor.cs @@ -1,9 +1,9 @@ -// +// // HtmlPreviewVisitor.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/IO/BoundStreamTests.cs b/UnitTests/IO/BoundStreamTests.cs index df3ea3248b..36a527e757 100644 --- a/UnitTests/IO/BoundStreamTests.cs +++ b/UnitTests/IO/BoundStreamTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/IO/CanReadWriteSeekStream.cs b/UnitTests/IO/CanReadWriteSeekStream.cs index 0127308655..8f7e6625aa 100644 --- a/UnitTests/IO/CanReadWriteSeekStream.cs +++ b/UnitTests/IO/CanReadWriteSeekStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/IO/ChainedStreamTests.cs b/UnitTests/IO/ChainedStreamTests.cs index c2dced35cf..ae824e0fe1 100644 --- a/UnitTests/IO/ChainedStreamTests.cs +++ b/UnitTests/IO/ChainedStreamTests.cs @@ -1,9 +1,9 @@ -// +// // ChainedStreamTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -160,7 +160,7 @@ public void TestRead () } [Test] - public async void TestReadAsync () + public async Task TestReadAsync () { Assert.IsTrue (chained.CanRead, "Expected to be able to read from the chained stream."); @@ -269,7 +269,7 @@ async Task AssertSeekResultsAsync (string operation) } [Test] - public async void TestRandomSeekingAsync () + public async Task TestRandomSeekingAsync () { Assert.IsTrue (chained.CanSeek, "Expected to be able to seek in the chained stream."); @@ -304,7 +304,7 @@ public async void TestRandomSeekingAsync () } [Test] - public async void TestSeekingToStreamBoundariesAsync () + public async Task TestSeekingToStreamBoundariesAsync () { long expected, actual; @@ -351,7 +351,7 @@ public void TestWrite () } [Test] - public async void TestWriteAsync () + public async Task TestWriteAsync () { var buffer = new byte[(int) chained.Length]; @@ -388,7 +388,7 @@ public void TestChainedHeadersAndContent () var entity = MimeEntity.Load (chained, true) as TextPart; - Assert.AreEqual ("Hello, world!\r\n", entity.Text); + Assert.AreEqual ("Hello, world!" + Environment.NewLine, entity.Text); } } diff --git a/UnitTests/IO/FilteredStreamTests.cs b/UnitTests/IO/FilteredStreamTests.cs index 44bfee6388..34ebd682c6 100644 --- a/UnitTests/IO/FilteredStreamTests.cs +++ b/UnitTests/IO/FilteredStreamTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Threading.Tasks; using NUnit.Framework; @@ -37,6 +38,8 @@ namespace UnitTests.IO { [TestFixture] public class FilteredStreamTests { + static readonly string DataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "encoders"); + [Test] public void TestCanReadWriteSeekTimeout () { @@ -95,11 +98,11 @@ public void TestGetSetTimeouts () public void TestRead () { using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.jpg"))) file.CopyTo (original, 4096); using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.b64"))) { using (var filtered = new FilteredStream (file)) { filtered.Add (DecoderFilter.Create (ContentEncoding.Base64)); filtered.CopyTo (decoded, 4096); @@ -119,14 +122,14 @@ public void TestRead () } [Test] - public async void TestReadAsync () + public async Task TestReadAsync () { using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.jpg"))) file.CopyTo (original, 4096); using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.b64"))) { using (var filtered = new FilteredStream (file)) { filtered.Add (DecoderFilter.Create (ContentEncoding.Base64)); await filtered.CopyToAsync (decoded, 4096); @@ -149,11 +152,11 @@ public async void TestReadAsync () public void TestWrite () { using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.jpg"))) file.CopyTo (original, 4096); using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.b64"))) { using (var filtered = new FilteredStream (decoded)) { filtered.Add (DecoderFilter.Create (ContentEncoding.Base64)); file.CopyTo (filtered, 4096); @@ -174,14 +177,14 @@ public void TestWrite () } [Test] - public async void TestWriteAsync () + public async Task TestWriteAsync () { using (var original = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.jpg")) + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.jpg"))) file.CopyTo (original, 4096); using (var decoded = new MemoryStream ()) { - using (var file = File.OpenRead ("../../TestData/encoders/photo.b64")) { + using (var file = File.OpenRead (Path.Combine (DataDir, "photo.b64"))) { using (var filtered = new FilteredStream (decoded)) { filtered.Add (DecoderFilter.Create (ContentEncoding.Base64)); await file.CopyToAsync (filtered, 4096); diff --git a/UnitTests/IO/Filters/FilterTests.cs b/UnitTests/IO/Filters/FilterTests.cs index b37b7d4ed4..a45539fc47 100644 --- a/UnitTests/IO/Filters/FilterTests.cs +++ b/UnitTests/IO/Filters/FilterTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -206,6 +206,30 @@ public void TestBestEncodingFilter () Assert.AreEqual (ContentEncoding.QuotedPrintable, encoding, "French (long lines) no constraint."); } } + + filter.Reset (); + + // Test 78 character line length with CRLF + using (var stream = new MemoryStream ()) { + using (var filtered = new FilteredStream (stream)) { + var buffer = Encoding.ASCII.GetBytes ("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\r\nabc\r\n"); + ContentEncoding encoding; + + filtered.Add (filter); + + filtered.Write (buffer, 0, buffer.Length); + filtered.Flush (); + + encoding = filter.GetBestEncoding (EncodingConstraint.SevenBit, 78); + Assert.AreEqual (ContentEncoding.SevenBit, encoding, "78-character line; 7bit constraint."); + + encoding = filter.GetBestEncoding (EncodingConstraint.EightBit, 78); + Assert.AreEqual (ContentEncoding.SevenBit, encoding, "78-character line; 8bit constraint."); + + encoding = filter.GetBestEncoding (EncodingConstraint.None, 78); + Assert.AreEqual (ContentEncoding.SevenBit, encoding, "78-character line; no constraint."); + } + } } [Test] diff --git a/UnitTests/IO/MeasuringStreamTests.cs b/UnitTests/IO/MeasuringStreamTests.cs index 627c5cdaa9..8e8543681e 100644 --- a/UnitTests/IO/MeasuringStreamTests.cs +++ b/UnitTests/IO/MeasuringStreamTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Threading.Tasks; using NUnit.Framework; @@ -78,7 +79,7 @@ public void TestWrite () } [Test] - public async void TestWriteAsync () + public async Task TestWriteAsync () { var buffer = new byte[1099]; diff --git a/UnitTests/IO/MemoryBlockStreamTests.cs b/UnitTests/IO/MemoryBlockStreamTests.cs index 099ae44d93..e814cb64e9 100644 --- a/UnitTests/IO/MemoryBlockStreamTests.cs +++ b/UnitTests/IO/MemoryBlockStreamTests.cs @@ -1,9 +1,9 @@ -// +// // MemoryBlockStreamTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Threading.Tasks; using NUnit.Framework; @@ -33,7 +34,7 @@ namespace UnitTests.IO { [TestFixture] - public class MemoryBlockStreamTests + public class MemoryBlockStreamTests : IDisposable { MemoryBlockStream blocks; MemoryStream master; @@ -66,8 +67,7 @@ public MemoryBlockStreamTests () blocks.Seek (0, SeekOrigin.Begin); } - [TestFixtureTearDown] - public void TearDown () + public void Dispose () { blocks.Dispose (); master.Dispose (); @@ -117,7 +117,7 @@ public void TestRead () } [Test] - public async void TestReadAsync () + public async Task TestReadAsync () { blocks.Position = 0; master.Position = 0; @@ -157,7 +157,7 @@ public void TestWrite () } [Test] - public async void TestWriteAsync () + public async Task TestWriteAsync () { var bytes = new byte[9 * 1024]; int position = 0; @@ -195,7 +195,7 @@ void AssertSeekResults () public void TestSeek () { for (int attempt = 0; attempt < 10; attempt++) { - long offset = random.Next () % master.Length; + long offset = random.Next (1, (int) master.Length); long expected = master.Seek (offset, SeekOrigin.Begin); long actual = blocks.Seek (offset, SeekOrigin.Begin); diff --git a/UnitTests/IO/ReadOneByteStream.cs b/UnitTests/IO/ReadOneByteStream.cs index b5eae7f286..c6a9222493 100644 --- a/UnitTests/IO/ReadOneByteStream.cs +++ b/UnitTests/IO/ReadOneByteStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/IO/TimeoutStream.cs b/UnitTests/IO/TimeoutStream.cs index 90e0f27f8b..cb0dc72c73 100644 --- a/UnitTests/IO/TimeoutStream.cs +++ b/UnitTests/IO/TimeoutStream.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/InternetAddressListTests.cs b/UnitTests/InternetAddressListTests.cs index 091444194d..141a3a0cbb 100644 --- a/UnitTests/InternetAddressListTests.cs +++ b/UnitTests/InternetAddressListTests.cs @@ -1,9 +1,9 @@ -// +// // InternetAddressListTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,10 +26,12 @@ using System; using System.Text; +using System.Collections.Generic; using NUnit.Framework; using MimeKit; +using MimeKit.Utils; namespace UnitTests { [TestFixture] @@ -144,27 +146,32 @@ static void AssertTryParseFails (string text) { var buffer = Encoding.UTF8.GetBytes (text); InternetAddressList result; + bool success; try { - Assert.IsFalse (InternetAddressList.TryParse (text, out result), "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); + success = InternetAddressList.TryParse (text, out result); + Assert.IsFalse (success, "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); } catch (Exception ex) { Assert.Fail ("InternetAddressList.TryParse() should not throw an exception: {0}", ex); } try { - Assert.IsFalse (InternetAddressList.TryParse (buffer, out result), "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); + success = InternetAddressList.TryParse (buffer, out result); + Assert.IsFalse (success, "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); } catch (Exception ex) { Assert.Fail ("InternetAddressList.TryParse() should not throw an exception: {0}", ex); } try { - Assert.IsFalse (InternetAddressList.TryParse (buffer, 0, out result), "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); + success = InternetAddressList.TryParse (buffer, 0, out result); + Assert.IsFalse (success, "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); } catch (Exception ex) { Assert.Fail ("InternetAddressList.TryParse() should not throw an exception: {0}", ex); } try { - Assert.IsFalse (InternetAddressList.TryParse (buffer, 0, buffer.Length, out result), "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); + success = InternetAddressList.TryParse (buffer, 0, buffer.Length, out result); + Assert.IsFalse (success, "InternetAddressList.TryParse() should fail to parse \"{0}\".", text); } catch (Exception ex) { Assert.Fail ("InternetAddressList.TryParse() should not throw an exception: {0}", ex); } @@ -223,6 +230,13 @@ public void TestParseWhiteSpace () AssertParseAndTryParseFail (" "); } + [Test] + public void TestParseNameLessThan () + { + AssertParseFails ("\"Name\" <"); + AssertTryParse ("\"Name\" <", "", new InternetAddressList ()); + } + [Test] public void TestSimpleAddrSpec () { @@ -416,7 +430,8 @@ public void TestMailboxWithDotsInTheName () [Test] public void TestMailboxWith8bitName () { - const string encoded = "Patrik =?iso-8859-1?b?RqVkbHRzdHKldm0=?= "; + //const string encoded = "Patrik =?iso-8859-1?b?RqVkbHRzdHKldm0=?= "; + const string encoded = "Patrik =?utf-8?b?RsKlZGx0c3RywqV2bQ==?= "; const string text = "Patrik F¥dltstr¥vm "; var expected = new InternetAddressList (); @@ -490,10 +505,14 @@ public void TestEncodingMailboxWithReallyLongWord () const string expected = "=?us-ascii?q?reeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaallllllllllll?=\n =?us-ascii?q?llllllllllllllllllllllllllllllllllllllllllly?= long word\n\t"; const string name = "reeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaallllllllllllllllllllllllllllllllllllllllllllllllllllllly long word"; var mailbox = new MailboxAddress (name, "really.long.word@example.com"); + var options = FormatOptions.Default.Clone (); var list = new InternetAddressList (); list.Add (mailbox); - var actual = list.ToString (UnixFormatOptions, true); + options.NewLineFormat = NewLineFormat.Unix; + options.AllowMixedHeaderCharsets = true; + + var actual = list.ToString (options, true); Assert.AreEqual (expected, actual, "Encoding really long mailbox did not match expected result: {0}", expected); Assert.IsTrue (InternetAddressList.TryParse (actual, out list), "Failed to parse really long mailbox"); @@ -551,6 +570,43 @@ public void TestEncodingSimpleAddressList () Assert.AreEqual (expectedEncoded, encoded, "Encoded value does not match the expected result: {0}", display); } + [Test] + public void TestEncodingLongNameMixedQuotingAndEncoding () + { + const string name = "Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx für xxxxxxxxxxxxx xxxx"; + const string encodedNameLatin1 = "\"Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx\" =?iso-8859-1?b?Zvxy?= xxxxxxxxxxxxx xxxx"; + const string encodedNameUnicode = "\"Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx\" =?utf-8?b?ZsO8cg==?= xxxxxxxxxxxxx xxxx"; + const string encodedMailbox = "\"Dr. xxxxxxxxxx xxxxx | xxxxxx.xxxxxxx\" =?iso-8859-1?b?Zvxy?= xxxxxxxxxxxxx\n xxxx "; + const string address = "x.xxxxx@xxxxxxx-xxxxxx.xx"; + var options = FormatOptions.Default.Clone (); + + options.NewLineFormat = NewLineFormat.Unix; + options.AllowMixedHeaderCharsets = true; + + var buffer = Rfc2047.EncodePhrase (options, Encoding.UTF8, name); + var result = Encoding.UTF8.GetString (buffer); + + Assert.AreEqual (encodedNameLatin1, result); + + var mailbox = new MailboxAddress (name, address); + var list = new InternetAddressList (); + + list.Add (mailbox); + + result = list.ToString (options, true); + + Assert.AreEqual (encodedMailbox, result); + + // Now disable smart encoding + + options.AllowMixedHeaderCharsets = false; + + buffer = Rfc2047.EncodePhrase (options, Encoding.UTF8, name); + result = Encoding.UTF8.GetString (buffer); + + Assert.AreEqual (encodedNameUnicode, result); + } + [Test] public void TestDecodedMailboxHasCorrectCharsetEncoding () { @@ -605,6 +661,84 @@ public void TestInternationalEmailAddresses () } } + [Test] + public void TestBasicFunctionality () + { + var user0 = new MailboxAddress ("Name Zero", "user0@address.com"); + var user1 = new MailboxAddress ("Name One", "user1@address.com"); + var user2 = new MailboxAddress ("Name Two", "user2@address.com"); + var list = new InternetAddressList (); + + Assert.IsFalse (list.IsReadOnly, "IsReadOnly"); + + list.Add (user1); + list.Add (user2); + + Assert.AreEqual (2, list.Count, "Count"); + Assert.IsTrue (list.Contains (user1), "Contains"); + Assert.IsTrue (list.Contains (user2), "Contains"); + Assert.IsFalse (list.Contains (new MailboxAddress ("Unknown", "unknown@address.com")), "Contains"); + Assert.AreEqual (0, list.IndexOf (user1), "IndexOf"); + Assert.AreEqual (1, list.IndexOf (user2), "IndexOf"); + + list.Insert (0, user0); + Assert.AreEqual (3, list.Count, "Count"); + Assert.IsTrue (list.Contains (user0), "Contains"); + Assert.AreEqual (0, list.IndexOf (user0), "IndexOf"); + Assert.AreEqual (user0.Name, list[0].Name, "Name"); + + list.RemoveAt (0); + Assert.AreEqual (2, list.Count, "Count"); + Assert.IsFalse (list.Contains (user0), "Contains"); + Assert.AreEqual (-1, list.IndexOf (user0), "IndexOf"); + + Assert.IsFalse (list.Remove (user0), "Remove"); + + Assert.IsTrue (list.Remove (user2), "Remove"); + Assert.AreEqual (1, list.Count, "Count"); + Assert.IsFalse (list.Contains (user2), "Contains"); + Assert.AreEqual (-1, list.IndexOf (user0), "IndexOf"); + + list[0] = user0; + Assert.AreEqual (1, list.Count, "Count"); + Assert.IsTrue (list.Contains (user0), "Contains"); + Assert.IsFalse (list.Contains (user1), "Contains"); + Assert.AreEqual (0, list.IndexOf (user0), "IndexOf"); + Assert.AreEqual (-1, list.IndexOf (user1), "IndexOf"); + } + + [Test] + public void TestEnumeratingMailboxes () + { + var innerGroup = new GroupAddress ("Inner"); + innerGroup.Members.Add (new MailboxAddress ("Inner1", "inner1@address.com")); + innerGroup.Members.Add (new MailboxAddress ("Inner2", "inner2@address.com")); + + var outerGroup = new GroupAddress ("Outer"); + outerGroup.Members.Add (new MailboxAddress ("Outer1", "outer1@address.com")); + outerGroup.Members.Add (innerGroup); + outerGroup.Members.Add (new MailboxAddress ("Outer2", "outer2@address.com")); + + var list = new InternetAddressList (); + list.Add (new MailboxAddress ("Before", "before@address.com")); + list.Add (outerGroup); + list.Add (new MailboxAddress ("After", "after@address.com")); + + var expected = new List (); + expected.Add (list[0]); + expected.Add (outerGroup.Members[0]); + expected.Add (innerGroup.Members[0]); + expected.Add (innerGroup.Members[1]); + expected.Add (outerGroup.Members[2]); + expected.Add (list[2]); + int i = 0; + + foreach (var mailbox in list.Mailboxes) { + Assert.AreEqual (expected[i], mailbox, "Mailbox #{0}", i); + i++; + } + } + [Test] public void TestEquality () { @@ -621,7 +755,6 @@ public void TestEquality () var list2 = new InternetAddressList (); - list2.Add (new MailboxAddress ("Chandler", "chandler@friends.com")); list2.Add (new GroupAddress ("Local recipients", new InternetAddress[] { new MailboxAddress ("", "phil"), new MailboxAddress ("", "joe"), @@ -629,8 +762,14 @@ public void TestEquality () new MailboxAddress ("", "bob"), })); list2.Add (new MailboxAddress ("Joey", "joey@friends.com")); + list2.Add (new MailboxAddress ("Chandler", "chandler@friends.com")); + Assert.IsFalse (list1.Equals (null), "Equals null"); + Assert.IsFalse (list1.Equals (new InternetAddressList ()), "Equals empty list"); Assert.IsTrue (list1.Equals (list2), "The 2 lists should be equal."); + + Assert.IsTrue (((object) list1).Equals ((object) list2), "Equals(object)"); + Assert.AreEqual (list1.GetHashCode (), list2.GetHashCode (), "GetHashCode()"); } [Test] diff --git a/UnitTests/InternetAddressTests.cs b/UnitTests/InternetAddressTests.cs index e96f9147bf..11cec0048a 100644 --- a/UnitTests/InternetAddressTests.cs +++ b/UnitTests/InternetAddressTests.cs @@ -1,9 +1,9 @@ -// +// // InternetAddressTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -216,6 +216,16 @@ public void TestParseMailboxWithIncompleteCommentAfterAddrspec () AssertParseFailure (text, false, tokenIndex, errorIndex); } + [Test] + public void TestParseMailboxWithIncompleteCommentAfterDomainLiteralAddrspec () + { + const string text = "jeff@[127.0.0.1] (incomplete comment"; + int tokenIndex = text.IndexOf ('('); + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + [Test] public void TestParseMailboxWithIncompleteCommentAfterAddress () { @@ -236,6 +246,64 @@ public void TestParseIncompleteAddrspec () AssertParseFailure (text, false, tokenIndex, errorIndex); } + [Test] + public void TestParseIncompleteRoutedMailboxAt () + { + const string text = "Name <@"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteRoutedMailbox () + { + const string text = "Name <@route:"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteRoutedMailboxSpace () + { + const string text = "Name <@route: "; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteCommentInRoute () + { + const string text = "Name <@route,(comment"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseInvalidRouteInMailbox () + { + const string text = "Name <@route,invalid:user@example.com>"; + const int tokenIndex = 0; + int errorIndex = text.IndexOf (',') + 1; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseMailboxWithInternationalRoute () + { + const string text = "User Name <@route,@伊昭傑@郵件.商務:user@domain.com>"; + + AssertParse (text); + } + [Test] public void TestParseAddrspecNoAtDomain () { @@ -244,6 +312,37 @@ public void TestParseAddrspecNoAtDomain () AssertParse (text); } + [Test] + public void TestParseAddrspecNoAtDomainGreaterThan () + { + const string text = "jeff>"; + + AssertParse (text); + } + + [Test] + public void TestParseAddrspecNoAtDomainWithIncompleteComment () + { + const string text = "jeff (Jeffrey Stedfast"; + int tokenIndex = 5; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseAddrspecNoAtDomainWithComment () + { + const string text = "jeff (Jeffrey Stedfast)"; + + AssertParse (text); + + var mailbox = MailboxAddress.Parse (text); + + Assert.AreEqual ("Jeffrey Stedfast", mailbox.Name); + Assert.AreEqual ("jeff", mailbox.Address); + } + [Test] public void TestParseAddrspec () { @@ -282,13 +381,14 @@ public void TestParseMailboxWithUnquotedCommaInName () // this should fail when we allow mailbox addresses w/o a domain var options = ParserOptions.Default.Clone (); - options.AllowAddressesWithoutDomain = true; + options.AllowUnquotedCommasInAddresses = false; + options.AllowAddressesWithoutDomain = false; try { addr = InternetAddress.Parse (options, text); - Assert.Fail ("Should not have parsed \"{0}\" with AllowAddressesWithoutDomain = true", text); + Assert.Fail ("Should not have parsed \"{0}\" with AllowUnquotedCommasInAddresses = false", text); } catch (ParseException pex) { - Assert.AreEqual (text.IndexOf (','), pex.TokenIndex, "TokenIndex"); + Assert.AreEqual (0, pex.TokenIndex, "TokenIndex"); Assert.AreEqual (text.IndexOf (','), pex.ErrorIndex, "ErrorIndex"); } catch (Exception ex) { Assert.Fail ("Should not have thrown {0}", ex.GetType ().Name); @@ -424,8 +524,16 @@ public void TestParseMailboxWithAddrspecAsUnquotedName () #endregion + [Test] + public void TestParseMailboxWithSquareBracketsInDisplayName () + { + const string text = "[Invalid Sender] "; + + AssertParse (text); + } + #region TestLegacyEmailAddress - TestCaseData[] LegacyAddressNotCompliantWithRFC () + static TestCaseData[] LegacyAddressNotCompliantWithRFC() { var addressList = new TestCaseData[] { @@ -544,7 +652,7 @@ TestCaseData[] LegacyAddressNotCompliantWithRFC () return addressList; } - [TestCaseSource ("LegacyAddressNotCompliantWithRFC")] + [TestCaseSource (nameof(LegacyAddressNotCompliantWithRFC))] public void TestLegacyEmailAddress (string address) { string text = address; diff --git a/UnitTests/MailboxAddressTests.cs b/UnitTests/MailboxAddressTests.cs index d6aa836d12..b3ecda72f4 100644 --- a/UnitTests/MailboxAddressTests.cs +++ b/UnitTests/MailboxAddressTests.cs @@ -1,9 +1,9 @@ -// +// // MailboxAddressTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,12 +26,14 @@ using System; using System.Text; +using System.Globalization; using System.Collections.Generic; using NUnit.Framework; using MimeKit; using MimeKit.Cryptography; +using MimeKit.Utils; namespace UnitTests { [TestFixture] @@ -100,6 +102,13 @@ public void ArgumentExceptionTests () Assert.Throws (() => new SecureMailboxAddress (null, "ffff")); Assert.Throws (() => new SecureMailboxAddress ("johnny@example.com", null)); Assert.Throws (() => new SecureMailboxAddress ("johnny@example.com", "not hex encoded")); + + Assert.DoesNotThrow (() => new SecureMailboxAddress ("user@domain.com", "ffff")); + Assert.DoesNotThrow (() => new SecureMailboxAddress ("Mailbox Address", "user@domain.com", "ffff")); + Assert.DoesNotThrow (() => new SecureMailboxAddress (Encoding.UTF8, "Mailbox Address", "user@domain.com", "ffff")); + Assert.DoesNotThrow (() => new SecureMailboxAddress (new[] { "route1", "route2", "route3" }, "user@domain.com", "ffff")); + Assert.DoesNotThrow (() => new SecureMailboxAddress ("Routed Address", new[] { "route1", "route2", "route3" }, "user@domain.com", "ffff")); + Assert.DoesNotThrow (() => new SecureMailboxAddress (Encoding.UTF8, "Routed Address", new[] { "route1", "route2", "route3" }, "user@domain.com", "ffff")); } static void AssertParseFailure (string text, bool result, int tokenIndex, int errorIndex, RfcComplianceMode mode = RfcComplianceMode.Loose) @@ -286,6 +295,16 @@ public void TestParseMailboxWithIncompleteCommentAfterAddrspec () AssertParseFailure (text, false, tokenIndex, errorIndex); } + [Test] + public void TestParseMailboxWithIncompleteCommentAfterDomainLiteralAddrspec () + { + const string text = "jeff@[127.0.0.1] (incomplete comment"; + int tokenIndex = text.IndexOf ('('); + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + [Test] public void TestParseMailboxWithIncompleteCommentAfterAddress () { @@ -306,6 +325,64 @@ public void TestParseIncompleteAddrspec () AssertParseFailure (text, false, tokenIndex, errorIndex); } + [Test] + public void TestParseIncompleteRoutedMailboxAt () + { + const string text = "Name <@"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteRoutedMailbox () + { + const string text = "Name <@route:"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteRoutedMailboxSpace () + { + const string text = "Name <@route: "; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseIncompleteCommentInRoute () + { + const string text = "Name <@route,(comment"; + const int tokenIndex = 0; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseInvalidRouteInMailbox () + { + const string text = "Name <@route,invalid:user@example.com>"; + const int tokenIndex = 0; + int errorIndex = text.IndexOf (',') + 1; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseMailboxWithInternationalRoute () + { + const string text = "User Name <@route,@伊昭傑@郵件.商務:user@domain.com>"; + + AssertParse (text); + } + [Test] public void TestParseIdnAddress () { @@ -325,6 +402,40 @@ public void TestParseAddrspecNoAtDomain () AssertParse (text); } + [Test] + public void TestParseAddrspecNoAtDomainGreaterThan () + { + const string text = "jeff>"; + int tokenIndex = 0; + int errorIndex = text.Length - 1; + + AssertParseFailure (text, false, tokenIndex, errorIndex, RfcComplianceMode.Strict); + AssertParse (text); + } + + [Test] + public void TestParseAddrspecNoAtDomainWithIncompleteComment () + { + const string text = "jeff (Jeffrey Stedfast"; + int tokenIndex = 5; + int errorIndex = text.Length; + + AssertParseFailure (text, false, tokenIndex, errorIndex); + } + + [Test] + public void TestParseAddrspecNoAtDomainWithComment () + { + const string text = "jeff (Jeffrey Stedfast)"; + + AssertParse (text); + + var mailbox = MailboxAddress.Parse (text); + + Assert.AreEqual ("Jeffrey Stedfast", mailbox.Name); + Assert.AreEqual ("jeff", mailbox.Address); + } + [Test] public void TestParseAddrspec () { @@ -363,13 +474,14 @@ public void TestParseMailboxWithUnquotedCommaInName () // this should fail when we allow mailbox addresses w/o a domain var options = ParserOptions.Default.Clone (); - options.AllowAddressesWithoutDomain = true; + options.AllowUnquotedCommasInAddresses = false; + options.AllowAddressesWithoutDomain = false; try { mailbox = MailboxAddress.Parse (options, text); - Assert.Fail ("Should not have parsed \"{0}\" with AllowAddressesWithoutDomain = true", text); + Assert.Fail ("Should not have parsed \"{0}\" with AllowUnquotedCommasInAddresses = false", text); } catch (ParseException pex) { - Assert.AreEqual (text.IndexOf (','), pex.TokenIndex, "TokenIndex"); + Assert.AreEqual (0, pex.TokenIndex, "TokenIndex"); Assert.AreEqual (text.IndexOf (','), pex.ErrorIndex, "ErrorIndex"); } catch (Exception ex) { Assert.Fail ("Should not have thrown {0}", ex.GetType ().Name); @@ -452,35 +564,85 @@ public void TestParseGroupNameColon () AssertParseFailure (text, false, tokenIndex, errorIndex); } + [Test] + public void TestGetAddress () + { + var idn = new IdnMapping (); + MailboxAddress mailbox; + + mailbox = new MailboxAddress ("Unit Test", "點看@domain.com"); + Assert.AreEqual ("點看@domain.com", mailbox.GetAddress (false), "IDN-decode #1"); + Assert.AreEqual (idn.GetAscii ("點看") + "@domain.com", mailbox.GetAddress (true), "IDN-encode #1"); + + mailbox = new MailboxAddress ("Unit Test", idn.GetAscii ("點看") + "@domain.com"); + Assert.AreEqual ("點看@domain.com", mailbox.GetAddress (false), "IDN-decode #2"); + Assert.AreEqual (idn.GetAscii ("點看") + "@domain.com", mailbox.GetAddress (true), "IDN-encode #2"); + + mailbox = new MailboxAddress ("Unit Test", "user@名がドメイン.com"); + Assert.AreEqual ("user@名がドメイン.com", mailbox.GetAddress (false), "IDN-decode #3"); + Assert.AreEqual ("user@" + idn.GetAscii ("名がドメイン.com"), mailbox.GetAddress (true), "IDN-encode #3"); + + mailbox = new MailboxAddress ("Unit Test", "user@" + idn.GetAscii ("名がドメイン.com")); + Assert.AreEqual ("user@名がドメイン.com", mailbox.GetAddress (false), "IDN-decode #4"); + Assert.AreEqual ("user@" + idn.GetAscii ("名がドメイン.com"), mailbox.GetAddress (true), "IDN-encode #4"); + + mailbox = new MailboxAddress ("Unit Test", "點看@名がドメイン.com"); + Assert.AreEqual ("點看@名がドメイン.com", mailbox.GetAddress (false), "IDN-decode #5"); + Assert.AreEqual (idn.GetAscii ("點看") + "@" + idn.GetAscii ("名がドメイン.com"), mailbox.GetAddress (true), "IDN-encode #5"); + + mailbox = new MailboxAddress ("Unit Test", idn.GetAscii ("點看") + "@" + idn.GetAscii ("名がドメイン.com")); + Assert.AreEqual ("點看@名がドメイン.com", mailbox.GetAddress (false), "IDN-decode #6"); + Assert.AreEqual (idn.GetAscii ("點看") + "@" + idn.GetAscii ("名がドメイン.com"), mailbox.GetAddress (true), "IDN-encode #6"); + } + [Test] public void TestIsInternational () { - var mailbox = new MailboxAddress ("Kristoffer Brånemyr", "brånemyr@swipenet.se"); - const string expected = "Kristoffer Brånemyr "; var options = FormatOptions.Default.Clone (); + options.International = true; + var idn = new IdnMapping (); + MailboxAddress mailbox; string encoded; - options.International = true; + // Test IsInternational local-parts + mailbox = new MailboxAddress ("Unit Test", "點看@domain.com"); + Assert.IsTrue (mailbox.IsInternational, "IsInternational local-part"); + encoded = mailbox.ToString (options, true); + Assert.AreEqual ("Unit Test <點看@domain.com>", encoded, "ToString local-part"); + // Test IsInternational IDN-encoded local-parts + mailbox = new MailboxAddress ("Unit Test", idn.GetAscii ("點看") + "@domain.com"); + Assert.IsTrue (mailbox.IsInternational, "IsInternational IDN-encoded local-part"); encoded = mailbox.ToString (options, true); - Assert.AreEqual (expected, encoded, "ToString"); + Assert.AreEqual ("Unit Test <點看@domain.com>", encoded, "ToString IDN-encoded local-part"); - Assert.IsTrue (mailbox.IsInternational, "IsInternational"); + // Test IsInternational domain + mailbox = new MailboxAddress ("Unit Test", "user@名がドメイン.com"); + Assert.IsTrue (mailbox.IsInternational, "IsInternational domain"); + encoded = mailbox.ToString (options, true); + Assert.AreEqual ("Unit Test ", encoded, "ToString domain"); - mailbox = new MailboxAddress ("Kristoffer Brånemyr", "ztion@swipenet.se"); + // Test IsInternational IDN-encoded domain + mailbox = new MailboxAddress ("Unit Test", "user@" + idn.GetAscii ("名がドメイン.com")); + Assert.IsTrue (mailbox.IsInternational, "IsInternational IDN-encoded domain"); + encoded = mailbox.ToString (options, true); + Assert.AreEqual ("Unit Test ", encoded, "ToString IDN-encoded domain"); + // Test IsInternational routes + mailbox = new MailboxAddress ("Unit Test", "user@domain.com"); Assert.IsFalse (mailbox.IsInternational, "IsInternational"); - - mailbox.Route.Add ("brånemyr"); - - Assert.IsTrue (mailbox.IsInternational, "IsInternational"); + mailbox.Route.Add ("route1"); // non-international route + mailbox.Route.Add ("名がドメイン.com"); // international route + Assert.IsTrue (mailbox.IsInternational, "IsInternational route"); + encoded = mailbox.ToString (options, true); + Assert.AreEqual ("Unit Test <@route1,@名がドメイン.com:user@domain.com>", encoded, "ToString route"); } [Test] public void TestIdnEncoding () { - //const string userAscii = "xn--c1yn36f@domain"; - //const string userUnicode = "點看@domain"; + const string userAscii = "xn--c1yn36f@domain.com"; + const string userUnicode = "點看@domain.com"; const string domainAscii = "user@xn--v8jxj3d1dzdz08w.com"; const string domainUnicode = "user@名がドメイン.com"; string encoded; @@ -491,11 +653,11 @@ public void TestIdnEncoding () encoded = MailboxAddress.DecodeAddrspec (domainAscii); Assert.AreEqual (domainUnicode, encoded, "Domain (Decode)"); - //encoded = MailboxAddress.EncodeAddrspec (userUnicode); - //Assert.AreEqual (userAscii, encoded, "Local-part (Encode)"); + encoded = MailboxAddress.EncodeAddrspec (userUnicode); + Assert.AreEqual (userAscii, encoded, "Local-part (Encode)"); - //encoded = MailboxAddress.DecodeAddrspec (userAscii); - //Assert.AreEqual (userUnicode, encoded, "Local-part (Decode)"); + encoded = MailboxAddress.DecodeAddrspec (userAscii); + Assert.AreEqual (userUnicode, encoded, "Local-part (Decode)"); } [Test] @@ -524,6 +686,22 @@ public void TestRoutedMailbox () Assert.AreEqual (expectedNoName, encoded, "ToString mailbox does not match after setting Name to null."); } + [Test] + public void TestInternationalRoutedMailbox () + { + const string expectedIdn = "User Name <@route,@xn--@-216a8b89fj88ctw7c.xn--lhr59c:user@domain.com>"; + const string expected = "User Name <@route,@伊昭傑@郵件.商務:user@domain.com>"; + var route = new[] { "route", "伊昭傑@郵件.商務" }; + var mailbox = new MailboxAddress ("User Name", route, "user@domain.com"); + var options = FormatOptions.Default.Clone (); + + Assert.AreEqual (expectedIdn, mailbox.ToString (options, true)); + + options.International = true; + + Assert.AreEqual (expected, mailbox.ToString (options, true)); + } + #region Rfc7103 [Test] @@ -583,10 +761,90 @@ public void TestParseMailboxWithAddrspecAsUnquotedName () AssertParseFailure (text, false, 0, errorIndex, RfcComplianceMode.Strict); } + [Test] + public void TestParseMailboxWithLatin1EncodedAddrspec () + { + const string text = "Name <æøå@example.com>"; + var buffer = CharsetUtils.Latin1.GetBytes (text); + MailboxAddress mailbox; + + try { + Assert.IsTrue (MailboxAddress.TryParse (buffer, out mailbox), "MailboxAddress.TryParse(byte[]) should succeed."); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.TryParse(byte[]) should not throw an exception: {0}", ex); + } + + try { + Assert.IsTrue (MailboxAddress.TryParse (buffer, 0, out mailbox), "MailboxAddress.TryParse(byte[], int) should succeed."); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.TryParse(byte[], int) should not throw an exception: {0}", ex); + } + + try { + Assert.IsTrue (MailboxAddress.TryParse (buffer, 0, buffer.Length, out mailbox), "MailboxAddress.TryParse(byte[], int, int) should succeed."); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.TryParse(byte[], int, int) should not throw an exception: {0}", ex); + } + + try { + mailbox = MailboxAddress.Parse (buffer); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.Parse(string) should not throw an exception: {0}", ex); + } + + try { + mailbox = MailboxAddress.Parse (buffer, 0); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.Parse(string) should not throw an exception: {0}", ex); + } + + try { + mailbox = MailboxAddress.Parse (buffer, 0, buffer.Length); + } catch (Exception ex) { + Assert.Fail ("MailboxAddress.Parse(string) should not throw an exception: {0}", ex); + } + } + #endregion + [Test] + public void TestParseMailboxWithSquareBracketsInDisplayName () + { + const string text = "[Invalid Sender] "; + + AssertParse (text); + + AssertParseFailure (text, false, 0, 0, RfcComplianceMode.Strict); + } + + [Test] + public void TestParseMailboxWithSquareBracketsAnd8BitTextInDisplayName () + { + const string text = "Tom Doe [Cörp Öne] "; + + AssertParse (text); + + AssertParseFailure (text, false, 0, 8, RfcComplianceMode.Strict); + } + + [Test] + public void TestParseAddrspecWithUnicodeLocalPart () + { + const string text = "test.täst@test.net"; + + AssertParse (text); + } + + [Test] + public void TestParseAddrspecWitheroWidthSpace () + { + const string text = "\u200Btest@test.co.uk"; + + AssertParse (text); + } + #region TestLegacyEmailAddress - TestCaseData[] LegacyAddressNotCompliantWithRFC () + static TestCaseData[] LegacyAddressNotCompliantWithRFC () { var addressList = new TestCaseData[] { @@ -705,7 +963,7 @@ TestCaseData[] LegacyAddressNotCompliantWithRFC () return addressList; } - [TestCaseSource ("LegacyAddressNotCompliantWithRFC")] + [TestCaseSource (nameof(LegacyAddressNotCompliantWithRFC))] public void TestLegacyEmailAddress (string address) { string text = address; diff --git a/UnitTests/MessageDeliveryStatusTests.cs b/UnitTests/MessageDeliveryStatusTests.cs index 7762e85a37..21e497603a 100644 --- a/UnitTests/MessageDeliveryStatusTests.cs +++ b/UnitTests/MessageDeliveryStatusTests.cs @@ -1,9 +1,9 @@ -// +// // MessageDeliveryStatusTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ public void TestArgumentExceptions () [Test] public void TestMimeParser () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "delivery-status.txt")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "delivery-status.txt")); Assert.IsInstanceOf (message.Body, "Expected top-level body part to be a multipart/report."); diff --git a/UnitTests/MessageDispositionNotificiationTests.cs b/UnitTests/MessageDispositionNotificiationTests.cs index aa6af4c3ac..c94d7f9343 100644 --- a/UnitTests/MessageDispositionNotificiationTests.cs +++ b/UnitTests/MessageDispositionNotificiationTests.cs @@ -1,9 +1,9 @@ -// +// // MessageDispositionNotificiationTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -47,7 +47,7 @@ public void TestArgumentExceptions () [Test] public void TestMimeParser () { - var message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "disposition-notification.txt")); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "disposition-notification.txt")); Assert.IsInstanceOf (message.Body, "Expected top-level body part to be a multipart/report."); diff --git a/UnitTests/MessageIdListTests.cs b/UnitTests/MessageIdListTests.cs index 862005c864..db91b5ae72 100644 --- a/UnitTests/MessageIdListTests.cs +++ b/UnitTests/MessageIdListTests.cs @@ -1,9 +1,9 @@ -// +// // MessageIdListTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/MessagePartialTests.cs b/UnitTests/MessagePartialTests.cs index e61e57f716..47030f6b2a 100644 --- a/UnitTests/MessagePartialTests.cs +++ b/UnitTests/MessagePartialTests.cs @@ -1,9 +1,9 @@ -// +// // MessagePartialTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -59,13 +59,38 @@ public void TestArgumentExceptions () Assert.Throws (() => MessagePartial.Split (message, 0).ToList ()); } + static void AssertRawMessageStreams (MimeMessage expected, MimeMessage actual) + { + using (var stream = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + expected.WriteTo (options, stream); + + var expectedBytes = new byte[stream.Position]; + Array.Copy (stream.GetBuffer (), 0, expectedBytes, 0, (int) stream.Position); + + stream.Position = 0; + + actual.WriteTo (options, stream); + + var actualBytes = new byte[stream.Position]; + Array.Copy (stream.GetBuffer (), 0, actualBytes, 0, (int) stream.Position); + + Assert.AreEqual (expectedBytes.Length, actualBytes.Length, "bytes"); + + for (int i = 0; i < expectedBytes.Length; i++) + Assert.AreEqual (expectedBytes[i], actualBytes[i], "bytes[{0}]", i); + } + } + [Test] - public void TestReassemble () + public void TestReassembleGirlOnTrainPhotoExample () { - var message0 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.0.eml")); - var message1 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.1.eml")); - var message2 = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.2.eml")); - var original = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.eml")); + var message0 = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "message-partial.0.eml")); + var message1 = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "message-partial.1.eml")); + var message2 = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "message-partial.2.eml")); + var original = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "message-partial.eml")); Assert.IsNotNull (message0, "Failed to parse message-partial.0.eml"); Assert.IsNotNull (message1, "Failed to parse message-partial.1.eml"); @@ -76,7 +101,9 @@ public void TestReassemble () Assert.IsTrue (message2.Body is MessagePartial, "The body of message-partial.2.eml is not a message/partial"); var partials = new MessagePartial[] { (MessagePartial) message0.Body, (MessagePartial) message1.Body, (MessagePartial) message2.Body }; - Assert.Throws (() => MessagePartial.Join (null, partials)); + Assert.Throws (() => MessagePartial.Join (null, message0, partials)); + Assert.Throws (() => MessagePartial.Join ((MimeMessage) null, partials)); + Assert.Throws (() => MessagePartial.Join ((ParserOptions) null, partials)); Assert.Throws (() => MessagePartial.Join (null)); var message = MessagePartial.Join (partials); @@ -92,33 +119,40 @@ public void TestReassemble () Assert.IsTrue (part.ContentType.IsMimeType ("image", "jpeg"), "Attachment is not an image/jpeg"); Assert.AreEqual ("earrings.jpg", part.FileName, "Attachment filename is not the expected value"); - using (var stream = new MemoryStream ()) { - var options = FormatOptions.Default.Clone (); - options.NewLineFormat = NewLineFormat.Unix; - - original.WriteTo (options, stream); + AssertRawMessageStreams (original, message); + } - var bytes0 = new byte[stream.Position]; - Array.Copy (stream.GetBuffer (), 0, bytes0, 0, (int) stream.Position); + [Test] + public void TestReassembleRfc2046Example () + { + var message0 = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "rfc2046.0.eml")); + var message1 = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "rfc2046.1.eml")); + var original = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "rfc2046.eml")); - stream.Position = 0; + Assert.IsNotNull (message0, "Failed to parse rfc2046.0.eml"); + Assert.IsNotNull (message1, "Failed to parse rfc2046.1.eml"); - message.WriteTo (options, stream); + Assert.IsTrue (message0.Body is MessagePartial, "The body of rfc2046.0.eml is not a message/partial"); + Assert.IsTrue (message1.Body is MessagePartial, "The body of rfc2046.1.eml is not a message/partial"); - var bytes1 = new byte[stream.Position]; - Array.Copy (stream.GetBuffer (), 0, bytes1, 0, (int) stream.Position); + var partials = new MessagePartial[] { (MessagePartial) message0.Body, (MessagePartial) message1.Body }; + Assert.Throws (() => MessagePartial.Join (null, message0, partials)); + Assert.Throws (() => MessagePartial.Join ((MimeMessage) null, partials)); + Assert.Throws (() => MessagePartial.Join ((ParserOptions) null, partials)); + Assert.Throws (() => MessagePartial.Join (null)); + var message = MessagePartial.Join (message0, partials); - Assert.AreEqual (bytes0.Length, bytes1.Length, "bytes"); + Assert.IsNotNull (message, "Failed to reconstruct the message"); + Assert.AreEqual ("Audio mail", message.Subject, "Subjects do not match"); + Assert.IsTrue (message.Body.ContentType.IsMimeType ("audio", "basic"), "Parsed message body is not audio/basic"); - for (int i = 0; i < bytes0.Length; i++) - Assert.AreEqual (bytes0[i], bytes1[i], "bytes[{0}]", i); - } + AssertRawMessageStreams (original, message); } [Test] public void TestSplit () { - var message = Load (Path.Combine ("..", "..", "TestData", "partial", "message-partial.eml")); + var message = Load (Path.Combine (TestHelper.ProjectDir, "TestData", "partial", "message-partial.eml")); var split = MessagePartial.Split (message, 1024 * 16).ToList (); var parts = new List (); @@ -131,29 +165,9 @@ public void TestSplit () Assert.AreEqual (i + 1, parts[i].Number, "Number"); } - var combined = MessagePartial.Join (parts); + var combined = MessagePartial.Join (message, parts); - using (var stream = new MemoryStream ()) { - var options = FormatOptions.Default.Clone (); - options.NewLineFormat = NewLineFormat.Unix; - - message.WriteTo (options, stream); - - var bytes0 = new byte[stream.Position]; - Array.Copy (stream.GetBuffer (), 0, bytes0, 0, (int) stream.Position); - - stream.Position = 0; - - combined.WriteTo (options, stream); - - var bytes1 = new byte[stream.Position]; - Array.Copy (stream.GetBuffer (), 0, bytes1, 0, (int) stream.Position); - - Assert.AreEqual (bytes0.Length, bytes1.Length, "bytes"); - - for (int i = 0; i < bytes0.Length; i++) - Assert.AreEqual (bytes0[i], bytes1[i], "bytes[{0}]", i); - } + AssertRawMessageStreams (message, combined); } } } diff --git a/UnitTests/MimeIteratorTests.cs b/UnitTests/MimeIteratorTests.cs new file mode 100644 index 0000000000..fa9f259d07 --- /dev/null +++ b/UnitTests/MimeIteratorTests.cs @@ -0,0 +1,194 @@ +// +// MimeIteratorTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Collections.Generic; + +using NUnit.Framework; + +using MimeKit; + +namespace UnitTests { + [TestFixture] + public class MimeIteratorTests + { + [Test] + public void TestArgumentExceptions () + { + var iter = new MimeIterator (new MimeMessage { Body = new TextPart ("plain") }); + + Assert.Throws (() => new MimeIterator (null)); + Assert.Throws (() => { var x = iter.Depth; }); + Assert.Throws (() => { var x = iter.Current; }); + Assert.Throws (() => { var x = iter.Parent; }); + Assert.Throws (() => { var x = iter.PathSpecifier; }); + Assert.Throws (() => iter.MoveTo (null)); + Assert.Throws (() => iter.MoveTo (string.Empty)); + Assert.Throws (() => iter.MoveTo ("xyz")); + } + + static MessagePart CreateImapExampleMessageRfc822 (List parents) + { + var message = new MimeMessage (); + var mixed = new Multipart ("mixed"); + var rfc822 = new MessagePart { Message = message }; + + parents.Add (rfc822); + message.Body = mixed; + + parents.Add (mixed); + mixed.Add (new TextPart ("plain")); + + parents.Add (mixed); + mixed.Add (new MimePart ()); + + return rfc822; + } + + static MessagePart CreateImapExampleInnerMessageRfc822 (List parents) + { + var message = new MimeMessage (); + var mixed = new Multipart ("mixed"); + var alternative = new MultipartAlternative (); + var rfc822 = new MessagePart { Message = message }; + + parents.Add (rfc822); + message.Body = mixed; + + parents.Add (mixed); + mixed.Add (new TextPart ("plain")); + + parents.Add (mixed); + mixed.Add (alternative); + + parents.Add (alternative); + alternative.Add (new TextPart ("plain")); + + parents.Add (alternative); + alternative.Add (new TextPart ("richtext")); + + return rfc822; + } + + static Multipart CreateImapExampleInnerMultipart (List parents) + { + var mixed = new Multipart ("mixed"); + + parents.Add (mixed); + mixed.Add (new MimePart ("image", "gif")); + + parents.Add (mixed); + mixed.Add (CreateImapExampleInnerMessageRfc822 (parents)); + + return mixed; + } + + static MimeMessage CreateImapExampleMessage (List parents) + { + var message = new MimeMessage (); + var mixed = new Multipart ("mixed"); + + message.Body = mixed; + + parents.Add (mixed); + mixed.Add (new TextPart ("plain")); + + parents.Add (mixed); + mixed.Add (new MimePart ()); + + parents.Add (mixed); + mixed.Add (CreateImapExampleMessageRfc822 (parents)); + + parents.Add (mixed); + mixed.Add (CreateImapExampleInnerMultipart (parents)); + + return message; + } + + [Test] + public void TestPathSpecifiers () + { + var expectedTypes = new Type[] { typeof (Multipart), typeof (TextPart), typeof (MimePart), typeof (MessagePart), typeof (Multipart), typeof (TextPart), typeof (MimePart), typeof (Multipart), typeof (MimePart), typeof (MessagePart), typeof (Multipart), typeof (TextPart), typeof (MultipartAlternative), typeof (TextPart), typeof (TextPart) }; + var expectedPathSpecifiers = new string[] { "0", "1", "2", "3", "3.0", "3.1", "3.2", "4", "4.1", "4.2", "4.2.0", "4.2.1", "4.2.2", "4.2.2.1", "4.2.2.2" }; + var expectedDepths = new int[] { 0, 1, 1, 1, 2, 3, 3, 1, 2, 2, 3, 4, 4, 5, 5 }; + var expectedParents = new List { null }; + var message = CreateImapExampleMessage (expectedParents); + var iter = new MimeIterator (message); + int i = 0; + + Assert.IsTrue (iter.MoveNext (), "Initialize"); + do { + var current = iter.Current; + var parent = iter.Parent; + + Assert.AreEqual (expectedDepths[i], iter.Depth, "Depth #{0}", i); + Assert.AreEqual (expectedParents[i], parent, "Parent #{0}", i); + Assert.IsInstanceOf (expectedTypes[i], current, "Type #{0}", i); + Assert.AreEqual (expectedPathSpecifiers[i], iter.PathSpecifier, "PathSpecifier #{0}", i); + i++; + } while (iter.MoveNext ()); + + Assert.AreEqual (expectedTypes.Length, i); + + iter.Reset (); + i = 0; + + Assert.IsTrue (iter.MoveNext (), "Reset"); + do { + var current = iter.Current; + var parent = iter.Parent; + + Assert.AreEqual (expectedDepths[i], iter.Depth, "Reset Depth #{0}", i); + Assert.AreEqual (expectedParents[i], parent, "Reset Parent #{0}", i); + Assert.IsInstanceOf (expectedTypes[i], current, "Reset Type #{0}", i); + Assert.AreEqual (expectedPathSpecifiers[i], iter.PathSpecifier, "Reset PathSpecifier #{0}", i); + i++; + } while (iter.MoveNext ()); + } + + [Test] + public void TestMoveTo () + { + var expectedTypes = new Type[] { typeof (Multipart), typeof (TextPart), typeof (MimePart), typeof (MessagePart), typeof (Multipart), typeof (TextPart), typeof (MimePart), typeof (Multipart), typeof (MimePart), typeof (MessagePart), typeof (Multipart), typeof (TextPart), typeof (MultipartAlternative), typeof (TextPart), typeof (TextPart) }; + var expectedPathSpecifiers = new List { "0", "1", "2", "3", "3.0", "3.1", "3.2", "4", "4.1", "4.2", "4.2.0", "4.2.1", "4.2.2", "4.2.2.1", "4.2.2.2" }; + var paths = new string[] { "3.1", "3.2", "4", "4.2.1", "4.2.2.2", "4.2", "3.2" }; + var expectedDepths = new int[] { 0, 1, 1, 1, 2, 3, 3, 1, 2, 2, 3, 4, 4, 5, 5 }; + var expectedParents = new List { null }; + var message = CreateImapExampleMessage (expectedParents); + var iter = new MimeIterator (message); + + foreach (var path in paths) { + int i = expectedPathSpecifiers.IndexOf (path); + + Assert.IsTrue (iter.MoveTo (expectedPathSpecifiers[i]), "MoveTo {0}", expectedPathSpecifiers[i]); + Assert.AreEqual (expectedPathSpecifiers[i], iter.PathSpecifier, "PathSpecifier {0}", expectedPathSpecifiers[i]); + Assert.AreEqual (expectedParents[i], iter.Parent, "Parent {0}", expectedPathSpecifiers[i]); + Assert.IsInstanceOf (expectedTypes[i], iter.Current, "Type {0}", expectedPathSpecifiers[i]); + Assert.AreEqual (expectedDepths[i], iter.Depth, "Depth {0}", expectedPathSpecifiers[i]); + } + } + } +} diff --git a/UnitTests/MimeMessageTests.cs b/UnitTests/MimeMessageTests.cs index dd7732852e..c2d113b3c9 100644 --- a/UnitTests/MimeMessageTests.cs +++ b/UnitTests/MimeMessageTests.cs @@ -1,9 +1,9 @@ -// +// // MimeMessageTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -30,6 +30,7 @@ using System.Text; using System.Net.Mail; using System.Reflection; +using System.Threading.Tasks; using NUnit.Framework; @@ -68,39 +69,77 @@ public void TestArgumentExceptions () Assert.Throws (() => MimeMessage.Load (null, "fileName")); Assert.Throws (() => MimeMessage.Load (ParserOptions.Default, (string) null)); - Assert.Throws (async () => await MimeMessage.LoadAsync ((Stream) null)); - Assert.Throws (async () => await MimeMessage.LoadAsync ((Stream) null, true)); - Assert.Throws (async () => await MimeMessage.LoadAsync (null, Stream.Null)); - Assert.Throws (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (Stream) null)); - Assert.Throws (async () => await MimeMessage.LoadAsync (null, Stream.Null, true)); - Assert.Throws (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (Stream) null, true)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync ((Stream) null, true)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (null, Stream.Null)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (null, Stream.Null, true)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (Stream) null, true)); - Assert.Throws (async () => await MimeMessage.LoadAsync ((string) null)); - Assert.Throws (async () => await MimeMessage.LoadAsync (null, "fileName")); - Assert.Throws (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync ((string) null)); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (null, "fileName")); + Assert.ThrowsAsync (async () => await MimeMessage.LoadAsync (ParserOptions.Default, (string) null)); Assert.Throws (() => message.Accept (null)); Assert.Throws (() => message.Prepare (EncodingConstraint.None, 10)); Assert.Throws (() => message.WriteTo ((string) null)); Assert.Throws (() => message.WriteTo ((Stream) null)); Assert.Throws (() => message.WriteTo (null, Stream.Null)); + Assert.Throws (() => message.WriteTo ((Stream) null, true)); Assert.Throws (() => message.WriteTo (FormatOptions.Default, (Stream) null)); Assert.Throws (() => message.WriteTo (null, "fileName")); Assert.Throws (() => message.WriteTo (FormatOptions.Default, (string) null)); - Assert.Throws (async () => await message.WriteToAsync ((string) null)); - Assert.Throws (async () => await message.WriteToAsync ((Stream) null)); - Assert.Throws (async () => await message.WriteToAsync (null, Stream.Null)); - Assert.Throws (async () => await message.WriteToAsync (FormatOptions.Default, (Stream) null)); - Assert.Throws (async () => await message.WriteToAsync (null, "fileName")); - Assert.Throws (async () => await message.WriteToAsync (FormatOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await message.WriteToAsync ((string) null)); + Assert.ThrowsAsync (async () => await message.WriteToAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await message.WriteToAsync (null, Stream.Null)); + Assert.ThrowsAsync (async () => await message.WriteToAsync ((Stream) null, true)); + Assert.ThrowsAsync (async () => await message.WriteToAsync (FormatOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await message.WriteToAsync (null, "fileName")); + Assert.ThrowsAsync (async () => await message.WriteToAsync (FormatOptions.Default, (string) null)); Assert.Throws (() => message.Sign (null)); Assert.Throws (() => message.Sign (null, DigestAlgorithm.Sha1)); Assert.Throws (() => message.Encrypt (null)); Assert.Throws (() => message.SignAndEncrypt (null)); + + Assert.Throws (() => MimeMessage.CreateFromMailMessage (null)); + } + + [Test] + public void TestPrependHeader () + { + string rawMessageText = @"Date: Fri, 22 Jan 2016 8:44:05 -0500 (EST) +From: MimeKit Unit Tests +To: MimeKit Unit Tests +Subject: This is a test off prepending headers. +Message-Id: +MIME-Version: 1.0 +Content-Type: text/plain + +This is the message body. +".Replace ("\r\n", "\n"); + string expected = "X-Prepended: This is the prepended header\n" + rawMessageText; + + using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) { + var parser = new MimeParser (source, MimeFormat.Default); + var message = parser.ParseMessage (); + + message.Headers.Insert (0, new Header ("X-Prepended", "This is the prepended header")); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (expected, result, "Reserialized message is not identical to the original."); + } + } } [Test] - public async void TestReserialization () + public async Task TestReserialization () { string rawMessageText = @"X-Andrew-Authenticated-As: 4099;greenbush.galaxy;Nathaniel Borenstein Received: from Messages.8.5.N.CUILIB.3.45.SNAP.NOT.LINKED.greenbush.galaxy.sun4.41 @@ -201,11 +240,36 @@ This is an attached message. Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original."); } + + var index = rawMessageText.IndexOf ("\n\n", StringComparison.Ordinal); + var headersOnly = rawMessageText.Substring (0, index + 2); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + message.WriteTo (options, serialized, true); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (headersOnly, result, "Reserialized headers are not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + await message.WriteToAsync (options, serialized, true); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (headersOnly, result, "Reserialized headers (async) are not identical to the original."); + } } } [Test] - public async void TestReserializationEmptyParts () + public async Task TestReserializationEmptyParts () { string rawMessageText = @"Date: Fri, 22 Jan 2016 8:44:05 -0500 (EST) From: MimeKit Unit Tests @@ -264,7 +328,7 @@ This is the body. } [Test] - public async void TestReserializationMessageParts () + public async Task TestReserializationMessageParts () { string rawMessageText = @"Path: flop.mcom.com!news.Stanford.EDU!agate!tcsi.tcs.com!uunet!vixen.cso.uiuc.edu!gateway From: Internet-Drafts@CNRI.Reston.VA.US @@ -368,6 +432,292 @@ ENCODING mime } } + [Test] + public async Task TestReserializationEpilogue () + { + string rawMessageText = @"From: Example Test +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary=""simple boundary"" + +This is the preamble. + +--simple boundary +Content-TypeS: text/plain + +This is a test. + +--simple boundary +Content-Type: text/plain +Content-Disposition: attachment +Content-Transfer-Encoding: 7bit + +Another test. + +--simple boundary-- + + +This is the epilogue.".Replace ("\r\n", "\n"); + + using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) { + var parser = new MimeParser (source, MimeFormat.Default); + var message = parser.ParseMessage (); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText + "\n", result, "Reserialized message is not identical to the original (EnsureNewLine)."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText + "\n", result, "Reserialized (async) message is not identical to the original (EnsureNewLine)."); + } + } + } + + [Test] + public async Task TestReserializationMultipartPreambleNoBoundary () + { + string rawMessageText = @"From: Example Test +Content-Type: multipart/mixed + +This is the preamble. +.".Replace ("\r\n", "\n"); + + using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) { + var parser = new MimeParser (source, MimeFormat.Default); + var message = parser.ParseMessage (); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText + "\n", result, "Reserialized message is not identical to the original (EnsureNewLine)."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText + "\n", result, "Reserialized (async) message is not identical to the original (EnsureNewLine)."); + } + } + } + + [Test] + public async Task TestReserializationInvalidHeaders () + { + string rawMessageText = @"From: Example Test +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary=""simple boundary"" +Example: test +Test +Test Test +Test: +Test: +Test: Test +Test Example: + +This is the preamble. + +--simple boundary +Content-TypeS: text/plain + +This is a test. + +--simple boundary +Content-Type: text/plain; +Content-Disposition: attachment; +Content-Transfer-Encoding: test; +Content-Transfer-Encoding: binary; +Test Test Test: Test Test +Te$t($)*$= Test Test: Abc def +test test = test +test test :: test +filename=""test.txt"" + +Another test. + +--simple boundary-- + + +This is the epilogue. +".Replace ("\r\n", "\n"); + + using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) { + var parser = new MimeParser (source, MimeFormat.Default); + var message = parser.ParseMessage (); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original."); + } + } + } + + [Test] + public async Task TestReserializationDeliveryStatusReportWithEnsureNewLine () + { + string rawMessageText = @"From: est@somwhere.com +Date: Fri, 15 Feb 2019 16:00:08 +0000 +Subject: report_with_no_body +To: tom@to.com +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; boundary=""A41C7.838631588=_/mm1"" + + +Processing your mail message caused the following errors: + +error: err.nosuchuser: newsletter-request@imusic.com + +--A41C7.838631588=_/mm1 +Content-Type: message/delivery-status + +Reporting-MTA: dns; mm1 +Arrival-Date: Mon, 29 Jul 1996 02:12:50 -0700 + +Final-Recipient: RFC822; newsletter-request@imusic.com +Action: failed +Diagnostic-Code: X-LOCAL; 500 (err.nosuchuser) + +--A41C7.838631588=_/mm1 +Content-Type: message/rfc822 + +Received: from urchin.netscape.com ([198.95.250.59]) by mm1.sprynet.com with ESMTP id <148217-12799>; Mon, 29 Jul 1996 02:12:50 -0700 +Received: from gruntle (gruntle.mcom.com [205.217.230.10]) by urchin.netscape.com (8.7.5/8.7.3) with SMTP id CAA24688 for ; Mon, 29 Jul 1996 02:04:53 -0700 (PDT) +Sender: jwz@netscape.com +Message-ID: <31FC7EB4.41C6@netscape.com> +Date: Mon, 29 Jul 1996 02:04:52 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b6 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: newsletter-request@imusic.com +Subject: unsubscribe +References: <96Jul29.013736-0700pdt.148116-12799+675@mm1.sprynet.com> +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +unsubscribe +--A41C7.838631588=_/mm1-- +".Replace ("\r\n", "\n"); + + using (var source = new MemoryStream (Encoding.UTF8.GetBytes (rawMessageText))) { + var parser = new MimeParser (source, MimeFormat.Default); + var message = parser.ParseMessage (); + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + message.WriteTo (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized message is not identical to the original."); + } + + using (var serialized = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + options.EnsureNewLine = true; + + await message.WriteToAsync (options, serialized); + + var result = Encoding.UTF8.GetString (serialized.ToArray ()); + + Assert.AreEqual (rawMessageText, result, "Reserialized (async) message is not identical to the original."); + } + } + } + [Test] public void TestMailMessageToMimeMessage () { @@ -380,6 +730,7 @@ public void TestMailMessageToMimeMessage () mail.Bcc.Add (new MailAddress ("bcc@bcc.com", "The Blind Carbon-Copied Recipient")); mail.Subject = "This is the message subject"; mail.Priority = MailPriority.High; + mail.Headers.Add ("X-MimeKit-Test", "does this get copied, too?"); mail.Body = "This is plain text."; //var text = new MemoryStream (Encoding.ASCII.GetBytes ("This is plain text."), false); @@ -413,6 +764,7 @@ public void TestMailMessageToMimeMessage () Assert.AreEqual (mail.Bcc[0].Address, ((MailboxAddress) message.Bcc[0]).Address, "The bcc addresses do not match."); Assert.AreEqual (mail.Subject, message.Subject, "The message subjects do not match."); Assert.AreEqual (MessagePriority.Urgent, message.Priority, "The message priority does not match."); + Assert.AreEqual (mail.Headers["X-MimeKit-Test"], message.Headers["X-MimeKit-Test"], "The X-MimeKit-Test headers do not match"); Assert.IsInstanceOf (message.Body, "The top-level MIME part should be a multipart/mixed."); var mixed = (Multipart) message.Body; @@ -442,6 +794,17 @@ public void TestMailMessageToMimeMessage () Assert.AreEqual ("id@jpeg", jpeg.ContentId); Assert.AreEqual ("image/jpeg", jpeg.ContentType.MimeType); Assert.AreEqual ("link", jpeg.ContentLocation.OriginalString); + + // Test other priorities + mail.Priority = MailPriority.Low; + message = (MimeMessage) mail; + + Assert.AreEqual (MessagePriority.NonUrgent, message.Priority, "The message priority does not match."); + + mail.Priority = MailPriority.Normal; + message = (MimeMessage) mail; + + Assert.AreEqual (MessagePriority.Normal, message.Priority, "The message priority does not match."); } [Test] @@ -916,39 +1279,39 @@ public void TestHtmlAndTextBodies () const string TextBody = "This is the text body."; MimeMessage message; - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.1.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.1.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.1.txt."); Assert.AreEqual (null, message.HtmlBody, "The HTML bodies do not match for body.1.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.2.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.2.txt")); Assert.AreEqual (null, message.TextBody, "The text bodies do not match for body.2.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.2.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.3.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.3.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.3.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.3.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.4.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.4.txt")); Assert.AreEqual (null, message.TextBody, "The text bodies do not match for body.4.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.4.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.5.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.5.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.5.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.5.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.6.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.6.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.6.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.6.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.7.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.7.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.7.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.7.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.8.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.8.txt")); Assert.AreEqual (TextBody, message.TextBody, "The text bodies do not match for body.8.txt."); Assert.AreEqual (null, message.HtmlBody, "The HTML bodies do not match for body.8.txt."); - message = MimeMessage.Load (Path.Combine ("..", "..", "TestData", "messages", "body.9.txt")); + message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "body.9.txt")); Assert.AreEqual (null, message.TextBody, "The text bodies do not match for body.9.txt."); Assert.AreEqual (HtmlBody, message.HtmlBody, "The HTML bodies do not match for body.9.txt."); } diff --git a/UnitTests/MimeParserTests.cs b/UnitTests/MimeParserTests.cs index f7e4159109..698c41ad8d 100644 --- a/UnitTests/MimeParserTests.cs +++ b/UnitTests/MimeParserTests.cs @@ -1,9 +1,9 @@ -// +// // MimeParserTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,12 +26,17 @@ using System; using System.IO; +using System.Linq; using System.Text; using System.Threading; +using System.Globalization; using System.Threading.Tasks; +using System.Collections.Generic; using NUnit.Framework; +using Newtonsoft.Json; + using MimeKit; using MimeKit.IO; using MimeKit.Utils; @@ -41,8 +46,8 @@ namespace UnitTests { [TestFixture] public class MimeParserTests { - static string MessagesDataDir = Path.Combine ("..", "..", "TestData", "messages"); - static string MboxDataDir = Path.Combine ("..", "..", "TestData", "mbox"); + static readonly string MessagesDataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "messages"); + static readonly string MboxDataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "mbox"); static FormatOptions UnixFormatOptions; public MimeParserTests () @@ -103,7 +108,7 @@ public void TestHeaderParser () } [Test] - public async void TestHeaderParserAsync () + public async Task TestHeaderParserAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\nHeader-2: value 2\r\nHeader-3: value 3\r\n\r\n"); @@ -131,6 +136,22 @@ public async void TestHeaderParserAsync () } } + [Test] + public void TestTruncatedHeaderName () + { + var bytes = Encoding.ASCII.GetBytes ("Header-1"); + + using (var memory = new MemoryStream (bytes, false)) { + try { + var headers = HeaderList.Load (memory); + Assert.Fail ("Parsing headers should fail."); + } catch (FormatException) { + } catch (Exception ex) { + Assert.Fail ("Failed to parse headers: {0}", ex); + } + } + } + [Test] public void TestTruncatedHeader () { @@ -152,7 +173,7 @@ public void TestTruncatedHeader () } [Test] - public async void TestTruncatedHeaderAsync () + public async Task TestTruncatedHeaderAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1"); @@ -192,7 +213,7 @@ public void TestSingleHeaderNoTerminator () } [Test] - public async void TestSingleHeaderNoTerminatorAsync () + public async Task TestSingleHeaderNoTerminatorAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\n"); @@ -228,7 +249,7 @@ public void TestEmptyHeaders () } [Test] - public async void TestEmptyHeadersAsync () + public async Task TestEmptyHeadersAsync () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); @@ -257,7 +278,7 @@ public void TestPartialByteOrderMarkEOF () parser.SetStream (stream, MimeFormat.Entity); - Assert.Throws (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); + Assert.ThrowsAsync (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); } } @@ -282,7 +303,7 @@ public void TestPartialByteOrderMark () parser.SetStream (stream, MimeFormat.Entity); - Assert.Throws (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); + Assert.ThrowsAsync (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); } } @@ -303,7 +324,7 @@ public void TestParsingGarbage () stream.Position = 0; - Assert.Throws (async () => await parser.ParseMessageAsync (), "MboxAsync"); + Assert.ThrowsAsync (async () => await parser.ParseMessageAsync (), "MboxAsync"); stream.Position = 0; @@ -315,7 +336,7 @@ public void TestParsingGarbage () parser.SetStream (stream, MimeFormat.Entity); - Assert.Throws (async () => await parser.ParseMessageAsync (), "EntityAsync"); + Assert.ThrowsAsync (async () => await parser.ParseMessageAsync (), "EntityAsync"); } } @@ -337,7 +358,7 @@ public void TestDoubleMboxMarker () } [Test] - public async void TestDoubleMboxMarkerAsync () + public async Task TestDoubleMboxMarkerAsync () { var content = Encoding.ASCII.GetBytes ("From - \r\nFrom -\r\nFrom: sender@example.com\r\nTo: recipient@example.com\r\nSubject: test message\r\n\r\nBody text\r\n"); @@ -370,7 +391,7 @@ public void TestEmptyMessage () } [Test] - public async void TestEmptyMessageAsync () + public async Task TestEmptyMessageAsync () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); @@ -463,7 +484,7 @@ static async Task AssertSimpleMboxAsync (Stream stream) } [Test] - public async void TestSimpleMboxAsync () + public async Task TestSimpleMboxAsync () { using (var stream = File.OpenRead (Path.Combine (MboxDataDir, "simple.mbox.txt"))) await AssertSimpleMboxAsync (stream); @@ -487,7 +508,7 @@ public void TestSimpleMboxWithByteOrderMark () } [Test] - public async void TestSimpleMboxWithByteOrderMarkAsync () + public async Task TestSimpleMboxWithByteOrderMarkAsync () { using (var stream = new MemoryStream ()) { var bom = new byte[] { 0xEF, 0xBB, 0xBF }; @@ -552,68 +573,256 @@ public void TestEmptyMultipartAlternative () } } - static void AssertJwzMboxResults (string actual, Stream output) + static NewLineFormat DetectNewLineFormat (string fileName) { - var summary = File.ReadAllText (Path.Combine (MboxDataDir, "jwz-summary.txt")).Replace ("\r\n", "\n"); - var original = new MemoryBlockStream (); - var expected = new byte[4096]; - var buffer = new byte[4096]; - int nx, n; + using (var stream = File.OpenRead (fileName)) { + var buffer = new byte[1024]; + + var nread = stream.Read (buffer, 0, buffer.Length); + + for (int i = 0; i < nread; i++) { + if (buffer[i] == (byte) '\n') { + if (i > 0 && buffer[i - 1] == (byte) '\r') + return NewLineFormat.Dos; + + return NewLineFormat.Unix; + } + } + } + + return NewLineFormat.Dos; + } + + class MimeOffsets + { + [JsonProperty ("mimeType", NullValueHandling = NullValueHandling.Ignore)] + public string MimeType { get; set; } + + [JsonProperty ("mboxMarkerOffset", NullValueHandling = NullValueHandling.Ignore)] + public long? MboxMarkerOffset { get; set; } + + [JsonProperty ("lineNumber")] + public int LineNumber { get; set; } + + [JsonProperty ("beginOffset")] + public long BeginOffset { get; set; } + + [JsonProperty ("headersEndOffset")] + public long HeadersEndOffset { get; set; } + + [JsonProperty ("endOffset")] + public long EndOffset { get; set; } + + [JsonProperty ("message", NullValueHandling = NullValueHandling.Ignore)] + public MimeOffsets Message { get; set; } + + [JsonProperty ("body", NullValueHandling = NullValueHandling.Ignore)] + public MimeOffsets Body { get; set; } + + [JsonProperty ("children", NullValueHandling = NullValueHandling.Ignore)] + public List Children { get; set; } + + [JsonProperty ("octets")] + public long Octets { get; set; } + + [JsonProperty ("lines", NullValueHandling = NullValueHandling.Ignore)] + public int? Lines { get; set; } + } + + static void AssertMimeOffsets (MimeOffsets expected, MimeOffsets actual, int message, string partSpecifier) + { + Assert.AreEqual (expected.MimeType, actual.MimeType, $"mime-type differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.MboxMarkerOffset, actual.MboxMarkerOffset, $"mbox marker begin offset differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.BeginOffset, actual.BeginOffset, $"begin offset differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.LineNumber, actual.LineNumber, $"begin line differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.HeadersEndOffset, actual.HeadersEndOffset, $"headers end offset differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.EndOffset, actual.EndOffset, $"end offset differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.Octets, actual.Octets, $"octets differs for message #{message}{partSpecifier}"); + Assert.AreEqual (expected.Lines, actual.Lines, $"lines differs for message #{message}{partSpecifier}"); + + if (expected.Message != null) { + Assert.NotNull (actual.Message, $"message content is null for message #{message}{partSpecifier}"); + AssertMimeOffsets (expected.Message, actual.Message, message, partSpecifier + "/message"); + } else if (expected.Body != null) { + Assert.NotNull (actual.Body, $"body content is null for message #{message}{partSpecifier}"); + AssertMimeOffsets (expected.Body, actual.Body, message, partSpecifier + "/0"); + } else if (expected.Children != null) { + Assert.AreEqual (expected.Children.Count, actual.Children.Count, $"children count differs for message #{message}{partSpecifier}"); + for (int i = 0; i < expected.Children.Count; i++) + AssertMimeOffsets (expected.Children[i], actual.Children[i], message, partSpecifier + $".{i}"); + } + } + + class CustomMimeParser : MimeParser + { + readonly Dictionary messages = new Dictionary (); + readonly Dictionary entities = new Dictionary (); + public readonly List Offsets = new List (); + MimeOffsets body; + + public CustomMimeParser (ParserOptions options, Stream stream, MimeFormat format) : base (options, stream, format) + { + } + + public CustomMimeParser (Stream stream, MimeFormat format) : base (stream, format) + { + } + protected override void OnMimeMessageBegin (MimeMessageBeginEventArgs args) + { + var offsets = new MimeOffsets { + BeginOffset = args.BeginOffset, + LineNumber = args.LineNumber + }; + + if (args.Parent != null) { + if (entities.TryGetValue (args.Parent, out var parentOffsets)) + parentOffsets.Message = offsets; + else + Console.WriteLine ("oops?"); + } else { + offsets.MboxMarkerOffset = MboxMarkerOffset; + Offsets.Add (offsets); + } + + messages.Add (args.Message, offsets); + + base.OnMimeMessageBegin (args); + } + + protected override void OnMimeMessageEnd (MimeMessageEndEventArgs args) + { + if (messages.TryGetValue (args.Message, out var offsets)) { + offsets.Octets = args.EndOffset - args.HeadersEndOffset; + offsets.HeadersEndOffset = args.HeadersEndOffset; + offsets.EndOffset = args.EndOffset; + offsets.Body = body; + } else { + Console.WriteLine ("oops?"); + } + + messages.Remove (args.Message); + + base.OnMimeMessageEnd (args); + } + + protected override void OnMimeEntityBegin (MimeEntityBeginEventArgs args) + { + var offsets = new MimeOffsets { + MimeType = args.Entity.ContentType.MimeType, + BeginOffset = args.BeginOffset, + LineNumber = args.LineNumber + }; + + if (args.Parent != null && entities.TryGetValue (args.Parent, out var parentOffsets)) { + if (parentOffsets.Children == null) + parentOffsets.Children = new List (); + + parentOffsets.Children.Add (offsets); + } + + entities.Add (args.Entity, offsets); + + base.OnMimeEntityBegin (args); + } + + protected override void OnMimeEntityEnd (MimeEntityEndEventArgs args) + { + if (entities.TryGetValue (args.Entity, out var offsets)) { + offsets.Octets = args.EndOffset - args.HeadersEndOffset; + offsets.HeadersEndOffset = args.HeadersEndOffset; + offsets.EndOffset = args.EndOffset; + offsets.Lines = args.Lines; + body = offsets; + } else { + Console.WriteLine ("oops?"); + } + + entities.Remove (args.Entity); + + base.OnMimeEntityEnd (args); + } + } + + static void AssertMboxResults (string baseName, string actual, Stream output, List offsets, NewLineFormat newLineFormat) + { // WORKAROUND: Mono's iso-2022-jp decoder breaks on this input in versions <= 3.2.3 but is fixed in 3.2.4+ string iso2022jp = Encoding.GetEncoding ("iso-2022-jp").GetString (Convert.FromBase64String ("GyRAOjRGI0stGyhK")); if (iso2022jp != "佐藤豊") actual = actual.Replace (iso2022jp, "佐藤豊"); - Assert.AreEqual (summary, actual, "Summaries do not match for jwz.mbox"); + var path = Path.Combine (MboxDataDir, baseName + "-summary.txt"); + if (!File.Exists (path)) + File.WriteAllText (path, actual); - using (var stream = File.OpenRead (Path.Combine (MboxDataDir, "jwz.mbox.txt"))) { - using (var filtered = new FilteredStream (original)) { - filtered.Add (new Dos2UnixFilter ()); - stream.CopyTo (filtered); - filtered.Flush (); - } - } + var summary = File.ReadAllText (path).Replace ("\r\n", "\n"); + var expected = new byte[4096]; + var buffer = new byte[4096]; + int nx, n; - original.Position = 0; - output.Position = 0; + Assert.AreEqual (summary, actual, "Summaries do not match for {0}.mbox", baseName); - Assert.AreEqual (original.Length, output.Length, "The length of the mbox did not match."); + using (var original = File.OpenRead (Path.Combine (MboxDataDir, baseName + ".mbox.txt"))) { + output.Position = 0; - do { - var position = original.Position; + Assert.AreEqual (original.Length, output.Length, "The length of the mbox did not match."); - nx = original.Read (expected, 0, expected.Length); - n = output.Read (buffer, 0, buffer.Length); + do { + var position = original.Position; - if (nx == 0) - break; + nx = original.Read (expected, 0, expected.Length); + n = output.Read (buffer, 0, nx); - for (int i = 0; i < nx; i++) { - if (buffer[i] == expected[i]) - continue; + if (nx == 0) + break; - var strExpected = CharsetUtils.Latin1.GetString (expected, 0, nx); - var strActual = CharsetUtils.Latin1.GetString (buffer, 0, n); + for (int i = 0; i < nx; i++) { + if (buffer[i] == expected[i]) + continue; - Assert.AreEqual (strExpected, strActual, "The mbox differs at position {0}", position + i); - } - } while (true); + var strExpected = CharsetUtils.Latin1.GetString (expected, 0, nx); + var strActual = CharsetUtils.Latin1.GetString (buffer, 0, n); + + Assert.AreEqual (strExpected, strActual, "The mbox differs at position {0}", position + i); + } + } while (true); + } + + var jsonSerializer = JsonSerializer.CreateDefault (); + + path = Path.Combine (MboxDataDir, baseName + "." + newLineFormat.ToString ().ToLowerInvariant () + "-offsets.json"); + if (!File.Exists (path)) { + jsonSerializer.Formatting = Formatting.Indented; + + using (var writer = new StreamWriter (path)) + jsonSerializer.Serialize (writer, offsets); + } + + using (var reader = new StreamReader (path)) { + var expectedOffsets = (List) jsonSerializer.Deserialize (reader, typeof (List)); + + Assert.AreEqual (expectedOffsets.Count, offsets.Count, "message count"); + + for (int i = 0; i < expectedOffsets.Count; i++) + AssertMimeOffsets (expectedOffsets[i], offsets[i], i, string.Empty); + } } - [Test] - public void TestJwzMbox () + void TestMbox (ParserOptions options, string baseName) { - var options = FormatOptions.Default.Clone (); + var mbox = Path.Combine (MboxDataDir, baseName + ".mbox.txt"); var output = new MemoryBlockStream (); var builder = new StringBuilder (); + NewLineFormat newLineFormat; + List offsets; - options.NewLineFormat = NewLineFormat.Unix; - - using (var stream = File.OpenRead (Path.Combine (MboxDataDir, "jwz.mbox.txt"))) { - var parser = new MimeParser (stream, MimeFormat.Mbox); + using (var stream = File.OpenRead (mbox)) { + var parser = options != null ? new CustomMimeParser (options, stream, MimeFormat.Mbox) : new CustomMimeParser (stream, MimeFormat.Mbox); + var format = FormatOptions.Default.Clone (); int count = 0; + format.NewLineFormat = newLineFormat = DetectNewLineFormat (mbox); + while (!parser.IsEndOfStream) { var message = parser.ParseMessage (); @@ -627,29 +836,33 @@ public void TestJwzMbox () DumpMimeTree (builder, message); builder.Append ('\n'); - var marker = Encoding.UTF8.GetBytes ((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n"); + var marker = Encoding.UTF8.GetBytes ((count > 0 ? format.NewLine : string.Empty) + parser.MboxMarker + format.NewLine); output.Write (marker, 0, marker.Length); - message.WriteTo (options, output); + message.WriteTo (format, output); count++; } + + offsets = parser.Offsets; } - AssertJwzMboxResults (builder.ToString (), output); + AssertMboxResults (baseName, builder.ToString (), output, offsets, newLineFormat); } - [Test] - public async void TestJwzMboxAsync () + async Task TestMboxAsync (ParserOptions options, string baseName) { - var options = FormatOptions.Default.Clone (); + var mbox = Path.Combine (MboxDataDir, baseName + ".mbox.txt"); var output = new MemoryBlockStream (); var builder = new StringBuilder (); + NewLineFormat newLineFormat; + List offsets; - options.NewLineFormat = NewLineFormat.Unix; - - using (var stream = File.OpenRead (Path.Combine (MboxDataDir, "jwz.mbox.txt"))) { - var parser = new MimeParser (stream, MimeFormat.Mbox); + using (var stream = File.OpenRead (mbox)) { + var parser = options != null ? new CustomMimeParser (options, stream, MimeFormat.Mbox) : new CustomMimeParser (stream, MimeFormat.Mbox); + var format = FormatOptions.Default.Clone (); int count = 0; + format.NewLineFormat = newLineFormat = DetectNewLineFormat (mbox); + while (!parser.IsEndOfStream) { var message = await parser.ParseMessageAsync (); @@ -663,14 +876,46 @@ public async void TestJwzMboxAsync () DumpMimeTree (builder, message); builder.Append ('\n'); - var marker = Encoding.UTF8.GetBytes ((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n"); + var marker = Encoding.UTF8.GetBytes ((count > 0 ? format.NewLine : string.Empty) + parser.MboxMarker + format.NewLine); await output.WriteAsync (marker, 0, marker.Length); - await message.WriteToAsync (options, output); + await message.WriteToAsync (format, output); count++; } + + offsets = parser.Offsets; } - AssertJwzMboxResults (builder.ToString (), output); + AssertMboxResults (baseName, builder.ToString (), output, offsets, newLineFormat); + } + + [Test] + public void TestContentLengthMbox () + { + var options = ParserOptions.Default.Clone (); + options.RespectContentLength = true; + + TestMbox (options, "content-length"); + } + + [Test] + public async Task TestContentLengthMboxAsync () + { + var options = ParserOptions.Default.Clone (); + options.RespectContentLength = true; + + await TestMboxAsync (options, "content-length"); + } + + [Test] + public void TestJwzMbox () + { + TestMbox (null, "jwz"); + } + + [Test] + public async Task TestJwzMboxAsync () + { + await TestMboxAsync (null, "jwz"); } [Test] @@ -713,7 +958,7 @@ public void TestJwzPersistentMbox () } [Test] - public async void TestJwzPersistentMboxAsync () + public async Task TestJwzPersistentMboxAsync () { var summary = File.ReadAllText (Path.Combine (MboxDataDir, "jwz-summary.txt")).Replace ("\r\n", "\n"); var builder = new StringBuilder (); @@ -737,7 +982,7 @@ public async void TestJwzPersistentMboxAsync () // Force the various MimePart objects to write their content streams. // The idea is that by forcing the MimeParts to seek in their content, // we will test to make sure that the parser correctly deals with it. - message.WriteTo (Stream.Null); + await message.WriteToAsync (Stream.Null); } } @@ -766,7 +1011,7 @@ public void TestJapaneseMessage () } [Test] - public async void TestJapaneseMessageAsync () + public async Task TestJapaneseMessageAsync () { const string subject = "日本語メールテスト (testing Japanese emails)"; const string body = "Let's see if both subject and body works fine...\n\n日本語が\n正常に\n送れているか\nテスト.\n"; @@ -806,7 +1051,7 @@ public void TestUnmungedFromLines () } [Test] - public async void TestUnmungedFromLinesAsync () + public async Task TestUnmungedFromLinesAsync () { int count = 0; @@ -848,7 +1093,7 @@ public void TestMultipartEpilogueWithText () } [Test] - public async void TestMultipartEpilogueWithTextAsync () + public async Task TestMultipartEpilogueWithTextAsync () { const string epilogue = "Peter Urka \nDept. of Chemistry, Univ. of Michigan\nNewt-thought is right-thought. Go Newt!\n\n"; @@ -893,7 +1138,7 @@ public void TestMissingMessageBody () } [Test] - public async void TestMissingMessageBodyAsync () + public async Task TestMissingMessageBodyAsync () { const string text = "Date: Sat, 19 Apr 2014 13:13:23 -0700\r\n" + "From: Jeffrey Stedfast \r\n" + @@ -925,5 +1170,145 @@ public void TestIssue358 () } } } + + [Test] + public void TestLineCountSingleLine () + { + const string text = @"From: mimekit@example.org +To: mimekit@example.org +Subject: This is a message with a single line of text +Message-Id: <123@example.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii + +This is a single line of text"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Lines; + + Assert.AreEqual (1, lines, "Line count"); + } + } + + [Test] + public void TestLineCountSingleLineCRLF () + { + const string text = @"From: mimekit@example.org +To: mimekit@example.org +Subject: This is a message with a single line of text +Message-Id: <123@example.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii + +This is a single line of text +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Lines; + + Assert.AreEqual (1, lines, "Line count"); + } + } + + [Test] + public void TestLineCountSingleLineInMultipart () + { + const string text = @"From: mimekit@example.org +To: mimekit@example.org +Subject: This is a message with a single line of text +Message-Id: <123@example.org> +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary=""boundary-marker"" + +--boundary-marker +Content-Type: text/plain; charset=us-ascii + +This is a single line of text +--boundary-marker +Content-Type: application/octet-stream; name=""attachment.dat"" +Content-DIsposition: attachment; filename=""attachment.dat"" + +ABC +--boundary-marker-- +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Children[0].Lines; + + Assert.AreEqual (1, lines, "Line count"); + } + } + + [Test] + public void TestLineCountOneLineOfTextFollowedByBlankLineInMultipart () + { + const string text = @"From: mimekit@example.org +To: mimekit@example.org +Subject: This is a message with a single line of text +Message-Id: <123@example.org> +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary=""boundary-marker"" + +--boundary-marker +Content-Type: text/plain; charset=us-ascii + +This is a single line of text followed by a blank line + +--boundary-marker +Content-Type: application/octet-stream; name=""attachment.dat"" +Content-DIsposition: attachment; filename=""attachment.dat"" + +ABC +--boundary-marker-- +"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Children[0].Lines; + + Assert.AreEqual (1, lines, "Line count"); + } + } + + [Test] + public void TestLineCountNonTerminatedSingleHeader () + { + const string text = "From: mimekit@example.org"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Lines; + + Assert.AreEqual (0, lines, "Line count"); + } + } + + [Test] + public void TestLineCountProperlyTerminatedSingleHeader () + { + const string text = "From: mimekit@example.org\r\n"; + + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var parser = new CustomMimeParser (stream, MimeFormat.Entity); + var message = parser.ParseMessage (); + + var lines = parser.Offsets[0].Body.Lines; + + Assert.AreEqual (0, lines, "Line count"); + } + } } } diff --git a/UnitTests/MimePartTests.cs b/UnitTests/MimePartTests.cs index fe194633db..8d2def2335 100644 --- a/UnitTests/MimePartTests.cs +++ b/UnitTests/MimePartTests.cs @@ -1,9 +1,9 @@ -// +// // MimePartTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Jeffrey Stedfast +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ using System; using System.IO; using System.Text; +using System.Threading.Tasks; using NUnit.Framework; @@ -68,22 +69,22 @@ public void TestArgumentExceptions () Assert.Throws (() => MimeEntity.Load (null, "fileName")); Assert.Throws (() => MimeEntity.Load (ParserOptions.Default, (string) null)); - Assert.Throws (async () => await MimeEntity.LoadAsync ((Stream) null)); - Assert.Throws (async () => await MimeEntity.LoadAsync ((Stream) null, true)); - Assert.Throws (async () => await MimeEntity.LoadAsync ((ParserOptions) null, Stream.Null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (Stream) null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (null, Stream.Null, true)); - Assert.Throws (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (Stream) null, true)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync ((Stream) null, true)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync ((ParserOptions) null, Stream.Null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (null, Stream.Null, true)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (Stream) null, true)); - Assert.Throws (async () => await MimeEntity.LoadAsync ((ContentType) null, Stream.Null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (new ContentType ("application", "octet-stream"), null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (null, new ContentType ("application", "octet-stream"), Stream.Null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (ParserOptions.Default, null, Stream.Null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (ParserOptions.Default, new ContentType ("application", "octet-stream"), null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync ((ContentType) null, Stream.Null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (new ContentType ("application", "octet-stream"), null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (null, new ContentType ("application", "octet-stream"), Stream.Null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (ParserOptions.Default, null, Stream.Null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (ParserOptions.Default, new ContentType ("application", "octet-stream"), null)); - Assert.Throws (async () => await MimeEntity.LoadAsync ((string) null)); - Assert.Throws (async () => await MimeEntity.LoadAsync (null, "fileName")); - Assert.Throws (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync ((string) null)); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (null, "fileName")); + Assert.ThrowsAsync (async () => await MimeEntity.LoadAsync (ParserOptions.Default, (string) null)); Assert.Throws (() => part.Accept (null)); Assert.Throws (() => part.WriteTo ((string) null)); @@ -98,19 +99,43 @@ public void TestArgumentExceptions () Assert.Throws (() => part.WriteTo (FormatOptions.Default, (Stream) null, false)); Assert.Throws (() => part.WriteTo (null, "fileName", false)); Assert.Throws (() => part.WriteTo (FormatOptions.Default, (string) null, false)); + Assert.Throws (() => part.ContentId = "this is some text and stuff"); + + Assert.ThrowsAsync (async () => await part.WriteToAsync ((string) null)); + Assert.ThrowsAsync (async () => await part.WriteToAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await part.WriteToAsync ((string) null, false)); + Assert.ThrowsAsync (async () => await part.WriteToAsync ((Stream) null, false)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (null, Stream.Null)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (FormatOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (null, "fileName")); + Assert.ThrowsAsync (async () => await part.WriteToAsync (FormatOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (null, Stream.Null, false)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (FormatOptions.Default, (Stream) null, false)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (null, "fileName", false)); + Assert.ThrowsAsync (async () => await part.WriteToAsync (FormatOptions.Default, (string) null, false)); + } + + [Test] + public void TestParameterizedCtor () + { + const string expected = "Content-Type: text/plain\nContent-Transfer-Encoding: base64\nContent-Id: \n\n\n"; + var headers = new [] { new Header ("Content-Id", "") }; + var part = new MimePart ("text", "plain", new Header ("Content-Transfer-Encoding", "base64"), headers) { + Content = new MimeContent (new MemoryStream ()) + }; + + Assert.AreEqual ("id@localhost.com", part.ContentId, "Content-Id"); + Assert.AreEqual (ContentEncoding.Base64, part.ContentTransferEncoding, "Content-Transfer-Encoding"); - Assert.Throws (async () => await part.WriteToAsync ((string) null)); - Assert.Throws (async () => await part.WriteToAsync ((Stream) null)); - Assert.Throws (async () => await part.WriteToAsync ((string) null, false)); - Assert.Throws (async () => await part.WriteToAsync ((Stream) null, false)); - Assert.Throws (async () => await part.WriteToAsync (null, Stream.Null)); - Assert.Throws (async () => await part.WriteToAsync (FormatOptions.Default, (Stream) null)); - Assert.Throws (async () => await part.WriteToAsync (null, "fileName")); - Assert.Throws (async () => await part.WriteToAsync (FormatOptions.Default, (string) null)); - Assert.Throws (async () => await part.WriteToAsync (null, Stream.Null, false)); - Assert.Throws (async () => await part.WriteToAsync (FormatOptions.Default, (Stream) null, false)); - Assert.Throws (async () => await part.WriteToAsync (null, "fileName", false)); - Assert.Throws (async () => await part.WriteToAsync (FormatOptions.Default, (string) null, false)); + using (var stream = new MemoryStream ()) { + var options = FormatOptions.Default.Clone (); + options.NewLineFormat = NewLineFormat.Unix; + + part.WriteTo (options, stream); + + var serialized = Encoding.ASCII.GetString (stream.GetBuffer (), 0, (int) stream.Length); + Assert.AreEqual (expected, serialized, "Serialized"); + } } [Test] @@ -277,6 +302,25 @@ public void TestContentMd5 () Assert.Throws (() => part.ComputeContentMd5 ()); Assert.IsFalse (part.VerifyContentMd5 ()); + + part = new TextPart ("plain") { Text = "Hello, World.\n\nLet's check the MD5 sum of this text!\n" }; + + var md5sum = part.ComputeContentMd5 (); + + Assert.AreEqual ("8criUiOQmpfifOuOmYFtEQ==", md5sum, "ComputeContentMd5 text/*"); + + // re-encode the base64'd md5sum using a hex encoding so we can easily compare to the output of `md5sum` command-line tools + var decoded = Convert.FromBase64String (md5sum); + var encoded = new StringBuilder (); + + for (int i = 0; i < decoded.Length; i++) + encoded.Append (decoded[i].ToString ("x2")); + + Assert.AreEqual ("f1cae25223909a97e27ceb8e99816d11", encoded.ToString (), "md5sum text/*"); + + part.ContentMd5 = md5sum; + + Assert.IsTrue (part.VerifyContentMd5 (), "VerifyContentMd5"); } [Test] @@ -307,10 +351,43 @@ public void TestContentTransferEncoding () Assert.AreEqual (ContentEncoding.Default, part.ContentTransferEncoding, "Expected ContentTransferEncoding to be default again"); } + [Test] + public void TestPrepare () + { + using (var content = new MemoryStream (new byte[64], false)) { + var part = new MimePart ("application/octet-stream") { + Content = new MimeContent (content) + }; + + var encoding = part.GetBestEncoding (EncodingConstraint.SevenBit); + + Assert.AreEqual (ContentEncoding.Base64, encoding, "GetBestEncoding"); + + part.Prepare (EncodingConstraint.SevenBit); + + Assert.AreEqual (ContentEncoding.Base64, part.ContentTransferEncoding, "Prepare #1"); + + // now make sure that calling Prepare() again doesn't change anything + + part.Prepare (EncodingConstraint.SevenBit); + + Assert.AreEqual (ContentEncoding.Base64, part.ContentTransferEncoding, "Prepare #2"); + + part.ContentTransferEncoding = ContentEncoding.Binary; + part.Prepare (EncodingConstraint.None); + + Assert.AreEqual (ContentEncoding.Binary, part.ContentTransferEncoding, "Prepare #3"); + + part.Prepare (EncodingConstraint.SevenBit); + + Assert.AreEqual (ContentEncoding.Base64, part.ContentTransferEncoding, "Prepare #4"); + } + } + [Test] public void TestTranscoding () { - var path = Path.Combine ("..", "..", "TestData", "images", "girl.jpg"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); var expected = File.ReadAllBytes (path); var part = new MimePart ("image", "jpeg") { @@ -350,9 +427,9 @@ public void TestTranscoding () } [Test] - public async void TestTranscodingAsync () + public async Task TestTranscodingAsync () { - var path = Path.Combine ("..", "..", "TestData", "images", "girl.jpg"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "images", "girl.jpg"); var expected = File.ReadAllBytes (path); var part = new MimePart ("image", "jpeg") { @@ -398,6 +475,7 @@ public void TestWriteTo (string text) var builder = new BodyBuilder (); builder.Attachments.Add ("filename", new MemoryStream (Encoding.UTF8.GetBytes (text))); + builder.TextBody = "This is the text body."; var body = builder.ToMessageBody (); @@ -409,7 +487,7 @@ public void TestWriteTo (string text) stream.Position = 0; var multipart = (Multipart) MimeEntity.Load (stream); - using (var input = ((MimePart) multipart[0]).Content.Open ()) { + using (var input = ((MimePart) multipart[1]).Content.Open ()) { var buffer = new byte[1024]; int n; @@ -424,11 +502,12 @@ public void TestWriteTo (string text) [TestCase ("content", TestName = "TestWriteToNoNewLine")] [TestCase ("content\r\n", TestName = "TestWriteToNewLine")] - public async void TestWriteToAsync (string text) + public async Task TestWriteToAsync (string text) { var builder = new BodyBuilder (); builder.Attachments.Add ("filename", new MemoryStream (Encoding.UTF8.GetBytes (text))); + builder.TextBody = "This is the text body."; var body = builder.ToMessageBody (); @@ -440,7 +519,7 @@ public async void TestWriteToAsync (string text) stream.Position = 0; var multipart = (Multipart) await MimeEntity.LoadAsync (stream); - using (var input = ((MimePart) multipart[0]).Content.Open ()) { + using (var input = ((MimePart) multipart[1]).Content.Open ()) { var buffer = new byte[1024]; int n; @@ -452,5 +531,39 @@ public async void TestWriteToAsync (string text) } } } + + [Test] + public void TestLoadHttpWebResponse () + { + var text = "This is some text and stuff." + Environment.NewLine; + var contentType = new ContentType ("text", "plain"); + + using (var content = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var entity = MimeEntity.Load (contentType, content); + + Assert.IsInstanceOf (entity); + + var part = (TextPart) entity; + + Assert.AreEqual (text, part.Text); + } + } + + [Test] + public async Task TestLoadHttpWebResponseAsync () + { + var text = "This is some text and stuff." + Environment.NewLine; + var contentType = new ContentType ("text", "plain"); + + using (var content = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { + var entity = await MimeEntity.LoadAsync (contentType, content); + + Assert.IsInstanceOf (entity); + + var part = (TextPart) entity; + + Assert.AreEqual (text, part.Text); + } + } } } diff --git a/UnitTests/MimeTypeTests.cs b/UnitTests/MimeTypeTests.cs index 9a03c150ce..4e9e26e269 100644 --- a/UnitTests/MimeTypeTests.cs +++ b/UnitTests/MimeTypeTests.cs @@ -1,9 +1,9 @@ -// +// // MimeTypeTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -35,27 +35,82 @@ namespace UnitTests { public class MimeTypeTests { [Test] - public void TestNullFileName () + public void TestArgumentExceptions () + { + Assert.Throws (() => MimeTypes.GetMimeType (null)); + Assert.Throws (() => MimeTypes.Register (null, ".ext")); + Assert.Throws (() => MimeTypes.Register (string.Empty, ".ext")); + Assert.Throws (() => MimeTypes.Register ("text/plain", null)); + Assert.Throws (() => MimeTypes.Register ("text/plain", string.Empty)); + Assert.Throws (() => MimeTypes.TryGetExtension (null, out _)); + } + + [Test] + public void TestGetMimeTypeNullFileName () { Assert.Throws (() => MimeTypes.GetMimeType (null)); } [Test] - public void TestNoFileExtension () + public void TestGetMimeTypeNoFileExtension () { Assert.AreEqual ("application/octet-stream", MimeTypes.GetMimeType ("filename")); } [Test] - public void TestFileNameDot () + public void TestGetMimeTypeFileNameDot () { Assert.AreEqual ("application/octet-stream", MimeTypes.GetMimeType ("filename.")); } [Test] - public void TestFileExtensionTxt () + public void TestGetMimeTypeFileExtensionTxt () { Assert.AreEqual ("text/plain", MimeTypes.GetMimeType ("filename.txt")); } + + [Test] + public void TestGetMimeTypeFileExtensionCsv () + { + Assert.AreEqual ("text/csv", MimeTypes.GetMimeType ("filename.csv")); + } + + [Test] + public void TestTryGetExtensionTextPlain () + { + string extension; + + Assert.IsTrue (MimeTypes.TryGetExtension ("text/plain", out extension)); + Assert.AreEqual (".txt", extension); + } + + [Test] + public void TestTryGetExtensionUnknownMimeType () + { + string extension; + + Assert.IsFalse (MimeTypes.TryGetExtension ("application/x-vnd.fake-mime-type", out extension)); + } + + [Test] + public void TestMimeTypeRegister () + { + string extension; + + Assert.AreEqual ("application/octet-stream", MimeTypes.GetMimeType ("message.msg")); + Assert.False (MimeTypes.TryGetExtension ("application/vnd.ms-outlook", out extension)); + + MimeTypes.Register ("application/vnd.ms-outlook", ".msg"); + + Assert.AreEqual ("application/vnd.ms-outlook", MimeTypes.GetMimeType ("message.msg")); + Assert.True (MimeTypes.TryGetExtension ("application/vnd.ms-outlook", out extension)); + Assert.AreEqual (".msg", extension); + + MimeTypes.Register ("application/bogus", "bogus"); + + Assert.AreEqual ("application/bogus", MimeTypes.GetMimeType ("fileName.bogus")); + Assert.True (MimeTypes.TryGetExtension ("application/bogus", out extension)); + Assert.AreEqual (".bogus", extension); + } } } diff --git a/UnitTests/MimeVisitorTests.cs b/UnitTests/MimeVisitorTests.cs index 3d2050943f..521b4bcad9 100644 --- a/UnitTests/MimeVisitorTests.cs +++ b/UnitTests/MimeVisitorTests.cs @@ -1,9 +1,9 @@ -// +// // MimeVisitorTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,10 +27,13 @@ using System; using System.IO; using System.Text; +using System.Globalization; using NUnit.Framework; using MimeKit; +using MimeKit.Tnef; +using MimeKit.Cryptography; namespace UnitTests { [TestFixture] @@ -39,7 +42,7 @@ public class MimeVisitorTests [Test] public void TestMimeVisitor () { - var dataDir = Path.Combine ("..", "..", "TestData", "mbox"); + var dataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "mbox"); var visitor = new HtmlPreviewVisitor (); int index = 0; @@ -47,7 +50,7 @@ public void TestMimeVisitor () var parser = new MimeParser (stream, MimeFormat.Mbox); while (!parser.IsEndOfStream) { - var filename = string.Format ("jwz.body.{0}.html", index); + var filename = string.Format (CultureInfo.InvariantCulture, "jwz.body.{0}.html", index); var path = Path.Combine (dataDir, filename); var message = parser.ParseMessage (); string expected, actual; @@ -77,5 +80,246 @@ public void TestMimeVisitor () } } } + + class MimeVisitorTester : MimeVisitor + { + public int ApplicationPgpEncrypted; + public int ApplicationPgpSignature; + public int ApplicationPkcs7Mime; + public int ApplicationPkcs7Signature; + public int Message; + public int MessageDeliveryStatus; + public int MessageDispositionNotification; + public int MessagePart; + public int MessagePartial; + public int MimeEntity; + public int MimeMessage; + public int MimePart; + public int Multipart; + public int MultipartAlternative; + public int MultipartEncrypted; + public int MultipartRelated; + public int MultipartReport; + public int MultipartSigned; + public int TextPart; + public int TextRfc822Headers; + public int TnefPart; + + protected internal override void VisitApplicationPgpEncrypted (ApplicationPgpEncrypted entity) + { + ApplicationPgpEncrypted++; + base.VisitApplicationPgpEncrypted (entity); + } + + protected internal override void VisitApplicationPgpSignature (ApplicationPgpSignature entity) + { + ApplicationPgpSignature++; + base.VisitApplicationPgpSignature (entity); + } + + protected internal override void VisitApplicationPkcs7Mime (ApplicationPkcs7Mime entity) + { + ApplicationPkcs7Mime++; + base.VisitApplicationPkcs7Mime (entity); + } + + protected internal override void VisitApplicationPkcs7Signature (ApplicationPkcs7Signature entity) + { + ApplicationPkcs7Signature++; + base.VisitApplicationPkcs7Signature (entity); + } + + protected override void VisitMessage (MessagePart entity) + { + Message++; + base.VisitMessage (entity); + } + + protected internal override void VisitMessageDeliveryStatus (MessageDeliveryStatus entity) + { + MessageDeliveryStatus++; + base.VisitMessageDeliveryStatus (entity); + } + + protected internal override void VisitMessageDispositionNotification (MessageDispositionNotification entity) + { + MessageDispositionNotification++; + base.VisitMessageDispositionNotification (entity); + } + + protected internal override void VisitMessagePart (MessagePart entity) + { + MessagePart++; + base.VisitMessagePart (entity); + } + + protected internal override void VisitMessagePartial (MessagePartial entity) + { + MessagePartial++; + base.VisitMessagePartial (entity); + } + + protected internal override void VisitMimeEntity (MimeEntity entity) + { + MimeEntity++; + base.VisitMimeEntity (entity); + } + + protected internal override void VisitMimeMessage (MimeMessage message) + { + MimeMessage++; + base.VisitMimeMessage (message); + } + + protected internal override void VisitMimePart (MimePart entity) + { + MimePart++; + base.VisitMimePart (entity); + } + + protected internal override void VisitMultipart (Multipart multipart) + { + Multipart++; + base.VisitMultipart (multipart); + } + + protected internal override void VisitMultipartAlternative (MultipartAlternative alternative) + { + MultipartAlternative++; + base.VisitMultipartAlternative (alternative); + } + + protected internal override void VisitMultipartEncrypted (MultipartEncrypted encrypted) + { + MultipartEncrypted++; + base.VisitMultipartEncrypted (encrypted); + } + + protected internal override void VisitMultipartRelated (MultipartRelated related) + { + MultipartRelated++; + base.VisitMultipartRelated (related); + } + + protected internal override void VisitMultipartReport (MultipartReport report) + { + MultipartReport++; + base.VisitMultipartReport (report); + } + + protected internal override void VisitMultipartSigned (MultipartSigned signed) + { + MultipartSigned++; + base.VisitMultipartSigned (signed); + } + + protected internal override void VisitTextPart (TextPart entity) + { + TextPart++; + base.VisitTextPart (entity); + } + + protected internal override void VisitTextRfc822Headers (TextRfc822Headers entity) + { + TextRfc822Headers++; + base.VisitTextRfc822Headers (entity); + } + + protected internal override void VisitTnefPart (TnefPart entity) + { + TnefPart++; + base.VisitTnefPart (entity); + } + } + + [Test] + public void TestVisitorMethods () + { + var message = new MimeMessage (); + message.Body = new MultipartSigned () { + new Multipart ("mixed") { + new MultipartAlternative () { + new TextPart ("plain"), + new MultipartRelated () { + new TextPart ("html"), + new MimePart ("image", "jpeg") + } + }, + new TnefPart (), + new MessagePart () { + Message = new MimeMessage () { + Body = new MultipartReport ("delivery-status") { + new MessageDeliveryStatus (), + new TextRfc822Headers () + } + } + }, + new MessagePart () { + Message = new MimeMessage () { + Body = new MultipartReport ("disposition-notification") { + new MessageDispositionNotification () + } + } + }, + new MessagePartial ("id", 1, 1), + new ApplicationPkcs7Mime (SecureMimeType.SignedData, Stream.Null), + new ApplicationPkcs7Signature (Stream.Null), + new MultipartEncrypted () { + new MimePart ("application", "octet-stream"), + new ApplicationPgpEncrypted () + } + }, + new ApplicationPgpSignature (Stream.Null) + }; + var visitor = new MimeVisitorTester (); + + visitor.Visit (message); + Assert.AreEqual (1, visitor.ApplicationPgpEncrypted); + Assert.AreEqual (1, visitor.ApplicationPgpSignature); + Assert.AreEqual (1, visitor.ApplicationPkcs7Mime); + Assert.AreEqual (1, visitor.ApplicationPkcs7Signature); + Assert.AreEqual (3, visitor.Message); + Assert.AreEqual (1, visitor.MessageDeliveryStatus); + Assert.AreEqual (1, visitor.MessageDispositionNotification); + Assert.AreEqual (3, visitor.MessagePart); + Assert.AreEqual (1, visitor.MessagePartial); + Assert.AreEqual (22, visitor.MimeEntity); + Assert.AreEqual (3, visitor.MimeMessage); + Assert.AreEqual (12, visitor.MimePart); + Assert.AreEqual (7, visitor.Multipart); + Assert.AreEqual (1, visitor.MultipartAlternative); + Assert.AreEqual (1, visitor.MultipartEncrypted); + Assert.AreEqual (1, visitor.MultipartRelated); + Assert.AreEqual (2, visitor.MultipartReport); + Assert.AreEqual (1, visitor.MultipartSigned); + Assert.AreEqual (2, visitor.TextPart); + Assert.AreEqual (1, visitor.TextRfc822Headers); + Assert.AreEqual (1, visitor.TnefPart); + + visitor = new MimeVisitorTester (); + + visitor.Visit (message.Body); + Assert.AreEqual (1, visitor.ApplicationPgpEncrypted); + Assert.AreEqual (1, visitor.ApplicationPgpSignature); + Assert.AreEqual (1, visitor.ApplicationPkcs7Mime); + Assert.AreEqual (1, visitor.ApplicationPkcs7Signature); + Assert.AreEqual (3, visitor.Message); + Assert.AreEqual (1, visitor.MessageDeliveryStatus); + Assert.AreEqual (1, visitor.MessageDispositionNotification); + Assert.AreEqual (3, visitor.MessagePart); + Assert.AreEqual (1, visitor.MessagePartial); + Assert.AreEqual (22, visitor.MimeEntity); + Assert.AreEqual (2, visitor.MimeMessage); + Assert.AreEqual (12, visitor.MimePart); + Assert.AreEqual (7, visitor.Multipart); + Assert.AreEqual (1, visitor.MultipartAlternative); + Assert.AreEqual (1, visitor.MultipartEncrypted); + Assert.AreEqual (1, visitor.MultipartRelated); + Assert.AreEqual (2, visitor.MultipartReport); + Assert.AreEqual (1, visitor.MultipartSigned); + Assert.AreEqual (2, visitor.TextPart); + Assert.AreEqual (1, visitor.TextRfc822Headers); + Assert.AreEqual (1, visitor.TnefPart); + } } } diff --git a/UnitTests/MultipartAlternativeTests.cs b/UnitTests/MultipartAlternativeTests.cs new file mode 100644 index 0000000000..f2d4bab563 --- /dev/null +++ b/UnitTests/MultipartAlternativeTests.cs @@ -0,0 +1,73 @@ +// +// MultipartAlternativeTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +using NUnit.Framework; + +using MimeKit; +using MimeKit.Text; + +namespace UnitTests { + [TestFixture] + public class MultipartAlternativeTests + { + [Test] + public void TestArgumentExceptions () + { + var alternative = new MultipartAlternative (); + + Assert.Throws (() => new MultipartAlternative ((MimeEntityConstructorArgs) null)); + Assert.Throws (() => alternative.Accept (null)); + } + + [Test] + public void TestGetTextBody () + { + var alternative = new MultipartAlternative (); + var plain = new TextPart ("plain") { Text = "plain\n" }; + var flowed = new TextPart (TextFormat.Flowed) { Text = "flowed\n" }; + var richtext = new TextPart ("rtf") { Text = "rtf\n" }; + var html = new TextPart ("html") { Text = "html\n" }; + + alternative.Add (plain); + alternative.Add (richtext); + alternative.Add (html); + + Assert.AreEqual ("plain\n", alternative.TextBody.Replace ("\r\n", "\n"), "TextBody"); + Assert.AreEqual ("html\n", alternative.HtmlBody.Replace ("\r\n", "\n"), "HtmlBody"); + + alternative.Insert (1, flowed); + + // Note: GetTextBody (Plain) returns Flowed because Flowed is also Plain and is listed after the text/plain part + Assert.AreEqual ("flowed\n", alternative.GetTextBody (TextFormat.Plain).Replace ("\r\n", "\n"), "Plain"); + Assert.AreEqual ("flowed\n", alternative.GetTextBody (TextFormat.Flowed).Replace ("\r\n", "\n"), "Flowed"); + Assert.AreEqual ("rtf\n", alternative.GetTextBody (TextFormat.RichText).Replace ("\r\n", "\n"), "RichText"); + Assert.AreEqual ("html\n", alternative.GetTextBody (TextFormat.Html).Replace ("\r\n", "\n"), "Html"); + Assert.IsNull (alternative.GetTextBody (TextFormat.Enriched), "Enriched"); + } + } +} diff --git a/UnitTests/MultipartRelatedTests.cs b/UnitTests/MultipartRelatedTests.cs index f43e125177..2c176e17a1 100644 --- a/UnitTests/MultipartRelatedTests.cs +++ b/UnitTests/MultipartRelatedTests.cs @@ -1,9 +1,9 @@ -// +// // MultipartRelatedTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -77,7 +77,8 @@ public void TestDocumentRoot () Assert.AreEqual (3, related.Count, "Count"); Assert.AreEqual (root, related.Root, "Root"); Assert.AreEqual (root, related[2], "Root should be the 3rd item."); - Assert.IsNotNullOrEmpty (root.ContentId, "Root's Content-Id should not be null."); + Assert.IsNotNull (root.ContentId, "Root's Content-Id should not be null."); + Assert.IsNotEmpty (root.ContentId, "Root's Content-Id should not be empty."); start = "<" + root.ContentId + ">"; @@ -96,6 +97,24 @@ public void TestDocumentRoot () Assert.IsNull (related.ContentType.Parameters["start"], "The start parameter should be null."); } + [Test] + public void TestDocumentRootByType () + { + var related = (MultipartRelated) MimeEntity.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "messages", "multipart-related-mhtml.txt")); + + Assert.AreEqual (2, related.Count, "Count"); + + var image = related[0]; + + Assert.AreEqual ("image/png", image.ContentType.MimeType, "related[0]"); + + var html = related[1]; + + Assert.AreEqual ("text/html", html.ContentType.MimeType, "related[1]"); + + Assert.AreEqual (html, related.Root, "Root"); + } + [Test] public void TestReferenceByContentId () { @@ -125,7 +144,7 @@ public void TestReferenceByContentId () // Note: MimeKit no longer sets the "start" parameter if the root is the first MIME part due to a bug in Thunderbird. Assert.IsNull (related.ContentType.Parameters["start"], "The start parameter should be null."); - for (int i = 0; i < related.Count; i++) { + for (int i = 1; i < related.Count; i++) { var cid = new Uri (string.Format ("cid:{0}", related[i].ContentId)); string mimeType, charset; diff --git a/UnitTests/MultipartReportTests.cs b/UnitTests/MultipartReportTests.cs index 4f4bdb899e..77dd1ba449 100644 --- a/UnitTests/MultipartReportTests.cs +++ b/UnitTests/MultipartReportTests.cs @@ -1,9 +1,9 @@ -// +// // MultipartReportTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,6 +48,14 @@ public void TestArgumentExceptions () Assert.Throws (() => report.Accept (null)); } + + [Test] + public void TestParamCtor () + { + var report = new MultipartReport ("disposition-notification", new MimePart ()); + + Assert.AreEqual (1, report.Count); + } } } diff --git a/UnitTests/MultipartTests.cs b/UnitTests/MultipartTests.cs index 73f79e30fa..f97bba736d 100644 --- a/UnitTests/MultipartTests.cs +++ b/UnitTests/MultipartTests.cs @@ -1,9 +1,9 @@ -// +// // MultipartTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -79,18 +79,18 @@ public void TestArgumentExceptions () Assert.Throws (() => multipart.WriteTo (null, "fileName", false)); Assert.Throws (() => multipart.WriteTo (FormatOptions.Default, (string) null, false)); - Assert.Throws (async () => await multipart.WriteToAsync ((string) null)); - Assert.Throws (async () => await multipart.WriteToAsync ((Stream) null)); - Assert.Throws (async () => await multipart.WriteToAsync ((string) null, false)); - Assert.Throws (async () => await multipart.WriteToAsync ((Stream) null, false)); - Assert.Throws (async () => await multipart.WriteToAsync (null, Stream.Null)); - Assert.Throws (async () => await multipart.WriteToAsync (FormatOptions.Default, (Stream) null)); - Assert.Throws (async () => await multipart.WriteToAsync (null, "fileName")); - Assert.Throws (async () => await multipart.WriteToAsync (FormatOptions.Default, (string) null)); - Assert.Throws (async () => await multipart.WriteToAsync (null, Stream.Null, false)); - Assert.Throws (async () => await multipart.WriteToAsync (FormatOptions.Default, (Stream) null, false)); - Assert.Throws (async () => await multipart.WriteToAsync (null, "fileName", false)); - Assert.Throws (async () => await multipart.WriteToAsync (FormatOptions.Default, (string) null, false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync ((string) null)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync ((Stream) null)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync ((string) null, false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync ((Stream) null, false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (null, Stream.Null)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (FormatOptions.Default, (Stream) null)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (null, "fileName")); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (FormatOptions.Default, (string) null)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (null, Stream.Null, false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (FormatOptions.Default, (Stream) null, false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (null, "fileName", false)); + Assert.ThrowsAsync (async () => await multipart.WriteToAsync (FormatOptions.Default, (string) null, false)); } [Test] @@ -98,7 +98,8 @@ public void TestBasicFunctionality () { var multipart = new Multipart (); - Assert.IsNotNullOrEmpty (multipart.Boundary, "Boundary"); + Assert.IsNotNull (multipart.Boundary, "Boundary != null"); + Assert.IsNotEmpty (multipart.Boundary, "Boundary"); Assert.IsFalse (multipart.IsReadOnly, "IsReadOnly"); multipart.Boundary = "__Next_Part_123"; diff --git a/UnitTests/Npgsql.dll b/UnitTests/Npgsql.dll deleted file mode 100644 index 1aeb4cfd0a..0000000000 Binary files a/UnitTests/Npgsql.dll and /dev/null differ diff --git a/UnitTests/ParameterListTests.cs b/UnitTests/ParameterListTests.cs index c59a3f5f68..970e308c4b 100644 --- a/UnitTests/ParameterListTests.cs +++ b/UnitTests/ParameterListTests.cs @@ -1,9 +1,9 @@ -// +// // ParameterListTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -60,6 +60,11 @@ public void TestArgumentExceptions () Assert.Throws (() => list.Add ("name", null)); Assert.Throws (() => list.Add (null)); + list.Add ("name", "x-value"); + Assert.Throws (() => list.Add ("name", "value")); + Assert.Throws (() => list.Add (new Parameter ("name", "value"))); + list.Clear (); + // Contains Assert.Throws (() => list.Contains ((Parameter) null)); Assert.Throws (() => list.Contains ((string) null)); @@ -73,7 +78,7 @@ public void TestArgumentExceptions () Assert.Throws (() => list.IndexOf ((string) null)); // Insert - list.Add ("name", "value"); + list.Add ("x-name", "value"); Assert.Throws (() => list.Insert (-1, new Parameter ("name", "value"))); Assert.Throws (() => list.Insert (-1, "field", "value")); Assert.Throws (() => list.Insert (0, null, "value")); @@ -81,6 +86,9 @@ public void TestArgumentExceptions () Assert.Throws (() => list.Insert (0, invalid, "value")); Assert.Throws (() => list.Insert (0, "name", null)); Assert.Throws (() => list.Insert (0, null)); + Assert.Throws (() => list.Insert (0, "x-name", "x-value")); + Assert.Throws (() => list.Insert (0, new Parameter ("x-name", "x-value"))); + list.Clear (); // Remove Assert.Throws (() => list.Remove ((Parameter) null)); @@ -94,12 +102,16 @@ public void TestArgumentExceptions () Assert.Throws (() => list.TryGetValue (null, out value)); // Indexers + list.Add ("name", "value"); + list.Add ("x-name", "x-value"); Assert.Throws (() => list[-1] = new Parameter ("name", "value")); Assert.Throws (() => param = list[-1]); Assert.Throws (() => list[0] = null); Assert.Throws (() => list[null] = "value"); Assert.Throws (() => value = list[null]); Assert.Throws (() => list["name"] = null); + Assert.Throws (() => list[1] = new Parameter ("name", "value")); + list.Clear (); } [Test] @@ -175,6 +187,14 @@ public void TestBasicFunctionality () Assert.AreEqual (3, list.Count); Assert.AreEqual ("; abc=\"0\"; def=\"1\"; ghi=\"2\"", list.ToString ()); + + list[0] = new Parameter ("abc", "replaced"); + + Assert.AreEqual ("; abc=\"replaced\"; def=\"1\"; ghi=\"2\"", list.ToString ()); + + list[0] = new Parameter ("xxx", "0"); + + Assert.AreEqual ("; xxx=\"0\"; def=\"1\"; ghi=\"2\"", list.ToString ()); } } } diff --git a/UnitTests/ParameterTests.cs b/UnitTests/ParameterTests.cs index efad610127..d87ea4659a 100644 --- a/UnitTests/ParameterTests.cs +++ b/UnitTests/ParameterTests.cs @@ -1,9 +1,9 @@ -// +// // ParameterTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/ParserOptionsTests.cs b/UnitTests/ParserOptionsTests.cs index a057683cba..ce6da9827e 100644 --- a/UnitTests/ParserOptionsTests.cs +++ b/UnitTests/ParserOptionsTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ using System; using System.IO; +using System.Threading.Tasks; using NUnit.Framework; @@ -85,7 +86,7 @@ public void TestParsingOfCustomType () } [Test] - public async void TestParsingOfCustomTypeAsync () + public async Task TestParsingOfCustomTypeAsync () { var options = ParserOptions.Default.Clone (); diff --git a/UnitTests/TestData/dkim/rfc8463-example.msg b/UnitTests/TestData/dkim/rfc8463-example.msg new file mode 100644 index 0000000000..a3397f2d4e --- /dev/null +++ b/UnitTests/TestData/dkim/rfc8463-example.msg @@ -0,0 +1,26 @@ +DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; + d=football.example.com; i=@football.example.com; + q=dns/txt; s=brisbane; t=1528637909; h=from : to : + subject : date : message-id : from : subject : date; + bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; + b=/gCrinpcQOoIfuHNQIbq4pgh9kyIK3AQUdt9OdqQehSwhEIug4D11Bus + Fa3bT3FY5OsU7ZbnKELq+eXdp1Q1Dw== +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=football.example.com; i=@football.example.com; + q=dns/txt; s=test; t=1528637909; h=from : to : subject : + date : message-id : from : subject : date; + bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; + b=F45dVWDfMbQDGHJFlXUNB2HKfbCeLRyhDXgFpEL8GwpsRe0IeIixNTe3 + DhCVlUrSjV4BwcVcOF6+FF3Zo9Rpo1tFOeS9mPYQTnGdaSGsgeefOsk2Jz + dA+L10TeYt9BgDfQNZtKdN1WO//KgIqXP7OdEFE4LjFYNcUxZQ4FADY+8= +From: Joe SixPack +To: Suzie Q +Subject: Is dinner ready? +Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT) +Message-ID: <20030712040037.46341.5F8J@football.example.com> + +Hi. + +We lost the game. Are you hungry yet? + +Joe. diff --git a/UnitTests/TestData/encoders/photo.uu-states b/UnitTests/TestData/encoders/photo.uu-states new file mode 100644 index 0000000000..711ecb3ddc --- /dev/null +++ b/UnitTests/TestData/encoders/photo.uu-states @@ -0,0 +1,2905 @@ +x +bx +bex +begx +begix +beginx +begin 644 photo.jpg +M_]C_X``02D9)1@`!`0$`2`!(``#_X@Q824-#7U!23T9)3$4``0$```Q(3&EN +M;P(0``!M;G1R4D="(%A96B`'S@`"``D`!@`Q``!A8W-P35-&5`````!)14,@ +M0``9&5S8P`````````2D! +M\@'Z`@,"#`(4`AT")@(O`C@"00)+`E0"70)G`G$">@*$`HX"F`*B`JP"M@+! +M`LL"U0+@`NL"]0,``PL#%@,A`RT#.`-#`T\#6@-F`W(#?@.*`Y8#H@.N`[H# +MQP/3`^`#[`/Y!`8$$P0@!"T$.P1(!%4$8P1Q!'X$C`2:!*@$M@3$!-,$X03P +M!/X%#044%]@8&!A8&)P8W!D@& +M609J!GL&C`:=!J\&P`;1!N,&]0<'!QD'*P<]!T\'80=T!X8'F0>L![\'T@?E +M!_@("P@?"#((1@A:"&X(@@B6"*H(O@C2".<(^PD0"24).@E/"60)>0F/":0) +MN@G/">4)^PH1"B<*/0I4"FH*@0J8"JX*Q0K<"O,+"PLB"SD+40MI"X`+F`NP +M"\@+X0OY#!(,*@Q##%P,=0R.#*<,P`S9#/,-#0TF#4`-6@UT#8X-J0W##=X- +M^`X3#BX.20YD#G\.FPZV#M(.[@\)#R4/00]>#WH/E@^S#\\/[!`)$"800Q!A +M$'X0FQ"Y$-<0]1$3$3$13Q%M$8P1JA')$>@2!Q(F$D429!*$$J,2PQ+C$P,3 +M(Q-#$V,3@Q.D$\43Y10&%"<4211J%(L4K13.%/`5$A4T%585>!6;%;T5X!8# +M%B86219L%H\6LA;6%OH7'1=!%V47B1>N%](7]Q@;&$`891B*&*\8U1CZ&2`9 +M11EK&9$9MQG=&@0:*AI1&G<:GAK%&NP;%!L[&V,;BANR&]H<`APJ'%(<>QRC +M',P<]1T>'4<=:AZ4'KX>Z1\3'SX?:1^4'[\?ZB`5($$@ +M;""8(,0@\"$<(4@A=2&A(B>K)]PH#2@_*'$H +MHBC4*08I."EK*9TIT"H"*C4J:"J;*L\K`BLV*VDKG2O1+`4L.2QN+*(LURT, +M+4$M=BVK+>$N%BY,+H(NMR[N+R0O6B^1+\<-]1B)&9T:K1O!'-4=[1\!( +M!4A+2)%(UTD=26-)J4GP2C=*?4K$2PQ+4TN:2^),*DQR3+I-`DU*39--W$XE +M3FY.MT\`3TE/DT_=4"=0<5"[40914%&;4>92,5)\4L=3$U-?4ZI3]E1"5(]4 +MVU4H5755PE8/5EQ6J5;W5T17DE?@6"]8?5C+61I9:5FX6@=:5EJF6O5;15N5 +M6^5<-5R&7-9=)UUX7&EYL7KU?#U]A7[-@!6!78*I@_&%/8:)A]6))8IQB +M\&-#8Y=CZV1`9)1DZ64]99)EYV8]9I)FZ&<]9Y-GZ6@_:)9H[&E#:9II\6I( +M:I]J]VM/:Z=K_VQ7;*]M"&U@;;EN$FYK;L1O'F]X;]%P*W"&<.!Q.G&5&YXS'DJ>8EYYWI& +M>J5[!'MC>\)\(7R!?.%]07VA?@%^8G["?R-_A'_E@$>`J($*@6N!S8(P@I*" +M](-7@[J$'82`A..%1X6KA@Z&I+CDTV3MI0@E(J4 +M])5?EAMJ(FHI:C!J-VH^:D5J3'I3BEJ:8:IHNF_:=NI^"H +M4JC$J3>IJ:H_ +MR#W(O,DZR;G*.,JWRS;+MLPUS+7--:6YQ_GJ>@RZ+SI1NG0ZEOJ +MY>MPZ_OLANT1[9SN*.ZT[T#OS/!8\.7Q.$))30/S```````)```````````!`#A"24TG$```````"@`!```````` +M``(X0DE-`_4``````$@`+V9F``$`;&9F``8```````$`+V9F``$`H9F:``8` +M``````$`,@````$`6@````8```````$`-0````$`+0````8```````$X0DE- +M`_@``````'```/____________________________\#Z`````#_________ +M____________________`^@`````_____________________________P/H +M`````/____________________________\#Z```.$))300````````"``,X +M0DE-!`(```````@``````````#A"24T$,```````!`$!`0$X0DE-!"T````` +M``8``0```!LX0DE-!`@``````!`````!```"0````D``````.$))300>```` +M```$`````#A"24T$&@`````#10````8`````````````$I````Q@````"`!) +M`$T`1P!?`#(`-``T`#`````!``````````````````````````$````````` +M````#&```!*0``````````````````````$````````````````````````` +M$`````$```````!N=6QL`````@````9B;W5N9'-/8FIC`````0```````%)C +M=#$````$`````%1O<"!L;VYG``````````!,969T;&]N9P``````````0G1O +M;6QO;F<``!*0`````%)G:'1L;VYG```,8`````9S;&EC97-6;$QS`````4]B +M:F,````!```````%7!E96YU;0````I%4VQI8V54>7!E```` +M`$EM9R`````&8F]U;F1S3V)J8P````$```````!28W0Q````!`````!4;W`@ +M;&]N9P``````````3&5F=&QO;F<``````````$)T;VUL;VYG```2D`````!2 +M9VAT;&]N9P``#&`````#=7)L5$585`````$```````!N=6QL5$585`````$` +M``````!-'1415A4`````0``````"6AO +MD%L:6=N````!V1E9F%U;'0````) +M=F5R=$%L:6=N96YU;0````]%4VQI8V5697)T06QI9VX````'9&5F875L=``` +M``MB9T-O;&]R5'EP965N=6T````115-L:6-E0D=#;VQO)E\K.$P]-UX_-&)Y2DA;25 +MQ-3D]*6UQ=7E]59F=H:6IK;&UN;V-T=79W>'EZ>WQ]?G]Q$``@(!`@0$`P0% +M!@<'!@4U`0`"$0,A,1($05%A<2(3!3*!D12AL4(CP5+1\#,D8N%R@I)#4Q5C +M+RLX3#TW7C\T:4I(6TE<34Y/2E +MM<75Y?569G:&EJ:VQM;F]B7I[?'_]H`#`,!``(1`Q$`/P#M%1ZL +M/T`^*O*EU7^CCXIDMBN#CE4@8MM;XNE752_[46?%-"5&EKC+A*FVAFWZ(CP\ +M5)C7/<&M$N<8`\U?KZ<\L:7.8QKO;+B=VA]SFM']MR<+*'.%3!PT#PA.`KW4 +M7=,QL>2YM;:W`/>222#]%KG!8]W5L?U:\;$:E2 +MFXH9%U&*`[)>*@8`W3.O\D>Y8?5^M9^#99ANL:,JMQ;:S$`=L=,&BS*:^S;9 +M5_A*ZO?O_G;/4_1KG79SC8XNW!YDO;69>3X676;_`'?U4:4^@@M)<&N#BPP[ +M:08)`>/H_P`A['IX7-?5_JF-CX`%AVON>Y[GD@R1^C]P9_-^FT?1L:S_`$JW +M:,ZBX2RQK_A_=])"Q=*HIB%%2W`]P?,<***G_]#M%1ZK_1_FKRI=5_HWS39; +M%(<=4O\`#V?)70J;0/M-I/T6Q/G/9-"YMXD!X<026Q`['7=[ON1>IYUGJM:Q +MT-#>2>"=';?S=NY:/U>QAD`D`$LG>3P)6-]914S)VUZM(>`!VD>W_.VH9"1# +M1,! +MZNUU;W;&L]2K99L]1:F;9Z>&ZP09O+R/,,]_^<]KG+.OR:[),0_=M!^7M4>. +M:BTP9`T/+ +M>!_84X-L=*Q3LR6[B-MIV$G@.=]!Q_MJXVP-,M):X:D<$'Y*GQN2W4V"7@<[Q[;?\YWZ5O\`QB;(6+[)B:-.IB=>R*X:\BQO\KG[UI_M +MVJ/H&=LQI]*?H_U=OYRY;TR8R>H.LS@^=&'GXG;_WY +M8&W_`*A&(X_>Y_P"DL_!RC6X=FGD>!XW! +M:OKXL?1'T=T2.9_\]?G*/A/%7=?8X;?_TNT5+JO\PKJI=4_F"@=BD./W5CZN +MOM_:.;2UT5NHWO'8EGT?^K<@,8]]C:ZVE[WG:U@Y)/8)W658)M90X6Y%HVWW +M`^T-/-&/_(_TM_\`AO\`B?IQF0B+^Q?"!D:'UYKK"VMQ^B--!]/7^ +M5/TD2ZNHYE.2&CU--&.X9M0=FK9CD=4NK:[:7VN8P^!.Y[%7ZB#;13]7.J-->=9S,B/2= +M^[]%WQG^JK51#0-[F[#PYT1\/I?25^>GQ&^OZ'GS,IO$;V^J[A%;_1__T^T5 +M+J?\P5<*I=3/Z%([%0S +MUPYKV/\`W3_WY7J,+'ZA:,+*9ZE%I][/E]-L_1K9Q3%<->;K45UFH]PX:*ID&IK2SNBUDTU-KF=K8E4LP$,LASP>0X1O57):;;/?KZ8V$^4?\`?4\4:*V30MQL +M>\BQK_3W`$L?P.'>UVG[JA5::O5+FBS:UY#3W=9M;_U2U,NEE6!M!!L&QX/@ +M'FVML_VD#%P:K:[B]NUU5>YVT2"1[6;F_P!=/'X+>"SHU-K&VS2W]"\;F[C` +MVQNV.U_\X>B^GC?Z-G$_2/\`F_\`J55\XBG(.)6=PJ:T/<-8MU<__-W;'*I% +M_P"\9W>/?_SE&M+6?I^QSAZK=P#A]HK/T?I;=OYBU, +M1^0+]N*X5Y-K75TV.D!KW?0]S?H[OYO?_+7/Y%74;\ASI0\6-!@P9@^"!8Z3"E315CB*V@2/<&B`H6O +M$IH`#)=HG-")4&"R3.UP+7?']Y!<[S4F/TEQX2E&TJM8T5G=QS*SQ8SUQ7,$ +MND'D3&K?\T(N;E`M+!INT,+/<&[8<1VASB0!^ZYT?FM0C'HM)U=>G#H:RUQK +M:?6!)#YYG=X^QS%GY?4:>G8]E-!8[)>00`=VTCZ-MS]?YO\`P57[ZIW"&V-< +M22`6N&Z1/QD[EDW0#`T[P$\16G)0T&I1@^XDDDSJ3J3.LDHF\^.OB@A/M="> +MPO\`_]7L'*GU$_JY"M%VL%5,^32[L!R2D=E-+I=9LZEBM[>JUQ^#3ZCO^I57 +M*MKNRKKWQNM>YYCS*LU6#$QY0\]WZYB`:F+2!Y[ +M88@30)[`G[%V,7D@#KQ3C'_&DQRG.:QTGD1'Q62X;G0%;S,@6M:YAEKP"#\1 +M_P!]5:O0?'7[N$\:!A.I4VEQ)_DZE2V(M9:`=W!$>>O^Y-O_`)/E'_?4+53_ +M`/_6ZYQ5//LIJQWWY#ME->KB.23]%C/^$>K3I[(=N)O=[?38/8VBC]VV[Z63F_P"" +MI_0T>G^F7,=0;LN=4'!Y8?>YLAN[^1/YJ[W.NKZ']5*<:K2[)&Y\NYUU7Z?G''N`N)?03#IU+9_ +M/:NG#*-NYI!:1(*Y5U.ACMJK73LU]$46'=7_`(,GMY)QU5$UH7<=Z?YN@'=9 +MN:R![?4:R?-Q*L.O#A)4JZVWX;K)]].91#?C7DN_[XHLIX82/A7^,SX! +MQ9L8_KQ_YIXGG]0`QVFR6GY$IP\=N2K/5\9U/4[*6"?4(M8/*P>I_P!%V]1K +MQFM(8/<3](^/_F*DA,2C&0_2`E]K#E@<>2<#^A(Q_P`71&UEU@WAI:S][_R* +M)Z!_M'[!C^MM] +M5V_=Z,0[^9]+U/6W3]/T/?L_ZUZB-COTMCL]G__7WK\;+ZWD6]*P[#CX5)V= +M3S&ZN<[_`,KL7^K_`-J[/^M+H,/#Z?T;#;C8C&UMK;)'@/SGV._\^6*/3J:, +M3$:VBL58[1-;#H7?G.L>YWNO:7#W.)X[D&=\?RM +M$/&RK*RXN@,:-29,#LV^K\YK?](W](S_`(130)`_%@R:GRTJ.3T6XQ5CV-OMF +M&M=-;B/^$]3VMV_UE)Q?3^7=C!Z-)F_\ +MYRASR$L.3AZ1,KV^3UMCE=,^+BT]00Y%?VO%QHVR\D^):S@_3^FK6-[GYV(\;P\ONKYC=6XOV-"`#[9 +M#M:Z`WZ>QK/T^0_;[/T=/T_45;KGUDIQ'79N3%C,W[59 +M^?\`S'^%7G_5>I]0ZQE'(RG[G6DCR:T?X-GW[G?OJO?$;9A&A3:Z]UC(ZL:# +M:]SF-S\UO\`(W=D,!@ +M3N$2(_EM]RY>Q_Z7<-08/R81E5L1D1=.RQV%ZI;#VT +MO&M.X;27?O#;[/[*CGYK?3&/22QCHE@X^W\[9O68]SPT%S#L(T\] +M3PQJ'ZS2P'Z(B),EL@_O$'Z2<("P==%EM^OJ%K8$-<1QN,QK^=_YD]&P,BRW +MJ5-CW3#]Q`T``U/];Z:R1L(VEH)81L<_7<`3W_.;_55O$R7-K=>UNUM53CN= +M^?:X\_U/H,8Q-SQ_53`&L@8?X_I9>6/Z[&3M"0F?+'ZY?]%G@9;&=2&7I%=I +M)>2Z7,+G3MK9[?YLO^FB]2?57NP9#*Z[8,@%KB#[?'<[9[G^RS>L\?:',#;; +M`UC^:^7$?G14W;_X(]7,EK++F96[TC8T;['"7RP>D[8S_!;FUML_ZXD8@9(G +MH8\/UAZH?]+*CBXL4AUC+C_P&%P+S$N,"\`/#]X<&%C:V5T(&)E9VEN +M/2+ON[\B(&ED/2)7-4TP37!#96AI2'IR95-Z3E1C>FMC.60B/SX-"CQX.GAM +M<&UE=&$@>&UL;G,Z>#TB861O8F4Z;G,Z;65T82\B('@Z>&UP=&L](D%D;V)E +M(%A-4"!#;W)E(#4N,"UC,#8P(#8Q+C$S-#&UL;G,Z=&EF9CTB +M:'1T<#HO+VYS+F%D;V)E+F-O;2]T:69F+S$N,"\B('AM;&YS.GAM<$U-/2)H +M='1P.B\O;G,N861O8F4N8V]M+WAA<"\Q+C`O;6TO(B!X;6QN7!E+U)E&EF/2)H='1P.B\O;G,N861O8F4N8V]M+V5X:68O,2XP +M+R(@>&UL;G,Z<&AO=&]S:&]P/2)H='1P.B\O;G,N861O8F4N8V]M+W!H;W1O +M&UP.F-R +M96%T;W)T;V]L/2)-:6-R;W-O9G0@5VEN9&]W&UP.D-R96%T941A=&4] +M(C(P,3$M,#(M,3E4,34Z,C&UP34TZ26YS=&%N8V5)1#TB>&UP +M+FEI9#I",#,R0CDX-3@W,T-%,#$Q.$4W-D(R030Q0S!!-#$V-2(@>&UP34TZ +M1&]C=6UE;G1)1#TB=75I9#IF868U8F1D-2UB83-D+3$Q9&$M860S,2UD,S-D +M-S4Q.#)F,6(B('AM<$U-.D]R:6=I;F%L1&]C=6UE;G1)1#TB=75I9#IF868U +M8F1D-2UB83-D+3$Q9&$M860S,2UD,S-D-S4Q.#)F,6(B(&5X:68Z17AI9E9E +M&EF +M.D-O;&]R4W!A8V4](C$B(&5X:68Z4&EX96Q81&EM96YS:6]N/2(S,38X(B!E +M>&EF.E!I>&5L641I;65N&EF.D1A=&54:6UE +M1&EG:71I>F5D/2(R,#$Q+3`R+3$Y5#$U.C(W.C4R+3`U.C`P(B!E>&EF.D5X +M<&]S=7)E5&EM93TB,2\Q,#`B(&5X:68Z1DYU;6)E&EF.E-H=71T97)3<&5E9%9A;'5E/2(T +M,S0Q-S8O-C4U,S8B(&5X:68Z07!E&EF.D5X<&]S=7)E0FEA&EF.D9O8V%L3&5N9W1H/2(X-2\Q(B!E>&EF.D9O8V%L +M4&QA;F584F5S;VQU=&EO;CTB-#&EF.E=H:71E0F%L86YC93TB,"(@97AI9CI3 +M8V5N94-A<'1U7!E/2(P(B!E>&EF.D=04U9E"UD969A=6QT(CY# +M;W!Y3PO7=O&UP34TZ2&ES=&]R>3X-"@D)"0D\&EF +M.D-O;7!O;F5N='-#;VYF:6=U&EF.D9IEB_<9Z?3[$?7VXQC9,E)RP9*Z.DY8D,`3W/WX+ +M8;6U6G@:K&J$+*Q93G8]MQ]."&-@\DD0EMK9`;36`JI8@[\+:2#V4@&1(LJZ +M:,/@W\R%1CK]]N__`)X/I$3*%I'M$C1/>YU7BA0"FV3D9'I_6_"8W3=/2)@^ +M"%JN,%3@$-['[?OXVPDK`SM`2EG>:$2DH%!*]OO_`*?]^)C#W$H=[1%D*)I` +M3G#1D@DX(&V/;@P5SN0G4@FZSZ;0<`(\5!CT`'^6/MPV<;OG1.F@+`BR,[=H +M^BBQF%2P.X]#].`W8TD3O6^J`A2<^DZ22-@8<-CT&Q^WUX2W$'-,I_\`3P"H +M"3E]32%SX(QW!/8\.NQVD(?]-((*F;9RRI)HFKYTBH;:APU0ZYZVQLD:[&1S +M[#L-V('&ZF*))DZ)3:(TYK-M^B:-I658D4(K2%BNRJ!_0X'&+<[1/]6P""IB +MEL%%"598HW4XSM_#]_#7Z@O!693$J5AMU+&`/"4@X!/K^7&C5,IRG2<7$.4C +M!#3@IB,#<#[?]^$@N(A9+3`;HLM0N&PJ].>V"/W<8V=%HD"VL>[K*QTL05.1 +MMC&<#/?A!9OE)F^8;E_%E_#AE&1MC((_TX7U9(D+=0M-@-%Q<]*C))8#&<]_ +MZ_RXQK"3!38:-ZZA'@C\);T'^G]>O"W&_"R(\$(,8Q +MV^P]?KQA!]+T&7BNLAL^955<$[>HX?:V+)MH$RNX(&!"@;]MS]?7AEC2==RP.` +M)BZQ&#G`8889QMG;A>0082P;YB5UNG5U$#)(SD`[C.?W\8QIU*QKX&4[UCF, +MD`_7(W_APIU.]^"PD@+'?*])*GJSW(SOWR.&:C9T6"3HHZENKN/?@VD\@$!)`A8\I4J"2 +M<`9P,=]^'V`$A8&YK!+K6,9:VSJ,E^D]AG)QPY38""=$W1L+JLMLF%-=RH)4 +M%MM^"L-!,!8QH:20F['.)W7\+'&PXQ\[TTV,Q7&9!+&JG8]/MCA8M=9D,74. +M]K#D]00`G&",_7?^O?@MN)$V2)B7>RLREM2JI/0`"N>PR1OWX0^J"E]6,HRZ +MK*^4`*CI)!V)^O#+W3HL[1$Z@K+@@PV",$MN,#VXR>"RH`;3HI.&DFJ(Y6BB +MZTB`>1V(5(U[99NP^GJ?3/;C`>*TU][Z+,J$AHBT$43SU@V9YDQX8[^2,[Y[ +M>9OR`[\)/`IR`=-2HJ?Q:AB93+))V'4Q8@?3/I_#C;3=-,N9*RX$$%%5R2,( +MY9>F*).HABI.6;'ML!^?"C#0DASM-2L14=BN'";[X7.=^%L(B%C0?B63T@*2 +M#DD`X`SMGW_SX27A.]:NU%#G6Z+*&003U#.V"93C/OM^?TX=U=`*02&#,=5 +M\:-6`!!;.V<;-].$NEHLG"`1+M5Q(#%L])7&Q[[?;AT-+0F@#E7%4)Z6Z=^D +M=1([_?UXTT!UBM@B#"R0JE'RV3*2X[MZX-$'*MTG'9=N^W"W.&D) +ML/+8LL@8`SDG\OZ^O"6@"X2KQ=<2BCIP`&ZLD$?3U_E[<:>#J=5C1)NOG2W2 +M,DDG/?OQLW,+67AHNLA59R05&<#[<;9(%UL@[ED=((;N(^^WL,[<8"+@;UN( +M$A8CDLP/X<$XP-L>_"F#LP=5F1VJQV``&"6`&5R-C]?X\)`O;_]?Y\$L;!)&A3>8:%`6KD!MM2`I/E]/;@ABVPS'7D:I#1!A2T:@LH(!ZA@D#&?OPG*8, +M)4APANY9$<910!A<>GM_KQA@&R6VS;+NP"?+^7WXP"T2F2W4[U_"-6.3AAG. +M0,C']8XS6R46#ZJ0M]LJ[A6T=!;X?'KJEUAAC!QU.VP!/H-\Y]`">-M@V&JP +M$S*+S):H+L*6DZ*VP6I&F3J7`N-0H`\5A[/)CI![1@#U.5AP#LPW)N[6QN]W +M][D._)BHCEN=YKI$\5V<>7KGJ6[L0-@!G.6)Q[9XVQM^U9:;/&ZQ::BBJZWP +M8C+\JO4[-(`K",;D''KV`QZXXV&M+K:%;=FB7+A6PR?,R32+X1R`$!SX8/8' +M\L#C1:)@+3P`VRQF0Q.(V*(V>Q[C;UXVYH#3F2G-RB)U7\8W+"-XFZSY0`,Y +M/L!_EQC#>0M%A'9XK.9ODU-*"IJ6&)6&X3W4?Y_NX<>Z-4XUQ!/+1?R#J#A2 +M6'8MVS]N$D'+)20\DB39]Z5>L>;?*70TD`&(;AGTRUSH_S(D1Q[0/(BZSN6O,'2?-71EEUSHJO:XZ>N +M$1:)G7IDC93AHW3]EU(P1]B-B.*Z]F0EIU4\*A<,T(W?UZ2#VQG?;VS[<-OC +M,`4\QNL\%_`_M#.>QP-^$6U-DFXMO7'H\Q0!P3V`.=M\\;RR4IKRNSH(!=F& +MY]OQ?]^%!G%-.=:RQI%(+E2!G;OPIO`)(-Y*Q9!YF9L9+8V&#]QPAA!=*4^I +M`"Z'8D=!`&=L_P"N>%@!9$0L&0E\87,?<^G3OWX3.8V2LT:J-<1ELGH?._;M +MPBH8,0MEKM%Z/.HD9(Z3ZG/<\&0F3R76!N5+$GC12&L,25\SLV"RX.`WO^[C +M24.Y?#DY)SU?4?OXVM"=0@O5BG]'RXSG!SOPQ7T(.BK; +M)XI>,$U)*E:#!$I3MU#&[=\#8>__`(X9+K63FMQ9=:G;YX=F4E@LJAG)OH!8 +MMEMAGZ^W[^"Z4`I%40>'>F[0M^J##+.2`-CM[_S_`(<(>TZ+;F3*(8NDJ%VR +M!MMMC'MPG?98)N%VA]PV67;N?7WX46$!+<>S`7)<'!92QQD#';C;8U":=`,3 +MJNY3@DY8COCW_+C(DI6*].BEC34Z@GSJ/,6)&R^F!W/9M +MK9<`M%W9`*&*V6HJJN:2KIY$G4]+((^AH@-@"O[)&`,'Z<;<"3.D+5G.DE.; +M1_+2_5%HDN5#2P_I"7"&:L(2"G38](._5(<_A`)&!Q*83`57CL"_R_="U,0U +MHE_OWO6#J#EKJ+0EFNEUN\='/2R1QE:F*3QD\1I1TJ6&RN`3Y3@\:K8!]%LO +MU]^X2FUVN,-2EHJ2HN=7#14*223N<`[G"^K,0-E'GGD-)`&NBD +M)VIJ;QZ2TQU-7,K%?FRN#CU1!Z9WW[^G"@1HS19F=$%1CT59120K4T=53EP& +M7Q(R@/VZOIQCW$6>"LIL;.<&RYQ2Q`ANQ4 +M=B"%*ID`9W4<.3+K>298!E(<4172S?[*:>MFL-?7&WZ#TG7$F@JKB>E[DHV9 +MZ2D4F>H7TZT7HSMUYXDL-LJK48*E3LLXGZ#4^"`_6L+BVF"XC6UI[]#&^)C? +M"J]S-^-WE%RM\6#0G+>IY@W>(-FMU:O7"VV.J.T4[J,`G(\:9CVRO<<2LX6@ +M8:SK#Q=8>#1]2FF4:U02YT#@-3WD&WF5K)YU?&9\8O.ZOM5ITYID26QF$%!1 +MU-%X%*?;P**(0TZG_$W4?<\1V+Z64"":M0$-W`V'@VWI*(;L)Y\#U@H\;.ZIW5XA\>ORL@FX\\]#PS2!]1)=4#3P"/_4;,%FL,\25FRXZXMU)=*)UN%O>_UUM4,&H"AL!2)823K]/W6Q2&L$JMTPO*W<]+#(_+/T/$8QX)NB:K2#W+O\6( +M@]3R4['.`XZ?;W]._"V1JM5+&PU4BZ952`2>GOZ'ATNWE-!QWKH()P2<8[=Q +M^7\N-03J$LB`NDAU!+'<'?`V^W&I@V2"6DPL20##9++L`,]]_;WXT&E+;K$+ +M#90>DYSO@9]!PJ9`/!8#N*CW(0Y\PP=CCU]N,`U@+8$B5'S@,5+!&[_BVQQN +M"=4EC@)&J]'#9Q@`+Z;#@EJ:M-EUGI7\1R3WXTM@G]">JA_\`392:@Q>)0"H/7@\ +M4G&GMZJ2INBQU*4.3@* +M2^.2!V\Q[9[Y^O!C&P2FGU'1>P01JQP+=5C<84[8W[;<.M8LIDET%5%GR+\/ +M-U,7QG'?^O\`7A>'%H6GM)>2[1-JW_A['/\`+M_KP_59"S(PM-M%.*-AU#`V +MSZ9VVX9TT6VU-_-9$88J,](^P(R??^&,\;+B"M/C-80LA<^3I+*3W]Q],\;` +M3)-YU`^JS[?;;A=*NFH;;2O4U\TJPPJO[E$$21JQ2/J<;*5`&0`/KP^VF]X(-@G'Y28M*?? +M(7EXFNTO.L>8=RM];H^RF*.KK'IY&JA*".F%78*9G)*`1^89*Y(X/P5`N.>H +MZ0.5QR0CZ[0V-/?OO5NK%?+!9]26KY:WPV::,SBW6P2K.[1*.J3IR`S2@;G? +M0I#!T`6AV\JG$IH=/Z;N:6Z7`F?Y:6=@6KK*PQTC!(*!V;JBCI2R)`H_9QG/4<^^= +MO?AIX$!P$)>H5(:0^2#"8K`N@L%Y5)^>GQ?\`*GD'6I:+M/-KR\"58_E[5(A\1B,KTMN7 +M)ROE0$@M@X/#XP1^)^GS_;WJM-Q#08&ORMZQ_E4LU!S_`.?6L]67#6VNKC=^ +M4UBAA2"AY7Z9DS)&IV66[5[9=7D(R8EQC.#@;<'5*%-EWC+;0?6??$9C,6T/JTL@_N(GR$PFJQHT'96OS?[9 +M`\"8)\@JVZMYRFK\:..*%G<`%9JGYF5-SLV,C/TZC[<3V'V0R$*+KXMSF +MS\[H!T_2:BU[47)-/4-(U)1QBHN-7+)#345JA)P):RID*0T\9]&D9>KLN3@< +M'5:E&@T&H==!J2>0U/@A*=*I4^'0:\DQ(*#E9I2CM]YK^8>OY[691!4ZGTKH +MF&KHX)@$9HZ"6Z5E#\VZ++&[/'$`H>,AV619"/7H8^M3-6G2&22`'.(DC<MC,;A<)UM2@'U!,,IG0#FZ)/ +MYPGQ@=\KTO\F^8E@I.6^E-.6L1Z1KK#"^FJZTSUGBI; +M*^BD:EJ81(%`=/%A=U?]M75O4\`5,0*H;7!D5`'#N=<'Z'@5(MPX:[JC`+)! +M\-?/Y)XQ:EJ:FE-41;JJ(>43TTX?'TSV_(\))?-E@:`.*[*34PJ'%/)=%=3W +M^8\J'Z;?Y\*;4)\4FI2.NB***LZG4B40`GO"W5&1[EO3'UX-I@N$`W3-2FUJ +MFA)`19<):ZIIL"MHR8LXZT/4-^'02-5LL +M`-ES2HCF(".?$Q^'&,=O0^O&A$F%CA-UP=3UMTG,8T+3AV8*P)`6 +M)92N,Y'U^XX2)DI`=)NHR55#8)"^VV<\-A@_F1`((W+T<9R"1CZ;\2(T0A)/ +MPKA^R,W^G#-;0I^G&:%K9YID_I65<,1U$A?KGBBXUI:XR%(T!V04GG8 +M#`.,$9V)X;#1JG7FZ_E(*DDAF(QD;AOOP;1,F(LFS$P5R;\+;JR_OWX*=JDD +M@]E`6K&S050*X'0<$9VX>:+:I((+I51W4&_1@H&;J]_Q??ARD+P$VYTDY4WK +M +M>=8I:"@$1:6(.3^JJ)3T)U$`JC%,@NQ!U +M*B\-!TGP$?24.^HTD3?[7GS_`&5AN37+OEFE!;Z_F'/J""_554(*:JBJ`[6] +MFE3PBU73YBZLQJ`3E0K=/FWXE=E80L875R"XG=-N%[^^*'Q-0.=+1'O]DU;Q +M2\D=+VMM++H:B%I56II*B!WZ\^-EA(JL!(JNRG)'6"2WS4T3]4J>(>F102.EL*P<,"04/J.$N:P&8[DIU)Q$3S6LOXL/CEU1KC +M351;-#:CO&G=/M62VWP+6"+A?ZEBN(*?IRZC+8+=\$`98@<_-:X6745)H/_P!1>=5M5:6FIUIUJ*72-++) +MXGRT1D81/,C%O$J966*-F*!V*DL93>^K)I1#+2=./W0->O2PX'6_$[0`28X` +M;[ZGX0=^];!OBLY"?"M_96Z&K;K\5'/BFKOBBOUNEJK#RPT!14M[O]0[JQAJ +M*^OKXVI:&F\7HZY6IFZL.(?&88,8>C[:@+\14<9W`Y1]SWV'BHK%=)L8YYP^ +MSZ;0]MCF&;+(L7GX08_D;G>09$#M#RSS=@8'!B,/2:V=\7/,DW/B59JN*K5?C> +M7'WH-`JPU5#JRXO;Z)+9[M?ZZ%V\'3]LKXJ6=PI(Q6U[%HZ4GU@IU +MGJ?V3X!\W`K\56J$-HB`=Y$^0U/"3#=\.">918VYP+0+:"+>6_P`5'5BZ]J].5MKCUI<+C0SUTMUJ +M*%Y#X3ULB!))R&R!(RJJE@!D*H.RK@FGM(L:*+1#!H-P[O();\$22\F7'S*P +MK7/7SW6SV#4K4LJ45&6=J10:F2G#Y,8R5261%ZRH8@!=NK`V+96-1ARBXTGZ +MH<,#'0_0K=]=[_I'X;ZCX>+O\-W.#6G-7X<.9NCYKO:FU52T44^G]04=0T5T +MMDL5,%CCE4R12/%C(\96ZI.OQ#S7![6QV+9B*6-8&XC#$6;,&FZ2T@'Q@C7E +M=6RGA,-2?2-`G)6&IU#P=_>-4>6GXG;;#+)-?++6T%9$=Y*)_!!&WF4=B-^Q +MSZ<`,QIS!SQKP]%+.V>RY;:%8'3/Q86&J@IJ:WQ4UV@SAQ5HJ3@>HZEV)]-^ +M",#LP1T +M*].?5?<\/9!>$P2X0'+G%,T?4KCQ8NP?&X^AXQARP!"2P&>G(4C;OGC56F2;"4IHXA>C08'F!/UX.30<-0NI@,8;)'\>, +M/)9>+KYNOL/MP@B5L/!7T[``@]O3T'&1"0"/BW(0U1*/D)\8.![?EPSB&RTP +MG:9$R-ZUM\U<"Z39Z0W5]OOQ2<:27J3I"P!29OK_#@EQFTIAK8N>"!M4Y-#4CI.2#PZUL +M+?69CE"J/+'TWQ65L98`C.W?_MP_3UNF)N93G!SW/KGWSP]4;R2 +MBP3R4ZC#&X`)SL?7VX;B"G&-F^J,^B&@M&IGI&3P9S;XHRVY*,[RL/KYH%__ +M`%X=$0X`ZI`)>01K?WZHGY96VGDN=-7U*]=8]4E'1;9,#!#++.,[=21H%4G( +M#2AOV>',.QI,DQ]MZ8J5'$1[]Q\UL"Y6VZZ7G1E'J>&]Z?6DCCCK`\CPU`6! +M?UZD*DCCNTTT0DBGZ>TIHRV +M7'2^G[19K%/201*M-*B+#=8Y),%QT?B.'++(O;().W$NYS:8.0"1NXCDD4VE +MQ[7A\U335VI:&+4222F?PHJYX6%3TR!JM%,D;2,I'3UK&PSME5R>.?8O:XHX +MDTMSS:3OW7W7CS5LP^SG5*0=O;KW#]I[X5?^?>N8X].WZMH+PE17I`9X)_F, +M9J8V4S)+A3TL`4(;T*$#!&>)##;4;4>ZE-S<>/LH<[/=&>+:%:_^97/Z^&:\ +M5AJY*NFJ[4E%)TNR=1%;D@,VX?PWD"_])P!PY6VG):PF3'RW^B<9@FY[K2W"IJII:B"0M(X'3 +MXGB,3T'Z=1?MMOMWX52Q,NF4U5HEC2T6/U3;_L]>6MW^([^T1^&KX>K/7V:B +MJ[WJ<6AJFYJ7CMJ&&66HJ$0$%V1(I.A`5+R=`)4'(L.$H=8W+QW\E4MMX]^' +M::NK@0T`\7.#1)%P),G?:UU[2O[37^TFY*_V+G)0_!7\!MKTQ6?%#/0T]1J" +M\W#PJAM)0S1LL5PN.,"HN,BKU04W3X<*!69%0Q1RRC6"FULB!N'U/'Z]RJ5" +ME4Q56I2I//\`_)4L"2/_`(V;FP#>+4P8`+W$CP#:ZYZZVUQKZ\)PHZI;`X+!X-H>\=8X;^D=ZJ3J6[UVK[W4WZ\6^P6IFCCACI+5114M+#&BA53IB51L/IN=R3P/B +MMH.J.)"AV]<#Z\"OIWA%,J_U'18.L+8I,.IK&[)>[>5ERHVF08)!'N-_ +MH1D9/#V!KFF[*[>LQ=)K@7#4(TL?-B]V'0Z::L]%!>-*S7ZEU?;:.8MBV72* +M,P5"PGT6HIV-/*O9Q'`WXHUX.?@*?ZIF-`[306GFTP8/<;CA)W%1[<0[JC0& +MA(/<1O\`NK@>!=J,0W#2U-P>W +M'-ND>SV8;%NHND#5IXM-VSSBQYJ];'Q#ZV&%1M]Q'`C7WP44E0#+&UNJ1%4I +MAGC8E)(B=\.OOL1G]V>(\503+AXHV+RPHXM&N+Q;_!DK+G70M'M3U!9NJ(^@ +MZNX/T.W#6(9V1DN$L92;IV:5^)+4VGY8#6U]16QL06-27:%O8C-GBJU/5#*#^SU#N.V0<'Z\2 +MV%VBRI!^$J,Q6"-,RT2%:?3VOX*ZD@$U?`\/X'GA)90W^)-B,XV/$U1JR,P. +MJCZM$M`(W)J03530BHM]TCK$._X_OG\_7AM[^<)MS6F%Z/0<@'&3C;;B +M0-D@VN-%Q)!/H/ICC:5!E<,#`V./;UXT>";@:KB[;>48;Z\:(XIS?"#=4X^1 +MJ`"#MO@XX8JGLDE+HD$W6N'FHG_U&7<%>K8>_%*QOQE'4'&TE)B3?U8+Z;>O +ML.$@F$\7`&-Z[%`"G`/K@9.!]^"*,)MQ`[6JY$>4DCN#OZ?]^#*;P2;)ISAF +MD(&U,0:.K`#=C]^'&@`))<#,A50J7Z;RK9SYCL?IZ?OQP[0B0$AHEUMR:=$/ +M(),D]O4[9X<#DXT'-(NIV,G9"5R!@GT_\<(FTE)IO=EDFZ+J*F>NM%):_FZ2 +MF\:6:M>:4L$C2).@=14$X):;``))].'J;9?9*>[*"1[LGSIG1%^TW9='U\FG +M36"XI>K=3W*)Q44T%7+T0J5>/*@JCJW4<#]8`-U(X)9AW9`2+7""?4DC+K?[ +M*S6A]2Z:ET38=.5]PT]IAK,K6RS5;665:CP,R">+QH9`THSNS,I$@D*,`0K" +M;P59AI#,X`BP,:\IWIJO0FI#1(X>?W]5F<^ZR"@TQIFFLDE'1SRTX--4Q3]2 +M"H5NL]+,QZ%=3YUWP)`?V3D#:6,%%@>1V1:WJI;`4#5):==??O!$Q"EOT3?TYI&^4^AE +MOH86LOF-J"]7C3D-((Z=*VVU$D<]'(V"K*\2%2"/*@96._\`>)SCBU[3VS_Q +M%)P%G#P@@G]E%X79;33=3-B#^RZ.?ESFMWPS_!7052T7VM64C$,CQO +M'4R*G]_;Q%P=SU>QXH>Q<3UFVMHOGL-+!X&WA=2V,IAF#P\_$9/E=:Q*B.X/ +M::F=P7J:"XQ4[$=Y,%D!'^$H%';T^O'4\7C:;B`#\053I4'@&=04.7*W(HNL +M>6,/@J\:G=3@]0QZ=\XX9PF,APC64O$8:`8X*:^&2MH.7O./2?Q-67XTN2?P +MJ.I;/?E:' +M`@1[TX+G.TJ#:H+*H)$^,@R(/(B1S3`YR8M[J +M)+ER5]=14VDN4\67B%Q2HFNM]EC/HUVJ,-"I +M78K1QTBD$Y!SPPQPR@F_OWO3M1IDI)WZ_:GUU=Y]0ZJO-==+E.`LTI<%F7T7 +M.,*H[!0,``>W&JF+DY4XRD#W+NIK<4C5:5(XBP_:7J#?<]Q^_@)[R;NNB:=A +M9)SX@FH2Q^QX9=(-DL,F25\AEK++(D=Q=9:3=8JC!*X[=+COC +M?\OJ#LA[0XV2Z;N*@WHDM59-0QH8[36,:BD.?_MZA1ED&?0CS#W&/;B5P6(S +M`L<;H3'4Y+QRONE`*=JNNT?(M8G@R%:H62MJ.AC$P_9I:^105 +M(("7)>V.(GI3LO\`5X`5F_\`,HF#P+''?R#O_9'[`Q[:6(ZEP[-22/\` +M(OX%%PCT[J-#3U,\%/<3U>'60]*,5SN9%'?!QG`V]1Z\R3?C]TA +M^4&6^2SZ:[BD19;)T5%(Y'73'/2">X`[(WIMMPZTD]FH((WINHQK>TW>FKH3 +MGA?-/S>'17JXI"/+\O4D^0?W#GL/;B696J,:"#8(:M28ZSN]6WTE\55XIZJ* +M*N+)3X`!.[J/;ZC[_EP33VBZ9*CG;-DR=%;S2'.NS:CFHUM=[B2YSKY::IP/ +M%([@-V(_C].):CBA4AP,$J.K8?*2"$YZ&Y0S0++4P/UGNJ'9#ZC'!3F&=)0D +MVT7IS[8()S]#Q,$[E'.$FR^'.=]OKQM.--EUEMLY).,XSG/&H6G$ZKH9MCG; +MT(XR%@?.B$M3$M0SEF!\IX'K"`83E-PF"M='-8!;E*6.'+#TXI6/;VB5(T0` +M2"DJS9\A(4D[8'#3&MW)<'4K^3ISTX(V]NWMP=2I``733G1,+[D8"CK`QW'; +M^N_!30;E(=*EDP`/-G`]]AM_7 +M?A`,ZI#;]G@C/Y6BII$>2KN;3BD586IHU"13;'HE).6_YF0-\E1N,\+;E`DZ +M^_HFY+G"$VK/J98!R\KK97GI2B2BKZ2!BOC=%2SKC!'G4NN,=PS#<;$NB0`` +M!(C3N.[F$@M,S,$?<^RGGI"PFIU3:&K[2-CX2KX3L[ +M1C(8A>D*^>HG@S"85D@:$<_(I/6/#;7!]^:`.>&K*>_66DKJ&WBT)4!8/T:( +M2HIHT1R8D(_"Q0N5Q]`,9XJ&WL:V],F`X0?(P?D"KALC#$00+M@RM>UX-OU/ +MH:2Y4DE-67&SWF@K_&.`RD=223))G)22-*?KZMLJQ]N.2/QL8ECA_,US#Z$3 +MW%70T(8X>,\I'TE"W.ZECU/HWF(-.VZ=]1W.SUZ1O*PRMT"PUR'PF_8,D:RC +M/=JMS].*]A:[<+BJ37N[--P/A.0_^+H[FA'5*+GTGQJ0>_B/4+7QKZ6@U5-8 +MKS%T&WWAFJ)(U/4:FJB5EDA78YZN@L=^S_0#BVUZP;1ZL_\`Q2.8:3(/A/HH +MRE_S;F[@#XC4+N^,^AJ:'E'\.<=!-%25NG+1\@51E44M341TWBR,V<`GP)U^ +MNX4<4K\.\6U^T,6#I4>3ON&S;U"E.DM!S<-2+;0WYQZ*D%TTE1UE]O5/3TE3 +M1T$M&U32O">LATJB&A`8@LX#X!VV!^AXO-+:#FTVYM0Z#W%MBH@X4%]ANMYI +M;7NVI_L\]?36ZIZFH)9?$,_21TN&7]6%&`/$5/?S0] +M:BYM(O-[3ZJM7,#05O;6%ZLU-;5I7EJ34+XE5,89'\V,$?A\V4S_`#VXOVP] +MM._2-J$R`.4^XNJ5M'9`_4%IWZAYY[[,M+86LDK2LT,!J9)@Q!)PK +M/DG/3L=QQ8*6U&BG=T\=RB7;-<'1$%15UH/!EZGMTHD4E0I?#`#&,'_VD#'T +M/#],@[T-6I.#M%C4]10.V?DI(Y`0"HE\I/L01Z\.&R1:41VVNM,AD@26LM\H +M4]2MTN!]U.-L^NW"7!VI2VEL"A9J::#!P,$K)^1VS]FX07%/MI@@7 +MG5=#6>)95D@(HF[?B/23]"1]N-AQ212S`$+/1JFA!BJ8T\%O,V!E&^K+V'W' +M[^-&Z4QI%RI2BE18I(Q$*F#`S3L,MN-RF?Q8&/+^[AIU.\I=-V8EI416V6EJ +M;=/2,#V\:CJ8SYJ68;KE3W0G((&XS^]%*JYKA4!TU]\4X[#A[.A[U977.E[WR\U[J30.L6@GU +M%9+M-:WKZ9^B*NDB9)5(V/'+=I[*J8:N_"U/B88/W[CN71 +M-GX]E>FVNT]EPD>/VWJ*I]8OTT]!=(H:JF;J3#*?#ZR=E9?8@@C!QGM@[<0Q +MV>TDEI@J09B2!#A(6-42B*!ZNRQR"%';KMZY,E.?7P<]P,9Z#O\`3A-.FX'+ +M4\_NMN-B&^7V0M+>U!_25FKHZ2J51U@YZ)#Z]0].^#GUWXD&4)^*Z'JU!_*8 +M4H;A0W6;$(G6Q5D('H1]L@ +MCU'`].0V_$I1QI:( +M?=1]7"M%VE>ZHEL;#S9QQ=`)52FT!<,DG)SN?3C'4Y)&>W8[?;UX-I7[02,@W+D^WK^[C,MY6!@(C2%4JL)%Z!_!YM +M_P#7@BG!,)L@!T!.334(JH+I3'`5J*60=1`"-&!(._\`[2/S'#U5F_@MET'D +MIRR6NNNEQBHJ;$Z#]8[,0HAA7!=W8G"HJY)8]OJ2`6FM).6-4NGET"J:\1H?.-F6E-;I-)3Z-H:RWM;BYM=6[M(\5/2CI=G +M\PZC)*TB!0,$)OMP_P!7E<'4[`;^7#Q3U,S9Y\%6+F!;HM+O<;!5V]++;Y1/ +M0&1Y)T)G21#(K%8^F:0%%(Z<8W)..==,:)%,$:$GQX*Y["J#.3Z<%K?CN +MTMNYB7G3-SI&2SW2BK87A@B)*/&W6`NXZO.82K#&RCU;''%]H57FDZ#<.&_6 +M;?=7]I#B`1J-_`:^A2H_VL-KU_I"VU/C^-5P4B9\4F.6:"I$3]LY#4\P4;Y` +M"COC`6+H&OAZCANGU%K\B)GQ6L,`VKV>[3WN5"[)%-9M5_%QQ=45L+1Q+;];3@]\2.^\CR4/08&5W4@ +M-':\%8KXV;":ZAU!:IX(88$AL]UIS&<2/$;A/2@G`W\@&<;Y<9[\.K(_E;?QA5%T-9(1-71R3M2U,D,YHICEWA#*DIRIW` +MS%$V>Q.!MU'B];6JDY3ND9AQU'U*B,*0&'-X>4H9UQHH4VFZ^Z(JUC_HJXPQ +M]",O1.DJ^0H!M^$KC)P5'!>#Q?\`&#!;M-/A";J@=40>#AXV20UIHVMK*^SU +M-)%&M8)G%,V.J65\B0'([KOV.WWWXL6QL9D:YCM(OPX%1>TDDC52Z>8`Q3$[@=0"J3N3TCT/$JZODJ9FGLG7RU'S\T`V +MF',(.HT\]$%R@Y!&1C<;[\36Q]H5 +M`P4W.TM/$;BHW:6$9FS-$3NYJLNIM)26J85B4[FB=B%!!#P-C(23;L=\'<'W +MXN>&Q>>WLJM8G#EEP%TV>PVVZXI!65MDO*,LU-4.N50[?M+GJ3&6S[#U[<+Q +M%=S+Q(WIRAALYR[QHB6":JL4[6N_4%-!<0Y1TBC*_,]/_,08Z77_`!*1OD?0 +M93J![<[#(/HL<#3=_$U1-0QP3(\T82I@7RN$7J\,Y[,O=?IG8_7A!<0X`ZIY +M@DRU9PM%/64Y-,T+JJEFC4'$9)SG(&5]MP1]1QMU;*Z#HL-#,"T(?J+:4PD8 +MD\K=6,8/;NO?V],@^W#S:LZIBI3RNM8K%HZFHCD\&1_/VZW&%;_#*/0_XAMP +MBI2%R$NE6)$'5"&H:`6R]QO)$M-!6'K>-P&$2G*3G+(*UT;JMIBIAG6`[3>YTS'HE\6-Z854%?`WA&)BHXSM_+BF8\PY232/B2*D8'U##TQOCA +MFB"XPG#!NOJD=)8@,1@=^_!=-UX.]-%A('%=JCI5L`Y/^?!;1S3-T(ZE0BBJ +M"=U"X[=A]3PI/4F@JG5RD5;ZHR`>O!W^O#V'^)-.B)!E.73]-+<@4A487H#- +MTENC)"@`#=F)PJH-V)P/<.U(&MPE$`WXIKW&IHM/PQVFFI8:NCCE9ZF-\.+G +M5*2I$A7_`(E-"V4"@],D@DQMY@G,6N#1[_PL80()$;OW\5:WX<;+6U5]@N6H +M)HZNRT5)7U];+35:>+/45`D:6-)(\XG^7M_RZD`>$KN5QMP;AF]OE]TP\DG, +M.,>:O=R6L4-F%EHJA[/-J"GLW6^DAI(TD8(ADA4@E0`25,I8DGOT#& +M>_$D)>#`LFVC+$ZE:PN>E%`+K?:BW4UOI[/3R"ID?YB*M.JPBT&#S':"MVS"1489X>6A6F:ON+VO65+77-DC-LNAHIJ +M@#KJ!"Z,D,P#$GI!D>-O5@0",])'F_:M-SW/:W5P!'"1$^DGV5U=DY6@7@[_ +M`"5?.8:34=RA6DZQ7VZ[+66RIHY%*P1APZ'8;+FD<=&Q`900#MPO9]-SJ?:% +MB(,]W[_-,XD`6Y_+W]D@NTNRQQ'H`LZ^ZYME1:KI;JGY4U+V^N9>C)C7QJA)'EQ^T +M%`9=_5QM@<*P^S7"N'[LPGP!`'J/`)+L6,ION.O'>AW7--3&ZZ9KZBK19?GZ +MJHEE(Z6&PP3P=L@.AP`W#3D?'P^<$,W^G#ZJ"KU^K<+[U'ZDO +ML%52+(BP^(J)(XD0XD.RMMD^4(R!C]F].%8?"EK\N[V4JJX9>1`VZN1G##;;<'V..),/#[(!S2T:IL4]RLUXCC>Z/)2U'2&CJJ9`DL)(_ +MYBJ0&7/J#@[W5]B-F_EOQ(T*X<(= +M91^(HAI!U4==*5;[8:NC5%FJ8U\2D88'ANNXZ1^SG\)3U!.">'VMR5`]OBFW +MQ4HEO^;)[?!W60\Q+_K'X?KB]0?_`%%L36^QH'"B/6%OZZJROC^_,PJ[;G__ +M`&9^W%JPU`8BE4P?_P#4'9_WMNWSNWQ59%44*K<0=&F'?[76/D8/@4$TG$4V[Q>R,.__L;ML5.-N,;4#A/\P2JE`M=!^$^BZ+A8WND, +M=?2Y6[F/>,[I6(OI[B0#!![^A]^-TL1$3I\ENI1FPU^8^Z&S33"5:N,S4M7D +MJW5^*3T*.O;J'][U_F6(=S"$;2#2$1TE3%XX;:#:\)]]P)"^0]6P!!P>W!C0&E(>03!6=&/+D#W&_KZ_Y<$-@I`<" +MWN0KJ8@T-5A1^$]CV^O"VLLF6DW(5*;U(L5^=^D``=>PWVWQ]SCAVCQ)2B!- +MN"MM;[1'I:&-ZR5XOE*>.13&0':26($U*^TLA:2&GS^&.*2?&%7K*Q;,ARCW +MS26/:X"=/=OOS0ZCO<*OQI$BB7``CB!5(8E&%C0?W0`%`W_,DG@1T+'..BN? +MR3O])67;2]FMOZ1IZJEIVN+1NS#KHTI:M3(W2=RS5#R=&"!&(N^&/!-,C-D& +MG[+;?ZCN]_);>.3V@HZJ@H8+;0SR^-9:.FCDEFZHX*:.F#[8]"$B.VYQWWXF +ML-3+B,J'+VR3Q\M58'F116[0>CYK=13+/7_)1(9NH81OQ&W/W99@QGJ-=N^RT[\];K:[;8JBLN$E3)45D-N.-I?$;I4`E +M&@SD$\4/'8]M-A#M7$C[>BN.#P;W/ENX!:#^;ETGLW,62^4CBJM5T +M:1D2%L9B\-.I02#TG)+C(SE5/'$MI85KKO.GL?-=2P=2&B09C]OHE!?YJ<\Q +MVHVJNBRW63PUJ"1&&%2LL43D[A6)F7K)'[6Y]>!-FR +M!V*[2+?U4S]@?90E(9J8C5AGS&[T\D3?&Q)3U>H>534:?)VBILDR+%$X946% +MGIV3KQYE6!-R/[H.`,\5[\-&.;1KDB2"/,P0?./-'])`8& +ME.NHDIS'+4/<5D[>(9#&3C_$>L@_<@X&W9S1#\+4,<`/"_\`E4MM7+59YE1V +MH-335%LNP:#%2HKHX^E1Y/\`A;`;%@.ECGU)X=PV'`>V-#E2*U4@.+A>_OP4 +M_KS6M9+I2WW>@K615HK?)$Y4-%32RHZ?@/<,R,-NV#Z<*V-LQC:SVN&\CZ_5 +M![0KDT@0=P]0@:XWJDOM)351A%+3U+]:@ME:28F,/&0024PS'?G@JK9=76`I%%6,TO2N#`VR,^,;C!7/K]>W$A +MAQEJ"=XMS0[P'-)X&Z'K=6U%(.BF=7*Y)61,K*"0O3[CN!L>[#WX.?3!-TQ1 +M)!LLQYTJ#!>[3'&:F,J\E/E@6&Q8#W!WW_AGA--N4ECBDEA=VE*.U/6QM6TC +M]-*QR&VZE`R`64_B(Q@C[^FW#S1!RE-U&AUUAFU/3RV^6FZ:6/PP(S#*H`SO +MTQMV93U9Z#[_`$SPZ:L.E)B;GJ;YAY`5QF*K0K4)@`8Q+ +MC8#!W'`M.I;*[S&Y./PXS!]/R5<;I6&AE,L$=3158VE@9AL?<'`SG[??B=HO +M)L;A0U=H:;64+I^_7&S:OH[Q8;K+9[T*F.XV^NCRK4-&A\1!*45RTC3S6TQ1S0R66=PD%2$\U'.!ND@.61AC8 +MG8A0/Q*0:]2Q(.MGC=Q')2]2A!)!D'Y\T-ZM9[_<)-"H0+ +M,HW5A_RYEPRA1Z2KM\J5M0B3E@I +M;HV\91VD'N0._KCB1S!^FJ!_Y;NUH42QVN"X9FIY*%#@!P1D9]P=MC[!1SYP!@]_8\,5G")3M,:`K7/S:20]EB0%W/8`=3*1AZ4DG18X$.%U8'4%R +M%POEQ2&*2GH(9RL$;[NY$:1F20C(,C"-`<9"A51?*HRO$`YB2-4D4VGX+2NJ +MC4N9T#,&:,J/H>&"ZZ?,MESN*O[\)7+N[ZJYH4S66DGFFAK)8W8+O)$$,*Q8 +M]%(QU9V`V[G@[`T'5*D`(*K6#61[GY>C6TZ:M'+.Q0V6WQQK.8HA.RIG +M`2,)T@?W.D#;U(/OQ:"6TVQQ0;6&H;*F_/+6 +MH_JYU8=0.6Q\N3Y0%\_TQQRC:U>H2#>+GWY+H6RZ+9[B+>(6H3FF\KV[1E_N +MHBB"77Y.JDD&&+-4(BDD>7\-0&)]`!G'%1QHS.?2(N02/#_$*T-#6M`8;)-: +M^AJ*G3XIIGIOTU24/Z5M*-A%,U&T,`AZL;+(\8&=\$^F>!-@5&EQ#[MF#W&2 +M?0H3'AP/9-CN\$K[4?TCS@H7:O>&BYA6JGDBZT"?*HH_W5F!&`R5M'4+@C(5 +M%SWX;VR"W`G>Z@XGOF[O#(X>*9P+1UH#K!UO?BNSXL:RHFT3R%UU%2Q)66W4 +ME8LM.5$95):VK0Q.QW*,R@D']ECZ$<1?0=C6XC$X=WPN;'B`T@H[;K"YC'<# +M\[%:H-;0JFH;+=Z:JGN-'3T:TM2[[234ZUKQI(1C9TDC>-O9E'H1GM>SC_P[ +MZ;A!)D=^4&/$$$+G^(!-=CC,1]86#K8U-(U>'DD64W"25&&9"Q-03&JY3:9ZE514M;X3)D=:*DD[84>N,'/TP?7B1P +M;`,:^>)/H/NH^NXG"LC2P07)?/T/535'0]52-`35TRY/2V0^5)..M.LX/K@@ +M['B3_3YQE%B#8H!M7)?&QS_P!49)]0!L?7`]N#VU)[1\4(0!(&J[*.4QT\ +ME73-U0-&)9%`RR.&QU#V!ZF.?0G?OPJI3DP[5(`MFXJ1H*E:6>*NC:&G?K82 +MQ]/D+C&6"^GN1VX4`3(-[)+2`05)U$#4T9GI*=Y++)E9Z*12W21D$8/\.Q[' +M/"V/,0[7BLJ6$@2I:E%*L%,&I_F:0?\`#$AZ63_"&[]6.RMGZ$\($EVMUD`P +M$1TR5E(L:TM6MPMC)UI&Y'CP'_`3^T,G(.0=Q[9:>&G=!1`D-0IJ_3E+=J(U +MU)#&PZ3UM&AQU8]C^$^I4_<<.T"YI0]:D'B0JPU\53:KA3S2QDF*57ZEW!7; +M.WOC/$]0>(E0&(9J%?/D9J)M3YL2ZDU[0\C5#6IN6\M=9:2^T%525E0,O07(,N)U`7_`':I`_YBJ/D1[U33\%(EIG>/L?=]RA-*QQ7JGGL%VMDJU*$TSTSL0_4 +MGF\+JP2)4528V&[IL"2HZE8O+3.=CHWSZ>4Z\#=-8+,\97#P_?Y<1937^SPI +MD.*N9WIG\:VUAC\Y@!W5Q_>4'JZ>S)XF/P[!#$0X-=OL1SX^*-ZC*WLG2X[O +M941<+6>ADIH(HB':0Q1GST4@.1TAB>J,YS]5(]^"*6(R'*_3YH=V&+Q.\:A! +MOZ/J0[M0T,:2''C0^L3?3'[)[C]WIP?5,F0@VNB9"_3['2-]A],?3B_P0%SD +MKZ2-R`%/?'&$+#Q7S*^7S8[<:)W)6MI77)U!2".GT[]OIPG@4F8L$$ZG_P#L +MY3UY/3Z[\,UQ8IZD-ZUTW#U.$T\Y1 +ME0MJ%E%'.QP0%/IO_6W#L+*(+M%274)+WKPO%8Q^(Q`+$A,[$@=@3L#[@<.T +M1<`IF7"VY+D#0(GTQ +M;:V]7ZUV>WPF>NGG6**,GL2=RWT`R2?IPTUI=`;J5JHYK18R5Z4?@.Y/V72^ +MGKMSD^3BIZ>I66W6%I/,9H1(3/6EAZ2R>5?98_KQ:]G4([7AX?O\E#D!]26Z +M"PYG>?MR5A^8NKHIW-&E5"USD1T5"Q\JKY69B.P!;T._?L.`-KXL`AHU5DV9 +MA"6YCI9:X.>^H:VEH$DM]'+)0%%C8](?I4R=U'J#\NQ&?7`VZLCGNV\:13MI +M^\^L*Z;+PX+X.Z_I^ZU\_$6SW&QZ4_1D$E72R5E=2H[+@QQ5$Q&WN>E.PP,9 +M)VR.*]M!V>DT4QQ\I4YLZGD>>LX`^(&A\_'1:D.;=G-9RPUK:I#3^+9[C2U, +MOA,?UQ89.(:I53J.PV,AQWY3ZMD^:M.T6"I1.6X]PM#^L$_1F +MI:>LHJ67$OSD$L4I*_-0/4-(._KNQP=PR@@<>D-G.%2BYI/])\0`/?DN78QI +M;4!Y?640\S6H5CO[2QRPVYS3^%/C+1!JC+^N8=7N#MQ+X;_`/=.)WC[ +M!!5'@X=I:EK'$M5+G%NNM#$C&:".J,70=^ENF. +M1B#ZY+@8/L.$L&9AXD?LEO(#Y`WK&6E:GGK[?6QR&A,GAJ)2W4C#W&!C; +ML54^_#K7-(!":<.V6E8-3:IZ>JI)X`A5^M)%48!ZBPVQW1UZOL=O;AWK`09% +M[)IP);`YJ)AABDB29"33NA4DCS+T[!C[,-P?I]^"'!P330`VUT14$_RCHLXC +M3S>"'8'PQ)V4-]'7`'ID#&.,+0X0%DY3?V%*2PPT:03U4\=/9YW(4R$,(VR/ +M(S8PI!P03@'';/&!Y<(&J<<`+C19S1"W'PZFIDHJE7!2=4\6&09R#@'J7VR, +MYP?IQKXX`N$@C+V3_E&5#1@./%EI8:\Q=3>%U],B]_-U*.H8[-^63MPR#!$F +M0$^UI>(-DB.:N@A)'->+92Q1TS$8\-^I"2"0!N>D$>A/<;'?'$OAJF6`5#XQ +M@(S#V%#_``]\R:3EAS1T=JK4=)+2LC<;^#,GA3Y_964>AR:+TAV*6U7T]XMWQ^U^:N^P]JYF +MAS18^DIZ4/\`N]-K@9>U?@5 +M:J;W9@&Z&_+O0AK#0\%3!3:ML32FZ(QB_5`H<1X98YF`_52H1D,!A>GJ4E20 +MJ,%B7!QHU!V3]>''FEXBFV`]MGS-O?#C]T_0K->TEVOKWK&O.G0E!#54R +M0_-"(/%(%P9HQD,N/1TS@IZ*<8V'#;*CG$L.A^?%.5FC_F#<$'5=MHKA,:F2 +MEE\0@=0#E,'_`*=C[_Q]>#Y<0,NPP2<'C4&5MH\5QDP1N"`/3C'"UE@&\('U/_`/9U +M&#MTD=NYX&J$W2Z9*UU\V"?TA*P;+=1].XSZ?NXIV.9VI(4A0="6#>F7$" +M80IJ1B*:<;DE<8Q]/_)X?BQ2I)$-LJ3WR4-?UP6'ZST'U'"Z([4%,EW:`'!. +M:QE3`K!&R%&0/7;^AGA\MD$!):]TZ*[OPER% +MEME/CKK*G;MTQ*5!_O,!Z\&X/#ESK;[=PWGOCU3&,/9,:FPY$[_`?->GV[3V +M+0^FK3I;3-'!;[/;J6.BHH$(411(G2H^F`I)/Y^HXL>)K"FR`$Y@<)G/`*E& +MI]7R3ZIMU*TXD@DKUBJFSTA5F5HNGJWQYV@\N^W?''-]H[2)Q`IDVD3X_:RO +MV'P#>H]L:;X!^WFM??-/4ICT/I6GGEHYXU$$K +MW*:$!G;Y(3`]&,(@D,JA<=\;G.T`*QZEEYTO$;E:!@@<34BQ$F/^H#7>8OPE +M:Z]5M#74?.^V=<572U=K->B"+>52T)&0?V@A)/<=3@]AQ7<<\]4"-01\U)%C +MFO;:)'T*J-SLI8Y^2U0]T<1U8L]%X`Z`S3#)B?+^G8-Z#(`/%=^GI]#\Q-9Z*N<0NM)15"OBHXKM3 +MR=0F!\+Q$J?-DKDIF/&/7;?WG&-<,9FG4$=\1]U%@#]-?C/S053I$;M;5%,( +M7>G://B=7605QL0`#D#?VX,J3D+AK*8H0UP:=%`6.(V;6-;&ZCY=9'0*1L06 +MR-L>Q]/3VX-J_P`2@TH>@T-K$`6E,#F(!3:BJ(#(DL+U99S@J"7CC'B=]L.N +M!]-N!\&#E!Y?5.XMQ!/>LZZVY:QI!UBFK'HXI5.-CE5)+#<$*P+=0_NGWX&H +MO+701(E.5Z6;M-UW)DZK3P(!W*3M-9%: +MY9Z:Z4\530U'5!,LR]2P%AT^?_"?1O0G?8\,O8"!&H68=^60="LVIM4EF1Z: +M)9JFQDE82A#&`^B.#GR]L-Z@CZX27YC.CDMP+6VN"N$$56*5!;E^J4:VTU5:3U1'"KN::5FEI)224E7JQY2 +M>X!7!S@@C!`XF,)6W&ZA,;3`(+4S*G5B1LVIE):%9;E?KZW5M-3V:Z5=50IX?2CB0M' +M`6.S(A[PD'=3NASZ8QS[:^$?2[8N/I]U>]G8P$"F=`K1T4-4DU9'3R/2W^!( +MUJH4V2Y1!0Z-D9!D`/6C`$XV(XJ3W&PW'0\#P5G:`^_'U'^$&ZUM4&GJ^DU] +M;/&I=-RL8+U!2GJ^1R>KYJ%1WCZ@&:,?AQE=MA)X'$LK?\.X=L:3OC=Y*+K4 +M32<'@RW>CNU72BNFG*[495JRA1H9;C+3D/\`),Y,<=:B=V.0`ZX\R,#L<<`U +M\$]M4!NH]P?&P1E.JTMC4;^X;_>Z4$W;2!2LDBIXZR*123)'"P8(2>K*G(\A +MZNI?N?0#A1JDM#HU365H$G>OT5D!!P>_;UVX[(TSHN1%UC"_F&,@[;[;<85M +MI$+B`=_7;N/;C1*T`97R1?*Q)[<8%IQN@349_P!VG&V,>OIPS7%DZQY&BUX< +MVEQ7$L!N_KMCBFX\RZ-ZD@8-TE'/3E?,5SD`>W#--H-RG7UHO"PL9[@LWL1_ +M+@D-`%DBD=9WKO1&P?,%;;MP_3-T,]LE"6HXV^6GZ54/@D>N_#Q,FZ>J$S;0 +M*DFH"%U!V`(DR6!^O"Z`ER;?5&:83JLC2+2HW8](./?Z;<&N!!F%JF((.J]/ +M_P#9[\FX.7'*"Q\R+M;IZ+4=SH&IZ,3+TO'3,X=Y2.X,CA?^E5]^+%LW#=72 +M#W"\($G.9'/UU^@'%_E=5EYPT534_#[=*&E-/6HVG;C'$\L8;HFC9F4X.RX\/ +M/OTLPVSQ7-C.G:/:XC3N"%K4#F+2-%K2UKJ273//WF5+%'5T,%+72VZ%6'2X +MDCBAAW!`QYH%(R-NA?7OUVO1#\/E=?\`RJ?1-^7%;//@OO=HI+:E;)+% +M_LB\`JVAF;)6AD58JF!QN>N+Q2N^S!8V&Q..6=+L(.L#SR3Z=\20Y26LMQ$,?2Y[B6G6D*G.Y([ +MYXMW0/'0RI3=N<'>#[FPX$GS4'M^F'N;4;H1^X^RK5K2EZ--WNJZ9A5QT%+) +M$RY!&&E'X>_;*C/L.++LMQZ]C0;$W]$+M*33<3P]_-*R::6[Z%U];JZ%9JZ" +MDLTZRPX202!II#U`8#^4N/0_7;BSU61B:51NDN'G`5=82^BZF=0`?)#*1TZS +M4?S)CFB25"&*DY0LC!2OJ#^\<$M:+PF`26@DKC5TCTNKZ%VCC#S0PR."0X9G +M0(6!'V)S]<<)IU`[#D<)3M1I%8'<4?K([4K(E30P1$[>?$AZ),9VQ +MD`_;A6!J');C_E:QE,.?V3R7V1(ETYH^O>I^9J(8J^VU],5&8XHNGI((.<$, +MW?L1]-\=2ESK<".](;4[+>(%T!7.USI555'-'4+64ZQ"(`>:>-5P,$9\Z$-C +M/H2OH.#6U1`0[Z1OP"G;9#0WRV&@N]8@IU;I!))%*K;=1`],E2"-UR0=CPU4 +M#J;LS0G:;NM;#C<>FY8=/3U]KK*JU7>$U+0A8YD??QX\D*ZMV[`#_P#4^G#C +MGM2X45;-20P454ZQTX!0DGI:##'R]9[+N.DG.#WV8\(C,TW5,"SF&FKZ6:.G +MHK7<90`C3JRTU8ZC!BSMX\^]+VJ]0RBYTOZ-J +MSAHDJ9^DK48P0)/0=@S>N0V<@<&N::BDHZIY**_ +M6ZK$W34+T.5.(Y4;?IV`B<,#@]'USP=U@<)&A47U9:_*F!154E#4AY(W@FAF +MZ73'28V/J,]AG?[Y';B(Q5$$0K!A:F6''E?Q")R4P,_JGW!Z6VH&U,+U;B3\.\>]XX[U<]F5`\"1?=]58>T7@WU +M*.@EMIFU'')+%50B00+J)-W!IQVCKERZE&`#LBD`.2C5>O1-)QJTW=G4TB7B3:>!!^NY"MDHZWEI-75=DJK34XJ:EJ[9#'%3W"SU]9%$6BA$9'73@'>)P`=U/;<]_8#A%-[7"9@HSM,-A(7Z +M#"D9&V_KQV,"3=<7T%UQ<'!!RQ_CQMT398("X@'/N,<:G<$HZ+^DPP(R"#PM +MH$3*UO0'J(=5++[D$]O7@2J;)VF1*U[\V5!K9".W41@#BH8^G!$H^GK&Y)"1 +M,;E5(^F_Y_7AFC)'!/D@RXKJ*C.2WE/<8[\.TS!A(=3!,+[T@*W;A]O%R6T7[5E2#4@`U%D]);Q,9]]^%TP`>TM5 +M&PZ"KR_"/R6K?B`YQ\O^6D"2BU5-2M1=I@0#36^+#SM]RHZ!]7'$IA:'65&L +MW>Y0=:I#,HU-OOY#U7JSU;J.W:?M_P"B[7'34ELHX%I88(FVAA50JC'MV'OM +MQ-8S&!H,(_`X$&`%KMYT:_'4].J3*8P`^6\LDA&^#Z#!`]]N.2=*MK`@L%H7 +M2^CVS!JY5$L&IJ>FUQI^[2-'\M02RW*9F\N%IX9*@[_>%1M[CCFNQ'.=C65' +MZ-EW_:"?F%T#'8<.PKZ;?YP!Q^(AOU)3,YQ7J>[\HZRSRSP^`D]ZHI9\-,S+ +M'")88B5V"O'4>O<1,/0\7W$52_#%IWYO33T*HN&IM9C6O`UR&-+DP3X%OJ%J +M^YCF.+1%ID(25?!DN=0O5@2`L@$9]2Q\7I^G4W;!XI([-%HW[UT.G)K/'JBZ=6)^8%JN#U(C>FO#5+$['H\(DCZ?@C_=PU4=G8>8_P`+>,I$L(.D?7]R +M@_5^G5NO+6@T\B/*\\MXM$JE1B)IY)50J#W`,@/TZ1[\4O9QC'!Q.A;?N0&- +MJ`DD\CY1]%HVYCT\<6I=:72D^:JH5O%8D9J&R[QQSOTM(1W8X4'ZCCN.&K`T +MPWD/7W*J%:@YK@';N&FBOQ\%FIX*"]Z0\1NFTK42:?K(YC^K6&K`D0N1[*O? +MTS)C?/%#Z4T6]J!),.[\MOK\E(X4D0=XGY?=6(^+ZQ2\V.0>IX*&UUERU%IN +MWTFJ*&18&,U1!2/)17"EQD8EA$3N-B<1#T*\1FP*GZ7$L>XV<(\]>_@M3O-"GHZZVZ@^6+315-E@:*2/996$//BVBH$ +M=LCBY5*9&5@TAT*M4[`NWVE1M?:Y*4QTRB:1Q5QQ+GS$H@ZP?J2`3^0X)PKP +M02>'[)K$TR(`4I;K<9*C3+I&T\!@EA95W8LC_LMW!((W_GL.!J9!SM/'Z(AS +M2,IUW(JO,<-146B2.->@VUZC/43@EI%&<;`AEC&^^XQMGAW`%V6#*FC292LL:#I5.M<90=O#<])Q^RPQL#P41GIQP3#I:[1 +M&--,*Y*>DE:.2FBB/AJWF,:$8*9'F(&Y"_B/8>8`$*P,\44"HC!_P!W +M!QL_^`$[@[KZ'&`-U0'01JEL(BG(3HFM3`?B1 +M>S0G!\N`0#G8C'$BPD-0-:F)C54"F:.V76HI:P2ME6CQU=23Q%2K!6[A@"=C +ML5_]O!%!Y([*AZ],--T6ZN_Y<-8FB +M9E2&#>W1,O3UUN5@J*>Z6NN\/H82Q.O2VX&<%2/;((]B>X)'$#BJ+7]EX4]A +MJY:,P,*[6C=66[7]MFKZBO\`D:]HH14LJ%EBG0GI:8*"X1CT],WFP?*Q(Z3Q +M0]I8-V'<&L;+;V^WV5QV=B6U;G7N]]RL'H]Y=0W.X_/TMJN5VN""@OENJD7Y +M34J%0`M5_[EQ!4L*;7,R.&NHY(IL +MO++4UFHY4T?9.8.KM)/,QIEMSP-56J4*HDHZZ)O,DL?D`?\`"Z%2-PP!+\:W +M$14+@QV_@>8[T,VD:78@N&Z-W+WN7NW78#)(''H/+_:%K(#U%DT\Q#!MC^?#-0)Y@$K7YS +M9`-9*V<*6QMZ\4[:#@'7NCZ0,@A([!'8@[9[;>W###(NGWN,\0NEF/YYX>IW +M,E-N=NWKB&(!="!D^GU_\'@A@@W23I,6WH6OH'RU2Q.W23CU/^@VX?!)&5:: +M0W5KWGN^Z'R!U3LC2WU/T5Q^9FM6I*2L'CN +MK(2[H&Z`QQL,'VSCB#VIBNP1.BNNS<*2X'BM:?,35!JZU5^99CU9)(.3GQ[\LJ0974=G4PQFD)66ZO-3#J\]",KVJ2WPNI)*RU\A`R3TU#!5V[=*Y_-V/MQ1,8\$#A?YKI.'DO+A<54KD]`:"?H]\>=C^_TXK#*(_7$#E]0JW7>"QQ/#[@ +M?):'==T<#'44T"CP9(I:A5W(\[LW;N?,IJ>5EL +MEL.J;C1906+JY:D$6-_>_P#RM!`TV=QO#5#MWR&Z?S^_'3<0_*]H[_HJ0T$M='*? +M-=UU2H,>C+@_2)Z>98JC;!!6'I#/]2B#?_"?8\*PA+7/;N.GB5JL\N#7<%-: +M/\5;-\R_S,#T5&U5$ZY7/E;.?S?]^/IPC%@-K!PT-D52=+2-%GM3U!M0*EMQ/R_RF,5F+(C7Y62\U;?)F +M?P'DD:2.AIZ-"6+-&J0K&5Z=B<9<_P#4.)RG3@RH=SY.4H?M-W>@N$\-2[U5 +M+4P"1TQU,0%`+H#L74,&'N%(]N&\70SM`%DNC6`J4B_L(FH14L%B4'S$-15V^8+(\`;K1\JTB]6"& +MQW/8[=PB.9,AED` +MZA[[;'<'AISG,=8>^2>;0#Q=*JJI+SHZL^9EBFFM3L`9@WC+C/9^Q!&/Q;$> +MOMP4QS:@MJA'!U($;O>J9VFZBR5%)*L$<)M[#K(#!HXQU$MT$?A))W#=*^N< +M[%M[G3,P4EN4B&B0IO5=NN=+IM96GJ*Q5!=&5\I@;%6Z,],F0#D[$;_4R="K +M(DZH:NTDQJ/54LU?%15RFKI1/0W.F?K66&0LK@>C*P[C."#W!QPY2EIY(&NT +M.UU0Q;)DMUU6NHXB;?7IUAJ>4%8YE_$GT.-QD#(QQ(!P<,I4>#D.8&2-Z:-L +MNSTLR2`1MNKH8AAPP],';TR#W!R/7B(Q6'E3N#Q1`DIK:5U)4V.NBO%@_P![ +MAE8M)%"I\0(?Q*5_;3(SC@^8+NR:BH1(WZ0FN-.JT\MQMM0JSW",9,?S+.^7Z`612=P`5)/3Q4L1ARV`&@Y9.PPP]@>/4<7LO/'VQ[XVXV7#0I`LN(V)&2N_"-#9820 +M5Q9=MP&'\N-Z2`LS(`U*0()Q@]M]^&*P3U,C>M?_`#8D'S4Q#97JP=NW_?BH +MXX!VY2#`1XI(Y_$Q.?7(/;;@%OPPY/R09)6%UG)((.!OOV]."V[I3=0F9-OW +M7U=QELG)[_GVX):),)#B`=8"%K[CY:H##R@';.Y&,\/"F-25CB053&Z6FY7W +M5]%:;/1S7.[S3^'#!`K.TSDX`"C)[XXW2;+\HWI+NRZ>"]A?(G0E/R5^&/E5 +MH"#PFK:6UAJW"%?%JY5,DC,._P")B/?R@<7%E/JZ08F\`+WUU5,^>M^6EAJ3 +M&QZE4X`7;KST@+_%O^KBB;:+2"5TG8S-`5KGOVHXJBNZB\ACZPBD$>8G?;'W +M`]^*34PY#NV%=J57*RQW(4U!S3TSH+0]PJKK=::BN==<0TCT)/BM?W/'F72:2U5>;+5>--3S2U\E+B/)/4(I`&*9W/5 +M@XR,MGL<\5*KA2XY>]7396T!U+7BYAOI/I]E6>Q\VZ2Z7VBMDD1CA2JIOUF- +MF'B1-E<[G`.X._?MP!4P;A((UE&8W:8R!P$'=ZRK"7RW_.:0M\T9:K+#4$4A +M4D'J_0\I1@PV/ZRF1L^V!Z\5"S<0'#6`?46]2H^I4S2#H(_]OW6A"Y3T\VD+ +M?52?C(H8,XPW3UQDC[[-^_[\=6PK8J0WG\BH;:-0AG:WE9'+9I*>Z72C<2SR +MR"5H8S(0&(+G8]EQU,L-%W.F +MO%EKQ/U-3T5R9"JJ!NT*51;.,%%:0#OCB(8#3Q(,6J6(W$M'H.3JZ2C$``G,$NS;$J"N[+D.E3 +M&&JN%,]D_5.L)9VB9CW/A(\^2TTU5NGLUMUS9T>2&6*IDI&#['I+@=+=\X&3 +MU#/H0=^.P4:S:IIO&A$^BIE:GES-.\F5&5D;S7F\6YY9:>EEMT*J1OTRL%Z' +M]^HEOW,>"7&&-<+D$_NF002=WN$::?)@K+U354OA(TK4$1;)4!$B4X/MD@?< +MGZ<"XL2P.;NNB<*&M='\I792VV6HMU[MH/F6(_OX1A, +M0.O#W;Q[^:UB:)-.V@*J_JBMFKK[4$?4=('U"\6^@WLP5 +M6*[7-<22NRAJ(*RG/S1,,,9@DV7_`($IR#C/96&/SVX9JM+2$\QTCFCFV7'H +MD33MQ=Z>L),ELJNK$?F';S#\!/5D;[Y(X$>V1G'BEBHX$`GN^J)*Z`5U6"W5 +M0:CI%(DVZ1-&#AOJ0N,AAD@>;L&PPTEE]6GT*/?VFV/:'JLV@GJ*.JB2HI+1 +M-,ZM&]-6YC@JXP=D=U(*9)!653F-L$'I/&8AK7,RM)',:C[\QO"W2>14#@// +M0HYFGH:MZ_5MC>HGK@?!O%LJ4S+4@*?$DDC0#,T6`Y88+A2Z[AQQ'LIN:13J +MZ;B-.7GY#3>B`6$YZ>HW>:[A6VC45.[4X!KHRD;H"&>,-L&9>TJDXPPV93@[ +M@<,OIOIZ:(QU0.$;E`T>F*:W7>GK+#(UBK&)S\G5],3L0!TA7/2"IZ3-5/4RH])*C8$\2*^<>DBY`?[;'ON>-T7%H +M0U5H?=Z6)6G7!`# +M@HE^'[5D94[9HXTD555^DI)$XPQZ<@E">QR-P1PW4`=HB6DML=Z+K,\]5&6I +MHX7JQYYUB!4RD#:14R"L@QOC8_GQ%8NE!NIG!U2X0$Y](Z\KK6W^\31WK3J1 +M-%5=4223TJ;Y#*/.5&WE/;TXKV.V'Q3F6F6Z\T^X]:T=LB@ +MKA755+;ZV)9::44PKZ:I`V+PL%)0]@RD`@@`DXVI=;9S\V41(UO!^BMF&Q8< +MV=W=*_1S3."#@C]_'>6Z+A&9?Q7);T^_&%LF5K5<5W.P!W]N-%LE;GV_KTX$;I(2ZL9LK=ZCC*PWVX*;R350")XH6U"TB05/41GI.WL.";$91I[NML,GFJH4&L[AHGF# +M9;Y0-@TEPAJL;#)216W.-QY<8.VYX=PY+*G9W$']D/6;`,[Q[/FO4CR=YT+S +M<BU%>U4TJ?/T*-&$=J64>)'T@$AEPRX/ML=QQ:'5@][O,=QT1.%:8!&\*D +M7Q!WZY+>_P!"6RFFJ[DS-,D0W,BGN-]L#=BQP%`R2`,\4#:CG=:&-W7\%TO9 +M=-O5]8XP./N_=%SN6I/GESVM_+MJRS6VNCO-4RB.ONU.>F*G4G"PT1_N^0B2 +MH`'B'"Q],8+2QO5!QAN[T4UE,=8X0/Z3KWN^C=VIEWPT+YC\U-0:7L7+ZZWF +M5J_7M!;6NNG;<4#"CN=RJ&F6YU$9_P"&E'3_`*/:GC/FDG2%L=$YMH'$DY@X[FR-3:3^!FTU>E^>G(J]11565HI;.$:9RD< +MAKFJZ<'OXCEZ>0$G(S)ON>"7T06%O)1V-+:K'..LWCA$?7R5HOBKY#Z;U)J; +M2QNRFJ@$,U.DL4IC99XV$"R$C)!:)8<^A]<]/%2%(=:Z.2F=D5W.9VQS\[QY +MDJI-HY,T6G*VJEM%8\)AP["25B961U`)!.&/8[;GJR6#](Z`N5CF-0LT+7`F56*@/-12QJ"V)\U%UG9AW>_V4MRTE@I;Q37"H,OR@GJ8VQN529UA4@'N>N3`]1W].-;6: +M7,RC6/E=!L)#B#OCTU3TMM\M.A]8Z&K]5T\4FA;W:Z[2&I(&EZ5DIII6PR./ +MP./$652NZLJD=N(K"TG5F/8T]H0YO(M]^2:V@2&MJMO'VT\4^*BSZCY7_P"V +M6F;PL-VGIUDII>ABE/!]$= +MU3^X?X^H6O;G9:'MVM=9V:]1T"25T+W"CKHE\U:B..EGZ3TF1@0&38 +MJRD;@CB\;'+NIIO:38P1[W*KXN2XYMX)^JKW#)!5U-3)U)+!'-^K.!UF)M@2 +M#Z#P64>Q&.+0^UAO48S73N1=;*5*V&WH7Z*BI&)VSZD,&'H=\'!XNNSL2U +M[9&N]5+&X,M,%!\%1)05574RQ+4(M.M+4H#Y7QC(.=NK'[ROOP=4&EB+Y+97S*@'JQ5G`WR>C&^V0@PAY@(DU,P`*9M%+3 +M7\QJ]2#5T*H]/+#Y6JD�.-I0=QU=U)SVW'>W*>1U1=.'``ZA5[N#3/ +M3QTUQ"]2HN/UIQY1&/V,_@Z=P9%06A&%50TNH%K=2Z6@CME^AB +M"W*U!2O@L2I66$#RM#(ZE=L!7('[0X`SFD>KJ7:=#QY'F->Y%L8UYS4_BWCW +MN0U2:IQ)3TMVH)#6,V21U!Y<'<#&T@]T8=0]/1N$5,.=6FR72JVAUBB-[Y!5 +MTL,-%<)I:)AUK&^6A#Y[!2,(3ZE&VS[C'&Z-1].3[_=-UZ+7D`"_%([5MOJH +M*N2YI3&-2.R%E/ME6]<>H._W[<2U'$M>-5$U,.]EBE37WRMLM;#=:23]&5:G +MPY)*V-98Y$.Q2564Y4[CMC_VG@^G2:6P1(Y?11^)<09%BF'%462KL[2U5CL0 +MA!+QBW2SE(01U&-F#D+L2Z`C=0P.",<-M:]I[#CXI8>QS8>T;M/?T4'/)9*. +M6&JBLUZ@C4EQ/27!9.F5A!+(1@R+#-$ZQN0!U=&,X&Q>!J.=,9N +M^)[I!$^*L.%Q%$`YG1W:+].E.K!`Z>.HKE!"^98`87(]`/?OQB4`OXC?Z\8L +ME?SXZ<'T['OQIPLM:E+G5;'P9>GT'?@2L20B&NWJ@G-4CQYR<,O5Q5-H.@F$ +M;1`)ON2)E9@F"`N>VQR1Q'L=!(WA&!IFRCE0&1@0H.>^?\N"VB#S3#C:VBRE +M4J@;"XS_`'NP(X*HZPFR+%"NH$=J><(@SZCMZ;<.!P%BL:X`JC^J-M0`M@KX +MF#GUW^O!+`,PNM5&WNO2;\`UDMU\^&KE%J>2CCIKU17:X6B2I>0NU5#XW4H' +MM^/I`/H".+5A*332:^(,D(7#5W-SM&@)^0/U5>/C%D>UZQU19?F#16H3B.H2 +M%!XE3T_A$SL1U(,#$?X!WZ<[\&GO]E777%IL]]UCJ2\-3R34E3,(83/(7D$$:B&'+>K"**)?L![< +M2SJI<90=.D&@$B#'KO\`64?\I+NVD]0Z(KK>L!J+==(JF(?A?J2IBF49[X8& +M9,_XN&*F+``OR]4X[`M8(^ROU\45K@-RF6A98:FCU!6!4R#UTM1&L +M\)ZO7'5TC_\`&>*O7>&8B&B)_9:V"XN8"="T&=+BQ^Y[U26MB:LU=1T=*K5+ +MU-:E*PW;I=I5&.D9R=P<`9V/?A..JRTG53I?E;+N$^0)5C-'W'%EUA.%;]&? +M)17H(Q)'ZF!9-@I&WA(P;/8`^O'.-ITP70>?D3"&J]EP:3G88*^')U/W`VVU5.MUB+1%/EX)HS'(.D##+%-0R1$KL%92<%3Q<=AOG#O9S]9D?^ +MRK>,I'K&N[O']XN>:J-=[7'1NT$JH\SYA3?`E03/E5QV.`"/?!/<\685;70' +M5!KK(ZH;C36ZZZ.J5HY*JB62!IU3&6#K@D;'IQ(SCZ$+[\0]=N=KF[]R,ITP +MW>)47RR!%3IPW[(8$L!Z=(SMC@5UE5J'3UOOY>UHU:%G/CT+$#I590&>+.W2I4]CG@K`[0+. +MW:UCX:>B%QF!#CD=WA(FX644-!=:>\2&@N]?4"")IHSYA$"XY=1U8WZ<= +MR>+;2Q6>',N![A52MA33>0Y1^E[/(]7<+;/X-1T)#<8T9B"E7$0$5Q@G$A?H +M.PSD9.P/#E2O`SQQ'AO3-&B2) +M%G!#4UVDIV"M4*CO5V28YQ +M!,W_`#$.&:*4Y#+MU%E8<1V'?(\1]$:X-=W<=X0A<=-76UPPW* +MEK:34EFE9HXKO0R&:.?'=)E`#!AME945QD=]CPXZLR(B#P^W[)MK729,CU6* +MU]N>((+[!5UM`!TH6B8K&HVV<9=,#89+``=@.!FT1=U.Q^J84%4V'5IO[*P9Z +M26WN#<*:GA5F"R1]862)L;JW3@D>S8W'UX,94IO$M*0Z@6CMB"NB/3T$K-6V +M2_PVZO`\D%3Y?F&R/*LAPKXSGS]!&#@D\:JURVSQ;DMMHYC+3"Y0ZCEH>N*] +M4%>)BD7)U!2!U9`R3VSP$UH)LG>V1*PE`(7<*NV_N>"&[^* +MT]@C35=P!P`I3)VSZ<$L/%-.L)!0Q?@?EYPS$`#UP,;>GTX=INBX%TK*,P5) +MM3TDU1J'HIHFED#Y\N!GNI"7%+JD%W="]./]GC89;-R0TSHRX14M*:> +M^TUWK9'.T41@%1/(^.RA0%R>YP-\\6G!NR8/JU1=I=;N +M7HC8^!=1P;*;K$-6LK4)BCEU!>J7H=[;035G4X)Q*[)3QCVZO$J4([?ASZ<7 +M?#4X;("`JC1A-B0/J?01XPJ9W2"F0"**-D!P%)V`'MG[#@JE3,:)O$5@'P=5 +M`P*_B:(!S'O\ +M_P#""P6(=3>*8X]Y@ALJJ>GKQ;8Z+_:*Q5E"_BRTJBJAE#^&KS()B.GNYC?P +MR2-PQ8R"-ZF:F-#I,R;_`"/UOX*P?*B=+E:[[:*HHAJM,U32+(AZ +M.@1)`Z8`V),Y7'I@\4#:K0&9G;C[*RL8J`M@P1'G(]`M07Q`4*/JB.ICCZ9_ +M`IJ23J=1\X(HTC9\KL)>B2-67N<]7N.+%LAH`AO/PG3P2JA+H*YT,U#431O$6A:*=7C);.Y`F.2#C' +M3_BXIVV<.:>/`([+I'U'F/1&X8BI2(!\N5O.$F_A]JAH.XZ=IFB2DI'K?T;Y +M7+I#3R%(U8,?Q-%XF_;#(R_>6VH>M>Z/B,'Q_?Y)AC"UK8@^S]D.\]-,1:/K +M^6]=6URJU!->]-UB*65)*WAISG[`*DUVL%0UWMMIJ:@1U3S2B*5<,K9"@!3V"MG8C]H;=^+:RJ` +M"^+*.@9N0T7."I:"_P#BR&2F2&K6D=0V`4*9V/IEBI(.Q^A'`=6A+9`G>GJ+ +MRTE-'4E.]K.E*MPH:6FE6I@EV,J`*'8*IZ>I1T;;'`&,]N(-SSG3I%1$/,%8CMY@0#V\X/8;,4L4`Z'C_. +MBS$4`X`@6];H-U?I*WZHMU#?*9HC04\`CF)4]5._B$RR2+WZ.MB#CL1@8XD, +M'M5]&H:9U,^-OGP45B<$VLTOT"7#6"Z:9>GDO%*LZ04R5RUL.#2SD,8Z5/$[ +M8,DBLRMON,'OQ8\/M2G5.5AN;$'4;R8[MZAJF"-,DU#]I[TFKN*^T7'YQJ>I +MJ*-).N-NM@*B)AU8/IYE)!]"<'USQ.T:K7MB;_51%9CF$EPT475I*CK==/2L +MTL#=;IT@O$O]\`?BC((!'IGV/#]-_P#*_>AG.(=F;N198>8DM'-"U73Q2T$P +M$1F&ZD;%6[[#U'#-?"APU1-'&!EW!-3YBTZBACEME8I$4..M8<3 +MA]R%J%SD-@D>*F01N0P!Q&O#Z;C&_G;P^RDFUF5&"=>2Q;5>]1:4KGK+=*DT +M,B&&HH*U%%/6QMNRG!Z1DC/4N"K`,,'AK$8:E5$/'B-4ZRNYIAIGZ*6O!L"Q +M0ZFL!NEHM-6_R\H/2QHY<'%-6!01U8W20#IE4'&"&413:;V_PGD$[N?,?4(] +MM0'M,MQ7&"@JJHB>DH*B.$D%JB@'B1JN,^(T8.`O8;$CTQZ<"/J!MG:\T5E) +MAQ&JS)],VNXT\UQH+E3TUPA/AR2VPER__P"5?0[8P0?IPP,:]A#'MD'C]$XW +M#->TEA@A95MI-31/%(S6N_4V1U>)"_41V`#QY*=_7I'":U6B-.R>7V2Z#*A, +MFXY]R*GU!372!;;?K/0SQ]0BE2NC2=F(_9$@\Q&-N_;&Q[\#4Q49VVDF+VMZ +M(EV'IO;EZIP(92PVQC@:L#*?`W!4'YJ +M,&GER#@L0-L<57:$"R,IR2(LD#4*#@'\(]GI;&^?3A +M\-C>AG.<2LR-0RX53N?7^?!3#!!2&50"AN_(O@SA@N"I/M_6.'6B+[TX'DWB +M4AM!\K]<\]>9=CY,X!E2.(NT<"#,KMC98U7=F.`,Y)X(PF'=5. +M1O&^ZR8K5&TCVKS[*WH44M@^#+EMK;EU9M=5O,;G1J299-47JEF9*.T(BA4M +MUL3/DA0;.^>IVZB?V52E=.NG#:37[/V?+JA^(@Z=W.->'>;=(Z$=!*F(J_ZE +MC1E9_*T^D_3CNLM6W,[6$$S5CB:>JD+%HI_\`8Z_I.J>/<[O34N`__(I8GE?`QV,M33;CU3&_IU;"4YI`ZDJC +MXU[16Y`$^9'K8^:K_6U-.U1'"LP20*21W+'';'IG'$L&M:R`H%P+G!Q]W5-O +MBOY?KJO3-=)3U#8^C +ME-CYI^_"OKJZ6#X9-%VZ2Y5E3'0W'YFIQ,6$BE88G(3/26C"R/C?J#,,^@`V +MR"XD@6/O]E`X9IIU"T:Q\M/D@1M37:R\T^9^FXM+SVJC1XZVFJ:.3!^6-3&\ +M<;*-E/=R=^HJQ[*,D5L/.'94>/5D"LF.N-R@)/]T@=';N!]!Q*='W]D-XB$5B'D.`//YD +M_=(`TZQZ?UTCI&:5:BEE;(),0^8G0N,G;I\2,YXG'C^(TCG\@HRJW=O/VE6( +M^$!Z:JHM3\N;A/!1SW&U-\N&?\#+T2$)C]EI(1WW\PQWXK'2^D2UM9N[Z)[9 +M<3;W/V"B;_:&@LFJJ2*::FK*2M,RNY"YCE(='],%9!(",=USW/#>!Q1-5A)'8]0TL4&'@]OD9"%Q$+T$ +M[[?M=)^_WXO3'$L='&RAW4>T)/FLF.PQ7.ZTPK(XW***AVR%6=<;[>C84;?3 +M/8'@=F(+1EW(E^'$9MZG[W#/<=.V^&OJW6>&XOX<[D]5/UP*2^?8/&0<[8)[ +M8XBJ](MK$`;OD?L4_05AT +MJR,,`2(Q[E<\/,Q#*H@B8'F/>G`\K(!]!X#GG0H4U+IZ\ZW?H>IIJNWU=3'IJ9I*=2W4IC57/1Y6R58!E!7?#(1G +M&#Q<<#7-9L/$/$'W]%7<;AA3?8]@H6U"WZ)NMLJ:!([;@<]/M7'T497;EJ"%U&FIKHZ%H'HS6,J0R)&'CD9B%`8=F +M\Q(!&/;(/&VU,M@=.*;?3:\2%]K**JTA=C1SSQM0K*%BK(9F5X3G'6C^BL5) +MPW?MW[XQ_6LS,]5MXZEP:="F99-5AI/T?J6>"HCZC&*J,,QD/?SQ%2,[;D>G +M<8WX"K4`02SWX_12.'KF>U='EIDHZ*K-=214]?;'3PI(I"6H:Z`GJ:"=1E@- +ML@J24.&5D('$+B&N+8)@^HYCWIJI6@T%TMOR^ZZKOIN]6NA&JM&23UND7F4/ +M&K9FM7@9M:E4)I5OB]#W?4(CMLA[-)/@N-MU167 +M*HA$]LM%;<5V,59A)B.G]F7,'VN/0)^GC,T`@>/L +M%,^R5E&D\L?Z*O%*&B)P':81#W4E>KIW[]6_T[\0E=I+9+@;\@I;#N`<(%CS +M]Z)B6ZIM=4U)2UEQM20/'F,2Q;,!MTD.)%.?;*G'MCB/>6F<*02&""IBCE`V`P5QML3WX%_U(23D] +M#])"QV&!L"">=U[R5!`(.PQGCTWO7GH+X22=B,<8MVWKYC?/KGT]#QL%8'+X +MQ/2>Y/KQI)*6NJY&6*10OFP?IP)6,A$TG0%0[FECQ)RQ&.H^GUXJNT-\(UL" +M.*0TY4@]85N^W`5+2$[&4WO"AW8HW3T]7\, +M#&M,9D.!.JG-+A;2]WU/<7*10A^A(HP07GE<[1PQKYG<[*!Z +MD@$^A1>\AK=P2W50T2[3Y\@K;UVI>6OP=Z0U!RXY&W"AO>MKA"M-K37JQ#YJ +M[GNU+0L#F&A0]E!RY\S$GCDW3'IV3FP&RCV-'/&I.G9(T[_+B>Y=`OPTL,=M +M434-VL.@'/F>'B>`H9J_F)7W6L1DJI98M_$WSEC@Y<>W?;WXI^S,#$$ZKJN+ +M:T`M"0=^K;C>#XJMB(*QDC*@>(?OZ=^+;@@&G,-%7<92EN1(G4]@K5A$PR,* +MS!"2W22?,!V]<'/TXN>S=IM!@E4W:>%D$C3W"1M-1-'=7^;PH7+O+W##V^^_ +M$U7Q?8.355>EAGR254_XH-87,11Z6M=MJHK+D25U:8022,'``[@>PX&PSVN? +M#[!'5GD2]NZR(?ABU1INGI+'RXH+W)5_,V=ZE^NB:)XZFHK7:(,,DG""GQ[A +ML>ISO;XILIDL,G7RNH,/BBT72.)@GJ=B2R1$[;_F>.:=("*C7$#6RM6$PP;3##IP\ +MTH/BHT^SW:]W6B@^=%7;WJ8TSO,RJ2!@#RYP8\;[A/?A&P*Q86R;"`?JB:QE +MM[&3[][E2FBIYJ_3VJD>-G::US0@LN\A#Q5!'[HI!GTWXGR,I#]\_LF'`D0= +MW^/LI/D!JK]&:PTC?34!8IK>L7BQRD!I(P9')/=2`B';U)X3MRD'T7T3N)\B +M@\`?XLMWGT5P>8^G;=>+CK&2UN%H*RAJ6I9-F:=1'XZ&;I[LH;JQ[$\4#"5Z +ME(T\PT-_D58*=,.I7CV/D@[E=;X]8Z1J-+2FEI4DH[WIDL^3X$A1:VB55`SO +M/32J-L@N!MWXL..J]56%3FUTQX'TA1F%IM+2':`7'H?NJ,:VH)*.KLM=X91; +MA;1,@QVZW$;*/L4;^/%^PE<93WJ/;3FSMRQZ>BD\.IK%PT?@%=AD+)TA3@'; +M(!8_]0['AL@DP4^6$F2BF6V+7VZI67$4YJ8FB:0%HY`8G)V[ACU`$]]^`6O< +M*H!N#/?N6FTQEX<_%=%#03QT[!*=(YTG*KUOXD5#[4HN-,M +M$L&8AI +M:9!D>1GY2JO5I=8R`-X_PN/Q1-.B-XTE +MBFJ)$P"\;$!ND%I#Z95=\GB7KTLW9(L?E[LH[#U0T=G5,NFETA?+9;5E5+?$ +M*.+<`]%.>MPP/5EE0D`=+=2Y`PW;B-IFK3>9O?[>YUY(\-IO:''?\T-5>EKK +M;ZFVAHX)Z*95IXJE5!ADD5^@03IV&?(5<'8CTSG@TU6N!`U'N0F&4"!F(D!< +M*6Y72UQBKLK2VVJZ_P!92L2W6C,=T8[>5E>,JX]M\G'"74P\Y'7''WQU6-K$ +M&6E.+2G,F.AK*>X24QM35$7R\\]%'&\-0K'#)443XBFC;!5XP%+;;@]+"!Q6 +MR"X%LR>!MX@[CPW*8P^T2NT\]6T%SLCC +M\7ZBI"R/2DY*2J\BJ"%9L^9HBFZO0:#5EKM`=0>$Y;`^%]W`2[JM"H0QL'Z] +MWVXH;MEKMM!4TQJJ/6FFT4H$:&F,BQ@8RRM$_F[=@&`[<-5:SRTBSN,V^:=H +M,:'"):1P.Y,>ABH:VHF:FYETL\9PJ?IK3G7U;;JRM#)N-MRRYQQ"O:`9=2CN +M=^ZE#5>02'3WCW96&Y7:>@GN%+1PWSD["H0EL[8"8&2 +M3VXBL7U;K',!WSYV^J+P]6HT9A'E'+C96^M=!J"*V6U=%:HCM:>`IK8[7J"> +M2%)M_(&:1FPHP/-C?JQL1Q'5<$)D"9Y!/T\>YTM,6//3Z\]KB +M2N[#MGC'!:A<`0`01N.-+:^2D]+*"#VVSQBQ+/508I*3D8SP-6`A.TP)5%^: +M6!+,A(R">W\QQ5\>P3F4C0)F2D%*H"GI8?E_F>(YC01`T3CB(MHHADRS!NP/ +M8\%,$0L+$8^H[*U"57!HN/W5R=>:ITG\,>E:WDYRKN=+>=8W"G`UAJB&+#7,C'^Y +MT['S0T:G.$&\N[,=\'D?3OID]]3_`$W9I['\[M[MT=W[@'6>X_AQT!:UHVGC +MQ+A\#3H-X,^"/7/$KA-N`'M;E!G9YC,$I9N7 +ME/4Q&EKK135BA/.\R*<$MV[9[;]^_$?C-J&HXN:5.8393;2IO3/*BPVW4B5U +M#3I35+1K2QO)"#X`7I$6'V(Z&5&P<[YW]>$,VJXM(*&QVQ((/?\`._U1M?\` +M1]/6 +MGIO0-IFUBP\P%66;Y.CJ*FD61>CK\-GP`R^A*_JMO7\^!L97ZQI`%T17PY++ +M#<;^?[J`YW6ZJN%C>&9Y8KA:6CJGD*JA>E=U@D)`QO',H./8G@79[PVH0S3? +MW_X0U9O;D:.GSU]1HJ&4#PT6I+_15,3014ESC^91,96%Y6C>5!OE&2H=B",! +M@?<<6AA.03O_`&^R`Q##FANL1Z3]$DM`)5:,6MIIHJ>HNEAN\E,8ICL6C:=? +MPC<@HK^OMP?C6![[Z.!^B!,7Y/'.,0'&H]IM\@I*DEM_P#\3.#CN3W/%IQHZ[#4ZD6B%%4`WKAP)COE +M)'GOIFJMETJ*6G99*.V:AK;92=*XQ3S-'6PL!ZJ4E;'MQ.[(K-KRY;'K@JA.?<\$O!+M=$^]EI(CW +M]U)QT'Z/MU/,:&@JJ:5NJ2)T++,!#DJP!SMOVQVV(/`.)G-E,CGP2S1D=D7* +M`[C4P6NY545HM[VZ=^BJ@1:B0I,%,GF5V.Y*Y!5MQD;MPNO0STQUCIBQ[D*` +M`"B\53'4FL-0K-ZCY<7Z@Y%S:?UC:X*>IU1H8?*5$TIC%0: +MNDBJ8TZL'HKXHIHI6C.TR2(3T,!G&/?A<6*I$M:?E;R^20\LQ-"UC-[:02+\ +M08B=Q&\);G@FL:<^K9CC:WK:.6;DM>_.>VW?6MCLT +M[V6YUL4FHKG5"1(RI2:HC61B'(&[!I1@_P!TG`R3Q8MFUFT7DS%@.\"UU%XQ +MKJG8U()]_)4ZJ=/UCP!:F5+;TCQ2L\J*5DD&,$*21MX0[9[['/%P9B6WB_FJ +MJ_#Y==5E112V^/2572W2W-6^!-$BI(,31_,,70END,"'/OV`X0Y@=F:1[A.- +M<:8#@=$_9+30"3HBW2MRT +MM;:^WWBQU%ZIKM;8OTA0(:&:*Y)$"5,<;PU"&4Q,'0KAR0K(1L,AUZ51P+7W +M!L;VX@Z6G7=N**HUF`2!!W?;FFI:K9RFU0AI$W\K`$K&5'5J<-K,L.,>ICUT/)/NJ-(!8Z#Y77?-KK0^D:B +MC-MT1\3U55%0LGB:VH8J:H/H\,JT$A+&-Q3` +M0"3Y_=-#3/Q":GI9FDIM`\ZK%I6,EVEJN8E+2@DH1T/*E,)JEB1E8D))[8`\ +MP`K]',+!B)[BB6[4KN:`=/`CQ"84'Q871H(1;:+7-EBQDT]%?:VM*G``,DB0 +M+YL`#&XVP"0.!QT:HM`;D$<[?,E.#:S[@O\`_'[+]"%6`!P-_H>.MP2N:2OK +M-D9*D$=LCA,`%8NEF`ZSZ??;C&@3=82NMF4J0<'WXTMI>:H;R-D]N!Z^DIUC +MMP5$^:1/C3%E\H)!S_+^O?BL8]MT?3IZ<2D'*/+@'&0K=1632FF[9->-1W.KCHJ"DB/GJ9W.%49./_(W5 +M(JO#6YBMI-SL]@^%+ES7W?/$BRF(@*._6&`2L2U: +M>J(NA)9!4M$&0](R&WR._MG]_#(HD"3N1GZT.TWIE:=H8:BJAC6.IBJ^CK(< +MDGI]CZ9]AQ%5\0QIRC5!XBDYP+M6ILU>B8[A;ZAZB"D%5T=(\N"-@<,<[\0E +M?&D`N.]""D,XB4E`JL`2H/^'Z[G)X9I[2$&%/40&M`"YT +MNFE6A+FEIY9`%_;SEA_C.!CZGUQP^S:3LN819-UZ(W8^@X54Q0,E%LP\/RN%P3Y:_LHS7STE?<*2ZR.!076W&2Y1@> +M7PZI72H(!_:296/<;LG;;A&%J2R5;]6[RJI\%R<8R244X]`AXM>`KDM(\4#C*);#A9+NK2.IY@37 +MJ!A%0Z@M27)5+962MA4JX!QLS`*?^MN)D/=U4;V'T40Y@:`(U^]E;?E%%2:N +MY::VT@M0*^6"F$=,^Y9@TO%0V]E8YM72Y^A1^S2YCLG` +M3[\RD+=M34UEYX*KI7BJT;T\LRS`GZCOCB>PO\` +M$P[\.3Q'/<1Z0@ZV&<6GOFM*6ZODA\)B$$CL27>JM;O!(/IU +MT;Q/['I'`FRL4&UC'?X.^SE+NI@@N`B/L#\Y2YL")3TUXD8W +MQPT79&.8??-1>)IN=#M/?W1WIFT5U+H_4%CEAJJNVW*E_0[SM*VS?VB<]MY!?#^>5NG5H;EK* +MOO1L=NJJM$DJ9ZVCMM.T<#2QX""06VB#A%SX99222.+5LK",KDLJ-L1)X_$7 +M$SQ$B%0VXRJ'L>TV@::=HD:=[G?.RU\\^:%+5I2ZZ0HKTE0T-=5M5U%$?]V> +M;Y?Y*:J1,,R@>//&7&W2X.,]JK@'5<+5#A=ITW3>0/16M[6XFC&A@=XMFCND +M3QE:Y[]R[J=-\M+V+I#55%QM5[M]SAJTE;HJ('FJ:.?J8`CK`GI68'.5;8C! +MXON$VM3KN&4P3(CP!^8/DJI4P%2D2")'$W8[_NXE*+^TXCE\E&UF]F3I=.'6%/)!HGE_1US4]PFM5CT\*B=9 +M<2.*^GK*MAT#D$*1H.:6M=NO\`,?F3(/4<..!L17_BL>VV9S.X2'R.[Y)RG3LZD1>#Z" +M1ZA*3F=RROCUNFM5Z/N=%37*XVJJU=;*1NI8UO%,H%UH8""0/$6)ZU$!PR,` +M`.H#A_"XH26/&A`)_M/PGP^'UT0M6@Z);8#WYQZI7V^V5^IKO%/-:;3<@>JK +MM];$[J]*7P4ZS&Z]?3*2I=&#JW2_9F(><<@RS''G'W'U"U2S%X+A*:=AJ+K= +MJ"LM.L--V^QW*6M)J;K161JAXI,$2/)#(.LE@&\15/42H=#U@@@8NF&D5*;I +M$6:3`/CNC=Y'5$85KKAX\?>JE;ER#YM4EW=Z*V6^[104_P#]_0ZFI4I32D8$ +MD;2LDRJ5P2IB]>[#/#=+;N%`#7DM/!S3\_A]?`+>(PKP9&AX'=[W(>?DC+%@-U,M.A0G)]#[;#B2;MBF!O0PV2?YA/>2OTQEWST +M\74$"Q5*!E?&VP-E'OCC7);YK'8^8]603].$P5D7E=;$LI(8`D`_?C2V(T0# +MJ-5,:U#5/)/)3P/5Q@[^".H_F!O_``XJVT06B0CF +M`.T*KU\K62$I'0U)D'_\IMNW?V]>`VDE/O$F2-%LK^&JTZ>^'OD7<_B#U'`O +M_J#JCYJU:>9PA>UVV.0Q33PG)(DF<.O5C(2,=@QR[MG:(V?@.O`FH^S??KY< +M%-=%-ANVCCPP_`PWYGW;N!XJDG-+GE<+_45U?2RJLO44CFFE++'Z@`'WQZ]^ +M.%OV'B\;5=6>;E>E<-1H4&BGPW:2JCW_`%O<-3UP>JJQ+6NY5')Z3O\`7U^W +M;B0;T?.%&:-411KL=+6FP0;3:3U!)_O<2&J4N&4@]72V^`N#W.X]O7C3-JMI +M]EX@K5?"MJ:%9\5Y:U5)@N,<@E.4+J0VX.-@/7.,GB7PV)HU;M*A,7A7@0!H +MF-9&^?3IC=IB$V`W(/BZ(XXWZ1$P`(4DE3TG))S@_F<\'LH$D.` +M1!V>V[:@GG[\E7365'!%!<+?;8$^1,!CI$.<4X8=?0/890@#L,8].)*E3[^(#Y^!,^B%^9.C`VD=`7JD2.&2AO5TTW +M+3X($*RL:V)<>G2SRJ/\+#U!X9V3BCUSJ;M[6F>ZQ^B(V@UN:09&OAH?D/-. +MRW30W_DIIO4%4*BMAHKG;JNX,S=0\.1&M]43]#T02,>YR??C&4RS%Y9U!CT< +M/64H/EN5NH'[CQU^RK_3T\E*9;25\6>&0T3](Z1(R"4.1Z]^GBZT8[1$UOII*VVUESI>B>FAIA.5!Z60-Y!W_`!@/CMVZUS[\+KT3`@2F +M*A():_W[^ZK[)<*V>AE@6$5-2DGB]$C$`=#*ROM_=8K@]\D'L!PSB*#2&U`X&\W\9O[X*0P@`HN`WYO0SS4%\>7,:NU%\3&AZ^JJZB72^FWCU +M4U5(H\>GEJ4J5C=@N5\18TC?K8=3#`&P!XN.P7@47/:9<9;RM!/V5/Q>&.5M +M(#3Z:^L]T+5KSTYRZDT]7V*[M7]%YI"MQAH8IW'C0RS2RS>*1V0>-3L5(S(W +MLJGBTX;95*NTT7B6Z7&AW1SL>Y0N(QSJ-2:0W_M\K)D:,U=8]5VG45EJ$2A6 +MK\8S>8&";*I*99$!'2XQO@`9)(QMQ1MJ;`Q%$]:PY@V(&\&^G)6;";795;#_ +M`'P2RYF<@-&24PO%-6RZ56M,4T56U0KT51.?*F)QLA(;PSX@4D8.3@'AS8G2 +MC%"KU7QD;B+C>=?.W-*VAL'#U*0<#'/[I*ZIY.7J\VFU6NRWC3MQKO#K$2?Y +MGH62229E78Y!*E$!(WW[$;"Y8/I*QKYJ,<)BTKL9S@&#WWJ/U=8&M6J +M^8M0LQL3)!G0&29^J +MC:FSG@R1'L?N@VAF`T'%I5C46D*8\I&YZ9)1-6RQR$'\15`N"PWV`[\&%T5" +M_7]@`4,QA(#3S]8^RMGIG6>H.7_P]\\4IJF=J2X6*U6FG$?G#?NY$LS`9M;?926F-96CF-R,U;JS2L%)I +M[5^E*JCUP+9'X<@L]5'*8*SPU95=:25)XZE02P41/%VB4F-JT#A\4VE4,AP+ +M9X@@1/\`<"(/&9WE&TW-J4LY$P+CWR5>.9--H*V:JAU)HZEK/]A[U3+J6T4\ +M)\,P0S=25%&"K8S%)'/"WE'FIR?4<3-)U8L+7_$TP=_H\,M-8_'E' +MGKP^R6YM,'L@_LF[8-962EE33]ZTON8% +MDZS7FJ,*HDDBF>*4'(9&((_=Q5MH2+A&@3;FCK$G\>$OOWEA +ME$@/KAL=CP3MS!BOA:%0:-D'D;1Z!='_``QQ36U:],_$2".Z_P!UI\U5S$OE +MSD>2JO/31,Q;J\0XQ]NW]'B*;0&5=7?6RFP!XH?TISJT11W.*URZ\TT]<24\ +M*6YP!PV?PX+YS_VX'Q&&:]L:A!'$!L%PCW=77LFK:66@A>EEI9*81AI,G\61 +MG'IZ$[]MS[\4[:/1[K3GW!3&'QS0U*0#P2K@:>GCE@@FDE:,R`$!&Q@?YXSCTXI&W:$O(TT4ILUW9@(]IZR +MEGB,B.4$DF21NVW8G;Z;<59M`R(WJ2=1&J=`C!488'<$@^^"=\\6-F";8@)5:L-YOK^R7<-PG,W@3 +MAB\#J(AD9(ZP<;X!P1D>@/WX3CL+#06C2Z@\<&@ES=')'ZD@:UU.L-+TV)4J +M*9IK"C<14):UV@W^4*GW,V@I[[9VOC +MRU3=-2Z-C(-'-U;=0."H.-C[J,[GAW!')5@>"C<2PAQ!ULJ[557I4=U'U'3E1GV"GOMQ7-K4?X-1CO=D[1$.!XJPFHM+17VC^(# +M0=/7D72G_1FLK8)`0"\$Q5L$#8%'$;'L01]>*EA:[F?IZIT,M/<1^R+J6FW+ +MZK/^&\TNLM,ZMT"\0AHK[;I*2F4MDP5,RL3$=NZRPJ?3'1WWXF]H@!S*Q^)I +M!\!^WS3#JN3M;@??S2GU'!\E56>LKB:9;C7TU?4%X\")S#X.6-+?9XWZG62H,KP0@]P.C'54,%'977&W%NV!AG-(:X?"YQY1N^BK6U*K +M>L<&CLZ=USZ?N5K[U];Y;]JFJO%P(K;-XU33APAZTB9VB8OZC*!3GML/7BZ8 +M9X93:T:V\_V5:KT'5#+1X<-X4_R3>Y:?Y@W*QW6EBJOFJ610K]+`RQQ](*YR +M,]!E[9#*Q!';",6T/:,MENBTLD-T1WR_NVL[/8;WIZCAI;I%1HQFL]PIR],\ +M:R/&WA[AT(95(565M]B>W%2V]LBA7Q#*E26S_,-9'F-^\%3V$Q-1E!S3>(L4 +M?Z:Y@\N]:U=DN]\M-+HW4E.D#W"F>@$Z1RAC+O5Q"*50X4L6E!'GP3D9X@L5 +MT?QN%=_!<:C9M#B+?[3(/"`1Q1K=I4ZC2TC*0/V5>=95=-662\UU/6"2EEG2 +M!I::J<]#JY9R\1S:+VF*ECKH/LJ]BZC'26)-R1)`UAGMR +MJ[05$,+'PPPZ50E3MY@,RD$[@;=N+`UYOFWJ*J,`>T-T"<',V047+"Q:*H(& +MN*UEWEKY95PY6*EABBAAPIZ@,F5L?WESW8X&P54FL7.M`MXS*_5I&YVX^836"/55`X$\#W)E7CEQ-8HZSE=076XWNU6ZMJ[OH^J +M$0G:>G,9:JI"X&&\6*!*A0-W>&=0.IG`#PN.=4(J/`#HAPX'Q. +M"%-T"[77'V4=RFLFGUOU+<[C77ZL2SSI-#3^+'%%41R2!6CE/G_4J&:4@@$C +M(]20YM%K\N00,VO'O'/<.&JWA6-(WDM[O)&>GZW2=B$D]H_15!49$@J*6/Q) +MY23DEJR4L023DE#GOMO@BU:55Q`(2J=6DP$[N'[HY&M8ZP)43ZIT_IBC=0T$ +M==='HED_98Q^1I)=U!+O@>90`,,JOT=CAP,ZH2KMI](!K=.7^%^BTK97J.2/ +MIZ<=%R#2=0=@O(\EK1^*;X7;C+I*[ +M/:JBMNO+^H?P/TE3*PC`."(ZA5WAD(V9&(!]"PXC,3ARRX^$;]WOO7=MA;=P +M^+_Y1%Q!!U'[<.2UXZ'^#K3=%;;E:KA8K7?&\,M&ZQ#Q!]3MOG.Q]Q],\%X: +MJUS3FN4?CQF((LN_E1KO77PQZ\IN7NL)KU>^3MTJ%IJ.25VF?3DS';I8^8TQ +MR`T?['XEP,@HK46O%K%1CW/H=IMV\.'=RY+8I>;I4R23TYD+$AL*IR-P(Q$K+'T]?X=\9R.P^OIPNGAFEA!"#VA4 +MS5`MF>EJKPJ*!*A`>E`I!8>H'?/IQSW;-$E\M4OLL61E351E62-9F'DZ$"'# +M`#Z^_I]N(8X$@@J8-0P&PA*YW#KI0:DY:+`"CL6]#[^O;.WKP92PF\I;&EIL +M;'Y)#7Z=Z@RP.*40!3PJC+;``+@ +M$C?\SZ?EQ/X?"P03HA,1B6Q&]`YN[BN^>J.J:*)&)P=S@8R2/7(7\QP]4P(< +MTL.]1]:K-T%ZS^7NELI;I'+"USII"5+`E9<@E@Q],Y(/IYB?3B.;AW47D$=E +MRCF503D=[]ZCP5=+W;:6KGK;;5S304M;`&,WB(>E6!P"K9SG/$7 +MB*+J9@&PO^WPD").GV\%7;5%B2RSU]DNL3)13(45\DM&"<$H3^TK#!&= +M^X[CB3P>(E@D>J5BBX)0P[L/<@]+X'?)X?Q< +M/&8[X3`I`6'O_.BV&V&W15O.'EN98XA0:KTI6:AXF*YZUH$ZBWB/W2,C6\_?L>"87Q0Z4CCN5W +MGMT(I[/)5M=[?)&N`14('9!_@$AFQZ[GOCB3V%B>PT&^[R0U*ME?VB3-CX'_ +M``J<"L6F%(7D96ED1]VZ?U0<>+G&^#UL/LI'KQ;NK,`;A*>>;DDW,^:%[5$) +MM8VZHF#,*=$BDCC_`!%DBD"L#]5P<>X)].-8^J&4B!JH\2YQ)]W%E;'0.J;3 +M:N6\UVK$BCN,.EZAH.EAA/F9ZF$.C!AO[%N+7L9QJHZZ*DJY,$/T`CI<@=P8S(,_3?A)B,O%+ZD2YI'=WJX]A +MYX:TYL-/XLHJ[%<*D.5.)9%,+MN`3@])/L"1DC;-7VK4<&TQP<%*[/AS2 +M=`1;UCT5,4L=/;-0ZM6XI'5(EM_1J/44=AFGELY@\*H"Q!IJ.:*11XCKC+)AF!8$91 +ML_X>#ZM9PASAVE#T\&V&DN)U3QV>#$B]TOJG31_27R-LO$URCE4^(8XSTK*V[(F#NJD](;'F` +MZ@,$"*;4I,5TTU.!T2"L!5Y*2) +MW7R.TZF:%L$).W3^"HER)2PH<34:)W.[MQYP+'B.8"#VB#3RTJMIN.\>_DE; +MK"L@AO.F-?VE'BTY<5>X11^`_135(+"5`DFP4X8J",JK-&=XF/$S0I7--VHM +MX>_OO57J5,K@Y!53K:T6HFFM%'+=9F19(:FI`6G6'N/&8;OC!4H#C*G)4;$N +MGAB>T;?=1[L3#^SYE+BZR@*H-;2#1$0$"^J*KM!LF)1],DWBR14TW1@;2(._;?@=@.A1+G@B0NN`4S.7BD\+ +M'=&['\_Z[\+IDZ0F209A6CY!Z>Z[I/$RTU3)4P%I*:I198)8F\@26-LJZL23 +MTL",+P?1>YOP:_NFZ)+7RTW'^!YSY!(CXR?@^TERRUGI'7'*&.B@T/JBR)>U +MM$4Q=*&11TU`IR@,%W&.%;5V:QAZREH1,>]V]=*Z*]*:N(H!N( +M[3FF)X\/>]:_K[IK3QC2IN5BI:MQNKE=]CL<_GCB&J7&8JW'$.<;%)[4U[-2 +MPIZ"UU/ZH=*^3;&,8!]._;@7JBZ\(AC7,)#2I3E1H^^7*]&X&@2F5,!4WW.> +MYQVR/XG@7%OR4C%B5MS6O(#M?5;$;9(]')34DTD3/L&(&5!`W(/KZ<43%B7P +M5+;.):TJ7EN!6F$:!BWF5"6[M]<>F_#%/#EP4WE$RE[>J]:[@T\DRR!8P&QC&.D8]3_GQ,82B`_[^)>G0BZ#%:224`5CN49'`.%R3U9+_3'Y]_3A_JCE[00IJYCD +M&_\`RAVK41!G3`#=2B/()9\8&,_0G'UQPWB\$*C;E"NQ$F`D[54C5C101JU/ +M5>(QIW/F19`"`-_1@0I']['?B`QN#?!SB0MO<-=Z$M0V>+5%ID1X)([O22]- +M13LH5U(!4E,9ZL'JQZ%>E3N5/%=H%V'J?VN1#H<(=;A^_OY)704%10+7/+_O +MDM+;99BW4>J2#PBF5'JK +MWF:&WW-7=Y/1%E)8!@?02^*RGTR1ZC@+`UB^D6-^)NG=_BR<`_A@Z[O$>QZI +M_P#,9[?K?E.U0ZU$5?98%6)DW1HF:*5"Q[,A5ZA0-B#(#V!X+V94ZJO('Q#U +M4=4::-N_]['V!Q3CF`XF? +M?OJ'=/4E+>[9XZ!H):@8F253A)AU*P)&<'(QCMGBR! +M]X]PFV!V4)A6/1%=)0W%:11+#-3]/0@&2^+PX/%9(JF.0N%7(ZR1`B]0]R1Q%8^BY["X\0? +M+_*'PS@T`-TC[+6ASCIS!?>8U'32+XSU09GR3VID922<$@F0MDCL.)*DX'*8 +MT^Z):Y_5Y?)5HY;U=]ME0U53B2ENJTK;:?-'JNI@2NIH(IDC+2J0"TC[D8![]M_7??<\0F(EA+3Q5JV:" +M]H)[BK-6CX?A-I"[ZBAAEBIEI^NK_6>657&0&QN?,#Y^XP?X<.8W$!C()1>SMEMZ +MPU(NEG\<8;0W,3EMI"TUDKST]A>LGD23)#2S8"HS89'"QA@4P,X[D#B8Z/T9 +MIOS7N/E*YO\`B#C0;@GJ8;K@R=3#92"S4>HX'NW*C-<2PYM_NR3=THJY(Y[/56^ +M$"F8L(H*@^?.Y)_:)SA@<8&3C@EL"X0=46+#HHZG:Q+"JK<[[25()$L=-2+4 +M]/MU-D$'OL?\^%D'A*:RN_ELOUGD&`O8?L+%.L5%^8Y)GE&`#D +MG.>*ICC#C=',<18I$U)_=CMC(/`[`0)1+AF,A1B@=08G`]3[`?\`;AW492AA2F8!V/;8R$@?3B8PK,TOT^EB@G%^ +M>&Z^@L;GS]%8KG[RTM57H_X&J&S1U$UN:CJ;9`E1GJGHZ@.RROZGJ!#@>@;8 +M57*2.&7J);.=CVV +M^G#]!I%E+57]G,+>REY?ZBG\82(5D`7KP1OG[>AXFL-AIARCW8MP&4:I3W>I +M>7Q9(B$._4`-P!],[GB1I4&@)JM5,W2ZKZB;Q_*ID103U>WW^O\`7KP72:1H +MAJSP6W*&JB5WC9)NDR;$AFVR.QSZ4'4C;DR2+CI!W(ZG3J1@=FPIV)QQ0,70#*II.^$HRB8^+Q^_ +MAKYJ!K]-QW!*^_4$1IWJ+>\512@$=)=HBY4#']W<>H8$9)/#3"YA%,Z3\I3S +M1D.4ZB$_>6JFX\M8],2R(*VAJHZV`9PR/)EE(]B'"@D^N/4\1.V&7%5ON/V3 +M#634CB+_`"^2^_$);AK/3^C>8%NAEIZJ:V9#$9BF967QX64#8JQ8_P"'K7B' +MPK&4:CF[I'?=/T&`-R.XGW[X($T!K:]VBX4NF[C45EPT[54)$$3[KY>@AB<> +M8A%8,#DX`]."7X-H!&^3!3-;-4:7--Q$^/#Q2EU?IR6WO)'+%`1%4M&A1`%F +MC!S$ZXVW0D9'JO%YV/5S,U0&*+9S`:C_`#Y(6N'BZ>.=&QM& +MZ2%E!/TZ/W;\2M6[;[OL@10#SE.A63S`M7R-3K.R4LW53I4O*[@84#9D)QWV +M.,?7@(/[5.4RXNR!_P#4E/I&BDJ;'<;_`%+X:H>:4'8R12.P*$>JXP,?;;L> +M)-H(>&[@$,UP!S'DLN*BBL%5^EDQ26FX2JLP"E(J2OP,@')PL@Z6WP,YQZ\2 +M=-YCLW^?^`E9`UQ&[W[_`,JTW*B))VZ)T4*'/E!P",=Q]#U'@;$5>S`4Q1HA +MH,G.,G,=2_A-U,!VZ89)ND#S-XF!WR':H# +MZ):>2@\12TR6CPM>WG?P6OWXD&GMO._5EOJ%+134U&93U]8/53J%*[#`"JN` +M=P!CZ<'46ES&N")PF0LUWGYS^Z#+'IQ+1)+6(D)! +MKG``IJI19'-,33*T;:BM^Z$^'>X7.&1*F&X0BF6-SYD8DJI0MZ^H&_WP>(G"5"RF7#>I +MZGA)Q#6-$Q/[*LO*^CM.G:9KW<*:HM\\BLS5$RGIAC&[,<#&,`[^V3P+B:CG +M$,B2I)F82YUA>_W6F7XA]:3\^N&VT\M')%BDB`2(+(04!; +MH9]L;N?;/'12FH:Z>JC7&?F*M\HIU[M_[*.Q!=D)&^->>G@;GNA7=^*_G +ME\/_`"!I]-5^M[V)M06^D6TZ5LD+K-44B&$Q?,LFNQ'"##C!3;W'4E +M?TM91U=)/&[I_A!.<8/<#WX55IN`A(9:H"E[<:MXY#&^%!8@=1V&/Y\2V`9, +M'DBL5B#E@#@ES?9?$$DE/*_C@@#I\OKW![?7BR4J319!MK91=!M9`,9 +M4YRV?7@SJKV";J53.:4%W5XE\&4T\\GGW(PN/8>N.,RN-R(A,!^:9*#ZJ-I5 +MD#IU(1Y549&1[?4[\/LI9A)2752/A-T.UD+M&J^%]-^Y;TSC&_\`IPZ8`@"4 +M,VKVKJ(GB*)*K/(S8V)08'V]QP._6R=8X%VE@L&V0@54$55)*M!.Y@D8;>', +MOF1@??8??'%3VSAW.&9NH@_1&,>#:+CY$+LK+<:&.XT,@8TTLJ)A01A"V>I# +M^RRL`0,_8=N(*A4[65VMSY>[IX%SP'#V?\(LY;ST\=XJ7J>F"Y2T127H!"O- +M&R2HX'[+$PAO^K;'JK&T0:<<_0V*9.91E,>@;"9VQY.*W3HRR3K<>26*HS@\8]^%TC:_3U/!4O3)*D,]//)-1] +M.#U)UY`(&^.EPI.Q\O$I3I"HSM:K=5Q!EMFF)^?G(]5)7G3=%?#+0!YR]11Q +MW2ED5\CYA4`G1:3-79I +M%9XY8)%9G7#-@])`W_>/3Z_?BY4P'4P2@*[[W69IJU4U_I9K%5.6I:Q0DZYQU +M!V![D<2&%HL55+RR2=/A^9L^5LQ*2??A^N&M9E-DAM(O;QN1ZS]4^/B4Y(ZMO>O=0 +MZNH=*W*LBCMUL#G?JF5:*(2E5`\V)`_UQOZ'A6"Q%.FSJSSNDX;#N=3#@1OM +MOU/V57Z>\T\-KCMCPF*6!BSQXP4R0`"._5C&_MC@JH_=-D4:#W.DB_!6%^&G +ME+6:UUO172HHY[=9TDZ?$?*]63N5S@YV./;'$'CZYJ'(W16_`87J&&J^^2YQT^Z5.ZHX&B8+OBY-.[O=O_`+>]:DPT5/)!(*Y7B550F-7(8_M> +M@]3WXMK1.ZZXFXW@%$]OO$T;K2,T]9$=XR\C+W]`0<^I`W]>$0EL(1?;+W2P +M24M=5376N#UO=34M7'66NKGI*RF4(5># +M_$+U/T/V>:.S*+2(@1W]HF?&1"J +MQRZ^)=[#"J*"I(7<`DDYS@;_`)YX%_1=H60[JEB2L6KJFIJJGJ8'B2G9F.WH`=LG +ML#CT_P#)*ZHQ!2!4T.J&+_=W4ICI?`(!P/7OOP=L]AS61+B'-,60555@E@E' +M42R'I`^G^0XL=.G<*-JL(=.LH7EF\&=RW6C'&Y.2#[_?;^'!S6B8"VYQ/9W( +M>JKC$?QJ)2V,-Z;G;MGZ\.&G:"D'#QVBH6KB*JF"K*>Q+=_^^_Y<*#)WH'K' +M"2$/U5,6IR"&IV7L"02H_K/&G#<2GA3,SJ5"52-*"BJTKC8GISVQV_A]N&*E +M."EAG%?*>DB+?+31R00B=6)4?A..D_3U_,9XC:U$/,GA"?SEFF@"/[=;(*ZA +MN-+<&>"24&)6`ZU=T'5U=.^0,(=NP8>_%!VGAWT:S',$D7/<;(R@_-2.70E! +MMCI#0:CL,TLD4$GB1P2MW7)8J6^QZR/Z!X.R]7?ANH]K*H,VD'YILN,&;`; +M_105HNEIOK:GM]OBD,!H#3VV624(T_RY1_$F+[`OF=@=NDR8V`VFF,@W\>28 +M#"&ZZ&_[+GI^RUEMOB4GTSMML!6L(. +M4W5FITWAHRSKXHTT/K"\5Q:.RT@H2.EE(C"*B,28KGQGQN%C!R?<=([D<'8'" +MNK5,OGW*N])-NC"4>L%]S1Q/V&OIO7G3U'<+A?;A<[]>;E/7WVKE>JJZB9\M +M4S,$3,+;0)*>_P]U]9;M:R?HYY%K`D-4G2> +MD_JIE)_^+-P70>0[,+0A\02)RWB_E=5_YR?!)K'4GQ\47)*BM5!)R]UA75=7 +M3:HN%),]#;J&GIY*ZN29HBICJ(H8Y550REV9"#@DA%;9[JF,`([+C,_/Q\KK +MO.!_$+#X?83L2UW\6EV2P$27&(-]T23K8&RJS/\``=I:VBOOJWRY-05!IH^MP2<]11\#.P7/J.!F;/8W+)UDCP,7[]R'Q_3O$5':7$`GGK94YK +M-"U$][MM+*2T+.%>11YF09V;I4`G./*=SL>&J.#?4G()_;]E( +M#I#AZN5F*[).\*0MWQ.V_P";J+9JNFKM.W^"0+54-9`T4L4G<$QL`5]P=^_L +M>`L1@"QQ!;!"0]F9H-)V9O%6=T'S2L6JX*:"AKHFR#ZYQMW.=B.V^P_=Q`X[ +M#Y''+9"T:VXHCN4AJJ:5"5BFA;*`$]OK_']W`V$I$/NI3#U]',C1 +MD$Y&P'Y^^>+/3DC@4IT`DS=15PA6)6$4T'F9*$U +M,K,(W;*MGJ``&!Z<.0=ZW5J29:L@THE.8RJ@MTX&,9S[<.M,(5P!D\5']**: +MD]74H(4)V]?\M^&W.!,E:S%MN*@YT>$-(WAR1C#!"-QG_/U^W"7IVBP/:0;% +M?$;P9W"]$B!"3D[GOO[>G`;G$F(@)=6G`D*:_2;4M9;S;7D,$,@GSU9)+!`6 +M7/ITJ`?0\06.P+:@<3O^B*PE5IAIYKA+224=]$D<(1&*:"R9M[NF#8=65JQ76AN86:.J#([CR]:'NN/4 +MAE5@?3@+%82'6Y'S'N4#UF5K9'L;T+TG6@2H\)5<9C*`9\>%L`YSVR$/?U&> +M(FM2#*P.[Y(U\%I&LK#J:.*TPUABEQ2)5+/"X)Z9,QE5'Y@])'IYN%4G.&(# +MCO$'SO\`L@ZS,]/(!)2RO%T^1D>W,5JJ.NZ5C#'/ARKLDOITGIPI.1L6S^$8 +MM%,AS)8(N:&/Q*M%WHWM-YIJ:)DJ(*JBKJ:FF<]*D5%+.A8' +M^\IZA]&!^G$ZV@YQD\OHF6O#?BW>_?)/'DEK:2ZZ3TG#I9"138;D?RV\DV4L$EF=KI`D"6^*&42EESLQP"! +M@Y&YS]0I]^%`N0%5K7`VU(_=%.H?T?>X8ZJHIC`\U)1N&"[$K%X3X)&V&C/U +M&?KPFI7J'7BB=D827.`W'Y_<)&UVFK0D\E5*8U9<@9"G)';./N=SZCA3'$V* +MLP:VG`WCZI';YD +M4>6D;`]6P"Q&2>+?A:`ILRA<4VKM>KB<0ZK5/<.`X#W?>D9>:U?P0K!%$/10 +M2?N6.2>#:9*KE6I-RA6BJNF<^*S2@_WC^'[?PX;<."U2=>%GN`:H/$H<.<8] +M>^^W[NW#M+X4S':A2T,\:2RJ"44G*;')'8@]N&!*KX$ZKI?8L^,CL!PAS=Q63*C)R +M&W"`L`44S$OVZ?7/OP@+9*@KR[?*2#&X!&W<\(<+2$XS6ZH[S24/53$`=6^W +MH=^*UCV]I'L<8L$B)T8%AT%`F%/R0("BI`N2"%![@_?Z?E_/AZD7#3 +M1-V5_O@SY1:%-!J#XA><5VN=)H&S51M%JM-"_34ZCN)16DB&,-X:"2(=*X+. +MV[!4(:7P]!C*9K5-!:.)]V\UK"[/Q&-KC#T!;>>1'H(N3W`;U;OG1\6'PR\F +M[?KJCTW1UO\`MM=4>UWB&AN6,I,1UY1'5>J,RKC88`/`FU^EF%PF=E, +M9WS$#CW\OFN@]'?PMQ>->*M7LTSVI-IX<[K0%JG7&BM67"ZU!YAZ@Y6TDCDNQ;!.(JT>NJF`&@D%]1T``7@3O.X!:I^>6JVU_88K/= +M+!IRBTQ%+-+!85I5EFK.M2OS%ZK0PDK*OIZ,HC1TL;CIBA"H"R<'C7_J#4ID +MD<3O[FBS9\2-Y*$PO02E3HYL9>H[4#X6_P!H.K@-"2>UK$*B,O(RZ!(+=::[ +M6-82PZ7J)C,8`<92)G!=$R``N?*OWQQ:QCW.B;J)9T>PU&7AQ;?BK#)1L@+HN1N7S@COMC^7$=M`TRW2Z9?39#BTR/>BVJVQH +MKE0>*N4'A#"GT`SD#Z\0``=VD+3[)B5QJZ`0ADP[,R!E/N._$[0$MNMFH220 +M+(3K[;),[(#X8VZL[YX(IM*?HO+1S0:Z3JTTA,4<8;I;J.6(S_YXH^GY\9&]*@P5'RS0HI&4 +M+[-U`^F?7]_\.$D`)3*;G&0%C4]5%,U.DBM+*0%4`Y+J!C&!PT\P8*55I.B/ +MY25DSTL$D-2X`C`CZ0Q8]**=L?O/[SC@"M3BQ6Z)AT`7*(9*IYZ6U5Z,[LL9 +MC<]/2P91Y2P]2,G!^^>(04FA[Z?B.]$.CP69#*9X&<0NZL.@+CP`'I@C)"AO7?B'Q^SY;FX)`JC-8J +M+NER@K;3X-?#%+;:CICBDZO.CE`%)&>RE6!R,$-[\5FA0<"029'R13LK1+-2 +MJLHR*=@3ARNX'K]^+A@`YQENBA:S0.TJZB +M_P#Z>AGI9XWG-52NQ19/-+CMT,?VE$2@#]I0/IQ(T\(6.#^]`.>YPD;D'V]- +M/4E5+:M562NO%MJCU4-PHY2E5:ZI2<21AB(Y8V_X=0=]QN(^G(_1!?+[4NH^7%#\JL9K[&Q+Q319(B8L,EEL'Z<9BJ`> +MZ6FZD]G[0?1<9N/DK17;XK-/U-127/3ED:TT%#IZQ6KY=2SF.HIK;3TTQR=R +M7DADF^@D`X=QF$#W33$`@?OZIW9FU64V9*QDE[O_`&)'H?12%?\`%_)!!<*4 +MTE76,D!IFB,>5/45[$[8ZB>`_P!'"74VFPDN;[U01JSXF]16S2.GKYI^.>I5 +MZBLM\$4CE"KHZ2C!`(_#)M]L>F.$MP:;PNW!2+GY9F/D0JD:X^)'F[J +M&E>FI*[]`PS(6G^5<>)^+MU$[=AZ9[]N#*6"8#=`XSI)7<8IG+\_`JI5PJ7J +M9ZB2KGDJJAVZI)'D+.[?XB>_$UAV$"2J;BZQWF^\H-N=Q$/5X`5G!P"1Y5/^ +MO!S`#JHBH;V0?53,4>69G;U);U.?;]W#[0(L@W$9KJ)@8&1)-\8WP<]MN&PW +M=O2,XS2%.+*B@R85G0=(R/7/?^7&4S!@K;F7LN`J>A>@RHRJ"$,G[)S[C^M^ +M-99*2X`#DIZDJU:/K>*2+/9D(8,/K]1PES"+!+IO`$K]9U<@=7KV_P#'$\UT +MV*@\H6+42>S>N?MPV\\DH!14C@@]N^.&8!-ULRL-P$7/2_#\&(6W:75C:KFG%I;X8M,21K5JNFM1W>KJ9%! +M,:O/#')!U@;Y9B1G'_*._8<2-;$%N$#@/@)GQT]?DK_T`HMJU:E`6+H\MY\! +M(6BGF3SEU%=[G6FG-9T9&9)'.6_O,1ZDD'?BD8?9P+L[]5Z2JXIM.GDX>BKG +MK'6FK772FEVJ&%!?-04WS9&%65J2&>HIH2Y[`SF.7I_:>",]T'$U3ZME"JT: +MF/G=<\VYC&G:.$JSV&%Y_P"K*,I\+PB;26GI)HJR:XA'EZRBQ]65C&?<_?UX +MCZ##!("5M3;QJ.`8;?-/*U43="_*6KQ$`"G!R0?N>'AB'#4:*LU:LN@.33I= +M*FI@>::(&;+'MC'8#'^O`&*(""+I54Y8O(609(!;.2,CL.,<)1#:+A=IF$+25"?-R0 +M("DY3\+-W`]?IPISDCJ(;KHL6J4Q8EC`(?"L"=QMMQ@A+IU'D92+J)N!E?YA +MU+I$&("_7`['Z<:A/4']J#JL!*EHQ$[.P&54-U8(W[G]W#3A">>V=%(6BJJC +M15#U$V91YIE^72:80+*'6,@$$L._ +M^7Y_7@;$T63FC5,MK%K2'!$%-5.6$Q)B14($;;"0[#'VR>W#):9[*%=`$C11 +MMPNZF)HUCA,@RW5)U.05SV&0/S.?;[IJTB1HULU'BGNB7" +M*6(5,40&(8'#^9,G!+9ZL$``!NYXA:^S&D2T0="GZ>(S@@Z#W/RL0_0_-#8OX>PDFL2PU +MJ"$B'PRBPD';ICQV_P"K;/%D93:XP4&T$,ANL(LHC2&NA^W`;62I:H_L@NLL;6-MI8N6-FI',6AC[_3] +M41]\[\-"!6F-1\C^Z$J,B1.GW5:;W+1.TE-/$&`'0DRD]:D;?A_:^VWWXD:+ +M)4;6)!U2PN8DB4A%`SG=AW^P'![6G>H[$$1;5`M7`K!Y906`/8'@@2G+ +M5.'HXWRJ2,,L&)'V/#5;5+I3E$K];!22I!&3]_X\30`G513@L"I;\72"<>_" +M73-UMO%1Q)P,`Y]03CAEW!;6+./*<%O;C'-A:F$+7'\AS3W)!M/)/?D-3Z#U3JF;E%S5M$]YY<:P6.SUWR\A2IHJC+&FJH'!P'CD +M.^0058@CB8PQ9!IU1V':_19A]H5\/5;7PSH<#NYV5(OC%_L^KW\.VK[A)45D +M5VT?)._R=93L6\:,@O$[D@8ZE.0!]?;B*VILCJ.V3+2NK[(Z:5<8S+/:]Z*@ +M5UY=VR_T-=8:N@5J*3#,#^(,#E75ANK`[AA@@YQQ7VOAW9*E\0>M9#[[UAC!'I_KPS4K0,IT6LL&4>54L:1N0D<2J25!.,^PX&8X%T!.N +MH]F)0G)UL\Q*]?4,`KZ`[#_7AUM*2MN!9&58];4@2.SRD%0,;`?P]>Q[\%8; +M7N2\/);"!:^J(J'_8<%R1`4CDM`N4+7&J"B>3K&%)"JSY.<[ +M%N%$D7W(G#-`@3KJHT2(%62='D8G(QG(/8`D^G"RX+8;)(!49("IS'*I\Q8! +M@#D?3;C1*W4BX73/4E8A$C`Q[L%.^6._;;UXPV"&ZR\E1Z>%-1U2QB8[Y(9B +M""?Z/#3A8]R>DTQF*QJDC*Y[X._Y=CPQ2.@X)3ZY+8:7#?,LQ498`=SO[=SMPH-`368 +M$6"6-YU2D=+*QE:*EQ^(=R`/8=V)('U)XRJ#E@[D-4XC>D?J#4#3PU!J/#B" +M/\Q"A'5TR``$=7J"N![%ESVQD8-!0[J@;?V4C8;]+/>J74C3>)-3PK3(KLV5 +M0NY9#[]2,"\%E=6:TV$B4+M)YIX9[P)(:;>"@]6F^BPMS"(E;!SME@<=^&WM(*R;J.;`Z_P`17[^O#6:Z40L:8%@0N"O" +MG.BRV1O0Q=8G:GD.W5PVX19+:J/\U4:.:;,7EZB,Y[?U_'BM;1%X*(I)`2DR +M$L<@Y/[\<1[$4^EFU6,F.K;.<9/;?M_KP0"6&=R1E@%'O+NM^0U]HBN,AC6* +M\4;,X[JOBKD\2!$@)@OR"1N(^:VU?&SRKJ]9_"[I&[SBF#P:?I"9)]BS(Q*, +M&_O%,#'UXF=KLG`$NW#Z2I'H:\,Q36"]S_[%>:.#1]SH9IXJX15;JQ4%5P!@ +M[D^_;WQQR88D;UW6O@VM[;;2IJ"U!4$:JDDC'``&/+]>"FNAMBH:I2>7$"T+ +M+-KGHRP4]*DGR^F!L#GTQ[<#YIF"GZ=(B'$*(KEJ`HZ.EE&-AZ'W/T]>'V-R +MW"4VYRJ-5NF"0,K.AW4J._Y?OX,I`0FJTRH:L45$8Z6"`'&6.!G_`,<$Y835 +M&IE-T%5<<4,L@`,:XP5/O]/IWWXT*EY"DJ.(FR@:QNE(@DQ`!+=);&^_KPNX1C'R3&JB9JDI*TB.@=UZP#N0O;/[^ +M-H2H+7*CDJ(5B<2NTH8D$]1V7.^W\OSX0!NU3=5\.L-%\H.B2:6E<@2@$(6( +M'2G<`$G?OQJVD62,15)&8:?=0L;XA+P[QENLRLI:ZU&2GJ&BBG8MGIF#%?V1G?(!W(R!D; +M^O&Z=1I`+=Z(K/[0!%TL:ZWW_4=_M6D+$E777">2FIQ'#)XM36:2OKJ2CNEPK)*B:HHJ1I*:&0,Y8^$2K2QC(RC(2,G@+:3#^K?+B0V +MT^2DMF$5,$T%H8'-T&Z=Z@::*KHW@>6I24HA8L5[L#^(=\>_WQP(3N3]1ICM +M(.UE#34&F[M=(P/E*VHB5E1P3!.HE#OU$L"?MMG?Z<3-)D"2JY6D%*BLN,U3*T;*R(#OG81CUR?< +M_P`/OP_H@*QOHH*OJ/%E@H5\JMAY0!V7T'^?"F,U)3-0%KLH7'H+*\JY(ZML +M#A(LG:D$66.L77*RA0H&2/IMC_/A0)28),1"Y0J0_P"I"O(!V.P^O^G&&4E@ +M`TU4S34QA*3P"543=E;!('^>.&'.&A3M)IRR-2B&.""H1)':%CTC#JV.H?E^ +M?"F.,D%$CM:A?K`+C`SW^O%E),JIF#HL64M@;9WX0]+!&Y4#`#IN33XFRGK- +M'5-=[1'01R2U[U<"4\8.2\IE4(!]2Q'YG@T,+CE&I0=4AK'.)@0?E*WI_P!H +M1JF72O+FTZ$MICDBIJ2*G>(D!).B-1C!W.XR,=R"/?A?2K&=7A,K=3[^2N?X +M?[.%2OF?[XKSPUU`]35/U*H4EB"K'.._^I]N.--K]HKN6(P]@1HN,=CBZ%D/ +M006P,#90-M_X;<&,Q+K3HH.M1,D!85TME/%`[LJ@J?3U^W!]-UP"AFAV4[X0 +M/<85DIS&`PZM\``#OWXD:?:,IGJP""4%U(%.$!8J,`C?'\>).D`&@%(J@&2A +M"OJ$1BR.[H,G<]O<\*#]R:%,1)0Y7]#JC^:5R0Y&/ZR._"`PNU3M*J6DH,N= +M0'$T<@A+8'1^[W_G[\;<^+)Z@Z!F"`+K(&AECZ5Q@^&PS@9_SVX61V1*E&8H +M@R-R#Y[A/TH53H=&Z&!&21W[^O"@V;)=2H!+77E0\M;.CJ[>%TL.EP!L.Y[^ +MW?\`=PEMQ9"/>P0T%8;W:&`]3S^*!A@!MT['_/'#3LNIN@:F(=$J,CU?$KN9 +M"(ED!QC?`WS]]P/X\:%^T4RZIVH"%ZK5X*M#'(Q!V#C)],8'US]^-%KMR9=6 +M:VWL(6K=6/)3QHVZ].`VX[^IQZ[]^'&,.6'733WC/=`M5J9+;;ZNNIEBB\<*[1IX*$J2ZKWZ<^H&=O].&@P!UMZ +M?J-,$A*SEQK"]I7\W+Y8JNP+JJ@N]?9;'5.DR+12O1F'YL2*Q+5-.)&DB!'A +MEX`"!GJ$C@^E+<'C6X$M[75]8#S)((Y18@]_)=2Z-?@+@>D'0O:/22KBNIQ% +M"L&M!_Y9:QK7.;`!=G=)RNT!`F`201SS6W3MDLU@L<&(::AA@IH^L,(H40!5 +M;&XV">GIP)FS&ZY&ZF&MEEMP0A=)KI6JZRW&&CB`(Z8BN2"=R,GZ<;;9#8EQ +M%I2EU+=K-06X45;44UVH'DZZFGEJ3BI'H,INK>H8;@CU&07Z39>H[$D99WJL +MMTCHO$^8MCK+3!@/%(P8LG8,!V;V]_3Z33;!0M5TH-N]52TL6(T9U5ML@YF< +M]@3_`!/T^_&VB3"%K.RMM=0$%,\:RRSL6GD.9&]V]OR!`_,\+*E*P$[^(=@IMO?MQH$[UN$*:@J.FGD`;.VP_ +M[\-53P2VQ*H_S,DZY)02RMOD$]M^*UCQ)E'4-+!5_F&2Y89)V[8_C[<`TQP3 +MTD7WKH0-D,03@9QP91I]J24UG('-69^$+3::M^)[D9:I8%FI?]HJ>NF1DZAT +M4RM4X;TQF`<2N$$U`-_[*-Q\&D0="6CU$^BM)_:&ZJ6[:KJ[<:EC.9"\I1LE +M5*KA28@'5`-UO"B>1?#`4#.?0$_ +M7V_[\(='!/4ZY`01=+A*TJ;)R/(G4%_>HXS#T\]04QO('FG:U8L;F! +MB+JL?PZ5575YC2/D2O6_X?N?0_!ZKB6M)S5'.,D$CW/3G\^)A@R,O[*\EU#N0W7T=L@IIPD46<9RJC?Z?Z^W# +MM$DZJ,Q;0`-T)`:ZKXIV<23`!%Z2W0,_09]>^V>P^G!]"SH"C,2X04@*ZI$< +MSO$5BC*-E1V96[DN:O%SFDN,0)I(3T)$V3T$G`; +MZ@XV/?;'#S3`0#CG=(T7*DIQ5281"R#LQ(!P-R3]SC]_#=1T!(;3FZ*8Z(RQ +MO(&"PKA"Q.%&?Q$?E_/AH.T;O1;I(77)0?.*(8XS%'*X;K(P8HQ@+]]\G'^O +M"&5(OP6`"!*.*2QT[4530TL,B4XI'J9&5G"'-BR4.*PW9ND@EOW^G"25L%!=^8-$XQT@C?;TX +M:JPEM-Y5-N9H`,N`-B=_IWXKN.M=&LD&%7I^EF9>IC@8`^GU_CQ'L"4"02N- +M)32UE0M/"I:4[YQLOU_EP2UV5*@CX-5>_P"#^>R:'Y_-]D@YF7]'#)-&(Z +M>1(U4'.,@^G?M_G +MPEP@7331P0K<]0`PEBRA2V_"@MOM\*7%PU$`?$>I*,/,!U$D_S[[\: +MGJR>GT!VX6!O30):9W)57C7(Q,SL0HP`2,X/N +M.%%D%,&O9*N\Z]26(8G0QI'U[LHSV)`)V^S']QX;RA.TQ>)3MM5KC9.LXBZ003@[ +MD'8??Z<(>;(E@@'+$NTLG\[9S.U5>?BE +MKFLG*#4M,K"F>NJZ>@7!WZ6<.VW_`+8F_+B5V(T?J`[@"??FHS;50-PKK\![ +MY)1_"W6!M":8J0T:1PWQ[9-UC=1)*9`1]?,HW]^.0])WN;TJZL?_`",#AW@1 +M_E>X?PHQC3^#-:JYN9M*L^D\?VOJ-?(YC-(YB-ZM/5M#)+4RKB!94['B.H:&.@M;2SQF,$83/HH!RQ'\?SXC*E8N?` +MU4CU!8P.A$4E'##;:"FJHBTTQ6:9%;\'4?)&00TL,?0OH#G8[;YP"=_\'"7B&AHU*QC/Y^":^@ZVC_17,ZZ +M2DI&=,2TE$BDCQ3-64L:H<#`7I\4D?W4V[[H>T-(G7V5E._:`]W2NJ,3&MI9 +M9WFJ6825,N-P"=E'IMEF^Y'MP:7P0`M&F<,?;?V_APAQG1;!``"Z9 +M,E>^!Z\(RE8%B$84GL/3A9`B%MX0+?Y0$WZ<`$9]^!J@O9;;94]YEY(FZ7)( +M)/?]_P#7UXK^T!92#(M&]5\/?I7!;;U[_P!9XC&,G5+(@RBV@$=CM_S+`&KD +M_"#W)QP]E:YUUA,7&J/^3UMU-J3FEI:>VM.DM#5Q5\U2!Y:,(>I6)]^H#`]> +M$X_:5+!TC7J&(TGBH_%&(8;YK?/EP&%N +MN4>?%CE`/E.X9<[%&!].-LVMAML8)NT<'<7#A-PX:@_,<095XZ$;::)I$W!\ +MUHOO&H7HNJ/Q>C$@SN-^VX/VXAQ3CLKJ3*X@2Z\PD1@D53U@C.QVVV +MV'"M4&ZJ,L0A.KUXU5(F:A6;V4X`;.W?;C37$A-/J7A1-1K0L@=Y8DZCDKU; +MD_UC]W"HX)H/=(S%!5UURJ]<4=0>E<$^;^`]N$L&Y;SFY]?1H))/F$W! +MZ2.X&^N9;?K(ZR#"X0T-PJF;JR3D?UGC66R6TN)DBRE::QRLW5)U +MKOC.0#WX;W+1`U"(Z2S8<,T3L@`)/N?;^/\`#C;;&ZW%@40TEO6-NGPU52>H +MX7('MQHANB2&FY*S98(XEZ54/D=(48./].,.MEMK)$A0E?;5:01QHS-X98@^ +MNW\\YQ].&BZ`GF-!$1=96F66CKA32NL,-0IDI7;R@N-V0GT."Q^WVX27VE/@ +M``\$];.$=ECDB5(R`3@__L`#Z]OW\;+1*>I2!;24:PH&@D176,%,@@#,>/OV +M].&GQ,G*10"@;([!3N%S[D;D^Q_=UK"TIZR1+% +M*KC#+&.D;9ZB?YG&/Y^O`M=W9*+I,`,!&44T%QNQ\?\`645,&!3OX[*K.P&? +M0E1^0^HXCP(IDQ<_=%AV:H&DV"Z6J*BIN(:>=Q5!C,[!OQ2OY>OZ8'8?X>%P +M&MLL+2YUU)A(Z:A:*G1'FDD,*(3CJ;MN?10,Y)]SQE(RZ3HG7@-$%."PTY2T +MS62B\2=ZJ6GHNPQ4],;MDC;_`)@BQ[`$^G`M:H9GV/=T[AF`B(0H;52_IF_U +MW4):))"H"X"S,TBDL#VW.$'L,?7AXO@91K[A:%AGX*$O%;/<+@\5`:B1(D!D +M>$A0\C$LQZCW'H,=@/KQ(TF0T!"&H,Q)7ZA$W6&.Y`[@\6A[;JF'58IGZ6]` +M??AL.`,++:!9/C*X.#U;>HSPO.L)NL"IF(CD/42<=O7A"V!>=R7%]DD=RCOG@>O +MB:="B:KC`"14JADNW?--K5NLZ'E?20\MM`SQ/J*7IEO%S0`=`VR,^_H!G8<> +M,/Q1_$U^.Q/48L6`WWG_\1P509.?5XT?K>Z:8HK5;=5Z) +MO(6GU+:*M_U%PB(P)0P_XE5K_X'M<\SM-U?,GX[:QTGAG>V7$+37 +M"F(SU*I)$=0HQ^)2OIY>/86`QN'QV#;CZ$L8=SK$>._O75]@],&UF!M5I!WF +M++6)S-Y/?$=R[J9$U;R7YHV-47J#SV2H"%>^>L*5/;N#CADEPUWJ\T]K47CL +MN"J;J#6>IH6DI)[=<*68;,K1LLB[>H."._#D%L!U@F35#Y(07!J.Z.8^HU$1 +MWSOTC[9]N%TWP=$!B':DW"RZC5TT(1G=0JC.2.Q[<*94!$I`?`@[T,5NK9G\ +M1NB14S@,QV._\/MPL#>%JO5+6@:H,KM25$H."4!&!OG^AP\W1!.Q#CHA"HFJ +MZYP6E(7UQ@Y_K/#]-DF90)J.&Y=U-::<.#)ALYS]>'"T`ILDN;`"+*"V4&54 +MQ)U@$;C`[Y[<*&GEI*-8+1*DOT80%RD9., +M`MPR`B)&Y9AID0@AW)Z>W8`?T>-$A9:(']7E78`=MSZ<+%X("0TP9A +M?5IXU)=Y8R^,D8&3PG@EB9D"RX)`CM(`K(-BKXW!]#PVX72Z;2XDKJ:W>-U* +MC+!.9/&#+CRR#LP]O7/Y^YRR?[4[1,@D\$P+)7RO%&A$/CQJ.H*/*Q'IC&VW +MI^X\;:ZYE.M:18Z!,N@JHY(DR5:)?,05'23CMOOZCC'-)D)MLEI=N5!/CGJH +M2_+NWPO%L*BIP#OAF(.WW4<36R3!<>/[*M=*G#*P3Q_90GP[QU-UY'Z]LE*W +M56+63U%(,].)`@)7/LR]0_(>W'G[\4WLH=)L+B'_``D-#NXGZ?*5],ORCX2M +MM'\*MK[.HF:C7U7,OO#&NC_JN+(NY7Z]M.I.5%EO22Q5%_@@6VFE#>:FEC4! +MIY1[$%?#'JQ+':/#]QQ.%ZM^3=]%\W:./.(FJ=223XI7:LN*DS3,7E6(Y=S@ +MAG[;$]\'J`/T/!6'9O"'K.B0576[U#S/XDGFDW6P"*-_7+=^^V>!:HD0.2=H-;J5F4L0681=3 +M2,TGS#M@`A00`O\`7TX'=(N$^P7`.BSS3FL>CCIXW<,"&(;`ZBV"`VWT'_[' +MC&ORZK99G.5-9+A26JOHK:!T,LI=G5L^&V`H5?JP7)]A@>O#0)+I-T4]S6B- +M$N[Q=YJRMDB@<14XZ8V'8#I`Z]OH0I^_!S*`9VCJ5'U:A<8;I==$5RJ8P1;* +M>:HD[RMX?63N<9)[>HQ[`<+-2!>R;HMI[<7&%3"25$5-.0Q +M.Q]3Z#@=[#JE!P7!495P<8)[>W"AHL)WJ.JB>EDW8'C"9U63>5"R4M/'"]97 +M'*8\H/;[\#56REA5;YI:BK)/F(Z/]1"#@8&_]?3B%QDD&2B0+R=$J[/25U+1 +M"WT5/+7:DK6\**-_$P_P`(S^9_AY7_`!:_$JIB'.V;L\]D:D'2\1WGAN57VEM`M(9_ +M-\A/S*I=?-2&BH[E,\\E3=ZDL\\Q_$['N22?Y<>>:>!+WM:?A"AP`T6%]ZA_ +MARY.7OGMS%CIXJ$U&DH:CHNE<25$K#M$A_:^OVX]"?A]^'SMH5A6JC^"W7GR +M'UY*Q;,!=\6@U7HR;2ULTEI&U:0M%L2AIY/`I(5C7I#*,%@!]@1^?'HOI148 +M,.W!4[!Q#;<-ZN>R,*"7.W-'J=2JS?&CS4:TTO\`LE0RU-)4PT@EJ2NPBC(P +M,_?';CF73W;!-;],R1EN>0/L!=*Z(8$NFL_?^_V6F#XO^8O*#_TJTW8:GE[H +MK5FKJ2D+SU=101M5&IE_#&9@.K&2#C.V!P1@MLUJ-!E,/@-':)OKWJX[(Z+U +MMH8[J6,S%QW<2?G]B5YDN>7-&P:4U=3Z>L>GJ&XSPJ3(9H#O=&I[DC\8-F8?HWBF[/I7K@2\3($Z`9=JN+HE# +M:[_)7551'26FWQ!9ZNZS-MT)&,8W.Q/%FQ>`HX:D_$U:@;3:))=H!Q[EQVGT +MHO+F&381J2=(5E.;7P]ZQY1V[1TVL[_IJCU!=Z45;V>.1GJ[4F,_[S@=(SG` +MP3D\!)$&B"$L,$]P>$%Q!E/@SO1_::MIE5G`EE.#C!&?\AV'"C4DW6W#*(; +MJB\12SHSB(.<$=.-LX[#'#;G#0!.L=,%,)$D#58 +MT%?S6ED=!'"SY4D!O;[_`%^O"7Q$I1IF)7!K'4,_7)'&A]`H[>^>$@#)-U$?XRZX]_ +MMQV?`.-7`4JKKG*#/&VOU7A3IE2IX;I#C,/1$-ZQUN$G3P*-=85T*4D]/$&4 +M.^$&VW?@V%$P"++" +MM43U=4E14#RKU.?4@9VS]3_EPEPM`6J;"72"I^J83R4M#&L;*<,P'JS?L[_3 +M&3[$\,Y!KO3Q,B`I%"#-)3#J-(OAH[;X8+YC^>?3Z#A+VP"!JE6F"I"&>2*6 +M6=05E;\/KDJ-L?;8?<@\-##R(*<>^#*DJ.15BAIS(5D1%,?2 +M/PP?*-S]3P._FG`JV:DHHI:F6LJ?)2P9&O5?-^`4#M? +M:[J32Y@[1^'NFYCD-.:UGWW7MPU)>KOJ&^W(5-RJI3+*S$D*=O*,=@.PWX\P +M/P)C--SJ>)YJEM>YQ))U49IRV:AYL:HMG+_1D7555$JI75BXZ:*`_B?[XR<9 +M]N.@="N@U;:F,;3:(;_,>`XJ9P6%-0SO7HG^%_D7:.7VFK%9;-30Q6^EA'Z] +M@.J;'=V/N?\`//'M+"X*E@\.W#X<0U@`\E=\+0+0UC;_`%C>K07*G@>_07BX +M/'#:+11R3IGLTIR,_8#]^>*CBJA?BAB'_#3!([S]@K1AF%M,4F;UY]_C2YD: +MBUJ^H[G:Y'B-TKA!2(JYE>*)L`GV!/;VWXX1M/:?7UG8VL>\W`X +M+OO0OHY7KOI8'",+ZKS``XFWAQX#4K0SS_UCJ6;](VBS]58:'J>ZW4L&AH)" +M-T+'9IB,X'[([\=&Z$]!,1MRF,9C0:>&FZ:].MG?AJ';-V:]N)V +MPX=MWQ4\/.[^ZH=PW6)CX3IDU!;[KS5Y@T.C>6^G;UJZ]UU8M/3TE'$9)[G4 +M,VRJ/4DY.3L`"3L,\=OVECL#LK!NKOBEAZ39+C9K6CWWGO7A#:6U,1M#$/Q> +M,J%]1YDDW+G$^I)W?1;?;!\+FE_[,_0M!S)YM4UEYC_&MJ"G'Z)L[-XU%HJG +M<;GJ]7`(S)W8^5=N/$6,Z4;3_$[:#\)@,X]`!D9X]4='-@879V'9@L&P,ILL`/GS)WDJ0K=EI=),WGC/R^@5&'JY[K5 +M55=3QB.CCZFP?PXSW)/OVS[`\7.DT,%RHAQWS$U9,YJ*UP< +M-C\/U`X?NAZQ`N4NUDF)+,S/&Q`)W!QP3:(4?!F9LB736O\`4^E:@RVNZ324 +MN233SY=7]AOQCZ+*@[0NM4\14I78Z`5L%Y&_P!.P'""[>4;3((`GFIBET]"57IA6=!@ +M*<[8]V?H.,:X'1)=O(UW*#FMCRH!(AB7'4IQ@M_VP/Y<.;TP^"Z` +M9[U0KXD[;!/KV*)CU5GZ'I^C.?\`A]=1U?\`R*<%4:KFD1\-_.1])5?VO3+G +M`#2#\T`_#%XU3?JVW1R(AGAJH@3Z,8T8'V(RI_CQS#\:R&X2E6(^%P\E[6_( +M/4?4VQC<&/YZ4>(-DGZB1[;S>DG5&2?Y]F8>TA!#?QS^[CI/1IY?LREO&4>6 +M[T7EK\74,/Q=]USZ'M]]OKPY*:.ED14%&:&A6.4JLLK"64D[`D +M;+_TJ,G[\:+=ZTPPV#JLJT+$9*BOF55B*B@BI8Z"]6+Q"H:2$RJ#`&4.H.3C)#YV)P<@X.W&4ZK1\34S594<9IW +M7ZF$Z\0HJ:8A6!)/OOPRYR3 +M*CV8M^$$8^G&)S1#-WC,A?L&.PW_`*^_`Q,"%N4*5UIL&G+!5:]UQ-34&D+> +MS3J)<8K)E.0"#W4'T]3QRS\2>EU+9F$)_G=8#GN'B@]HXQM-D/-IOS/#ZE:0 +M_B/^)Z[5E53.M-:HSX5%"'\M.GOCMU'U_P"W'DP8"IB*CL7BC-1VOV"I +M->N7N-6I$N].7O5*.P6_5^KJ^@L>GJ"HN-XK&$4=.ON3@NQ/9!G)./;B4P&Q +MGXJJVAAVRX[EK#ASG#())]^^"W;_``F\A+7RM@H].)F\:HJ$$UUKNQ.3EE7U +M`]`/;CUWT6Z-T=E844&07GXCQ/V"ON"P(HM#`;G4_0+=+I>R46FK+!-6*T0> +M/J5,[X]."L<\.[!L%/X9H#_%>8KXZ^>MLY;V +MRFTWI>NJ[AKRYN+3220CJ^3!_P"+*#Z8&?N=_3BD_AMT79TAVH<4^3A:/9'! +MQ%_$\=P',E>Y>E6W:/X6]%33I0=MXX1(N:3#,N_M`_EWO=?06U#<]>9&B*G0 +MMFL>I+L^A.3=OBDC-)1RJUWU)5(`7FF8_AC9^K#'<_3CV-C=K8.D&4"88+!K +M=3IPT'O;\25:KX&*_07PC\IHOBHN/*NV5O +M/CF#3M1\E="2L&JZ6T$E/TY=9&_X"3N,KGS-&HP/,<>2OQ4HXKIQM3_[V"B@X\V>.P= +M&^C&#V5@Z>`V>P-I4]!Q.\GB2;D[U9\/0:RE-27$FY_J(U\-P,:"PNM>?Q&< +ME-;\V-:Z@H+6*V+1-EG5;[=%'4*RXR',Z4I'_$Z%Z(EZ=@%/8`GB8IO%('-J +MB:M,UGEC=+`GGOCN%@M?O.R.QZ(HZ?2UFI::.H@8M\HAZ_"V`7QI.SR`;X&R +MG;@B@2XYG)%6FQH+1[X2=Y5&;I,5G>6=FJ:R4$G?/3OCB2:TE0E5X!F;J%*R +M];R29#*Q`V]O3AQ]@`$VVF7$E=4ZIXBL1Y-V4`]SPY3>18H`"*M@ +M)V27I]!Z@]Q_VXK6*H=4\CI([U&52>&":A +M^MMCN1E?X>NW"SI=:8-T0H6IJQ&\W0H2-CGI+?AQZ%CZ_0<:'"5CRRTFZ$Z^ +MNA>>2./,C%?[N-SZ#;AIU[`IE@`B#JHT4<%('GKYAX2KU"-23N2#D_EMPL1H +MDO<2`XBZ&:^XK52L\8)0C"+MLN3_`#VXFSZ)/Q,/S_`'2XYNVR:P\[-84,F!/% +M=%=64'#*R=0./J,''%Q_#C&C$;!PU5NA;\C"XI^:;8SMG_B%M/#.M%2?!S6F +M?%"$DN7DJI!F)"OIYNWOL.%BXY)@]F.*RVKHHAX<.%B5,$9[D[DG^'[ +MN&YA/0T:;UB25D7*"-"W2!^TV/0?F?W#WXT=4YG%UASWA8PTKN0V,`!P, +MX],_S/[N%"=R0ZN`HZ*Z5-760_+LSLS#'2APHS_+?MZ\)>1$E,-)T;HI*UV& +MHKI5,M)4R!`<$H<)@YR<[#!P3]^-EW-:-$:@IKVVDIZ)Z.>..*EE598G2+,C +M^*%8YZFP`?;'8;XWX;J7%]$ED:"Y0]075Y:=##15P0#I#11=2-]NV."'TB#: +MZ#IUA&]?JE,X"]P#]/7BQ$J*S7RC50=6^6(``'OGAMQ2R"=5#5"!B,;C^7#9 +M=:$X!:ZZ`.E3GJ]L<(60-Z_J.V4M=4U%3JU@,F+2M(7QV?%M_M[7S:2T=43V[0U%)X%+#&<)5RJ<=> +M_=?;W[\>*]K[8K;6QIQE:/512U$KL`T2DL7<]@OUX&JU2XY&"ZBZU09^I6Y/X0/AQK](2/S/U3&AO, +M\'A4%.%S\O$=]P?VO3CT/^''0UV!I_J\0/XKAY!=`V'LDX9@J5;N^ZW:_#5R +M5_1\-7K#4$!BEGS+B3V[Y/'4'$M!\*US-QKIEE:BIE*I&/VR +M.P']>O%2Q>*+:;ZCMV[GN4[08'O$:"RU6_&KS7ETU8*V@BG@%;X95FZ\2^;` +M$<'J6)(&1QSW:^Q&_P"DU=L[2$4:?&V8ZY0=\Q?D%[+_`"Y?AUB=H[2&*:A?]35%+635E91&40I$A)>K;..D8!PNX:<29Y+;=\!7)G4VL]< +M\E[;S)N]SKM;7*AIZZ6BJ)#-'I'3LA!7:LN14M)+-MB-=AT +MH/PA@S=@#",Q'6P]^X6X[KGW;>IJC2R-RL-M.'O3V%YI>:FI:W4%VN#PHOB2 +MNS22`$Y;/92>X^OJ1B20GUW_`'<(D)<1H%@24S,A!P)!V`[*/;A; +M7F4P:<&#J5(I2B*CIGD3"R$'';(SN3[\),E;=3`;)WH_Y1\S[QRKU9%>*)G- +M$\@2JB0[2)GN![CC,3AA5;E*AXKE6B0YW.!^[^M^-"1>4\^O +M(,H5J]3022+B6:=P20JC89_AG;A5R$AH+K;T.5-==[C*YI8S2Q[9H*5*JML6@H;Q2$_B6HAO$##)/;JBDJ4QW/6..>=,=J.P^U-E4F +MFU:NYA']IHOGU#3X(O8^Q:FT*CL)0$U'!Q:.;6EWT5*?AEMD]3SGBMM#!-55 +M33%(80/,_4=ACL._EMEADBG2MM=%4K-&?)/(A>!^AOVE7PP`WKW['C7X"8] +MM;8!I`WIU'M/C#A\UG_U#=BU<+^)+\4]F5M>C2>!OMF89_N[-QNTFRKS/3^) +M*B-U"EA3Q'(!_6-WQ[`G.?Z''8LR\5Y"5A5-:STYA"I&">HX/?'_`)S^7"CJ +MFS8$*+:I$91E=900.WOOG?\`KOPHG<4@-DS*[(:^0@MW!;"\QC2CHD&&90_"";PD5GR>Y=_Z-J+Q6PVNSTP50_2 +MS!=V/8$G?'<#'&IR@N(JOB7.%O+WPU[@;(NF\2)T'O]E,WO35OL514QBCBJY945YS$%95 +MDWZ7&Y0D@J#_`/D)SY>)'"T7907&-8'+W,=R$Q&(;G[(4=9M,S2BHDN=JO?Z +M$J&2KDBI:!_FVBB`,LJ]6`JK$O47;;*G&1DA\86M4&6B)(FY-A?YSPTW\VOU +M#:9&8Q/F5823E1K3E?K#6NBD\.MGHZB(2,*0MA73Q(P593TMX;QD@9&3L6&# +MPANS\/BIQCA%BLYK(B@EJ7C@A5I)F(55 +MQOGTXTX@`N-@$DN`WZ+7/_:'_$Q!H;3U-R%T9=42[5P\2\SH>AX(_5=CG+8( +M&?3/OQY+_$_I<=JXHX'#G^#3^+FX:#PW^"I&W<4:[SAQ\(N3Q.X=W'R6@_4- +MV>]WJEBC67P$P`A!R3[C]_%)H84L88$E*H4P*<-$K;_\$7PZ05JTG,#5U&\K +MQ@?HZG=3A<]V(]^V_'7OP]Z&ACOU^)$G^4?4^"L6Q-ATV$XFIKJ%O6BS1O]Z\U>*^UT=!24 +M5BM:*B-A3T[=*C_QQ![4Q9)%-JFL#AI&8V"`>9.HJ#1VBKE62!HXXX6/D&6> +M0]ACUR>_%0VSMC"X=N;$DBF-2!)XZ>"M>P<`VK6:UVDA>PL%3%#!LS`-!DNO=Q.X +MQ81I>\KZX_@7@>KV93IL8&,&X:\B3QB_BM1GQ?:GN%OTI=[9;TJ4NM93AI7C +M(_W>`GL?7)W.WIWQD<"_E9_#(;2QO^HXD31H$&#_`#/U`\!<^'-1?YA?Q1.R +M=G.P>$<17K"&D;AHX]YN!Y\%H@Y<6>^\W>?-AY;Z'L$ERU#=[K'1&XQMU2VR +MTQ>>MJ(V8EUJD6MH$(@MEGBBT;_\ +M?5&;-P1+@\VY;IO[[S/!>/OXY.9$=#<:?1--4G`V4=6">%[);G.8BP]V^J,VI6#!E:.?L;SK=:H+K;#"9*N[L*$L +M2R+,^6)]Y#[^N!G<\3[<4#9HE5XTB/BL@ZMJJ%Q4M1PRU3](B5B"J,Q]AW)P +M#PMKSJZR'+A)#!)"AQ054B.)(UA+$X4#'3QLUVZ)5*@\B767R*S>5C-&8XQD +M,3Z\;%83&](=2)[E]KX_"2F7IZHA"`N1L.^W#C3JFZD#LG10\U*\8J#X<8;' +M6@Q^9_APXUYF2AZ](B2$\^17-NXZ0N,=HFJQ^BY#Y%;LN3OPSC,.'"0B]DX] +MU-V7=\ELSTUK2GU!#2,:T,H4*0CX)W[;\0E1L6-E:65LZ9<5;0X180J1$#I/ +M5G._[0[<-AED_G.JR*F])'Y8RJH!^)L$;_7WW_EPZ9`@+#`DE"]=5T]4`K*' +ME7S-U/YS]<#MPIK(-PF&N.]"LS1-)%&SU4P!R%5V\OT_?[\;`),E*)#3E"CJ +M^JI((I)8FCCE[=9&3]@3V`]^,_F6FN,04^>1E.FH>2GQC.U#(SP:+I@LR@80 +MO=*4!2?3(20_EQQ3\2@!TGZ/M+OBQ#Q&^.HJ:>)"ZO\`@#V^F>SSN-3+YMF596I*:9BH+^6$.\:GT!*G/J<`9QD%'XW8R-BLI@Z@GY +M`'PE>F_R%]&'4^F6+>\7I$4YYYC'R^J:WQVZ(":3Y1\PJ:.1UH+]6V"HDQG$ +M<@2>'J]\],@_\\4'\L'2(C:&-V6\QGITZH'-I+'?,%=7_P#JC=$B_P#TW;M, +M7:33<>3VAS?_`"8?.%K?N4QEJVHU9Y$7",>K9B=SL-L;#/V`X]B,!U*^2U8C +M*&M0W*[]$WA(KJYZ5)&R@8/^0_CPZAG`$*.E8+X<:=3#.`,;G]W&@4V7@"Z8 +MNF='5ER,,M3"\5,AR%((ZSD9R<=M\?\`GANH\`$H>H^=$?M1_,BGM=O6,3.0 +MG2QVC7&^%]N_IG\N&`X`DG1,FYAN]-G1FF:>P3Q44<(J)I1URNH&2P&.C!/X +MNL`'.R!PQR#PXS!NK-#WF!]/#E?G'))?BVTSE;J?FFH;K'-&ULC^9NU4\GB1 +MPP)([%6/2L94D/TG!'FW"-(OXH]RPQN':':-XZ>/#CIOCB@"752`1+MWC[\D +M"&[2W6LMEKML45YOG/F?162Y&&G]0WV]Z0M]70ZR^0\" +MX37*IBCJZ>"K+P_,+'4D2$*_67DC4^'THV.D+B;QN'V0_!,?BP#1!,0"18&? +MAY'W*KC<1C'57=3(?>=QU&]W.(CYJ[=^TQ)S/YI\R*N7FMS,MMOL+4.DH:RV +M4-?.MT>B@$;2B3JA/A])BZ?$_6DEW9(A(JFH8S:S!FZAE=9#D@$?4\-@PM$;BA;G!S6L'(3E3J/F9J&54G2%H[ +M=#U^:28C`P/J=N.5_BKTP=L_"=10,U:EARG?X*"VMM#JVDMNXV`Y_9>4+6_, +M74?-O7M^U5>:J2HK*V9IYW)V0?W5/;`[?EQYEH8046ACKG6>)WE5XX7JVY=2 +M9-_OWJ_7P=_![>.:-?0\RM3VRI@TW$?_`*;3RQD-4GT=@1@CV],;\=;Z`=#3 +M7C%5Q#9D#B>/D7D=R+I=-4E++/3Q-/&JE857:+Z` +M>_\`+CT#A,*RFW312F*Q)C--XL%?.DM=):*&GIG4AB`[*!LOWXCL=7`!)1&% +MI%Q`)YK`J33TGSMYJVP54%<[9]`H]MR.*5C*V2:C]5;:%*8'!4=^*O7=5;;" +MEEI:NGJ+S4RK#%`#L'88&?H,Y/VX\F?F%Z=[XN>:5SO\6I-7_, +MPJELIY8EI8CM%75#E8HR?VBD723CWX^RWX4]#J.QMG4>^3Y6 +M7S4_%?II4VIC:N)?HV0T<`;-'_;"1WP-6#4W,34>I[1IR.T+\_DO-F'PF;$# +MB1SOK)YD"8&G`3<^W7X2K9:.3OP[SQ6>%2E/%T +MD8ZQ"/FG?]N6I3O@#B"=C12HFHWXG>@G]IYDRBJE-U;$0T=D&!W:C[GO%[+3 +MS\<_-VZT%1=Q:ZJ,:AN*K1Q54C9>T439RJL=S,_F[>9L$[`\5*IC"]Q$P=3W +M;E<,)A0T26V&@]]UEY8.;FO+:NH[E'8!#=+JTA6>MJ,.`W;IC';;?;\(W[G? +MB];-HES`#9JK6U<0WK)9KQ5?Z"Q7/4%2U74))43=7FD<&0D^P/8<2E7$LIB& +MJ%9AW/T1#4VNFM2)2]+(ZDO(0F3&!,5AI,J3V=CW$>YI$ +MA3IKM(&Y%]/?:6KCBEJ!&9`W7&G5GPSCLH'KG&2>&:=S"=<\B5RFK(*DA'CC +MC`\Y;L5;VR-_3A]Q=H4ECR38*(K:ZHCDG;SU8`V`8(0#V^G;C!)65"@N:20] +M;UJ53+V6/IV^Q(X348!$)FFYQU6T3^S\T53\P?AQ_M$J8T[BI31$<,"-'CPW +M2CKZU=CN#U4<9'WWX\C_`(_[<=@^FO1,38XAQ/<74J9\Q4*N_P"%6U!A>EVR +MWMM_&8#_`-3FL_\`R6K?D;I6ET_9_PM\T +M+53PM454#O>Z#R[BIH90[*/;,9E7\^//WX;=)F['Z;8&L\PUT4W?[:P+0?!T +M%=0_.AT7;TAZ(8ZA0$O%,5&#?GI$NCQ@CQ*T+77G+BIO)6[ +M7.FEAIDC,P4(<%`2,DX('V]>&WUH[(09;F!S%-&\+3T:?HZTK%)MTB-^A6V` +M!8?@/ID@DG\\\`M.8Y?--.;$9UV6ZG:PQ"F$[+,:$-(_4&QX462<$G';) +MZP@.%;/!E.DU\/<.8!^9Y?2=X0[ZA82![[D=PVZ^4%*M/76B]:3M[0'$M5`E +M..D``2&:5PD<94NJQA7DZ04\Q5>DEFT*;G?P2*AG<2?(#6($DD#?($@MNI%I +M.8$=\#U/'<+SN1C;-+Q675=BM&OM)\T-(Z&F8- +M,Q@2$LY+%V56*I*X/!.#75:194K;FD@-!%X)$W&IC2T";F*QF(=+6.EM.]XW +M;]_'QW+:[\)/P]P",T$'>UA,&`"]Q[(TS)>"PC,5 +M_#8\=42.1$C7F=>0`N9L;]V/DWR\J.8_+35^I++KBIU=I*T4=)I6.[U$;4T[ +MK+*%GG"&;HC!F969AY2(U2/J*,>/OZ<8RM@<11PV('4UB[XV.D`G*:=-MA!: +M#/Q1<.-H5AJ;%HMK4W%DO:/Y2(-IS..ZXD&Q.Y4M^&7X>=<_$G:M?5'-#6UW +MY7PV*_UE)&E'04T\UQN<\\M17RU+R`!I%>6",$!<*BKC"*3W';'2O9>#-)F' +M8U[#39E)C+DCL!H(.Z[N,B52=G[/Q500X@P;R#>8/@/%>O6;(4[?N/; +MB84J6F"-R'*]NHD8`'U/#;XUWIUI&BYTM+0VZU7#5>H:F"V:7H4:6HGD8*'P +M,X!.WIN?3BL=).D>'V;AW5ZSH@(7%XIM)A>38:GZ=Z\R?]H'\8]P^(C7TNGK +M#5B'E];)6AHX4?`J&!QXI&P],`>V_KQY.K8JMM#$G:&*^(V`X#NXJKX2G4K5 +M#7J#0=DT0.W^ +M+CHO0CH*=H5/U=?_`)33;^X\.X;U(4,'U[G9_@;OXFU@O6]I3E-:*"WVBAL% +MF@H:&GB2-.A`J@`#&WY#CT?5PS601`CRLIBMBRXY:05D[#H>WV6VK4S*PJB, +M[XR3Q#X[&M'JFK-0-9:.02VZV,):V4'R/*1E4S[Y(V^G%)VWC`'._MUX>TZ2T>,`\I)S=P'%>_ORR]&6/#WM$R0V?"25I#^)[F%7V_EKJBME=D2ZU,= +M&_F*XCZNP(^N,_3/`GY9.AHQ6V1BWB6X<9O^MUF^0!/?"[9^/_2*G@=D.HTS +M>I%,1PU=]EH]^*>\^!HO2>CK:B&LK)9+E(Y/FJ)I-O$<_P#4%`]EX^H'1F7$ +M$:#W*^:O2FH2SB2%L$^`OE-93\AIVS_,5%MU)K&U::OE*C*)X[)9XY*J6&0' +M\,E6T<4YCSE5(#;D@6C;N*S-I4&FG_G!JZL@TWICEPLRTUZFHY/TK448\E`G3X]8P(_`%ZHZ9>X4!3[XZ>>LFI-2:H6URSFP6_]5XHC"*'= +M<@*!^*23H`S^S&J*/4D39%,U7-+OYC,<%9MH5C1IN,?#[`[Y\A'-:>JG3!Q4 +M7G4M/)3`J',$C!78D9\W]U1^\\7T8G+_``J-^:YY5PP(ZVMY(=-]B2"J%I+B +M&'"A8EZ5&W4S`?M=(Q^9'$I1PHD.J*-KX^"0S3WHHR"F:OHGNM3%/&"&<]0! +M/L`/YYX-`AV65'=9F87&RD:&ST\7@M4=$)!\.0[L(CZGH!R3CU/K@<*J,)$% +M8VL&B6'19E9%2NB5$=)61VZ#`226!E52&LQ!`*?"ZWGN,*B)Z>0SGS)&)V9Y#CT49+=OM]>'9DI!,AE:<@=7<@].-AG&!Z@[['A9:!*T`8TC[K;K_8Z:BK*WEC +M_:16R@BHWBATA2PAAD+(\M%[^6LP^3VD>L+7WRDB6>BTY)T!4#TF%.V"I([_G_`!XM/XL4 +M^KVN^GQD>9(7V[_#3%=5MO#U-`ZWS'I`6S?E=:K95677%IGHY)(+?J%TJAG* +MR4M5&5DQ^1SCZ9]>/$73JM7PV+P]4&'.IV_WTW`A>E^G6'I/QAHNC)48#'^[ +M=XWGO7ENYMZ7J.6_,K7_`"^JF,DMAN]7:NIO^8(Y6`?_`*EZ#^?'V+Z([=9M +M796&VI2^&NQKQRS`$CP,A?FF_$/H\_8>V\9LJIK0J.9X`V](*R^76A7OLS7J +M[J4HU!:*.0]/BGI;#G8D*,9&QV&_?/$]5J0(=]5VC?/R1G4PV3I["#FK&CJT-31>CM;5%#;]1R:ZK-9U-EI]6TURIWDC +M6U13SK%!X,4CR-/528#^GM>B*/EA +M8=!Z5KK[;+G56RJFCJ`M+9I99':>C>42U#-+1>-X8F<*H+-CJ;+<5KIG3?BN +MMVC6#W`MAC9FJY@AK"!_*'S(+2'D02;0G=EL;2#,/3(:=3P:;EU[3$00X$`^ +M"^Z:MNH]`Z^H+5+4ZTO?*5*UA=/TS3)1/XIK%EEJY98Z>`.#4TP9XU8M/(R, +M654917<-L9N.V?AZ=$4W5:+8W3`,0J4S%NPE>IG# +MH>9$@>.HOW^=U[)9\]`/5G;?WXM;@BP-RZ;?;*:<5=XO4XH-.4:^+5U!;IV& +MY4$^NWY#BM=(^D&'V=A78BL8#0F<56#&F\1@:1C3U%33OT_I`#;&W_`"P?_P!OMW\H;2VO7VUBOU>)D4FF6-OW`GZ*KLIG +M%5`]X_AMNT;S_<>K::YVW0HD69YI$Z7J<$'! +MSV7^>W%_Z(]#:FT8?6[-+C_5W(K:.*% +M)CW3$1/&^X+)+U5PF&<'W*+TJ? +MKD<R!/G$G_M%N2N?1S9CJM4!K9GYG["!RNM0WQ':PK;5;Z7 +ME[#61BJF59J\I@A'9NMP#]"57[+Q\I/Q1V[7VKMX]8993W"(!.[GE$">(X+Z +MP_@]T7I;*V2VH6W;ZNWGQ.G):*/BLU9#JC4UIT50/60VVU.16^;*-/W8A<[@ +M*HW^HX]T_@)T.&R]DC$.$/K`./K'@!I^Z\O_`(Y]*'8W:C<&TRVD3^_RU6J; +MG)JZ2\:GIQ14ENCG@J8X+;6,I$U&BDE2"#@X.2,@E?3CU5L#L40($1["\L;= +M?UE2QB3;EP6Y;^R$B_1%5HVXUKR326PWO5]6[GJ:>JJ(DI(?$_Q.TC$9],]^ +M,VGCVTJSG_TB!X_Y4/A\&#AF4XNXEQ_?GZK8A\O;CJ^R,/3IL[-UQC: +MNT*E:JOI)JOKDC*UD=."KU'2=V8^IZC_`/$_3@I]5U1HM`0+6BF3O.]?*NWO +M24@6C6YS&=V_IQ&XRFU@%1AU4M@ZQ=+*H45J&0BG6M,<<\,9Z3$PZA +MT]AM[?7OZ\&X(YQE&J%Q0-(YB)"7SDMX4U*'\"/#$%MX?_;[C<<2%2F19VJ' +M;598LLLNIMT=?;WDB_63(>I@`?,W][^?`G6%C@"BS3%1F92VE;N*.I19F*]& +M`R^N?ZQP63*#H@-,'56HTO?*6JIPB5+QQG8CK\S;^G`55LZ*:IU7?#P3'H;G +M03%I$1J>#IZ=L#JP?Y#;[G/`[I&J-$%VBQ*JNIW#FG9*5YN\JDB3H[]Q_/Z_ +M3C3:8&FB279B,NBKKS"UQ#0TTMOH9W&[8S^SDX`_=D_O]^",F;460]>O!(6Y +M+^P'KH;O!\>FGJ@32P3Z*BJF`;/5TT]:@Z0/V@6SG[<>#/SPNZC'=&\8#!&) +M+?,TSY(?9&+-+:&&K-T;49_[M53.6U-+!IV%T95D3J?([>650.+E^-I#-N$^ +M_B4%UD6-]8:.K;O2M(Y`DKJ"> +M'RJI&>IH*F9NX_X0[\>9?Q6Z+NK]&SMR@.UA*[FX!P\0Z;\"M;/]H+\.\8^(F@YF")8],:FM<%1.H*@27.F +M(@G4C(R2@IFQZECQZQ_*)TU=C.BSMG5+OPKRT?\`]M_;9Y$N'@OEE^>GH(,' +MTLI[6:(;BZ8D<7L[)/BW*?`I'T-)3V>WR4D$D"4[HJA5F4=3=(]!)@+YL$]B +M21C?CU`VH'-L?<^=]R\6Q:/\+NEH*LV.HAHH::6J@)8-*%,9ZCN&Z0@7;'FZ +MO;L!PAQIBLUM0F#:VOS,^'-9U;C2);J%EIIB>RQTEZLEIJ+E?+0JW*6BFIU; +MKI"O2149(E,'0Q_6(98V"J201C@W#UZ6)'4UG0RI+9!/Q"_9BP=(T<&D:"05 +M&FD6=MHES;W^O[2K(\OI],WKF!I>YU6F8]'/J:.GM$UEJ5IYZ"X4M3#T15S, +MP\%IXI4DS#+D`"'J(8E`W7V*^CLVH,_6'#=L.N'!S73U8&N4C5P(F2!`NF:V +MTFU<0TY0TU+1N(B)[Y(W+'Y!W7F&O,:MY:U2W6NH2T/R<$51 +M#$RET>:D2->PZ08F$+$#P1T]`VJS!U<"<1BV`L8TN#=1)$$"-9F.<\"9I]"O +M7;BC1H&Y)`.A!'VB1SMO"N1R\T;JWX>K]8.5]C7DU>N?-\@JWL%RJZ1\4D%; +M3E9I)ZU`)YIY87=(HVZ*=/$$LDCL5`J.-K4-K4/U;Z;OTM$0]N8`&""!!AC6 +MLLYSSFFS6@"Z(H"KA*AHR#6<9#HF-8,W,DF([R3N4OR7H>S(2&AH:,SHB)EI<9TALZI>RGXG9].MU@-X`:9B2>%CSMQO?5\7WX +ME[K'9=%TE=HJ\Z7UKJ*VW2X4$=>88(+8]&D:@4:!1))3SRN\/C[SJX95#@X' +M,'_A_AF9VTWNAA:"6NS!YJO,EQ``[+;Y`0T",\@7MM/;SZF4N8-^HT@#3Q$` +M[]RI5S`^,34>F;I8[YJW3::XMFH;+0WNVVQJ\T*:<9T*U,2QB.0DR5"33$LY +M;SC('HP4W.:7$R7P9S7`$0;!H@7N3I`8KI`X.#GTVF0#$ +M:;HWD]YN5[EZ.F^8G,:E$4`O)(?PHH[DYXO.+Q+:-,U'V`"'JOR#-O6D_P#M +M,?CIFA27X;N3%PDJ5?%/G0>E/2*IMW'$M)_ +M3,-O[CIY#=Q57Q+_`-55[1_@LO/]3OJT?/C"A/[/_P#LG+SKM;?S8^(.W5=, +MDKK44-G<'K]^J;';T\O'3NB/X>=;&(QPANYA^9YJN' +M34%#8;>J`)&`F`!W_+B&Q>-@$E2.'P\0`EIJ'5]!003U?4B.1A,[?;\OY\5> +MKBLQ);O4Y2P[6"2%7B_ZLI=/V2Y:BO++4W$L[J6_Y*`=S]!_'B%Q6.91I9S< +MW]^]2I?"84N<)]\TI)K?+JV[*&!ZC5U^+1D>(4(6GB4?_E=5"G^X +MQXCJV'EU,.)<&@U'6U.C0/$@>!*+:\,D$7GT&OF8;XDWA5%^*'7,?^W>G],4 +M,I6CLE(]UNSC!2>H$A(!/8>?`^R,./('YBOQ$_TO"NJ8?_FB6-.[-)+G=P,3 +MY!>F_P`OO05^/V@UU82QG:/?N\S?N:5HLYY +M/?P:Z!5-L[2;1>,P;#WDGB[?Q*]^_B3TKI;$V2"W4=D#B +MZ+@??=JM->H;A?;I:Z[4:P35-ZK:`SA47K?QJI\(OW$:J1G^\#Q]0\'A>K;3 +MI1`^0&B^:^+Q=2L:F)?\1!/BXZ*EM]LU70\P-5V^JCBJ%MLT5(6$B%9JD)@1 +MH^2"2X?)!QA3OQT3`MBD'!4/:6(FI&ZP\>'F/1>BW^R\L+4?*76A!*7&Z7"V +M4[>+A!3TR+))+)(W;&%;+'8`9VX@-L5W6:!J?34GP"*PS!JX[I[XFR3?Q>:G +M76NH[[>):EI=*4$[5RI(Y"3LBE(%1&_"@`0#T&3W/5Q4C,P]2S,?,/0<=/V)L]E&F +M6CXCJN7[:VB_$OZP_"-/?'FF'K[1E+IO29O=1;*>X:B\`3-!X*L*=!^$N0"6 +M;<%5/USV(X,P&(F_UVVRG3:QQJ[K<9'%+J%[WM##KX0=_DNZTVRWO7R5R7Q);U4'J=G(N@_*[K:?BI=Q#F=54\$IJBCGMTU325,3QSHA:,Y[XW'W!WXMU*JVNR +M0H&MAGTGY7>BP*&LFHX%JT=VC63H8]6``?3[?Z?3@'%41,%.X:N2VQ67=9)8 +MJR&MIDC\"8X8']EO7/MPBD+0434_K;JC*P:E^6"J2\4;##$'8CUV^O"B.">I +MUR\%-)=:T4$,=$B55;.R^6&)2SN,]O8`^YVX'#`=4:S$P("A-3:NU/\`+R23 +MRP62!HR(XHP&EV/J_;U/8<8&`V*T[$/RG,9__KG_`/%!XFH:5'K)^&_D0?HA_DY:#=8;=;PH?R/^$9+`E7[? +M]7\N)+\RN+.'VY7DV$$>,K[^4\'.+>PG^8G_`+F-(^:!4U3/H/XT?AUU?6W" +MJIK98/%DJ^G8?*-<#!-&WH%>%L-G;"_3B8Z&]':>V>@NUMGEH/7M:T?[L@+_QUZ9XG9G3S8>-?4@4A4!G0,+\A'=!D]RV)_'+R\_2'*^\W6.5Y*S3 +MMTCNT<#TB.SWZ8AA9CH_'7Q5``CDPBL- +M@Q(E(&!G8Y]3Q]._UK*%(U*AL)/R,+Y)MPSJCPUMMRM%H?2-#$(J:AI*J>3K +M(*+N:@E<=)(R>D@[#9NY'8E:=C,16Q%221NCD)GNGTX\#,TJ+:38W>JC:ZRT +MFEZVKL-'1P#Y2L,T45(98:>E5G#]=)\P6%/(W1+B:-GII`LD2AR2IZ+LVD:E +M$8A[B"X1)AS["V>`W.+@EA`=3L^8"I.*K#K"QH$">0\)F+Z$:H2GO5DU+R9T +MM4+9BMWTG<:6%"0\X>DEJ&5Y#$9,K!+TJQ6,C>$JF-WXO56B^AM%XS$-JM(L +M!%F\Q=P-^U89I/!59U=E7#SH6'4SK(U[Q:WAHK)Z'Y=:;K_B#^)ZYZ_U#KNS +MZ:L-/<*^XU^FK=%1S4](@65)G3'C1QR1`P!51W4.99B&7#P>&VA5I[,P-/"4 +MV5\\,;+W"XW@@&8#YX[+H(=D;3FX#B`P'.XB[B22A,+BZ[:[/T` +M(G +MI*22FJRG5X"_,S@^$'9G\1SG*%G]G,PU3:F)JU*+12ZNF!(:.P0299K#M9C3;1-PRX=J9M))UGE<`+$Y&Z$Y+7CE7IJXZTT)2S:@9 +MI(VEEO,D,D\:].'D,DK'K+&7**B*F`,N2S<&=*=H;2=C7-V5B12:+D.`-Y([ +M((L.S,DDDDZ`!-[.V;AW46OQ%+,3P)]>=_EOE>L;^T+^*NR_#-RSET1IRM2H +MYH7B!XXDB(,E.",=9`[`9P`>YQ]>.3?BMTN;6=_I5`ZW<1N'#O)W*K;5Q9)_ +M34_B(EQX`_4JN']EQ\`'Z2U!0?$?STIIKWJ2KZJBV6ZHB#K3!SGQ)&;\4ISG +M([9XDOPXZ#"BQN-Q(T^$>&IY\."(V=@6AC:K[,%P./?RWCU7J`TUI)*>*.*D +MH8[;1!<`!0NWT''875`!F*EW/>]\`1S3&@-):(O$$@ED&=]@1].(7$8@"Y4A +M0HP>)2AU5S1I9:VIA2=)*6`8E<'8G.,#W[@<5#$8_.\C4!63#84!I<=VOV2< +MU)>(##6:HU%616?3=%&TDCS-CL.Q^PX`QN(#&E[S#6ZGY`(["434>#O6K_7? +M/'5G-76=!8-#)5W6WU5>M-#%'&Q@HZ9!UO/4-[$=(53^)BH&>.;T-HOQV(:V +MC=I,:&`T7)/AI.IA=`."IX6@:E:SM1[X<>=N"V*.-!EB/J1D_\`7]>/E%^8C;S=H=*'8&E: +MCA&-;']Q[3IYR1X+ZH?EEZ'MPFPF8RL.W5)>>X68.Z+]Y7FC^)WFE5:SUYJ2 +MV6R2G%DTU`UKHU4Y_6MCQ93]2Y5?ITGCUK^7WH$-E["IXFJ/XV*[;IW-N&#P +M;?Q7"_S`]-G8[;57#4S_``\("!S>8+SX&&>!2>U#544=DM,5-(XIY[I.'(/D +MD2FB@AC!&>V5.!]..[.?-0NX?JI))6BX2)25#8-1J*2OE +MD51U^&%Z-S[#K;\VXOU$9*-_Z51\35#ZH&_-/T^I7IQ^"2.T]3-*M%&6!'3XKC\!'%0VO78`>LWC32TW\[`>* +ME,-3+JHR:`_3Z?L5KB^+;7USNEDU+32,E/=KC6*U0T4?DIO*L<<42?\`\-`[ +MD#OMD[D\`[`I==BPXBTSY#0+_A*)KD0.S)GG'!<]QF+%+X=0!`X=_? +MJBW04\T]M;_:*']+U%4\B1QNP05TH&!/*1YA'GR[]/4$QD9X&J":AP]`Q%YW +M@;P.?#A/)Y?4=Z+M):LI+%HBKT9J::YWB^0372Y1UI*H +M):1D+P*7Z).DB1&1>D;9P",\26$V;3=7-6@`P=D&Q/`&!([RHH;3<:!94)+A +MF(,QN)&X[Y'DA#7NBM+ZGT?IV'3UZKK1HPVREOZR7JJ%9#635A\$!)",1R"8 +M=+(-@P/;.Q^"KXEE7K*],/JN")(,Z0M5JM)]$-IO+:IM$7B*RZ@HXZ.G@J!)3S"19$=5?/2'!(!\I&,@@[$`\6S!8 +MRC78*U$R")B\^O\`C@H3$X:I2>:3[05)K-=ZO]&>`\M/7)<7JZJK"A_#CE8I +M&6`_98,"0,^F1WX-J.:221,@?*2F6M=`C4&YX28$J:JV8W2KJJZ.LN,?5!23 +MQ4*KUS53AB9(T8%3E<#I[Y].`*5%IIV,"\3N`X^*(?5=UA:9.@MQXK)I(;;J +M2(VVLK;!XE*8YEZ_#&WG3/EQ])^'=G:.SOX3RY*:P=45AE< +M1IXPES>K25<6:\?[N22M-5$8Z.^`_NIV'TVX/P.(C^)2\0LQ-(N'4UM=0>'? +MR2TGM=1;JZJMMQB5'.#TY\LF>S@^Q&_$ZZLVJP5&WE0@H.I5"RI900J:B""2 +MW2D*#D1N=SMVSG]W`H1E*L`("X6JNJB)6=WR"`.H[@_3AXM$`!:IY@"Y&UDO +M"T+S/(O7*^,G/F;'IGVX;9A7 +M*^&*S5`U+1P#J-/34C+*>G_FH(HU`^^')^W'+_S>XEHQCG[W"GZAQ*_0DVDV +MGM,4`-&C_P`&MI_,>BJM\8UJ&EOB#AMD`JI*273+5*1QIUL4EK&)"I@DGN,$ +M>F=@#QUK\LF)?4Z,5:\WZQGHP:^:^8WYQW$](,'3_P#XJD^-4CZ!;<>4NHXN +M>OPV\O[C?:>'Q;A9)M-W>$Y*O)$IIG8-TKG/2D@(&Q/TX\#_`(D8"IT3Z>XE +MV&/_`"ZK:[#R><\;^;?!>\?P=VG2Z5]!*3,4)ZVD:3QS`+#\@5JNT_88-,W^ +MMT]=)474,-144125AUR&&3PV*@GS'J\/`R!ALD@=_J+AC4VKAV8G#WI/#7`C +M>'B1II:?HOD=MC9!V1B*N%Q-JE-SF'EE)!L=?93FH]46VQ]$M*E0##*[2531 +M]$%52*A>.I296R(^GQ"5"B1A32@=@4MVRNC#:9:^KK_3O#I$BXBQ_FN&ES3O +MO2-H[:HF96E64G#LD +MKO2Q],*EV9J:I0$L4:VX);<5IK/G)JOEUI*Q\S-/WR2IU!JK6%UKZN@K)626X4`1DHI9'8LL +M\4$=5+A`4C#NBNLA`5-8#9M/&8LX"H,U*BQ@:8L'-/;(G0NB#$F&FXWAXZL: +M=,XB8<\D^7$B13)@YB8,.+2138"' +M$@EQ#4[L(,H4Q5([50@-O<\0!\W:7@`D6,->?"7S)U)IWEK7\FM=IB'43XD@1=V<=."68]"Q]O64I8#";/J.IT<&ZK-RX9#?Q&N +M\\22HVMM"M5:'5*H`W"\CR\AW+TB\@OA6YK_`!Q<^KU\2_.RS&AT[-5B2V4- +M0Q$$2*-<`&C7>58L!A1(R>^:2EGL`95N][G^7LM'&TT(=L&23&\LN? +M8'8=AN>!64.J9G<8@2.7]Q^@1I`>PDN(W"; +M238$V$S>(71-B[$_T'^$/?"30ZOYSUU5?[71V70EBJ;D]);J +M.CF\1+!0($,]3+(26J;E,P6(._DB4N0,X`M'1)M>JSKP!3:X]D#1K1\3IU<] +MQAH)T$FQ(`@NE)-*H*)<7.%R9FYC01N%FSI)=:P&P[XJ:H:)Y-2Z"T7$M)=* +MR&.GB)?H^5HPPZY'<]F;J;<[GS'TX;Z:8AK:)I,(:`,SB;!K&P3).DW\)2.B +MN$=6KM8T27&`!O)W>]W(+RS_`![<[:/3EYO4^GYHJF.PVNHD:5!@5%3D],9/ +M<]4G@)_[0WOQ\O.C^PF]).D=5[;C$5B)TL7$N=>]F3Z+ZWX?:@Z.=&G5Z@_Y +M-/-!.YC88.][R`O/U-\U3VL)=:N6>[W*YS5=3.!DR10Q^(QR.W5(YW)]N/I[ +MA,$QH#:8AC``!PW`>`"^9^T,=5J%W6.E]1TN/'>3W$DHYNFG[I=4Y=62VTRU +M55+0M5-'%_Q(Y2[G+>@SMN=O,NXVXCZ`[54;Q\H2ZKY%/G]_\>:K%RJT-=;_ +M`,P*1*^S57Z)H)I_GEF#0J^66$0EC@^9V(;&X19&&.G(Z!CBUF&`=R5.PHG$ +M9N!,^2WYRZZGK>1?+"G/@-35LENN]+3*BJE+;R9HZ*.-1CIC\.W4\@3L#4;? +MBR>5[3$UG1J1?RCZJX;+LP$"1,#GJ?HJ#"HBG,9(832&-N +ME6S^P#N?7;'$CL89=+$#ZH;;K@6#OGQ`574MT?Z1O^I:OJJ)I99*FL(WK<74XMQIMI,M-A]_NJ4*#>M=5/,GN"[Z5KQ1WZIK8V#P2,8JJ-& +M;PA2^&.J/*]D'EZ=]V*\.T*`-$-!@\=\S8GWHHO'EY>;\_(:?9/3Y#]*VVW7 +MW1,]#)Y +M76R\7C2U(>8%DAD<`O'FK,08X$D#+B1NGNT;8P?3?B[]'OQ,V?BG-IU9I/=Q +M^&=_:&E^($(?%;&JM$M(=W3)\^*555%;WM-;J:IFKK75/X`-/2X2:F<*%:*$ +M@$1]6$4MN<9QOCBR-J5,W4F(;/0``JB,C,RCJ)ZP03CTWX*=A&UFM9>XF2/K/HF?U'4O)D6,0#^U +MQS1%3U$>N-/0S-$*RL\-D1POXF!R5)/HV,CT!)XJ5>D<'B"W0:JXX9S<51%0 +M:I57JF,<;V:YI+'.AZK?4$C,+[9CDSW0C'VVXG<,[_Y*5P=1]1S4/7`/\*K9 +MVX_0H"NU.:FEZI*>2GKH<+(C;D-_IP9E'Q-T*CSV1!%T-5E0E,:4#`8IXF<^ +MI[#AQ@2ZK[V6#5W&1D\&-I%=SER?1?IQM[)3321HHFLJ7DB89554'(QG]_#8 +M;=..J3:$Z.3WPZ:XYLQK=(GCTOHU9%2:ZU,3.9![4\8WD./4$*/4\0FV.D-# +M"/%*,U0B0T?,G=-IL\-=>:K4NG: +M>VW.JN3B7K@AK(JOPVA`$:]30#;?<*">.#=*:^(VQM;9U=\`8:JYX`_J=3=3 +M!G>!FY<>"ZE^&_0ZEC-O[/P@N:E>DTD\"]N[06DE7$Y&TMOHM2WE[:Z5<;89 +M0K=1`8%LD^N2&Q]!QQ;\]&#;2VU3%.S'4VD>%O3ZK[*]$MJ,VABWX@N[4,G_ +M`*W5'?(!(?XX;1IJEYUZ-OMTH7J*E-*-;IT,)(EC%6LHFZL8/2LPSZ].3@@; +MS_Y3AB:_1JO088'6M<#.\LB/&.Z8&]?/G\W]&@S;V%KU+S2>`(_IJF?HGG\# +MFJ(*K1FO]%5JO0BEN$=TMM+&B+'%3-B"H0].#XJS"(N`,8>-@6#@\TTBHT!H%5HQ7 +M=<*5`@4],'F&29C$WK(T\)ARTXE\F!FB`T-(L9-RR);I+A'],KQ]-2I(IMAN +M@G6;3XS$G0$)EW:WV'E?ICDK\1%DYESZTNMVKI_D;/X4#5-#1F*=>NDCBD9S +M4P2I,LDCG_@$.N%9>K*+NNK5\&ZGE@3<@S<7=$V<+AL"71)U@"I_"8RLYV;= +MI!$[MW&YW7"16FM7\O\`F+S'U5+J*:JT]ROEK:ZXPVFDK)$M=+\Q$#+1PN.H +MLTW@E65!EE\")G\-)'X'VJ[$4,+2ZILF1][K +M\)WG<+[_`)SS52[C=;[KR[FMIZ*YU$3R54L5)2T\DGZ.\:5YR$"C(78G"^7] +M4=L`\7C9V%908'-&@`/"0.&[C&N]5^L34=``-[=RL9RQL>M]&T51J"MH;K9- +M0W>)M#Z=I:J1H*F9ZC]74SH)"&DHX8Q41/X?E62;#8`8\06W=M403AH.1HZU +M[@):`TCLG^YYXW+1W29@=G/R&H?B/9`)O>;CNUG16BUS;N74&G^7]DEYS\S+ +M%>J+1<-!'J*&E*6BZ-%%-!&D!ZTF$-.)&A:H)Z)(I5"=)(62L;,;B*M:KB:F +M':[-4!!>M17*+2&D)%CDCEFA>:6ZEI0A@INE'\,J`_ZV3`\A5>I^E.+? +MM[I92P+7007M$WT\7:`Z'*8D7D*(V?L1UJV&%(IG,XBD::%&3I1B(UZVG8("[DU%SF +M8X!^TFFL^Y$'(`UWP]D$`%P&8BY$@$V@2@R82)FYG28\%^C?1BR +MZ2T[:=/:9I*>TVZ)1%$L2].-NR_4G)SQ//8UK8T"0YS6L#6CL:`<4R](QQTT +M!J9HV:<[Y4'+'/;W/^?%=Q^/+CE9JI#"X=C&ES[#W9.Q.JWVY;E=Y12@+D1G +M`*\1E7+19F<>T46QQJNDB!N59+Q6Q:MO=;>7ADGM2R>%"S;"1AW8`_LCWX@* +M!%6:[A+3IY_)6!@@=,U4SZ>1BEYK8S@2X_\`[>)O +M;T)'V]^*GMK'?J\V'I&6`]LB;G`JU:AH46R^VFZ=&]W +M$[A=7BICF4*/7.FUP!J>`',K;;\+_+O3OP^\HZ&A(I*RKMU''#=+D,(U^K\Y +MD^7SC$?B,ZK[C)/?/'7L%A68?#-I4]&ZGB=3'*28Y>"Y/C:QJUG5GW)]>[D- +M!XD6A53^/WFI.M1:K;)=Y;/6SF.::D"=32+%Y@K,1V,DL(R-CX8'H>/._P". +MVVQ0V74DEO7%E..4YW^.4$<+@:+T'^`71XXG:S7$9A1:YYX3\#!_W.!YPO(? +M\>W-B@MCI:C'-5UMZKIKU*['):EA8Q0`_P!X22J\F/7I4<<>_+%T3-;$5=J/ +M;:G+&_[W=MY\`6M\UZ-_,KTO_1[+H[(:Z[QG?_L82UH_ZG`GG`5(M5)4T5%2 +M6&K9!=X*&>EJNO8I4.$#[^A4N,8X(R'E7U8-G`]]^^_%!3IY=UK\@+I3H`]>+?M`BH&,=80#Z"%5,&\TA4>1_,1Y$K9W#JE:[27+WP?&I*2&P6!(: +M:1B[P(MNCGC@8_\`\J(JOUP#MCB@8JDXU:A(^)Q/@('W5HP;HI-&D`>9$_55 +MSU-4TRO#XF?$2*,^&AR2ZEE!;W.,]_IQ-X-@!=P(A1>VJG89F.AE)OF+3FS4 +M&E*>8F@HZM37R]04O(BEE`PNY.Y8'./.-]N)?!8>JRH[?EM.[NM5\K]0M=[+-/5VPR(M52%.I9PV!)Y6&3D9./7J&?4<6 +M"MLNCB:>5UG`V(U"@'/>QV=MQ['BK*:$O>A^;IA6RW:Z:#U93JAD`8&%,1BW5\*[_BVBHS1KM'#C)@@\M#S435H4WLRTY!UC,;5:Y7,M^N^4MQI*>LJH+;:4'4DRI5RO%*S1%O$;I +M=$*@1LW4=R$R2JNJK`XKHI4#(I=J.,3OFY]>Y#/VA5=VM#R^VG-#FM?AE^&G +MG+0W"MK-+T5MN533"7YNSU$M+,ZM$)"SH"ZL`OB#I9690H)4$,>&,!C-I8)P +M:PDM&@B1.L?,PGGX\OD9M>/7,K^RCL])4M=^5O-!H:*4EZ*@O:=8!10Q` +MJ83ET.VYCSOW'%RPGXC5[#$TN-QRYMM,ZUM!(>K!+>%U,FX8Y*J<@9QGB3?M+"XH2*@)X$0X>=O53VRL +M=D(:P1XH`UMI(:DL1O-##'+=:93'71=)!*#<2='<'<@C;!SZ'@39^-=1JY'_ +M``NTX3P5FVC@VUV9Z=R(E56>KAG4051\Z92.;&^!W5OJ,>OIQ0DQQ*,PVR<17O1;/R3TA_LK/C#>:ICK=,Z,M= +M+$@;YB>_0M#*>D$@%3@PO\`^JNPW'L59/#*9]0$>.C.,((@6YIS +M:*_LS*K1=W@N/->_Z8:NT0B-9*>)CTJE%$JGI +M9:1.EY4!*JP0$H"'.%4DQ6S,!^NJN;E.XGBZ3<9K@&+@FQ,#5&5W]0T.&ATO +MISBTB>'>;)#ZYU_4W&.BM%7-7UHJG:JIYJ:0.L31RLE3#(%"Y9&E*';#CPGP +M"=NA;#V%1HN!I@`"`9$2(!:;\8!C5IS"ZZ/^7RN\])6[2JSEPK'U.6<@M8/` +MN<;:Y05;[X1;Y#?[GJB(T%=2U5-60T-2DR=)B9:8OC'I_P`7&/\`"#ZGCQK^ +M>6J]V+P;\XBF,V?7PT5*(Z^F6-L74R7$`F_::7B8!)(`U*Y1^6[IA@^C_3#!8H +M5NQB"*+P2+!]@8W0\-N;`'5;+N>U9JBVZ0Y=G,"U\Q]2: +MALDM!R]OEZ2$U%EL$DE97T,L:AT9UZF6GDZB=R7\H'4LC99OIIL]^%K85M)K +M26TW'MN[((T@%W:>!8#T@0!\L-H5:S*I7EBOC? +MI07?41>Y30H(V-!UU,@F,Q5@561PJ(H2-<+)Y7ZU8$[&J9\4]NK*8#1?>!;0 +MQ,7O)B-$#M*13$V<;_6/7NN4CUK[V+17:;BAGHJ,'YNK@CC`ZV0=(>1B.KPQ +MGJ`!Z2#DY`!XMH=1>YM4$$B0#.DZCA)\U"4W'+U8'9)^GV5Q>6W/WEERUT[# +M16O2^JZ.%80U;\C-#`U=./$<2S%LLS=70%0L4C"GZGCGN*Z+8_$X@U<1E?.X +MDV&D``0!O)':-[W`4]1VQ0I,#&`@Z:#=K)W_`"%DEM2\U+SS[YCZ<;5%906J +MPRRK0Q0N[3)30.P0++-%"7EEW"ERO2=E1(T'2+7LW8]+9.%>S!M[4$C<-\0" +M0`!KQ-R27&5$XC'/Q=8.KF/M\S.B;%TYMW2VT-GY;WBEK4TI61UM#6Z9CH$% +M71VO,<=,.G8M5(L"R+([=!,44F"(E'$=2PM"OB7;0+R8B'%SLI?%^S,`3`+0 +M-!WHO%5'-:*8;:3:),;K^<'TNN-#S/K.9M7I3E?H[3=_TQI.EHI*&O5()2;1 +M0=T&Z-B= +MP3YQYJ.ZBDS*-\:@`1X=XN=$56O7EFT.*VP:1Y8V3F'=*>=X;L*.TFN@MDJ[ +M+3P2*1B&,$Q#.>IH9'!Z77BJ;4Q6=X=BZIH@CLYGY2[67$1J;$C^4$#4%2.% +MPHN`T.(L3$B>`[O5?HH\N:V]ZWE?5:P//1R2&"V4J[Y7..K/;)QW]N+1C\2< +MUNX*#V=GJDXAYMHTLAG\L9[G&>`&4^K&;> +MI+$.`^*W+[H!U5J%-45-2\LKTUCBR,Y(\;[?3_7B&QC`]P?4-E([.:7'.!R_ +MPJ2:[Y@WC75TNO+WES5K:;+0#IOEZ`RE`G_^/%Z-.W_Q!R>*)M7:-7$DX;#' +M(UMG._I'!HWN/IJ5>\#@12`=4U^G[^]Z7&M'L7+?2$MSK:A[=8:8,8:?O*S; +M=.<_B8G?)W.?J!Q&XA].A3AMJ8O"G,/-0EW^`/>I0-\/7*.]:CU$VN=7NVEX +M*]99(X9GZVH(AYIJF9QCKEZ/+G9$R$'8\371[9CJ3>OK=G-,#>+W).\Q;@+- +M&]1.VL7F<*+3)XZ;N'<;\`0+$E-FKYH0\TN;^EN5.CJ63_TWLKI<)I`Q\2O6 +M+SK$<[",DQR.Q.2"J[`@<2-&L<15R-;%,7\.'<)EW.!H`H>JQK*0)WB-VFOE +M$$\K:"%0_P#M+8+V>?,=_O5)-_LQ2Z3IQ038*Q5L[U#"1`_J5F"HX[H(A_>' +M'DK\TK'T\3AZM8?PF-<_D7.(9'>(<(%_->R_RJX?K:.)%$_Q7OIL[FM!>>Z7 +M.'*PE>.77VI+IS'YOW[G/+\OJ+1UFO:4-E@J1TP5E1&6-'3]'K#$E/\`,R#U +M&!^T>/0/X2]$QLS8>'P9;%0MS/\`]S^TX^L>$;EQS\9>E;=I](,1BJ1#J+'Y +M*?`AG99WCLFH[B#&]+^&XSZJO^G5DJOT@T]1&]5.S?\`'"S>+,X([DL'W^G% +MTQL,I/(W#]@N?X%A>YA!D\=9WD_-&7.HM>+;:ZND+456]TDK<[X1)(?$4J=] +MLLI`XJ^RFBC7<7<(]59=I/STVAO'YA+AKN]%4ZGJZ"/KJ+C:JAW">5#+)"&D +M.!N>H.XQV\Q'$M@VDL)<="!ZJ/Q#PQTC^:3XP#ZE73CNTU#;;CXX$C^KU6.! +M8:<^&,JBNI`#QN?7(8G.,YQOZ5G`8EK34INTOY64]5J]9D.^!Y\4%"CAKYTJ +M?"CZ#(U.T:H<*^!U`8_Q*3^?[Y7"XD06M//WX636*P[C!TU_=&1Y?I<*!M0V +MFK:SW^@Z9XJN(X\ZD$+Z9R,@KOGJ!QMP_6VPV>I>W-/O@>]!NV:QPF8/E[X* +M:M_-"S:^IZSEMS1TW;$JXTJ(WG0"?I9VZBW0Y/5&63\&_2,A.@.DUM +M>A5EO])`$\)V9GQL9W_`$0[9W$;CZ'+2S`N) +M.L'\,F2"Y.1U]"@Y'EX.=1HU`74S:??[\=%$5&EIREMO4^2N/;^87,&*BEOM +M14IJ"TRR$I5P3("ZD$-*S%BK';)R2@,>%78\1>*P-(C^)W:?/NW+*CW;MY4? +M6'#%"/#@<&22'#;$+GJ&1OUDH.WIOP&=FMGM"WB??I=(IXL$1 +M-OOZ_1*_5E=HW5LE)-?K';*FEG6H/S/@HP<=(4JLHPSD$ACB0YQC)SCA3]FV +MENG?IW<_/R4CA]I5V.!82.[W=#G*/X#>0^I-1P\GNW%#UX:>]T]4:BO +MEE>"'Q"M(2BC=MB__$C`,(4AY4Z45CT$PJ>)IN&%$BI29`D$;S&^!8&VD,F3 +M&;^)9#L6T@9W:V.[AKPGA/.T&:F<\+;0):['>`E#46JFG=)*V:D2;]"&2)EA +MJ97VZ(^L&.6-0ZR1O4(?P*>+MTUL033%4Q$C=)OO^D:0;Z*M$W+#56KM<6@:7L=RI-3VRS7&XT%(M09A*],3X +MUMG<91.C+*M3DF17A<]/XA=6[3PE##1B'2RI4:TF/ZQ+7MWWCM-ME(=W$38^ +MV,;A,1UF$,'*9X$#<=)UL>!"M_\`"PM?*UKU17T]-3UM_IJ.[,*>G6"G),!C +MZ8\$,Y'0>IW526[`J`Q\#?G!+3CVX<&U%CFWF?C)DS.LB(M'.5],_P`CV(-; +M86(Q-8RZK7#I_P#\;0!X(K^,RSZ/OWQ(36?4VC[#4VNEL]N2*Y5574+5?.U` +MS%3TL<;`22LU+DQEE+0B4=66REU_*=B\:WHI5J86L6DUX$DCXJA```(S203`U6LJ_7?FQIB>$\MK3HZ +MJN\2FF^=TG9DIJSQ@K5#=85,QK!)"Q*J1'&XR`>E"OM;9%'`O>!B'5!&C:CW +M$9=)@F^:8EW:]#\T:6ZUNF +MX[W\[63ZCM])+)T2K2E5I(:8CK?P_"\V02W7U;J`Q^O6RA-.I@JK"2W+%,/` +M<&S\9,]G-,]P(O*^(N+86/%5]@9DQ:>`XQ?T1Y\2]K5I^90TN9KU4T%5;+CJ +MNIKS*CB.0,+?1P1#91$)Y995;Q"COXGB*6:/C.AU`X=H%=F49G!@!GF][CO) +M-O"(.I;VP'.$9IM?EI`[HX;M5-\KN9?*>[6/2=CUY9JN_P!^L]#^C*:KK$:: +MJJ:63"RT\/@LI952)?*X?(DW)(4A[&[`QK*[JU!PRO)=E`,-(B">Z-``+;EJ +MAM>@6M;4':;:>)X#<)DW^J:DTA#HF_WC1,G-*V4E3J#2I@O!2GCI9* +MRGJE\5#EDD:5*N/HDP[.P"H.CS1U7IC4_6TCAJ50TGD-)[,`Q$M$]J!!,D`6 +MU3IV-2#7!SVAXOHZ8X'IF=P[O&L;8L.$VEM'#-;2JTB][B8+G">.X1`U)(`X3(4= +M7HX9[\]*I#0!N,>IU)T\RE_4:/AK*E.85NM?-B^4=1(:A[[7LELI&@PN3))' +M!@1%0R]61L1A02,[JXH4V'#-6?+5-&Z6UG05'.FB-\%1-/^A6CJHXI(Y"BP2K&O7'*L?@NW6,,9CTDJ-C, +M#B,:ZH^C4ITWN9$N=V021)+9!ELF!!W7U3>+ZD!M1CRUKM`+V%A-Q?P^2_5) +MTTNF.5VG*2DIH():I$$--#&`>D>@'MVXC,,RT^X1F(Q#*<-;NL+;ONEA>=07 +MS4>IC9&KRE0Q2>2")BP$.>SG]D?3UQ[<:KN`&4?$A:.%SU@'ZZD:F/D%7'XB +M-?:TNM11\J.4TZT>H*QU2MN[CJCM=.20[(.S28!QZ#N>W'-]OXZO7J#"X4P! +M\3[0!P'$\/5=)V5A&L;UKA?=ZHRL.AM*2>/$E2%(E[H'LJJ_,N.76%XT_$$-K5Q(D0!J2?A`''APNXP! +M?#@ZSNL"#(R=Y6#-CS<6TM(;DK.`(NZ+`<-=PW?U'M%50F7F!]86^ATUKR\U5@O5!62WR.T1W!@%:IM:RQ%):0,!CYEWC4+GJ!8 +MNQ"H@X;V7693P[G92"209X38#OD3SN3$!+VI1J/KF#V1`F^\"W(DQ:\#6P$Z +MU_CQYH6'F?5\X=7T%]N%+;9;C6T]3!UITVY(@T8,;`X`V9M\'96/XN/&WXT- +M&UNE6#VBCJ7VJ+K42(JRSM__#4]*H`-^E!D[GCW +M'@*+9ZR-?E-EX>QN(>0:Z]NX7O*F.7J0:4T_;+Q52Q&2WP2Q!WW! +M)C).W_NE/;_+BH;4>:M4L9O5SV=2;1I=8[^4?1$5I@J+WR[N,M8WC5-#XM;Y +MV_6)3^(H5,YP57]8!MD!\'89X@MH5@,0,O(*3VA%8N&]P.@=)'V^G$S1)%-S6ZR/?U4<\%SQFT^D_L$\=.:BJ +MJ^UZA@,@EJ_T+9[YX3'&)"O@F,^Q*MC./64*S%.)S$WRL/T4 +M#1ZI2A6TW=/"J9K76TUSIUE!7,90$#([9(()&^>W!;L*9(J>4'JCCRL<15"&P0`"`2;A@<2 +M:6&=4#X`;E:.&XDZB>%M5S?'8,.KBG%R +M(H0'!#*P9E66I8]M>C-373_''F->:A<U!\0>C==22::U;\)FI*O +M52*N8,Z))'5TON5"]MBVVPZ>(C%T64*?6TL3U8WR;6Y.X"YTF +M5F#PKZIRTP'#QE-^S:/Y54%JIM1ZIY?'1\:P-)%8XZ^JJ+C.O00(JBH,GZL' +M)PL3*SL'7R.G0*SB=L[1J5',P-0N&F>``)WM&\CG:X)D&5;=G]'Z3&Y\2+<` +M?0\!QWJGVH/BJK*B^4\UMDFI-,05,@H?D:<4CFV+3M-3PK$IZE*F%495#,O0 +M,MEYP#;-&@%KFIXX'G>E4I$]/EI9&$FNZQJA)*&J,'ZU!`ZR.QE5 +M<(=^IRRX!&%,:Y9L]]P,%LJC3<"1KK8;]/Z1N)!.8]EI`[26_'N2(=/5%??:I:6=ZB44QZ5D!,^(@R9:*-E?PP2CR$%]R#V)!(F+_@M!I#*2 +M9,6,ZP2(+C,"PB`P&Q*?HMZP`F\#0@1/C;3S[1W*%YG5%#8;AIC],71(:F`5 +M+0YMDCU*5"966HBJ0Q%0IB9DGHQ&,Q=(O3P[T6Z-A&XK+74E!+-!48)E@C9H661WZY8GABRBL_1T*IT7IXG9[:+W9:CJA>T@ +M$',V2,S38.(!D`!N?M055W;0JLK%S0"`V#W'AR)MQ%QP*?\`\*>I6U!IG1E3 +M\W\_'")*:GJ!4&4O$)9RJ8)/0J;`(V&`P3G(9O`WYS\"RGMHO:`"^F'$<+AM +M^),$E?4_\B==[^CE8&X%>/\`Q#CX01ZH>^.+455<_C6=)G!(DDR1A6ZLX`''MYVR65\,QA,AHMO$Q`)WGYKQ0S&]76)`N3Z3X`: +M!;9O[-WG)3W::_V.IH*VC^3O-1,M)55+U!^5JB9@K.WF8"43(,G.,`G(SQ\N +M?SL=!:FS=JT=J4XBK3;<".W2[/\`ZY2>*^LOY(^F#=J]$ZVQWN[>%J6XY']H +M7Y',/()0\Z.7]ZNO/NPZ(T3J4W&JT9?*F:L2>!:9K;15U8&AG0R'Y=HTIIX( +M2%`9UU37TZEQN-@JK5SF305VU-4U<4U;` +MBFGH*DT:'P::ID&&G!!`$#ECEQ&2`P3B4&U*;,93JX%HIL$DN<.6AG6(1,_B*0`KH&+2(W3GQ//E6STWHUTE_44*K<0;,=!)``,WT!,: +MZ&][Q*IFUMFN96;D^(^F[?\`/CN1AI?1NIJNSZJ77G-G45QBKH7J;M26^HFD +M,Z*(0PEJ&D!<".F5<`>90`,(H;B/Q.WZE6H&X>BS*T]G,1J+V`!B]Q/?NB6B\J9K?=8M3Z=>V\PM"&Z+!+%^D(UCA8'HIY*N7,BB/)0 +M]+'S,S)TL%SP57Z4X:IFI5LU*KEN#45\N4]*LK4A*?+PHY8HD,<:JBM*%5=BSA&(#`@\4WHWLX' +M&-VE5!IM8'P)L2[>Z2?A',!LPIS:=4FF:-;1V" +MW5M'1W&36-V/3:K=(O5.B'_GRI^R`-\>@(!WX=-=1W&IJ-55\7765M0>J9O\``![DGI`'T`XJ6WL> +MW"TR)N=>('=Q.@5OV-@FP3H-23P%[_3@AOEOHBZU#UFM=6216:5XO$J8Y%PU +M/"=U@)/9\8+>WY<56E1=DFKV0!VARW-[^.]6D/),-$$Z5]C50D:(Q-XK,@)!&%R7R2HVW/5@;L!Q"UGC%5G5ZH_@LC7>=P[N, +M7&[4*68]N%IF##N9TM(UX290U1^'7E:.=W-_3SW?FC4P-%IRR/&/%IKG +M5C*T,"C.:ET"+++VBAC9`0.KJNH8["TQB,0)JF0T1':=N[X':.C6C*.*IV)K +M=:Z6`GD1Q'#C$2/Y6]D7)6OCFO>DTORSY@7'G1K*EET]=*F&^Z[U$:@EJZJ# +M=:6Z%20$HXT14"+^,Y.,,.@4ULS976ORMX +M9G'A&_<(!O\`W.)CLA:F=:_&GK#GF]WOMRME\Y<-+.P"^#2@+U9R(C^)6H==B=20`V;!HD`7OQ).^/*<_2M9B& +MMI#L@$@_U:G_`+;2YVA@Q,6I=S>YJW*B^!Z_ZEO=VH+K?[A<^FHGH83%3R2O +M.C!(@<,Z=2D>(=VP3@`XXX;CME==^)6`RB6MIN?,?T!X]"X77I'H_M-M#\,, +M>XZYPRVDU'TSY6(G?KO6A+3%CJ=6WV*KK^IX/F'FDSN2%.V?;)S]3Q["QV*& +M&I1O7D?`X?\`4U>4JV5SIDN5H_0M,&^6CJ3'48['(0_PVXHW6N8[K'ZG17)] +M-M1II-^$:IAV2HH9H+/32QLL-UJ*RAF15P45T8@J?[I*$#_MQ6ZM,N>3/PP5 +M-TGM:``/BM\TG[?:7I)M>35E48Z:ACBM\!VQ5RRQ(Q`]BO0`P].L#N1Q:\(Z +M:#'<9/D57*E0BL]O],#S"F-!ZD*QV6[!P(:_2%*V)E!#M!$PS[; +M<2F)H?$W>UY]6CYSZ*+P]9IR'4%E_!SOH@:W:@HH:NFL]54*]NJ(I:,M(IS3 +MLK-T]1]0KQ`?9L^O!U2@YP+P+V*%IX@6:=]O)-C1&N:6"W4]MJHF1H&ACS,G +MB=-;&Q$993Y3&ZL49CNH*X.V."]GLJ7RND&;*ST@V"'NP:OMMS@>CGK%JUD*LH2?'3$8U+HKMC/4K, +M5`[@]6RCQ#1,3L7$`=90$&3((W@VF,WB8G<"\Z2S<4USLM4[K1W'28F>7IJ6 +MK8;E3UB0QT=;75DL$2BH\6D"K)U^9HNMNGI4B9P23D"JB(\J%EI>U<(ZF7"N +MQNL`@W$`@$P3H6@\#E?O(!.I514EP,<;3KJ.Z_'>#HNC7%DY15D-':@OVF[E+KO4]%3U-"]VN5%; +M6C"V^D8`QQR2MXF)7,L4>%55ZH9E#9QQ:=LXFOAJ=0,:'?RM+I:7&8)`,=D` +M$SKVV$V,**P=&E7+03&\@7MKS'^#O"NE8=%*F;QS7Z(KE8;=44EABE7J-/20K3I51DF1^IE"K)D2`,#@2 +M=2B3HD*2,WA.C!&6M7E\'>28-A:22((D3);V@,S9".=C&@EC`&SR`^0_SQNJ +M%\Y=:+?[)-27"Y5M/0U<ZG4 +M!I:B^EH)-N1-VC6.(;E:J=M3$TW"7&YW:$Z7[N>_O52;A?9([K`]ETE57>HD +M:HJZR"`2]<5,WB%NG(#]*R352J6(!3#8([=(PV&!IEU5^4#*`3X1K:X:WQ!G +M158O"N@J)I[I%9:QE,CV_P`B3NWA1S28@5"S/UT\H$C$`>*F +M-V'$=5V7FO`+9$.O&I`[6\0]OEP1'7-!X%,*W1:ZQ +M!0.*QCG-EQN/O/S03'^D-'T6H:W4-IIZBZ7JP8MD3P%HJ:8N$GB@E@"S*65"3ZH0-@./F?^;#:+L9M9V( +M.CJ;(_VEQR^E_'BOKI^2;`-PG14DB[JU0GO#6@_))3XZK]76#XJ[GK":IO5K +MM\FFA9:::D8JDC!W5HV;!ZDP5++AMMCCN/0'Y5,.VKT2J4&`9W5G.\"U@=PX +M$!>1/SAUW-Z1X8YK-PS!YU*C@/4*I,5WY/Z3TD*1*&?6>H)*9H:I:B%U4RD* +M"8)"/)&N6?KP7/4`!G+<>H*M+:&)K`9>K:W2\^@-S-H-MY7DJA6PC:9>[M'W +M\E=3X;>;E(O.O3U!!I2AM5QJ]/".MJ:&15?YJREH)A.E?HN_R"B'3UJ&7P6(,>%&R+ER +MOFQ*Q8AL*N#Z'%?$/FF]K1)F)+NT0+FYD@";0&V`O=>0,3E;VPYPM$P!:??> +M=5K"U=37G4U;RYEO5OO=7=+K/4W1T0*TT%'-4EHP)7CP`HCD<3MA%3I(PH.. +MV;/%+#=>&/8UCYP`!D`[Y'9$GC;V4)B&$Y:;OBN+V[(-CQGWS25L'+87NF@N-SN,*^) +M3HR124;L8SUR!NE1N$R-F('40V,XXB<1C#5<71>>/O\`:5IM8T@`+ROTG?@^ +MU#KCXC=177FS=]/IIW1[$-0R31%9&3&1C/[..PR?<[[!QE8O!?;O2L)3>^H7 +M`@@[]23WG4#L[=J*[TOC::H'_P#HM(PP*RI4_P#W3KV\--^G +M.Q(SZ#CGN.:ZMBVU2;#X1W:O/(7CFKW@HZKLW'_L>/_5Z;_H^C4=4LC$>N-@/J!Q3MKXEV+Q#=EX5UC=SO4S[X#5 +M6C9^'ZFF<75'=.\G]KGR1)RJT_I7F7J^.Z6NG5.2^@YIJ2AJV8"*ZW.G7];. +M#V:&%P1U_M2@X_`#Q?\`9.&HO`\U'G+:W%K3P']3__`!:.)3VS,.00X"^[D#O/]SNZPYD+S@_'/\9^ +MF]9:HM7+2Q4VG;%RJT^X>"2ZRBLB^8'E^?FB4GQI%`\L`5V+>J`;0%)C:K@[ +M+$6$WC=,;R1Y*WNPYH@-@1J=;]_A:(.F[?JX==QU +M$CR'RQQR15$C.S>PD=,>V0`-AQ6L)L(__].6BFT=:`T9ZP`K.[?BE<#;^/8<7#%XEV(J7 +MT"I&"H_IZ9RC5-;2E`W^Q]3)/*342UTLKX;=BQ3!)_Z?RX@=I8@==;<%.;.P +MT4LKM29*EX9PFHM.VU)UDI8JRCII`IZ<9DPQ^X#$Y^GUX!PC,U-SSO!1>*>< +M[6S.@]4G[[?*B'4O-JAJ96BB$M.T*)_PX889$<'_`!,WB2$D[GPQ^5SP.'S8 +M2@._UG]E4<=B2W$UB[EY#116FM0T<6DN7==$$IG,MSM=0(MEA3YJ:3IZ2<`' +MJ;V[CVX-.'?U]5I_M/H`HME5HHTW`1\0]24(:@K(1<4AAD@J(I)Y,E6Z0LK( +MR,,'`!S'G/KGB3PK3E!.L(/%/`.7GZK)I-0T\UOAAN72C,!3/,QZ&C?!Z?$] +M.EO,.K]D[=CLY3PQI5,S$QB7MJ4\M3N]]ZL-RIIM73VU+M;[3=:VG:2**L-4 +MJP_-1#J3Q1)*5#`-T*S*<8/WS(XUK*C0'&"=._AXW4-A7/I.,B_L3X*UMDNE +M\I*B$U--!55.5Q'%603!XV(4@Q(Q#88CR=BQC#9$6U(Q^#R@M-IGS^T:\A&] +M6/#.8Z"#)'J/\W\>2ESKW4NG8I)?T=6VUS3&*1(Z:0A$CD"Y5R"O1CJ!8X9_ +MUCY)FZD,H[!I8EQ8\]D$WMJ1K>;Z<@0```T!1&)V@ZF);&8Z\OEQ[]^I0;J_ +MGK:*.V0UU]JKI=KW64<]LHFI417>/I?Q%#.V8XQ).TK=./.Y_&QXL6R.BC&. +MR4(:QL$^E[&Y@1)$Q&BKVT=K5,H=4DN,Q[W7X(?U'0K +M14E,]:T26=+CX4CTX0^7Q`L\B22G'4%=6&(P#)8?!DU,+U`/4M,ND7.2P<;D +MB8!`U&[XC`KBW)6Z\?Q(@03_`#:C07W2N=+K*:VVRDMU+XJ7:V^)23QH1.W7 +M&M8'CC650H#D+YCD]/2<*W4H:?L]KZA%LKC8V%CU=Q$G2?EI!3]/$G*'LU$_ +M(VY>RFLFLHZVW).C3T@9'B<2``J^>N7$+(,J%D#$MD2%HSC+-(]7Q&RR*EB" +MTZ1-M3K,@\Q!`!N9`%BI8DEI+1<^6[=`[CWZ"\P%1J^FH8JPSU9A149:D4D< +MD\:[,VSNPZ@%C<@Y)(23SR*X7AG_`$MI_A@2;1F@:VW"W,"!.C6Y0ENKD=IQ +MMR/W_P`WWJL>L-=V66XUE91T<4_ZM1U/6"5(D#-+@K"OZP8DG4R=4899I>A% +M<..+Q@L$64PPF3R$:B#$SR-P8+1?+"KV*KESY;[^7#3GQ29H-4\P;3:*_F3I +M735LI=(2SK;X?%`=O(RJDL_0Y:0J4C4R$@`QG`4=YK$TZ-:NY0Q5-QL%ME$5>B,),SB,L +M2I`Z6.22YF!`)!P%2Q]$X<4L-4G0=7%(![3!&4[S8C>?#T6A3IN>&%T +MM/OPX]W>NZ*GTS6)?=`W;4=/J*>E;-FN$;?,-5TS'J7P0@8JS%?.(QXC#K+$ +MB,#C6(Q.)8QE9C2)U:;J;&44V`01&5HL!^R^P'Y7=FNP7 +M0S"LJ?%4ZYY.LYWD3XJC_P`<.MI]8\TQ:WNDTM/0-*KQH,D.2G5U=6=SN +M^5-NT2;Y\YKZMI;;9J93*8#32225[]+>4*@(508PIZMRTD0&`79/06TSB^J# +M,)\3MYW#]SOW7.X+S1@A2#@ZM>-W%6^H-8/G1^7VG6P/2W';"KL&=[)&8Q#J; +MK@/,\/'5">I=9?IBZ5>C=3\Q:J/ +MEU;:\17:MFC85VI6W9R(Q$"\:M'(J1.0L:LC$L[XXFMC;'I8:F,90PXZYTEK +M0;,:3:Y,3$%Q%R;6"C,5CW5']4YYR@WG4QU@T5R0Y%:SNFB]=ZFU+:=?U<,[W*^Q4WAT +MEDDEA8Q_+H0U0^[%6J70X8-X:L`W$)L]VTMJ85FT6L#:;?@IF'%\6S/O`TD- +MFP^*Z>7^B]!Z?KKU36+3M[KK +ME0&9V%/2];J8XZ:)GD`8N6G;;>1P,M@<7S$S2Q53$O==X``WVF23XP-P"K]( +M?PVTS_*2;CP'IZHRY1\I]1ZUO-)?^8TESK!75[4CPUM64E*`([M)(&,BMX>5 +MSCK4NF!@`\47'XQC)92`#&@F&CA.@L.&_O4J'26DF7.-YY<3JK?6NFJ=&6RW +M_(UUFTG?:Z/YFXQ2B(3$!F2%)8RQ5&6-%P1YF5E+Y;@:"2GM$+W'7EQ +MA-/;Z"/!^3@!PJX'8_M$]MN^!QQS:NWJC26MO7>-/Z6[A[^2Z3LK9'6&]FCW +MZ>JI%R[M>H>7FEJ>QV^IN-3\2O-6:2&HNBCQ9-/6CJ4SSH.XZ%D4)_?GDC]$ +M.">CNR7X6BVD)Z^O1N"9V_M`/?V##&6`^9C>3ZD@:*]FN-0: +M'Y-Z,L/([1@MM"E);U@2WTYZV^7C`)+GL(TQYY'.&8DG))XOV/QU'#4QA*$0 +MT`1W<>0XJJX+!NJ5`2/#6PT\!Q.INO*I\>OQO7'7B\Q.5/);4S6W3<5;);KO +MJ66M\.6Y59R):6C"@O*54=+2`;9(&!Q0RRI7J"M5=V#)OO\`#?/NROE)E.C3 +M=3;\6A.\DW,6OS\]+GSE:LD@@BO-SO%YAC@C'@+"%\P8[$[[L<;;]L[[\72A +MALI8QK;FZBJV(:0ZHXHHY<1H="ZHN30PVU9Z66&FCQU.(?&A!=C_`'NE&``] +M6XB=KNG%TV"\&_D?JC=D4P,.]SA%C'=(^BRM!P?IVBU+8N@34#333R-CJ;YA +M(5D0K]$$4A/TSP5C6EN5[3F\*^:A:_0_,:(6OL@CFI;1XBBY&0F9F_!3 +M$'S'VRH&,^GY\!84.`*/V>]I8PZR?V0-=;@QU;<9H&@8)5DIT`_A1?+@_7A.S2*>6>I:!E$E31:J23I7&4BE5U./\0F\; +MG!]<^_!F"[+!QNA,2!+IWW]^2@[+7QH9A41I5-T,H20=2$Y'F9#LY7`8`Y!Z +M03GMP>\.<8F$"*H!S.$IC4M^N9N=PO%3)47*X-"OCF9Q+)60,#G#MG+`*V,? +MW!C\(X#PU2!DTCT3V+ESI%[75A;+J>EJK6]555Y>WE34?,*Q6)%RO220I.W4 +M[]RI!*]QGB6:UM0C*.UH5#.+Z8DF1J%AS:MJ:6Y7!-"5=]U-+.HJ*)(HY"J= +M2A,ROZJO^$$X0G;!P72H-R3B"!%C\D)5J2^&R0=.Y8C7&^U=!6:JO]9\_5W" +MH_1DII8O%:B,L:M1O21*29`)/'>5'+.# +MGI65,DOLXS$FDX8/!'^8ESBV0WEXDW/T33J0(-6L(,6$Z\UROFHDF_15UHX0 +M^J*:..FKV,LBPZJ,P^*(`RFZSZW6UQOL$=#JTU^K_``%0!WC5D4(H8+T2-U)Y +MSAL%L$MC@1E5_4#$5/\`FM.43>Y-N),@=X^G?]@N?4R-GMQ*##UJ#&MH]K69.IU.OWL$*U['N +M+WF`%)6VJY@RI?[MH2:_U^CXI7C@:=PRE%\Q_5/E6)VPN"^>(LU,*T-9 +MBP!5(OE&DVB1<>B?(?FEA);H)];+%TQJK66I9YZ*S'1%+=*A#)-+4T%)"TN" +MR;IO>^S0)[A/AY)D76MCT +MM1P:9*=ZNNHZ&HAI*6IC>0,]/5U,,9J`&/B,4`Z6"Y#;CB!P3!B +M,0[$8<9F-B"[,2#'\H)RV&CD?B?X;.J?8GA'?=&%RT10TVAN4FC=7UE=;(Z@ +MR26=[72NU#2]=E/5+@>^`?^H9X^:733%C&;6?CGBU6L]P']H-A?RNOM=T,V:W96P*.SF? +M_#0I,/\`N++/-35]#5SM5,:\&/H\# +M*2(YZE8>(,PHW4.K;IXM;^D%?$4JOZ<%KJ=P8M&\.F(,7CXC(T7,J>SJ3'4^ +ML((.HYS8\[V\$'37[2N@;!J/36B*^HYBU3U"0T%#=:1/D*=PZF2J$++^M97C +M2,-+T!B'"HREB6:SJ^,JMQ.)I]2T`20Z7$?R@[A8DG+,2),V20QM-A8TYC>T +M0)XCEY2KV<@KY<^:_P`$W-_E?JN"HGO%-;JN-X$Z%>HC@D$J=`792#'&`!@# +MH(['CP7^*&&9T6_%/`[KPP#O@=(&#]%L/LUS&9,6X.O,`0">+KF3WSXKY15<5F(ZL1(X[N&Z%CZ1Y2 +M734T3ZAO];;-/Z-I55JVJ=G:"!F7K2GQ'O45SKCHI(CU;@N\2AF4C$[6ODIB +M:I!RMT+HU-YRM!L7$1P#B0"W^E$%[C8:G7PMJ=\#QBZNKH35-FY>7_3$M)J# +M3%BL]KI&NM79_&E-Q;I@=DIJ]56.")D*B0I%(JQLZ%I)).AUINTJ3'84U:S! +M6J$96NB&2XP=2W?FI\ +M34]CM`M%!66FBJY/!NZ0RDSH_2H1W_$Y54C4D`YZ%RPW+2=#$LP++/,0!E)$ +M".`@1-[/>G+RTY,V73NI12WNVSW6N%.?D+I4"$T2R( +MY\3P_-D-T](!`,@*-DC!XK6U=H5*M,O!OPO,$=W?K;0W3-)SJ3X>V&F=\^^? +M!/*HUA:-'5=ND@IJ99:5JXS5E3,K(L(@(D7Y4>(W5,9VCZL=9`).RJ>(3#89 +MSFN(==PN/'>;:`"`+3ON5*U27%@.C0X?73QUWJA6MOB):WW"FMM+72ULU+$* +M5OET>,P1)M%$^'3)1<+@[@``A?6>_P!*JUW&HZP.GE'#E^Y2*@LT-U`[_)?J +M,?$[\1=!IV2ATGI()#;*3*PK&E725]7$`,'9;,>^.[ +ME,KJG1[8S0R76/RY]ZT\7?6YO>OOTKJ>[M%=VC-UO#R'RT-`F52`D]O$8,2- +MLI$?[W%4V91<^M->5[\K*S^BM2T?* +M6V7CXK^:59-1ZEO%M6EL%KK2$>U6@,3$Q!_#)*7,I&QR_P!N.F,K_IF_JZL] +M8\:'%JXQW6U!#/_;OY?-3-5E+",ZND07F +M)(W=WO??BM%-7S!2R:-:JH(YH(I143F1Y,U#@D*J*Y_!D#+L-SGOOQ.U<.:N +M+R`PT0!\TNC693PN8?$9[^[[JM=2];J"GM+5SAC4,LG2H\J@G/;V``^^.+[#BE8Q +M_P#Q#G[P0/$S*MF"8[J<#@XGNL!Z2LO1&K?_2V_P!)J"S45%H +MJ1%#6.I\RA5Z1D^I;]K'KWXL&!PHI,S'0:*O8_$NJ.+:>_7N5O[TM+I^@LUM +M*0$T-H5H@!E7E9`HW].D]/W[\<]KS5JN=Q*N>$8VFQHY)":?JA47V^QQ.9(D +M\0*Y/9$@._Y])/Y\6"K1BFTC>HFF)J.'#[('YG.MPM0+L(FDIV7Q"YQ'(T01 +M5VVZ20,_4@^G$]T?):XMW#[J&V^06@CW:R&M'O+46_6Z9,4KE6 +M./?(_(\36,$.IN&XD*$P8+FN&E@?)!FJ*J5+M#-2D+Y.E2/[P<8!_-",?4\& +MX5O9[7NR`Q#NV.?W4*LTL=93U=',8@2'0G!`S@@'W[G^7!S83#Q(D:IFT[BY +M:<-;:DDI[G3U"3QQK^R,-XD:GTPR!E'H">(^J2*L'0B$_2J33MK/^5TVO5U7 +M:!45=,AFH3$U7'3YZ0V'3QH0.V,^<`=CGT.[]&`8)C=]C]$!7:3<"VOW3;AY +MJ5P-FK+>;.KQ3AJ*>=28MTRC-TCI)97*,3@E2PV))X+I41>9/$<=Q^_>@:E1 +MV6!;AW*?I(K3-27"[:1N.E*[7#W;Q8FG\:![697;I6E@;/ZL=US*0$VB\".T=>%O!,TL"V#D(<_G/HH^&XW6^S*DC3ANKJD"O"OD4A1&2=B0Q*>YM'$-%!P:T@0-)//F1Q0 +M[&_PR7`DS!.NGT4%:JZSLU>][O%QH*2:%8(=0+2^/17E$D0+'7P98&158(K, +MV5=QDC'5P2^H_-F8V3O:##FSO:[A;2+IB!)SF#&NX\B/%?8:_3]NMD=MO=@K +MM)FH9YOEKU22U5MJ78,OB0SI^LA#'S](ZEQ#%NPWXW^K-6[7]8`=6$!PY%MY +MY[^03[@&@M7+8 +MC>18V\H(#GJ?!'6.,J[2'6=7UA:QPN""T]XMNWGN"32PT4])<#J(C?SMKHL6 +MGO-PL=XG>Q5D&E37HD%;13PK62J`Z'QX:2)9F$I90`'"+YTZ=@21"]CF.#^W +ME-C\([BXP(WF+^:)JTP"`VT^]WUA"E3IK4U?<:?E_:ZK3NFK,RQ/4^-7PS54 +MP8@XE(PS.O0"(5"A1TC!+9*W8UK0[%O!>X$Q`(`W6&D<2;GD$T:1<[(V&COU +M[S]M%\TW9]?\M)M4TTM#7T5!N:]8ZB".NIX5<()=PQ1"&;?H.RD^7&>'*];" +M[08P,>"=P(.4F--TDVWJ/LF'2:DTG+05VJ+CJRZ5%[HZ4TMNL +MXMPII9G+,5#R0L$*(P)9PH)=QV,8PY7V9B`T8>E2:&O,N?F,CG#IG2`)LM_K +M6`=8YQ)&@@7\?'T2^T_4WKEM-=(J:@J;=JX-3U$=P>0+44T>/%.`25(E#Q') +M\Q!"[Y($T_`T<;EJEV:G!MN/,\>6[@HW]4^F"RTC?P'`?5-CD9I;1_,?F3>- +M0\T+W34\-!'^F&HD/1#6LLJ(%>0(X6G5FCZL8)C5_P!ECQ'[8KUL#AV4L$VU +MQF.ZTB!O)/(P!HC<`PUZKJE3RYSSW1ZPIOG%K*[ZKYLQ\HSJ![MIZGU*PH5D +MB\(TZ32([4S1@*H2`&=1A0`2Z@]!4"L8[$T-F;$Q&UF-API%VMR0TP>]SC-H +MN5&P^CS\;M6GLXF7MR-_ZGN`=Y9C/<5]@.F?2:G@MC +MUMJ"U/\`B5/^EC26?]P:+:P5JZO&NK[K."ILNE;?<:>E:^/R-=,OTVW<3L5QEM>GG;_OI&;][21QM`5=]9*VULC` +M;1I12;6I@N>8>9:W*X`:-EP^)UAI''RU^+/0RGL7I'M#9SAF%.HXM;H,KSG9 +M)%R,KH@:QNU%;[IYI:TF?YW +M6`\!KW")T)`3]2I3$L#KCF.(]*8`ZR2O= +M>Y.PVSS4HN!OF/IQ)WGY(0M/7"3=L^OV51K_`*_U-S#E:*U2U=ATS3*0:ZJ/ +M3X"D`$_X=E4>K>@/FWE\)@6TQ+KDGWWI_0PEG2WBAMJ?)6*Q4=T1`/%JJJG> +M3QVWW3#*0NV6=LX<]<6V#B`).C!%O\`J)-]Z]!;'>"S,=!Y +M]\;]PYE58Y*4&BC;=1\P>:%<*K35/6"_Z@K75OE:EPH6CMT/7O($B`9V;'GE +M(QOD2_1_!T:;7/K',P',3>"Z.RT;^RW4G>;#@%MC&5W.ZJG:;0-P_(6B +MW^TN_M(=9\^]67#3M@O=5:>75#-(B0P.0DTF0HC4_M*`,>V0>)S"4*V-K==7 +MTO`Y)#13P=*WQ'Y\N7-::ZN[WVNMUNK;W25L%LJJEYZ99X6198CB/Q8F8#K+ +M$.G4N1L1Z<6VM1R=AIO"@J50$DD;U(\P*2GBTY1M2QM)!'1>'#$0#D&4J-OK +MC/UXC-F2:Q!XJ0QI:*4@;I'FH[36F7>HMU7B1.N]76VU"2CACBI*6-680=1,L\I!Z?%;ON +M=R.Y[;#B;V/@:C^V\7*#VSBVTSE9H`@#DC15-_UE:FNC$*M1,[AADR;CJ&/8 +M+U-_[NGB9Z0UA2PQR\@J]L27U0')5[K5@'D#0"/DD;HJ1VN-Y60+'D3GN1E3$4_F"?J>+-BF-; +M2"@\.9K.[RA[7T3&S:KC'G6"&AF49&5(J(P1_P#JS?NXE=B"'M)WR/11.V23 +M3'S0SIZOIZ2Y:0MJR]%7?:>JMK.?PH)(W,7_S:,_]/UXFL8P]6]Y'P0?( +MW]%!8>N`YK3;/(\]/5!NII9XZN,3IX%3([QM&^/U4L?AL0<;#!D/W`'KG@W" +M/:YLBXU\#*!Q1+2)U^HC[H=NC-;JI94C9(LA7C.P",Y/_P`6ZE_=[\%4;BZ8 +MQ#R+;TQ=/5XI'6:*3IIYZ7KE!SCK1\@CZ@I_\B/7@6JPQ?<4NA4%RW>%WWV* +MEHYVDB81VNK;QHW7M!*RE6V]1C.1Z_NX:@FXU"43ZH4I(9Z:ANL$NZ1_JZF( +MDLJ8.5.W=,]>&]B![<2%/$AKP=Q4?6I2T[TY:&&6#3M'>*.O>[1T4,$E5%%, +MRM2,P'DHB +MR6"]V"TW,WO5E'0Z9G:1*BE$3303$`8$NP/2RE2)$)P,C9M@5B]HTZE0,IME +MXYP1?W":I88M&9YAOOWWH.34^E@)M.U=MJ*W3JX:EJC,WCP/TEF;';=V9L9P +M/+W`WDQA:Y(J@@/WB+>^:#-5@[,=GU7+3=^MFF*RIM%;=+;>M,5Z*\DOR[N( +MF7(59(74'(!*;8\K;'^27AZM)C[W!7=/JVDEI=36 +MYY+W/0I%'^AZ6OD9<(&7,;%,%E*X*J20!OGJ(X:PVS7-+7V#C.8C?W3Z\5C\ +M4(.L;@?V3!GM7+CF+K33]+9]0RZ=CJ:9IO#DCC"TQ7IZJ<*%18V.).ERV.Y. +MR`G5'%8K!TG5*C0Z#Y\_N(^JT^G1JN&0D6]4M=86;5-DN!I_TU27BDAB$"SP +MRX,4:@EH@K'J55;(PV46HM35^I-4RRU514UPGJ*.C+P04:9!D^8J)$49_8`4 +M`DLS#/8Z_5U:%#J:-H$`FY)Y-'ST&FB<&&:3UE4WWQ\_%+FSZHONG;K?+;IE +MH:>"HJ@QK8(9*AXZ=6)41YQF,CI)#+ENA<]L<'XEHK4@_$;A&60))UF-_<83 +M-)Y8Z*?FF-RGY=UR +MKU]MNVFUN8,WGBX]GQU/*)7K/\U73"EA.C[-D`P^L0VW]++OCQRCQ5":"CI+ +MC74EMM`L=IKU/5\ZT;U;2.=U"0PJR=0P?,0P!(W.-O;7Z:JVD35)`.[3PDW] +M0OFSUK,\,$G1/[1GPU:8NU!9]6:CUC=`T7)XFT<&QX#GF!J=!8:F_ +MEQ)T1/0O;*5JS6NC.7MJML5+U0T%7?*^/HHR'ZHI((5$2.Z`AG8^(GGP3C*N +MFG@74&_I\=6F0"YK&ZSJ"3)`)LVX<1,<0AV(%3^+09`!@$D>FZ?K"(YOB,YF +MU]!HZGEK8KF]/=DK+M*L,<5.M.LBQI'%T9+_`(1N!T1L9"`CSS,]5Z4]$;YC/"`.<7D-:%T#\.^GV(Z/;;P>V7O.:A4:XW)[`L6B +M.+2Y.CGSRVLNO>9.F^:\U.]YMUPLB-4TZRMT551!Y4`0$`ED?)R1LHW''`OR +MV](*F%V9B>CSS%2C4)`C1COBORJ/SO\`1BBS:F"Z24#_``<12R2-[FPZ +MG'?3>!_TH;L/Z#L$D=KI+:E"9(HLQTKIX:Q!68B281D9=1UY$@"E%ZF'4#QZ +M1%:E3.:HZ3Q-XC@-=>4G=-FM=CI9*"LM@O8I9: +M>2HHY#)3Q"0EF568R,24`ZADHS$>4K&I*X-=[7/9E:TR`=9`@$CS(&[C*?9A +MQ2:64Y^J4TY6AC>^V\I:UEBI;+5PW7F%<&N=U&6CM +M23`NK=7:9L_J_MN1D#T($FS,;4TDD1F*A[A77B]3TM36M1TMN@8M36V*,&G4 +M8[E3^(^;.3D_D,<2%+#`7-R@JF+DP%*4&D#=;?2U8JXU@RRH#"Y"D'<;`^I_ +MCZ[\$NKM:;RO<7\;&H;Y=>=VBM%7&Z5598;M'%?ZZ-R"9JHR$ +M`=L>&H`Z5QM@<>0MIO=4QH:\R'`./>XW/VX+U%T9HM_1YXO*K/\`')S(U/I3 +ME3I?0MAGI[?8J\">H"*0[,V8R,YQCI'MG<[\6*N):VC_`"M!/J1Y*#P-ZSR= +M;>I@KS'JUL:%BL5%2QA(8D&%7=MR#W/UXO>Q6`4@FEF_V9L4KR26R>X0RO&S$X;SJ"N_EP!Z?7OQ(UK5'.X`_11K*38#0-2"G- +M>*2&BY=22PJ/G$I8HHZA@#)&IF;/3MC^'%>HN(Q1YDJ8QCIPT[P!'FN=CA2C +MH+K6Q#KEIZJEI(`_F6/"@^)@]Y,L3DY&<8`P.,Q==P``_FF4SAF!TN.HA=%Z +MKZL6[7&H?'D-W9)4\8DY`,G2 +M*&FD/5",2D9/G9QEB??CIVSJ31HN=X^J9]5:[X>((H[IJJNZ%>JH+88*=V&2 +M`1UEC[L2`,^H`'%-Z6O)ITV\2I_H\T=8\\`!ZRI.L)EH[XTA,C3K22/G?#=8 +M;;_]CQ`L8`YHX2K2P=EQ._[_`+I=`2(4 +MLVH=)Q,S,M/7J\6^ZE)8P/WCOQ;C>F\\C\BJJR]1G>/F%/\`,1O&6NK75?F8 +M[_B33),UNN,,A)46X2@@[JV-R#_U'C51H+@> +M:&82&P."(G5:GEO,M81O1K3-(RAZR=4]THX +M9)'Z7@FI)".[QB%@`3].A#]U'",4XW.:.W-` +M]+.TWZY.ICE<]L#IVVVR?4\5G:5=QJ-=QM&ZQB>]2^!8`,O"_P`[=UD$ZWM% +M/<;IH/QYZV*)ZRHH9(X9C&)(Q$)/,5P>K+$9S^';MP[LEW5G$!NX-=>]YC?N +MY)G:#9ZITZF/2?V[D@[Y;++!IBEB2Q6L5+((Q4A&65.G&X((!)+%CD')`]`! +MQ8L%BJKZY#G&)T4;78T49`NHSEC9J"I)NU1$)JD&H5%<`I'T0]8(4C?/8@Y! +M&1C']O8MV&I,-,"7$ +M"]TY@*(J/AQW?4*Y/+Z"T4^KM76FV:>L5EI:=:/K-)!T/5DKU@S,22V"N!V& +M">^V/)GXVXVM^CPK'.)S.J.,\;-%M+`F+;U[=_*7L^D[%[0K1#FMIM'=+GGS +M.M?EX +MV+AQT;IXR.W5<\N\'9`!P`#1ZKD_YG=LXBOTK?A:A[%!E,-'^YC:CB>9 +M``W*,JB)$"]'6`2IR#@9XZ[A]B +MX5S#1AHKY1IJ:LH(9'%(E +MREZQ)/%$20K-O[]()5>E?+Q#;&Q3^K>"9+7%H)U@:`G>G,7AF%T^,;I4WRVT +M_0:NN&C*#4YJ;W0U:Q4@@EE*QTT0=L")4Z0,8VSG&3COP'B,4\9W`WF4+7JE +ME,Y=RLQ;--V.HF?%MI*6NMMNH9Z.K@C$ZR:_6EV4.:#`M93]5>:B\_#WIV^W*&"IKHZR">,DN`CLT@) +M!#9V[XSW`SGCS%T=S8/\1<32PY@/#YTO9KOG=?1;IY5&T?P1P&,Q@#JE(TPT +M\,M1](?^%E5S4-UN70*FKK:BZ2RQLRFJ;Q/ERS;^%G\&=AM[#UR3Z8K`NJ%L +MQ!W6GOXKP!2>&1D`$I-W>MJ:BBI&>3"R3=+(.Q!)]_7RC?OP;1I-;<<%CWD^ +M:(-=U\W+]J;2>DUBM,56D*5E>B_[[4K/`DCJTW<)YBH10J]/<$^;@K#40_\` +MB/O!L-P@Q,<>>O"$RYT-M[D)<:?T];Y]6UUMJC4U4$1FE#._G=E!(ZG&"=QQ +M)8QQIT@YEB8"#9_$J]6[2#\DUM1V>S6N[T=-26JE2CGMIF$+,Y6"1E?+QDMU +M*?*/7'T/$7L[&578=U1SI(='A;[HG$82FVH&@6(^ZJ#=JVJFJ55IY5`0-Y6( +1R3WS_KWXL9>22DT!#1"__]D` +` +end diff --git a/UnitTests/TestData/encoders/wikipedia.qp b/UnitTests/TestData/encoders/wikipedia.qp new file mode 100644 index 0000000000..52bd6e2b29 --- /dev/null +++ b/UnitTests/TestData/encoders/wikipedia.qp @@ -0,0 +1,5 @@ +J'interdis aux marchands de vanter trop leur marchandises. Car ils se = +font vite p=C3=A9dagogues et t'enseignent comme but ce qui n'est par e= +ssence qu'un moyen, et te trompant ainsi sur la route =C3=A0 suivre le= +s voil=C3=A0 bient=C3=B4t qui te d=C3=A9gradent, car si leur musique e= +st vulgaire ils te fabriquent pour te la vendre une =C3=A2me vulgaire. diff --git a/UnitTests/TestData/encoders/wikipedia.txt b/UnitTests/TestData/encoders/wikipedia.txt new file mode 100644 index 0000000000..c99f0a9708 --- /dev/null +++ b/UnitTests/TestData/encoders/wikipedia.txt @@ -0,0 +1 @@ +J'interdis aux marchands de vanter trop leur marchandises. Car ils se font vite pédagogues et t'enseignent comme but ce qui n'est par essence qu'un moyen, et te trompant ainsi sur la route à suivre les voilà bientôt qui te dégradent, car si leur musique est vulgaire ils te fabriquent pour te la vendre une âme vulgaire. diff --git a/UnitTests/TestData/mbox/content-length-summary.txt b/UnitTests/TestData/mbox/content-length-summary.txt new file mode 100644 index 0000000000..fd3cb2276e --- /dev/null +++ b/UnitTests/TestData/mbox/content-length-summary.txt @@ -0,0 +1,278 @@ +From - +From: mailusr1@navstar1.mcom.com +To: atzet@netscape.com +Subject: Re: mailusr1@navstar1 3.0b6gold #1 +Date: Sun, 21 Jul 1996 17:02:55 -0800 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: message/rfc822 + Content-Type: text/plain + +From - +From: "Jamie Zawinski" +To: "Jamie Zawinski" +Subject: attached image cache test (test 2: inline disposition) +Date: Thu, 13 Jun 1996 23:25:49 -0700 +Content-Type: multipart/mixed + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: message/rfc822 + Content-Type: message/rfc822 + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: text/html + +From - +From: "Jamie Zawinski" +To: "Jamie Zawinski" +Subject: attached image cache test (test 1: attachment disposition) +Date: Thu, 13 Jun 1996 23:25:49 -0700 +Content-Type: multipart/mixed + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: message/rfc822 + Content-Type: message/rfc822 + Content-Type: message/rfc822 + Content-Type: text/plain + Content-Type: text/html + +From - Mon Jun 3 12:50:27 1996 +From: izzy@nugget.scr.atm.com +To: jwz@netscape.com +Subject: RE[4]: your generated HTML +Date: Mon, 03 Jun 1996 09:42:32 -0700 +Content-Type: multipart/related + Content-Type: text/html + Content-Type: image/gif + +From - Mon Aug 18 21:13:21 1997 +From: "Chuck Simmons" +To: "Jamie Zawinski" +Subject: 3.01 MIME prob message [Fwd: communicator 4.01 a conference problem] +Date: Mon, 18 Aug 1997 21:07:07 -0700 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: message/rfc822 + Content-Type: multipart/alternative + Content-Type: text/plain + Content-Type: multipart/related + Content-Type: text/html + Content-Type: image/tiff + +From - Thu Feb 8 18:49:08 1996 +From: "Dr. Mark K. Joseph" +To: jwz@netscape.com +Subject: Example of CID linking in a multipart/related MIME message +Date: Thu, 08 Feb 1996 17:33:10 -0800 +Content-Type: multipart/related + Content-Type: text/html + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + Content-Type: image/gif + +From - +From: develop!nextmime@ebony +Subject: More richtext questions/comments +Date: Fri, 25 Sep 1992 14:13:02 -0700 +Content-Type: multipart/mixed + Content-Type: text/richtext + +From - Thu Apr 25 10:19:58 1996 +From: "Raph Levien" +To: smime-dev@RSA.COM +Subject: Multipart/signed message format +Date: Thu, 25 Apr 1996 03:26:57 -0700 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Fri Nov 8 18:21:51 1996 +From: "Eric Rosenquist" +To: "Lisa Repka" , "Jamie Zawinski" +Subject: My encryption certificate for S/MIME testing +Date: Fri, 08 Nov 1996 14:45:18 -0500 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: application/x-pkcs7-mime + +From - Thu Nov 21 13:20:54 1996 +From: "Eric Rosenquist" +To: "S/MIME Developers" +Subject: My encryption certificate for S/MIME testing +Date: Thu, 21 Nov 1996 16:10:23 -0500 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: application/x-pkcs7-mime + +From - Wed Dec 11 18:06:10 1996 +From: "Jamie Zawinski" +To: jwz@urchin.mcom.com +Subject: signed frog +Date: Wed, 11 Dec 1996 18:05:56 -0800 +Content-Type: multipart/signed + Content-Type: image/jpeg + Content-Type: application/x-pkcs7-signature + +From - Fri Dec 13 15:01:21 1996 +From: "Blake Ramsdell" +To: "Jamie Zawinski" +Subject: Re: can you send me an encrypted message? +Date: Fri, 13 Dec 1996 15:09:42 -0800 +Content-Type: application/x-pkcs7-mime + +From - Fri Dec 13 15:01:22 1996 +From: "Blake Ramsdell" +To: jwz@netscape.com +Subject: Encrypted message +Date: Fri, 13 Dec 1996 15:10:21 -0800 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Mon Apr 22 18:36:56 1996 +From: "Arjun J Taneja" +To: "smime-dev@rsa.com" +Subject: Ready for interoperability testing. +Date: Mon, 22 Apr 1996 18:20:32 -0500 +Content-Type: application/x-pkcs7-mime + +From - Thu Dec 19 13:29:25 1996 +From: "Lisa Repka" +To: "Jamie Zawinski" +Subject: very cool +Date: Thu, 19 Dec 1996 09:38:50 -0800 +Content-Type: application/x-pkcs7-mime + +From - Fri Mar 7 02:51:22 1997 +From: "Jamie Zawinski" +To: "Jamie Zawinski" +Subject: forwarded encrypted message +Date: Fri, 07 Mar 1997 02:50:39 -0800 +Content-Type: message/rfc822 + Content-Type: application/x-pkcs7-mime + +From - Fri Mar 7 02:51:23 1997 +From: "Jamie Zawinski" +To: "Jamie Zawinski" +Subject: forwarded encrypted message (mult/mixed) +Date: Fri, 07 Mar 1997 02:51:07 -0800 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: message/rfc822 + Content-Type: application/x-pkcs7-mime + +From - Mon Mar 17 17:19:30 1997 +From: "Dan Hugo" +To: jwz@netscape.com +Subject: This is signed +Date: Mon, 17 Mar 1997 17:17:35 -0800 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Mon Mar 24 00:03:37 1997 +From: "Lisa Repka" +To: "Jamie Zawinski" , "Dan Hugo" +Subject: testing out some new stuff +Date: Sun, 23 Mar 1997 23:11:56 -0800 +Content-Type: application/x-pkcs7-mime + +From - Tue Apr 15 10:42:13 1997 +From: "Dan Werbel" +To: "Jamie Zawinski" +Subject: Re: Obtaining other people's certificates +Date: Tue, 15 Apr 1997 08:05:56 -0400 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Wed Apr 16 16:57:13 1997 +From: "Jamie Zawinski" +To: "Jamie Zawinski" +Subject: encrypted +Date: Wed, 16 Apr 1997 16:57:13 -0700 +Content-Type: application/x-pkcs7-mime + +From - Sun Apr 28 13:05:40 1996 +From: "Blake Ramsdell" +To: "'smime-dev@rsa.com'" +Subject: Deming Software -- ready to go! +Date: Sat, 27 Apr 1996 01:08:58 -0700 +Content-Type: application/x-pkcs7-mime + +From - Tue May 28 11:02:16 1996 +From: Ray2@FrontierTech.com +To: smime-dev@RSA.COM +Subject: Frontier Technologies testing, here's my cert +Date: Tue, 28 May 1996 12:24:23 +0000 +Content-Type: Application/x-pkcs7-mime + +From - Mon Jun 10 11:45:25 1996 +From: "John T. Gildred" +To: "'smime-dev@rsa.com'" +Subject: Signed Confirmation +Date: Mon, 10 Jun 1996 14:37:52 -0500 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Wed Sep 11 08:47:00 1996 +From: "Peter Williams" +To: "'smime-dev@rsa.com'" +Subject: plase help by returning what gets delivered... +Date: Mon, 09 Sep 1996 12:52:38 -0700 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: text/html + Content-Type: application/x-pkcs7-signature + +From - Mon Sep 23 13:04:41 1996 +From: "Ron Craswell" +To: "S-MIME DEV" +Subject: multipart/signed test +Date: Mon, 23 Sep 1996 09:20:00 -0700 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Sat Nov 2 21:56:58 1996 +From: "John T. Gildred" +To: "'smime-dev@rsa.com'" +Subject: Signed SHA1 with VeriSign certification +Date: Tue, 29 Oct 1996 15:12:00 -0500 +Content-Type: multipart/signed + Content-Type: text/plain + Content-Type: application/x-pkcs7-signature + +From - Mon Jul 29 02:26:23 1996 +From: "The Post Office" +To: unlisted-recipients: ; +Subject: email delivery error +Date: Mon, 29 Jul 1996 02:13:08 -0700 +Content-Type: multipart/report + Content-Type: message/delivery-status + Content-Type: message/rfc822 + Content-Type: text/plain + +From - Fri Sep 27 12:03:19 1996 +From: "Dr. Mark K. Joseph" +To: lewisg@Exchange.Microsoft.com +Subject: RE: problem with relative urls and applets +Date: Fri, 27 Sep 1996 09:36:54 -0700 +Content-Type: multipart/mixed + Content-Type: text/plain + Content-Type: application/vcard + diff --git a/UnitTests/TestData/mbox/content-length.dos-offsets.json b/UnitTests/TestData/mbox/content-length.dos-offsets.json new file mode 100644 index 0000000000..d1b8840ff0 --- /dev/null +++ b/UnitTests/TestData/mbox/content-length.dos-offsets.json @@ -0,0 +1,1330 @@ +[ + { + "mboxMarkerOffset": 0, + "lineNumber": 2, + "beginOffset": 9, + "headersEndOffset": 675, + "endOffset": 1939, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 2, + "beginOffset": 9, + "headersEndOffset": 675, + "endOffset": 1939, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 20, + "beginOffset": 725, + "headersEndOffset": 753, + "endOffset": 831, + "octets": 78, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 28, + "beginOffset": 883, + "headersEndOffset": 948, + "endOffset": 1887, + "message": { + "lineNumber": 31, + "beginOffset": 948, + "headersEndOffset": 1747, + "endOffset": 1887, + "body": { + "mimeType": "text/plain", + "lineNumber": 31, + "beginOffset": 948, + "headersEndOffset": 1747, + "endOffset": 1887, + "octets": 140, + "lines": 4 + }, + "octets": 140 + }, + "octets": 939, + "lines": 21 + } + ], + "octets": 1264, + "lines": 34 + }, + "octets": 1264 + }, + { + "mboxMarkerOffset": 1941, + "lineNumber": 54, + "beginOffset": 1950, + "headersEndOffset": 2430, + "endOffset": 8331, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 54, + "beginOffset": 1950, + "headersEndOffset": 2430, + "endOffset": 8331, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 69, + "beginOffset": 2506, + "headersEndOffset": 2655, + "endOffset": 3134, + "message": { + "lineNumber": 74, + "beginOffset": 2655, + "headersEndOffset": 3095, + "endOffset": 3134, + "body": { + "mimeType": "text/plain", + "lineNumber": 74, + "beginOffset": 2655, + "headersEndOffset": 3095, + "endOffset": 3134, + "octets": 39, + "lines": 2 + }, + "octets": 39 + }, + "octets": 479, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 89, + "beginOffset": 3164, + "headersEndOffset": 3291, + "endOffset": 3755, + "octets": 464, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 101, + "beginOffset": 3785, + "headersEndOffset": 3912, + "endOffset": 4404, + "octets": 492, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 113, + "beginOffset": 4434, + "headersEndOffset": 4565, + "endOffset": 5099, + "octets": 534, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 126, + "beginOffset": 5129, + "headersEndOffset": 5258, + "endOffset": 5762, + "octets": 504, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 138, + "beginOffset": 5792, + "headersEndOffset": 5941, + "endOffset": 6419, + "message": { + "lineNumber": 143, + "beginOffset": 5941, + "headersEndOffset": 6381, + "endOffset": 6419, + "body": { + "mimeType": "text/plain", + "lineNumber": 143, + "beginOffset": 5941, + "headersEndOffset": 6381, + "endOffset": 6419, + "octets": 38, + "lines": 1 + }, + "octets": 38 + }, + "octets": 478, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 157, + "beginOffset": 6449, + "headersEndOffset": 6625, + "endOffset": 8162, + "message": { + "lineNumber": 162, + "beginOffset": 6625, + "headersEndOffset": 7210, + "endOffset": 8162, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 162, + "beginOffset": 6625, + "headersEndOffset": 7210, + "endOffset": 8162, + "message": { + "lineNumber": 177, + "beginOffset": 7210, + "headersEndOffset": 7735, + "endOffset": 8162, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 177, + "beginOffset": 7210, + "headersEndOffset": 7735, + "endOffset": 8162, + "message": { + "lineNumber": 191, + "beginOffset": 7735, + "headersEndOffset": 8156, + "endOffset": 8162, + "body": { + "mimeType": "text/plain", + "lineNumber": 191, + "beginOffset": 7735, + "headersEndOffset": 8156, + "endOffset": 8162, + "octets": 6, + "lines": 1 + }, + "octets": 6 + }, + "octets": 427, + "lines": 12 + }, + "octets": 427 + }, + "octets": 952, + "lines": 26 + }, + "octets": 952 + }, + "octets": 1537, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 205, + "beginOffset": 8192, + "headersEndOffset": 8248, + "endOffset": 8301, + "octets": 53, + "lines": 1 + } + ], + "octets": 5901, + "lines": 145 + }, + "octets": 5901 + }, + { + "mboxMarkerOffset": 8333, + "lineNumber": 212, + "beginOffset": 8342, + "headersEndOffset": 8825, + "endOffset": 14761, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 212, + "beginOffset": 8342, + "headersEndOffset": 8825, + "endOffset": 14761, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 227, + "beginOffset": 8901, + "headersEndOffset": 9054, + "endOffset": 9532, + "message": { + "lineNumber": 232, + "beginOffset": 9054, + "headersEndOffset": 9493, + "endOffset": 9532, + "body": { + "mimeType": "text/plain", + "lineNumber": 232, + "beginOffset": 9054, + "headersEndOffset": 9493, + "endOffset": 9532, + "octets": 39, + "lines": 2 + }, + "octets": 39 + }, + "octets": 478, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 247, + "beginOffset": 9562, + "headersEndOffset": 9693, + "endOffset": 10157, + "octets": 464, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 259, + "beginOffset": 10187, + "headersEndOffset": 10318, + "endOffset": 10810, + "octets": 492, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 271, + "beginOffset": 10840, + "headersEndOffset": 10975, + "endOffset": 11509, + "octets": 534, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 284, + "beginOffset": 11539, + "headersEndOffset": 11672, + "endOffset": 12176, + "octets": 504, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 296, + "beginOffset": 12206, + "headersEndOffset": 12359, + "endOffset": 12836, + "message": { + "lineNumber": 301, + "beginOffset": 12359, + "headersEndOffset": 12798, + "endOffset": 12836, + "body": { + "mimeType": "text/plain", + "lineNumber": 301, + "beginOffset": 12359, + "headersEndOffset": 12798, + "endOffset": 12836, + "octets": 38, + "lines": 1 + }, + "octets": 38 + }, + "octets": 477, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 315, + "beginOffset": 12866, + "headersEndOffset": 13046, + "endOffset": 14588, + "message": { + "lineNumber": 320, + "beginOffset": 13046, + "headersEndOffset": 13634, + "endOffset": 14588, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 320, + "beginOffset": 13046, + "headersEndOffset": 13634, + "endOffset": 14588, + "message": { + "lineNumber": 335, + "beginOffset": 13634, + "headersEndOffset": 14162, + "endOffset": 14588, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 335, + "beginOffset": 13634, + "headersEndOffset": 14162, + "endOffset": 14588, + "message": { + "lineNumber": 349, + "beginOffset": 14162, + "headersEndOffset": 14582, + "endOffset": 14588, + "body": { + "mimeType": "text/plain", + "lineNumber": 349, + "beginOffset": 14162, + "headersEndOffset": 14582, + "endOffset": 14588, + "octets": 6, + "lines": 1 + }, + "octets": 6 + }, + "octets": 426, + "lines": 12 + }, + "octets": 426 + }, + "octets": 954, + "lines": 26 + }, + "octets": 954 + }, + "octets": 1542, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 363, + "beginOffset": 14618, + "headersEndOffset": 14678, + "endOffset": 14731, + "octets": 53, + "lines": 1 + } + ], + "octets": 5936, + "lines": 145 + }, + "octets": 5936 + }, + { + "mboxMarkerOffset": 14763, + "lineNumber": 370, + "beginOffset": 14796, + "headersEndOffset": 16325, + "endOffset": 23019, + "body": { + "mimeType": "multipart/related", + "lineNumber": 370, + "beginOffset": 14796, + "headersEndOffset": 16325, + "endOffset": 23019, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 398, + "beginOffset": 16372, + "headersEndOffset": 16466, + "endOffset": 21776, + "octets": 5310, + "lines": 111 + }, + { + "mimeType": "image/gif", + "lineNumber": 514, + "beginOffset": 21823, + "headersEndOffset": 22028, + "endOffset": 22970, + "octets": 942, + "lines": 13 + } + ], + "octets": 6694, + "lines": 139 + }, + "octets": 6694 + }, + { + "mboxMarkerOffset": 23021, + "lineNumber": 537, + "beginOffset": 23054, + "headersEndOffset": 24310, + "endOffset": 781880, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 537, + "beginOffset": 23054, + "headersEndOffset": 24310, + "endOffset": 781880, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 562, + "beginOffset": 24397, + "headersEndOffset": 24476, + "endOffset": 24506, + "octets": 30, + "lines": 3 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 570, + "beginOffset": 24547, + "headersEndOffset": 24641, + "endOffset": 781837, + "message": { + "lineNumber": 574, + "beginOffset": 24641, + "headersEndOffset": 25478, + "endOffset": 781837, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 574, + "beginOffset": 24641, + "headersEndOffset": 25478, + "endOffset": 781837, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 592, + "beginOffset": 25520, + "headersEndOffset": 25599, + "endOffset": 26242, + "octets": 643, + "lines": 16 + }, + { + "mimeType": "multipart/related", + "lineNumber": 613, + "beginOffset": 26284, + "headersEndOffset": 26368, + "endOffset": 781789, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 617, + "beginOffset": 26410, + "headersEndOffset": 26488, + "endOffset": 27356, + "octets": 868, + "lines": 18 + }, + { + "mimeType": "image/tiff", + "lineNumber": 640, + "beginOffset": 27398, + "headersEndOffset": 27587, + "endOffset": 781745, + "octets": 754158, + "lines": 10192 + } + ], + "octets": 755421, + "lines": 10223 + } + ], + "octets": 756359, + "lines": 10252 + }, + "octets": 756359 + }, + "octets": 757196, + "lines": 10268 + } + ], + "octets": 757570, + "lines": 10285 + }, + "octets": 757570 + }, + { + "mboxMarkerOffset": 781882, + "lineNumber": 10846, + "beginOffset": 781915, + "headersEndOffset": 783201, + "endOffset": 830478, + "body": { + "mimeType": "multipart/related", + "lineNumber": 10846, + "beginOffset": 781915, + "headersEndOffset": 783201, + "endOffset": 830478, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 10870, + "beginOffset": 783248, + "headersEndOffset": 783342, + "endOffset": 785774, + "octets": 2432, + "lines": 50 + }, + { + "mimeType": "image/gif", + "lineNumber": 10925, + "beginOffset": 785821, + "headersEndOffset": 785985, + "endOffset": 792087, + "octets": 6102, + "lines": 79 + }, + { + "mimeType": "image/gif", + "lineNumber": 11011, + "beginOffset": 792134, + "headersEndOffset": 792297, + "endOffset": 804527, + "octets": 12230, + "lines": 157 + }, + { + "mimeType": "image/gif", + "lineNumber": 11175, + "beginOffset": 804574, + "headersEndOffset": 804739, + "endOffset": 826735, + "octets": 21996, + "lines": 282 + }, + { + "mimeType": "image/gif", + "lineNumber": 11464, + "beginOffset": 826782, + "headersEndOffset": 826991, + "endOffset": 830429, + "octets": 3438, + "lines": 45 + } + ], + "octets": 47277, + "lines": 649 + }, + "octets": 47277 + }, + { + "mboxMarkerOffset": 830480, + "lineNumber": 11519, + "beginOffset": 830489, + "headersEndOffset": 831421, + "endOffset": 834102, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11519, + "beginOffset": 830489, + "headersEndOffset": 831421, + "endOffset": 834102, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 11542, + "beginOffset": 831432, + "headersEndOffset": 831463, + "endOffset": 834089, + "octets": 2626, + "lines": 96 + } + ], + "octets": 2681, + "lines": 102 + }, + "octets": 2681 + }, + { + "mboxMarkerOffset": 834104, + "lineNumber": 11644, + "beginOffset": 834137, + "headersEndOffset": 835308, + "endOffset": 837133, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 11644, + "beginOffset": 834137, + "headersEndOffset": 835308, + "endOffset": 837133, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11663, + "beginOffset": 835326, + "headersEndOffset": 835328, + "endOffset": 836249, + "octets": 921, + "lines": 20 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 11686, + "beginOffset": 836269, + "headersEndOffset": 836351, + "endOffset": 837111, + "octets": 760, + "lines": 12 + } + ], + "octets": 1825, + "lines": 41 + }, + "octets": 1825 + }, + { + "mboxMarkerOffset": 837135, + "lineNumber": 11705, + "beginOffset": 837168, + "headersEndOffset": 838329, + "endOffset": 841797, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11705, + "beginOffset": 837168, + "headersEndOffset": 838329, + "endOffset": 841797, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11728, + "beginOffset": 838513, + "headersEndOffset": 838594, + "endOffset": 839348, + "octets": 754, + "lines": 14 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 11746, + "beginOffset": 839358, + "headersEndOffset": 839541, + "endOffset": 841787, + "octets": 2246, + "lines": 31 + } + ], + "octets": 3468, + "lines": 60 + }, + "octets": 3468 + }, + { + "mboxMarkerOffset": 841799, + "lineNumber": 11785, + "beginOffset": 841832, + "headersEndOffset": 842992, + "endOffset": 848942, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11785, + "beginOffset": 841832, + "headersEndOffset": 842992, + "endOffset": 848942, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11812, + "beginOffset": 843190, + "headersEndOffset": 843271, + "endOffset": 846129, + "octets": 2858, + "lines": 47 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 11863, + "beginOffset": 846153, + "headersEndOffset": 846336, + "endOffset": 848918, + "octets": 2582, + "lines": 35 + } + ], + "octets": 5950, + "lines": 97 + }, + "octets": 5950 + }, + { + "mboxMarkerOffset": 848944, + "lineNumber": 11906, + "beginOffset": 848977, + "headersEndOffset": 849895, + "endOffset": 865868, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 11906, + "beginOffset": 848977, + "headersEndOffset": 849895, + "endOffset": 865868, + "children": [ + { + "mimeType": "image/jpeg", + "lineNumber": 11927, + "beginOffset": 849971, + "headersEndOffset": 850109, + "endOffset": 860977, + "octets": 10868, + "lines": 147 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12079, + "beginOffset": 861007, + "headersEndOffset": 861162, + "endOffset": 865836, + "octets": 4674, + "lines": 64 + } + ], + "octets": 15973, + "lines": 224 + }, + "octets": 15973 + }, + { + "mboxMarkerOffset": 865870, + "lineNumber": 12150, + "beginOffset": 865903, + "headersEndOffset": 867318, + "endOffset": 868768, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12150, + "beginOffset": 865903, + "headersEndOffset": 867318, + "endOffset": 868768, + "octets": 1450, + "lines": 20 + }, + "octets": 1450 + }, + { + "mboxMarkerOffset": 868770, + "lineNumber": 12195, + "beginOffset": 868803, + "headersEndOffset": 870180, + "endOffset": 874641, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12195, + "beginOffset": 868803, + "headersEndOffset": 870180, + "endOffset": 874641, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12221, + "beginOffset": 870227, + "headersEndOffset": 870294, + "endOffset": 870404, + "octets": 110, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12229, + "beginOffset": 870451, + "headersEndOffset": 870606, + "endOffset": 874592, + "octets": 3986, + "lines": 54 + } + ], + "octets": 4461, + "lines": 69 + }, + "octets": 4461 + }, + { + "mboxMarkerOffset": 874643, + "lineNumber": 12290, + "beginOffset": 874676, + "headersEndOffset": 875907, + "endOffset": 879457, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12290, + "beginOffset": 874676, + "headersEndOffset": 875907, + "endOffset": 879457, + "octets": 3550, + "lines": 55 + }, + "octets": 3550 + }, + { + "mboxMarkerOffset": 879459, + "lineNumber": 12368, + "beginOffset": 879492, + "headersEndOffset": 880590, + "endOffset": 881260, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12368, + "beginOffset": 879492, + "headersEndOffset": 880590, + "endOffset": 881260, + "octets": 670, + "lines": 10 + }, + "octets": 670 + }, + { + "mboxMarkerOffset": 881262, + "lineNumber": 12400, + "beginOffset": 881295, + "headersEndOffset": 882097, + "endOffset": 884952, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 12400, + "beginOffset": 881295, + "headersEndOffset": 882097, + "endOffset": 884952, + "message": { + "lineNumber": 12419, + "beginOffset": 882097, + "headersEndOffset": 883500, + "endOffset": 884952, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12419, + "beginOffset": 882097, + "headersEndOffset": 883500, + "endOffset": 884952, + "octets": 1452, + "lines": 20 + }, + "octets": 1452 + }, + "octets": 2855, + "lines": 43 + }, + "octets": 2855 + }, + { + "mboxMarkerOffset": 884954, + "lineNumber": 12464, + "beginOffset": 884987, + "headersEndOffset": 885714, + "endOffset": 888960, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 12464, + "beginOffset": 884987, + "headersEndOffset": 885714, + "endOffset": 888960, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12484, + "beginOffset": 885790, + "headersEndOffset": 885869, + "endOffset": 885885, + "octets": 16, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 12490, + "beginOffset": 885915, + "headersEndOffset": 886073, + "endOffset": 888928, + "message": { + "lineNumber": 12494, + "beginOffset": 886073, + "headersEndOffset": 887476, + "endOffset": 888928, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12494, + "beginOffset": 886073, + "headersEndOffset": 887476, + "endOffset": 888928, + "octets": 1452, + "lines": 20 + }, + "octets": 1452 + }, + "octets": 2855, + "lines": 43 + } + ], + "octets": 3246, + "lines": 58 + }, + "octets": 3246 + }, + { + "mboxMarkerOffset": 888962, + "lineNumber": 12541, + "beginOffset": 888995, + "headersEndOffset": 889676, + "endOffset": 895778, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12541, + "beginOffset": 888995, + "headersEndOffset": 889676, + "endOffset": 895778, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12560, + "beginOffset": 889780, + "headersEndOffset": 889859, + "endOffset": 889901, + "octets": 42, + "lines": 2 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12566, + "beginOffset": 889945, + "headersEndOffset": 890100, + "endOffset": 895732, + "octets": 5632, + "lines": 77 + } + ], + "octets": 6102, + "lines": 91 + }, + "octets": 6102 + }, + { + "mboxMarkerOffset": 895780, + "lineNumber": 12650, + "beginOffset": 895813, + "headersEndOffset": 896896, + "endOffset": 907272, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12650, + "beginOffset": 895813, + "headersEndOffset": 896896, + "endOffset": 907272, + "octets": 10376, + "lines": 141 + }, + "octets": 10376 + }, + { + "mboxMarkerOffset": 907274, + "lineNumber": 12813, + "beginOffset": 907307, + "headersEndOffset": 908707, + "endOffset": 911574, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12813, + "beginOffset": 907307, + "headersEndOffset": 908707, + "endOffset": 911574, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12840, + "beginOffset": 908811, + "headersEndOffset": 908890, + "endOffset": 909517, + "octets": 627, + "lines": 17 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12861, + "beginOffset": 909561, + "headersEndOffset": 909716, + "endOffset": 911528, + "octets": 1812, + "lines": 25 + } + ], + "octets": 2867, + "lines": 54 + }, + "octets": 2867 + }, + { + "mboxMarkerOffset": 911576, + "lineNumber": 12893, + "beginOffset": 911609, + "headersEndOffset": 912172, + "endOffset": 912702, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12893, + "beginOffset": 911609, + "headersEndOffset": 912172, + "endOffset": 912702, + "octets": 530, + "lines": 8 + }, + "octets": 530 + }, + { + "mboxMarkerOffset": 912704, + "lineNumber": 12917, + "beginOffset": 912737, + "headersEndOffset": 913972, + "endOffset": 916892, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12917, + "beginOffset": 912737, + "headersEndOffset": 913972, + "endOffset": 916892, + "octets": 2920, + "lines": 38 + }, + "octets": 2920 + }, + { + "mboxMarkerOffset": 916894, + "lineNumber": 12977, + "beginOffset": 916927, + "headersEndOffset": 918106, + "endOffset": 920258, + "body": { + "mimeType": "Application/x-pkcs7-mime", + "lineNumber": 12977, + "beginOffset": 916927, + "headersEndOffset": 918106, + "endOffset": 920258, + "octets": 2152, + "lines": 30 + }, + "octets": 2152 + }, + { + "mboxMarkerOffset": 920260, + "lineNumber": 13030, + "beginOffset": 920293, + "headersEndOffset": 921392, + "endOffset": 924402, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13030, + "beginOffset": 920293, + "headersEndOffset": 921392, + "endOffset": 924402, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13053, + "beginOffset": 921427, + "headersEndOffset": 921494, + "endOffset": 921494, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13058, + "beginOffset": 921529, + "headersEndOffset": 921611, + "endOffset": 924365, + "octets": 2754, + "lines": 42 + } + ], + "octets": 3010, + "lines": 53 + }, + "octets": 3010 + }, + { + "mboxMarkerOffset": 924404, + "lineNumber": 13106, + "beginOffset": 924437, + "headersEndOffset": 925493, + "endOffset": 928445, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 13106, + "beginOffset": 924437, + "headersEndOffset": 925493, + "endOffset": 928445, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13127, + "beginOffset": 925536, + "headersEndOffset": 925617, + "endOffset": 926083, + "octets": 466, + "lines": 14 + }, + { + "mimeType": "text/html", + "lineNumber": 13145, + "beginOffset": 926126, + "headersEndOffset": 926204, + "endOffset": 927041, + "octets": 837, + "lines": 27 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13176, + "beginOffset": 927084, + "headersEndOffset": 927184, + "endOffset": 928400, + "octets": 1216, + "lines": 16 + } + ], + "octets": 2952, + "lines": 72 + }, + "octets": 2952 + }, + { + "mboxMarkerOffset": 928447, + "lineNumber": 13199, + "beginOffset": 928480, + "headersEndOffset": 929576, + "endOffset": 934179, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13199, + "beginOffset": 928480, + "headersEndOffset": 929576, + "endOffset": 934179, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13222, + "beginOffset": 929621, + "headersEndOffset": 929694, + "endOffset": 929853, + "octets": 159, + "lines": 7 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13234, + "beginOffset": 929898, + "headersEndOffset": 929980, + "endOffset": 934132, + "octets": 4152, + "lines": 57 + } + ], + "octets": 4603, + "lines": 75 + }, + "octets": 4603 + }, + { + "mboxMarkerOffset": 934181, + "lineNumber": 13297, + "beginOffset": 934214, + "headersEndOffset": 935337, + "endOffset": 939460, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13297, + "beginOffset": 934214, + "headersEndOffset": 935337, + "endOffset": 939460, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13320, + "beginOffset": 935373, + "headersEndOffset": 935454, + "endOffset": 935532, + "octets": 78, + "lines": 5 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13329, + "beginOffset": 935568, + "headersEndOffset": 935650, + "endOffset": 939424, + "octets": 3774, + "lines": 58 + } + ], + "octets": 4123, + "lines": 73 + }, + "octets": 4123 + }, + { + "mboxMarkerOffset": 939462, + "lineNumber": 13392, + "beginOffset": 939495, + "headersEndOffset": 940640, + "endOffset": 941937, + "body": { + "mimeType": "multipart/report", + "lineNumber": 13392, + "beginOffset": 939495, + "headersEndOffset": 940640, + "endOffset": 941937, + "children": [ + { + "mimeType": "message/delivery-status", + "lineNumber": 13414, + "beginOffset": 940782, + "headersEndOffset": 940823, + "endOffset": 941017, + "octets": 194, + "lines": 6 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 13424, + "beginOffset": 941044, + "headersEndOffset": 941076, + "endOffset": 941908, + "message": { + "lineNumber": 13426, + "beginOffset": 941076, + "headersEndOffset": 941897, + "endOffset": 941908, + "body": { + "mimeType": "text/plain", + "lineNumber": 13426, + "beginOffset": 941076, + "headersEndOffset": 941897, + "endOffset": 941908, + "octets": 11, + "lines": 1 + }, + "octets": 11 + }, + "octets": 832, + "lines": 16 + } + ], + "octets": 1297, + "lines": 34 + }, + "octets": 1297 + }, + { + "mboxMarkerOffset": 941939, + "lineNumber": 13445, + "beginOffset": 941972, + "headersEndOffset": 943868, + "endOffset": 948839, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 13445, + "beginOffset": 941972, + "headersEndOffset": 943868, + "endOffset": 948839, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13477, + "beginOffset": 943913, + "headersEndOffset": 943994, + "endOffset": 944875, + "octets": 881, + "lines": 18 + }, + { + "mimeType": "application/vcard", + "lineNumber": 13500, + "beginOffset": 944922, + "headersEndOffset": 945088, + "endOffset": 948790, + "octets": 3702, + "lines": 61 + } + ], + "octets": 4971, + "lines": 92 + }, + "octets": 4971 + } +] \ No newline at end of file diff --git a/UnitTests/TestData/mbox/content-length.mbox.txt b/UnitTests/TestData/mbox/content-length.mbox.txt new file mode 100644 index 0000000000..e915901497 --- /dev/null +++ b/UnitTests/TestData/mbox/content-length.mbox.txt @@ -0,0 +1,13567 @@ +From - +Return-Path: <> +Received: from navstar1.mcom.com ([205.217.251.46]) by hedgehog.mcom.com + (Netscape Mail Server v1.1) with ESMTP id AAA29011 + for Sun, 21 Jul 1996 16:59:17 -0700 +To: atzet@netscape.com +From: mailusr1@navstar1.mcom.com +Reply-To: mailusr1@navstar1.mcom.com +Subject: Re: mailusr1@navstar1 3.0b6gold #1 +Date: Sun, 21 Jul 1996 17:02:55 -0800 +Message-ID: <19960722000255.AAA26598@navstar1.mcom.com> +MIME-Version: 1.0 +Content-Type: multipart/mixed;; + Boundary="===========================_ _= 1212158(26598)" +Content-Transfer-Encoding: 7bit +X-Mozilla-Status: 0011 +Content-Length: 1213 + +--===========================_ _= 1212158(26598) +Content-Type: text/plain + +default echo 1 +default echo 2 +default echo 3 +default echo 4 +default echo 5 +--===========================_ _= 1212158(26598) +Content-Type: message/rfc822 +Content-Disposition: attachment + +Received: from hedgehog.mcom.com ([205.217.251.17]) by navstar1.mcom.com + (Netscape Mail Server v2.0) with ESMTP id AAA3678 + for Sun, 21 Jul 1996 17:02:54 -0800 +Received: from cabrillo.mcom.com ([207.1.136.82]) by hedgehog.mcom.com + (Netscape Mail Server v1.1) with SMTP id AAA29001 + for Sun, 21 Jul 1996 16:59:09 -0700 +Sender: atzet@netscape.com (Michael Atzet) +Message-ID: <31F2C3F2.D47@netscape.com> +Date: Sun, 21 Jul 1996 16:57:38 -0700 +From: "Michael A. Atzet" +X-Mailer: Mozilla 3.0b6Gold (X11; U; SunOS 5.5 sun4u) +MIME-Version: 1.0 +To: mailusr1@navstar1 +Subject: mailusr1@navstar1 3.0b6gold #1 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +mailusr1@navstar1 3.0b6gold #1 +-- +Michael A. Atzet atzet@netscape.com +Netscape Communications 415.919.3274 +--===========================_ _= 1212158(26598)-- +From - +Message-ID: <31C105ED.41C62@netscape.com> +Date: Thu, 13 Jun 1996 23:25:49 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: attached image cache test (test 2: inline disposition) +Content-Type: multipart/mixed; boundary="------------167E2781446B" +X-Mozilla-Status: 0001 +Content-Length: 3748 + +This is a multi-part message in MIME format. + +--------------167E2781446B +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline +Content-Description: a message with a text/plain body + +Message-ID: <31C10324.41C62@netscape.com> +Date: Thu, 13 Jun 1996 23:13:56 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: test message one (a message with a text/plain body) +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +This is the first attached message. + + +--------------167E2781446B +Content-Type: image/gif; name="one.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="one.gif" + +R0lGODdhpAAoAPAAAP///wAAACwAAAAApAAoAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3nuhP0frCT/HpBkK8I+RmUyM2xyXgipFALtbq8AphYirb63RK73nF2zOUe +hgt2W52Ar6VMuTgsux7ZQ7P4HEfkdgf4BtRAtTdIyHijRwd52Bg5J/lXqIDXeCeZ2OlX82jp ++VlaeYq5iRrlR7qqOiM61do6a4rpmgkaOEp7m0oj+/o1SHnWZ/mq28tciYwjnJo73Rxhx2mb +DawTvWmsugiLuAucKw4Naj5ppm6bPL4LZ35t0z2P9m3YyRPfX328Joc9X876HFv07EEdYgQL +kouR0I3ENOxKJXQ2waC+M0Ph6JFxguzdx5EVHpE8eaEfypUZkz1kCZOXx5g0a9q8iTOnzp08 +e/r8CTSo0KFEix4oAAA7 +--------------167E2781446B +Content-Type: image/gif; name="two.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="two.gif" + +R0lGODdhmgAwAPAAAP///wAAACwAAAAAmgAwAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCoeBojFAPCqVQ4axCXgapNEiVEEVWg/Z7ZXr1Say0S+CDESe +w2XzNHx8e+Njeh0tZzfwy+rTnqfWQvYXtyRYJXfnN7eFh6WXByYIVxhpQkhlp9lI2bk2GfHo +F/q25omYkonY9an4Sgob6zDKSXm6uLKKWzrFO2v7u3cJ7MjKNjqy2zt76lp8mLqQLGV4nJos +sizbqtZtyjxBbYX0lxt+st0cLMuITUwLz8R43p6OXHnd+z2d3S99x5u6ZijU8Yu1SZ4mUfCg +/UN3752+fdEEHnLmzx4kRlCQyGX0cNFdoJGwOoWcBDDgvH4c/zV0gxEQTJiZZtpMVOfmTHw6 +bZ7sCTSo0KFEixo9ijSp0qVMmzp9CjWq1KlUq1qNUAAAOw== +--------------167E2781446B +Content-Type: image/gif; name="three.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="three.gif" + +R0lGODdhqAAzAPAAAP///wAAACwAAAAAqAAzAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCofEovGIrASWzMCwCY0CoEkHs3g1ZKfLw7aq+Aa7XrLWeUaD +w2ahOp1Qi9dw4pt7l7fp9TS6WbaHJzh4F0i4MBfohwAI2PgIqUgidkUV9UZW2UVVNxmHWNjJ +iOdplvUZsnm61cqqBwu5CPEZ+YWKO8ule7Iq+dvnGttX+lDbdstKbIkcCuLLewtcTJ1syHa9 +3HxtTe1dAq3Nbft6KGUc2s1rfonp/BHurT6f+c5wXJ+fiJhqEq9ebc8oYhPwTftGcN2Kf9t0 +AQRlD1uDh4oiScrWS2BDZoeahFlpFcFgNH4gSU1RwVCfn3Pu8ln8iJEiyYGYUtQstDJnMFg3 +D9FyB7Ejrpc+sWFc05KP0okalzoFxeap1F2ypkrtaTWr1q1cu3r9Cjas2LFky5o9izat2rVs +27p9Czeu3K4FAAA7 +--------------167E2781446B +Content-Type: image/gif; name="four.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="four.gif" + +R0lGODdhmgA5APAAAP///wAAACwAAAAAmgA5AAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCofEovGITAIDzGZg6IxGlYbm0ZrAKrVE7oFJBXiF42q4vAQj +nuKzuop1fsdTRd0ub3jZ+L02L2YFOOL3NCXFFwiXGGgIGPfWt8bY6BjJhQlJ+VHI9/j2Byqa +OKpXmnW6OEmqNhhSuBqrOts453kZuSqFyhjK+jtnAmsra0ZM61vMe8yMjAusMkxb25fqi8iQ +uVycCZ0iTT2tKfs8sbfN3K18Aq7u3OuKtnC+ntwsL9Je/r5uuzmfSxK3fdPY5XLHr1Kzal9M +/RvobRC+VwcJhkOkaZc/UXwTFUo8ZM9gnZF57oTaeGfRQ4wPUvp719EIxodhoFSsSSVgQJxd +4PHMqfGn0KFEixo9ijSp0qVMmzp9CjWq1KlUq1q9ijWr1q1cu3r9CtZpAQA7 +--------------167E2781446B +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline +Content-Description: a message with a text/plain body + +Message-ID: <31C10333.167E2@netscape.com> +Date: Thu, 13 Jun 1996 23:14:11 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: test message two (a message with a text/plain body) +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +This is the second attached message. + +--------------167E2781446B +Content-Type: message/rfc822 +Content-Disposition: inline +Content-Description: a message which contains a message + (which contains a message, which has a text/plain body) + +Message-ID: <31C106F6.59E22@netscape.com> +Date: Thu, 13 Jun 1996 23:30:14 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message which contains a message + (which contains a message, which has a text/plain body) +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline +Content-Description: a message which contains a message + (which has a text/plain body) + +Message-ID: <31C106E3.15FB2@netscape.com> +Date: Thu, 13 Jun 1996 23:29:55 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message which contains a message + (which has a text/plain body) +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline +Content-Description: a message with a text/plain body + +Message-ID: <31C106D2.794B2@netscape.com> +Date: Thu, 13 Jun 1996 23:29:38 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message with a text/plain body +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Foo! + +--------------167E2781446B +Content-Type: text/html +Content-Disposition: inline + +And this is some HTML + +--------------167E2781446B-- +From - +Message-ID: <31C105ED.41C6@netscape.com> +Date: Thu, 13 Jun 1996 23:25:49 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: attached image cache test (test 1: attachment disposition) +Content-Type: multipart/mixed; boundary="------------167E2781446B" +X-Mozilla-Status: 0001 +Content-Length: 3748 + +This is a multi-part message in MIME format. + +--------------167E2781446B +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment +Content-Description: a message with a text/plain body + +Message-ID: <31C10324.41C6@netscape.com> +Date: Thu, 13 Jun 1996 23:13:56 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: test message one (a message with a text/plain body) +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +This is the first attached message. + + +--------------167E2781446B +Content-Type: image/gif; name="one.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="one.gif" + +R0lGODdhpAAoAPAAAP///wAAACwAAAAApAAoAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3nuhP0frCT/HpBkK8I+RmUyM2xyXgipFALtbq8AphYirb63RK73nF2zOUe +hgt2W52Ar6VMuTgsux7ZQ7P4HEfkdgf4BtRAtTdIyHijRwd52Bg5J/lXqIDXeCeZ2OlX82jp ++VlaeYq5iRrlR7qqOiM61do6a4rpmgkaOEp7m0oj+/o1SHnWZ/mq28tciYwjnJo73Rxhx2mb +DawTvWmsugiLuAucKw4Naj5ppm6bPL4LZ35t0z2P9m3YyRPfX328Joc9X876HFv07EEdYgQL +kouR0I3ENOxKJXQ2waC+M0Ph6JFxguzdx5EVHpE8eaEfypUZkz1kCZOXx5g0a9q8iTOnzp08 +e/r8CTSo0KFEix4oAAA7 +--------------167E2781446B +Content-Type: image/gif; name="two.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="two.gif" + +R0lGODdhmgAwAPAAAP///wAAACwAAAAAmgAwAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCoeBojFAPCqVQ4axCXgapNEiVEEVWg/Z7ZXr1Say0S+CDESe +w2XzNHx8e+Njeh0tZzfwy+rTnqfWQvYXtyRYJXfnN7eFh6WXByYIVxhpQkhlp9lI2bk2GfHo +F/q25omYkonY9an4Sgob6zDKSXm6uLKKWzrFO2v7u3cJ7MjKNjqy2zt76lp8mLqQLGV4nJos +sizbqtZtyjxBbYX0lxt+st0cLMuITUwLz8R43p6OXHnd+z2d3S99x5u6ZijU8Yu1SZ4mUfCg +/UN3752+fdEEHnLmzx4kRlCQyGX0cNFdoJGwOoWcBDDgvH4c/zV0gxEQTJiZZtpMVOfmTHw6 +bZ7sCTSo0KFEixo9ijSp0qVMmzp9CjWq1KlUq1qNUAAAOw== +--------------167E2781446B +Content-Type: image/gif; name="three.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="three.gif" + +R0lGODdhqAAzAPAAAP///wAAACwAAAAAqAAzAAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCofEovGIrASWzMCwCY0CoEkHs3g1ZKfLw7aq+Aa7XrLWeUaD +w2ahOp1Qi9dw4pt7l7fp9TS6WbaHJzh4F0i4MBfohwAI2PgIqUgidkUV9UZW2UVVNxmHWNjJ +iOdplvUZsnm61cqqBwu5CPEZ+YWKO8ule7Iq+dvnGttX+lDbdstKbIkcCuLLewtcTJ1syHa9 +3HxtTe1dAq3Nbft6KGUc2s1rfonp/BHurT6f+c5wXJ+fiJhqEq9ebc8oYhPwTftGcN2Kf9t0 +AQRlD1uDh4oiScrWS2BDZoeahFlpFcFgNH4gSU1RwVCfn3Pu8ln8iJEiyYGYUtQstDJnMFg3 +D9FyB7Ejrpc+sWFc05KP0okalzoFxeap1F2ypkrtaTWr1q1cu3r9Cjas2LFky5o9izat2rVs +27p9Czeu3K4FAAA7 +--------------167E2781446B +Content-Type: image/gif; name="four.gif" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="four.gif" + +R0lGODdhmgA5APAAAP///wAAACwAAAAAmgA5AAAC/oSPqcvtD6OctNqLs968+w+G4kiW5omm +6sq27gvH8kzX9o3n+s73/g8MCofEovGITAIDzGZg6IxGlYbm0ZrAKrVE7oFJBXiF42q4vAQj +nuKzuop1fsdTRd0ub3jZ+L02L2YFOOL3NCXFFwiXGGgIGPfWt8bY6BjJhQlJ+VHI9/j2Byqa +OKpXmnW6OEmqNhhSuBqrOts453kZuSqFyhjK+jtnAmsra0ZM61vMe8yMjAusMkxb25fqi8iQ +uVycCZ0iTT2tKfs8sbfN3K18Aq7u3OuKtnC+ntwsL9Je/r5uuzmfSxK3fdPY5XLHr1Kzal9M +/RvobRC+VwcJhkOkaZc/UXwTFUo8ZM9gnZF57oTaeGfRQ4wPUvp719EIxodhoFSsSSVgQJxd +4PHMqfGn0KFEixo9ijSp0qVMmzp9CjWq1KlUq1q9ijWr1q1cu3r9CtZpAQA7 +--------------167E2781446B +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment +Content-Description: a message with a text/plain body + +Message-ID: <31C10333.167E@netscape.com> +Date: Thu, 13 Jun 1996 23:14:11 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: test message two (a message with a text/plain body) +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +This is the second attached message. + +--------------167E2781446B +Content-Type: message/rfc822 +Content-Disposition: attachment +Content-Description: a message which contains a message + (which contains a message, which has a text/plain body) + +Message-ID: <31C106F6.59E2@netscape.com> +Date: Thu, 13 Jun 1996 23:30:14 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message which contains a message + (which contains a message, which has a text/plain body) +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment +Content-Description: a message which contains a message + (which has a text/plain body) + +Message-ID: <31C106E3.15FB@netscape.com> +Date: Thu, 13 Jun 1996 23:29:55 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message which contains a message + (which has a text/plain body) +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: attachment +Content-Description: a message with a text/plain body + +Message-ID: <31C106D2.794B@netscape.com> +Date: Thu, 13 Jun 1996 23:29:38 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b5 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: a message with a text/plain body +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Foo! + +--------------167E2781446B +Content-Type: text/html +Content-Disposition: attachment + +And this is some HTML + +--------------167E2781446B-- +From - Mon Jun 3 12:50:27 1996 +Return-Path: izzy@nugget.scr.atm.com +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id JAA03193 for ; Mon, 3 Jun 1996 09:48:13 -0700 +From: izzy@nugget.scr.atm.com +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id JAA25021 for ; Mon, 3 Jun 1996 09:47:05 -0700 +Received: from nugget.scr.atm.com ([206.100.186.2]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id JAA16682 for ; Mon, 3 Jun 1996 09:47:10 -0700 (PDT) +Received: from mailman.scr.atm.com (mailman.scr.atm.com [206.100.186.54]) by nugget.scr.atm.com (8.6.12/8.6.9) with ESMTP id JAA29136 for ; Mon, 3 Jun 1996 09:51:56 -0700 +To: jwz@netscape.com +Date: Mon, 3 Jun 1996 09:42:32 -0700 +MIME-Version: 1.0 +Message-ID: <19960603164232.izzy@scr.atm.com> +References: <199605261926.AA283048804@merle.acns.nwu.edu> + <19960527225319.izzy@scr.atm.com> + <19960528160415.izzy@scr.atm.com> + <19960530190556.izzy@scr.atm.com> +In-Reply-To: <31AEE9BD.59E2@netscape.com> +Subject: RE[4]: your generated HTML +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Emissary V2.00, by Attachmate Corp. +Content-Type: multipart/related; + boundary="=_03tW34g.bO1996u.N16d000A.r06Y.42:0047e7"; + type="text/html"; + start-info="X-twg-cidlinking-V1.2" +Content-Transfer-Encoding: 7bit +X-Mozilla-Status: 0011 +Content-Length: 6555 + + +--=_03tW34g.bO1996u.N16d000A.r06Y.42:0047e7 +Content-Type: text/html; charset="ISO-8859-1" +Content-Transfer-Encoding: quoted-printable + + + RE[4]: your generated HTML + + + +
+>> >2: your fixed-width text is *larger* t= +han the default size for fixed-
+>> > width text, and since the default s= +ize of my window is 80 fixed-
+>> > width columns wide, I actually lose= + 2-3 columns off the end of each
+>> > of your lines.
+>> >
+>> This is really the receivers problem not t= +he senders.
+>
+>Total nonsense.
+>
+I do not appreciate your response here!
+If you continue with this type of response then I will not be +talking to you again.

+If you read the MIME spec (NOT THE HTML spec), then you will see that= +
+display (including line length) is the receiver's problem.
+I am talking about Email not the Web. Just because HTML is sent in a +
+mail message does not change the mail ground rules.

+If the sender choses to write lines longer than 80 columns then the <= +/TT>
+receiving client should be smart enought to display that text without +loosing anything.
+
+
+

+>By using a "standard" line length but a larger = +font, you're
+>guarenteeing that anyone with a "standard" size= +d window will lose,
+>unless they ignore your markup.= +
+>
+NO I am not. Only those people with less than capable clients will
+lose. I am tired of having to deal with broken or less featured= +
+receiving clients. You could tailor and restrict the HTML you genera= +te
+in Mail, but we will let the user have full control. If he gets in
+trouble then its his problem. The sending user will learn over time.= +

+>I'm not saying that the composer shouldn't be a= +ble to control this
+>stuff, I'm just saying that the HTML you sent i= +s ugly. Those are very
+>different statements.
+>
+I would think that ugly is a subjective point of view. You think it = +is
+ugly then fine. But that is just you and others may not think so. P= +lus
+its up to the sending user what format he choses. He could make it l= +ook
+just fine by your standards.

+>tags. The rest of it is gimickry for its own s= +ake, and it doesn't
+>come free.
+>
+I find it very hard to believe that you said this. There is a bunch<= +/TT>
+of stuff that can be done in HTML with images in MAIL that cannot be = +done
+in standard MIME. "It doesn't come free", what in the world are you<= +/TT>
+talking about.

+ >But hey, you're welcome to generate ugly HT= +ML in your product.
+>I'm sure your users will vote with their feet..= +.
+>
+Again this is totally uncalled for. I have tried to hold a conversat= +ion
+with you so that mail readers in general can handle HTML in mail. Si= +nce
+Netscape has the market share it has I believe that interoperation wi= +th
+you guys is important.

+>Nobody's telling web page authors that they can= +'t make their pages look
+>any way they like. But as yourself, when's the= + last time you saw a web
+>page that looked like your message? With fixed= +-width fonts? With some
+>fonts that were so small as to be unreadable? = +That looked really bad
+>if your window wasn't exactly the right size?
+>
+>--
+Now this is total nonsense. Who cares ? Its all about giving the se= +nding
+user all the control he can get. If he (me in this case) composes "u= +gly"
+HTML then it is his personal business. Just as long as the sending u= +ser
+has the tools he needs to construct what he wants.
+

+ +--=_03tW34g.bO1996u.N16d000A.r06Y.42:0047e7 +Content-Type: image/gif +Content-Transfer-Encoding: base64 +Content-ID: <0.19960603164233.izzy@scr.atm.com> +Content-Disposition: inline; filename="SIG.GIF" +Content-Description: The Sender's Signature + +R0lGODlhvgBDAIAAAAAAAP///yH5BAEAAAEALAAAAAC+AEMAQAL+jI+py+0Po5y02ouz3rz7D4YW +ABzleBqpyCIkycLw84azOjJrtLfLrephagngC6g4ooJBZON2lBFdpSmzWRQ2raaT0+cwrmozLhmq +hHy71OiaF8XCuQE6+F55U/FJrUfPF3jVBShoeIiYqLjI2Oj4CBlTGDYZiWj3I2KU11MJKfYx9Ya5 +gbbURzjIVueXQTfWytkqKgTa95qWpmZWtYbmBqwHfJsSZ4lzWOgZGotKeYyn3Cw5DW19jZ2tvc3d +7f0NHi5uaHy6fEzKvCh6uupNVD2UnspcHK+Kn21rUyZ8vuui3R4Kuvgg+bcLVqd58twRrOUmCz1W +xBhucUZRk6/+XgXbxLIjZZiEgl44BltY0qOOclksXnDpMCMhWBNZiZwzyFTLh1pO+ixp757GoDZV +rvwoEhDCUp46xhynYdLSqFOfQXU1TegfrSi4jptVlenVsWTLmj2LNq3atWzbun0LN67cuXTrng1b +xy5ZpyP5fsPL7czLYlD9ggCMNeVDieDgRUM8OODige/s3THc5jDNCV8gP6Y8VOYTz3klc4bYbR81 +0T9Iq4bTmuelHV5x5stsA/TIlR5Rk85n5bec20U1mhjCmyTtp1viOdW5WrdNpC/dVXISzFlwhdJb +4hoeGiNL76VPN8e8Z9j4iIxZjxp/HgypOCClYWcPk5fM7OWG+t2s2NMZv8HEWnHgFcVLdn1tR9xB +PyHFXnxXEChJexeBR0uEsK2iGnqtPTgTg9vV1gGDOcE3HUqYpOOgh4NVgyKFmvRGom3zCEdDU/7o +hdFos1XIY4GxJVOjVXZJVWRX8iXZWDM45shkQnEp9WSOQS55VCNRXjkailx+CWaYYo5JZplyFQAA +Ow== + +--=_03tW34g.bO1996u.N16d000A.r06Y.42:0047e7-- + +From - Mon Aug 18 21:13:21 1997 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Messaging Server 3.0) with SMTP id AAA8166 + for ; Mon, 18 Aug 1997 21:13:55 -0700 +Received: from ywing.netscape.com (ywing.netscape.com [207.200.73.68]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id VAA02497 for ; Mon, 18 Aug 1997 21:12:23 -0700 +Received: from cantor ([199.104.214.79]) + by ywing.netscape.com (8.8.5/8.8.5) with ESMTP id VAA24863 + for ; Mon, 18 Aug 1997 21:10:35 -0700 (PDT) +Received: from cantor (localhost [127.0.0.1]) by cantor (8.7.4/8.7.3) with SMTP id VAA01935 for ; Mon, 18 Aug 1997 21:07:23 -0700 +Sender: chrlsim@futureone.com +Message-ID: <33F91BEB.10E2A9D5@futureone.com> +Date: Mon, 18 Aug 1997 21:07:07 -0700 +From: Chuck Simmons +Organization: Organized? You jest! +X-Mailer: Mozilla 3.01 (X11; U; Linux 2.0.0 i486) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: 3.01 MIME prob message [Fwd: communicator 4.01 a conference problem] +Content-Type: multipart/mixed; boundary="------------746A59DD382995F41B0947E" +X-Mozilla-Status: 0001 +Content-Length: 747282 + +This is a multi-part message in MIME format. + +--------------746A59DD382995F41B0947E +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +My problem message. + +Chuck + +--------------746A59DD382995F41B0947E +Content-Type: message/rfc822 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline + +Received: from gezer1.gezernet.co.il (gezer1.gezernet.co.il [192.116.212.2]) by future.futureone.com (8.8.2/8.8.0) with ESMTP id OAA19067 for ; Mon, 18 Aug 1997 14:50:46 -0700 (MST) +Received: from default (gezer68.gezernet.co.il [192.116.212.65]) + by gezer1.gezernet.co.il (Gezernet/8.8.5) with ESMTP id AAA16299 + for ; Tue, 19 Aug 1997 00:35:52 +0300 +Message-ID: <33F8C032.C5DC0CA2@gezernet.co.il> +Date: Tue, 19 Aug 1997 00:35:46 +0300 +From: NIRI ELLERT +Reply-To: nirie3@gezernet.co.il +Organization: GEZERNET +X-Mailer: Mozilla 4.01 [en] (Win95; I) +MIME-Version: 1.0 +To: chrlsim@futureone.com +Subject: communicator 4.01 a conference problem +X-Priority: 3 (Normal) +Content-Type: multipart/alternative; boundary="------------D866708591E89309695535AC" + + +--------------D866708591E89309695535AC +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Hello + +My name is Barry and I live in Israel . +I am a system programmer of M.f. IBM at a governmental company/ +I have privately interest in Internet. +I have recently downloaded the communicator and I like it. +I have a problem thougth with the Conference I start to recieve a call +when there is a Buzz +and a message appears that a person wishes to talk to me I hit accept +but nothing happens and i can not hear the other side. +I check the mic and it works and while talking i can see the bar fills +in with green amber and red . +I hope you can advice me what to do to make it work + +best wishes + Barry [Image] + +--------------D866708591E89309695535AC +Content-Type: multipart/related; boundary="------------A9E4A76F8F8B49A8F9408311" + + +--------------A9E4A76F8F8B49A8F9408311 +Content-Type: text/html; charset=us-ascii +Content-Transfer-Encoding: 7bit + + +Hello + +

My name is Barry and I live in Israel . +
I am a system programmer of M.f. IBM at a governmental company/ +
I have privately interest in Internet. +
I have recently downloaded the communicator and I like it. +
I have a problem thougth with the Conference I start to recieve a call +when there is a Buzz +
and a message appears that a person  wishes to talk to me I hit +accept but nothing happens and i can not hear the other side. +
I check the mic and it works and while talking i  can see the +bar fills in with green amber and red . +
I hope you can advice me what to do to make it work + +

best wishes +
                   +Barry  + +--------------A9E4A76F8F8B49A8F9408311 +Content-Type: image/tiff +Content-ID: +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="C:¥win95¥TEMP¥nsmailRJ.tiff" + +SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAnQEAAAEBBAABAAAAvAEAAAIBAwADAAAA +wgAAAAMBAwABAAAAAQAAAAYBAwABAAAAAgAAABEBBAABAAAAyAAAABUBAwABAAAAAwAAABYB +BAABAAAAvAEAABcBBAABAAAA5GQIABoBBQABAAAArGUIABsBBQABAAAAtGUIABwBAwABAAAA +AQAAACgBAwABAAAAAgAAAD0BAwABAAAAAQAAAAAAAAAIAAgACAD///////////////////// +////////////////////////////////////7e7Azun1r931jOT1zuX9s+X9xfH3fe7qr939 +pPLrXurqV+f9p+f70PD2nPL2uun/bvD2jeT1oN38guD2n+bqO9vqcuz3WODrg+b4hej/3uD8 +s0rjksnYWtehb9eorMPwY7bEVKZVgsH5PcXpdIKOcKNff6uIXcy2o8mXmZfiw5t3h9HYkK6Y +lKh1sMejQ7GqtJTm17Z9nGbFVoq9W3Z7ToiKYsmebXnGTYmeQ8y+g5O+aoJyP4tKgH/e3Xej +b6tqcZmFrTphoJfBlNBluJOiT4lkUZDfU6SxL3SsTn5nZbqgeZuFeHaXYXZxkoN/eYHJhIGX +bLB5TYiFuM1zw5ukpHWy1LJMn2+6HH5UmFS3csGDTJh7ba6cLnecXHGopsa3dn2dKpF4P22V +oYE0WYF2madanct7xYGoP5yxubRfeGKyX3JYppJxYFFWgbmDec2nMmW4IWSYSpWnnpmdVo58 +XFeHRU2R35xyTnqZK51hamiH7ISps4ChTZ2zbJWtE4ScX3ibOXqhXV9vrqCGP4ibL3NkmXnT +qnx8b6WSoIdqWY/YyXaDM1yI3K6WcGyqiYykKqCusZ29aHLCzbupgKJkT5VXenZ4bHFvKIXA +8dKCOMCEl8WIK7eZxbl7Q4xyi7ttVLebmGWLfY6BbWYyQ5egx4WaT3C3sYqihJ6V4bG3QWKp +zIZunHC8YzycJ5pUjKmPRMqipFOG4bhGjIuCiYpBdl6av5U8e51/uaGOqIJ3znZyqqCGaFjD +xHLKt8mCg2Y8lbiuvGTHnI+sVuS5q7hguRyj2IhhsnFez1qFrn22QrzNepe/ZLnSi3trTW5e +kMGBbauVrVC+Xcx+S9GTPI9LKhmiTbyEvc/bnsDDz2ZzqoWzEG9nw5ZVJOc5WU7at5530UAy +xS2lmBWEzuyGm2HYp1KB7GM740Jm6k7me2Jnt5JYRZDH83HUY9G27FBzLaui6LhGnbiAnp1u +UHzQ57eBgtn40KwOQQ+SFSfUwl8O87v8bsPiWh7Pf3/MPpnrOK/9PpcWbFntl9mpspoMbKkc +duNTn8a6rfHGgNW4lODfR9PZw01gOmp1W8TryX4bwcFVzOIborjSOXvlJcKGWo/hvNlVTpzC +J6opr+XWXpfpva2ZpE/KrLSiX2+s2saxTWbqyZi8W6Bogox+aHOyyL3NhY1x0qm7y3dsl3XV +gYAOzV3ErUfe5h98jmcblW5mqSLK0LmFeGNZzqPBtIqtizBDnHjygGy3cyx0dsq9le2ldWQp +ql/qpmyIMs5UgYfxmLj93MJlZuTYhdf5yF6QbLblzJiYXnbMnrfJqrqNXK+vlEOd0J/rcYVU +urzKiaC87nGval6YlYOHhKXKXqiqglevlWPUhZPRUnKCc6bHSqx8PFdpOpGfqJvXzmLjkW9O +x4aGlV/dnKOjbKrcicq5ZKt3TrJZWlF9X4jUeUN/wFgUTXGyZsLZVpDJ34i6UJGYj6h/q7XI +K1hOf0NsM6tzMKJWMX+Pa719DYrdZk/QzL6wbml/X5ytiHyTfXKzbqietq3WUrakg9R6oYn1 +QOyywZH5WMbvhOu7SOvzxa36gPbdrO39bv63e/Tetur/cf7d29rh2eDo2+Hi2OLv2+n12/D5 +2+7t2uXz2+z22+nm2+Ps2+Lq2+fq2+Ly2u7t2urw2e3+2/Pz2+7y2+fu2+ft2ubl2+Lv1+vs +0ebr2+Tt2eTd19VmVFNDSkBHQUFESD9IRz5ASj9HREBDRj1DRj5CSj1CSz5ARzxDSzxDRz5H +Pz9ARz9IQjpCRThESj07RzpERz47SjVCRDw7SzpIQz4/RjpBRz1BQjhDRDtFSTVCSEBFRTlF +SjpCRjRERztERjtCTz9BRTtCRD1DQzpJRT8/Rjw+RjxBSDZDRTg+RzlBSDk8RTpGRT1BQThD +SD4/RzpDSTtCRTdDQjw/Qjw+RDY/RDhERDhAQzdDRztBRDpCRjpARDhFQz49RDZFQzs7QjhE +RD48RjZGRTs8RDdHRjw1RTZHQTs/RD1FQjs9RTg9QzxBRTk/QTY/RTo+RTw/QzY8QDhDQjY7 +Rjw8QTtCQUA+SDk+Qj44RTE+Rz9ASDtCQ0E9Qzc7R0E9Rzk9Rzo9Rjo4RDo/Pzg5Qjg/QD0+ +Rzw9RDw7PjpBQjs+Qzw7RTxBRUI+RjtCRzw6QzQ+RD08QjxEREA6QD49RzxBRDtARTw9QkA7 +Qjc/Qj48QjxAQz9BQjpDRj09SD5ESUE7Qz47Qjw8RTk6QDo8Pz88QTQ6SD48QDc4QTo6RTs+ +Qj5ARjs5QDU+Pz03QzU6Qj04QjQ+Qzw6SDY+Pz02Rjk8PTw1RTZCQz07STs9Qz46RDc9RDpA +RDs4Qz08RTw+RTw/Rj45RDs1RTQ9QTw1QzhBRUM8RThBQj87RjxAQT84RDQ+REA7Pzg9Q0E7 +Rzc9REA+REA/QjQ4Pzg+Pz46Rjw+RT48RT5BRTw+Rjo/QT0/RkJDRkE6SjdEQ0E3RDc/PTs1 +PTQ9Qzg0PDU5QTszQjxJUUVOT0hSV0ZUUUtVVkJUWEZSWERSVUdWVUhVVUdUWE1UWENVUkZT +WkZcXFZVU0dZVk5bVUFWWE9bWUNZWUxhV0xaW0laW0dSW0lbYU1YXEdaXE1aYkJZYU1fW0xZ +YEtaW0tgWktjYkZWXEVnYE1aXUxbYklYXkxfZEtaYUhfXURPTDtYSzdJS0NielCBdmJ6e1t7 +el91eVt2dGF9elx+eF17c11/eGV7eVp9emF7fl58elqAe2F2dlx3fmB2eFh2el17cV55dl52 +cl5wdFuBeWBwdld0dVpxdVd1eFtxdVZ1c1xxdVd0cVt0dVR9dFxzd1pxc11zclpwcFhxdFdx +cVdxcFN3bVlxb1RwalZscFR3bltta1JvalVoa1Bxa1Vma0x0b1ZqbE5salZqaU1ia05laE9l +Z0xiaU9kZ09dWEpARkQ9RDw6Sj4+Rzo/SDs3RTtBSUE6QjtDRjw5QjtEQD84STpEREE4RDo9 +SEA9RTsyRjk4Qj5ARzdCQkA9SD0/RD07Qjs7SDg3Qjo/QTg7Rjo3SDg9SEE6QDg7R0M4Qjg5 +R0A6RTk6QUE4QDo6RTs+RTg1RTo3RT0zRTZAQEE4RTo/RT06QjxARz09RT4+Qjw+SDw8SD1A +RD9BRz5NU0bk2aH62eqPaOH71fL73PL64fP14u/14ur04+7p4uf24ufu4+fx4er14u/14fDs +4+fw4ujw4uv13+zr4uni4uDc49ri49zi4ePh4dvk4uD8///7//ny8+/g897h7Nzj8931/PP1 +++bz/e3u/eX1//js9/D+/vz9//Pm9+Hw9+fl8eX99vzx8ubm7ef19PH9/v379fHx+vL9/vT2 +9/H++Orb39VhT09GRkFIRTxDPzxAQztIQj09RzpKR0FDRTpEPT47RDhIOj1FQThBPTs/OztE +Pj5FPz5BQj5IPjw/Oz1DPz9EPzpCPz5HQTY8PjZEOTs/QTdJPjtCQzRKPz88PzVJQD1BRDpD +Qjs6PzU/PjdDQDdCPzZBOjhBPTc9PTc+QjpCQTk4PDhEPzo9QDw8Pzk/PTk8PThAPDo5PTFA +PTk7PzFEPTc8PzZBPzs2NjRAPjU7QDY+PDg+PjQ+PD07PDk9OzhBPTw9PTg7PDdCPjs/PTdC +Pjs5OTY3QDo5ODZEOjsyQDZDPzo2PDRCOzk3PTZHPTk0QTVCPjg2OzlDODpAODo+PDg8Pzc3 +OzQ5PTk/Pjk8PTQ4Ozk/OzQ+Pzs8PDY9Pjs9QjRBOUA4OS4+Oz85PjE5QTs6OTQ7PTw8PDo9 +OjdBPzs9Pzo9Oj45PTY8ODk6PDk+PDg5Ozg7PDg4PTk+PTs9QTo7Ojg8QDs5QTdAPEA6PDpB +Pjg8PD1CQT8/PDs7Pjg+QTs6RDZAPTk6PDo+ODszPDU+OD41Pjc7PDY1PjlAPDg1Pzk5Pzk1 +Oz02OzU4PT03PjU7Ozo7PDc5PDk6QTc3PTU8PT81PDU8QD83PjVAPkU4QTQ9PTw3QDg7Oj03 +Pjg6Qz05PTo7PTs5PDg7PDk7ODg3QTs8Oj05PTo6Pz5BPzw4QD0/QEM3PTg+QD42QTc+PTs0 +PjdAPUQ0QjY8PDo2RDM7PUA3QjY+QUA4OjU+RD45Qz46Qjs7Qjw0Pz4vPzc7PjkzPDk3PTct +RDU8PDszPDdBRD1HUUJTTkdJTT1RS0VTUUlTTUtQUUZdT0ZRUkVNWEdZTUZTUUVUVE1UUkZU +VE5XVkZZU01cU0ZXU0laT0hXU0hdVU1ZVUBZVkhXVklYWFBbWUVdWU1XWEhaV09gUEdXV05b +WUhZVEVlYEdXVkRVXVBcWkVaWE1iWUVcVkdaWkZVTUlZRTtMRTpPSDtmclGFfF6Bd2B+emN5 +fGV5elx9eGJ4d2OBe2N4cFp/cFp9eV59c2B2e1l8dlp8dFx8dFt4dFl1dWB2dF91dFhzcVx6 +dWB2cVxzclRzcVZ6cGBvb1d2cFtxb1lycVh0b1Zzb1Vtb1Ryc1hvalJ3cFdtcldvbFhscVRv +a1htaU1zbFJsbFRsZ1R1bFJsaVJqalVtZ1Rkak1rZFRsZVFtZlNkaU5pZ1NhZkxqZ05ha0tm +Yk9lYUdcVUs7Pjk8PDk3PjM6Pjg7Pj04QDg9PTo4Pjg7PT43OjY8Pjc9OTk2Pzc+PDsxPzY+ +PTowPDk/PjsyPDdCPjs1OjdAPjw0PTs8QTUzPjk3Pjk9Pzs6PTk6PT04PD0+Pzk3PjQ8ODg4 +PDk4OzY5Pzo6ODI+PUAxPTNAPj80PTM5QD49PThBP0A+PT07PT5AQDk2PzhAPjo1RDdBREA6 +QzxFUETY8Zv6//T///////////76//X+//3+//n+//f+//n///X8//n8//X9//n+//j+//70 +/O/5/fL1//Lx/fDm+uTl+Onf89jp8+Ti8d7r7+Ln/+ny/vfy9/L+/fv9/f37+/Hz//n8//Ty ++/Tz/O76//L1/+7t++z8//f9//7////z//vv//L3/fX5/+/6//n5//X59Pn7//D9//r//fXm +5OPl5NhiT01ERD5HQUBEQT9IRDxCREBCRkFBRj9DRD1CRTxHRDwyPjpERD03SDhEPjw8PThC +PT9AQzhFQT09RTpCQz89QDxHRDtFSD85QjxBQDk8QDw+Oz5APTpGRDxBQkI/QD1DPz46RjVH +QDw7PjZHQzo+PzpGQT0+RDlHPj5CQjo9Pj1AQjhAPDo8PTlDPjhBPjc+Pjk7Ojg9PTc7Pjk/ +QDw5QDZFPjo2QTc7Ojs6QDZEQT4zPTVCPzo1PTlDQjo2OjhDQzs/Pzg+PTg/Pjw9QjZAQzw9 +QTtBOzk5PzxBOzc+Qzo8QTQ7PTw3PjE8PDw2OTRCQT43QDE/PUA9PTs5Pj47PDQ4QTo8Pjk5 +OzlEPj87Pzc8QDc2OzM7PDg1Pzg5Pz47QTg6PDo2Pjo6OTc9Oz85PzY7Ojs3OTVCQDc8PkE7 +Ozg4Ojk3Pjk9Ozk2PzE8Pzw5QTs+PT0zPTU9Oz47PkFGPjw2PTc+Pjo2QTw+Pjo5RDs5QjxB +SUBBQEE9PT89PjY6QDw+PDs3Pjk6Pzk0Qjg5QDk2Ozc6QTk3PDk4Ozk0OjI7PTk3OjQ9PDwx +PTY4Ozg2Pjg4PjU3OTQ4PTU4Ozg6OD05Ozg5PDo3Qjk7Pj01QDM6Pjw2PTg6Pz0xPzU7PUEx +PTI6PkI2PTg8Pj41QDE2QEE2PjU3REA6Pjg4QDk4P0E1PDc2QDs6Qjs0PTc5QD00Qzk3Pj47 +QDc/Pz0yQThBQkA3QzU8PD4wQzdBPj04PTw5Qjw2PTs3Pjw8P0I3Ozk2O0A1PDQ1NjgtQTg4 +OzgxQTU6RDhPTUVMTkJPS0pPVD5UVUpPU0JVUkhSTENUVE5XUEVWWE1WWUdTV0ZbVExPU0tZ +VUxYVUFWVU5VWkdZWExYWkNSVEtVWUVXVEtfWUpPVExfWklaWU9gW0hVV1NhVktWWlFhXEpX +WlJaUE1kWEpeWEZiXE1aV0heW05bV0VaW0tbVkZOQkBTSTtJSUFsdFJ9dmF7dVx/dmN6dWJ8 +d1t1d2F7dl17d114dmF1cl15eFtxdV15dVx1dVp6cmBydFx2c19wdFp7dGN0cFd5dF5xb1l3 +dVpycFd2cFp5cFtxdFl0cVZzc1lwc1xublZ1c1p3cV1tbld1bltycVB1cFtublVua1hmb1Jv +aFpqaVBxaFltbFBua1lsaVZrak5oak9rZ1JtalBoa1VjZlNoaU9hZk1pZU9jY0tmZ1FhaE1q +ZFJTUkZEQT00Pzs/PzkzPTk/PT41Pzs6Pzg1ODg0OTc8PTozOzg5Ozs3PTc2PTk2RTk+QTg3 +Pj84PDg4Pjs6PTY4Pz82PzUzPz04Pzg1PD84ODc1Pj8zQTgzPzg5Pzs1PDo1PT0yPTQ9Pzk1 +QDc7Oj00Pjg3Pj44RTw2QDw4QDtDPUE7QT07QD44QD86SD09PD43Qz86QDw7RDxCS0A+QEJD +U0bu9qz4//L9//j9//n///z////////9//z9//f5//X2/e35//L6//Lz/vX5//D1//T6//P5 +/Pnq+eT8//nx7fXk9uHj89vm9uvm9eTd5try9uPg9dz4/vny/+/5//L5//P18+bm9ODx/Pr7 +9+3o9+Hz/uv09ujo8eXz/u79//f0/u30/vD5//ry9Oz9/vLt8ejx6uf3/fX+/+7u++r9//3y +5+FlUkVESz9CRj9BQzxBSDk/RUFDQjhHRDs8RTxEQj9CRzVEPzg/QDk9QztCQTpCQDdERDs/ +QjZBQjs9QDc/RzpERDRDRDtFPzlBPDxEPz07QzhJRT9BRjhKQz08QjpGRz06QDdFQTtBRDhC +QTdAQTZGRDtAQTk/Qzk+QTlERj9LQTk9QzlDRDdBSDU8PjZBQDlBQTdEQDo3QTRGQTw8QzVI +Qzw8QTZHOjk8QDdEQjw7QjVFQzo2Pjg8PzU8QDg4QDU+Ojs9Pzg8QjVDPTg7PTY6Ozk4PTQ/ +QDk4QjNAPjk3QTZFQD44Qjc/Pzo8QDVCPzk7PjU/QDg8Pzg+QTo7QDk/QTc9PDk4QDg/Pzs8 +QDs9PDg3QDg/PzQ/Ojk9OTg8PD1EOjM8QDw8PDI8PT05OjE7QD05QTM5QTw6Ozc6QDhANzc8 +QThDPzw1RjVDPkc4Pzc+OT47Qj49PTc7Pz49QDw/PEA5QTQ/Pjo6QzpCQTo/RDtBQDk8QTg7 +QTY3PTw6PDc6PDk3QDg6Ozg3RjQ7Pzo0QTQ4PjcyOzA4PjM4PTQ4PTQ3PDs5Pi82PDw4PzQ4 +QDg4Ozc2PDg6Pzk0QDQ9Ojk3PTc6Ozo0PTc5PDs0QDc7QDo4PDg8Pj81PzQ4Pjw3QDc7QDU1 +RTo5Qjg4QTk8QTxAQDg1QTs/RTo7RDs5Qzg/Qj03QzU9Rj47RDs8PT84Pzc/Pz04QztEQT86 +Qjc/Qj08QjU+Qjw3QjQ7QD04PTc5Pzk3Qjg+Qjs2PTo5QzszQDQ4PDUzODE2PS8xPjk5QjY0 +QDc9QzlET0BRUU1MTj9UVkxMVEZVUUhTUUNbU0ZXUkdTWUVWVExXWENZW0tfVEZXVkZYV0FV +WUddWUdTV0tZVUxXWUJhWU9VWEZdU1hXWEFYWlBTWUlXWU1bW0RbV09eXEpeW0FhYFBcV0Vh +WEhZXEVaXEpZW0RZWU1dW0ZaVkpfYktaU0NQUDpRSD1RSzplcE9/eFx8fV9+eVx9el9/dF15 +el91fV1/cmR5fWGBc2F1dVh+dl99dViAdlp1e1d4dV55dVt3c110dFt8eVx9d1l6dFt5dV91 +clVtdld1clV0cFpyclptdVZybld0b1N4cFlwcFdzbl1vblZyclpscldua1hpaVJrcFhubVl2 +bFRqbVJsaVVsb1ppZ1NncFJrZVBka05qZU9jaU1raFFkZk5rZ1RkZ1FraFNiZlBhZlJhZktd +U0k6QjQ6QTk2PjRAQD86QkE4PjdAPTk4Pz06Pzo+Pzg2PTg8QTg0PTQ6Pjo3PTY+Pjk1PjRD +QjozQDY8RDkvQzg8PTYyPzQ8QTg1Qjg1Pzo2QTk6QjQ2Pjc1Pjg6Pzg3Pjg4PTg4QTs4Ozk3 +RTo1QjU3Qjs5PjM/Oz43PzA6QD49QDQ8SEA7RDg4RUA9Qjc7Qj1AREA3RzpERUA+QEFLU0Xn ++6X+///+//vz//L9//T///z////////////8///1/ej6//T////////6/Prt+Ovy/ubs+Ofx +/un1/+/o9eXn+uXl+tzu+ejc89fk893///X8/O7z/e3l7+Pl7t/o+ejw/+3+//r1/+/0//Hw +/uz9//3////////1+/H7/fT+//74/+/k/974//n/7vH6/Pf/9/ns/+Lo8uX39eze7djo7dRb +TkVMRUFFRThBP0Q/RDhJP0I8QztCPz05RDVGQT5APjlAQjhBPzk2RTdCQzpJQTxAPzxCPzZC +PzhAQDw/QDk8Qjk7QTZDPj8/QTVHPjs5QzRJQT09OzNNRz1IQTZIPj0+QTc/QjdAPTY+PzFA +QTo+Pj5HPztEPDlAPTVFQTw7PzhAQTM9QDJJQD08QDREQjs6PTdJQDw2PzdEPDg7QDdEPzlI +QDs9PTg7PTc6PzVAPDg6PjZCOzo9PTY7PDU7Ozc+QTY/Ozg9Pjg9PD44Ojc/PD4+PzM6PT85 +PS05QD4+QDQ7PTY+Ozc8Qjc+PDtAQjU9Pjs5PzQ/PDk2OzU5PDU0PDM7PDc6Ozw8OTlBQzs2 +PTU7Ozc6PTdCQTk6PzdCPTU7Ozo2OzVBOjpBOjtBPzw1PTE/Ojs2RThBPTg4OjpAODQ7Ozk/ +QDY3Pzs7PTg5QDZBPTk8QD09QDQ+Pzo/PDU7PDg+QTY+QDo/PjxAQTk/PT03PzQ/Ozk4QDE9 +Ozg4PjFAOT04Pjg8PjgyPjY7Pjg4OzxCPzs3PjY8OTw6PDY5Ojk8OzY5OzY4ODU6PTo3OTQ1 +OzY5QDU9OjsyQC84Ojo4Pjc+OjwzPTM8Pz41PjU6Oz02PTY6QD44QTs3OTM4Pzw4Ojg1PTo3 +Ozg6PDk8Pzo8Qz09Pzs5QDlAPzo4Qjs+PkQ2PjM8P0I4PzpCPzw3QDVAPjs5QD1AQj09Pzw4 +Pjg4QTk6Qzk7PTw4RDc5Ozk6QDo4Ozc9Pzk2QTc3PTk2PTI9PTswPTU3PzsxNjE5Pzo2PDc8 +RDlLSj5LTEZTTkZPUEVTSUVOTDxVUERRT0FZVUhYWEdVT0tYUEVQVUNYVUpSWEtfWkhXU0Zc +WEhTVExfWEpXVUVaVU5aWEZZXEhZVkVWXkphWFJWUUVcVU1ZWUxeWklYWUVeX0xcWkFiXEpa +WUdZWE1ZVUheV05bX0daW0VfW0laSkJNRTpVSjpLSDl7dlp2el2Cflp7fFx8eFt1dF5+dGB5 +eFh8d152eFh/dmB7d2F/c2F2dFqBeFh+eFd2d194cVl2d1x1c1t8c1h1dl18c2BzeFt0dVl2 +clN1cllza1R6blxrcFN6c15vcVZ1bGBvcFZ3bVlyblJqb1V3b1RqblV0bVdtbVNvbFJrak9v +blJvaVFsaVJxa1VsalBxZlNpaVBoalZlaE9rZk5haFBtZlJfY05sZExkZFFtaU5kY05ZTUM9 +Qjw5PTs7PTk7PjU4OTc0QDg6Qzc6Pjo0Pjc4PDs4Ojc7Oz88PjQ4PEA0PjUzPUA2PDQ2PDc7 +OzU6Pzc/PjszOzY7PDY3QTY3NjczPDU2OTo7PTc5Ojo5Pjo6QTw4PTw2QDY5Pjg9PDg6RD06 +Pzo7QTs9QD41QzJAQT44PDU/QTw0PDQ7Qzs4Pjg9QUQ2RzY8RD41RDo/RDo7SEFIVUTo9Kf+ +//b///////////////3////////////6//v9//X////9//f3//H3/PD5/fT8//vz9u7x/+r4 ++/Do9+Xp+ubW7M7j7dve79nb6tzt++zl8+Pw+/P2/vj0+fPy9ers+u7v+uXi89/r9uft9+fs +9+Xx/uj1//j5//Tw/ezq/fD1/+/z9e/4//D6//P5//H39/L+//b+//v9//f1+/Hn2dJkT0hM +RUY9Oz1JRz8+RDdFRkA/RjZFPkFDRTtEQERIQjVEQzw9QTREQjxCQD5EQDs/PjY/QDtCQj5C +QTc/PjhEPTdBQDc/Pjg+PDpFQDo4QTVHO0E8PTdJPj46RDpKPzw6RDlJQzk7Ozc+PzQ5PTc6 +PzVBPz5AQThCPjg7PjhDQTo+QDg9PzM/Qjc+QDZBPDpCOjU+PjxDQTRAPj0+PjU+PDw7PDc9 +QTU9PDU4Pzg8QDQ6PDE+ODk5Pjc9OzoyPjE+Pjs7PDU7PTk7PDc4Pjk9OjE5PDI3PjU2QjU7 +QDc5QDRAODk0Ojo5OzU6OjU4OzQ6PTw2PjU7PTs3PTY8OTg1Pzg7ODo3QDc3OTU9PTY8Nzc6 +QDM6PTU3PTVAOTQ4PDk8NzY4OzU7PTI8QDo5Pjc4ODU6OTQ0Pzc8ODo0QzRAQDw6PzQ+PTw6 +PzZDPjw4OTtBOjw0PzQ+Pjg+PzlEPT89PDs8PTk8Pj1BPzw7Pzw3OzY6PDE6ODo6Pjc4Ozo6 +OzE5PTs6PDM7Pjc3PTQ6PkA2PTA4Ozw3QDI4Oz00OzE1PTY4OzQ0PDU6OzU5PDc7PTYyPTU2 +OTgyPTU5OzI6QDc1PjE5OzUvPjc4QDo1PTg9PTwyPTU5PzoxPTY1QDU3OTkzPjQ4OzoyQDc7 +PTg0Qjc3PEA8PTs8OT07QDo6QDk6QTw4Qjg7QUI4Pzg9P0E6PDQ8Pz81Pzc3PT1AOzk6PDk1 +Pjg2Qjs7Qzc2PzQ7Pj0zQTQ5Ojk2PTc8Ozw6Pjg8OTw1PTMwOTU0OjUyPT0+PTouOzc6PzdI +T0NPTkFMTD1SUj5UUUVMTUNRTEVQUkJVU0VWUzxaVEZSVUJZVUpSWEVYVExRUz9aVU1TVT1Z +WEhWWUdhV0xZVE9VU0BXVUhZVkdXU0JXV0RZVkNbWEVWW0VfWkpVWklaWEdYW0ZjU1BXVEFg +VVBWWEleVkxYV0ZbWEpZYEdZTUFKQDlPRDtJSztsc1x2e118cl58eF6BeWB6clp+eF54clx9 +d2N1dFh7eml1dlp9c197eVd2cWN3eVp9dF91c1x7c112dlp6dFhzb1h5clt5c1Zzclh3cFt0 +cllyb1x1a1dxcVZ5bFltcFR2cFZublN1b1pxb190blZucFhwbVVya1dwbVJubVlxaVFya1Rq +aU1vaE9rZlNmZ1Zna1VkaVFnZk5nZU5sZ1RhZ05oaFBhYU9hZFBoaUxjZlJjZlFWT0g8Pz0z +PTk6Qjw0Pjk1Ozo2QDA8PTc1PDA8OzYxOjU6PjkyPDM3PTw7QTw5OzozPjg4PT43PTczQDox +OTQ5PDw5OzQ6PTs2OTY8NTgsOjY8OTsxPDc8PDcuPDc9PTYzOzo9Qjc7PzU/QTo4PDo8Oz07 +Pzw6QDs3Pzw8RDg7Pz06RTw4PzpAQD48RTU/REk8RDlBPD44STxDQ0Q6Rj1NU0nn+Kb9//H/ +//v5//f2/+79///////1/u/1/+/7//3+//D+//z6//f///z////8//z9/+76//b2//Lx+e7y +/Ov0+ffg89bm8+Lg8dbb5Nbv9ez59/Dc7tXp+u3t/vD+/vz19/P3+fX///7///////3x/e3+ +/fvz9ufz/u38//vv+ejz+/H8//j2+enq+ejr9Onn8eH49+3y/+zy9e/v9+Xm59phTlBJR0JE +QT8/RTxERjtDRjlDQztERjdCQzxERTJCPztFQzdEQjpKQzs/QjhJQkE3PDpEQzo6QzhEPTY2 +PzVIQzg/QTZCQzZCPTg7OzZDPTlCPzREPjlHQjpDQjxEQTxCRDc+OzM/PjU9PzhCQDpDQjk8 +PTJBPzc8QjU+Pjo/QTZBPjZCQTc8QThBPjg9PzhEPj46PjZBPjY/QTRGPjo8PTZCPTk3PTU8 +PTc6PzY7PTU9PjY+Ojg+PDk5PTZDOTc4OzU3OzY8OzQ3OzU4Ozg6OjY9QDc1PTI8OTs0PjU6 +PDk1Oy88OTUxOzU6OTg1OjQ6OjU5PTQ8PjM1Ozc3PjQ8QTU6Ozc7PTE6PDhBQTU7Ojc1Ozc5 +Njk4PDM8PDU2OjA+PTs1PDRBPDg7PTc/PzozPzk8OzgzOzRCPDU8PTQ1PTU6PTc7QTo9PDU6 +PTY+Pjk8PDg7PzQ/Qjs6PTRAQz01PjFAPDo5PjI/PT00OjA7Ozs6PDA+QDo8QTk3PTA8QDc1 +PTo5PTcyPjc5PDU3PDU3QDU3PTc2PTE5OzU3PTJAPjk5PTVAPD03PDM/QDg2NzM7Pzk2RTc2 +OzE2Pjo3PjU4Oz04OTQ8PTs2PDo8QTk2QTM3PDc2QTQ6QDcyPTg3PzU9Pjg8PTU2Qjo1OjI2 +Ojc3PjU3Pjk6PzY6Pjk5QTc1QDk2Ozw4QDY7QTc1QjQ7Pjw4Qzc0QDk3OjA3PT0yPzI3PTg2 +QDQ1Pz0+Ozc4PTg5PzY1Qjs5OjQ2PDY4PDM7PDg1PzQ4PDc0Oy42PTw2PDQzOjM1QjZJTEVO +ST5OUUpLUUBST0NMTkBQU0dSVD1VVkdQUEhXVUFXVENWU0ZXUEJeVUdSVkZTV0xaW0peV0tW +WkhaVEpZWUlbWEtWV0VfVUhPVEdgWExVVUdbV01bWkxNUEtdXElbWEVaWkZaXkJYU0lbXUVV +XkdaWURZXklhW0tcXENgSEJDRzdaST5DRDZvcF18e1d8dlx3e1t9elyAcll6elp7clx5fFt6 +dF55elZ4dl12elx6dV98dl52dFt7cll6eFZ9eFZzeFh8cFprd1h/c1tzcFd1dFhwcVd0clJ3 +cVh1blV6c1tyclh4blZwblh0bldycVNycFZvb1ZqbVRralVublNvbFR0bU5vblRwalJqbFNq +Z0xvaFVpalBlalJsbFJkaU1nZlFmZkttalFpZEtoY1FlYk5qYk9fZUtiZU9OS0M8Pjg1PjY9 +Pjk8QDc8QTU4OzYwPjc0PDU5OjozPTI2OjczQDY8ODw0PTU4PjoxPzQ5OjYxPzI8PTc0Pjc9 +Ozo5OzY7PjY1PDM5Pjg5QDgzQDM1PzY5PTc7Pjg7PzsyPDk6PjY3QzU3OTY0ODQ6QToxQjY6 +OzgvPTQ7Ozw2Pjo/PDouPTk9QjcyPjlDRTs8QEA5QTs8Pjw9Pjs9Qz5EVETj9qX9//X////7 +//z///////////v///////3//////vT9//zx/+r9//b///7///v3/vbx/Oj4//Dv/+73//Pj ++OLY7s3d6Nbu8uLm+uLp/+nV9+Lp8Ojj7OHz9u7r8+Dt/PLx/eXp/enu/O30//P///3u/+n7 +//3z+evy9vHt+ez5/vjx//D///7///n///7x6evz/PX2+/Hz++3l6NvV18hnTkpGRT1NQkRE +SjxERT5JPz0+QDlLQjo9QTlJOzw+QThKQjlEQj1FQj5CPjpCQzpIQTw8QzZJQDlBQjZIPj08 +RTlAPz0+PzdHPzc7PjZBPThBPjdCPDZJRTtAPzlBQDxCPDtEPDlDPDM8QDlBPjM/PzVBPDlA +OzhDOzs/PTZCQDk5PjREPzlCPzpBPTpBQjc/Ojk/PjY/QTdBPTk9PjhAPjY7OzdBPjU4Pzo/ +PzZCOjk/Ojc9PTo6PTM4PTM4PTY/OTM5QDVBPDs3OzU+Pjg3PDI8ODk3QTY5OTc2Ojg/Pjk7 +OzU2PTI/PDc6PzY5PDc3QTc2ODQzOzg3PTQ3Ojc3QjI+PDg1PzQ9PDc4Pzc/Pjs1OzFDQjsz +PzM9OzU8QTRBQjk9ODU+Pzk3OTRAPzs3Pzk3PTY9PTU6Ozg5OjU8PTw7PDJBPT87ODBAPD0/ +QTJBPEA/PjVBPz47OzJAQT48QDk6OjE7OTg8Pzo7Ozc6PDtAPzw8QDdBPDo9Ojk8Pjk/Pzo5 +Ozk8OTs5PDhAPjozOzQ/PDg2PTk9Pzo2Pjc9Ojs3Ojk/PzY6Ojg4PzM8PD82PDM+PTw3PzU9 +Pjc5OzU6PDY8Ozs+PjY4PTw6PzU5PD06Ozs7PTk7PDI4PDw3OzQ2PTo2Ojk7QDk+PDo6Pjc9 +PTw4Pzc8QD08Pjw7Pjo6QzE2PDo6Pz06QUA6Pzs4QTk8Pjs4QDg8Pjk7Ozw7PTw8Pjo5Oj08 +QDs3QjU5Pjs3PTY8Oj01PjhBRDw3QDQ6OTY0PTc4OzkvQSw8Pj05ODI4PUA5QjtLS0hMTEZT +STpKTkRTTkJRTUVTTkJVUUJVUUtRUkhZUkdVVEFYVkhVU0lcVE1VVEJZVUtYVEJhVEpYT0hg +WVJbW0lcWUlZWU9WWEhZVk5YVkhbXExcWkhbWUxXWUlaVUhcW0xTV0hjVUtXUURbVlFUVUBi +WlBbWUBgV1BaV0VcTkdUSzdORT1PTz1qe1V9dmF1c2CAeF1+dlt4dVp6eFp6d2B8dVt4dF99 +clp0b19/cFlydFl+d2B0dFp9c1xyd2B6e156dlp1clt8c19zcFh4bVtyc1R3cFdxbVR5bVtv +bVZ0bl51bl11bll1bldvcVt0bFN4a1FybFlya1Zua1lyZ1FrbFRvalRoa1Vua1RmbFRuZlNo +aFVva1RlZ01taFNjZk1nY1BhZE1pZlNmak1qaFhmaVNnZ05pZExiYlBVSUc3Pjs0OTU9PDo2 +PjQ8PDs2OTw8Pjs2PDY8PTwyPDY9Oz01PTg8Nz0zOjk+PTw2OTs5Pzk4QDJBOzk2PTk2PDg6 +PTozPTg4PTg7PDg5QDY9Ojw4Ozg9PzozQjg9QD4yPDY/Pz4yOjtAQT8vPDQ9Pj40Pzs7Ojg9 +PTo5Pzw6PDs7QjpCPTs7QDo9PDw9Q0I5Pjs8QD85QThBPz89RT9JVU3v86j7//T///b///// +///9///9//j///f9//z0//H5/+z9/fX8//r////9//jz9+71/un3//L8//Tx+u3l8OPU4dPZ +8dD0+/Pf79vQ3svq9Ofn8eb9/vz9+/f9/vz0/fHu9ebp8OHt/PP///3x8+Xs/evr/Or1+fDt +8OXz+fP///77/e7m8+bs++Pq/+j4//T8//n9//f9//vs8+P9/vrz/eRhTUxJRjpDQzxEQDtA +RjtLRTo5QzZIRjw9QTxHPzc/QzxJRjREPztBQDZEQDdAQjFBPjtAQjdCQT0/RDg+RjlBPzY9 +Qjc/QDhCQDY/Qzg/QzM/PzY+QDNCQTk7PjU/RTw8OzE8QDZBOzM8PzVBQTg4QTNIPTc8QzBD +Pzk6PzE7PjQ+QTI9Pzk+QDE9QjU7PjY/PDU/QjZBQDhGPDc7PzQ6PjI4Ozc7OjE3PTY2PjM9 +PTo1PjQ+OTcvPDI7PjM0PzA9PzczPTQ6OjQzNjI9Ojo0OjQ5OzQ1PTQ1OTU2OjYyPTA2PDY0 +ODgzODc1OjEwOTExOTM0PTA5Pjg1OjA6PjUyOy4/OjcwOjJDNzg1QDZAOjUvPDE8OzU2OzI7 +PDI2OTY3QTY1OjE2Qi47ODU8PDQ6PjM5Ozs5Pi45RTk2RDA+PTk7QTFAPT47QzFBQDs/PzND +Pjw5QDA6QTw7Pjc2Pzc8PDA5Pjs8PDo2PDQ3QTc5PzY6PTM3QDM9RDU7PTw6PTQ7OTk4ODNA +PDo2PDM9Pjc0PDU4PTU0QjQ5PDk8PDk7PTQ8Qzg4OzQ5PDU5PTc4PTk1PzQ8Ozk3PjY8QDg0 +Ojc1PTQ1PDUzOjE5QjU3OTU0QTY3PDA3Pjk6QDI3PjA6PTU3QDI2ODY0QDU+Ojo2PjM7PDg3 +PjU5OTs5OjY3Ozk2QTs0PDo4QTQ1QDw5QTc3Qzg7Ozk0Pjk7QD04QTw2PjY/PTo/QDQ8Pjkz +QTQ6QTo3RDA2Pzw2Qi4+QD0xQTQ6PTk0PzA0NzkvPi42QEMzPTU1QDU8PTxKTDlLSkBLTUJL +TT1TUUFSUkBWU0VNT0FVWUdPU0NeVEdVUUBZVEVSVUVdWEtVVkJcWEtVWUNXVEZcV0dTWUNR +VkhVXEVZVktcWEVXVEZYVUVXXFBcWUZXVk1dXElUWUFfWUxXUj9iVkxSVkBcVFBVW0BZWkta +WT5eW0hZV0VbUkFUQjtRRTRNSz1sdVJ8cF57dVl4dVp9eVl3eV2BeF1xdF6CeV94dlyAd1V0 +c1h7f1Z0d1l9cFp5c193dFd6dlx7c1t6cF92fFZ1bldwclZ8dVlzdVl7c1hvbVJ4cFl6d1tz +cVh3cFpvcVZzb1p3b1ZvcFZ1alFsbVNvbVJpcVRycVpvbFFyaVRka09tZ1Zla1FoZlFkZk9v +aVVqZk5paE9oak9pZVFmZE1nZUtpYkloY0tlYkxhZk9mYkxjYUxSSEM3PDYzPDQ+PTgzQTI0 +QTg0NzA+PTczPi49PzoyOTE/PDcwPjU4OTk0PjM8PTg3PTo4OzM1PDk1PDkzOzU4Ozc2Pjg0 +Ozc4PTU7OTs4PDg2QDkyPjM8PTs1PzNBPjkxOjY+RTkwPDQ+PDYwOTM7PzM1PzQ3PTY2PzYy +QjQ6PTY4QDk9PTg+QT05QjY9Pjw7QDU6Pj83QThBRUI4Qj1LUE3n96D+//n7//f1//b6//D/ +//n////6//H+//j8//79//n////////2+O/p9eH8/+v8/vry/O/s+Onr9uPu++by//Ho/+Dn +8eLX4tHh69b0///3//Ht/Onr/Ozy/uz3//D6/ff7//b1//L1//b1//P8/fHu/O35/vb4//Lx +/+zp/ejq/+ft+ez4+/Tz9erp++fy6+bm+ODl8Nzt9ent8unk485eSUxLSTw9RTlIQz06RDVJ +Pj04RTxHQDg5QjtGPjVBQTk/QTs/QjtBQTlCRDs9SDNAPTs8QzlCPzk3QjVCPDQ/PTY+PTg+ +PDVAQTU+PjVEOzZAOzk9QzhAQDtEPztBQTxEPzk8QTY8OzM8QjlCQTo4PTQ8PjYyOy9DQDk9 +QThBPjo8PzZCPTY6QDM/PTY+PjU+PjY/QDc+PjM7QTI1OjY5PTY8Pjk8PDc3Pzg3ODRCPTc7 +PzQ9PTgzPTI6QTY3OjU9PTUzOzI7Ozo0PzM8Pzg3OzM7PDY4OjI6OTYvOTU2PTQ3PTA3ODUw +OjUzOjYwPTQ4PTQzOzA3OTYyOzM+ODwyQS09OjgyPjQ9OjcyOzNDPTM1Pjc5QDg6PTQ3QjY6 +PDQ6QTI6OzU4Ojg9Ojo7Njs8QDc8Ojo8QzVBOz04PDZAQjs9QTU/OUA3PzU/QD09QTY7Qj09 +Ojc/QTc8PjU6PzU6QDc8PDlCOTs5QDs7Pjk2QTQ7PDg5PDc7Qjc9PTk2QDNAPTs2Ozc7Pzc2 +OzY6OjczPTU8PDI0Ozo2PDg3PDw2QTU5PDg1PzY6PDo3PjI8QDkwPTQyOjY1PTM8OzU5PTc5 +QDE0Ozk6PjU6QDc5QDU3Pj43PjQ5PjQ8QDU2PTI5PzkyPjk3PDk0OjU3OjsyPjM8Ozo3Pjc7 +PDw4QTk3PTU0QDg0PzU6QDo5PTo5Qjk2Pjk5QDU2QDw7Ojc8QjoyPjI6Pjs2PTw6Pjs3QDhA +PDw1PDg7Pzw0PDM6Pz4xOzg5ODYzPjMzOT0vOzE2QTg7ODc0Oyo1OTdLTENOTD5NTT9ITEVT +T0dSTkVTT0dSVUVVV0xPVENaVUZRT0BXUUtTVUVgVUdOTkZaV0tZVUlaWU5ZUEtVV0dZWkxc +VkJcV05aVktVWUhcWEdcWEtgWUxWXE1gXUtSV0ZfVkxUVkNeUU1YWUNaVVFUU0FYWE9kWEVb +XEleWEZZTkdNRT1PRTdRRz9wclN1f197b155dV53dF10dVqAcmByc1yAeVtzclh7cVh0dFuB +eVt2cVt8c1l6d1x1d1p3dVx7c1p7eFtxclh1dFxxdlZ0dFtsc1d1cFpxb113bVZxb1ZtcFdx +cFpzb1hxcFpwb1ZvcFdualZucFRzbVNpbVNxcllrbFJtZlJoZ09maVZnaVBpa1RfZU1jZlBm +aE9nZVJoa09iZlBkZk5pZFBlYkpbXk1kZkpgYEhlZUhgYUpPRUM6PzQ2Oy48OjsvPTQ9Ojov +PjQ3OTUxOy87PDUsOzE4PToxOzQzQDg3PTQ5PDg0PTc3Pi81PDo3PzczPjQ5PjY4OzY3Qjo2 +Qjg9Ojk1PTY7QDkxPjJEPjkyQDQ/PzkzOy88OTgzPjU+OjY6RDo1Pjg3QzY1PTg4QTozQDg3 +QTs8PTo9Ojg3Pzw7QTw6QTk2RDg7QD9BQTlBR0I+STxIVUzj85/2//L6//T///7///////3/ +//v///7////6///9//H4//P0/u/8//f////9///y/ez1++v2/e/9//X8/fjq9unY7c/j6tno +7ubk89zr+ejs/O3o9Obq+urx9+r0/O/s7+Th9Nbe8uPz++/y/vL+//7x/+3k7uXh9N3v8vDw +8evs8+7+//3///v7//b3/+3r7ufq+u7+//v///Xu9ene1MtdS0xDST9BRzxERj09Rj9MRDw2 +QztIREI2QztEPzo8QDlFSDlBRDo+RjY/PDk7RDU/Oz06PzNCQjs8QDVEPDc8QjZCPzw/QDk/ +Pjk8QTo9Ozc/Qz06QDdARjk/QzdCQTpCQTo/QztAPjQzQTk9OjY4RjhBQTo8Qjo+Pzw8QThD +Pjo7PjVBPTo+QjNAQDo5PjZAQDc9Qjk+Pjo7PDZCOzhAQDU3PjU7QDc4QDY8Ozc7QDc3PDZC +Pzo2PjZBPDw8Qjg+PT00PjY4PTo4PjZAPTszPjM8PTcuOTU2NzUxOzY3Nzg3OzoxNi84OTY1 +OzU2NTE1OzMsPzY3PjkwOTI2PzgzPjU4QTc2Pzg+PTk1QTc/QDgwPzdCQTc2PTRDPDk5QDU/ +PzlAOzo/Pjw8PDs3QDw4Ojc4Qzc9Pzg5Ozc3QTM5Ozc0RDNBPkA3ODU+Qj0zQTA9Qz48PDA4 +RD87PTo9Qz49Pjg3OjY3PTU8Rjc9PTg1QTY6QTY5Pjg9Pjs7PTo4Ojg8PTY6PDk6PDY2PzI3 +QDQxODU+Ozk6PTc9QDk0OzU1Pjk2PTc0PDQ5QTkyPzI3Pzc3Pzc/OjsyPDY2PzQ2QDo5QDc1 +QDc0PjM6PDs4Ojg5Pjg2PDY4PT45Ozc7QT06OTs3Pzk1QzcyQjc5PjUxQDY3PDkxQjQ4Ozk6 +QDo3QD85QzkyPDgxPTc1Pz03Pjg3QDg1PDIzPTk7QDgyPTtBTzk3QTwzRTc6PTw2QTQ6Pzsu +Pzc7OzwtQzc8Rz0yQTU6O0AvPTM7Pj0zOS81PTwyPC8yPzg6QzdJSD5JS0NPTkNHU0ZPUUZQ +TkJVVEdNVEhTUUdSWktZVUpTWUFVTktTVEBZV0tLVkFUV1JSVUVXWUdXW0dcWExZWU1XWkZV +V0xXWkJcW01bWkVRWEdZW0ZVZEtbWEtYWkVcWEtXWkReU0RYV0VdW01XU0RVVExXVj5ZVkpV +VkhVUUJISDhQQzVJUj9wd1d3fFt9eFh6dl5ydFt1dF11eFl1eVp8dVxze118cVdqdVh9el1z +c1iBeFp1dlh4c110dFtzdVttdFlzc1h2clhudFp2cVxzb1Z0dFtxcFh3cFlsdldxbFhycVRx +blR1clFxa1VucFhxb1drbFdtblFtbFZzblVmaE9oa1FocVJvblhibU5yaFZqalNraVNkZ05m +Z1FjZU1jZE9jY05kZU1cZ01jY0xjY0xdZE5jaUtfYk1OS0M2Pzo4Qjo3PDkyPjU6PTkxPjI1 +Pzw1QjQ9PTYzPzA1PTUyOzA0PjcvODU5PTs0OjY0OjgxPDk1PjIyPjg0PzQ1OjY1PTkzOTg2 +PjQ0PjY6OjgxOzFAQTwyPzU6PTsqOzQ+OjkvQDQ6OzgqPzg8PjkyQTc4Pzk2PDU9QTo2QTo4 +QDc4PDsvQDc4Pjo4PTg8Rjk3Qzk4RjRARz05RDlJU0ni8Zv9//////////////j///3///// +///6//fw/+z5/unv/u32++7t/+j0/+n5//P1/e7///zz/fXn+eDd+N7Z7dbX8s7u/ejk9+Td +6trn7eD59fb49vDp7uLk693q9eT0+fX9/f7z9+vw8ebt+e3s8OXx8un+/v3///////f6//r/ +//7u+ePr++n7/+/08+rx8uXw/fLt+97r9+329+ff29BkTklJRDpIRDtDQTxDRzhDQTk/RDpE +PjlARD5KQTY7PzNEQjc7QzNEPzU7PTVFQTk3OzJEQTU9QDY8QTFBOzc9RDNCPjc9QDQ/PjU+ +PzRCPDZDQjM/PDZEPDVAQDdDPDVAQDRCQThDQjdBQjg/PjdAPzlHPjNCPzxAQDVAQDVCPjU/ +PzVDPDY5QTRGPjw/PzNAPjc+QjFAOzU8PzU+Ozc7PDFAPDg7QDM+PTU7PzNAQTVBPDU6PTI7 +QjI4QDM8QC84ODY3PTQ8PDYyPjA3ODM4ODA7PjY3PjQ8PTIrOTE5NzIvOTI3OjM2OTA5MjUv +OzA2NTI6NDYzPCs3PDE6OzU2QjI4PjM2PDM9PTo7QjRBOjY0PTQ9PTc1PzU+Pzo4PjdGPzs5 +PTREQjU3OzFFPjg1PDU4Ojc8QDg7PDY3PDQ6PDI4PzQ9PjQ9PTc6Ozc5PzM+PTo0PjA9PDc4 +OjQ+PTo6OCw/Ojc3PzA8QD05PTRBPzxBPzY8QDVEPjc6PzA9Pzk4PTU9Pzw4PjY7OzI4PjY5 +PS49PTo2PTU6PjkzPzM+ODk4PDJAOjk1PzU9PDY4PzQ5PzU3PjY2PzU8PDU4PjI7Ozk2PjU7 +OzU7PzU/Pjk5PTQ8PDY6Pzo5OzA7Ozw5OjM6PT01OzQ4QDc3Pi46QTU7PTM2OzU7Ojk5OzU6 +Pjc3QTM5PTs2PDI7PT06QzU5Pjs0QC41PTk2QzI2QDg8RTU4Pzs5Pjk1PThAOzU4Pjo7PzU7 +PzQyRDQ7PDk3PzI6OTQ0PjA3PjszPy03ODUzODA7OzgzPC1NTENOT0JUSkdMTTxYTUZRVEBY +VEVQVUtRTz5WVEdYU0VaU0haU0VVVEVXVEdNUEdWUUZTWEFeVUZVU0FfT0tRV0JiVExVVkJf +T0lZWEJdWU1YV0ZSV0dVWEhZV0ZcU05iWEZbWUlbWkVVWEZcW0NWVkZWWEdeVURZT0tXWD5h +T0ZLQzJWRjlETDNxc1h5dlh7cWN4d1t3eVl8d15zdFt8dF98eFp8cF56dFx8dFt8elZ7dFl3 +cFpzeV17dFp5cFd2dFtwdll9dFhubVZ9eFZucll0cVV0a1R0bVJyb1dtcFF1cFVwcVN6bVNs +bVBwcVNra1JuaVJvblJqak1sbFNxalNlbU9yalFsbFJoaU9malFqaE5makptbE5nak1mZU9n +akdsZk9iZUtoZUpiZUpoYUxiZktlZlBiZktiYEtPR0E0PzcyPTU2QDc8OzcxOzM0PC84PDY6 +PzUzPzQ2PzY6OzYyQC89OjI1PDI7OjcyPDI2OzcvPTU5OzQ3PDM8PDU3PzI1PDQvPTU4PTQ3 +PDQzPzI2OzY2PjI2QTY7OzU2PTI8QDkyPTY7PTkyPDU7QDkyPTM+PDoyQDdCPTwvPTVDOjg3 +QTY7Pjc4RDw6Pzs6Pjo5Pzc9Qjc/Qzo9RzxFWEPt96X9//b+//b6//D+//P///////j///f2 +/+/6///0+eP+//v////9/fr9///0//To+uXq+Obr9d/v9ej8/fbt+/Hn+9vm7ubd39To9dzy +/u7z9+vr/u7y+vH6//H+//z5/+/z8ePr+uj3//f18+rs++zz/e3q8ur2/u70+u3q+ev4/+71 ++/L18uHl9eTy/+30/e30//X+//7z/fPq7+Hl5tZcS0VFRkQ9QjNEQ0FBPTdFRT1CQDpAQjg7 +QDdEQD9BQDU/QDc7QDQ+QDQ+Ojk/Pjk5Ojo8OzVAQjZCQDg5PzNIQDs5QTdDPzg2PTdEQDs3 +OTxEOTg9Ozc9Qjg/PTg7PzU/PzpAPTRFOjw3PzRCPTc9QTc+PTY+QTc5PTU9PDc7PjU/Pjo9 +QS8+QDk+PTM+PT86QDQ9QDU/QDc8PDRCQjw8PzhDOzg9PzM9Pzs6Pzg9Ozk9PjM9Pjg4QTU8 +OzU5Pjc5OTc9Ojc7PjY6PDI4PTU5ODQuPDM2PTE4OTk1OTQ5OzYuOTIzNzksNjUwNTYwOC83 +NDMwODU5PTs1Pjc5OTY5OTY7OjI2PTI5PTc9QDg4QTA4OTY0QTU9NzU8RDk+PDE/Oz05PDM/ +Qz45PDZAQTowOjY7OzkzODZBOz41OjY+Ozg1PTo+PTg4Qzg+Pjw6PzlASkA8OTk+Pzc8OzU0 +PTQ0PDEyOTYzPzA7PTw1QjM3OEAyOzM5QTs1PzU+Oj0yOTM8PD04PTE2Pjs7PzM5OzM5PjU1 +OTg7Ojw5PTg8OTk9Ozg3OzQ4PTE5QDc5PzozPDg6PjkyOTQ9PTgyPTI3PTYxOTQ7PTY4OTo6 +PzY3PDk3PDU7PDc1PDA3PDg3Qjc0Ojg3OTU3ODc1PjQ8ODM3OzMzOzI6OTw0ODM4PTs0Pjg4 +Pz00QDI7PT04PDI2Ozk7Pz03OzQ2PDQyPzc8PD82PjQ6QDs1QDI6PUE4QTQ3QD06Pzo4Pjw4 +PDovOzs1Pjc0Ozk7PDcyNzc1PDctNDc1PTE5MzYxQDVPSEJPSUNPTExHUj5YT0VLUUJUU0hS +UkJYVE1SVUJXUElZVEVXVktSWUdVT0tTVUdWVEFWVk1WW0pWV0NhV0pTVUVVVUlaWEZcXktV +WUVVV0pVV0ZbU0xVWEleVkpSVkJeUUxZVUZeU0RaW0ZbWEdcWEZWVklaV0paV0tXWExaTD1L +RjtNQTw9Szlxdll2d1p9el90d1h6c190dVZ6cl1zdVx2eGN1eFl7cmF5emB3dVl0c1t4c1l3 +cF5zdl14eV52dVp3dVx6b1p3cFp8cVpucVt7cFxuc1h5bVZtcFd5blRzblZxcFVtallyblZr +blRzbFZtaVdrbFFxaVZta1Rzalhrak1taVRpa1BoaVFoZ1JqZFFpZ05mbVFraVNjaExnZlBo +aE9maFFnY0thZFNiYk9cZEdgXklfZUlgXUxLQj46PTs2PjU2OzYyOzI7OzwwOzU1OjcyOzc3 +ODc5Ozg3PDY7PzczOTo0PzU3OzkzOjQ3PzkyPTc4ODczPTQ1PToyOzQ3PDguOjY8QDcxPTg5 +PTgyPDs+PzkvOjU6PDkzOzozPDk5Ozk7PD44Ozo4QDs6QjY6Ojo5Pzw6RDk1PDU7Pzs0PjY7 +PTs3PTk+PEE0PzlBPkQyPjlBREM3RT1LTkbZ5Zzm+N/5/e7////6///7//H////7//T9//b9 +//z8//H+///6//j6//Du/u3r9+Pz+fL6/fj9//nv/Pfk99nn+Obg8dPm++bl9OHc69jz8eHi +7ejp8OLu9+nb59vm9eTq897q8+f7/vXs9+Xr/ef+//n+//j6/e3z+Ovr9Ovy+PTs+Oj3/vv7 +//f+//zz8+vt7+b29vLj8uL2++vp8d/p3dlZUEZLQzw9QjdDOztFQzk9QTlFQDlHQjpCQTxC +QTw+PTRBPjtAPTlIOzk7QDdDPzs8PTVFQDo8QzJCOjo8PDFHOz07PDFEPTw/PDI/PjpAQDg9 +PzQ+OTQ/QTVEPTdCPjdBPDhAPjM8PzI+QzM4QjNBQDg4QDRIOjk3RDVJPDs/QTNHPTs7PzlJ +OjZBPjRAQDNDPzZCQDhCPDtCQj5IQTg/QjNEQjpFQTpEPTtAPjtFQTZEQDw+QDNDPzxBQTFE +Pz0/PzU9PzdBPzQ9PjhDQDg9Ojg9Ojg0PzE8OTY1ODM1ODYxNy86ODQvOTQ0NDQzOCs5OTM3 +QTY4OTM2OTY8PDY8PTk8OzQ/QjY7QD1BQTlAPjlBPTBDPjo7PzM+Pjo8PTQ9PDU5PzNKQDg3 +PzRBPzc6Nzc/NTc3PjY+PDU3Ojc9QDE8Pjg8OzU6Pzg9PDg+PTY7Pjs2OjA+QDY2OzI9Njs2 +OjM+OjgzOjY8OT02PTc5PTczPjVAOzc2PThAPzs8PDQ/PjlBPDU0PDw8QTs9Pjc8PTg5OjU3 +PzU7OTk7PjQ9Pzk3OzU+Ojk1QDM+PTw2QTE9Pjs3PS0+Pjw5OzA/Ojs6ODU6Ozo5OjY4PDM2 +PDQ2Ojc3PjY8PDU7OjU9ODc4PDY7Ojg2PTQ7PTszPjA7PjotPTM8OzszPTU+PDoyOzM8Qjk3 +OjsyPjc3Pjs7Pjg5PD05QDg6Ozg3PjQ7QDg7Ozk7QDU/Pz80PzU3QDk5PTU8PD43QDQ8Ozw6 +OSw5Ojs4NzA3NTs1OzAvOTc1OjU0ODQ7Ojg7QzBOSz5QSTtOTEVMUUFRUkVVUkZPUEtTWERS +UUxXU0ZXVUJdV0FSVUZaVkhMUkVYU0VXWkpWV0JbVkdXWEJfU0NXT0JaVERXXEhZVUhfWkNd +VkNXV0BbXExWWUJcWklfVUJaWkxcXkNYU0ZYUkFdWkdbV0dfVz1aW0FdUEZcVEdbSD9LSzhZ +STVGTzdwclZye1Z2dGN0dFV6dlx2eVp8dF93cF59dWF8d110eVx5c1p1d1tzdlt5dld0c1l7 +d151c1p8d1l0dVt6cV5wcll6cl12c1V0cF9vbk90blpta1VycFpxbFF1cVh1blVwbVlvbldu +blVxbFVwb1RubVZzbVRxa1ZwblNta1Rqa1Rra1Bza1JkZlBwbFJla05tZ1BgZlFrZU9jY0ti +ZE1kYUthZEphYk5gZUtiZ0tfYUlmXUpJREA8PDM1PDY4PDU7Pzc5PjE4Ozg8PTA2Pjg3PC84 +Ojk8PzQ6QDg7OzYyOjQ7PTkzPDQ4Nzc2PTM5PDIyOzM0OTU5Njs6PTg1PTYzOjU5PDo6QDQ3 +PzQ6PDUzPTg6ODg0PzUxPjY8PDI5Pjc2ODQ8PTc2PTQ+Pzw2PzhAPTk0OzY7OzgxPjZAPTw3 +PjlAQj03QDk7PTg4RTk+RD4+RD9HUkP5+q/+//j////+//f+//v///////z///////35//r6 +/+36//b0/+35//X3//P9//3y/+/w/Ors++nr7uXo8ODg8uLf9dDf7drg69bd4tn8//L2//j9 +//3////z8+fs7uX3++v8//bt9eXw+O3s9e7u7+X+/vz59/Hw/uj9/vn////z9+zl+ub1/fDt +/+f0/fTu+fLr/vHx+ezx+uvt8+Pd4dJeTEVERz46QzhEPz47PzhBQD44QjhEQTtAQjpHQj49 +QjZCQj1APTc/PjdDPDc+PzY8QzY6QTs/QThEQDs/PDY8QTY2QjM+QTc8PzJDOzk3OzJENz87 +Oi5COjs3QjZEQzs9QjI9Pjk/QDQ+QDY7QDQ8OzZAOzlBPjhCPzk9QzhAPjs8Pzc7PzVCQTY7 +PzJDPzg3PTNCOzo7PTRIPTo7PDZHPzk6PTVGPzo9PTdCQjhCQTdEPjxGQjw+QjRHQDo/Qj5H +Qzs+QTc9OjM9Pjo5OzI+PDg8QDQ3PTk2Ny81OTozOS8yODgyODAyOjM0ODMyPDM1Oy8xPDM5 +Ojc2OTU5OTM5QDI+PTU+Ojk6PzZBPzs8PzY8PzU4NzQ9Qzc/PjU6PDY3PDY+PzhBPzk3OzM+ +OzQ3PzFAPTg5PTU4ODg1PDM9PzU2QjY7PDk3PTg/PjczQzU7OzM5PzI1QDI5RDY6PDY4Ozg6 +OTE6PDo6Pjk4PzE6OzU5PDU7ODgyQC87Ozs3PTE9PTs5Ojc+PjU1PzI7Pzs1OzY6QDUxPzE6 +PjY4QTk/Ojk6PjQ4OjYyQDc1PjU3PjY7PjUzOzY3PDMyPzA6PTc1Oy47PDk1OzI6PTo3PzM8 +Qjw4PDI5Pzw2PDIzPDg2OT03PTI5Ojk2PTQ6Ojo5PDw1STk9Ozw3PTY8PTkzQDI7Pzs3Ojg7 +QDswPjQ/Pz8vPTI8PDoyPjc8PTo4PTw7QDU2Pjk1PDc1Pzc2QTU3ODgyQDQ4PTg4QDo4QDs2 +QTY0PjQ0QDgyNzU4OTgwPS84PzoyPTc6Q0BJRj1OTkZPTkBRT0BYTjxQUkJWU0BTUEJVT0hW +VkVXVEJYVUJZVk5VVkdUU0hVU0JWVk1ZU0NTWklbVkdSVkZZVUZRV0BiVUZaWElbWUdcV0ZW +U0dfVEhZXUdjWUtZWkpgWUtTVkxcVUlXVEVZU0pUWEVcWE1YU0NdV0hWV0VVTkZNQj1URzJC +UDlxcFZ5dVp+d2B5flx8dV10d1t1dmBxdVd7dGJzc1B4cl1ycVd8d11wcFV3dl53el91cFt1 +d1tzdVp5c1hwblh1dVp2cVpxcldvcFxuaVNzcVtrblVzbldsblVzc1hraVFya1dlbU9yblhx +aE5ycFZtbFFsbVhza1VuZ09vaFFmbE5oalVpaU1ma1FsZ0tqalNlZU9iZ1JraVJhZEppZU5g +ZUlmYk1fZ0xmZE9hZ0pmYkxhXUpMQ0I4PDo4OTQ3PTc2QTY5OTkuOjU2OTUzPjI4QDU0PTQ6 +PDQwPDM1OzE8Pjk4PDE2Oj43OTgxPDo3OTE1PDkzPTQyPDY7OzYyOzY5OTc1PDU6PDg2PTc0 +PDk0PDY+Sz04Pjk2PDgwPDkzPzY3PTw4Ozs1QDQ3PjY5Ozk6OTk8QDY6Ozw+Qjg+Oz84PTo6 +Pz81PzhAPzs4Pzo/QT8/Tj5TYFXb9J3+//P9///9//v////////6//j///f7//v5//X0/+n/ +//f0//X9//X///30//Xw+Ony++7t/Ofy+env/evs++7Z8tDZ5Nbe7trh69zz/+vr9ezs9+jp +8ubz9+7q9ebw++bq/Oby/evt9+b9//36//vz/Ov1//v8/+739e7t++r+//zx8eTz+PLn+OX3 +++nu8ub3/PT8//nv+uzp7eLZ29NbR0dAPj1DRz5CQUFCQD0+PDk+QD1EPzM9Pjo+PjxAPzdC +S0c9PzZCOzs1PjdBPzk8OzJEPDs7PDM+OzhBOzZBOj03Pjg/PDhBPTdFPzlBOjo5PDg/PzQ/ +PTpDOzk9Ozk9QDVCPTg8PDNBPDo8QTRBPjg8QzJHPj42PDRCPzg7PjJCPDo1Oy9COjo1OzFB +QDk8OjY7PDI8Pjc7PTU+OzM4OzI+OTY8Ojc9QDZDPTc/QDZEOzo6PTFFPjo7QDRIPjw+PzZF +PDc+QjZEPTk/PDo9Pjc/Ozc3PTU3ODYzODQ5NzczODM0Ny8xOTU4NzE3NTY2OjE8PDs5PDI/ +NkA5PDFBPDs5PDBBPTtDOy8/Pz9BPTU7QDU7PDk5PDhHQTo+ODg7ODg6NzlDQTo6PTU/RDc/ +Pzc2ODk+PDg5PDQ+Ojo3PTU+Ojk9Ojg9QD04OTo7PTQ8ODk4PDY8Nzs5OTc8Ozc0OTQ7Ozcw +PzM7PzYxPDY2NzY6Pzs8OTc+QTo7Pjg3ODk8PDc6PDo6ODY5Ozk2OTc4ODk8OTk3PDU+NTw6 +NzI4Ojg0OjQ4Ozo0ODI6OjU1NjI3OzY3ODo7PTk1OjM+Ojs3QTY7PD05OjQ1PDU8Ojk6Pzs7 +OTg6PTo2QDc3NzgyOjc8Oj4xOzY6PTsyPDM9PDs3PjQ2Ojs2PDA+Oz8yOjI+PEQ0OjQ6Ozw8 +PDs6Ozc2ODxARz02Ojk4Nzk7Pjk6PTw2PDY6PDgxPjs4PDsyPjE7OTkzPi4+Pz4wPDQ9ODww +Njc7NTQ1NzswOjc4NzY0PDY2Nzk6PzhLTEVMTUNPS0ZQUkJLTkVSTkdQSkJXTkhSTUFVWEtS +UkdcVEpVUz5VVVBTU0VWVUpRUEZTVEpXVUhYVUNaWUpaUUJaU0hVWj5cVEtXWUVVVUxaWD1X +WU1eT0xWVU1gVEdYVEVfV0hXWEljVUVXWEhgU0BaU0dZVUhdVUZZWUVdT0RKSjNWQzxGUDtx +b1pyelh+e2R7dmN9clt3dll4dlt2cVt1b112dVp5b1tzcF18clh4b1x1bFVycVp8clxycFZ1 +bVF1cVd3clxxdVd4blhvbFFzcVtyblVyb1xsb1JvbVVyb1Z1bVlvbVNuaFd0bVVxblVyalRt +aVNpbU9wZ1RrbVFuZ05maFFqZVBnZ05qalFiZUxoZ1RkZ1JoZVVjX0hlZ05jY0loZ1RlYE5h +X01lZU5gYUxkZFJfX0xgXEtJQUU2OzY9PTk1QDY+PjsxOjZAOjgzPDU/PjcvOTI/PDozOTs/ +Ojg0Ojc3PjY1Ozo5Ozg3OjszOzY4Ozc6OTY3NjY3OTk6PTk1OzczOzQ2QTo2PTI2Pj02OTM9 +PzszPzM3OTs2OzM5PDo7Ozk1Pzk6OzU0Oz1BOjs0QDM4Ojc0Pzg6PDo3PDo7Pzw4Qzw5PzY4 +Pz47Oz08Pj48RT1CQj9DUkns9KP+//f///n///r///79//n///j5/vb5//P////+//j+//7/ +//////35/vn6//Dx/+31/evv//Px++fw++vn+OXY69bp9uTc6tnc5dT09+vl8uPw/fHu8+Py +/vDz9+n7/fz5+enl8OHs/u3u+eXi7uXx+Ovy/PP///j2//P3/uzs9+nz+ej0/vP5+Ofi5tfb +5dju++/1/e39+e/t793j3tJaTENLRz87RTtFQkBAQDdBPjg8PjdAPzk9RjhAOz09Ozg6SD5A +RDg9QTM6PjU6QDU9Pjc/PDo/PTc9PTg1OzM9PTk1OzJBOjo+QTU9PTs8OjU9Pjk9QThCOTo8 +PDU+Ozc4PzY/PTY7PDE5PzQ9PjY9PTVCOzlBPzg7PjRCOzo9OzVEPTc5PDBAQTo5PDNBPDo6 +OzhEPjo2PjRFOzk4OTM8OTY6OzE4PTs6OTg8PDU9Ozk8QDU9ODc8Ojk8PTU8PDo/OTVBNzk8 +PjNGOzk8QTRDPDU8QDZJPjozNzM2PDYrPDE5OTYwNjQ5ODYzPDY3PDU6PjM6Qjc9Ozk7Ozc9 +OjQ5Pjk9QDU7QTg/OzZBQj03PTVBOT07PC9AQTo6PTI8PDk4PDA7PTk8PjI4PDc/Pzs4PTg8 +PTU3PzQ5PD07Ojk6OTc8PjU6QTg4PDo4PTE4QTk5OzY5PjY4QDM9Ojs6Pzo6Pjk3QTk8PTg1 +PTQ2QjU6Pzc7PTE5PDQ3QTU+PD02PzQ5PjY2RDY5PDQxPzM3PTI0Ojk1PTI5PTo6QTQ0PTY2 +OTA2PDs2OjQzQDY1OjU1PzY2OzQ0Pjc4PDk3PjY/PzM4QTQ8PDczOjI7OjwyPjc5ODczPTI1 +Ozk0PzU0PTk6OzU3Pzc1PzQ3PDo4PjI4PjgzPjY2OzY6PjY6PDcwPTE9Qj80PTM5Pzg2PzM4 +PDwzOjM7PDc3QDA7Ozg0QC83PDQ0OTY2PDk4OjcyOjUzQDc1PjY1PDU2PjY3OTk1PDYqOzE2 +OTkwPjE0OjUoPTI4ODwqPDE+QTxBS0FSTkVKT0NYVEBRVEZQVUNWVkdTUEJTUkpVW0haUE5W +VENVVUhYV0JOUEZbVEtXV0ZcVEtTUUJaW0xWWUdaWEpZVEZTVkhaV0JcUUpZVkZXWUdcVUdW +VEVgWEtaW0ZXU0heXkJYU0pgU0lXWEZhWURRUkZdW0dWWkZoVURaR0BSQjtPQT9GSzxxeV18 +clp9d195e1p5dll1dFl8el93dV56dF52d1p5dVp3c11zb1x3dFZzbV91c1t5dVtzcVp7cldw +dl9xc1dtcVt3blhrblR1cFpzcVhzcFhteFhzcFhucFJ4b1ltbVVzbFtpa1VvblNubVVrbVVv +blNobFNsa1Rvb1Vxa1FhaU9oalJta1FqaFFlZ09naU9kZE5hZkpsZlFeZktlZE9gZEpqZU5f +YkhlZVJfYUtgY05eXEpOSEI6QjY0PjI3Pzw2PjM5PDkzPTY2ODo6PTU3PDM7OTkyPTQ0PTcx +PTI4OzUqOTI9ODssPDE+PDUxODZAOzgnPDU6PjYxOTUxOjU0ODgwODI4OzkuPDY7Ozc1PTY6 +PjE5PTo8Pjc1PjgxPDI3PTs0PTQ3Pjo3QC02QT80Pi83RDg8QDkxPDc7PjY3QTo/Qjw1QD4+ +RTw7Qjg+Qj82QzxTZ0Xn+Lb5//D7//L0//P5//H+//f///////r///70//T0/+X7//Xz//Hw +/+z0/u/9//Lv+ur8//vs++3x/ufp9+zb6NvW8dPb6tfZ59bY49Hy9+vs+uzw9un2/u/u7+nt ++OP09u74/u/+//71++nw/Or7//b7//n5+/bs8+ju+Orz/fH9//r///7+//////Pz+/Dt7+bu ++uz4/+7j59zk4dbT0MdjTEU/SEFDPTk+RDxCRTk9Ozs/RzdEPzo/QDVBODo6Py5APz0+QjhA +Pjk9QTdAOzRDPThBPTU/QDc7PDNAOzo1OzM6PTY+OS87PjQ8ODQ9PjZCOTU5OTVCQDk7Pi9C +OjQ9QTFAPzQ6PTM6PDM8PDY8OzQ6PTQ/PDc6PDQ/PzU7QzQ8NzU/PDQ6OjM5PC88OzA6PDI9 +PDQ5QTBEOTc5PTJDOzg2PS9GPTk4OjRCPDo+PTJDOjY3PjJAPzc+PTJDOjY7PTc9ODE8OzI6 +PTQ5Ojc/PDk8OTQ/OjQ+PTM8NjkyOjE1ODY1Ny04NTktOS9COTU3PDFCOzk4PDRBOzk4QDlD +OTY7PTI/OjI/OjY+OzM6PjQ7QTM9PTU4PjVEPDU6QDY9PDFAPTtBPzI7QDU7OS5AQTw6OTE4 +Ozs+PTE+PDo7PDM6PDE9PDM6QDRAPTU5PDBBOzo4OjU6OjM6OTc9OjY4Ojg4OjU7PDY2PTA6 +OzIyPjA7Pjc4ODU8Pzk2OzQ+PzMyOTM0OjA3PTQ0PTg8ODk1PCo5OTg3OTU2OzQ3OzM9PDQz +OzE7Ozk0OTM2PTEzOzQ2PjM2PDo6PDE6PTw7PC84PDU3OjI2OzM7PTcxPzQ+Pzo2NzI9Ojkv +PzA6PjUxPTM3Pjc4QDA6ODo1PjQ6Ozg2OzA5Qjc5PjQ3PTQ6PjE1QT02QTA2Py87PjE3Pzgy +PDQ3QDcyOy83OzUwQDE8PDkuPjA5Ojg1OjA6NzoxOyw6Rz01OzI1OzU1Ozg6Oi0tPDQzPDIw +OjU4ODQvOjY3OTAtOTE1QDNGS0VRTkJLTTxVUEVPUzxYUEVPUkFXV0NNV0ZYVUVMU0VZUUJX +UkhVU0BWU0dZVj1WVEhXUz5aWEJaU0ZSUUhYVkVWV0BdV0VaV0VbWEtXVj1YVE1bV0VbWUxa +WUVbVExaVkZaU0ZZWkVcV0daVUFZV0FZUEdXV0FdUkVaXUBTRj9SRzlNQjtNUTtveVyBd1t2 +d1yBe190c1h8dVp1dF19dFt7clx8dlx6b1N2dFR2cVRxcFB8dlZydFV5dVlzc1h4c1lscFR2 +bVh3cFh3blZxb1JwcFd0bVB0cVNzcVVzbVFvbVRvb1dtblR1b1Z0blBzb1Jra1BtaFRobE9x +Zldra01vaVVoaVFoZ09qa0xvalNlaE1rZlFmZktjZE5kY05kYk5kZE1kYktiZExmY01lZk5k +ZU1bYEdkYU9eWEZNRD8wOTE+Nzg0PDE/PjkwOzI6PTgyOjQ3OzgvOjE4PDE7ODgxOjEzPTQw +PjI1PTQ3OzQ4PTM4OTEyQDI6OjgyPDI7OzksOyw7OTcrOzJCOzkrPTY9PTk1PDI4QTU3Ojcx +PzY1OzU0OzE3OTQwPjU3QTg0QTU2PTQ1Pzg4NjU3QDc3QDM3QTk4PzQ6PTw3PTA9Qz87PTU8 +RD8+RD08SzdQXEXd76T8//L///////f////7//b4//P///n7//f0/+3v/eXv9+ns+eLx/uj4 +/+/y++38//nz//Lv9eff69zu+uPw+vTV79Dl8eDj7dzg6NLf7d3m8+nz/vHz/O7+//T0//Hu +8ejo++T4/evu//D0/O7q9uPl7uTi8t3y/vf2//L4//nu/ub0/e/u9Ojq9/D///3////09Ovl +8uD9//ry8ura3dBhS0E+RUREQzw5PjtHQD0zPzhCRD82Pj5LQj4zPTpEPTk+RDpBOTpCQTtA +QTQ9Pzo/PjU/QDc9QDFAPTg6OjhBOzg7PjpAQTc8PTk8PTU9PDg8PzM8OzlCPjo9QTo9PTY9 +QDpAQTk3QDlCOzc6PzQ+Pzo7PTY/PTk4PzA9PDc4Pjg+PDw9OzQ/PDc+PzZAOzY/QDdAPTc2 +PjI7OzY7PDY2Ozc5OzU6PTM7PTtAPTU7QzM7PDY8NzZBPDg2PDFAODg1PDJANjQ4OjFAOzg9 +QDc/OTg6PTc6OjM6PzU8PDQ0ODA3OzQyNjYxPDguNTU4OjQ4OzM8PDQ8PzJAOjw1QjQ9PDc4 +QC9BPzsvPTRGPzo3PTNDOjczPTRBPDU7OzU1OjM9OjY7OjU/PDo6PTQ7PDc1ODpBPjQ6Pjg5 +QDE5PDg3PS85PTU3QDI9Oz01PDE4Pz06OjQ7PDs9OTI6Ojs7Ojo2PDI6PDUxOzY5PDY1PDc2 +OTU4OjU3Ojc2PzY1Pzg5Pjc2ODI9Pjo2OTo+Oz46ODY+PTo2Ozc8OTc3OzU6PTk/PTw4OzU3 +NTc2PzM7OzU0OzU5Ojs4PTY+PDY2PDY6PDM0Pzg1PDM5PDc5PDYyPD06PDMyOjk2OTU5Ojk6 +PTQ1OTg7Nzk0Ozc4Ozg3QDQ6PTYxPTA7OD05Pzk7PTo1PDY6PT09Pzc2QDk0OTo4NTk2PDY3 +PDY8Pjc2Oj08PDg4OTo1Pzk6Ozs1PDg3Ojc0QTFAPEQ2QTE7Ozk0PzQ3Nz03PTE4OjkyOSs2 +OzstOjA0OzgyOzM9RD1IS0VQTkBPT0VWSkZYUUJTVUJRTUVXVUhQVUFWUkdRUUdZU0tRWkJa +VktOT0FcVkxTWUVfVkpTWEhaV0lYU0tVVkNXUUtVXEVcT0tWV0daT0hXU0heWUxYW0hYWkdb +XUtVWkZbW05XUkFfWUxaWEFeVExZUURdW01ZVz9aV0ZbTj1KRTVUQzdKUjhydld6dFl4dVt8 +dlp3c1p7cVp5d2B+bVZvcld8cltza1l4cVpwbVh3cFJtcFV4dFV1c1p1d1R1c1x3clp3c1ps +dVV1dFltb1R1a1dublZvcllycFNyb1hualVsb1V1cFVvaFVpaVJwbE9qbVpva09sb1VubFRs +bVZuZlZmalBvalNmZ1JuZ1NhY0tiaFJmaEpnZFNmak9mZVJlaE9mZldeYU5jYlJoZ01laE9m +Z0xZYk9mW0tHQEA6Ojs3Ozk3QDc3Ozk3OzY6ODozOTI8NzczPjY4OzwyODY+OzkvPTM9Pjk3 +ODY2Ozo1OjY2PDY1OjU0PjQ1OTM0PTY1OzQ3Ojo2PDg6ODo1PDg5PTw0PTI+PDw0OzE/Pjoz +PDFBPzgxPTs7OT01PTo8PDg5Pjg5PTs1Pjw2PTU5QTg6Rj08PT4+PTk5Pzo5REA9QTs/Qz09 +QTlDRUtKWEPv+rL////5//P+//n///////r///////z////4//f9//n////////////x9/ft +9uPj7eDp+ePp9OTu/Obw9PDb6djc89P2/PXa4dTc7tDt+Ojm8uLp8N/h69zx9urm7+Dt9+jr +9+Ps7+bl6eLp/ebw/fP4/en3+e7x/+7x++7m89309un8/vv7//j7/vD6/+/17uvo+eDu7ePo +9+Pt9d/m79lbSU9EQThBRD5IQzpBRTtCPjw7QzY6Pzg7QzY9PDlEPjc7QTg/PzQ/QTk/PDg3 +PzVHPjY2OTdEQTU7QTdHOzg3QjU9QjQ8PDQ6QDE9Pzg/QDQ+PTU3PjNFPT47QjE/QDQ9PjNC +PjU+PzQ8PjJDPjY9PzM8PDU7QDE/PDo/PjU8QTxEODI4QDQ+OzU3PDBAOzU0PS9BPjg4PTRA +Pzg4OzE8OzU4PzE9OzU6PDo7Pjc7PDY8PjY2OzY8NTU9OzI7PjU8PDM6PTU8PDFGPDc5PTM+ +ODo5OzE/PzU4PTE9PDU1NzM1OTMwOC85OTM1OzA+QTU8OTM+PTY7PDM8PTQ/OzVBPy5BPzQ+ +PDg8Pjk7OzY5OTI/PjQ6PTM8QDo3QDFAPjM4QDBCQjs4PTNCOjs4PjRCQDg4PTJGNjo/OTtB +PzZBOzk8Ojg/PTU/QTU9PDU8ODg7OzM5PjI/OzM/PDk4OTA/QDc7PDE8PDs5PTE7ODk2OjI7 +Ozw2PC04Qjc9OzU6OzM4ODs7OTo8ODc2PTc9PTg1PTM3Ozo6OTM2PDk5OzU0PjI6Ojg4OjQ+ +OD4yPTU7PTo2PDZAPjY4PDQ5OjI1PTk7PDQ5Pzg6OjE8Ozg1PTE3PDc2OzU3OzU4PTY3PTE0 +OTY5PzY6PDk1OzQ4Pjo3Oi43PD82OjE5Pzg3PDM1Pjc5PjszPTY7PDs6QjY4OjU1QDU5PTkx +PS4yOzcyPTY3QDo2QTUzOjk1PTM6Ojc3PC80OTo8PTU4PTM4PjQ1NzY1OC03NzYtOzE4NDc3 +OjQ7OzAzPDM5OjNLUD1UTkNNT0NWT0hTTkJXVEdQVT1VT0JVUUFVVEZTUExVUzxTV0NaVkdW +UEZVUUJVV0dYVEZSUEhaVEdVVEdbWEpVWUBaU0VUVkpfVU1TWENXW0ZWVEdeWUlZWUdYWUZa +WEhXVEVdVUxaWkRbVk1ZVT9aTUVeWUdaVUNjV0dWTT9TSj1RRjJPUz9xeVV3clt3cVeDcF91 +clh8dl57cld8e1x3clt4blx6b1pzcVR5dll5b1Zyblh2cVV2cFp3d1dzbld5clptcVp8b1h1 +dFx7blpwbVd4b1Rwclh7bllycFh3b1drcFdwbVRqbFZwa1V0alFvaE5tbVJubU9xZlFpaFBo +aU9salBuak1talVpak1rZ1Bra1FkaU5nZ0tkYk1nZk9jaU1qZU5kYktoZU5lZExmZ1NfZ0dj +YExdXUVFQkIzOjU2PjQ1OjQ8PDU4OTg5Pzc5PTY3OzY2OjczPTk3RTc3OjY2PDE5PDYzPTQ5 +PDcwPTQ3ODgzOTI7PzMxOzI6OzMxPDU4OzYxPjQ3PDc1PDc6Pjk5Ojk4Oy88ODc5PDU7PTQ2 +PjU2PjI6PjkyQTg3OzYxPTM+QTs0QDREPjs2QTNEPj02PzlBPz43QTpAQT05QT9FQjs/PkE+ +REBIUUbc76Du/OH+//j////7//j3/+39//r///r///f9//rw/uns+eH9//z7//X///v////x +/Pj1++zo++P2/PDn/eLp/+be79jT3cvc6c/j8d38/+/9/u71++/0/Pz9//n7//L+//3t9dnz +/vz////////99PX9/f769+zz+PT++/Lv+e7+/+/s++r4/+zz/+/3++ny8vf///7/9fX17+3x +5+ba1spdQ05BPzxHQD46PzhAPTw8QTtBOzxCPjc8OjU4PDg8NzRLPTs8PjY6PTg9OS5AOzY/ +PDU8PTZCOjk6OzQ8OTg3PzZCOTY3OTRBOzo3OjQ+OzY5OzRBPzQ6Ojs9OjY6PzZBOzhBPTdA +PzdAOzI+RTpDPDQ7ODI7PDM+OjY9NzJEPzk5OjBCODc7OTFEOzg6PTFDOjc9OjdDPTo9OzJC +ODZANjE7Ojc6NzY6PTFAOjhBOTc9OjZDODY7OzRAODY7NjNCPDc8OjE+NzU5OjFBOTg8PTBF +OjczOzBCPDYzOTI9MjYxMDY4OjEwOTA6OTFAOzY8PDU/PTA/PDdDPjg/QDhHPTJFQjZDPjQ/ +OzU7PS1CODs/PjRDOjo+OTI/Pjs/PC07OTc9OjA5OTU/OzM8PDU/Ojc2ODJBQDc7PTRBNzU5 +PDQ9PDg8PjhCQzk/Pjg6OTU9PDg3OzVDNjc3PDc/OjY3OjI+PDQ7Njg6OTlBNTk6ODI9OTkz +PDA6OTg7OzM9OTc6OzM9PDs3ODc+OzI1OTU5NS83PTo3OTE6PDo+ODQ6Ozo5ODE3Ozc3OzE0 +ODc5NzQ0PDI9OTk3OjA9Njg5OTI6OTo2NzE3PDk6OzQ7NjY1PTE6ODY3OzU3OTk7OTVBOTc+ +ODk3OjQ6Pjk2OTg3OTE7PTM2Pi84NzU2PjI7ODg3PjQ7OzE2ODI6PD8zPS89Ozs4NSw+OD05 +Oy45Ojw2ODU9Ojg6PDY5PzM2OTU6PDY2PDY9PTg3Ojc6PTQ0Mi89NDgwOTQ5NTgvOCk6ODsz +OTFAODs6RzlVUUVLTkBXVUFUTENTT0JTUkJTUEJaVkRXVEJZVUVYWENaT0pZUUhXU0NZTkxW +VEJcT01XUjtdVktXVkVcUU9bUUdZVU1eV0hfVUhaT0JaXEhgUEZdWkhaV0dZVUZcVkpcWUJT +UkhbT0VgWEhhVEVYV0ZeU0hWWUNdV0dWWUVbQDtPQjtXRTVKTEJ4c1V6dF12c12Aclx9b1F8 +dF91dlp9c1tqc1d2cltwblN4clp7bFZ4cVx3eVl3dlx2dlV2b1pzdV5zcVt6c114blVzbVdy +cFd3bVh2cVxvb1V0blhta1J3a1publBuZVVubE1walNuak5ybVVobE5salNuZ05saVNtZU1s +alBxalJxaVBpaE5raU9laFFpalFpaVBraVBkZ1BmaFNlY0xsZlBjZU5oY1FlZkxnYk5jY0hc +Wk5HQDw8ODk7PDc3PTA0OjQ1OTg7PDk5PDk0Ozc4PDY3OTE/ODo4OTQ7PDkzPDM9PDkyOjM+ +OTUxOTU+NzY2Ozk5ODg5Ozc2Ozg4Pjo1PDk6OTg5PjU+Ojg4PDk6Pjo3Pjw7Ozo7OTw9Pzo7 +PD05Ozg+Pj09Pzk8QT88OTY9Qjs5PDk8Pjo+PDs4PDg+Pj48Rjo9PTg4QTdCQTw/Pzw/QEBM +VT75/bX////////9//n+//z///3///////////j2/vL2/ez9//b1/vHz9uvw8e/y8eb7//P9 +//n4//Pr+Orp79/g8tzi+dbj9ePp99/g6dvx/+/v+e/x/fH69eru9uru/+rt6+To8+X7+vvt ++uLq9ujy//Dp9+Xt/Ovy/vL5/+/4/+vt9ubx+uXs8+vo7uXk9ePt7+ry/+v2/uzs/+n0/efg +7tZcR0Q+QDdJPT03QDlFPjg1PTs8OzY5Ojc8PzY6ODo7PjE5ODY0RDQ9Pjs1PDQ9Ozc4OjU6 +OTI8QDU3PTI8PTM9PDU8PTc8OTU/PTU2NTE8OzU9PTE7QDhCPDg7PTg/QDU6PDA7OzI7PzRC +QDg7OzI8PDk5PTQ/OjY7OTM+OTc4OzdGOTk3ODI9PDE8OjI9OjM4NzQ/Ojk8OTE1NzI9OTU9 +Ozs4OjI8OjI4OS5COzQ6PTA7ODc1PjRBOTc4Oy85PDgzODFBODc6Oy8+OTQ3PTY1OjM4PTU3 +PC42PDQ3NTU1Oiw1OjEtOS0yNzMvOTBAOjc7PzFGPTo4PjBENTo0PTJHQDc+OjZFPTQ3QjVF +QDk8QTdAQjk/PDc7PTVDNzdBPDo7OzY7PjM7NzE4NzZAOjg/Pzo4PjQ4PjU4Oiw9OTk1OS89 +Pjg7Ny0/QD85PzM1Qjk9OzY2OjQ8PDY2PTU5OTk6Nzk6OjQ3PDg5OTg2PDQ3PDc7OzU3OzM4 +ODY3OTQ5OTc7PDY/OTsyPDc8ODUzPTM5PTEzPDc5PDE+PDM2PTc+Ojw5OzI7Nzo3OjE6ODs4 +OC43OzQ3QDg4PDg5Ozk2OzI5PDk3Oy46OTg8OzM5Ojw9ODk0QDg4QTY1PDY7PTk0OTM3PDky +PjQ6PDkyNzA1OTgzPzI2PDs3PjE2ODUyOzM4PDY2Oy42PjY4ODMzOjQ3PDc3PTc1ODQ7OTo3 +OTg4OjU1OzE4QDg2Pjg5PToyOTM6ODszOTM5Ozs3PTA2OTsxPDQ0MzcyNyw0OTczNzc6ODAw +OTQ8QjRRTkBQSUdMTkZSVERTTEdXVUZQTkJVU0ZTVkFUUU1UVkJbUkhSU0ZbVkdVU0FcVEZV +UktZU0dZT0hbU0VZVEdZVUFVT1BfWkxbWEtWV0xZW0ddV0lZVEdbU0lcVj9kV0xcV0RhVU5b +V0VfWEpfV0NYV09eU0VWV0ZVVktZV0RhST1ORzRUOz1KUzh+c159flx7eF9/dVt3cFmBeFVz +e2N8dlVyc1d7dFducFl7c1dzc1Z8d1l2cVt1dFV1cFducFJ2bldybVN4clZzbld3bld0b1N3 +d1l0cVt0cltwb1NubVN0b1Jzb1ZrbVluaFZubFRvaVBvbVJybFVqa1RubFZtalBsbFdrak1w +ZU9obExqa1NoaU1kZ1BrbFJoa1FjYk5mYUxhZExqZ0xoYUtoZU9pZk5iY0xjY0pkYUhkVUpA +Ozw1PTQ3OTU0PDM5PjQvPDA5PDg2PTc8QDk4PDQ8OTcxPTE2PzkzQDM8OzcxOjc3PDI4OjM0 +PDU4PDIwOzY4PDQ2PDc1QjU1Pzg2NzQ+ODY1NzM+OTw0OjM6PDsvPTA8PDcsOzJEPz44PTo9 +Pjs3QDY5PDw3PTU0PzI+PTk4OzhAPjk3QDo6Ozg7RTk2Pzk+Qj4+RDk3QT88RDNEQkdGWEPo +9q/0/+r0/+/y/+j3/+38//X9//r7///3//P3/+/8/+37/vfv/+z5//D9//z6/+/7//b1//D0 +/+3w/+zu/Ofj7+Tg5tHj8dzn++Dc69jj9uP08Obq79/k9ubw9ero9+j6/vX8//H08+jy8vD6 +7/D09PLw+fD+/vvt8+n2+/P1//T7/evq/PT+//79//v///Hu8O729e3i6OX08ub59/Dk1tNZ +R0U2PzQ9OTo1QzM9PjgzPjI6Pjc2QTI6PDc2PTU4PDc6PDQ9NzY2OzQ9ODI4PjY6OjI4Njo1 +OzQzPTY+OjUrPjM8NDg2PTU8OTo3OjA6OTgwOi0/Ojo2OjU7NjY3OzQ5NzY1PTE4OjM2OTM7 +PTQ0Oi8tOTQ2OzY1ODMyOjI6PjY4Oi87OzI5PzNAPTY2PCw4PTYxPTA9NjY0Oiw8OzY1OTI9 +PDYyOi82PDY3PDI8OzE8OzM4OjI2Oy81PDU3OTU4Oy82OjA4OTMyOi84ODM3ODU8NjU2OjE/ +PTgnNTE7ODYsPDE4NTUtOjQ0NjMzPjE2QTQ9PTI6QTc5OjUzOzQ/ODY3PjM3PDQ8Pjg6PTY5 +OjU8OzBANzk5PDI7PDc6PC85Pjc6ODI3Ojc1OC43Pzs3PjQ6Ozc2NTc2OTU6NTc0OS44OzE5 +OTI4OTc2OTU6NjY5ODc2PTA7PTYxOjU1OjcvOjMwNy80ODQ2ODg0OjM3OjE1NjU2OjE1Ozgw +NzA1ODU0PTY1OTYuOjM2OzAuPjQ3OTEvPDQ1OTIyOjgvNSs4OTkzOC4zNzY2NzM1OjY1OjMy +PTc0NzIxPDQ5OzcvOzM5OTkvPC00PDQxOzAzOzYtPTQyPjgwODQ0OjcwPDEwNjYzOjE1PDg0 +OzQxOTU7OzA1OzUyOS01OTcuPDQxNjMwOjQ3NjczOTQzOjoyPCw3PTUyPS40ODctOCw2ODkt +OSsyPDgvOjM1Ojw0Ojg5PCgwOzgyOjguPTg3OzIzPDI0OTAtOTA2OTQrOCczPzgtOS80Ozky +QjFMTEVJUztST0ZGUEBXUkdQUUJVU0hTU0dNVEJWVUVVUkBSU0ZXVUBTVUVXU0FRU0lYV0hS +TkJZT0dSU0dZV01aWENXUE5TWEFVWkxTVkVaTkhWV0FVU0dXT0tWWEFYVUVSV0VaVEpTWEdW +WUZZU0FYVElaVUBSVUJaVkBTV0lZRDlKSTdPRThIUz95dFZwd1t5cVp7eGB2dFlveFlxelx8 +d2Jxdlt7dFxxdlhzclxuclF0cVFzdVN0clhzcFhvcFRzc1h0cVlxclltck9ybFFsdVFzclp1 +cVd2cVdrbFNqa1Nvb1VpbVFpalRmcVBra1hnaUxwalRka1FoalRpbExobFJmaktpZUhnZ0xm +aE1pZEphY0tjYk1oaktkY09mZU1gZ01lZ01faFFnZFJmY0plaVFcYkdiY01ZZEJXV0o6PTM1 +OTY0Oy80PTgyOTY0PC83OzMvOjQxOzIwPjMyNTI2PDQvOzIzQDYsNjQ3OzgpOis7PjcwPDI9 +OjksOzQ5OjksOjQ4OTgtPzc6OjoxOTo0PDg3OzYuPDIwOjE3PTk2PTgzPDc1OzEyPjo3ODM2 +OTY1PTU3OD0xPDE3Oj40PzQ3QT02QTU5Pz04Ojc4Pjo7Qjc3Pzo/Qzg6Qjo9RkBLYEbf6bT9 +//T4//v///z////+///7//T7//T7//r8///y/eb9//f///35//Px/+/0/u3q+uvm+Nv0/+/q +8uXc7tfb+dzf9tTc7drc6dzV4dXt8d7g6uHg8N/x7+fi59rx+vL6/+ry/Oz9/v7t/+/1/+v9 +/vv5//H1//H///7p9+Xi/t/u//Dl+ejt++Xq/uru++rn6+L6//H9//3////u+enc2c9NUUNB +Q0E7QDNBPzs0QjQ/QTg3PUFBPjo6PDk2PTo9OzQ3PzM1PTpAPzU1PDI6OTQ0QDQ2OzYxPzA7 +OjUzPC49OjgxPC48PD4xODBAOjo1OS06PDk1PTE/Oz08PDI2PS45QDE5PjQ7PTQ6PTQ0PjQ3 +OjA4PTY6OzgyPTA4PTUxPC9COjIwPS49PzQzPTA8OzM0PTJCOzc1PDI5PjM6PjQ4PzE6OzM2 +PTQ4PDI3PjA7OjM6PzU4PDM3PjE4PjI6PDcyOC85OTc3OzE2PDk7Ny86QDk4OjA3OjM1Oi8y +NTI0ODUxPC41QDQsPDE0QDQ2PDE6QTg6PjU4OzQ6PzQ8PTI6Qzc5PTI1OTI2OzM7PjU5Pi88 +PC85OjU7PzIzPjY4PTQ3PDQ4PTA6Ozc4OzI9PDU3PDA9PDczOzQ8ODU0PTY3PC87OjQ6OTAz +PDI9PDM0PDg2OjQ3Ojc2Oi4zPjI2Pjg2OjIzOjQyPTU6PDkwOyszNzgyPDI8OTkyOTA3OzUx +QDE8OjgyPDM5PDM2OTE6OjQ0PDQ6PDk1OjIzODYyOTE0OzMxOS8zOzQxNy43OjEvOzE2Ozg2 +RTQ3PjUwPDI0OTgyQS82PDU2PS02OzkzOjE1PDg1Njc2OzI3Ozc2OzM1OTYzPDQ0PTUzPTQ0 +PTUyPjIvPDU6QTkvOzA2OTgqOyg5Pj0sOiw2PDcsOzE2Oy8xPzM0PTYyPDguPDY1QTYzOyw1 +OTsxOTM1PTU1PTk0ODEyOzQvQTU0Pjg1PjE0ODcvPDI1PTEwNy4xOjYuPS8uOTU3PDI6RzxP +ST5LUEJXUkNPUUJYUEVWVD1ZVEhXWEBQU0JXV0BXWUhUV0VXUUtXWEVQVkVcVkJPWUpaVkNM +UUdZVUZYWUtXXURWUEVVW0VaWE1SXENZV0hXWTxYVVBWWEhcVkxbX0NYUktVWT9aVkpUW0Za +WUlZXEZXWkpSWUNWVUNWV0VWSzxJSjtSQTdMWT52d111c1t4dl14el14b2FzcVZ6eGF2d1p4 +b2J1fVl+c2BueVl3dFtxd1lzc1dzcVZzd1p6dFZxdVZzclhzdVZtcFR1cVxycVhzc1hsblZz +bltwck1ya1RvcU9xb1hqblRwblpxb01tcFNqb1JpbU9oblVlalBqaFFlalBubFJsaU5naFJs +a1Bpbk9taFJlaE9mZ1Nhbk9paVZcaU9laFFhZUtmZ0hfY0tnY0poYUtgYkpaUkk5PTgzOjYz +PjU1OzQtPDAzOTQ0PDQ3OjE0PDcyOzAwOjY1ODI0Ozc1PzI4QD02OTQ2QDk1PTQxPjQ1PzEz +PjY3PTcuQDE5PDUzQDM0OjUyPTI6PDYxPzU6PzcxPzMzPTQxQDo1PTY4OzI5OzU1PzYxPDY1 +PjMzPjkzOzM7QTozQTU4Qjc1Qzo9OzkxPzc8QjgzQjU9PTkvQjk8QzhBRkZPZkX6/rn9//X/ +//3////+//r+//r///z///X7//r9//jy/eX8//r4//X6//Tz++73/+/8//n2+/Hl8OHe7dXs +/Ofo7+zI5cTh79ba6dbi9d3u/+3x++3y/e3p/+v+//7y8+Pt9+rt+eXs+ebq8uP9/f37//Hp +/efr9+vt+er4+O7q+u70/vH//fL18ur7/vn5+fjq6uLr8dzk8tzm7N3j6tre3NBUSkRDRUE3 +QTZHPDw2QTU8QT42PjFHRj86PjQ9QTw7PTE6PzY+Ozg2PzQ/Mzk9PTQ6PDc4PDI7PjQ3PDE2 +PjU7PzM0QTE8OjUyPjQ7PDg0PThBPDY4ODFBOzs3OjQ9PDI6OzU/QjI7PjU6PzNAQjY0OzQ6 +PDQ0OTE9OTI4PzI9OjU3PDM3Oi84QDM+OjA8PDQ3PC48ODg7OjE8PTI7PTI3OzU8Oi88PDM9 +PDQwPTQ7OzA4QDQ8ODYzQjM9Pjo6PDQ+OzU9ODQ9Ozg6OzU+PDU4PTM2PDI5PjE4OzA6OzMy +NzNAQjk9QjY0Oiw1ODk4PS4/PTU6OzE/PTI1Oi9BPjs3PDJBOTU7QTVCPj43OTJCPzY7ODhA +OjQ7QDVAPTRCPjk5PTQ9Ojc5Pjc6OTA+PzY6QC9ERDYxPDQ+Ozg0PDA+PTUxPSk6PDowPjU/ +QDQ4OjJBNzE1PDg6QDM5PDQxOzg1PTM4OTA4PDQ2OjY3ODY2OzgyPC02OzQ6PzE7PTQ2OCw7 +OD0yPTM7ODk3PTA3OTo0PDE5Njs2OzA/QTs2PzI3PDI4OTU1Py42OjU4OTQ5OzY5PTQ3Ojg8 +Pzc0PjI4PjMzOzQ9OzozOzE4OzMwPDA5PTYxPTU7PDg4PDo2QDU2Ojg7PTI4Pjg4PTE4Ojs3 +OzQ6Ozg0QDI6OzU5OzY1Ojc1PTU0OzI4PjsyPTI3Ojk2PS84Pzk1OjA2OTk4PDI3Py43OTY5 +PTs1PTUzPDM2PTcxPjA4PTgwPDM6PDs1PSkxNzMyODI1OTg5OzM0Ojs8OTYzPDo6RjVRUEZV +VUJRVUZRVUJZTkNQU0BbVUhSVUNWU0VVWkVcVEdeUz5ZVEZXU0JWVkhTUz1cWkxaV0ZaWktT +WEFYWU1ZVU1ZUzxaU0pcWEJVVkVcWkVXWEtaXEpWVUdiV0lZWERiWktXVT1hVUdVW0FgVUlb +XUZcXEVWT0JcUklZVEFXRDxPQTtPRTlMXkJ0elZ4eFV+dV91dVh1d195d111dl11eFp9cV10 +c1iCdV1zdFR9c1p0b1Z7dGB3eFd9bFp6cVV6c094c1l2b1twcFVyc1hvdVdxdVJzb1ZybVFz +b1V1c1htbld3cFRtc1hzcVRoaFRucVRoalN0bVFpa1RubFFqa1Npak5va01raU5ra1NnaVJx +aFFgZ05taEppbFFnZ09sak9mbE9kZ09oZ0llY09qaEtiYU5qZ0lmY0tTU0A+Pjk4PDM3PjU7 +ODE0QjA6OTUtOjM5OjU6OzY4PTgwPjU9PTk4PTc7OzU1OTM2PTY1PTc8PDk9PDs5Pzg4PTE6 +PDg3PDg4Pjg0QS86Pjk2OzU+PTk3PTQ8Pjc1Qjc9OjwyPjU/PDcwPjU6PzU5QTI7PTY9QjhA +QDY5Pjk7PzE8Pz48PjZDPTw6PDo6PTc9Ozg4QDQ9OTw2PjVBQz5BRTtSXkjf7639//T+//35 +/PX///////z///39//n5/e31/+z6/+ny/en0/+/6//by+e32//H5/+72//Tz/+z1/+vq+ujf +9ODt/+Dz//Dg89bc6Nbj+eX7/vP1//Lq9ebd7eLr+uj+9vzs7+L18vDx/Ovt+efs8+3y8+34 +9+/0+fT///7///fx/uzz//Hp/+Ho8OHh9uTs7OX9+/z19fD9/vvy9+vZ1MtXSUdARDxDQDsy +RDRBOTs6QTZBOD47PTQ8PDk0Ozg5Nzg1OTJBOjk7OjY2OzM8OjU6Pjc6OzY6OTUvOjg9Ojc2 +NDQ+OTo3ODg8Ojg2Ojk+NTs0OjdANjo5PDtCPjs2PTE8PDw7PjY2PDw5NzQ+OTM/Njo6Ozo8 +OTk9NzY8Ozc+Pjg7PDQ9ODU4OjQ+OTo4OTI8Ojk5OTVBOzY2OjFBNjo0OjRAOjg8OjlFODo7 +OzY8Pzc9OjU6OjVAPDo7QDU/PDY7OTo/PDY7Ozo9OTJBOTdBOjM8Pjk6OzI7PDo0OzE4OTk7 +ODVAPDw3NzU7NzhCOjo6PjRAOjY5OThCPTw3ODY+PDk6Ozk9PTg9OTZEPTo8OTU8NTZAODs9 +PDZBOTw8PjU/Ojk9OjU8PTc6PDg6PDI5ODs1ODQ6Ojk3QDc6Pzg2OzRBNjk1Ozk6ODs4PztC +ODQ8OTY+NDo6PTk7OTQ7Ozo+PTU8Pzw6OTg2OTk6OzQ3OjY4Ozs3OTc5ODo3OTQ4Ojo3OzE5 +Nzk5OjQ+OTg0OjI5Pj0zOzM6Ojk2Nzk+ODo7Ojk8Ojs5OjQ3ODs8Ozs6PTk6PTY8Pjo2PDY1 +Nzo1OTk7OTkzOzI6ODsyODE+NzszPDE+ODw6PjA9OkA7NjU6PD42NzU3PTY4Njg1OTQ2NjI5 +Ojc6Ojk6Njg4PTY5Nzc3PDc1PDUvNzU4PTg0OjM9ODszOzQ/ODwxOTg9OTsyOjU7Ojc2Nzs3 +PDc3Ozg5ODg2OT0+PTs6NzQ4OTY2OTk0OTQyOTQ2ODc4NDE8NT03ODU2OTo5TDNZTk1PUkJT +Tk5UVUNVTE1aTkVRUUtZVUlSUD5ZVE1XT0ZZVE9VTkVaVEtcVENXVUhdWUBbVUxfW0xXU0xd +T0dTW0liV01WUUpaWU1TVkhcV01dVExbVEtiVkNcVkdgUkpWU0ZnVE1XWEBhVkxbWkdaXE9f +WkVaVkpbV0NgVElSQ0FRRD5PPjtWVkR6e2KCd12Abl18eWB4eF17cVpzd1t+d2N1eluCc2B0 +cVx4cmF5cVp7b15zb1Z5cWJ1cV14dF10cViAcFd3cFl3b1h6c111blp3b1lybVZ1cVl0cVhw +cFh0aVVtbFh2bVltbFZya1Zua1FyaldscE5yZllxa1JraFVrZk5qaFRoZlVpaVFualRpalJp +Yk9raVFmZ1ZrZFFpZ1JpaFBkYk5uZU1oZU9sYlJhX0ppYUxeYkpeTkk1PTxBOzg7Ozs/Ozg0 +OTY2OTY3OTc6OjE7OTw4Ojg4OTk5PTg7Ozk2PTk2PjY5ODo5PDg9Ozw7Ozg5Ozo9PjM3Ozs6 +PDo3QD49OT47Oz08Ozo1Ozk/OTw6PTk5Ojs7Pjk6OT4zOzk7NzwwOjg5PTw6Oz07Pjw8Oj05 +Ozs8P0I8Ozo/PT0/Pj9HPkA8P0A9QT4/RD88Pz1BQT9CQD5FR0JRZETw97////34//D0/+jy +/+bw+Oj4/u3////////5//X0+e39//r////7/Pj1+/L7///u+Ort+unt9urr+OX2/vPt/+jd +9Njf6tji5dnb69vx/+zp8ebt/O3s8ebl9OT7/f3v+9/9/v3///f8//fm8+D2+/D3//nx++7s +/vL3/+vx+ejq9eXk8eDv+en9/vf5//Ty/fj5/+71/+/2/+/l59nY0cxLSjxJPj03PDNBPTo2 +Qjg8PjtAOzgqQTc6OzY2PjU5PDg7PzU1PzQ3PDo1PjI9PTYvPC86Ojo1PTQyPjcuPS47OjY0 +PS44Pjw2OzA3OzgzOTM7PDk6PjY3PTY8PzQ6OjU6OzQ5PTM2PDM9PjE1PTE3NDgyOzM+Ozc0 +OTQ+OzszPTU9PjYxOzI/OTU0OjY4QDI2PDY0OTc7Ojg1OTc2PDo2OjM8Ozg2OjY5OzY6ODY4 +ODY7QDU8NjE4OzY5OTE6ODo2Nyw7PTY4Oy01Pjg5ODM6PTM7PDY7PDQ7ODkzPDQ3OzUxPDI5 +OjgyNzQ6PTg1PDI/PjY2PTo8Ojg4OzY8PjU6QTg+OjY2PDA6PTQ/PTM1ODI5Py88Pzg2PzQ2 +PDQ4OjE9Ojo4PjE8Ojc1OzBAPTk1OzQ7OTk1OzQ5PTMzOjg2ODA5PTU5PDU0OjU6OjY1PTY8 +PDI2PzU4PDU8OjU8PDk2OjM1PTcyPjM6PDswPTE4OzgyOzE8ODc2OzQ9ODQxODk2OTk2PDY3 +OTgyODA4OTk3OTQ5PDo1OzIyOTU3OzA2PDYzPDQ0PDUxOi44OjEuPy81OTkyPC87PDYzOi43 +PDs2PzE4PDswOzA3Pjo5OzcyQC4zOzI0Pzg2OTM0OzU5OzkzPDU0PDc1QDY1PDU5OzYyPjE5 +ODcwPi46PDowOTRAPDkvPDQ8OzY0PDU7OjY7OTs3OjgzOzMyOjM1OzcxPjAxPTcwOzQzNjkz +OjQzQC82PToxQTQ3PTkyPDQyPjYzOjEyNjswOi0yOzgzPy8zOzg0NzEyRTZUTT5PUUBRVEZS +T0JZUklXU0ZXUkdUVkBXVkVZVz5TVEJbVUhUVU9cVkVPVEhbV0NQVUlgW0JZWEpXUUdYWUdT +WEFaXEdVWUVhW0hWW0VZY0pZX0VbYkxVWkxeVE1YWkZaX0laXEZgV0lZW0NYV0ZaWUdhW0Fd +WkVWWUFaVUhVS0BKRDhRQThKYD54d1t2eF19cVxzdll6dF50dVN8clp1d1p/cV12cl94dl5x +dVp4cFZ0d1d4dVp1b1hxdVt1d1N5c1ZxdFp7dltwcVp5cF1yc1V0c1dsdE94cl1sb1V2cV1q +bFF0c1lubE9vbVlwblRxblRwa1RxcE9na1FnaE1pbFNpa01pbFRrblJqbFJna1FmaU9sZlBk +a05paVNjZU1rZlFkaU9valVgaE5qZ0xgY09iZE1hZE1jYUlaSEo4Ozk6QjQyPDc3Pjc2PDY1 +PTYxOzk6OzU7PjY3QS01PDk1QjQ4PzkzPDY8Pzk2PDI0Qjg1OzcxQTc4PT00QTY6OjkzOz07 +PjkyPDQ6OjsyQTY7QDkzQTc0PjQ3PTg5QDc4Ozk1QTo4Pzc0PDc7QTY1PDg9PTs4PT00PjQ5 +PTs6Qzg8Pzw4Pjg8QDw4QzhFRjw3RT08SD0+Rj4/Rj48RT9QZETq9Lr+//j7/fX+//r+//v/ +//z////7//z4//D///z//vz///76//f3//H////4++/y+ufz9erm8t7x/unm9eLf7dzN6Mnb +6tfi8tfh7eDv/+zs9ejk9/f///zy/fT1+e7y//Dt7dji893w+Obs+unp9OPs/en4/PD9//ry ++ezw+fD69+79/v3///X1+/Ly+e737+rs8uP+/fr1++3t7N7d18tUQ0VARTU9PT5CPTg7PDc6 +Pzk8OTM7Pzs2QDI8PTs9OzQ2PTQ6OjQ2QTQ7Ojg2OjQ/OTsyOjM5OzowPzA2NTQ4OC8+QTw2 +ODM8OzgwOjM3NTQ3PTE8OjQ9PDk5OjY7OzU8PDU2PDA9NDY1Oi88QDU5PDNCOjYxOjA/Ojo2 +OjI/PDY1OjE5ODg4PDJAOjU3Oy49PDU3OzI3Ojc5OzQ3OjM3OjM3PDU4ODQ7OjI5OTQ/OjY9 +PTM6PDgzOTA/OTc3OjI9ODc0NzE/OzcxODFCPzg9OjRDQDs3ODY4ODM4NTg5NjcyOTUvOjQ6 +OTU2OjQ7OTI3OTM5OjM5PzQ8OzQ+QDo8OzBDOjs4OzE7Ojk6NzBAPDk7PS04OzY5PjM8QDc9 +PDc6OzM9OTE5PzI3OjM0PTI5PC83PDQ1PjQ3NjI1ODM5OTQ7PDU/ODw8NjM9OTg2OzU/OjY1 +Ozk6PzY4OjY6OjU2Ozw1NzE6ODc4OjU6NzU2OjM7OzcyOzY7OzYwPTI5NzU1Ojg6OzE8Njo6 +OjM4ODY7OTI2Ojk2ODQ4PDU5OjU2OzY7ODg5Ojg+Nzk0PDU3PDgwOTI8Pjk0OjE5OjQvOTQ7 +Nzk0OTM7ODwzOzc4OjQ1PTUxOTg1OjQ0ODc3OTg3NDYzPTQ3OTM4NjY4PDUzPDE7OTk0OzE6 +OTI2OTI7PDozPy86OzU3OS07OTk6OjI6Ozk1QDYzNyo3OTo1ODMwODY2ODMyOzI4PTY6PTM1 +ODM2PTE5PjgwOys6OjovOjA5OTssNSo7PjgwPjc9PTUyOTU2OzQ8QTtMTUZST0FUVUNQT0RY +T0BXUEdUVUVaUEJVV0tNV0dXVEZVUT5ZVERZVkhYWVFaVT5cWk1ZV0ZZV0xaVkVYVEdcVkVa +WEhhWUhZWUZeW0taWUJbWlJdWkJcU0taWD5WV0ReWkJcWUpnVUlXWkphWkhWVEZhV0dWU0lb +VUhZVEpUSDxYSDdIQTVZWUN0dVV7dVl0dleBcV52d1p8c1tyc1d2dVd2dVRzdFx7cVd6dFly +clV6bVZ5dVt4d1Z0dFp0bVRydVZ6b1lzcFh8bF5ycVV2cVVtdFF1c1dvcFZ1b1prblJxcVZu +blh5a1psalFxa1dxbVVubFZva1Rna1BoblVtaVFrZ1FoalRpbE1wZ1JqbE5tZVFlZk5nZ1Rn +aE5qYVBpZU5pZ09mYUliZE1lZUxoaE9iZkxlaFJjYUlXSkI9PDM5OTU5OzQ+PDo1OzU1ODI1 +PTQ3Ojk2OTU9PTkvPjI8ODYuPC8/OjgzPzM9QjU4OjQ5PTU2PTY4PTc7PDc5QDU2OjU2QDkz +PDY0PTc7Pjs1PDc4ODM5QDc3QDU5QDsyPTI7QD81QDM7Pjg5PDE7Pz45PDc3QDY+QDg2Qjc+ +Pj06Pzk8RTo5Pz09Qjo4RDg+QDs9QTs9Qj08Rz1AR0FQa0nv+sX+//X///v///////////36 +//z5+/P9//nw/+3v/uPz+ezq9OX0++v6++z1//D7//P7//f9//z5//ry/Orc593c7tHs++vm +897b6tzq/eft/fH+/fHq+en9//v1/+/1+/H1+ebx+ur0+u/t9vDy+eXy/PH6/erx+uzx+Obz +/u74/+/m8t7q/uzt9+X0++ft8+f9//7///Lv9e3m59fY1s9bSEU4RjxFPj07QTlHPzw2PTk+ +PDY8PTo9PTY1OjU8QDBBPDo6OjM5Pzc2OTQ+OTc1PDU/Qjo6OjY1OjU7Njc4PTU5PTg7PTI6 +OTM5OzE1Ojg8QDo2Pjg9OTQ8Ozc+OzM6QDI6PTg2PDE9OTU2OjI5OjM3PTI/OjYzOjM+NDg8 +OzE9OTk0OTc+Ozk6OjU/OjQ6QDU7OTNAOjM6PDU4PjM9Nzg9OjQ9Ojo4OjQ9OzY2OjU8Ojcy +OTE+Njc8OTBBOjg7PTI+OTU0PTE9PjY8ODRBOzo8OTc8OTE1ODE2OTM4OzI2PjI7PjQ9Ojc1 +OzI9NzQ8OzM5PDU2PDJCPTk0OjFEOzc0OzNFPTkyOzJEQzk7PDM7PDU8ODM8QjY7Ozc7PTI9 +Ojk3PjU8NzA2PjA9ODM5PDo8PjA6Nzc1OzQ8Ozs0PC47PDY2PSw6Ozc6Oy82PTk6OTI3OTM2 +PDQ5PDZBOjk2OzM6ODY7ODY4ODg1PTc6OjA4OjQ1NzI4ODQzPDQ5OjQ0PDRANzg4PDg+Pjc0 +OTU/OjU3PTY9OzE5OjY2PzY9ODo5OjM9OjQzOzU9PDU4PDM4OTU5Ojw4PDM3PDU8PTQ7Pjc2 +PjE2OTM6OjM5PDo3Ny02Njc4PTY3PjQ7OTI4PDU7Ojo1OTI7PTw5PDI9Njw5OzE+Pjs7Ojk7 +ODs8QDY8PDo3PDU3ODo4OzU5OjQ7OTQ4OTU3PDM5ODgwPTU3OzM3OjQ5Pz0zPTQ+Pjo2OjQ8 +OjU7OzM4OzoxPTI5PT0zNzA5Ojg0Ni02OzguODI0PDMzPzI9RDhKTT9UU0VTTkJWU0RXVkJV +TkFVT0dVVExTV0JbU0xUUkNhVklSV0ZeVEtVU0VcU0VVWEdfU0dfVkhWX0lcWVBcVEhZW0tb +WktfV0ldWkdeWkxdVEpcWUlaVU5jWkdaV0pWU0RjWE5ZWEdhWkpeW0RfWU1bUT9jV0tdWUNf +WEZWSjxMRjlUQzxZXT97fWF+eFp8d1+AeFZ9dFt9dWBweV6CeWBucFd9dltydVx6dF9vdVR9 +c1t1d1l8cFd8dld6dVZ3dFx1d1t5cF9xc1Z6dlx1eFl6cFhycFJ4c1d1b1V4bVVya1V2b1Nz +blR1blFtbFNzbVJwaFdwZ1JybVZvaFZta1VralJjaU5sZ1VlaE5xbVVoZkppaVFuaE1tZ1Fo +ZE5rZ05raUxqZ1BpZk9qZk1pZktiZU1qY0lhWUtYSUY4Ozs2PjA8OzQyPDQ8PTg2PDQ9Ojk0 +PTQ9Ozg2PTU+OTcvPjE5OzkzPDM9Pzc2PTQ4RDc5PDs8OzU6Pzw4Ozw+Ozo8Pjo7Pzc8PDc2 +PDY8Pjs2PjRBOToyOzU/PDg4QDZFQD0xPzhDPTozPTdDPz06QTxCRzpHRUA8Qzo9Pzo8QTk+ +QDs7RjlARTo7Qz1ARTs+PENDQz0/PUI+QDhESURZekjx9839//b9//j2/+79//r+///7//H/ +//////f///j////////9//j9//zz//nx++z3/+/0/O7u+Ofy/Ovu+OPk9uDj8dbg7trd69Pc +69Xy/+rr7+jf8N79/fv19efk/OTs/ODw/+/+//71/fHx/PLk++rs+eHy/vHx//D6//ry//T5 +/ffw9+z5/vv///////v///vx/ezp+Of99u7m6t7t6ttOSEZFQDw7PTs/Ojk6RDo8QDYvQjg6 +Qjs6PjQ6OzgwPzE8PzY2QjA4OjczOzI4ODo3PTg7OjctPzQ4PDQ3OS83ODM7OzQ3OTgyOzc5 +PTUyPDg6PTc0PDQ8R0BAPTVCPjkyPTg/QDo0OjA9PTctOjM7Pjc3QDI4PjU2PC46OTY1QTc1 +OTA4OjU2PDMzNTQ2OTQzPTM6OzQyOzQ6OTM1OjM/ODg0PjE7OTUwODA6PjYvPTI8ODUvOTM+ +OTcwPDU5OzE4OjI1OTQ6OjQ1OTc3PzQ1PjY6OjQyPDU5ODYvPDU2NzMvNzczOy04ODoyOjA4 +Ozk0OTg4ODk6OTA2PTs8OjY1PjM1ODQzOzA2OjQ2PTQ6OzQyPjE5OTc7PDY3OzQ0OzI7OTY3 +PzE5NzA2OzM2PDI3PzQ0PTQ1PTU4ODM8QDgwOzM4OjA2OTQzPDA4ODcwPjE1OzgyOy85PDI1 +QDc5PzYvOzM2OjkwOzQ1ODExOTozOjQyQDYyPTQ0PDM2OTE0Nzc2OjE3Nzk1PjovODQ1Nzc0 +PTM4ODUzPDM/PjszPzJFP0A1PDI4OTcuPC81OzoxPzkyPzYwOzM1Ozo1OTAtOzg1PzI0Ozcy +PTQ1OzY2OTEzOjMzOTQ3PzkvPDQ2OjYvOi40OzQxOzA3PTouOy45Oj03OjM6Ozw2OjE1ODI1 +Ojo3PjgyPjg0PD41OzU1ODczNDk2PDI2OTQ3OTYzPTM1PDUwPDU5OzouOzA9PTs1OzY7Ozkt +Pzg6OTYyOTQ4OzgsOTUvODA0MDguPTEwOzYwOTAyOjg6RztQVUdUTUJSUEdTVE1TUUVUT0tR +VUZUT0xSV0JTWUpZU0VVVUtWVkRVVU1cVElWVUdWV0ZXV0JcU0dXZEZcUUpbVkdZV0xcW09Z +V01ZV0NZWU1gWEpXVVJeXE1VWElfW0dXWU1dW0VZWUZcXEZgW0lbWkFcWEpVXEJYW0xXUEFX +Q0JRRjVVQUFYWUJ0eGF1dl90d1Z3d1V5dl1+d1x5elp5dl93elV1c1x8cl94eFqBd1t3dVly +cldzeFlzdFx0c1l1dlxzdFV7cl9wd1p8cl9vclp2cFlvblp2bVlvdVpxcFVyb1tqbVlwcVhx +bE9qalVrbVNubFRubVZva1RxblVqb1Vra1NpbFBxaVZnblBsaFpiaU9talNsbE9pZlRnaVNj +ZU1oZkxfaUtpZk9qY05kZE5hZExfZEtiYkdVTEU1OzoyPjQ0PjcuPTM5OzsvPDNBOz4tPDM5 +PjksPTI4PDk1Ozc1PjAyOjY2Ojc4Ozc2PDgzOzY4QD04PDk4PjY2OTgzPTU3PjE2Pz01PS43 +Ozo3QDE9QDw4PjQ8Oz08Ojk2QDk8PTs7RT8+REE5Qz88QD4zPTs8Ojk2PTg6QTg7Pjw2Qjs5 +QTo1Qzo7Pjs2Pz0/RD09Qz48R0JART9JR0JMYkzr+rry//X6/+3////8//vz+en+//v7//n0 +/u/4//b2/+X1/fXt/+X8//b4/Pjx+ez1/vH5/+/0//Dv+ufh9eLg9t7c99Xn9trk8ePh6N/v +/+n4//fx+/T3/+74+e/4+O3z9vPy8+Po+ez+//b5/+zz6+zk8uPw+Ozq/ubq/err/Of1/vX0 +/ez0//P0/eny/Ovt6OLm8+f8/fLz9evx9+rd3cZSR0k/Qjc6Ozs7PzM0OjU8PTctOjY/PTYu +NjM/PDgyPTNAOzMzODs7PDg2Ozc0Oy46PDQzOjA8Ojo2PTM2ODcwPDQ3PjY0ODc7OjkyPDM0 +OjQ2OjQ4OzY1PDc6OjQ3Pjk5OjQ6Ozg0OjI6PDk+OzU0PDQ4OTUzOzc6NTg2PjE/OzkwPS84 +PTgwOjM5NjUzPDE4PDU1Ojc6ODUxOzI7ODUxOzI1PDQ1NzMsOTc3NzY4OjU3NjU3OjM2OzE8 +ODQ3OzU8PDYyPDQ5OTQ1PDE7OTU2OjU5Nzg3OzI5OjcqNzM2NzA1PDQ3OjEwOjI0OC44ODY3 +OzUvOTc5Ojk2OzU2Njk1OzE4NjMyODM7OTcyQTA7NzgsOjA9NzUwPzJBQDozOTQ+OzgzNzc8 +OzM1PDI4OjcyOTcuOzM5NDMxOTY0OzQ3PDc7ODM5PTk0ODE0ODU4OzQ4OTozPjc7Ojo1PDA7 +Nz03OTA0Ojk2PjkxPDQ4ODc0OjM6Ozk0OTk3ODY1OzU6NzU1ODU3ODY6Nzg3ODc2NzkvOTg4 +PTYzODQ7OzozOjU3OzgxODU5OzYyOzc0PTk6ODU3PjQ6NzkxPDE5ODsxOi4zPDgzOzQzNzQz +PDYxPDU0Ojc1PTQ1Nzg1ODQzPD06PTQ5ODw5OzU2Ozc3PTU1PzE3ODkyPDs1Oj41NzA7OTkz +PTQ3Ozw1OzY2OTUzNjY2ODk2OTY3Ojg1OjY1NDcxOTc1Ozc3OzYwOTU1PjE1PS8zPDI3PTs2 +OzM5OTgsNy43OzgvPDg2OTovNy82Nzk1ODQ1OUA5STRRTEhMTkNWUUdSUUBRTU1SUEdUVEJQ +U0NbUEBWVUVYVUhTVUlWVEVWWEVaV0pVV0NaWEZUTz1eV0tVU0hcV0tTW0ZeV0dVWUdiX01d +U0tWWkZbWUxXWkliVFFdW0tYX0daW0pYW0haVkdaWUZgVUpYV0hcWk5YW0ZiXFBaVkRVRURY +RjJRQkBZZUl9emF5dl12d1t7c1t7fVp8eV52d1x5cVt6dVt4dVp4elp0cVpyclh1c194cFty +dFh7dFludVh9bl1zcFt6cVh0b1t6dVh2c111dFlyb1tqcVZ0bl1ydFdvbVhqb1FxblZubFVx +aVRybFdqbFZvbldxb1RybVhsaVJtalRxbFNtaFFraE5oaFBqaVJqalBsaVJiaE1paVBjZ05m +ZVFlYUloYFBkYUxlZU5gX0hhY1FjYEhPSkU8PTs5QDsyOjQ2PTU+OTczPjU4ODc3Ozs5PDo9 +Njo2PTU8Pjs0OjQ8OzcuPjQ6PDkxPjY8PjY0OTNBPzwyPjY5Ozg1PDM2PTw2QTw7PTk4PTk1 +PTg+OTk+QTw3Ojg+Ozk5QDg5PTw4RThBQj40PTk8QEAyPTdCPzw0PjdBRDs2QjtCPjo7Ozo/ +Pz0+Qj06Qz1BQUJAQT9AQDw8R0ZBQj5Na0/e7bX7/O7////z//P1/+j///7///////////z9 +///x++P9//j9///n+Ojx+uT4/+z5+vTh893v/uXk7eHk6+Pa6trg8tTo8uXd7tfg69/p6uDk +793u/uzr9+zp9uzw9uz1/u7u/+r9+fnq9Or3/u/z/+z8+vn79/Dt+ef9//3s/enx/Or1/Pnx +8u706ujq9uj+//v5/vr5+e/w8unp+end19BRQUE3PDk5QTU0PDI9PDo3QDc8QDs0PzQ6Pzg2 +OzE7PDgzPTZBOTowNzc5OjY5OzAuOjc1PDM5Nzc2NjU6PDMyODU2PTQ0OjU4Ojg1OzI7NjYw +NjM9PDQzODNAOTo7Oy86OTdNRUk3OT00ODY9PTo1OjYzOTI1OTY5NzY2OTI1OjM1ODM4Njg1 +PDU6OzEyOjA7RjgyPTQ+NTYvPDFAOTkvPDU9ODQzOTM/PDcyPTc5OTU6OjM8OzU3Ojg2OjY5 +ODo5PzY4PTU4OjY5NjM3OTY4OjIzOTk2OTAzOjgyNi80NDgwOzA0NjgyMjE3ND83OjA2OjI4 +ODY2ODQ8ODcxODI+PDgxOS89PDQ1ODU5PDQ0Py83Ojc1OjI1OTIvOjEzPTM4ODI3MjQ3OzM4 +PDc2OjExOTU1OTA0NzQzPDE1OzkxNy87Nzc2ODg6ODUzODQ3NjQyOTI6ODYyOTg3ODc0Ozc1 +ODQ8NjY2OTM0NTo5OzMxNzo1ODUyPDY4PDk1PzQ3OzgyOzM4ODgwOzI3OjwxPTM5NjkwODAy +OjQwOi84PjgvODE5OzYxPDU1OTM0OTYvOi8xOTE0PDQxNjE1OjI4NzE1OTU0Ojc5OToyPDI3 +OzQuPDA4ODo1NzE6OzkvPDQ5OTsvOS03OTo3QDc2OTk5PTg1Oy8zPDkuOjM2OjI1PjMzPDUy +NTUzPDo1OTcyQDE3ODYuNy85OTotOTA2OjwuOzQ2OTgvPDc5Njo3OzMxPTc0OjgzOTE1ODc0 +OzczNDo2OTY3NzgwNTEuOTg6OTc6OjQ5OzcyQjhQTEpPUUVVUEhWUENWU0pQUUJSVkhYT0BT +UkJZUUdTVUZXVEhWVUFXVkxYVj5bUElWV0ZWVklfVktWVkxYVkRVVk9dVUdWVEtfWkNZV0xh +WEVbW0xcXklfV09dWEFZWUtdXklhXk1ZWUVhVUlZWEpZWU1aWEJeUklWWERfVEpPRzVURjlR +SThha0t7eGN6fF51fF13dlR1c2F1bVhoa1J4dF54eFx6dFt1bVZpZU5sblJ8d11udlV5cVpy +clR6cFt2b1d6cVhzcFh9cVRyclp0dVt4bVhvcFhycVR1cFlyb1JqbVZpcFZybFhsblVxbFhr +a1R1a1VrbFFzbVdsbU9ybFVla0xuaFVjb1BsaVZka1JjaVBsZ05raE1pZU9ma05nZE1iaEpf +XktpYE5cZEtjY09cY0tjZ0tcYUlSR0QvPDY+PDwtOjM7OzgwPTU2OzgyPDg0Pzg2Pzk2PDI6 +Njc9PDc6PDczPzc4PDczOzs0OjczPjg3OTQ3OTk+NzQ4Pz03OTQ1PTc3Py87PUI8PDg8ST0+ +Pj86Qjw6Oz45Qjg5Pjk1QzY7QDg2PDk9PD4zQTM6PDk1QDU7Pzc7QD45QTs9QT87RD07QD4+ +OjxBR0E6Qj1BR0FBRkJBQD9AR0RPZUru+bv9/+////7///3////7//X7//X///////z7//n+ +//T3//Xz++j////9//r0/ffv9+L5//L4/fjt/ujp/Ojr/+ng9trZ49rk8OHU4NT2//Pv/PH1 +/fDs+en1/vHt/ejx9er0/vLq/O/5++vy/fL2++ry//X///v8//H9/fzy9ejs/O7v//P7//P5 +//rz9e/k69/z/eru+u71//Tw9unl5c1QRUs6QTo7PjkyPjc0QTYzOzY4OTg6OjY4Ojg1Pjs+ +PDg1Ozs5NzM2PTo6ODMyPDk3NjkuOzU5Oj81OjU8OTctOi0zODgsODA5OTY1PDE4OjQvPDM5 +ODYxNzQ+Ojs0OjU8PDU3OjMvODQ2ODI4QTc3ODY4ODozOjQ2OjUzPTQ2OjQyOjQ3NzUyOTA3 +NjkxOS46Nzc1NzM2PTg0OTE5NzYxNjo2PDYzODUzOjI5OTYwOzQ5OjU1ODU5PDc0OTU3ODQ3 +OTQyOy46NzgyOzM2OTYtOTQ+OjYvODI2NzQtOTU1PDEtODEvOjQ2NzUyOjQ1NzY3Ozg0Nzk1 +OzE3NjMzNzM3PDEwPTYzOzM1Pjg0PTI2OjcyPSw1ODo1Oiw1Mzo4OiwuPDw7OTMzPTI3ODA0 +PDM2OTYzNjU1OTUqODE3OTcxODM3ODE0NzYxODQzODYzNjE5Njs4ODk1ODgzNzU3PTcxNjYz +OjEyNzk0OTY5NDgwPDU6OD01NDE6ODkyOzE3OTUtOjg1ODgzPjc5OjI3PDg1OTQyOjo1OjEy +OzYzOzY2Nzk3OjE2Nzk0NjcyOzM1Nzg0PTU4Nzg1OjI4OzcyNjQ2OjoyOy82PTgyPjMyODY0 +QDI4ODYwPTU3NTczOjIwODU1OzcuPDgyOjE1ODg2NzkzOTs0OTM0OTMwPTE4NTosOTFPTUg6 +Ozg4OTkxOS01Nzs0OC45OjsxOjY2OTsyOjU0PDMyOj06NzU3ODExOjQvOTIyOTcyPDc0OjYo +NzAxNDYqODE+OjgwODA6OzcwODU2OzY1RjZSTkhLUEVRUUVQTUpOUEJRUkpYVUJTUk1TU0NX +VUZXVUdbUU5ZV0hXT0xZVkhVV0hcWUpZV0JUWVBVUEZeWU5ZVT5aWU9ZVktaVk1aVEldZE5c +V01cW09eXEtbXURXU01aW0RfX0tYYT1cVk5bXEdiWUxjXUJcWEtiV0hYWEtUQkFESD5MRjtV +akx8eF59cmB9d1Z4cV95cVR5cV94eFp6b112d1mBeFx6cV15bll2c1x2cVx5c1Z4dVh6cFl4 +cVp5cVtxdFp0bF13dFV2blx1clZvcFV0c1twcVdzblprbFdwbl9rcVdrbVVrbUxzb1h0cFZv +bFlsbFBza1Rrak5ralVrblNralZwalVlbFRsZ1RraVRuaVVpZE9mbU9wZ1BqZ0tiZ1JhYUpo +ZVNdY0poYlFdZUtlZE9fXkdOQ0c0OTU5QDY2PTY1PTQ1OTYzPjYwNjEzOzQzOzQ0OTIyPTc4 +OzowOjQ2PjcsPDIzOTctPjZANzoxPzc8PzwuOzdBQDs4ODhAPzk5PDoyPTs3PTw3QDg6PDw2 +Pjo9PD44Pjk5OTo1PTs4Pj02Pz04PTc7Pz05PDk5PzsyPTQ7QUQvPzY6PD49PT46QEFBPzs/ +RUE8QD41RTlGQz8+RT48Qz1LbEnr98X+//j7//r9//ny+/D+//P///r///z///71//js+d/y +8ubz/+37/e/s8PHt+OD8//vq9+ze69Tm8eHr9eDk9OTa79PY7Nfg697N4cvu9+3s79/i/Orz +/fLj69nn7+j5/fz7/e/s+unx9+3q9+nq8+nr8eLj9uHs/+zp/+z69fTm7+Ht+Oz0+unr8OL3 +/PX29/T5//Lu++7///Ho7dzeyLxFRkNHQzkyQTxBQzsxPzg4PTE2Ojg0QDA5PjgzOjg9Ozow +OjU9ODY0PS8zOjcwNzE1Ozg8OTY6PDc1ODc4NzczPDM5OzM1OTY4OS8zPDg4PTMzPDQ6NTg0 +OjM3PTUwPDM8OTgyPDM8ODczPTI3OTgwOjQ6ODoyOjE3OTUxOjIzOzQsNzQ3OTkyPTYzODY4 +PDM0ODA0OjM1OzM0NjM7PDY0PDQ1NTY0NzI6NjkzOzQ3OjUzPC84PDcwOi88PzcxODQ6Ozgx +PDM5OTc3OTc2OTU4ODk3OzM1NzEyOjItOTUyOTE4NjQxNi8wOzA0OjYuOjM5ODkuOyw1PDUr +OjA8OjgvODI8PDc1NzM3ODU3NzM2Ojc1OTI2OjU3OTYyOjU3PDgvPDU7OjIvPjc0PTE6OTku +PS04ODsvPC82PTc0OTI4ODs1NTEyNzgyOzQyOTYvNjYyNjI3OjMyQTU1OzMwOjI2NzYyOjEz +Njg4OTU1OjI0NjcwOTc1PDQuOjM4OzQtOC83PDc1ODQ3PjkvPTUwOjYtOjEzPDQ4OTgzPjQz +OjMyOzU2Nzg0OzM1ODQuOzI1OTk2PDcxPTQzOTgxPC4vPTkwNzE0OjkzOjUzOjgzOy8zPTIz +QDQwNzEyODUxOzYzOjkvPTIvOTUtPTM2ODgzOTM2Oz01PzUwOjgwOzYyOjg0PDc0Ozg0Nzcz +PTUzOzAyOjEzPDI3NzQvOzI2OTQxPjA3OjYwPzQ5PjssOS43PDYyOTM1ODosPCwyNzkuOS8z +OjsvPi8yPDgrODcsPDEtOTUzOzc3SDdOTkRKUUFQT0dQVEZSU0JTVk9XWUZRV0FaVEVVVEVb +V0dVVUVaWUhSV0hZWkdVVUVeW0VdV0tcVkRaVUtcVUpZV0taWEdXXElZW0NcV0VaXExWYEta +VU1fXEhjXUxaYERgXk5WV0BeXEhZWkRbX0tfV0VaW0xYVkpaWUdhWkVJQT5USDhLSDZiaEx4 +ell9eV+Aelx5d199d1x3dll6d1x0clV6c1xweF17eFxsc1Z4cVhydlR3d1t6eFl0d1x1cWBz +dFx6cWFxbVV4cV9zdFl0d1x3b1d0c1lxblFwcVV0b1RvcVd0cVlubVlvb1dzclNqcVdwbFNt +bFRta09qbVFpbFNnbk1taVFpalFpaFFpa09iak9qY01naFVlaE5kZlFlaU5jZ05kak5hY09l +Z0tfZk5hZUpkZlBjXEpIRUIzQDUyPTkvPTM3PDQtOjQ4OjgsOzA5NjcsOTE8QDgyPDI4PTYv +PS82QDkzPTM2PTgwPDk1PTIzQDYyPDQ1PTU1OzIzPTg3OjovPDU3QDwyPzM6Ojc2QjY/QD8x +PDY7QDoxQTQ9QDotPzc/Qz02QDo7Pjc5Qzs0OzY3Ojk6PDg8QTo3Pzk9Oj48Qzw6QT09QDo7 +Qzk/REA4QzRDRD9BRjtQfk3x98/9//f///////j///n///7////9//z8//L6//f+//D///// +///////7/Pz5//D1/+z3+/Xx/+b+///z/PDn9uTW5M/h8tzh6tze69jl+eTp9ufl8+Ld99v3 +/f31/+/q8+Dq+ebz/PD4+PDr++j+//37//P69fDy+/H9//f3//P7//v9+e/p8uj///z1//P0 +9+7z+uXr9uPf6NTh7t3g0clJRUM+QTs2Qjc7Pzo2Pjc+PDYwPi8+PTEvOzQ+OzYzPTE9OTEz +PDUxOi04QTIyOzE4PDQ1PDQ+QDcuQTM2OzIqPS81OTI3PjI1OjE4OzI1Oi03ODg0OzI3OjQu +QTU4QjQ5PjAyPDM5Ni0xPTMyPDAuPzA1OjQvPy43OzYxODE5OzYyPDA1OS8sOy41ODQ2OjEy +PS80OjI2OTU1PTI2OjAyOy83PjM1ODE0OjI3OzQ3QDUzOjE4PDYxOjA8OzY1OjU8OjIwPCs1 +NzYuOjE5PjM6PjA7NzUuOzA3NzIwOTE0PTQyOjQzOycvOjE0ODM1PjEyPTA0PDA4PTY3OS43 +OzEyPDA3NzYwOjI4OzUvOS89OzYvOy45PDMyOjFAPi8xOTE0PTQzOTAuPS85OzE0PTQyPjE0 +ODA3PDIuOTAxOC8yOjEzOTE5PTsyPS87ODsyOC48PDkyNSw2OTc0Oi84Ojc1OS8zOzU1OTUv +PS82PzMtPDAwOTQzNzAzOTQwPDM0OTY3OzY2ODI8PDk3Oi06PjUvOi43OjgsOS82OTI0PDE3 +PjItOjU0OjMzOTIyPDE2PDcwOiw4OzwyPy87PjsxPTQ4OjQ3OTE2OzI0PTQzPTI1PTgzPjM0 +PTg0PTUxPTk1PDE0Pzs2PjU2Ojg7OzcwOzA3QDc2PC43PDcxOi83ODQxOjE4NzkxPy4vPTUx +Pi81OjU2PjMzPDgzPTA1PzYwPjQvPzE2PC4yPDYyPS02PTcuPC05PTY0Ny81ODQxOjE1PTgx +PC85NzcvPDE3NDkzOjA1OzQ9STVRUklRUDpUVUlOWEhZWDxWVUdUV0ZTVUVVVkVTWUBZWEhZ +V0dfVkpSVkVZVkZaWENbWEdWXENgVEhVVDlgW0pSWEtiWUhTX0RbVUVfW0JYX0VVXEdaWUxb +XUlhX0ZiWUhdXEFgYkpeYEZYXUZjXEhfXEViVkhbWj1bXU9WVz5SRz1QSjVRSD5kbkp6c1x9 +eVp9e2F1eFpyeVeAeFh6eFh9dWJ1e1tycl6Ad1h4dVl7eVl0e1h5dFZudFh9eFdsclF8dFhv +bll0dltycFt9c1Z1dVZzdFRzc1dvcVJ1b1dvdFZyaldqdFNyblNtcVlxb1RvcFFoalBta05r +alBqaE9sak5kblVvaE1qalZnaUpkbU9vaVJrbk1vaVFmaUxmZU5iZ0lmZ05fZUZiZE5gZUdk +Zk5rZkhiZE5dXkpKQ0IyPzU6PDc5PTY3PTQ5PTc3ODgxPC40PTMsPjM4OjI0QSw3OjcvPDA4 +PjYxPC86OjM0Ois9PTMtPjM/ODUyPjA5OzU0OjY1PjExQTc3PDE7Pzk6QDg5QDg+SDo4QDg9 +Pjg3PDM4PDc0PzM8QDo1PzM+OzwyQDc7Pj0wPTc/QzUxPzZBQzs2RDo7Qjo+Qjo+ST09Pz08 +RDs+Rzw6SDw8TDxcmlH0/+P9//j6/+7////////////+//j9//v8//Xy//D5/+v4//T1/+r6 +//P///v6//vy/PDr9+Lt/uzn+eLn9uPY7NXX687o9ebd69PS5dH3//n1++/1/fv1+vDs+fD7 +/ub0++vz+/Dt/uv1//Dr/efz+ezl9Oj7/v3///fk99rv/fH0//D2/fr7/+/x+PPu9+Hl5drp +8u39//r///Xy8uvj0MlJQkE7RDk7PDk1Pzo8PDQxOzc2OTU1PDc4PTYuPDU6OzQvOzA9OTg1 +PDM6NTo1PDQ4PTgsPjEzOjQ1OzU4OjkwOzM3PDU0PTY3PDM0OzE4NjYwOTk2PDMwPDI7Ozk5 +PTI8OTc2PDE5PjMyOy49OjgzNzE6PDgyOzA8OzoxOjA3OTY6OTM4Njo1OTQ4NzE6ODYvOzU2 +Nzc1NzU3OjM8ODIzPDcxODIwODI5ODctOTM9OjYuPDJAODcvOTJAOzUvPTQ9ODU4Nzc3OjQ4 +OTUwPDM5OjQ6PTQ2NjQzOTI5OzoxNTE0ODY1NTQvNjAyOjgyOjQ7ODw0OjI6ODs7PTQzOjk2 +OTAzOTY0OjM2NzU8PjYyOjQuNTI2PzU3NTg1PDQvODY2OTI5NjI4Ojc2OC8yOjY1ODQyOjQx +OTE1NzcvOTE1OjY0Nzg5OTI0Ojg1OTk1NzU5ODE4NjgyNzE3OjgvPDE2ODcwNzIyPDkuOzM2 +OzQwODE4NjYuODYzOTY1ODcxNDM1OTw1NjczODY1OTQ2OTM5ODkwODM0OzYwPjA3ODkxOjM3 +ODYuOzA2OTgwOTQ6OzsuPDE1ODYzPDQzNzgvNjU3PTUzOzQzPDYyPzMxOTQ0OzIxOjY3Ojc3 +PDo3OjE0OzcwNzU6PDkuPDI4ODczOzA6OzkyOC45Oj4yOS43Ozo1OTA2NTwxOjszOTMyOjEy +PDgzOjYxPjc0QDg2OzUzOTQ1OzcxPjU6ODYxPTQ2OzMwPDE0PDYyPDA5PDgsPjQ5PTgsODQ2 +ODczOjczPzc3Ozo5QTNFTT1WTEBVU0dTVENXU0VXVEVXV0VVU0dTVUJVUUpTWEFZVk1fVUdX +WU5WWUNZWUxWV0VZWk1VWEhYV0lbWkpZXEhbVU5YWENfWFBaU0daXEtXW0BbWUlcYkRTW1Ni +XkdaWkljXUVaWUdiXkhVXk1gWkReXUpgXERYXFJcXEZeVkpLRDlaRj1MRjZnalR8eFqDdWR5 +d118eF55eFdxblhyeFt9cVx1c1t8eFh5emB2d151c114dVt3dlh5b1pzb1h+dFdzeVx9c15y +dVh5c1pycFl1cF1sbVZyblx1c1R2a1pvblNxcl9yb1Z0bFhzblFxclJ0bVNpblZqblVrb1Rt +bVVybFduaVJqaFdoak1rZlRmak9taFViZ01laFVkaUxlZU9lYkpmZVJjY0liYk5kZE1kZVJj +ZExiZE9kXUxJQUM1PDg4PTc0OjU8OjcvOzI7ODozPDM7PDoqNzY7OzYwPTQ+OzczNjVBPDsu +PjY8OjkzPTY3PTQyPTU0PjY2OTczPTc7Ojg2ODs3OzcuOzY2PTU/Sjs9PTw5P0IzQDY9PEEz +PDc6Pj44OjU1PT40Pjg2QD48PTs2Pzk+QDk1QTg+QTk4Pjg+Qj43QT0/Qj07Pj06Pz87QT0+ +Pj8/R0FFRUJgjEvs9tL9//f////+//v8///9//f///36//H1/u71//P7/+n7/+/8//X2//D3 +++/q9ubw+uj6/PL19u/h6tzw9Obv+PTg+Nrb7ODZ5tLY59Xr6Onq+Orz/fft//by7+ri8eP0 +/Pby/ezr8unr++Pq8uXn+eH8//v///r18evr8O30+Pnt/eby/ejy/+75+fH0+/L8//f5/+7u ++eXm9+Lw8uXYxr88SkNBQUA2QDY3Pjk6PDY1PDY3OzQzOjQ0OjI2OjY5NjcxNjc2OzgwPTE2 +OzktOi84PDgyOy0xOTQtQC45PTc4ODY0Nzc2OTc1PDY2ODM3PDM0PTQ6OzE3OTQ8OzQzPDM8 +PDM1ODA6PDUrOSw9PDYrNzU+NzYsOTM4PjYzNjM2OzU1OTI0ODU1NzQwOzA1OzExODA5PDMt +OjM0OjQvPTA3OjE1OjQzOjI1OTMzPCw6OjQzNy81ODU3NjEzOjUzOjAvOTc2NTQ2OjQ2ODMz +PTI4NTUvOjAxODQvOTAyNDQvOS0wOTMvOTM1NjIxPDQvOTIxOjY0OTYxMzU4OjQyODA2OjU2 +PzA2OTMyODA0PzMyOjA4NjUxNzQ3ODgxOi4zOzAtPDM2NTQyOzA0OTE0PTQyOTMsPDIzPDI1 +Ojo3OC8zNTM1OTAzNzQ1PDY2NjI0Pjs0NzA1NzkvOC83OjUyOzE5OTYqPzEzMzcsOTI8Ozov +NzM7ODgvOC84Ojg7NTMsPjcyODI1PDsxNzM0PzQzOTI2NzI2NzQ1NzUvOy84OzUzPTE1Nzc1 +Oi44OzswOCs4OT40Nis2OT01OC0yOzg3OTcvOTE1NjMxOjExOzMxODM1Pjk1OTQ0OzI0ODUy +OjU5Nzg0ODI3OTkxOzY+OTozOTU7NzYwOjU7PTk2NzI2OTc1PTo2OjIwNjYvODM1OzgsOTQ7 +PTcwOi4zODYxODc3PDU2NzYvOjY3Ozs1OC02OTYvPTQyPTsxNi80OTkyNjItOjQ3NzExOzA4 +PzQwQTQ+RzxEUDlPUEZOTEFPUkpcV0VPSUpWVEFWUEdYWEJST0xYVkhOUUNcVUNVVEZVVUhV +U0pYVEpXWUpWXUVXWU1XWEhcV09WV0dZVkxXWUJfWE1YWkBXWUxaYUFbWUxZW0ZiV05eXkNY +WUtWXEVhWkdUWkhiXEZhWklfXEpZWUdgYUdVWERbV0ZKRTdUQzxJQDdnbVJ2elt8eGV2fVuA +cltzd1h7eF90elt0clp8fGB0dWN5cWF8dF50dF1yc1l1dVx0cVR2cVh7c1lzdFR7dlpydVp5 +cFt1clV2cFhxcU92b1huclN4bltwbFJybld1blVtblhxaFRtaFNwaFFrak1qbVJra1NtaVVt +ZlBqbE9talRjak5mZk9oaU9oalJiak1tZVJjYk1WVURfYk1jaU9jX09jY0tkZE5jYUxkZU5j +YUxnVU1DQj46OzYvPDYzPDU1PjYxOTA6PDcuOjM5OjgwOzQ4OTo5OjU3Ozs3OjIyPjU0Ojcz +PDk1PTMzPDM0PTYwOjM2PTwuOTU4NzkwPDY6PjgzPzw2OjM3PjQ6OTc5PTc0Ojk5PjY4Pjs3 +Pjg3Pjo6OzU0QDY2PjY2Pzw2PThAPkI8QTg+PkA6QTQ/QEA5RTpCQz43Qzo+RDg6QTtNS0hB +Rj5BRD9jmU35/ez6//P+//n2/vX5/+z6//T7//j///r////+///9/e7+//31//fq9eT2+ez+ +///y+evt/OX4/e/4//D3/fPg9NvZ7tXl79rf7N3f8N/u+ufi9OTq8efx/Of3//bt+ev1+O/1 +++jt/evu9e39//32/ev2/vHz/+/6//f+//Xx//H6//v1/e/x9+z0/ezu//D1+/Dp7Nbw7+Xq +8+fm7OPbxsZPQkA6OzlBPDk8QDk+PDk2Ozg6Pjc9PDk+QzlAOTo2OjU9OTg4OzM+OjctOzhA +OjY8ODk/OTk4PTU0NTY3Pjc6PDQ8PDk9Ozg1ODQ5ODQ2Ozg6ODs4Ojg3OTcyOjZCNzk2PDU+ +OzczOTA9ODk2ODE8OzkxODU5ODQxOjI3OjU0Ozg6PDU1NjA6OzY4OTQ1Nzk7NzQ3OjcyODQ7 +PDU2OTQ2NjU0NzU8OzMzPS8/Ozk1OjI+OjQyNzE1PjkvPDI9OzM2OTA6OTUyOy43PjY2OTc4 +OTA8Nzc4OzY1NTQ4NjY2OTA2Ozk3NDM6ODk0PTI/Nzk1ODY7OjgzOzI+ODsvOTA6OjY1ODU8 +NDY0Ozc7OzoyOjk3OjM2OjE0PjA7PDgyODQ5PDM5OTg9OjU5NjY2OjM5OzsxOS05ODk4NzU8 +Njw2Pi44ODw3NzA7Ojw7ODI4OTg7NjU2OzY0OjU0OjY6ODg0NzU9ODk1ODc4OTcyOjY1ODQ3 +OzYsNjQ5OTYwPTE6Njo1OjU3Ojg2OTc+OTgzOzIzODQ5Ojs0NzI1OzY0PTI4ODUzPDU6OTsz +OjQ2Nzc1Ozo4NTY2ODY3NDI4OTo3OTM5OTg5ODY7ODs4OTE1PT07Ojk0OTQ3PDcyOzY7Ojsx +Nzc2OjUxOi86OT0wPDM6NTk4PTU3NTk1ODo6NzgzPTY6PDo8ODU2Ojs7OjU1PDY1PTg3OTk5 +Ojc8ODc3PDc3OTc1OjM5PTc0PjM5QDwxPTg7PTs1NzFBPD40OzE2OjwvPTMwODg3PzM3Ozw7 +QjxBRDRFSz1RTUFWUkVRT0VTVT5STUhUVkhZV0dXUUlaUkRUVkhZUUpZWkZbWUZTT0ddWEtW +VkZiWEZSVUhaUU1cWUhZWktdWkZaWkdaXUtdYEleXUtaYEdcXE1fW0hdW0tiW1BZYkRiW0pb +XEZmWkxbVT9jXVNcX0ljYE1dYUlgWkpfW0NiWEZaRTxUSTtQSTtnb0x9cGV9dlqAdWF8d1l7 +c199dl59dGF9c1t7cVqAdlx4cFuFeFp5dld9dFh0dVh1eFl4dF98dF12cGB4dWB/cmFzcVt4 +cVdsclV9cV50bll6cFhwb1p5bVV3cFl2dFl0blhua1Vxb15zb1ZxamBvblVualN5b1VoblRx +aVRsaFBuZVJnZVZwalVvalNtaFZnaFFpWVBZUENjY1BlaE1qZVFoZUxkZFNmYU1qY01rZFFf +W0xGQT46PDs3OjQ+Ozk0PTVCOjs1NzU8OTs4PzVBPzg1NzJBOzo3OjI8PDs0PDU5Ozs1Ozc6 +Ojk2Oj08QTU4OTs8PDo8OTg5OzU0Ozc8Pzo2OTY/Pjk2OjVAOz81Ojc/Pj40PTdFP0E2PjVC +QD00PzlDPT42PDVCQjw7QTw8QjpAQD9DQj5BQzo/RkI/PD46S0FCPj1AQT83QTU+QEJCSTxI +R0dekkb0++L8/+z///////r////9//v8//f////+//z5//P4/+rx+en6//D////////0/e3v ++un6/fDz/PLu9Ojd6drc7dje9NXj+t/j+t3l9N7r9Obw9efo9+j1+PPt6+Xz+PT1/PDx/+vy ++eXm/ef0/ev4+/X1/vL0/PP5/e7y//Dr+eHo/OTt/e3y++jd8t38/vvq8eb4/vr///X1/Ovj +79TZxMJCQD87QDc2PDM1PDk2PDQ5OjE2PDU8OTU3PTw7PjE2OS47OzQyPDE6OTgxODA6ODUs +OzM2OjYtPzE4OTkyPC46Nzg1PDE3NzkxPzQ2PDcwOTI3PTY0PjI4OzM2PDM0Ozc0OjIyOzAz +Oy4zPDQ0Oy87ODMuOS80ODEvOi46PzgtOzE2PDQpPy42OzQ1Oy47OjUyODI4ODMzOjA1OjM1 +PDA0NjEvPDQxOiwzNC41OC8zOzE4NzIxOTE1OjIvNzA4OjkvNjA+OTkqOC08OzIuNzE5PDMs +PjI2OjEyNjIwOjUxNDMvOjYzPDMwOy8vNzIzPjE2NjAwNjEyOS42NzI2ODM0NjMyOS4zOzcz +Ny06OT00PCw1NzU2Ny0tPTY2ODE2OjI0NzAxODQ5NS8xOjE6OTMuPDEzNjMyOzQyOjIzOzcy +NS80PDQyNzMzOzIwNTA1OTUuPDE0OTIwOTE2PTIuOjU0OjQ1NjYqOTAwOTgqPS80OzgtOTA3 +OTkvOTE4NzUwOTQ1OTU1ODsxNzIyNTAwODE1Njg0ODI0OTY3PDQxPzU3OjEvOTIyNjQvPDMy +OjQtPS41OTUuOzA3NzYvOS42OjYrNTE4OzoxOTQzOTQxOi84OzAyOjU0QDUyOTQuPjUzODE0 +Ojc0PjQ1OzQwOzA1OTYvPjM1OjgyPDA2ODUvOy81Pjk2PCw0OzgvNi84PTgzOjA1OzgxOjEx +PzE1OTYxOTQ2PTY4Pjc3PjMzOTMzPS80PjYsPS40NjYuOjExODcwPC44PTcsODQ6PTgwOzE9 +QDUuPi1GSzxST0JPUURSVElRUEBWUElUU0FTUUNTU0FWU0ZWWEZTWEdTVUpWV0ZZVUtSXEJf +WkxWVkNaWU1ZV0ZgWVBZWUJbWkhaWkZZW0lZXEhZW0VhXEtfWUdcWE9dX0VaW0VdW0VaVUli +Wz5VXEpiX0taXEthW0JaV0ZgVUVTVEhiWEFFRDpWSTlESTRkcE57d116e1h7e1p0fFh3dVpy +dlh5fFt1d1Z1cmF0dVp3eVh3eFV5e1x2eFd1eVl6dVh5dVl2d1x7dVZzdll0clVxb1V6blhx +clZ1dVZzc1RzcVpycld2dV1vblJvbVhucVRta1ZtbE9sbVNtblFvbVVralFvaVRvbVBma1Vq +bFNtc09qaFVrbU9ja1FnalJoak1oYU9iY0prZVNlZU1mYUxjZkdrYlJhXkhgZUxfYUdiWEo8 +Pzc0PTIwOzI2OzA1OzMuOC8zPTQzPTM0PTY0PjQwOTM6PTUwPjQ0OzYyQDQ7ODgwPTI5Pjgs +PTI9PTcxOzA8OjczOTY4QjYvPDczPzEyPzM0OC83PzYzPzI4OzcuOzM2PTU0PDw0OjU0QDIz +PTE9QTs0QDM8Pz44PjM8QkA7QDQ6Qj06Pzs5QT4+Pzg4Qzw/Ozo4Qjk/RD42QTo8RD9CSj1t +lkro9NT8//L5//L+//j///////r///////7///n7//39/u/0//H9//L9//rp9ujx+eb7//T6 +//bu/ub1/+/y/uzq+uvb79Lf69no+OHf6tz0//r3+fDo6tzh9Njw+PDx/u/l9eDt+/Lz++/q +8ejk9ePy++7s+OL4/vv9+/Lt8ebt9O/x9PD1/PX///77+/Ds7+Xi1c7i693h8eH5/vj/9/Dj +vsBAQ0BAPDUyPzZCPDozODI+OTgxNTk+PjMyOTk2ODUuNjY1PjI6Ojk1OTIyOjczPTI5ODUy +OzA5OTc0OTY7OTk1OTM1NzEzOzM0NzE0OzM2NzUwNzc4Oi8yPjk1OTU4PDU2ODQuPTE0OTUu +NjU4NDgwOTM4ODwwOjI4Njg0ODQ4OTk0ODMzODMwOTQ5ODQtNTA3OjY4ODYxOTYzODMzNjc6 +ODEvNzUwNDM3OjQyODA7OTMyODU2OTYvNTI8NjgyNDU6OTk4NDI6OTYwOTI3ODozOjQ7Ojcz +OTUuOjMrMzM1OzEwOjIvMjE4NjUyODk0OjMyOTYxODE6OTgyOTE1OzYsOy41ODctOjM9Nzcx +OzM0OjErNTM8MjkvOzI2ODQzODQuNjQ2NzYyODUvODcxNzQwOTEuOzcxODQ0ODM0NDE0NjM0 +OzIyNzQwNiw4PUIuOy03NDkvODAxOzUwOy8zNzkwNjQyOzI1OTQwOjI6OjouNDY0NjovODEz +OjYzNzU2ODU4NjcwOjQyOTgtNzE3OjkzOjU1OTMuNzc0OTQwOjE0OjQ2OTgyODI6OTw4OTIz +NjYuODc2NjkzOzQ2OTEyODUzOS80ODg0NzQxPDc0ODM0ODUxODMzPDUwNi4vNjUyOjMyOjU1 +ODQvOjQzPTUzOi42OTcvODE2NzcxOS01NDoxPDAzNTUwODAyOTkwODExODA0PTIwODg4Ni82 +Ozk2ODcuODQyOzcxOTMvOzI1OTYvOjA5MzUxOjE3OzksNS0zNjIvODE2NTcoQC8zODgzOzA2 +OUE/TThQT0JNUkZWVUhNUktRV0FOUENTVkZXWEhXWktWVUtVVkVZWEdYVkVPVUJaVkpZWUVa +V01TVztfVEtVV0tbW01WV0ddWkhaVUVWVkpaXElaWUtaWk9aVz1ZXExaWktaVUtgWktaXktd +WUxbW0VfYUxXXkFiXlFaXD1eVkpQTz1NSEFUSzxJSENjbVV6e1mAdV55emB6c110clx7eV94 +dll6e2B3dl93dF5+dVh2dl19cVpydFp6d1luclh+c150cld8c15vcV97dFpyclt0b1l0a1dz +clh3bllxcVFzbV5wbldsa1dqblFycFtxblNxbFZybVVsaFBpa1JwblBsa1VrbVNqa1VraVFq +bFRqY1VrbVFyb1Nla1BnbFFmaU1mZlBjZk1laVVnZUxiYFNfY01kY09iY0xhYFFeVUk7PD80 +Ojc3Ojk4PDUvPTc0OjM3PTk2OzQ2OjotQDY2OzYwOjA9OTgvOzI7PjkuOjE7OzQzOzE1ODkt +Oy81OzsyOTczPTkyPjcuOzUyNzkzODI2OzcxNzk4PDY3Pjc2OTM6OTkvPjQ6PDozPjE9ODoy +QTQ8OTwvODdDQUIxPzU6Pz0xQj06Qj02QT0zQT09RUE5PUE8QDo9ST08Qz09RkNFTEFrl1Hz +9+D////8/vn1/+3+//n///////34//v3/+75//j9//X3/vn1/+zy++zx9+jz/e/5/+z3/fHt +9+fv+uvp+uXe9tvc8tXl8N7e6dXd5Nrt8unx/erz8+rk9eb4+/Ps9eTx9O7t+OTx/vv////1 +//z6//b9//v49vD3/+7+//7////////////r9+rz+Ojr9Ozs6+jr+O////37+e7s7Njj0NJE +Pj45OTc2OzQ8ODk7PC83OjUuNjE/Ojs2OTA5PDowOjI7OTU5NTI3NDU4PDgxOjQ1OzY2OjM2 +OTY1NzM0NjgzOjUrODI4OzM2ODY8ODQ4OS86NTUzOjM7NDcwOjA7OTYuOi47OTIzPS04Njc3 +OzE6Ojc2OjQ4OjYxOTI7Njc4ODUxODI4OC04NzU1OzA4NzE0NzI3ODQ1NzE3NjQ0Ny83NTQw +NzE7OTU1MjE4OTQsNy07NTc8NTI4Nzw1NDQ4NzQ6NzY2OTI4OTE3OjQ2ODc1NzM6NjE7ODMw +OjY3NTUvNzMyOzM0ODA5NzUxODE8OTcsOS5BNzsvNjU7NTcyNTE1NzMzNzI4OzM6NjU5OzA4 +NzQxNzI3NTEzMTM3OTQ2OTM0NCw4PDcyOC4zOjgyOSs1NjU2Ny42OjkxNyo1Ojk0Oy06NjU3 +OjAwNTQ1OTgwNzE4ODQwNTI4ODc1OjQ3NTU1ODMxMzE3NTUvOjM2ODgvNjM1OTctOjY5PDQw +OC05ODY0Njg4ODE6MzczNjU2NzgzNTI3ODQ0ODI5NzkyOjQ0NTQ0OTM5NDQyNjk3NzI0Ozg2 +Nyw1OTg6NDM0NjY0NjU0NTM8NjUxNzU1OjUxOC84OTgxOS43OjcxOC44OTUxOTA0OjcrNy83 +ODw0OTQ0Nzg1OTY2OjgzOzM5Nzc5Ojc2Oz43NzI2ODU1ODc1OzYyNjAzODAwOzI1ODYzOzM6 +OTkzPCw3ODY3OzI1Ojg6OC85OTgzOiw6ODwwOCo0Njs1NTM3Oy42NTM3NC41OTE3ODctNDM/ +RzxSUUJaUEZQT0NYUUpUVUZXU0hVUUNZUkdUUEVgVktXVUVaWUtXVEZfTUhZVkhUVkNXVUlX +WENaWU5ZWkZWWkxdV0teWU5hWUdcWEZfVkhVWEtdWVJeXEVkXE1aV0VcWk1fW0dcY0taXEBf +WEtoW05cVkpcWlFbVkdaUkhWVDtKRzxYRjhKRTxodFB7emJ9e1Z7el+CcWB3dFuAdV54dVqF +d1h0dl14eFZ4dl95d117blt4cVl4cVtzdVZ3c111dld2cV10d1x1b1lwdFZ8b1xydFN2clVy +cFRzcVRzbVxycFdxbVlwb1RtblZya0tvblRub1FsalFua1Nna09ybFVrZ1BrbFdwak1qaVVk +Y0pqZ1FrY01oZ1RibU1uaFFgZUxoaFFkak9pY09lYUljZE1jZEtjZU5hYk1dU0g+Pz01PDc3 +PTE3OTUyPS03PzM1ODU6OTkuPDA5OjM2Oiw8NzUuOTA0PTU2PTYzPTUwOjQ0OTMzPDYzNjM5 +PDQzPDQ2PDQ1NjkyPDY7NjQyOzU4PDouPTE8ODY1OzU+PDotPjU8ODYxODc+OzU2Pzg0PDw1 +QTg3PDg7Pzk2PzU9QDU6RDo/QTs7RDw6RTg3PEA+QDY+REA8Qzk8QD45QzRERUF/o0j9///7 +//T///f5//X4/+37//H4//D9//r///34//jz/+bx/ef4/vLq7OH8//T7//fz+/Pm8ODy/evv ++/Hw9unj7trX5sze79jh79rV6Nbi8drj7t7o9+Xt9eru+Orz/vX5//L9//jt/ev2/ery++/x +9O/m9OLs+u72//Ht9uLi8ePy+ejs+/H6//z5//X+//3u++3y9+nr8eH5+uzr8eP5wMo/Qjwz +PTo3OzI5PDU3OTEzNzI1NTY2OTI1Ozc1OjIxPzI2ODYzNi06PDQtOis9PDYyOiw1NzYwOC03 +OjQ0OTA5OjkyOzAxODM2OTM5ODMzOi41ODAwNDI5PDM5OjU6ODM2OjU6Oi41OC4yOC8sPDA3 +OzEuOjA7PDMvPiw8OjMzNTU6Oi0xODIxOTQ5NTM1NTA0PTYzPjE5NzYxPTIvOjIzODEzOjAy +OTE0NS01OTYyNysxOzYxOy01OzYyNyk5NTc4OjIxOTo6Oy8wNzE2OzQvOjA2OTEyNy80NzMt +PzA0PDMvOywyNi4zOi8zNjI1OjUyOjEwOTEyNjI0PDIyOS80Oi8yNy83NjIwOjQzPTAxOC8w +OzI0OjY0OjQ2OTMvOzE8ODIuQDE3ODQrOyw7NzQxPzM5OTA2NDU5OTQ1Nzc1Nyw1OTU2NjEz +OTQwPS4uOS8zOjMtNy43MjUvNjEwOjEuOSk2OjYvOCwxNjUuOi43NzQsPi82OjMyOS02NzQs +NzI4OjAzOTEvOTc1OTMxODAxOC0uOy4zOTE4PDI1Ny80PTQuOS44OjgvOC80PDYtOjQ2Ojkw +OC00NzoyOy03ODg0NTAyPDczOTMwODMxNTExPTAyPS8yPC80OTI1PTAvOTExPjQwOTA2OTMu +PS83OzUsOy84OjMqOy80PjIsOzQ2OjYrOzMuPTI1ODE6OTIxOTc2OTQ2OzAzOzI4OTkwOC82 +OC41OzgzOTM1OTo3NzA3PDQyOjEzPDUtPS4vOzUwNSszOjs1NywzOTQyOzAyPTc1OzQ8SzlS +UUhPVD1UU0hTUDxWVUZVVzxRV0dWVkVWT0JZWkJVT0VgWEVTV0hYWUVWU0hcXENZWEdXVUlb +WkdbUUZZWUZXW0dbVUpTWEdfWUdXXEdaXk9cW0ZhX0tYWkZYWElaVUhgW0lWW0NbWkxaX0Vh +WUpdVkFcW0hZXT1aWENVVEVPRTpVSThLSzhgd095d1p8eVR8dl2Aeld7e117dlh3dFh4dliB +cl1ydFh5cV17fFp1dVt2dVp4eFh0dF57eVl1eFRzcFZ4c1d3c11zdlh6cFZuc1J9dV1yb1V3 +b1tqbk5ycVhua1N2cFhyb1Fyb1lxb1NrblBvbVNncU9sbFJtaVFxaVFpbFJmZ1Bra05qa1Fx +aFJja09tZlJjZk1saVFmaEltZUxiZk5rZkxgZktlaExiZU5jZkpjYkpkWUhBPzo0OS06PDY3 +OTE5PDIxOjEzOTA4PTc0NzQ1OTY0OjA1OzY0PC02PzYyOTAwPDY4OzQyPTUyPjIwPTIzPDA1 +PDI1PTUsOzAyPTMxPTA3PDU2Py81PzIzQC82PC02ODY2OTM3PjYzOjM2QTQ4PjY8QTcxPjo5 +QDg1RjU8SDI3Qzk2QjE7QDg6PjRAPj46Qzk+Qzs3RzY9QTg3RjtCQ0A+SD+AoE32++j9//j/ +///+//3+//z///////75//L0/+j8//b9//z9///9//r///37//H8//T+//Xx/O7g8dzm8t/Z +6tfh8djq++Dm3t/c6M7f69n9///7//X6//3v+/Hx9vL9++/k+eTn9+fx+urs/en5/vLz/vHy +/PP89+7r9ufr/Ofu/fb4++7x++j4/PX3//Tt++vk7uL3+/Ds+Ovx/u/49uvfs79EPz0uOjc+ +OTw3QDk6PTowQTI1OjYzOjg4OTU0PDY5NDo6ODI2PDg1OjU1MzYxNzM0OzUvOTc3OjY0OjU3 +ODcuPS82PjYyPzI4OzcxPjE3OzcvOi85ODg0OjM0Nzo2OzQsPDU5NzQ5OS4zOTY6OTc3OjY1 +OjEyOTcwODUxOjI0ODEzOzI2OTUyNzE4OzcyOTM6NjUvNTM8OjcwPjY9OzcyOjI2OjQ0NjQz +OTM0OjIvOS83NTc0PTY1ODcwOjM4NTUwOzc0OjAyOzM2NjI6OjkxODQ2PToyNy82OTkwMi05 +PDQ3OC8xODY2OzYvNjQ4OTMyNTIzODUvODA5OTcuNzE3NzQxPTE2NTY3OTU2OTU0ODU0ODMz +ODY5OTg0PTQyODU3OzIuPjU3OzA0NzM2PC8zNTYyNjg4ODgyOjE7OzksNzQ5ODYvNzU4OTYx +NjI3NTcyODk7OzYyOjc6NzQ2ODozOS83OzY1OTAzOzczNTE0ODE2OzYtPi82NjovOzQ3OTUx +OjA1Nj0zOzE5NjcxODE3OjouOTE2OzguOzU3PDMwNi40Ozc0OTU0Nzc1OTUxPzUuNzc0Njk0 +ODgwOjMyOTI1OzkzOzM1ODgvOTU3OzM1NTI5PzsxOy02Pj01Nzc3ODk1OzMwOjgyOTYzPjM1 +Njs2ODQwPDY1ODk2OTc0OjYzOTM0OTwtOTI6ODozNzI3PjctODI5NzkvOjE3PzYvOTQ7Ojg0 +OTg0NDQ9Ojs0PDMyNjUwNzE4OTgyOTEwOzgsOTIwMjU3ODUuNTIyOTE0OTQ1OT00RzlWUkZS +Tz5WU0pVTkFYU0dWU0ZXVUhXWkVYWkhXS0tbV0VcWUVXU0VYV0lYV0ZaV0haV0hfWkpZW0JW +WUtaWkVeU0xcWEVTVE1dV0xXXEtbW0xbW05ZXUJZW0xbXkVeW0ZZWktdWExfXkVeX05dU0xd +YktaV0tjWkxfVUJgV0tSQjpRQDpJSjhxc1h9emKCeV56el5+emV6e2F5eFp3d1t9dmB5dl6A +e2Fzd119cmF1dVZ6b2J3d1t+dl1xcVd7dVtwdVp7dlpzc1x1dVp5d2Bpb1d1d1t5c1xycFd1 +cFpydVZ0bF1vbVpzb1hubFZzbFZrclNwbllta1FyalJpbk5ubFRwbVBxalptcVBqa1dsaVNp +aFBtaFNna09oZU9oZFBrZU5kaEtkZU5nZVBhY0tkZU5hY05jZFFUUUlBPD4zOzY9OzouOzk6 +OzUwOjQ3PDU1Ojk5OTk6NzYyPDQ1OjYzOzcxPTQ3OjY5OTU2PDg0OjM1PTgxOjI5OjkyPDA4 +OTk3PzI3PjU2OjYyOzw7ODM0OzE5OTY0Ojg5PDgzPTY5PTsvRDc7Ozc2QTQ7OzozQTk8PT46 +Qjs5Pzo7Pzw2QDk7PTo3Pjg8QTs9QD1BQj04RD48QT8+P0E9RjxEREWGoUvw/Oj3/+/8//H4 +//D////////////////7//j2//ry/ebx/Ov8//X8//n9//r3+PHo7t/o9+Ps+OLx/+3y/PDl +9+Ld69Xa7dTZ6NfU49Lp8+Pp/ej7//Pz//L1+fHq997r8Ons+ub89+3p8uPt+Of0+u77//fz +++vu++35/Pn///7z//T2+u/x+en6/O7w/fHy8OPr/vD///rt/O7z8+HUrLVFQz47Ozs6Qjc6 +PTk2OjM0OzQvOTQ5ODk6PDI3Nzc6PjQ3OjYvODQxPTUzPDI3NzY5Ojc3NzE2OTU2OTMzOTw3 +OS00OTQwOjIxOzQ6OTMzNzE2OzUyNjA6ODgxOjM2OTctPC80OTMwNis0OTUyOzAyOjQ1OTg8 +ODc4OTg4OjY5NzcvOTI3NDU3OjUzNjQ0PTMxODI2NzYyOzA5ODUzNzA4ODcsOTE8NzgzNjM1 +OjkyPDAzOy8vOjE5ODcwOjIxNTI5ODk1OTA2ODQxOTQzODA5Nzg3ODQ3OTU0OTAzMjcyNTM8 +NTgyOy47PDYtOTc3NzUvNzI8NTYsPC09ODc1OTQ0Nzc3NzM1PDUyOS4xNzE3NjQyPzMyNTQ1 +PTQ0NzQ4OTg2NTM4NTk4Njg3PTo2Pi46NTkvOTA4NTk4OTM6PDszOTUwOjI4OTg0OjU2NDcy +ODc4NTUsOzE4OzU5ODk6OjY3MzQ3OTM3OTcxOTE4OTcxOzI5NzcuOTE6OjY4NTU4OjMzNjU4 +NzQ4OjkwOzU5PDgtOTA3NDQvPDE3OjcxODA3OzMwNjQ1NjMxOTU0PDUzNzcyNy4yNTk1ODYw +OTYyOTQ1Nzg4OTIxPDI0NzQxOzM4NDczOjI3ODQzOjE2OjYvOjE4Ojw5PTM4ODo1PTQ0OTUx +OzM6PT80ODg1OTU1PDMxPDgwOzMyNTc2OzQ3OTQyOjU3NzUyOjE2OTcwOzM1ODczPDA5OTkv +Oi83NTsuOi00OTg0PTIyOz0yOTA0OjgwODU0Ny4zNjg4OzYwODg6NzQvOzBDTEBMTEZXTkJR +TjxXTUpSUEFYVUpUUTxcUUdOVUZeWUlYWUZYW0ZVWEtXWEVeVEdXWEhXWEhfXkpXVk1YWkde +WUZcWUtaWUxcWkxeWUdjWkdWWUtiXExWVkFeWk1aWD5ZU0xZXkBeW0tbXUdcZE9gX0xiXEth +V0pbW0deXElaWEBLRUFWSTZLRjlsdVd6dl+BfVl1el6Jd2V3eVh/dVp1dV6EeFl6d198dFt7 +d1x1eFx6cVt0d1d6cFtzc1d6eF1xc1Z7dF5zcVl1cVpvclh6dVpydFd1eFh2cVt1c1h3c1lz +clN0cld1b1NvclhycVVqa1dwa1Rqb1NtallobFBwbVNuZ1JsbFVscFNrbFZpak1rZFNqblFu +aVRnaU9talBlaktrYExlZ05iY1BmZEtiZlBhZU1gY0tjY0hbU0o8QTs7PzwyOzY3PTcwPTE7 +OjcxOTI7PDowPDE6PTYxPjQ8Njc0OjI2OTkzPTg4OjA1PTYyPTI2PDYzQDQ0ODU4Ojk0PTU3 +OTkvODI3OzgwPDQ6ODguPTA9OjoyPDQ7PDkuODU5OTcuPTM+PDk3OjQ2PDY8PDk1QDY4QDY2 +PzY1PjQ2Ozk9QDY8Qj06Pzs4Q0A6Qzg4PT47RTc+PEI7QTpEQEmAmE7o9Nn9//T///7///n8 +//b9//X0/u/6/+3///37//j8/vD7//X8//j4/+/5/Pjp+uP6/+////z////2//Lt+Ofh9N/g +7tXf5tnk6d3d6tr/+fTn8eHh5+Hm/ej+8/P0+/H0//Po9eDw/Pz////y+fn3/Ozx/PP5/vP8 +//z///Tn7ePw+ery9ezv797e7dfd9OLw8u7///758Ozt9ePp6+DatLVGPT8yPTU4OTk2OjM6 +PTc0OjA4PzQzOTI4OjU5OjgzOzYuODo2NjA1PTo5Ojc0OTYxNzUsOjA5OTErNzE5NzQuOi4x +ODYqNjE0OzYxOS4vNzcxODM5OTYxOTI5NzMtPDQ3OjU2NzUwNTI1NzMuNzM0NjI7ODMtPDE3 +OjUwOTU2OTUxOy42ODMsOzI6NzguOjE6OTgzOi83PDktOyw4OTgyNzE1NDI1ODAvPDUxOzM2 +Njc0OjQzOTMsNzM3Ozc1OjkyOjcwOy01ODMtNzA4NzgtNTJBODgtOTM3NTErOzc4OzIuOzIy +NzQxOjYwOS8zODQuPTM2ODU1PTU0ODYzOzYxOC8zOTcvNy81Ojg2OSs2OjowOTAzOToyNS43 +Ojo4OzA4NzwzPTMyOjY0OTI0ODc0ODYqODI0OTYxNjQwOzgyNzEwODUzPDUwPTI2ODkqOTEy +OTEvOzM5NzUuNTQ1OjEyODg3ODIyODYzOzczOTkxOzAzOTUuNTQ1OzUwPjQzODUtOjYzNjcu +NDQ2OTYtOzg4UTc8PEQzPTgwOjIvOzItNzcxODQzOTs0OTUtOTM3Njg3ODUzNzotOzA2NTgy +OC83OzktODA1OjgtOjEzNzcyPTE0OjktOzI0ODE1Ojc1ODU1OzUwOTo2ODc3PDc1OzQ3OjYx +Ojc6Oj4zNyw2Njc2PzE6NTYzODE7ODswOi8xOzcwOSk3OjszOi42PD4zPTMzOTowNzo0PTkz +OzozPTAsPTc1PjQtOTcwPDEvNTM1NzcuOC41NzgyNS43OzstODQ7PTgzRjRYTERPUElaUUpV +T0JZTkZVTk5WVEZYU0hXWkNZV0hZVEdaVUVWWUZXVkZZUkpTWkNZVVBVWEZfWUhZVkhdVU5e +WkZfXFBXWEhaWlBeYENcWExhWUlcX0hgWkxgW01cVUZYYEthWUtZW0RYWExjWUtcWU1gX0Za +WEhoV0VYUklWRztRQkFRSztrcVyCdmF5eV5/fGJ6d2R8d1l8dl16eluCeVpyeVp4d2B4eF12 +dGF8dmF6dF5zcVt0dlp7dVx5cVl0cl5zdV94c1x0cVp1cFx1c1lzb15zclxwbVl2cVpxdVV1 +bVpwbFNualhrblN2a1dva09ub1hrbVFqa1dtblZsbVhsbFFsZVVra1FsalVoaVNnZ1NwZ1Jm +aU5oaE9rZFNiaE9naVFjZkxqY09gZEtjZU5fZUlkY1NVT0BBPjszPTQ5OTY1PjQzOzU1OTg0 +Ojg0Pzo0OjgyPjs3Ojc1PDg3PjUyPjQyOzMvOjI7PTszQjY7ODwuPTY8OjowQDA3OzQvPDQ7 +QTktPTY8OTk5PDMuPjU0Pjc1QTA6ODk3Pjk3PDYzPDE9STw1Pzk5QDc2PTk3PzY5Pz82PTM8 +Oj80PzI7REI7QDY5Qj86QDY9RT4/PjtBQz47RD89Rz1FRkGaqFL8/vn4/vD9//3////8//v3 ++u3+//j4//L5//T6//z6/+3////9//nz/+30/+3y/ero9ubr/eTo/ePg9d7n7tzh9OXe8tXm +/+Hj7t/X7dP2+Ons9ur+/v7s+enm9uTs89/w/e32/+3+//vo++ns+ePs8evt+eTw++76//Tx +/fH6//X9/v79+fv///7///X5//H4//Xq9OH8/fru9Ovs6+LVoKlGPUI9OTk5Ojs5Ojc0OTc5 +Nzk6OjkzOjYzPTU6Ojc6Nzo3PjM6PDUxOTA6NzozPDQ8ODcwOzQ9OzgsNS46NDg1PC01Ojgy +ODA2OTg2NDc2OzY6NzQ2QDgzNzg2Ozc4OzU7ODI1NjM6OzQ1MjU8OTU3OS87PTgxOjQ+OjYz +NzVAOjgyNDM/OjsxNzo+Ojg5ODM1OTY2ODY/PTc7OjY0NzU5OTUyODU5Njo1OjY6NDM2NzY1 +ODE5OzszOC43PDkyOjM3Njs2OTIyPDk0ODA2NTg8ODQ0NDM3NTUxNjQ8NDs0OTQ5OjgwNjM1 +MzYvNzM6ODU0ODU1OjgyOjI4Nzg1OTc0ODQ2OjU1NDY5Nzc2Nzc5OTc2ODQ6NjIyNzg5NjU7 +Nzc4ODU1OjAyOTI6MjcvOzU2NzQwOTg5NzQuNzg0NzIvOzQ3OjE0NTg1NDI2OTo2OTExOTc2 +OjUzODc4PjQ3PDc3Ojc1OjI1OTY4Ojc6OTg0Ozg5ODczNzk6OTsxNTI1ODsvODM8NjozOTc5 +OzM6MTM1Ojg2Nzc1OTQ4ODU4NDczNzU1NTg2ODQ3MzgwOzQ5OTkuNjM5NjkyODI1Mzw1Ny82 +OTw0Ni85Njc1ODE4Ozk2Nzc2Ojc5OjYxNzk7OjU2ODU4NzM3OzU3OTg1ODY0OTc8Oj01OTE7 +NzozOzQ6ODoxNzU7NjowODQ5Nzo1NzYzPTY1OjI1OTI4Njs4Ozs2ODs2OTM3Njg0NjU8OTQ4 +ODY0Nzg3OjU2NzQ2MzktOS03MzouNC05NjgyOS82OTk8PzA1PTpESj1OV0NXS0hVUD5VT0xZ +VkJYVkdUT0FaUkpVVUZWVkldWUdbVkxaV0pWV09gWUZaWUhgVkVXVkphVkxZVU1bWUdbWE1Z +WkJaYE1VWkleWE9TXEdiV05bXkJif1tdYExbXVJfWkhjYExeWURkW1NdXk1oXk9aXERhWEtf +WUthVz9KQz9VQTRLSjd5e1l7fmGEelx7fGGFdWN1elt7eGJ3emB9dGN6eF56eGN2dFl9eGJ0 +el56dlx6cV12c1x3cVt6c1h1cmB2c2J3d2F4dFh3cVp3bll1clp5clhyb1h6cV1vblZ6cF5p +cFR4b2Fva1J4aVdva1N0bltxcVlxaFRxbldtbVVuaFZtbVJwa1ZtZlNuaFBqaVFnaFBuZlJk +aUxvZlNhYU9nZFBcaExvYFJfZU9lZ1BmZk5kYU5fTko/ODc6OTk0OjQ2ODY0PTk4Nzo0ODY3 +PDY3OTU4ODY4PTo7OjM7Ojk3OC47QDo1OjQ6PT02OTU2Ozw2OjQ9PD04OTU3Ojo3PDQzQDU3 +OzwyPDQ8OTk1OTg7Oj44OTo4PTk6PTtAPjo0QDw9Ozg9Pzs7Ozk3QDo6OjlCRDk1PzpAQDs8 +Oz88QjhAQj07QD1APT88Qjs/QkE+QjhCRUA5Qz5EQ0GRpVL4/uv////8//3t/en+//X///// +//////////3z/vPw/d3x+Ozy/un5//T49fj2+Or///75+/L29PH9//b8/fze7dzZ5s3Z69nb +5NTe8Nnk9un+//Tn69zd6uHw8+n9/fLv+e/t+ODb6N7s8+339fDt9+rx8+z8/vn7//P9//n6 +//fw/erq/ev1++zy/e35/vfn6dvm+Ofy/Ofr9+vu5+HanalFPDs4OjQ5NTk1PTM1OTk8PDku +Njk1NjcxNzQ9OzsxNzY7PjUuOjVAOjcsODg7ODIxODg4NjYzOzssOzU6Ojc5ODI1OTUzODg8 +OTUxNy82OzI0ODMzOTgyOjQ0ODE6PTgwNzM3OjI4ODAtOTg1NzYwOTs6ODM1OTY1NzMwNDY3 +NzYsODc3NTczODI3MzctOTQ6Nzc0PDY6ODgyOTI2OTQxPDE1OTQ2NjQ2OjswOjU3Ojc7OS8t +NzgzNzI1PzcvNi82OjktNzQ0OTU0Oy88NTk0OjE6MzQpOTE5ODkqNi87NTQsOjQ5OzcwODEz +OjQuOTU0OjI2Njo1OjMyNzczNjUxNzQxODQvOi81NDM2Ny84Njc1ODQ6OTYyODM5ODYlOC89 +NTgxNzU7OTcqOTE1ODUzODMwOjYsNzUvOTU1Nzk1PDcyNDQ0Ojg1NjMzNjUwNzI2Njw0NzU2 +OTswOC86PT4vNTM2ODsvOjQ2ODszOzAxOTcyNjYzODI1NzUyODU3NDYyPDYzODUwNTU4NDUy +ODg0NjUvODc1OC04OjcyOTE3OjQtOTE2NjUyOTUwPjQtODQzODQ1Ojs1OTEyNzc0OjE0NTgy +OzU2OTsvOTU2NjUwODU0NTkvNTYvNDI2PTkwOTI5PDsxNjEyOTYzOjM0PjU2OTAvNzY2NTUx +OzM1ODcvQDM1NjkxNzQ4NzkxNTI1OzUwNi01OjctOTMzNzcuPDQ1NjcwOjMvODkxODMyODU1 +OzguNjsyOjcvOzY1NjE0ODgzOzI1PDYsODA0OzwvNTE4PDhERz1VUEZPTkVTU0lQU0FVVUtU +U0JaVktWUkBXVkhVVEdWVD1WV0hZVUVaWkxZVEhSW0ZXV0pZWExYWktWV0lgVk1ZVkNbWU5V +WkZdW01XXkhiWk5VX0xZZEtZYEtgX0pbVkpZW0daXkxdYEdbYE1bXkVdYVFaXUpWX0NkWEpa +U0NQQT5MQjhQTTpqdVV+fGZ/d1d+dmN5eFmAdWF8eF15eWB7dl18c2F6elx7dVp8c1p2eFh3 +blx5eFJ1blp8c1dzc1V5clZzcV18dlpxc1mAelxxdVd5c1ptcFd3bFtsb1h1cFluclt1bFRz +cFR0b1R3cV1vblVwaVJmcVZ2aFVwbVRyb1htbVVwbFVuaVZoalFnZFRmaE9gaVRsZlBnY1Zi +YklmZ0lmZ09iZEpmZE5fZUllZFBeY05iY05QTEI4OjwzOTA6OTYuOzE4OTc0PjY3OzY4Ojc2 +Nzg0PzM1PDQ1OjA0OjY0PjM1ODQyOjg2NzoyOjI6OTkwNDA7OTguOzI/MzgyOTY+ODozPjU5 +OzkzPjM9PzU0ODA8Ojo0Ozc+Ozc4PDw0OTc2OTc4Ojk4OzY5Pzs7PTs5Pj00PDY+Ozw0Ozg6 +Oz0zPz0/Pj8xQTY8PD0uQTVBOz40QDlFRUNBR0CJm1Pt+Nr9//r///z///z////7//f1/+/9 +//X6//L4//P3/+r+///+//z///j3/O/3//X6//D4//z0/+zt/Obj7+Dc8Nrg9NTt8unk8Nrb +6NXy/ezw/fLx/fn///78//v0/+/x9efp++r///j1//H3//Lp++P6/vHt/+rq9+Ld89zo7unq +8Orr8Ovs9+jw/vH4/e/u8+r5//709+73//v3/+vdmaNBPEItPTIyPDcyOS86OTosPC07PTou +Oyo2OjowNzU5OTg4OzYzOzczPjItNjc6OTgzPDQrNDUtOTAzNzk2PjEyODU1ODMrOzI2OjIu +NzM6PjMzOi9ANzYpPDE1ODUsPTU5OTQsNDEyODYzODkyOjIuOjQvPDE0OzUtOjYwNzUtPTQ0 +NjUyNzQ5OTIzOjM0OS84OzY3ODU5OzUzODU2PDg0NTAxOjY0Oi0yOjQvNzIwOTExODMqOy01 +OjMtPi40ODcwPC8yOTMwOzIxOzczOTY0NzMvPDYvOjQvOjUuOjIvOTMuOTcyNjUyNzguOzQv +OjEqOjAyPDYoODAzOjcsOi87NTUxOjM1ODMvPDE6ODorNzI0OjUuPS81OzgxNzIxOzQwODA0 +ODA0NzIzOjQxNzQtNzQtNDI0OTcwPS81OjUtOTQ0ODYvOjAzNzgsOC8zOjIvNjI3OTgxOjA2 +OzYxODU1PDMwOjAtOzUwNzQvOjEwODIxNzUvNi8yODMyNzAzOjYsPjA3ODotOjE0ODcwNzEy +ODksOSwvPTksNzAzOTstODAwODo0ODIxODIyODQyPTMyNzcxODU1NzY1NzQyOzg3ODguPTcw +ODwuODA3NzMsNzI3OjouOTM1NTkrOzI6ODguODUzPDc2OjgzODY3OTYuPDMyODgyPTY2NzUv +OTQxOTYzODwvOjU0OzYzODAwPzEvNjI3NjkzOTI2OTgxOy8xOTkzNzExOzUvOjMsOjY1PDcr +QDQzOzMvOi8vOTwxOi8wNzcyODMzNTovOzcxNjgzPDY+Sz5RVEVOV0pWVkNQUUdXUEhXVEZZ +XENWWEpVXElbWkxSWEFWW0tWWkZaVk9UXUJZVkdSW01eV1JVW0ReWklXYEJhWlBVYUJaXFBX +XEJbWElZX01dXUBZY0xbX0daYEdYWUZaW09gW0lWXkhYW0xgWkViX0pZW0FmWUhaYkRgT0RJ +STdZRztMTDt2e153dl+AfF2AemJ5fF56d196eFp5d2B5eGJ8c1x4dlx6eFt8c1x1elx8c2By +dFx6dWB1dFp2dFt1c1Z6cmBzb1h1d1t6dVZ3c1p3dVxydVV1cVxucVlzb1dzbl5tZ1lucVdy +b1RtcVFxblRxcVVpa1NvcVlnb1VubFxpblRzbFFlaldqbVNoalJnaFBlbFFkaExsaFFjaE5m +ZFBkalBnZlVmY05lZU5hWU1jZEhfYU1LTEQ5Pjw0NzQyPDYxNjQ1PTg0OjU0OTo2OzM0Ojc3 +PzcwPDQzODkyOjUzOjQrPTU8OzctODMyODUyOTYxODc0OTc0Nzc2PTY3OTYxPTkxOjk0QTk2 +Pjs2PjU0Pjs1QTkxOzY0PDc3QDgxPTU5Pjs0QDY4PD0zPzg6PzkuPjI+PDgxQDc5Pjc3Rzk/ +Rj02PDw+PDk5RD47Qjs6Qj84Qjs+Rj8+RUKZqFP1/u31/+/2/+39//ny+e/9//f///30/+/8 +//j2//H8/+/0//T5+e7v9Onr9d7u/uzk9OHc6dfu9+b3/Pjp8unh9Nzl/eDb7N3U3s/f7dXx ++ebk8t39/vvl9eXj7djk9env8+z4/fbs/eHk7tjd5tz99/T2+uTm9OTo7uXw+Oj09/b3/vD9 +//7///P1/vL19+vu+u36//Dy+uzw/Ovl7d3MjZQ7QTQ1QDg7OTg0Pjk5Pjk4PTM/OzMyOTI6 +NTQzODM7OjYzPDE6ODYrPTI9Ni8yOjE5ODAwNDEyPDMzOjQ1OzM2Ozg0ODI5ODgzOTA6PzU3 +OjM0PTIxPjA2NzE3OzY7QDI1PC4zOzM1PTc2OjM1Ojg1OC00PDIzODI1OjI7OTczODA1Nzc3 +Oy0/Ojc3ODE5ODczPDI4NzkyOTI3PTQ2PTU5OjQ6OzI3OzIyOjE5ODY2PTMzOTY4OTI3ODQ0 +PC87OzQ3OzI3OTYzNy44ODUyODA6ODcyNjA8ODcsOTI8NjU2NzI2ODUzPC42OjQ0PDA1NjQ4 +NjUxOTIyOTU0OzYxPDM8PDc1PDE6OTU2PC87PTgsOi88MTg0OjI9OzkvOTQ/OjcwNjQ9NzYt +OzI2NzcwOjQ5NjMyNTAxODQ1NjU0OjE5NTc0PzI3Ozg4PDY2NzM8Ojo2OjE5ODYyPi05Ojgz +QSw2ODk0PC02OjkyOzAyOTk1ODI0OjM0OTc1OzQ0OjEyODM4PTQvOjQ1PDYuOTQyOjM3OzQ0 +PTU1PDMzODI0OTUxODM5OzUzOzE8ODU1OTQ8NzM0ODYyPDE2NzQ1OCw2PTUtPDQ1OTUzPDU5 +OTQzNy80PDIyPDoyPDQvPDQ4ODY0OTcxOyw3PDk1OS82PTg5PDE6PTg0OzMyOzQ4PDcvOC83 +PDcyODk6OjouOzQ2PToxPS4yOjQ3NTA2ODUzOTUyOjg2Oy82PDk1OjY5NTc2OzE4Ojc2PDIz +OTQvPDMvOC8vODA4PDsyQDA1QTQvOzI6ODc0QS9FTD1OUz5WUkZTVkJUUEtVUz5WWUtbVEFX +WUtYVEdXXkdXWEhfVkNXWUZhWkpXWE5fVkpXW0VdWkpXVkdhWU1dXEVaWU1TWkVhWk1XWEBk +ZEtWXUxiX01WW0dkYUdbXEdTXUlfXk1gZUNiW1BiXUleXk5kX01gYEtiXUZaVkheUkRLSD1a +Q0BRWDqBdV56f1h+cWB9d1l/eV57e1p6eGF7d194fVeBgGV7e2B6elt4fF15c2F+e1h8d1+C +eV11eGB9dFt1dlh2c1tzdVp6cV1zdVh7dlhyc1h1c1Vxcll1cV11cWB4dVZ3cF94c1p6b11y +blJzcFducVRwbFlpa1Nvb1hvblpzbldtbVNxbFVqaVdocVNsa1Nta1NwaVhsZ09oZ1Nrak1l +Z0xpZU1kZUxsYktlZ0tmY0xhYktTS0gzPTkwOTY1OTA9PDU0QDU5OzI1PDM4PjgzOzM3OjQ6 +OjEwPjU6Pzo1PjQ2OzI1Pzc1PjM3PDczOzU4PjQ1PTI6Nzc3OTc9PDkxPDI4PjY3OzQ9ODcx +PzI3PjY4PzM8QDg3Njs4QTI3OTw6QDo6PTc2PDU3OzE8Pzk0PjI6Pzg6PzU7QDoyPTQ/Qz01 +OzRCPzw0Pjw/Qj44PD1AQz1BRj1MSEWQolXz+uX////9//j5/+r9//X////////+//j7//nv +/vHt9d/v/+L5//X///n7+vb+//r////9//n5/fjl9eLl8t7h+N/O5sjW483r8+Hl5uH8//nv ++efv9Ory+O7t9e3x/PL2/+7z+fDx+ur4+fLs89/n+eX0//Lt/PX6//X5//j///3///vt9eXk ++OHx//D3/+/q6Obs+OX5/fDy7ebo5+Peho07PDpFQjg2PDc/OzkzOjU+OTYxNzU0PDMxNzc1 +PDU1NzkxODI/NzgtODA4OTYuNy43OTcoOzI0NzgyPjUzNjcuOTM4NjMzOTM1NTI7OzQ2MjMw +ODUyOTY0Ojs4NC81Ozc5MzUwNzY6Njg0ODA9OjQvPjM9OTktNzE4Njs0PDY3PDsyNjU5NTcx +ODQ4OTQ3OjY2ODg3OTU2OzE9NDY6PDg7PDRHQDg6Ojg9OjkzNzM0OTYxODU6NzYuODU5NTcr +NzI4OTc0NDQ5ODktPTE0OTY1Oi88NTQxOTU2Mjc2Ojg4NjA3PDIzODM2NjQxOTU0OTA0OjMy +ODczNzUvOzM+ODk2OjA/ODk0PDJBNTo0QjJDOzYrOTE5OTcvPTc4NDgzOTU2PjE4NzU1OzY1 +OjQ4ODU1ODI1NTMwOzE0OzQzODE3NzgxNTA7OjktOjA3PTg0ODM0ODw0OCw2Ozc3OjA0OS02 +OTY2ODc4NzQ0OzI2Ojc2OzU6OTc0OTc4NDk2NDg1NzYzODkuOzI0NjoxNjc5OTM1OjY3OjQv +NTU0ODUzNjg1PDUxODczODQ0ODUyOjQ6NzcwOjQ0ODY3OTY2OTQ0NzczOTYzOjQ2OTU1OTQv +NjQzODc2PDI1OzU1PDIzPDg1OTQvOzUyPDcwPzE2NjYxPjA4MzcwOjA7ODoyODE3Ozo2QDg0 +OzYzOy8wNzs0OjM0NjgwOzU0Ozs2OzcuODc1ODQ2ODcyOzc3NjcwNjA5PDAzNzQ7PTowNi80 +NTQsPjA6OjU3Ni07OTUyOzA3Ozg0OTE4PT1EUDtVVElTT0tWTzxTT0hYTkFXVEVWWUdXVkJX +VUxVW0JaVERWV0ZdWUxZVEhfWE1ZWkthV0xXWUthXE5VVUtjWk5WV0ljWEhhW0lZWEhcX0lf +YktcWk5cXENfW1FiYkddUEVeXUdhXkhhXlJiWUtiX0xaW0VgW01ZWEVlXExaTztOR0BVQzlU +WkN7eVh9fV+BeWR9fF6Be197eFmBc2d7eV96cV5+dV11fF2AeFt1el2BeVt1d1l/c15yd1x9 +c2J3cld4clx9cFt7dlx3eGF3cVh3c1V1cVZ2cVxycl94bVpvb1V0c190eF92cF1ybFRyblh0 +blZybFdsbldwblRtalVva1BucFpta1Noa1Jsa1VrbFFpZlFmaVFnZVVhZ01la1FkZ0tmZ1Jo +Y0hoZUxkZkplZFFfZFBkXk9ISD85ODQvOjQ6PTc6PDEuPzUyODI3Nzc4OjI1OzczPjA4PDI0 +OTI6OTkvOzE3OzgxPjE7OzkwPTM8PjY0PDM2OjgzPjY7PTU0QDMyPjc3ODo5OTk1QDg3Qjg4 +QT0+Oj00Ozg5PTg2OjU5ODcvOzA8Pjs0OzFAOTo1QDVBOTwxPzhAQTsxRDVBPzs1PDk7QTo6 +QDo6QD03PTc6Pzg9QTs8RUBBRUCeq2j2/+7///X///P///n////+///+//j///3+//r+//z/ +//v///v///jy//H8//Pv/Ovn9uPq8uPo8+Lz+Oj0+PT0+vPm89vx+uzd69nc5dXq+t3u8+rr ++uv3/vz///X59e7y/u31/O35//j7//bz/e3v8Ojh8+D9/vv///////Lu/+nx//T0//n7//nt +7+rs+e3z/e/x/e/3/vL1++3s++jZhI81Qjk9PDQzOzA0NzgqOi80PDosPjE6NjUsODQ9ODYs +Oi80OjQwOjMtNjE1OTMwOTMxPDIwPjAsNjAvPDI0PTA3OTIoNjE1OTItOzE0MTUqOTIyODQt +PTA4NTUtOC44PjgrNjAyOjMvPDEyODA2NzIrODIwNjEtOTQzOTE1OjEwOS80OTMtOjI4PTMs +OjE5OTUtODA9PTcwPS9CPTZCPzhURjpQTD1VRztIQDY3PzAzOjU0PDUzOzQzOzE5PDQrOTM1 +ODQzOS82OywvOTIvPjEwOjAwOS8zODYxOS4xNzUwPCwzOjY0OS4uPTQyOC0vNy05PDM0NzA2 +OjQwPzE7PTM1OyszOjAzNjE5ODQ4OTI0OS81PjU3OjEyNTk0OTIuOjMwPC8zOTIxOjE0NjAu +ODUsPDQtNzIvOTI1OjgqOzMyNjUvOjIzNzg0OTc8PTUyPDE3ODkyOjY1NzItPjc4PTMwOTM1 +OjYvOzA2OTE1PDc1PzIyOTUxODU1PDE1ODcwOjI0NzYtOTM0ODItNS01OjYyNy02MzUsOjQ3 +ODMtOi01ODEuPTEyOTQwPDMxOjUuOzMuPjIuNjc5PTc1Oi8wPDQwOzEyOTIwNzEzOTMrPDY0 +NzkpPSw0OTgwODEzOzktPDA0NzsyOC01OjkzODIvOS4xOzUsPTI1PTYwOjQvOzg6OTkxOjM0 +PTguOzcyPDcrNjI4OjkxOCo2Pj4tOjQ8OTQsOTEyODYwPTQ3OjMsOTYpOTU1OjgzOjMzOzMy +Oi0yOjcyOTU0OjgxOi0wOzQzNTMuPTRGUkFSUT5VUUlTVEJVUEtTUkVWVkdTUUBVV01VVUdU +WEZcV0dcW0ZYWUxXWkNeVFBaXEdeWUpaVkdaWUldXUtfYVNdXEZZVElhX0pWWU1fXUNVXktg +WUtTXExcW0ZdYUddW0ZYX0paWkRjXEhZXEVmXEhZYUdgYE5VXEBdXklVTTxUSTtYQTdSWD54 +flh8hWF7f1x8fF96e118e1d0eF92emF2d1x1el16c2B7dF5xeVR6el92dV56dV9yd1l4eF1u +eVd1dF1xdlh5c1pyeFp3d11sc1x5dFt0dFtwclpvdFlvcFVzclR2dl9yeFtxbFhxeVdvblpt +aldtcVltbVV1b1pqa1B0aldpdVFqcFtua1BrbFVnbFFtbFFkbFBrak1pZUxjZUtmak5paVBl +ZU9jZkxmaVFkZ05eYUtPRkQwPTM7PTgrPC8/PDkwOi43PjQpPDM7OzMzPDU3OzM1OzU0PDIx +PDYoPi4yOjYtOzM0PjUwPDM3PDIvOjM1PzI0QDUwPjMwPDwzPDU5PDo0PC85Oz43PzU5Pjs6 +PTM3Pjc7OTEyPjU2PTc2QTk9Pjs3PTY+Pzw2Qzo5PjY5Pzc8QjQ5Oj04QDY2Pjg3QDY3QTgz +QDY1Qzg4RTY8PDk4Qzw/SDySsGn1/eX2+u74//X////9//3///z///f///////z5//33/+7/ +//zy++79//j////4//n8//j////9//n2+vPk+OHj9d/j/trm9OPa7tXY7dbs6ePj7N3k8+Pw +/e30//b+//z7//H3/e3l+uHp+u34//r9//n2//fv/+j0//D5+fHx9+/9/vzz//b+//j7//D9 +//bu++34//jt9uXp69/e79rVe4guOzc5OzotPTE4Njg1OTQxOjYyPDkvMzUtOjY2NzUsOzY0 +PDc1NjIwLzUuOy8wODUoNjE8PDcwNTM5NToyOjA4NzgxNTA4OTssOSwsODg3NzU0ODcuPjIx +PDE4OTgzPS4yNzAzNzUzNzg2NzEyNTMtOzUxODE9NTUsNjQ3NTYrNzI+OTcsMy46PDIuNDA7 +OTM3PTg1PDI+QDhQSD5TRTlGRThKQjtERjtKQDxBPzs8OzU3OjUvNy8zOjkuOy4xOzgxNzc1 +NDgxNC4zOzM3PDEzNjkzNjQyNzQyNTQxOTczNTUsNjIzNDgsOi0wODQxNDA0MzYtOzMxOTI2 +Nzo3ODY5ODcxOTEyPjY0OjQ4PTMyOzY7Py82Ozc2OjMzODUuNjQ4PTUwNjA8NTcwOTA2OjYv +Oy80NTctNjQwOTcuNTU0NzExODM3MzU0OjVDQTc4PDc0NjczNTYyNjQxNjU3PDcwPDEzOzcz +ODU6OjowNzM5OjgsOi8zNzYxOTQ7NTgtNjI2OjYsOjk0NjwuNjMwNDEvOTQtNDQvOTMzNzgy +NzIzOTkvODE0OTkxOzEyOjEqOS8uNTUvNzM1OTQtNys6NjkvOys4NzwuOSwtODgzNTA3OTcw +OTcxOywyNzYvPjQuOTQxOTEyOTIwOTIvOTU3ODAyOjQ0OzQzOy42OzwrOzc7OzsmPTI0OTYv +Oy83NzkvOTg2NjM1OTkzOTEwOzYvOzE1ODQvNjQ1OzcvPzYwOjk3PTkzNTo4OjswNzEyNzwu +Oi0sOTMwNTQ3NjkvMys3ODkwPDFFU0NVTkhOT0dVTUZQUUNXSkZRUz5XVktYWEhWVkpWVEda +WEpbVklZVExfWEpXV09dWkpWVk1hWkhXW0laW0haWEhaV0hbXVBeWktXV0lTWkxfXkhTXU1g +Wk9bWUliWE1aXUZeWkpZW0deW0xdWz9gW0xWYUVhX1RZYkVWWkxVUUJPSzJSRDtQWT14eGCA +d2J8eF6AeWR+fF18eVt2fF95e2N8dVp7emR7fFt+d2Jyd1t9eF16dV55dF10dFl4d2F9dFtt +cVtzd1t2dF5zd1t4c2Bwc1Z0cVpzdFt6d11wcVhvclp0bFZ0c2Jzclp0bV9wclN1bmFxcVZw +cFdsaVVvbFZtcVhsbVZ0Z1RralRlaVhoaVFraVFqZ1JralFtalJqZ1FqalVgak5oZ09bZk1l +ZU5gaE1oZFBcXkpORj82PDc9PDY0OzY1PDU3PjkuPTQ0OzYvOzQzOjYvOTQ2PTQ2Pjk0OTEz +PjY1PzE2OzgzOTQ1Ojk0NzE1OTo1Oi4zOjc4PDI1OjY1PDQyQTg2PTozPjQ2PTUxPTA2PDgt +OzU4PTUtPTQvOTQ0PDYvPTY2Qjc3PTQ2OzUxPTQ1OzczPTQ8QTczPTs1OTc4QDk3QDU8Pjw1 +QTQ9PDsxOzc8QT08Qjygt2n+//n////7//js/Orv/ev9//D////z//H0/fHz++n9//T+//r1 +/fft9Of0/uj5//T4//Du9+jm/d7h9eHc7Nnd7d/O5cTb6tXf89rc7Nj8//H6//fz/ujt+Orr ++d7x/vTy/+nk+ub9//v///z7/+39//n+//z///nu/ezy/+nq/uXk9d3i9OLy9Ojk9ePu/+Tk +7eX0/fHz/+vz+Orp79rKc3s2Ozc8PTstRDI4Ojk1PTA3PDg5PDU1Ozg4OjY1NDQuOjY5OTg5 +NTIzODAwPC06ODQxOjA3ODQtPy81NjcrNyc1NjUvOi85NTsxOi45NjMzNTM2OjQ6PTc1ODI1 +NzU1Oy41NzI+NjAwOzQ1NDM4OTE5PDIzPTI+ODIxPC85ODUrNS9CNjYqODE7OzMoOjE5NjE4 +OjQ7PDhORDpcSzdRQzlEQDhLOzpAPzREQDhGRTRPRzhAPDY5OTE0ODM1OjA3ODU0OywwOjMw +Ni40NDYuOSowOjQyOS00OzE2NjAsOzE1ODMsOzE5OzQvPSozOTUsNiw1NzMzPDE3OjM4PjQx +OC45PjgyODI5OzU1OzM0PzE5OjU8PDA6OjI4PzQyOjYvOy42OjIvNiw5OjUtPC44OjQsOC8z +ODEuODE8OC0uOjI1NzQ1PTI7PjE/QzhQRTdBRDg6NzMyPjQ1Oi81PjY4OTU1PTI4PjUxPDA5 +PTguPC45NzU0PDE3NTIyPTA4ODUvOy01OjMuOSw0OjMtOi8yNzUyOjAxOjY1Ny8zODMyOzMx +PTEzODUyPDQyNy0yODYuOS0vOjQtOi00PDEvOio2OzQuOyc0OTUsPCczOTgxOi8wODYvPjUz +ODIqODM3OjYyODM1OTI0OC8zOjQ0Oy82NzQ0OTA5ODYwOzA3OzQvOzE3PjsvPC43OTYpPC40 +PTUvPzA4PC8xNzAvOTQyOTUyNzEwMzMvNzE0ODQ0OjMyOjQuPTQzOi8vODYvOTEyODQxNSgz +OjcyOCsyNzsuNi46ODc8OjBFTz5TUUFSUUdQVkZWT0VXVUdWVT5aVEVWWEJbUEpXWURZXUte +V0JbWEZfWUZUWEleYEVWU0tiV0hXWkxiWT5YWE5iWkNZXUxcYUhfXEheWUVdX0hWV0ZkXUhb +XENgWURWW0FZXEVbY0RiYEVcX0FkZExZXT9kYENbY0BfWkZQTz5VSTtVRTxUXDx0eliBf2J7 +emKGel+Aelx8dll8d1d9d1p0e1p1dV12e1yBe2R0el17cll1gFp6dl97elx8d2B5d151eld6 +eFp1eFlyc1d3dV50cVZ2cFpzdVZ2cF96cV52cl1vdlh0cV50cVh1cGByclt0cl1yblZ2b1hy +blZ0c1lwbVdxb1Nxa1Zub1Nxa1BoalFvbFVtb1FrZ09pZ1NlZ1BraFVkaU5mY01hZ01mY01e +ZkprZFBdYEhNQjswOTU8QDU4OTczPDQ4OzQ0QC42PTAuPS48ODczPTM5PzM6OzQ0PjMxOzIx +OjA4QDQ0PTQ2PTYzOyw4PTkyPC00PDQ3PTA2Pzk6OjQyQjY9OjcvQTI4QDUyQDQ8OzgxPTM4 +OzY1PjY2PjczPDQ5PDc2QTg0ODE8PTY0PDo1QDg6PTU3PTo6OTQ7QTc2Ozk8QTc9Ojo5QDc7 +Pz41QTU9RDg6STakyXr+//b///////7///////3///zx/e7+//j///n+//zy+ubq9uD3/+/+ +//n09e7r+eHn9uTo797u9+fv8Ojr+eHh6+LY7szt9Ore6tXg4tfm/Ony/+7x8fDl897t+/Xz +/ufm9eT0++nz//T5//Px/+/v/eXl99vl897p8+Pr797l8uv7/fT6/ff4//X19e769PLy5+Xx +/Oz6+O7u9urv7ebUc3Y9QDk6PjcxPTk9PDg2PDg1NDYuOjwzPDY8ODc3PDg0NjcuODQ8OTQv +ODM5OTUuPi44NTk0PjY8PDcvOTE6NzovOzE0NjUzPDM4OzI0Ozc9Njg1PDU4Ojk3OjM5NDc5 +Ozg6ODg0PjQ3OzEvNTQ3NzY4QTRmSUBdQThCPTgyODI4ODgzOTA6OTc3OjI3OjY5PDM7Ozc6 +QDdhTTxfSj5aRjdVQjlNPzpIPjg+PzRCQTlKQDpJRTZLPjs1OTg5PTMqODI8OTgxOTA7Ozcs +Oi88OTgvNzA7OzApPDE4OTc0PDI2OTIxNzA1ODQ6NzgrOTE4NjUxOjY5PDM7PDQ4OTU4Ojk7 +NzI2OjgvOzQ6OzkyOCs6OTo4ODBBQTxBOjg3OTU6NjY1OzM3NDgxOy8yOTE0PTM1ODIuODRB +PTFMPzs3ODI4OTY2NjNAPjtIQTVcQz9EPzk7PDg1PDA5ODI0Njg6PTc1ODk1OjQ5OTUxNzg5 +ODg0PTY6ODkvOC86NjQuODE0OTQ1Ozc0NjkzOjc4NzE0NjkyPTE0OjQ0ODExNzQzOzAzNTQ3 +NDMzOjE3NjswOjE2NjkvOy84Nzk0OzQzODkvOTM3ODszOTM5PDkwOzMyODUuOjc2OTkzOzUz +OTU8OjU1OzU1OzU0OTU1OzY3OjYwPTI6Nzc1ODQ7PD4vOTE3OzowPTY3PDYzNy06OjszOys1 +OjsyOi82PTc1NzQ5Ojg1OToxNzIwOjQ2Ozw1Ojs1PTQuPDA3ODQvODE3OTYuNTQ2PTsrPjE4 +ODouOjA3PDgqPTE8RjxDUD9VVEpbUkNXUkNXUUlZV0VUVEtVWEJaV0lXVUpcWUVZVUdaWklj +VkZeVktaWE5aWklhWE5XWkxjWk9eW0NdYlVWWENgXE1bWERdYE1gWkxcXEteYkxbYUteXk1b +XEteYkheXUpbWExdYEleXUpjXU1ZYEZhYEtfYUdlXElUT0FaTDhOQTxdX0V/fmOBel1/dl2A +fF2EfmN7fF+EcmV2d1uBe2J0elx8elp7eF6BeV57elx8dlp2elp7emJ9e155dlp3cVp9dFpx +dVx5dVl1d1t2dV11elp5dFtxd117bl1zd1h0blxydFd2dFpwdFdzcF1xc1V0cVpwcldzcVtz +cFlybllrbFRub1hxbVptbFVtbVRwa1FxaVFtalRlbE9tZlJkZk9oZlRjaExqZlNkZktoaFFk +YkxmW1FEQzs6PT00OzU8Ojg2PjU2PDM7PjY2PjM2OjM2QDM8PDg6Ozw3PDQ9PDk0PTQ8PjUu +PDE8OzUwPTNAPTkxOTE7PzouPjQ+OzkxOzU8QDMzOzQ2QTg0PjY1PTc2PDkzPDU1Pzk2PTo2 +PTY0PTY5Ozg5QDw1PTc4Ozk1PjM7Qzw4QDU6OTk4PjA3Ojc3QTI3Pzk9QDo3QjZCQj06QDs/ +PDw4QUA+Qzmk24f6//L///n///f////8///2/ez+//v///z///jy9vD3/er////6//z8/fb4 +//T9//v9//n3//Hw/O/q9t7u9efh9uHr/OPl8OXe6tfZ49P19uvu8urz/vP8//fv8+Do7uLt ++/Hw+uz3+/L19erz+vr58+/+/v7///X0+PH9//7///v9//bp/+zj/d/s++7z/+by//n08url +8ODw9+js793Zc3o2PTJDPTsvOy47OTsyMy07PTovOy41PDgyPTY0PDQ0ODI2Ozc1ODg1OzI0 +PDQzNy85NzI2PDMuODQ4OzcyOTE5OTctPC06OC8tOi47NjAyNjI/NTgwPTY6OzU0NzU9PzUy +ODIzOTE0NTUyNjE5PDU0Py9lVjldTDxQPjc+OTQ3OzA4QDYwOy82OzM/Pi47ODk+PS9RSEB6 +Vj1vUEBsSTpfSThOPzdCPTRBNTo2OzM8PTRDRzVWRj9CQTM1NzczODQ6NDY0NjQ0OzMyOTU2 +NzUuNTE0NjM3ODEvNDQ3PDIzOzE0OzIzOjQyNjY2OTEtOC08OTg4NjQ9PTUyOjM6NzEuOi82 +ODEyNzQ0Ni8wODE2Oy81PC88OjU4PTs3Oyw2ODcyOzM0OjU2NzY1Ny83OzMuODA3ODZBQTNV +RDo/QDQ3ODM6OjJEPDdQRjhoSUFDQTc+NjMyOTU4OTU9ODM0PTc7OTU8OTg2PDc0PzU2OzM1 +NzQ1NzUwNzcxNS83OTg0NzM6PDgyNzA2OToxNywyODkuOSw0NjsxOSw3OjkzOzEwODA0NDMy +OTg2OTM2OTkwOTYuOTMyNS4zOTUyOjI3PDUvOi42OTgxNjI8OzUqOTM2OzIvOjg3ODcvOzQ2 +NjU0OTMuOi01ODIxOCwyOjUyPDI0OjY0PjQ3PTcwPDU3NzEzPTY2NjA3OTwxPTA3ODgwOys0 +ODUuODI4PDcyOi8vOzUzOjExOjM4OTAyPDI1ODguOC83ODsyPTE0ODwwNC02ODM0PTAwOjc2 +OTM2Ojg4PDYvPTBLTz5RT0dTUUdVUkhZVEJUUkNaU0dVUkZZWEdcUU5XWkZeW0dtf2hmXUtV +Wk1iWUlbYEVbVk1VW0NfV0tfXEhfV0tjXkhiYUdXYExdWzxXWkZgYExVX0hhXUtTWktbWU1a +WEtbWEZbWUthYUphXEVjXU5dW0dhX1BbYENpWE1VUTVUTDxQQjRZXUF8e1p7emOBe1p8eGF7 +emGBdV19elqAfmB5dFt7eGF4flx/dF95e1yAeFh3dl99cmFzeFd9eWR7d1l4d2N2dlt8gF54 +d1t1d1l6dlp2eFl0dVt1cFxycF51dlpzdl1zclZyc1t1d1hxcFd7clhvcFd0c1xtcld5b1lt +a1d0bllna1tua1RtbFZsblZvbFRta1NxalVpZk9lZk5mZk1rZ05rak9paExlY05pZU5qZEtj +WUhEQD02OS47OTc3PS82PjU5OzI4Pzs5OjU2PjM1PTg3PjY4PDQ1QS83PDUvPy82ODcyPjM4 +Ozg4ODQ8PDcwOjg1OzMyPzQ2PTU6PjU2OTc7QTYxPzU4OjY3Ojg0QDY3OzkyPzY6ODk0PTQ5 +PDY0PTQ8OTgyOTE9OjgvPDU9Qjw3PTk6PzU1QjY7PzY0PTc3PTg7OTo8OzI/RTs6QDk5PDQ7 +QThCSzyo2ob0++f9//j3/+vx+ev4/+v///v8//T89vL9//j////4//P9//H///b///j9/Pjs +/ers/+fu/+rw/Ovu+ebu++nf9uLT7MnX5dLf8dbf89v0//v1/+vv9e/k89rd697y/Oz+//7/ +//3t+ejr+u329+z1/O/z+/H3/PL4//Dz/fH5++vq+Ovs9ers9e/5+PTy9Orr7N79/Pz///77 +//ft8+XOb3Q7QDc6ODszPjc2OToxPzY1PDYqPjA1NjUsOjM4OzgzODE5OzIvPTcxNTQzODQu +OTMxNjIzPzk1OzY1Oi0yOTAvNy0sOjEyODQuOTE3OjgoPS8yNjIyPTU2OzI3ODI4OzktODQ7 +ODY0NTI8OzczNi43OzU2QTZQQTpZRjlGPztAPTdCPTlAPjdNRDlRPzRTQzleRTuTUUGsaEap +ZUjHhlTUiWWwXElaPDo/PDI/PjY0PTJBPThPSDhLQTkwODM4NjM4ODM0Ozc0OjQzNjEwODM1 +OTgwNzI0NjUwNi03OTUsOis2NjQsOi06ODUmOC49NjY0OTVCQDQ4PDNAOzI0OjEyPDIyOTYv +PDM3ODAzPC8yOS4yNS08PTY8PTczOjA1ODoyOi83OzgzNi8wOzctOC81OTw1Oy46PDc4QC83 +PDk6NzQ9OTZCQTc/RTdNRjpAOTg+PTgyOTA5ODM6PjdDQDdDQT09OzFAPDkzODU1NzoxOTE4 +OzYxNzc7OTgyNzY2PjQ0OjgwNzIzODowOTY2PTcwOTE2OTIvPS42OzUvOTI1OzMrNzI2OjEz +OTQxOjQvOTYyNzI0OzUyOC4wOTQzODIwOTYyNzMwPDI1NzszPDc4PTIuPjE2OjwvODE6PDwx +PC41NzkxODI2NzUtPDA2OjcwOzI2PTgzPzQ0NzY7OzIxQDo3OjE1NTs2ODQ5OjYuOzA0ODkv +OjAzNTYtPC00OTQpOC80OjooOTE3ODs0Niw6OzgyOTIyPTQwOi0yOTcsPDQvOSgyODAyODEv +PDQyPjUyPzJNTUFVTkNVVkNPVENYVEdVUUJZVEtSVkhZV0tSVkJaW01UXEZfWUxZW0dhWEdf +VkZbVkZbVUtfXkldVktTW0deWk5hYEhfWklfXEtfW0JhWk5bXEhhX05ZXUllYExaXj9eX1Bb +XD5eXUpbWkFdX0piWEVhak1aX0hbYkhcW0lQSzpMRjxVPzhZYkGDfFx+fmeBe2N5fWKAe2B2 +eWOBemJ3eGWDdV51d1l9ell9dlt+eFqCd2B+eFl+e2N7eVd/dmB7e113d158fF97cmF7clx6 +c1xxd116c151a1p0bl55cGF2cV11b1t4b1dvc1twcldxdF10cFNublZvcVpyc1d1clptcFVy +blppcFJzb1x1cWBwbVVpbVFwallra1FtaFVnbFNoaVVnbFBvbldoZ05bZFFoZE1jZEtfVkdD +QDs7OTQ5Pjc3PDQ2OTk1PzI/QDkxQDc7PDsvPjU6OjozPjE2OTk3OzA5Pzc2PDU1ODY3Pzkw +Oy4zPDc2Ojg7OzcuPzMxOzM4OzUuPDE7QDc1PDM6OTgvOzE9PDcyQDQ8PDczPjY9PjkuOjM8 +OzYxOzg8Qjo4Ozc3PTQ2Ozo6PTU6PzgxPjQ3PjQ3RDk5PjY2RD44QDo5PTc3Qjc4Qj06QDVB +RkOt4438//P////9//z9//P///////////////////36//3w/uH7//D1++/1/uz7//f0+ezu +9ejt/Ojx/+fm++Pl8t/f8eDd69Xf7+be6NXU4dDy8vDs9urt9uv19Of4/vz////p9uXu/+Hn +9OXv/ejt+uXx/evy/+74//H9//b2//L4++vx/vX5/e75/vX8/+/6//z5+fXt/u7+/+3x/+nm +9N3AaWs6PDk9NjY2NjZAPjs0OCw9PDUwPDU3NjI5NzY2PDY6Oy42ODM1ODM6NS8wNjU1MjE1 +OTE2QzcxOTg6NzMwNzU3NzUuNzY2NTIvNzI6NzgwODE2ODUvODA3OjYwPCw8ODM2OzE7OTI6 +Niw5OTM1OTAyOTA3ODJNRzhgSTlMQDlEQTZFPjdIQTtRRzhZSDWEXEPYsHvx27Ty477038D4 +5L/45L/uw5qtXVFEPDBCPjY+Py9FPzNRRzhbRjdAPjU+NTQ4OzM4OzQ3OzQ2OTIyNzQ4ODUu +NC4wNzErOjE3OTUrNy89MjYsNTE7NDQqOi81OjEyOS5FPjc8OTJBPTY9QDY0OzA1OjAwOjM2 +Ni8zOjI3Oy4zODM8PTJAOTs6QDI2Nzk1PS8zODkyOy4wOTY1PCk3PTg2OCo2PTk3OTExPDE9 +OTI8NzVBOjs5PTc8Ozc2OzBAPTVcRThnQTV8RzyUVEOfW0iERUFTQjw5OzU4OTYvOjE2ODcv +PDA1ODQsNzY4ODMyNzQ1NTM3NjczNy84OTwrNy0wODIuNzI0NjMtOC80NzEyODAyODQyNTU5 +NzEwOTcyODExOTc3NzIzOjYvODIzNjE1ODE3ODIzODEwOy03NzQwOC44ODkzOjAzOTUyOS81 +OzkvOyo1Ozc0OTMyOTA0NzQ1OTU3MzY5NzY1Oi8wODQ3NDI2NTA1ODM0OzUxODQ2ODovOCs1 +OTYyNzE3OjMvOjA3NzgzOik4OjcwOC8zODg2OSs2NzU6OC80NDcuODA0Oi8vODMyOzI2ODU6 +OTczPzFOUUdQVkVYU0pTTj5WUUVTVz5bVktXUEJiWExTVklbVkpXWklcVkdcWUVeW0haWUla +V0ZiakpfWUJgWEtaWk1cWUxZUUVbWUNfXEpVUUtfXU9aYEVjXU9cW0BiYE1bVzxdXk9cWkRa +WUxjW0RkXUtfWkFcXEthYE1iW0NgW0tXTDdRRj9LQDdcZUiAemB8fl9+e2B2gWSEeWJ7eF2C +e2B0dF6Ed155clx9dld1eGF1elyBfV10d2B6dV17dlt8d190d1Z6eGN2dV6BdVpydVR4dVxs +cFdzdVt7dVl2dFh6clh0cll3b1p3cFd2bVt4d1lyblx5cFlycVZycVtrbFh3allvdFZya1xq +a1NsaVZpa1VyaFRobE9vaFJna1FublBna01ta1FnZlJpZUtmZEpfY1BlaU9jYE1gWERDPjo4 +Pjc8PDgzPjI/PTo0PzI7OzY1OjU5PDc0NzQ8ODo0PjM9OTc0OTQ6OjQ7PTM1OzQ3OjQxPC80 +PDYzODUxPjc5OTg3OzQ8PDgxOzU6OTg0Ojg7PDUzQTA+OTozQTI8OzYwODU8OzgwQzFBOjc2 +Njg9PTs5QDc5QDo8QDQ8Ojc6PDg9Qzk/Pjg1OzU6PjM+TkBBQjw5Qj46QjROU0ZDQUNKQkWw +5Yf1/uX4/+n///////zx/+/+//X5//P9//P9//X3/+/8/+7///v///z9//zu8+r9//f+///3 +//Hz++/t9OXs9Ofg8trb9tDh+N/l6eDX5NLt/+zr9+Xz/u/t+/Ht++rs/+3w5+zz9e3+//77 +/ff1/u/+++3j9+Dk+O34/e3u++zl8+Tz+Orv/PX+//z////m9d3o7ev0+e3u9+n0++Xj4ta4 +Y2U/Qj46QzQyOjc4NTg2OjQ0PzQtOzUrOjY2ODM4Nzo6OTYzOzU+OjM0OjQ7NzcuMzU9ODcs +QT8/OjYsOzZANzYwMTY6MzQzOjUzNjE0OjUzOzM3NjE3PTI+OzY0OjJDOzc8PDk+NjY9OjU5 +Nzk9PjUwOjA7PjdEPjdSSUBMRjVJQTxHQDREPzlOQTtiTT7OsWz18Mn5+t33+d/8/eP7/OH/ +99z268Xam3RkQDlLOjZHQTVIPjVRRDhWQjxDPDU6PDE4OjI3OTg1NjM2OTIyNzQ1ODQvNTM7 +OjYxODA7NTg1PTA9Njo0NjI7OjQyPTI8OjU5PDBCPjc/PzY9OjU3PDU6Oy04Pjg/ODQ6OjU3 +NzQ9PDRBPTdCPzRPQT1PRTk3NTUvOjM0MzIyOTM1NzUrNi84NDcwODM4OjY2NDVHNzs7PzNG +PTtBPT03OTk9NzY/PjlbRDuOYT61eEvRm2Pdq2/ktILTlGqjYE9hQDdBQUAxOzU6OTovOSw4 +NzcwNi0yODYyOC85ODk2NDczODM6NjU0OjU0NzQ3ODc0OjMyOTcyODMzNjAzOTgzPDguNzIz +OjcyNi44OjctNjg4NzctMTU3NzUvMzE5PjUzODIxOTUyNzYyOS00ODgrOzY3NjkyOTI2NzQv +OTM3ODk2OTczNzExOjoyOjM1OTc1ODUzOjcyODYzOTQ1PTUyPzs7OC01OjQ0NjQtOTM9ODw1 +ODY1OjsxNzM2Ojk3OjI4Ojs1OzIwOzUzPC8zNjc3OjIwOTw3NTMxODU0OjEyODQ3PTQ0Nzgx +QzhOT0NZUUVYUkxSVUpYVUxYVUNaVEZSW0ZcV0xWWEVaU01YW0RcVktXV0ddWEtaWEVbWENZ +WEpfYktZW1JcXUtaXEdcW0hVWkhgWkxcWk9dXEVRXkhhXExXYUthXk5ZW0dhX0xYWUliW01W +XEVjXEteXktiXEpeV0daZ0dhWEJWQjxNS0BORTphbEmCfmB+fGGFeV99fWOGeWN1e12Ce2Z0 +eVd8dFtzcVh3b2NzdlaAc2V9dll9eF56clyAdlp7eGJ5dWN/eVx5dlp0d1l2dlp6dF94dVp1 +dF58cVl4dVp4cWBxc1p2dF9vcll5bl1qcFV2clptcVdzcFlzb1pya1hybFt0b1ZtbFdra1pt +blZrbFRwa1ZxaFJva1VqbFRtaVVua1VxalRsaFVoZ05ralZjZFBlaVJqYktbWE4/Pjc3PDY6 +PTgyOTk4ODk0Ojc8PDg2PTY9OTs0OjI5PTo3PDQ4NTc6OjU5OjM2PDg4Ozk7Pzs9PTk6Ozo1 +OTc6OzU7Nzk1Pzk+ODk2PTU6Ojc3PjQ3PjgtOzY9Ozk4OTM/OzsyOzg8PDY3PDU8Ozc8PzpA +PT46Ozs7PDk2Pzk+OTo6Qz08Pzc3Pjc4Pzo6Pzg5QT1EPz0+Ozs7QDZDREM/R0FFREi+6oz+ +//////f///////////7///////////39//X///zy++f6//D8//P5/+71//Xz/uzw+Or5/vDr +8+rt9+D6//Ho7vDS3snX3NHf6Nnd4tfl7Nnd99/j9en6/vvy7+He7uDr/eTv/+Ll++L1//b5 +++fi++L4+uz+/v3///vz9/X//v7s+ej0++zm9+Tm++Lx9ezp6dnt+Ojq8eL89Ozo7Nu8Y206 +Pzc5OjcyOi46OzQzODQ2NjEzPyo1OiwyPjE1OzE2ODMxOTI0OzMzOCouODE2OzUuOTE2QDgr +PDA2OjIzNy4yOTUsOjA3NzUrOS47OjI1Ni86OTcxPzA8QjRDPjVTQzplRDNiRTlUQDdEPjhN +QDRAOzc6OTA+PzNDQzVRRDpLRzVHQjhJQzFaSThzZjvp35f7+tn9/Of6/uH+/+T5/N3+/OP7 +8tDktH16T0FVRTRTQzZZTDVhTDplTTtTQzM6PzQ2OTAyPC4xNzA6PTQ4PSpRRTpTTDZWRDk0 +OjE8OzMwPjA9PTMxOjA8PzI/PjZMQjdJRTpFQDJGPDU/NzA/PDE5PDA9QC9DPzY/PTM3OjNA +PjBESjo8PDFLRDpNSC84OjY0NiwzNjY1Oy0wMzQ2ODQtOi0xNjU1NzNAPC9GRDJRQjRTSThF +RDU8OTY9NzE+PzR6XTvBklPlzHj68cL478/69Nnz38Xfr4CobFZXRDQ7OzU2PzM0ODE0OS8z +OTEvOTA1NzQtNzAzNzQxNi00ODMrODEzODQsNS8yNjEyODMzOC40OzovOCwsNzQzOi4tODAy +PDMwOjQvOy8uOS80NzYwOy4tNzQsPy41ODIrPC4xODQwODAxOzEqOiwwOTUwOjExODQvPjA0 +PTc0Oy8yNzQzODItOjcvPy82OS8wPiozQjIvOTA1OTYsOyw3NzMzPS81ODQzPi84OjYzOi84 +PTkwOSo0ODY2OS80OzoyOS8yNyw0NjMvPC8vOioyOCgtNTAvPS8uMi8yOi4tNyo5NTMvQzFN +TkVWUEBYVEhMVkNcV0dVVURdVUFPVkJZUURZVEJVV0daVkpZU0dZWUVaXEVaW0hXW0lXWkFj +X0RZXUlfU0tVVUZhWk9WXEJgWk1ZWkJbYktXX0liY0taY0FXW0lfWEZdZ0lkZkBZXERhWkte +WUZjW0leX0ZgXEhfYEdeV0dVSTlSSDpUQjdfakuAfFuBfWGKe2B9eFuGfWJ8d2CCfF1zcV15 +cFp1bllycVF2clp1e158e2N2elx8eGN4d1t7clt3eV13bVl6eVl3cVZ2c1t1dVh0c1Z4eFxz +clpzcVVyeVtydlVwbFZ1cltvb1h1cVhydlp5bVtzb1pxbVZzdFNyblhtcVFzallwbVBybFZr +aU1lbVZoaVRxaE9nZ0tsalFxa1Rmak9qak5nZk5kZkppZUxfaU9jaE1cWURAPjcxPTM4PTQq +OjE9OzIwPC84OjQyQDE3PzYyPTI6Pjc0PTIxPTY3PTMyOjAwOzMvOjM3OzM5PDY7Ri89Ozk7 +OzA0OjQwPDI6PzkwQzE5PDkuPTI/OjQvOTA4PjQwPjM6QDUzPDM1OTEzPTU0PjQ3QDc4PzU8 +Ozo1Pjk6PTYxOTQ2PTQ4Pjc7PDA3Qjs0Ny84Qjw0PDI3Qzw2PzQ/RT88RzhMUUrP8pT8//D/ +//3///f///j///f///v///n////7//f5//P7/u3x8+Xn9d31/Oz6///q+unr+Ofy/ezy++3p ++ujY7tXU6dLg9NPh69/a6dHR3Mn0+/Tu8er9//v1//H3//f//vLt8Orr7ebu9+ft+Ory+u/s +9un5/vX5//fy/e/+//bx/+n3//Pp7eLl8eHq+Oz///Dq6Obt8uz1/urw/er2//nCX3g1PjQy +OzQ2OzMyOzI7PTcvOTE8ODgwODA3OTksODEuNjgtOzE5PDgrPjU2NzcvPDYyNzgwOjQ1OzUx +ODM5OTY2OjMyOTMyNzU5OTQzPDI4NjQ3PTNBQDdLPzaGUT+bbErAgVm7elKvak6XXDyBUUVY +QDlHPjo8QjRIRD9PRTlaTEBYSD5ZSDdnSDp7aULo6aT8+t78/+P9/+T9/eL8/OD8+uL88NDW +pGl+UkJhSzlgRjlWTjpkTTxaSDlVRDcwOzA4OzA1NTA0OS43OTI6PC5HQzVOSzlMRzwyPjQ5 +PDQxPTc0OS81NzY2NC08QDk8RDFFPj06PDA9QDg+Oy42PDg3Oi44PzdCOTQ6PjRCPDVHOjVA +PTc7OzA8QDc5PjY4NzgxPTQzPDMsOjQzNDExNzcvNDcxMzMwOS9BPTRIRDdXQjlXRjlVPjg/ +Ojg2ODNGQzmCZj7Eo1bo4H/6/cX499f8+uT7+t/y0qq7h2RwTj5DPTg8NzY0Njk3NTMwODQz +Oi8wODU0Ny8vNDc0NTMvOjUtOjQtNjQ1OTMtODEzODcuOC84NzkzOTUzMTYxNzUzNTUrOjE2 +NzwuPC83OTguNS8zNjcvNzAuNzcyOTIyOzQzOjIyOTUyOS40ODQyOTEzODcwOS81ODExOjM0 +NjowOSoxODYxOjAxOTYzODEzODkyNzA1NTw1ODMzOC0xOzEtNzc5OTkxOTMyPTgxOC8zOjM1 +OjMwOzM5ODQvODk4NzQsNy45NTYqOC82NjcoNy02NzQtODE1OTAuOzIsOTY1ODA2QjhMTkhW +U0FaVEtYWkNbV0dXUEVWTEZXU0hUV0lZUU1VWUdhW0tXVUtcWE1dVz5hV09aXEZWXU1eXk5d +V05bX0taWkpbWEteX0ZbYVBbW0dbXUtXXUheWk1jX0ZXWUtlX0dbWUtmX0NVWEthXkRdWUZl +Y0xbXExiY0RbXkxcVkZRSj1RSzlWQDladUqJf2d8eVx/dWF1e19+dVx5c156dmN0dmF1eV5y +a1lrblNtcVR0el6BfGF+c2J6cV2Ad195dl92c2B2c115dV13dFl2c11ydFh2clh1cVh2b1t1 +dVlzclxsbV51cV1yeFdzalxycVdydFlwcVhualltb1VrblZtcFFycFVubFZucFVtbE9sbFZo +alNnaFNvalVva1NlbFFraFJna05nalNlZk9malRhalJoZlJkZ01cVEpBPDgzPzIxOTY3Ozc2 +OjY6PTgwPDU4Pjg3PTU3PTcyOjQ9PTkwPTE8OzopPzE8OzYsPDI0PDUvPDI1PDkvPTM0PDQz +PDgwOzM8PDYyPDc2OzY0PTs0OzYvODU2PDQ1PDU3OTIzPjM0PTE7Qj04QDE4PDs/RTo4Oz05 +OzY3ODs5PjY0Pjc6Pzk1Pjc7PDY0QzE8QTk3Pjw8Pzk1QjY6QTs9RD1BSz7M85n6/Oz///z9 +//////z////2/+39//b///f3//b6//Lz++v1/+n9///7//X5/fP0/+r5//Lw/u3z+Ofr8OTt +9OPr/e3g+tje9tfe8NTi+uT////6//j0+e3i8Nfy/e73//L+//z5//H1/efz/uv4//T+/v33 +//Ho9eDr++z7++js++j6/u/0/e/8/fPz+Ofs/u/9/fnx/+7y+eLf9Ofr59mjW29BQjw3OTo4 +OjM7PjYtPDI3PjI0QDQ/PDU6OjY4OTk0PTQ6OjQwOjU5ODg2OjQ4OTczOjI6OjU6PDc0OTA7 +MzM3OTMuOTQ0OzYxOTU7PC8wODE9PTNFRTiEYEXFn2LYtn3mzJDrwYjr1KfkpX/NiVWZWEhh +SjtTRzlJRjZNRDRTSzpfTTllSjtyTz54Yz/Y4IT5/NX//+D//+H//+P9/N7//eT278O9gVd6 +WD12UUBjSzhjSjxaTTx2VUZkSTg8PTY0NzQ1OTY2PzE4Oy02OTU/OjM7PjQ+PTM3PDQ4OTU6 +NTM7PTk3PjU7PDgyPDE+PTsyPDI+PDkwPTVIQDpCPTZLQDlAQDNLPjdBQTRJQDpEPDk9QTVE +QTdAPjQ8MzU1OzM3ODU1OTQ8Oy48ODM1OjI2ODkzNiszPTczPitOQTtaTTJwVkR6WD9YQkM9 +OzdIRDV+Xj+wkErl2XP6+8v89tr8/+P8/eDo0Zm0hlZpT0BFQT04ODk0NjE5OTcuODI3PTUw +NDQ1OTQyOjg4OTUxOjYtODQvNzg0OTU0OjQwNy85NzM1ODQ3OjI0OTI2NzUwOTQwODIyNzcz +OTMzOjU1Oi0wOzU1OC01PzgyNS82OjozOTIuOjY0ODYyPTc2OzgxPjc1ODgzPDI0OzYxOS86 +ODczODMwOjs2OzM4ODkwOzQyOzQyPTMuNjI1OzMzPTY2NTUwNzYyOjExOTcxOTU1PTkyPy44 +OzctNzI5PDovPTAzPTIwOjE3NjwyNi05NzcyQDA3Pzs0Oi84OjsyOSs8Ojw3Pz1RT0BUUUhb +VEpTWExaTkVUWkZZWEdWWUtZWUtXWEVcXExWXEZiWkxYWkJiWUlWXUVhXExTXExkWkxYXEdk +W0hfXklhYlBfW0ZfYkhgX0tfYExXX0lfYUNaZUlgZEtjYEpbXUtYX0NgXVBaW0pqYk9fYEVp +XVViYENiYU5eW0FUSkBURDpUSjticlB/e2GDfWF5e1+AfGR7gFuAfGCAel58eF+Ad1p7c2Nq +alRiaE90d1d0fFd/el9ze199eVt2d2R8fl96d191el18d15zdlV9c1xxeld4c2J1dVV6cGN1 +dFp+clp1cl55dV10cFduc1x0clp0b1l0c1trcldzcl1xcVdycVx0bE9zbldta1VucFJyaVhr +alRubVhqaVBva1VqblByalJrbFJwaVJna01oa1VxaldnaFZUVUs9Qjw3PTU3OjY3Qjk5PDo2 +PjU1Pjc3Pjg5PTc0OzQ5PDg1PzY8PTo4RThBQTgwPjA8PTkwQjU5PzcvPzY8Pjo4QTU8PTo1 +PzQ5PTU2PTs6OTQzPzg4QDk5PjQ1PjU5PzU9QDo1PzY9QTg8Qzk9Ozw0PjhFPD81QDVBQDwz +QDxDPzozQjpBQTw9Pzo1RDg4PDc1Qjg8Rjw7Qzs8Qzg9RjpAQ0BFUkPY95b0/+n6/+z///j9 +//T+//f///X///r+//f+//r1/PX2+eX9//73//rr+eTp8d/8/+z4/fLs7+nl+93i+trt/+vl +7+Pc8s359+3t7Onb59Pj8tjj+eb1+ez6//b9//z9//P6/+zk9d/x/fDx/+/7/+7v8ebs/fXr +++r7/vP1//ny//Du++v2/fD///3///vy/+vn8OH2+fD5+/P4+PDx7eGeUWhDPD4zODc9Ojgv +PDE7OTszPi4/ODotNCszOzo0PS8yPTM4OS46OTY6OzQ1OTA7PDgxPDQ4ODQ3ODQxOTI5OjIx +OjQzODM0OTc8NTUrNzBBOzg5PjZWRzyZf0zYxnfp6b/799749Nj99tj268royIu/hFNrSzlK +QThAPTVGPzZLSTpkSDxpTTlvTDpeSTuWpFPy9Lf7+9z9/uP9+uH//OL8+9nt2qWpc0yKXUB4 +UDpwTzxvTT98VjlvUkFNQjU/Nzo1ODM8NzY4ODI4MjUyPTE9OTE5NzQ3PDE2OzgyNzg4Nzg7 +NDg8PTMzODQzOTQ1ODMxNC83NTcxNTM5OTg4OTNBQDw7PTVCQDg7PTk/PDUzNjA9OzQ4OTQ/ +PTQ7OTY+OjhCOzdDOjJHPjhPQjFQPzc9OzE0OS8yODYzOTBCQDRgUTSHXkN4XzpOPUA1PTVG +OTtjVDibfUjSxV35+br39tD9/eP07sLasXeedk9bRTxCOz03PDQ2OTU2NjE3NjE2NjU2Ni8w +OjMzOjMwOjQtNys0NjgyNiw2OjkwNS03NjowMysxODYxNy00OTgzODA0Nyw2NjMyNjQ1NTU2 +NzQ4ODQyOTQwMzE2OzMzNzI6NTgzOTU4OTUtOzI0NzgsNy40ODcyNjU4OjUxOzU6ODc2Oi8z +OTQyODMwOzQ2OjQyOTo3Oz4wOjA2NjQzOzEyOTQzOzIyNjI3NTU2OTI3OzkyOiw0OjQxOS4y +OD02Ni4yPDc0NzAzMzQ0PTYvNzUxOjYyOTA2LjUyNy81OTcyNC86OTU6QzROTkZbVUNSTkVZ +VUNaU0ZeVEZYVExhWUFXVk9fWkNbWE1cVkhgWUZdWkdbWUpbYEteXUxZWEJkWlNZWkpkXE9V +XEtlWFNVYExjXVVbYEJkXU1aYUJgW1FbYUtkWklbWU9fXUlcYEtkW0ZiY0tkYE5fXEZbW0dY +XkNmX01aUkdUR0FRRDlURj9lc1GCfmR3eFyAdmF7c119eV+DeWB+emZ9fmF5dlt4cF15alVx +bVNuclZ3c116dVZ4c1t6eFl1cVeCcF1ycFh5cVt3clp5eFx4b1V8dWJ2cV55cGB2cVh3cFtz +b1V0cVp3cl50b1t5bl93cVpycFhzcFJxbVZ1blVva1hvbVJxb1N4blltbFdzaVdpaVJ1a1Rp +a1BwbFRva1RwaVFraVBoak1rZ05uaVBsZ1Jka1JsaFRdU01COz45PTc6OjQ6QTg5OTg9Ozs4 +OTM2Pjo0PDA0PDk5PTY1QTc+OzU9Pz08PzQ3OTc5Pjk1Pjk7OjQ1PzI+Ojk7OjE6QDU5PzQ5 +PTk0PzQ2QDUzQTc3PjEzQDU6PjY8QDk4PjI5QDk2Pjw2QTo9OjU1PTQ4PDc3QDE+PT41PzI4 +Pjc2PjQ9Pjg6PjhCQz07QTs9PD03OzpAQTg8RDs/Qj8+Q0BFSkLd853+//H///z9//v8//H/ +//z////////7//D////+//r+/O36//P7//j9//j69/Lz+uz7/e/9//T8//bw9ezm69/d6dLZ +89PZ69HT38jj7Nrx9/L0/u/y/vDq9+br/en2/vLt7uP+/fvt/evw9e/0+enw9O7w9OX4/vH/ +/+zv9Orm+OTz/fTt++vw+/L4//D+//v5/O////by/+/2//Py8uKTWGs9RDw5Qzg6Ozg2OjMz +Ozk1OjQzODk6ODU4OzQ0OTQrQzI6ODgyPTE6OTcoPTQ/PTYuPDY8OjMxODY2QDI1OzQyPDA7 +OzQuPjI1PDUuPTE8OzQ0PjRcUjyXgErRyXbr7sj7/OH9/+L6+dH07bXUtWyMaElmRT1FPThC +Pjc4PDVSTDp7WkBzTkBpSTtTQztUUTuovVbr9af9+tj6+9z7+tnz76zFnlqydU+fakZ4WT98 +WkFvWD5xWD9gSzlFPzc9PTM7PDY4OzQ4PTY1OzQzOzIuOzI3NjgtNy43NDQvPTA1OTUvNzI4 +OTgvOTQ3OzQ1NjM1ODQ0OzIwNjQxOzYzNi42OjQ2OzgxPjEzQDQzPDY5Njo0OjE6Ojk3ODVB +Pjo+QDNENz0/QzVNRDhBQzhpSEBDOjg7NjMuNjI1Ojc/PzljVTl/aUJdSz47PTc1Pzc2PTM+ +QzZlYj6biknUzF/v75z08bTjx4OzjVR8XkpMRTdEQkM7Oy86Ozg4NjQyOjA6PDgzOzU1NzU3 +OTcyOjgtOTUzNzAwNzAyNzUtNzEuNjExODUvODI2ODUtOiw4OTUtODM0OTQxODQ0OzItODQt +PDI3ODY3OzM4ODguOzQ0ODQ0ODA2ODgzNzM2OTIuOTMyOTIxODMvODIvNzQ3ODM3PTg1PTIx +NTY1OzQ1OzY1ODA1PjkyOTQ0Ojo2NjQxOjQ5OzoyOzU2OTozPDIxODY0PTIyOTg1OzMwOzQu +OTMxPDUzNzIzODs4PDYyOjE0NjErOzM3PDA1OjU1Njc3PTk0OjE8QjhPT0JaWktSVENZVkhY +WEJaWUtZV0VdV0lZVkZbVkxWWUJdXE9XWkZhV0tdYFJZWUZbYk1cX0lZXkdaWkxcX0dhY1Be +Y0lhYExbYkthYE1fYkFeXVBcX0hhYU1ZX0llWk5baERiW0pcYUheYDxhXEpXZkheYUpiY0Vg +XktfV0NSSD1YTDtIQjtlcU99fWN9dmF7dluAeGB1d1iAemJ6dl55dl92cFFrZFVlaEpsZlVs +bFB3eVd8cVp0eV11dl9ydVp4cl96dlV8d199dFt4d115dF1yd1l6dGBvc1iBdl5tcVp8dF5y +cVh/d1xzdlx7c1Zuclh1cldybVlydFp2blpwcVlvbVxucFR1bFtsbVd0bVVxbVNxbVNucFdp +b1RvalVvbVJubVZnalFoalhralFpa1JnaE1pbFBcU0o2RDdBPT02PDc+Pjg0QDRAPDs1QDQ5 +Pj05PDI7QDk0QTY8Qjc4PDk6Pzk3PzY9Pjo4Pzs7Qjo6Pzo4PzoxQjg5PDs8QDc4PzkzPTc6 +Pjk6QDY8QTw1QTg8PzguQTc+OzsvQTc+RDg0Qjs2QTw3QTg5QDQ3Pjc6Pjk3QEE8QTc5PzQy +Rjc2QDs7QTg4Pzw9QDo2Pjw7QT02RTg6QT85QTdAST47Tjzm/KX2//X7//Hv/+n7//Tz/O32 +/+n6/+7///n////1/+/5++v7//T9//T4//L9//v9///29+3z9u/l9d3k+N38//Hz/PXh9dL3 +/fTs9OXg5+P3//Lq7+Lt8+P3/fXs7+Hl/uT++/zz9enp/OXo+Nvr++b1//v///7r/+zx9+no +9+f9//Hr/+X6+fHq+Oz1/vLx/+/y8/X79/Hr8efh59rk6N6WVnI7PjgtPTIzPjgxPTQ1OzMx +ODM3PDcrODI4OzouOS81NTgyOik8NzsnNy86NzgwOC41NzQ6Ni81PTUxOjIxODE5OzQyOTE1 +NzYyPDYzPDM3OzQ8OzlVSDp+a0W+smPg6av4+t31+t345rLSsmOfbE9hTDxTQzw3PzY7OjY0 +PDRFSTduWkBoUDxlRztDPTlEPjhRUjyIkEnK0WLf3XXXyGmqh0p3YUSjfEqYakdpTjtgTj5Y +SDhMQztHQTdAPzc9OTc9NzdBPDc9PTQ2NzMzNTM3NzcsOS82ODIyNjEzNjgyNDMwNDUwOjIu +MTIvNDYxMzQyOTQuNjMxNzApOzI0NCwyNzUyNy81ODQrOy83ODcuNTI2NzU1OS9CPTs9OzVE +PDY2QDFBOjVBPDdOSjlsTz9fRzszOjQzNTAvOTY3ODFNSDlPTTs6ODg2OzYzOTE1OTQ6PDBC +QzVUUjaEdUmqplCzo1yYgUh8YEdSRztFPTo0PDY6OTYpNzA1Nzg1ODcuNzQ2OTM5ODcxOTMt +PDQxNjIzNTUxODAuMTcqOiwwNTUuNS40ODYsNS0xODczNSk0NjwxOi4wOT8xNjAxOTYyNzEz +OTEuMzUtNjMyOTAuOi8xODQ1NzMxNjExNzcxOTMuNzQrNjM0NDkuNzU4Nj0tOy44ODUxODA5 +OTQtNDIyNDEvPDQuNTE4OTcvOzExODcvNi0yNjQvNzQ2OTYtNjYwODMvNTcuNzQzODUyOjI2 +OzkqOiotOzosNC40NjU3NzE3Ojs1ODIwODQ2NTMuPDg4OzUzRTRRV0xRUzxXVUtZVERWUkdT +VEZXV0tdV0hWWUteWUxUW05gXEtXVklaWUZXWlBgWU1XW0tcWEtfWE5dYE5lWkdXYExhYFNV +YEhiXE9ZXkFkWklZXkNbVExiYEFcWlFiY0tdXUxiWkNhY05dXEldW0ZaYU5cYUlZWkxhWUxY +WUVTSztQQzlQRj1ka1Fwc158eWB7fWV5cF15cmR0blp5cltvblFuZlZlZ05sW09aZkxobVB9 +dlp3cF9zblp3blZ2eWx7dF51dl13d1p4d1p9d1t6clp5dl50clt4b1lrb1N5cll4cld3cWJz +clh1cFp0dFdycFx0cFpydFV0cVtwcFlya1dxclVucFxub1Nsb1NxblZubFlybVVoaVJwa1Vn +Z1NvZ1lnalFybFdeZlFnZk5iaFJoakplZ09cUEg8QzsvOzE6PDQ0PTU7ODY3PzY6OjQ4Ojk3 +Pjc4PDk4PDY5PDs1OjU2RTk4PjI8QD44QjQ4Pjw8Qzk3Qz46PTU2PTU5OzU3Pjg4PzoyPTY0 +Pj02PzM5QDc0RDg8PTo0Ozc0Pzw9QTk3QDg0PjY2PjY1QTg2PTY3QDczPDk+Pzk4PDcxOTg2 +Ozg3PzY1QTozPjU7Q0A0QDs+Pjs0QDk+Pz85QT4/RTnO75n9/+////z///f////////////6 +//v4/+/z/+7z//D+//H8/vnw9+z1++z4//D1/+v8//j3//T4/fPx9/Dp8+Ph7uDe88/a7dXa +7NLU6dDk+t7p9erj7+Dr/e/7//f++vHx/+z4/vD7//3////2//j7//Hx//Px9+r1/PH5/fvr +/uf+/v3///n49+vq8+D3/fL///X+//7///f09+z99+2EV2s7Ojs7PTc0PDM8OzcuNy87OzIu +OTQ3Nzw0PTI2Ozg2PSo7OTsxOTM7Njk2OjM1OjYwOC82OTYyNzcwPDI1NTU6PDQ2NTU7Ojc5 +OTM3PTI4PTU2OzZHQzZwXkGcgUzCv2fu86j488DfxXe3g1FzUz9RQzk6PTU7OjM1PjM5OzI1 +PjVORTdhTz9XSjpHPzg/OjRGPzhMRzheTTpkUz1jTj9YRz5ZSzmgf0rKhFKNUkRhSzlRRzxR +QzVGQTpFQjk7PDJEPDlKPzJNPzs2ODI3Mzg1OjIxOTgsOjUuOTcuNzM3OTUvODU3OTEyOjMy +ODI0ODIwMzQxODIwODE1OTEtNzMyOTAxNDItODA2NDM3NDM2NjU0OzBBPTk8PDFGOzg/PDZF +Pjo9PjZMPzRkTDWCU0JSST0+OjgyPjU2PC83Ozg7PDI3ODc1PDU1OjM4NTcvPzE2OTU0Oy09 +OzVEQTVfUUFbUTlZSTxHQzdKPzk2OzZBPDcyOzU4OzIyOjEyOjQyNTE3PDQ0OzQ2NzQuOTQx +PDA0NzIzOjcvOio1OTUxOysxODEuOS41ODcsNy81NTorOi82OzoyODI1OTYxOjIzOTE0Nzkx +OzIwOzUvNjA0NzIwPDMyNzUtOy4sNzIyNjIuOjE1OTUtNS84OTcvOzA4OzMrOzM5NzYvOTQ4 +NzQyNzczPDMvNDg1OjU1PDQ1PDI1NzUuOzAxOzMyOzU3NzQyOzQ1NTEvPDcqODEyPD8wPDE1 +ODYtPS80OjItOC8zPT0wPDIvOjEzPDMvODUzPToyNzVDQjhVVUNYUUlVU0JVVExZV0daWU9e +WUNUWEdYXUJaW0xeYUdaWUtfW0xZWlBgXUZaZEpgX0NcYktfX0lbWUxbWUlgW0xaY0hhWUda +X0dhYU1ZYEZfW01cXkRaXElgY0VhXElfYUFjYFBYXUVYWUpZWU1dWD5aWUhfWkhdXEdbU0RJ +TTdRQUBLSTthZkhnbFJtbFdlb0tsblhjb05qbllkZ0ttbVVnYkpjZU1qY1JkYkdnZUxxel93 +cmFxeFt0bVtxcFJvdlx5dF9zd1h6dVtzcFd7d2BxcVdzb15ubE9ybFhsb051aVpwc1F1c2Bu +cVlxcFt4dlt0bVF1cVh1blZucFlvc1dxbVV3blRtaldwcVZqa1hwa1dta09ycVlqcVNtalRn +bVBxa1Zna1Vsa1Nta09pb1FmZ1JmZk5XT0k2Ozc7OzQ1PjQ7OjU8QzU5QDg3Pjc8QTc3Qjc6 +QDM+QTg3RDA4Qjc4QDY4QDo5QzQ4Qz07Pzg4RD0+RTs9Rjk/QD03RDg5QDo2PjQ8Pzg4Qjg7 +Qjw6RDo6RDk4QDg7QTY0Qzc7PjcwPjg2QDQ5QDcyOjU1PTU4PDU4PzM2Pjk0PDU6PDo3OzQ6 +PTcuQDQ7PjkyQjE/Pzo4Qzk9PTozQTg+RTtETUDh8pn9//r///////n///H///v///f///// +///////9///z/+f9//n///n///7r+PHr8Obp+uPt/enq/+bm+OHh9ePX69fh/db1/PHm7eLk +6Nf1+Ozv+O3x9Ofe89/z/e3w/+z0/fTt/OX09+fu/e79//vt+ev2//H0/uzx/vL9//X9//b0 +9+Xw/Ov+//z1/+7s/ejn7drm9OTo+eLv+uvp7dt2VWtCPDwuODY9OzcpPTFCOzMpOzA/ODcs +OTE2ODEyOTQxOzQ5NzU2OzQ2NzcyOTA4ODUwPjE3PTQuNDE2OTU0ODM1PDEqOy8yPjQ1OzQt +Nyw3OjVGPTVAOzhOST1vXEOOej+xpVfCo1WhiEuKY0JbSDtEQDc3OjI3ODQyOzA3OzQwOTJB +PjVGQTZLQDc1PjE5PDQ2OzE/OzdDQTVKQzdMPzhGQjddSji6mlLZsm+/fVSLXD5dRzxORTVN +Pjo4Pi9APDNMQjRXQjhMPjZGPTMyNy45NDIyOC03NTUwNzEyODY0NjIwNi4wNDE0NjEyODQs +NjAwODIwMTMuOS0zNzQtNTQ3NzcvOysyOjMrNy88OzUwOCxFODhCPDRIPDc6OTJEQjlEPjRD +PjhTRziOakCSbEtQRTo0NTMxODAzOC8zPDgwMy87NzkwNzIwOjczNys0OzYxNC43OTsyOCw7 +ODk8PDI3OTc8OzY6QDA6QjQ3PTE4OzUwOzI1ODA1OTE0NzI0NzU0ODQ0PjcvPC83ODItNjI0 +NjQwOjAzMy0oOjMxNjQuNjU5OTEtNTMwOTAtODQwOC4yNzQyOjUxOTUuNS03NjkxNzQ2ODUu +NTMyOTI0NjgwOC41NzkyOC0zOjYyMjMxNzQ1ODAyPDU1OzMtOTUwODYvOzMzNTgvNy0yMjkv +OC83NzoyNjItNzgvOjIwNTAxOjI0Mis0Oy8xPTs1ODUzOTQwOS8vNjE3PjMxNjYwOjAtPDYx +PTAuPDYwPDAvPTYpNS05OjQxNzEzOTQzPjA2Ojg3RzRTU0lTVj5WVUxWWEZaWktXVEZTWUhS +WUtcW0tYWkhcWEdaWkVgW0dWZElhWUxUXExeXE1bXEdgW05XYkxkW1JbXkNlXExMX0hkW09X +XkldX0pTWEZeV0daYE1fXkldXkdbY0xaXEpjYD5WVEVYVkdZVkZVVEZPUkVVSz9GTDhNSz4+ +QzJKRUJVYD1gVktdV0BaVEdYWEFWV0BfWkdbZkxhX0tWWkVhXUhjZEhfWk1ZWUJlZkxzc1Fx +a1Z4blVmcVJ0dlVrcVR7b1Nzb1h0clVxd150cFRzbFhwbFRpa1RualR0b1Z0eFV2cFlwc1d1 +cFtvblZvcldqb1d0cVZtcFNtcFNyb1hxb1hyblV0bE9ybFNvaVRsbldya1NmalJpalZralFx +a0xobVBoa1NmaU9oZ1Jnak9raE9RS0RDPTozPDA2PjUwOzM6QDU0Qjc+Qzo5Qjk6QTk8Pzky +QjU1PTg3PzY6QTY6PzY1QDg5Qjg3QzU5Pzk0QTI4PzgzQzY7Pzo0PzY5PTgzPzc4QDkyPjc5 +QTQ3PTY4QDk2PzkuOzI6OzIzPTA2Ozc3QDQvPDQzOzIzPTE4Pzc2PDE2OzM0PC82OzswODA7 +RD00PTVBPz8yQzg/QTgzOzY4PTU4RDg9STvx+6v///f///n///3+//z5//f4/+/4/+////f/ +//30/vH4++f6//L6//bw9+T5//Pz/e3u+u30++rk7+T8//Lp9OHv++ng9dzg8Nfb7dTd6tzn +/eX0//n8//D5+vrp7dnh9ePs/erx9+Tt+Ozy9e/q79/k8d/s8Oz9/v37/fX1++zy/vn///7p +9evk8d/k9+Hp6uDp8fX///b3//Xz8+ra4tV1VWY2PTs2QDM4PzczPjA4OjkzOjM2OjcxOTA7 +NTg0OTIzPjM3OzE0PDY2NzQ7OzMzPDQ3OjU5OzUxOjEvOjU2OzQ2ODYwPDM2OjQ5PDQtOTQ3 +NTg0OzM9OTI7PTNMQjpiVUJ4YUdxXEFlSkNURTlPQT40OTQ5OjQwQDM4PDMyOTIzODI7Pjc2 +Ozc+PDg+PTk1NzVAOTk8PTNAPTlDPjxPQDxSRjrFoVzv4qn53bDmwYHXmWSUYkFiST5IQjhE +OTpEQzZdSDpiST9YQztSQDk4OTkzOTIzMjIuODM6OTMwOC43NjcsODI+OzgwNy81ODgsNi06 +NToqOTM1OjQoNjQ3NzEtOTUwPDQ1OTE0NjM1OzI0PTBJQTtURzlHQzpBQzhEQDhGRkBSSDmc +b0aoekmEYUxOPTQ+O0AwPC01NzwzNzY0NjU2ODMyODg1OzQuODYzNzQuNzY7NTcuOjI5PzQ1 +PDo6Ojc1Ozc4Ojg6Pjw2PjU5ODk3OTY5Njk0Oy82OTQ2PDA4OzUzODo5OjgyOjYzOzUzNjkt +ODU1OTYvNDM3OzYxODEzODArODE2OjcuOTYzOjQwOjYwMy41OTkvODIyODc0ODIvNTcyNzUz +Ojc0OjIyOjkxODUvPTI0OTgsOjI1OjoxODE0NjgvODI3PTwvOjMyOTctOTM3NjczODQtNzYz +PDouOzY1PDgxOTY0OjQwPDMyOTEyOjQuOTAyNTQtOzI5PDovNDA5OTk1NDc1OjgtOiw6PDwv +NzMzODsvODA1OUAvOCwyODkwNTMyOjE1Nzk6QzdSVEZXVEVWWklTW0xWVktgWUhZWUVaWEtX +VklgWEpXW0dgYk9SW0dfXE1WXExhYE5aXElcWU9aYkhWYEtcWU5eX0xbW05hYFBgXUtXYUpc +XExhWU1SV0xdWklZZENgV0pWX0ljWU1aX0FWTUdZVjtOT0xERjlJQkRKSTxISD0/RDc8QzY9 +QjlKUT5QUEZYVEFRTEhRSUBUT0VaTT9LT0NYWEdWWEhhUUtPWUdiW0hWU0dfV0NVV0piYUxb +WUtka05sZ1RfZlFwa1ZzcFZxa1RpblJyb1lja1R0bFRjak5xa1poc1ZxcVt1bFpvcldzcFly +cVR2cVtxcVNycVp4b1dwb1hrb1dqcFl1bF5qa1NxZlZrb1JrbVVsalRrZVRsa1RvalZmZVBo +blBobFJsalRgaU5maVJjZlFTTEU+QDgtPTc4Pi84PjctRDY5Qz43QDU8Qjk0QzU9Ozw1QDk6 +RjkxQztARzsyRTU+RDs4RTk9RTw2PTc8QTs2Rjo3QDtdYUE3Qj46PToyPTg9QDk2Ojk5Qjo5 +Pjg0Pjc4NzcuOjc4Ojg3OTY2PzouPjU+PjksPTM3Pzg0PDk8OzgxODU8QTU1OTY3PDc0PToz +PTc7Oz03Pzk9QTkyRDM6QT0+RT0+TDze9KD1/+3x/O/1/+/7//X7//j9//z///r9//r7//H1 +//Hy/ujz/+f+//H6//P9//71+en7//X7//n3//Xo+uvr+ung8uDZ7s3b6tnd6dLb59z09evl +9OXr/u31//P3//3///Pj8eb5/vz////9//X4//z////1//H0+/X1//Tt9erx/PD4/fTz++79 +//v///////3z8Ovp+unr9uvt9+Ph4thmTV85OT02PTU0Ozo4ODIzPjY/Njo1OTM5OzksNzc9 +ODQxNzY9ODMuPDA6OzAzNTQ3OjQ1OTM1Oi81OTQ1OzE2NzgwOTY2NzcvOzM4NzkwOjQyODY3 +PTQ7OjU2Ojg/PTZJQj5SRTlSQztEOTo+PDpFODg+OjY5OzY0OTQ6ODg3NzU8ODYxOTQ5NDg0 +PjQ3OjUyOzM4OTg6PDQ9PDpBPTpFQjuMgkXy76/5+Nv+99v84rPnwH/MmVyfZUpiSDtXRzpY +RjphSD5hUDhlUEJTRjdCOzwrODM3OTgvOTMzNzMxNy82MzgwODc2NDkzNTkzNzU1OjcvMTAz +NjgyNzExNDMwNjY0OjAwNTUxMy83NDw3PDI7OzdVSzdkSj9TQzhTQD5EQTVgTjyVdj3Fm1uw +iVbDnUvfvWXMnFRxSjs1OjUyODUyOTYyNTMzOjQxNTM1Ozg0Njc1OTkuNzE+OTo0NDA3Ozg2 +NC86Ojw6PS05Ozw0OTE2Ojc6ODc4NzQ5OTYzPDM1NzcyOjMzODczOzQ2NzMwOTU2MzA0ODQx +NTc4NzkzNzM3OTotOjEyNjQtNTE1ODkxODMzOzgsOTgvOzIzNzgwPDMxNjYxNjExNzUtODI0 +ODUxODY3PDUtODIyOTUxOTUrOi4sNTU0OTEzOzo1Mzg0OzszNjI1OTgyNzMrPDMvMzgxPDcv +NjgxODE2OTotODI2OzoyNTI1OjgvOSw1NzwxOy8tNzoxPDQuOTY1ODMwPjEwPDAyNDc1ODUv +OjgzOzEwNTMzOTM1OjQuNzM0ODgyNTRASUBVUkhcUUdXVkZZV0pXVUFZVk1YWEZfWE5aW0dg +WVBfWkddW0dZXE5jXUhXXElcW0xSXUxbXk1XWUxXYU5caUxgXkxVYEdbWUpbW0xgXE5SWUVZ +V09RVkFWVEtGT0laWExWU0dTTUlUTURGS0FJQkJFRDtERj9AQzg8Qjw/Qjg8QzVCQTg3RjM+ +RDpBQj5ORkRDSztNQUQ/RzxNRUc7PDdEREVISkNNSUFNS0FRUUBYXEdXVkJaWE1bV0daVUpi +YU1nZlNhZERmb1FxdFhpbFRpZFFlY05vaVFkbVJuZFNnalBtblZpb1p7bl5wb11tc1l2cFht +b1d4dltscVl4cVtrb1ZycFttblhwbFhsblZybFZwb1VtbVdpbFZra1Fua1ZqbFRqalVtalNk +alVobE1kZk1oaU5jaFFUSkc1QDk8QDo0Pzc2PjkxPzU5PTg1QTU8Pjg6Qjo7Pzo3QT47Qjs+ +RTw7PT08Pzg4QDs5Pjo7PjozPDc9OjkvPjY1Pzc7Qjo3OkA2QzY6QTcsOzI2PzgzOzg7PDgv +PTY4OzcxPzk6NjM0ODM3PTYwOjU2OjU2OTo4PjM3OTcyPDU4OTU1Pjc2PjY4OjkvOTY9QDk0 +QDY7Qjg2PTg7OjsvPzlDQUA+TD/m+KP6//n///r///////////v////////5/+75//D1/+/8 +//H///32//Lz/fDu++X9//n9///z/Ozp+ODu9+vy/Ofq+O7e8tDo9+Hq9ene69309+ns/Ozu +7+jq9ef3/O7q+On3//Pr8d3m5+Pl9un9+/rz/uT0/vDu+Oz1/vH///719+zw/PH0++/18erz +++7y/fL89/D///r7//v///75++twVGM+QkAvPjU/ODs0PTc9OT02ODg5ODo0PjU0ODU1OzQ1 +Ozc0MjU/OjIxNzc4OzUyOTc3ODc0PTQ5NTYvOzE9Mjc1NDM3NTczNDE+OTovOC85NTozNjJB +PDg7OTU3OjRFNzdEPjdDPjU8NzM/Ozk/ODc+OjY7OTM1NzI/NzYxOzY4OjgwOTNCNTgyODQ8 +NzUwNzNCOTc2OzNENjc7PTlKPzioqFj69sn6++P8/d//+t/29bv25JnjunSngUOghkBwWjiF +aTuBYzd6XEJQRDk9Ojo1Nis5NzczOC41NTY1NzAvOTU3NzcvNTM4NTktOTMwOzAwNC40NzUs +NDE5Nzo5NzU6NDgyODQyNjQ1ODU4OC9HQzduXD9xUj5pU0B1Vj1oWDy9pUXWs2erf1LEtFL0 +8ZT99tT38NPx5sCGcEQ7NzguOzQ3MjUxODY5ODY4Nzc3NTExMzQ1ODYzOTU5ODE1ODU1NjQy +ODQ2NTc2PTQ6OTc0PDc4NDMtOjE4OTYyOi81OTYwOTE7Nz0wODQ5ODgsODA6NTU3NjY6ODUt +NjQ2NjQ2NTQ0ODY0NjMwNzYyOjI1NDAvNjE0NS8zNzIyOTgvOS40NTMvNzI5OTQqNy40NDYu +OTM2NjgzNS42NToyOTQ1OTkxNjQ1NjcyODQyOTE3Mzg3NzQ3NzQxNDQwPDM3Mzk2Ojg5Ojgz +NzM6OTgyNzA8OTgtNTI5PTcuNDc7NDEtODU6NDMxNTEzNDE6ODQ2OzQzOjM0MzU0OjQ0ODU0 +ODQ1NjUrNzI5ODYuNzA3OTszODRDQD1PV0FVWUtXVkZZVlRcVkddWE9gWkZYWUxcUkNYXU9a +VUxaW0VgW1BaWkNkVU9eVEljWU9hXk5XXE1gYEpeWkliV09ZU01jU0hTVEtiVEVOUERXUUVR +UUxRTEdOTUdOTz5NTURWRUJNRUVEPzhKOz9BQDxJOkNAPTtBQTo6PDU+QTc5PDA6NDg6OzQ/ +PjlAPzVDPjs9ODxDPjQ1PDs6OjQ0RDZEPztCQEFQRz1KRT5PSEFOTD9VSUVRTEBbSUpZVUhk +T1BjZExqZVNpZ1JoYlBjYk9sbVRxbVRoaFFqaFFsbVNzbF1xdFpwbVV0cVlycFt2b1txa1l1 +dlptcVR9b19va1F4bmBtb1V3bGBobVN1bl5qaVNvb1lxaVNvbVFubVZqbFRqaVZkZ1NpbFJo +bFNnZ1FmaVJiYk9PSUc2OzY2PDYzOzA8PjUwPDY+Ozk0OzdDPDs6PTY9Ozs3PDQ7PTg8PTo7 +PzQ6PTg0OzU4Pzk4PDg6PDozOjo9Ozg3PTY5PzY5Pjo4PDc2PTw5Ojk5OT42OzE3Ojw0PTM3 +Pzs3ODU6PjQ7OzY1ODY6ODc0OTE5Nzc1PDU4OjYzOzQ4ODM3Ojg5PTk1OjkzPTo7Oz04OTQ6 +PDo4OTo5Pzs4OThEPzo9Rz3c6pz0++b///////////z///////7///n////////////5/vL2 +/+35//H2//L///z4+fbu++H+//z9/vfz++7l7N3a8NrX7s3l9N7i7Nzi8tjr7+Hc7dzw/evs +9+Tv8u7z9ufr8Obz/u3x+vPz/+/+//bm8d70/vv8/fTy/O/z++zu/vH19+vw/O/3/vL1/u7z +/fX18/D5//Dx9efy7+nm49drTmRBPzktNzM9OjczOTc5PTkyODg6OTUuODw4OTQ1NzY1PTU7 +ODk1NzE2ODgvOS82OjA2OTA5OTUwNTA1NjE7PTU0OTI1ODU1NjY1NzQzNzI0MTY2ODdAOjg5 +OzUzOTQ+PjY8OTQ9ODg2NzM6OjU0OjFBOTk2ODc1Nzc0OTE6OzcxOjc4OTg0Njc6OjsyOTM7 +OjUyOjM+ODhEOjg/PDhDPDtjT0fSwoX49dD+/uD9/eT9/N77997xy6idW1Z9VU1tTEJvUUVl +RkhSQjtJOjw5OjI1ODc7NDc2OTQyNTEzNTU8Nzc2NjQ0Mzc1OTYvNzQ0ODUvNjI3NDYzOTQ1 +NjYwNjE3NjUrPS86OTowNDBAOjk8PzFgSj59XkCSaz6WaEKebUl7Tky8rVv69bD//d7//uD+ +/uP+++H7+OPbrplHQDkvOzA4OTYyNyw2Ojk0OS01OT4yNC41Ozo0NzExOzg3NzoxNTI4ODU2 +OTo2OzczOzU7OTU3OTgzODU1ODM5OTI1Njg3OjY7NzkxNTQ6NzkxOTQ5NzgxNjM3MTMvMz04 +OjQyNzM1NjM3NzQzNjM3ODwxOTE0NjYwOTUzMjcxNDU4NTQvNjU0ODQzNTg1OjIyNz0xNTg0 +ODs4OTQ0Njg3OzEzOzY2NjYxOTEzNjQzNjQ7NTUyNjU6NTY0NTI4NjY2NjM2Nzk3NDU3NDg2 +ODU1NTg1NjQ3OjQ5MzM1OTUzNTQ3PDk9Ni41OD4yOTE2ODczNjg4OTQwOTczNjUxNS02ODgv +NzE7NTczNy41Nzk0Nzc9NzhDRzZbWUtTV0VaVE9WVkZZVkhaXE1YWEhdWkxYXUtWW0xjVUta +X0xjWk1XYEteVUtZW0hiXE5XXEhfWU5VVUlhV05TUkVZT0pUT0hVTkpFQ0JGPz9CQEZHSUFG +O0RESENEQUFFPj1COj9EQT42OzlEPT07PDhEPD88PDQ+PD09OzBBQjsuPC89Nzw8OzNAPDk0 +ODI+PjY8Pzc5OjY7OTk/PThCOTw7ODdCPT1EPDxFPEBEPj9MPkBKQz1ERT1RTEBVTkZbTEtM +TkhnVU9gXVFqY0xlVU9kZlJtY1Rwak5uaU9vclR3a11ubFh3clpwd1p4cFxzdFt2blh1bl1v +bldvcFpubVhzb1hybFR0a1Z0cFFybVd3alZraVlybFNqa1ZvZ1ZpaVNubFRlaU9palNlak5o +aFRnaFNlZFBLQkE/OTg3OjU1ODw4OTg9Nzg1ODg4OzY4OTc5Ojk+OzgzPTk7ODU/PDU4OTw4 +OTs7PDU5PTgxPDc9OT03PTU6ODksOzQ7PDk0PTg6PDk1PDQ6PjwzPDk6Pzo2PzY8ODc0Ojg7 +Ozc0PDc0PDQ0PDY6OzkyODI4NTk2PjU6OTk1OzY6OzctPDQ/PDoyPjY+OTs3PTVCPTo5PT09 +Oj01QT48PDo9QDpAT0L8/bP///X4//T///////////////v////9//n8//X+//7//vry/+v9 +//H///z2++37/+73//b6/+3w+u3w9uvm9uPg6tvV6dDa49TW49De5tPt/+j0//H1//X6+/P2 +8uz9//75//Pt7eT0/e/9//3n++r+//r5/+3p9ub1//v///nt9uvy/Oju+ez0//Dz+evq7+Lo +8uPz/Ov2/+/y6urT2c1zUGA4QTc2OTk0OzU8PDczODYyPTg2OTM1PTQxPjMzOzE0QTM2PTUy +QC82QDMsOSwzOTUuOjYzOjUrOi02OTMvOCo0OjgxNC44ODsyOTEuOzQ0OzMxOjQ9ODQ1OzEz +NzQ1OjM5OjU3PTQzOjM4NzM2PTM1PjI2NjE1PjIvOTE2OTQsOzQ3PTQsOS8/OzcwOTM6PDU2 +NzU6PDE3NzY4OTJCQDpDQjZeUUmsr2Dn6Jb09bry8bznzY2hblRUQ0BJPDtDOzxCPjhCPT89 +OzM/PTo2OjA1OTU6OC0zOjIvNzMtNTAwODIpOTAuNzIsOjAyMzEqOy8yNTMxOzI2NzUwOjIs +NjQxPDQxOi8wOzM1NjEzOjI6OTRBOzc/PjlMQkBLR0BOQEBMPUKboEn3+b/8/t3//+P7/+L6 +++Dw6caidGc9Pzc0Ni8vOzM5OTQtODU3MzIyODM1OTEtOzcxOjEyNDM2OTExODAxPDcvODU0 +PTcxOzM1ODsvOzI2ODMvNzIwNjYtOC81NTYuOTQ3ODYwOTE3NzYsNjIxNjEyODUtPDU0NzE3 +OTkwPS4yODEwOS4yOjUxNjQzODMuOTEwODEtNTA0OjgwOCo3ODwzOS00PzgvOC42ODkuOC0y +OjkwOTE1OzExODUuPDMtOi8uOTEyNjc2OTUyOzM0OTMwOTU0ODAtOC84OjYvOTI4OjQuOzQ6 +PjUmOS02PDgvNTQ5PDQ3OC8wOTA1OjcvOi4yOzcsNSwoOTQzOjI1OzYyNjMzPDIwOy41Nzc2 +ODUuNikzNzEtODI7PDk+QjJVUU5UVkVTV1JXVkVXW0peW0FZXUpaWlBhXUtcWUdYXEhcW09b +XEdYVktdWUlaW05eWUdTVU5eVkhVUkZTTUVGTkZPTkBJR0NQQjw/RT09ODg6PDo3Qzg5QTk7 +QTU+OjU2QTo8Pzw0PTpAOjg2PDIyNTY7PjM6Ojk8NzM0Nzk/QzI4OzY2PTI1PDQ6OzE5PjM4 +OzM6OzU1PTo3Ojc0QDY2Ojc1PDJBOjg1PTE/QDg1QTk9PT88QDZARkBCQDhOSUNFSj5FR0RL +TEJWTktgWEtTU0dYXEdeYU1gak5sZlVqa1ZudFhxdFd2cVlycVl0clxzcVd5dVxwdFd1cFpz +dlVycFhtb1RybVlsb1NyblZqblZycVlubVVvbVFubFJvaVRobVNqaVRna1RsZVBpa05pa1Jj +a1JjXk5CQT48OTouPDI7OzYzOzI7OjMsPTI4PjIzPDozQTQ2OjU0PzU2OjUwOjM5PDk0PTM8 +Ozk1QTU4OzY0PDg4ODI2Pzk2PDM3QDs1PjI1PTo0QDE3PD02QTg8QEA5PDYxQTY2PjcvPjY3 +PTUvPDIyPjI0QTk2PDoxPDU4OzQ2PjY4ODU1OjcyPTQ3PTQ2PTc/Qzw4RDg6PTw4Pzk+PDgv +Ozg5QDY6Qz9HXDrm8rL+//H////+//v8//P9//////3v/+38//D+//r5//P3/+n9//f1/vDu +++X5/+76/vPr9+Xu++Ts+ebz/urs9+Tp/Onp+97v/Ori9Nvo7+Hs/+n4+/Tk7d/k8OPt/ubh +6d3y/vD4//Dz+eje9drl9OXs/fDw+ujw/Ozz/vL1+/Dw+e34+/v/+/X39u/t/O/48/bj597p +7uTs9uPx+Orm7N5mTGg1QTcyPTcxPTYyPDM1PTU1PjEyOjUzOjMuOjYuPDM0OjQ1OTQxNjZQ +RkMsNzo9OzcpOTU7OjMyODU6PDMrOjY3ODMsNjYzPTQtOTUwOTE5NDcqOi8zMzQqNyw2ODMn +PTM2PDQvOSozNzIwOjQyOTA2NzYzNjExNTc0OS41OTc0OjUvPDg4OC8yOzIuPDIpOi85Njgw +OzE7ODc2OzI3OzUyODI3PjhASDVWWD5weEJ2dUJcUT5DQDkzOzI3PzM3OjY4QTY5PTQ4OjMz +OjM1OzQwPC83OzcqOjU1ODYqNjEzOTEsODEzNjAoNjE2PTAoOSs2NTIwNzIyOTAyODYzOzQy +NTMyOzM0PTkvNzI3PDM0ODgyOTU3OjUxPTQ3OzY0OzE8PThWYzrZ4mzv+sT++tfz+9Dw6rOq +l1xYSD4rPTM4OzYpNjIwNzMtODUrNzEtNTItODQuOTExOTMtOS4zNjYyMzEwODQsOS03Ozkr +PDE1Oz0uODA3NjosOTEvODQuNSwzODcxNTI0OjYvOzIsOzIuPDAsODIwOTIxOjY8SDo0NzQx +MzEyOjYyOjUyNzcrODEyOjUtNC82OjgnODA1ODUrODI1NzQuNjQvOCwuNzcyNS4uOTEtODIx +OTYwOS8zODUsOC0zNzsuOTUuNzEyOTYwOzMyOzUsODEvOjkqOiovOjwxNS0yNzo0MTUvOjkx +OjA1ODAwNzgwNzQzNzUwOy82NDUsNy03PDgzPTIuPDYrOjAxODIyOjAuNzExOjAqNzUyQDQx +OjwxODQsOzQ2PDQ+SDxVVUZYWUtXV0dbV0xaWEdfWFBWWkRhW09VX0VdXkhWXUdbYk9XYEdZ +V01YW0pdX1RZWkZZWk1XT0NMT0ZDRkRERkBCRkA8Pzg7PjU6PTozPjA4PzcrQDg6QTsrOjE2 +QTgoPC45NzQnOik5OTYsOis7PjkyPDVEPTxIQjlYSzlSST5ORz1QOzxWRTdWPz5NSDtFQjtK +QT1GQjhJQDg6OjU+OzczPi41ODgrPS49RDszNzM5OUAzPDE2Ozk8RDE6Qjg/SDpJTj5QSDpP +TUFTVkZhWUhVVkdQVj1kZ01vcFRvbFh2cVlwcVt1bltub1d6c1lucFh5c1lrdFt4cVlvc1Z2 +cFltbVhyclRvbVpubldya1ZkcFNxbFZucVpqblhpa1Vua1Bqb1RpalJlaVRpaU5rbFNhZk9b +X04/PTgxOzgyOTQ1OzUzQDIzOjk3PDQwOjQ4OjUtODI+ODovPDQ2OTYvOzY6Oz03QDYzOjk1 +PDY2QTYyPToyOjkyOzc2Qjo5PTs3Qjg3PTUxPjovOzY5PjoxQzY4Pjs1Pjg9QTktPzU6PTgw +PDU4OjUsPDI6PDgsOjM8PjsyOjQ2PTUyPDc4PTY3OjU6QDc0Pj01PjE8Pjg+PTk2PTg6Pjg6 +PDk/SUNHYkD8/87///////////n////8//z+//T///j////s++j5/er8/vL9//j///L1//Xz +/PDv+er0/Ovp9ufn9d/q9uPo+uLd8N7b8c7h8Nrj8t7a49rq6tze9ePz+fHx/fj///3x+/D0 +9Ozr7Nzr/O3+/v75/+v1//r6//n++fj1/fHx//T1/+3t/+7y/+zq9eng/OHn++f+/v7///X0 +/vj5++3y9+NkUmc7PDo0OzY2OjMyPDgyOTk5PTQsPDQyOTMzQTI0ODMyPzQ0ODc5OTM6Njkr +Oi80ODYwOS42ODoqPDI0ODMuOS40ODkwNy8yODQuOS4wOzI3NTUvOTQ5NjIzMzU1Ozc1PDYx +PDI5OzYzOS8vOTMwOjQzOjkpOjQyNjYtNDE6OTkwOTE6ODcwOTA4ODk0Ni84OTc1ODU1OTAz +OTU3NzIzOjMzODQ5OjQ3NzU1PjU7QDc6OjE7PzUyPS89OTUvPjE+PDcxPTRAOzowOzA9PDgq +ODE5OTYuOzYzOTc0NjQuODUxNDMqNzMyODQsNzU3ODMzODM0NzUyOjQxOzEvMzkwNjE3ODcu +ODEyNTkyOS00OTYvNS8yOjc3ODAyOzY3PDAtNzE3Ojg8PjhjaUCwvVHP1mbEvV+He0pNSDw3 +PzU2NzYuPTMwODgrNTQrOjcsOC4uOTYrNi0rOTUvODYwNy8zOTkuOTAuODUtPDIxOjMtOzAv +PDUrPDAzNTEsNjEwOi0rOTM0NTUyOjA1OjQxOTkvNzYzOTYyNjIwNzQwOS8xOTkzOjQuPDQv +OTYsOy82OTgrOzAyODQuNjQ1NDQrOi4yNjctOjIzOzQvNi00ODgtOTMwOTktOTExOTIvOTMq +ODUxNDUtOzAtOC0zOTUwODEyNDQuOTcuOTQuOiwxODknOTY1PDspOC81OTMuPS4zNTc0OC41 +OzUoODM2PTs0OjMwOTMuOTIwOTcxNjUwNzczNjIzNjMyNzY1OTctPjMvOTcqODQ1OjQsODE2 +NDQqNjI4OTg6SDldV0xTU0daUUxWVUdZXUhXVEtZWUhcXFBeXUxaXE5aWUtbXk1ZXkhYXUZa +YVNXYExVVUtOTkFKR0c8Qj0/Pz0zQSw9PTs2PTU8Oz00OzE4PzcyPzUzOTc6ODgvODEyODgq +PSwyOjQ6NiwyOzI4OzBEOzZURTtRRj9rVURlTz9wU0BtTjt4Vj1yU0F1U0BvVkJ4VUBnTDts +SzlnST9hTDleQTtEQDVNQTo7ODM4PTUyQjQ3OjY2ODMzPDk3Qzc9PTg9QjY/RjxATEFKS0NF +TEFXVkhRU0dgW0lcYUduaFNqcVZ1dV10c113cF1oclZ0dGFydF5zcFhuclVwb1psb1Jvblty +bVdzb1lsblRvbVZ0a1VubVdrblFnbFRoa1Jpa1Nmak9qaVBlaktrZ1NncE9laFRmak1fVk05 +Qjs0OjgvOjI1PTgzOS43PDMtODAyOjkxOjMzPTY2OzQyOTI1OjkwOzY0PDczOzUxPTE0OzIv +OjM1PTgvOTQ4OzYvPTQ8PTkuOTQ+PDwvQTY8PjcxPTY8PDkzPTQ6OzY3OjczOzk4ODcyPzU1 +PjkzOzQ1ODc0PDs4QDQ1OjQzPjQ0Ojs1PTM5ODw2Qi46PD8yNzQ9PUM4PDg1Qj47ODg4QDlA +RD5JaETk+bz3/+j4/O36//v7//b3/e3+//j////7//v8//X////7//D4//L1//P1/+r9//X9 +///7/+////////bu++7e8Nnk89/s9dve6N3a79jR4c/1//D1/Pz///n5/+3s9e3x/uvs+Ory +/vH0//H0/e3o/e77++7u/vH4//Py9+nn+Or7//vn8d7w9+37/ff6+/D1/O/x7ev5/vr///Lr +9+Xd4dNbUFM/Oz0zPzQ6Pjg6PDg1QS40PTgzOTs0PTI4OTkuOTY0PDYuOzA9OjQvOzM4PDYx +PTM7OTgvOzM3OTYrOTU4NjYuNzQxPDguNTU1PTgwNTUvOzQwPDE7PTMyOjE0PTQxODUxOTUy +OTItOTUzODE1ODYtPjU2OTgyOi02NzgvODA8ODUvNzE7PTY4ODU0ODczNjI6Oi0yNzc1NjA2 +OjM1ODA1OzYxPzUzPTI2OjUyQDY7OTc5Oy88PDYxOjU9OzYrQDVCPTozOzM9OzgrPDU3PDU3 +PDUxPC4tOzQ1NzIzNDczOzg2OjQxOTAyODUuODUzNTIzOzIyNzIyNjUuOi81NzcuQS0vOTUy +OS0zNzo0QS40OjI3OS81OzU1OjMzOzQ1ODc2OzVAOz07PTFMQzpTSj1QSEBKPjxBRTk4Ozww +OzAzNzkuNi8zPTUxODEyOjYzODQ5NzgtOjY1OjUwODcvOzMxNzUyOjM3NzgzNzE1OzgyPTM5 +PDQrNzI4ODMqOjAyNzMvOTM0OjItPDUwNjI0OTc1ODcvOjUzOjEuPDMzOy8uOjQxPDEwODA0 +NjQwOjY1NzQpPi44NTcvOzExOTUoOjAzOjgwOy82NzUyODI0OTkvNzE3PDM3OTUqOTQyOjEy +QDkwODE1OTUwOC80OjcsOjU0PDQsPzM5OjgzOTE1PDgvPS82OjgvNi02NjUyPDMyPTswPDM1 +OjwyOzEyOzQzPDQyOzMxOTA0Py0uOi4yOTExOzgyOzIvOjI0NTUrQDcxPDMpOS80OjosPCoy +OjUtPDBFUz5RVkdYW01VWEhZXExZWE1XXkpaWEtZWkpZXExbXEtbXk9fYkxeW1JcXENeX0pb +XEpTUkBORUE8RztCREIzODE6QDs1QDM4Ozs9RTQ4PzU1Oi84QTY3NzouOzE2OUAyPTIuOz02 +PTA6PTk6QDFDRjlYSTxVRj9wSztnVEN7VkFyWUN8X0V8YUWBX0F2WkV8WENuSkByVD5xVkFy +U0FvTUNsUDhlSz1bRzZaRz1EQTg/QDo2PS4zPjM3PjE9OjUyOTQ4QjVDRDhISTxKST9JSz5X +UEZYV0JdYkdsZk9xc1N1clhvcld5dFx2dFh1cV1wcVp1cVtycldzbVZscFlzbV5ucFdzcVtt +clhwb1hzbFRua1RzalNmb1VtbFdtblVtcVNxaFRnbFNsbVZlaVJrbFJjak9oZVFfWEdBPTws +Oy82OzUwPjA2PTkxOTY0OjguPjYxOzMxPDI0OjQ1OjYyOTIyPTQ0OjgyPzQ1QTY2PDQ8PDY0 +OzM8PTU0ODM8QzgwPDc5OTsvPzg/QD4xPjY+PDszQT0+PTk5Njo1QDw1PzcyQDI2OzkoPjM0 +PDUzOTM0QDg6QDg2PDQ1PDU3PzU2PDo3PzA6PzoyPDA6PT06PTQ8QTw4OTQ5PzpOUEU9SEFP +dUr3/Nb///z////8//30//D////5/vX0++36/fD+///s/e7y++X1/e/3/+z///3///j4/uzu +/+jz/+7t+ur0/+3u9+zw++vf9Njc6Nfj5trm79v0/+/x9uTx/O3s+eru+O7x/fXy+enk/OLx +8urr+Of+//zu++n4/fvs+ODt/fHx/+j4//P4//L4//X+//r///T6//n18uzq9ubp/ubr7efi +4dhYUV07Pzw5Ojo/ODcvODc/PTgtPDI9PjcvODM3OzIxODQ6OjQsOjQ8QDE2ODQ0OjI6OTcz +OC43OCsyNTI2OTQyOTM1NTMzOzY0OzMyOy8xODE1OjQyOTJAOzg6OjgvMjQ6PDA4Nzc1OjAw +MzQ6ODQ5OzMzODQzOy4yODEtOS80OjArOy03OTEwODI3ODQyOzA3ODMyNjE5OTAsOS43NzQ1 +PzI4OzY1Oi4uPDItOjE6OTUzNzA8OjcxOi88ODIvODA9PTU3OTdBPDg0OzA6NzYzOjI7ODIv +Ny84NjYuOTIzNjUyOTI0PDI2NzQ0NDAxOzQzOC8yMTc1OTUsODM1NjUtMC43NzUvNy42OTcx +NjQ7PTorNTE8PDUtPC88ODkqOTM6NzM1NzI3Nzc6PjQ6PjVDPjg/Ojc3PS86ODc3ODU4Ojk1 +NzE4Nzc1OjE5Ozc5ODI3NzcuOS04ODY0NzE2Ojg0OiwzODkzOi8zODc9Ozg0NjU1OjQzPzQx +ODUwPDQ2NjA0PTc4ODE3PDQ0ODAxODMxNTQzODYxNi44NDcvNzE2PjUsPTE3OTUyNjEyOjQw +OTQvOTQuNjMuOy00ODgwOzAzOzQvOTMzNjMzPzE1MzYxODI2NTY0OzI1OTUwODQwOTEzOTYu +OSwzPTcyPDIyOjk2OCwxNzQyOzQwPDc3ODkzPDU2Ozo2OjQ3NzozODI2OjQzODYzNzIyODI2 +OjI0OjM3OTw1OSwuOTQ4NjEzMzI5NjAuNTUyOioyNzA1OjAyOTgzPCw0PDcyOy01OTcyNy4/ +QTs8SThaVktYWERXWEtbVkNeWE1XWEVgYFBcW0BaVVFWX0pbWkhaXFBaWEhTWktZV0pXWkZX +TUVIRzlEOT03PDRCNzsyPC88OTgvRDQ8PjwwPDE1PzgpPTM2PzYsPTU2PjkxPTE3OzVAPjhL +QDhNSzlYSz1dSkRlVEJxVEV8XEJ7Y0GBXUiEYUWIX0iJZkSMX0qKZD6WYU2CXjeFUkV5Tzx0 +VEJ0VT50UT9qTz5nRzlbSTtbSTdYPzVBPDI7Ojg1PS86QDM7Qy82PDZDQjlJUD1OSjxPSkBW +VkVdaEpqZ01nb1F5dVh2dFl6eFp1cll0eVh2dVp1cVdvbFlybld0b1lxbVBydFVrb1F4bVNv +blZqblJrbVRnbVBuc1VubldrbFdralNta1ZxaFBma1NsbFFlbE9salFsZ1JlVEw5QzM3PTQs +OzI3ODYrOy86PTQzOi84PDcyPTE3PjY3PjQ7PDg0PDc4Ozk2PjQ2PzY4OzQzPDdCRzc3Ozg2 +QDU0PTc0QjM4Pj00Qzc9QD0zQjY6PTo3PzU8PDo1PzY6PDo2PjY6NzguPzY2PDM1ODU4QTg3 +Ojs2PTI3PzgzQDI6PDQ2PDYzPDE5Ozo4PjQ1PTgvPDA2OTg2PzVCQTszRDNGRT43QjxSgUfy +/9n+//f///v///////v///v///v////+//74/+v8//L9//X///74//T2/+/6/fvq+uP5/+7+ +/fnu+u3n8+Pn9+Dd8tvW7c7t+OXr9e3j69Xx+ebv++v4+O/s7urr7OLx/fH9/vfu/ub4//j1 +//D59erk693w/urw/O3+/vv///n3+/H3/vj7+fXx7+Xp9+nu++ry6uv6+/Tu9e////3///9h +T1xBOUE2PzY8NT02PzMzPzozPjQ9Oz0xOTM4PzU2NTI4OTM2OTU6NjczOjEzOTQwNzc1Njc2 +OjcrNTcsOzE6NjYuOzM1NTQyOzU5OjgtNS42NTkyOjI+OjstNjE4NDw2OTE1ODYzOTkzOzY5 +Ozc1NzgyNTYzNDIwOzQ0ODYyNzMzODc2NTE3NTYwODI4NzQzNzM6ODgtNjM9Mz0wODM4ODYv +NjI5ODU0OTY0OTgzNzU1OTQ3Nzk0NTU0OjMzOjI2OzY3OzU8PTU4Ojk4Ojg6Ojk1ODQ4Nzkw +NzIyMjsxNjQzPDk2NzMyNDgzODIyNTU4NTYwPTE6NDQuODU3NjgvNzI0OTYyNjMzOTQzNjQ6 +NDUyODgyNzE1ODYyMzU6NzgzODM3ODI4Njg8OjU0Nzs4PjQ4Ojk3OjUyPTMxOTI5PjYuOjI4 +NjUwNDU7Nzw2NjMzODUsODY3MzUwNzQ1NTcwODg1ODs1NzQ0NjU0ODkzOzE0PzU2MjYzNjQ2 +Njs0NDEzNjo1NzA1OjkyPjQ5NzoyNjI4ODYzODE1NjcuNjE4MzUxOTkzNjwzNTQyNjY2NTIw +NzcxNzcxOTUwODQxMzUwOjY0NzgxNzAxNzkvODM2OzksOjU3MzowNDA2NzgwOS84NzwyOTU1 +ODswNTE1NzQyNzQzOjQzOTUxOjYzODQxOjYzOTgvOTgxNzQzNTgzODU0NTgvOjA5OjsuODA4 +NzcsODQ2OzkrOTc7ODkvNDM2OzMuODcsNjQsNzgvNTMzODg0OjM1NzcyODEwPDg0ODIyOTQ+ +RUJRVUlZV0tVVUtgWFJXWEdcV05aW0lfW1ZcWkhZXFJhXUlgYVBbWEdVW0NaWlJXTkVQTEhC +QTlAPTw5PDU2OTY4OS8yNDg4PDQvPDs9PDspPDg/OzgvPDQ6PDYvPDxDQzdBPTpKQTdNSDpU +Sz1fTUBnTz16V0p9YkWJZ0uIa0mSakyRYkmZZE+OaEOaak6VZkiaak2QakiPZEyKYEOMW0aB +WkeEVj58VER2U0V1T0BuSUFeRjtTQT1EOzc9Pjo1PDU8Ozk6PTk/PD5FTTlKSkFFSz1WT0de +W0dkZU9ua1N2clx3cFptcF94cF11cFxwcGB0cmBwblhvc19sbVt2a1xta1Z1bVdxbVRxblts +bVR0a1htblJ0alhucFFuaFxma1RmaFVsalZwbFJra1VqalJtbFJpZ1JhVU0+OTo3NzI0OC83 +OS81NjUzOzc6OTk0Ojc6OTgyOjk+OzovOjQ7PDgtOjM4OTQ0PDo0ODg8PDg3PTY3OTkyOTQ6 +ODc1PDI4PTgxQjY6Ojk4PTwzPDc4Pz44Pjg5Ozs4Pjg+PT0xOTE1OjczOTE7Ozo4OzgyOjg+ +OTgxPTQ0Ojc0PDQ8PzkwQDU8PTk5QDc6Pjk4QDw9OT47PTs6Ozs7Qjs8Qj9BRkJPfErq+c32 ++e77//Dx/ev8//f3/O/+//7///////76//f7//n2/uv7//H///b6//f4/+3+//v8//Px/fH1 +++vr8OX4+/Dl9Ozq/dro+Onj9Nzg7+Dt++v+/f3r9+fq++T9//76//H2/fH0/Ob0/vL7+e3q +9eTt+O7+//71/+3y//Hz/Oj1/u/+//T7//P+//v9/fLy++/u9+j4//Dv9eX3+u/h4dNRSU89 +OjsxPjM5PjgxQTM0OzQrODE1OjkzOCw4OTcvOTE2NTk2OjA5OTgxNzc3OTQxODQyODc1NDcu +OTMuNzQzOTU0NzIxNjMuOjU0NTUzODYyNjIzPjM7OjkuNy46MTguOik1PTUtPCo2OTgqNjE2 +OjcxNTMwODU2NzU5OzAxNDExOzgzNzUyOjMwNzMtPDIvNzQ5ODcwNTA4NzcyOzM8OTcqNzU6 +NjgtNzI7NzUvNTQ6OjMtNjMyNzg0NTQ2ODI3NjgyQDc6OTQ1PTQ5OTczNzY1OzUvOjQqNDM1 +NTY2NjUxODMtMzAyMzkwNzIzPTgvMi81ODkyNzMwOjowOTMxODU4MzEyOi81NzYxPzQ3Ozcx +NTQ1Nzk0NTU1ODgzNDMwNDA3NjUxNjYzOzM0NzY1PDUwNzQ0NzgxNzU7OzQvOzQvNjMyODkx +NTIzNzcvNjA0NDYyNjU1NTctOC84NjgvOjM0PDcvNjM1OTI1ODk1NzM4Nzo3OTUxNzIyODMs +ODg1NzIwMjY2OjU2OTEzMzUzPTMxNjYwOjEwOjYrODEvODQuOTIwODgwMjU0ODYrNzI0OTMt +ODEzNjYwOjIyNjUzNzYxMzUtOjIxOzkzOi4yOTorOTYxNjctNzUzOTYrODUzODgsNi40ODot +NzA2ODouOi43NzkvOS8uODguOTEvOjY3NzszNTA2NjsyOjk1NTgyODc1ODY5NjcyNzI5NTcw +OTEyODMuODQ4NjcwNi85ODoqOTE5OTgrPTE2NzcnNTE1ODQsQDUxNTAzODQ0OjU3Njs3SDhT +WUlVWk5XVklYWUZWXUtYWkZbVkZgXE5aWklcXE9ZWEFbVVJbWEVaVkxXXEtUT0xHQTs8QTg3 +PzcuOTM6OTo0ODk5OzgyOjA1Oz01OTQ1NjU5Oi0yNDw8QzY3PTlFQTlESj9fRzVVTD5oVzxx +VUR8XUSDY0aKZ0uRaE6VeVKkdFahdk2kcVOddEyiclSUbVGfbkuYcEmTY0qRZkaSYEmJYkGP +W0WDWz2GW0SHWUKBV0NvTEJjRjZcRDxFOzo6OjQ9Ozk6OTA6PzU5Qzc/QjtIRz5YVUZYX0pk +YktiZU5raVprdVd2b1x1c1pxdlxybF97cld5clVvb1pzb1pwbVZybFRwb1Rwb1hzaldla1Nz +a1dubVRybVhla1ZubFZna05va1loaE1qalVlaVBpaFNkak5kZVJYVUs3OzUyOTUyNzMwNzQy +OTIzOjE1OzYuNTM2OTY0PTY4NzgvODQ9OjkoPDI7OzgsODM8OjcsOzRBPDstOTU9Ojo2PDg3 +PDQyNTg2PDg2PDszQjQ3PTw3Ozo4PToyPzY4Ojo3QDc0OTM4PTk4PjM2PDo0Oy44PTw2PDE3 +Ozo3OjQ2Oj03PzMzPTc3OjsyOTU+RTo9QT4+PDg2Ojc9PT00QDo9Pzk6RzlRgEj6/+L+//r/ +///7//T5//L+//7///7///////7///////////z7//f////9//v2//P///b5/vjs8+fy/un8 +//Lz++7k+OPb7tPg793l69vT39Hu+OX79+709fPy+/Hn8+nu8uP4/fz//+3y/e7///7////7 +//Hs/uv5//j3++/8//X+//fu9erp8+Pt8+jx//T9//zu7uTv+uv9/fXs9Ons69tUTVE+Ozg2 +PDM3OjI2QDA4NzczPjAxPDA2OzU0ODc4ODgxNTE6PDMrNzA7NzMrNy88PTQuNzE+PTQuOzE2 +PS4zNzE1PTA2OzEsNi82NjYvPS80ODUyOTI9ODczODE4ODI1OjA4PC0zODMzOTE4PTI0NTA4 +NjM2PS4zOTMyNys4ODM4OjAvPjA4OS4wODQ4NTMvNzA4Oy8zNCs7Nzk0OjA3ODMzOi0xNzAz +NjU+NTgxOi8zNzA5ODU1ODUzOzEyNjE5ODczODc7PS85PTM0OSw0ODQ1PS03OzIxNy4zOTcq +ODM1Oi8tOCszNTI0NTM4OjIvOS85NjMyNy43NjI1PDUxOCswOjUyNyo2OzM1OjI0PDAzODAw +NzA4PTQyPTA3OTM0NjE1ODkuOiw6OjcvNi87PDgtOC1AODgvODI4NjUqNS43NTM0NSwvOzY0 +NzE2NjA0MTQ0PDI3NzQuNy8xNDAwNTcxNzA1ODMuPDM1ODMwPC82PjU0OzIxOzUvNyg2Ojox +OC00NTk1Nzc2OzA0OTE1PDIxOi8wMi00OTIxNyw1NjU1NzA1OS40OjIuNzE2ODYsOS01OTYt +Ni03NjYpOC8zODQtODI3OjQxOTQwOC0yODQ4PTM3OjguOzM2OjMvPDE4OjQ2Oi80OTcwOzQ0 +PC4xOjUwOTM2QDYzPS8+Nj01PDAzPT0zOysvOjY2OTIxOzAvOy0yOi83OzcyOzQ1OTcvOyw2 +NjIzOjI1OjQyOTAyNDk3PC8zOTQ3OzI3OTQyOy4uOzUzNiw2NzQ6PSwvOzU5PCpBSkBcV0dZ +XkpZWUNYWUdXWEhcWEZXV0NcVUtZXUJaVklcXkJdUU5WWUJYVkdRTz5PSUc/RTRBPTs6PC04 +OzMzOjQ4NzQyPS8zOjM4Oy81PzQzPi89PTMzRzBBQjRBRTlYTD5ZUzhtTj52WEGKZEmLbEqZ +bE2cbU2bcE+cdEiedVKjd1CugFSwg1OufFCteFKqfE6rfE6rckygakqdZEuVakSUZkqOaEKU +Y0qLYj2QaEiHZTeNW0SBVTVzUTtlSzdcRTVFRTFCOzY7PjU7RDE2PDI8RDRPUDtcZEVkaUlk +ZkdkZk1tbk5vb1R6d1luc1p7cllyc1R6cVRxcVR0dVhtblZ2cFRyblVvclJyb1hvcVdua1Rt +blNublZqbVNucFhrb1VsbVFrbVJoaU5qbVZvbE9va1NvZ01XU0g5PjQzOjQzOjIzOjQ0OC0y +OTM8OjEyOTA1OTI1PjE4PDUwOjI2PDUwQC84PTMzPzE2PDY4QTM0PDQ3PTU2OzM0PTQ7OzQ2 +QDM5OTc3QDU1Pzg3QTg2PTU3OjI4ODkzPTA2OTUxOTM7PzY0QDE9PzU0PDA6PDQyQjA7OzA3 +PTY8QTUyQDY3PDAzPTM3PjU+Pzk5Pjc7PTk3RDQ7PjZAQjZAQzlDRD1RhEb3/t34//P+//L/ +//n///n///j9//z2//H///v6//r3/+/3/eT9//v6//H3//D7//fz/e39/+3///X2/+/z/unn +8+Ha6tfS6Mje7dvc7dDm9dv2/+7z+O3p++n6//zs++vz+PLq++jz9+Ty/ffz+/Dt/ert8ujp +++b8/fb+//L4+fHq+uv8/vv///////P1/Ozz//Hu8O/3+u/5//ny9Obi5dVWRlgzOzQ6OTs0 +PjI+ODgyOjE3PDoyPjI6ODg0OzUrODU6OjMxNzQ1ODczPy8vNzM1PjEzODc2ODQuOTU2Ozcx +OTM6OjQrNDE+ODIuOS45NzIyOTU0OTMyPjk2OjAtOjI2PDM0ODMtOS02NzQyNDQ3NjgvODU3 +OTMzODA8ODcwNzQwNzcyNzUzOC81NzUzNjE1NDc0NTIzPDY3OjAtOzUzOjMvOzY1OTctMjQ3 +NTYvNjE4ODgwOTM1NjYsNzI0OTk1Ojc4PTkxPDU4OTUyOjU5Ozc4NzI0OTQvOTUtOTM3ODcu +NDU0NzI0Njg0ODczNTcyOi42MTIwNy41MzgwODQxNzQwNS42NzMrNTM0OjktNi46NzU1NS85 +ODMtNjQ2ODY4NTk1NC02NzgzOzYwOjQ1ODIyNS44NzgwNjM1NjkrNjQzOTctOjM4Nz8tOzA2 +NzgsMzQ7NzYsNzM0NjUxMzE3ODgxNzIwODQzPDQyNzozPTc3OjYwOS0xOTUxOTEzNDkxODMz +MDYxODA3PDkyNjExNzovMy0yNjkvNy0wNTo0OTMzNzs0OTQzNy0yOjczOTg0ODUuODY4OTkx +ODEuNi4wOS8vPDY4NDczOy40ODctODA4OTotPTE4PDUrOi82NzQsOTM2NTUtOTQwOTg0Nzgx +OTMyOjozOTM0PDYuNzc1OTc1PDkxOjM2ODkyPDM4OzgyOTE5ODcyPi83PzowNzAzNzozNjI1 +Oz01NjM1NTQ3ODU0NjUzOjcyODMzNjgyOTE4NTgwOC4xNzcxODEtOjU3OjI6SEFZWkZVWktZ +WUlWWEhYXUNcW0xaWkFYXU5cWk9aWkhcWEdWTkdQTT1RT0ZKSkJHRT87QDU7OzwzPDQ3Ojkz +PzE6ODs0NC01OzkzODA2QDg1PDE/UztERztTRThWUz1jSjtwUEV3V0KFaUibcFOXak2ca02T +cVKlelyrglOreFivfFWveVusgla2glmyfFezeFurfFC0eleibkyccE2ncUifbUucakqha02c +akqXZUmYaEWTZEaNZUKOX0J9VT1+ST5iSzVUQDxDQTRFQT82OjE/PTtARTdXU0hZWEhiYktz +cFFucFRub1RvcFZ2eV5ybVtzdFh2cVd5cV51clpwbVd6clxxcFhwcVhlb1tya1hubVVybVZl +blRtbFZsa1VycVJra1JsaVRpbFdraFNpZ1JmaVBqaVJWUEU8ODozODY3PTM0ODkyOjYyPDU6 +OTE7PTk3OjM3OjYzPzIyODY1PDAyQjg5OTUwPjQzOTcuOzU4PzgxOzQ8ODowOzU3ODgvOTI7 +PTk3Ozc3PDouPjo5Ozg2ODcyPTg1PzY5PTM3Ozs4OzU6PTQ0Ozw5QDg9Pjw1Ozg5Pj82Ozk6 +Oj01QDc/OzY3QTZBQjozQDc6Ozg2RDg9QTw7Qjs/RDk5QT1CRT1Sf0j6/9r///////////// +//////////////////3///f4//f6/+z8//v7/+/9//vw/uf3/+/y/u3u+ezs++rp9Ofk8N/x +++fo+uTh69vV39PW3NHn+eHp9eLe793e7t3Y6tfk9un68On0+O70+en3+PX7/vb8//n///by ++evu7Ojc6t/s++nx+On0/PP5//Px++zw/PP19+7z/u7s+Oj1/PXk69ZUSFEzQDY4ODczPjc4 +ODQ2PDY0OzU1Ozg4OzIzOTM0PDMzOzIyOjMuOjE0OS4vNjA1NzMyNTM3ODguPDAzNzIrNi84 +NTUuOi83OzcuNyo0NDoqOzI2Ozk3Njs5OTYtOjAyOjQqOjM2PDU5NzMzNTQ0NTIzOzcwOTMv +ODMwOS84ODMsOjA6NzQwNTQ1NzgtOjE0Ny8tOzA5ODQsPC42OTUvOC80NjYwOS80Njk0OjEw +OTIzOTYuOTE1OjM3ODQzNTI1PjYzOzQ1PjkyPzI3ODEyOC84OTUsOTA2NjMxODU6OTgsOi84 +ODUuNS8vNjExNzEwPjU0ODQuPTE0ODYxPDQ0NjcxNzc4Njs1OzUxNjA0NzkxNi0xNDgyNTI3 +NjgzNjAzOjgwOTAzOjgyNyw1OTY0OjEwPDg2NzUuNzMzOjcvNDMxOTQ2NzI2MzkzNjU0ODAo +OjIwNTItNzYuMzMwNTkyODQ5NjYtODI3PDgzNjUzOjUwPDI1OzIxODU4NzA1ODYvNzAyODwx +OzM2ODcwNzA4OTkxNzI6MzM0OTUyNDQvOjYyNzMvODQxODMzODY2ODAyODUuODQzOTg0ODU1 +OjkzODQuODQyNzkxOTQwOzUuOC81NTYuPTAvOjcuOC4zOjktOi40OjIuODA1OTs1NzU0ODg3 +OTc0Ojk5OTUyODgzPDUyOTQwPDYzNjQyPCw2OTgxNi82OTowNzM1OzkvOTY2ODcrOzIzOTsv +OzMxPDkzOTIyOzcvOjM2PzUvOjUwNzE1NDM3NjgzOzQyQzYvPTM5PjY6TkBXV0pXV0ZcUkhX +U0dYWVBZWkhhW0xXXkZfVUxUVUVYWEtLUENRTEVLRkFHQDs8OTg4OzI2OjQzNzo3NzU0OzQu +QDc1PDIuPzU3Pjg+PTVMSEBWSUJZT0BfRzdqUUhwWkCHY0uNaUuYbE6Yc06ielKre1SsfFSu +dlqtgVW1h1u3h1q4hVy6f1e1glm7iFuyf1q9flW5fFW4gliveFOtfFKeb02raUiibk6ocU2h +akybZkmaaEyWaEiUa0iTXz2KX0SBXDxuTT9WSThRQztERDU+Ozc9PTlEQzlMTUJXWkVhXE1j +Y1FlYk9sbFJmbFN1cld0c1l6cVtxbVlxa1ZscFd0b1pxcVpyb1tzb1RzbVdqbVBxbFlqa1Fu +b1psbFZqa1VqbFRta1RobFNmalVrZ1JhZ05oaVBaUEk1OzU1ODY1PDI8OTQyPjQ3OjMyOTM6 +ODUwPTA5OjQvPDI3OzgxOzI6PDUzPDQ7Ojg0PjQ6ODY4Pjs4PjE9OTo0Ozc8Pjk2PTg1PDQ3 +QTkyPjY5Ojc1PTY7Ojs1PTI9Oj4wPTI8PDszPjRBPD0zOzpEOz03PDk9Pjw9PT80QDo1Ojg7 +QDs9RTo9RDtBPjs4QT0/RDo8REE9QjxARzxDSTtMT0VMWkJzlF7w+87z//T5/+/9//v///// +///7//H6//X///j7//b+//nz++z0+ur9//v+//z+//j6/Pny/+jv/Ort+ubx/ez2//Ll+eXe +8NPq9OH5/fHs9evq+eby/Pb+//7z9efx/PH9//Lt/e7t/ury/O/7/vf5//X2/vPl6uD9/fn/ +//7////5//n///7z/+7y9eby/vn1/ert7+zz++319urw9Onl49lKSko9OTowOjU2OzY2ODE8 +PDQzPjc1NzkzPTYxQDc2OTg5PDU2OjU2OjUwOjc1ODMyNzo2OTUzPjU0OjQyOjU3OTEyNjA2 +OjcyPDc4OjUtOjE1ODkwNi83OzswOzA9NzkwPTM0NTUuOTAyPDQ3NzQ2Njk3PTkvNTgvOjQ3 +NjQzODEzODMtODI1OTMvNzI3ODYtNy86NjkwOzE1ODMpOi81OTgvPDE5OjMvOzMtOzM1NDI1 +Njg3NzM2OTIuOTIwODY0NjM7Ozk3OjM6PTcyNjM1Nzc0OTY4OjkqMzI5NjgsODM3NTQtNi48 +ODQrNjM8OTkxODQ1OTQyOjYwNjYyNDIsNzQxNTYwOzI2OTIsPjQ1OzIuNTUvNDA0MzctNjE3 +MzYzOjE1ODUxNiszOTwyMi81NzcuNDQzODgwOTIqOi83NzgsODMxNzQuOzQ3ODMxMjQxOTgw +OjQ0NTQyODgtOjc0ODkrNTEzPDgxOTk1ODk0ODg+PTY1NTY4OTYyOTg1NTMzODMuOi0yODUy +OzM0NDksNDY1NDQzODM3ODYuNTQ2OzQuOTU4OTYvNzQ1OTA1OzQuNi0zPDU0OzAzNDMzNzMz +ODQyOTEuOzQ0NDcvOy8yODYvODE0NTkvOjIvODMvNy44OjstPCs0Nz40Ojc0NjcxOzIyMzU0 +OS82NjQ1PzQuPDM0PDEvOzAtOjA0OzYyOzE5OTYzOzE1ODMtOS8yOjcrOC84NDYtPDIvNTkw +OjI1PTsxOS8yPTgzPDA3ODUtOTg0OC4vNjM0OzQ0ODQvPDU0PzU/TTxbVktcUkhXWkVbVk9V +XEZjXEpXXEdhX05TXUheVkZWVUhRSEU8RjhEQjpCPT81PjY5PTMyOy82Nzs1PTQ3OjszOzg6 +PDo3OzNGSDtYSz9VQzxaS0pmUzh3WkZ3YECNcFCWd0ydbleid0mkgV+uhFizi2K8imC9jGW+ +jWS/kV3BhmHCjl3IimLDkGHFjGG+iVu+hV7DiFmygFazfE+tfVWyfFSldEytcU6nck6udE6h +b0mdbkagblGmcUaeaEeUakiXZUmHXD18UUFqTjteRztORDpEQDtBPjlAOz1ERz1XVkhdYkti +ZEtiZ0pubFB0cFh1cVZsdV1zcFlvcll0b1ptb1x3b1hpbVJ3b1hvcFVvaltvb1ZxalNpbVRn +a1hra1VmaFFqb1Vpa1RpaVJkbFRvbVNraFNUTUcyPTkuPjQ1OTg2ODI1OTQwNy86OTIwPDI1 +OzU0OjM1OjM0PDM9OjUsNzA1OzgvPTA6PjkyQjg4Ojk3Pzg6OTU5QTg1PTUyPTc0QDY3PzI0 +PTYzQTU+PDg1PTM8QDkzQDE7OzsyPzE/QDkxQjU8QD41QTNBQjoxOzhGPj49Rjw8SDs/Sj4/ +Tj9QXkFYcUZ0i1OPn2Gqtna7y5DK2KbM27PG3LW4zrLL47Ly/t/7/+7////////8//j9//v/ +//////39//b///j1//H6/+n///38//zy/Orw+e/q+OD3//D6//f1/u72/+/n8+bl7+DT7cvr ++One6tra6tX///z5//Dv/fDx/O/x8+Th6d739fnx/eLw/u3u++zh9uby9Oz4/vb7//Dt//Ds +9ePx/O/17ubk8eL9/fv////06+ns+O39//r0//P69+7j49RUR0tBPjw0Pjc2PDY6OzczPjc4 +PTYuOzc3OzM1OjI3NzIzOjQzOzMsNi81PDUqOSw4NzQrNi05Ojo0QC0zNjQxOy0zOTczOjIz +ODI3OTMyOTEyNTA7ODQzPDcwOS4zOTQ6OjU0ODY3ODIzNi47NzYsNjM9PDgtNy47OjUnNTM4 +NzQsODQ3NjYwNzE0ODEwNTE1Nyw2NjY1NTQ4PDQwOS49ODEuNjM1NzMvOTcxOjE0NjMyOi0y +OTYzNS48OjYzNS84OTczODA4Ojk4OzA1NzQ4OjA1OTM2NzUsOTIxNTQzNzE2OjMrNy8vNzIv +OTAuMzAvOC4zNjIwMjExOTI1ODQtNjIyOy8vNjExNjIyNjU3PDAwOjYvOTMvODQuOjE3ODkz +OC81NzQtNzA5NzEpOCoxOjEuOzEyODAxOC87NC4tODQwPC4xODE0ODYwODMyNi4tNzM0NzIx +ODQzOTQxNzQ4NDkxNTE3ODYpNzQ2OzUxOjE2OjguODUyMTctPDE5NjUxOS85OzYqOzE2NzUy +ODQ1Nzg1NTQzOTcyODExOi41MTAyODkwNzMzOTYvOjg1OTktOTI1MzUsMyw8OzguOS46OTsv +Oi40OjYyNi80Ozk0PjIxODg1OTYyNzM1NDA2PDQ3ODU1NzQ2OTQyNTU0ODU2OjYxODY2Ojct +OzI5NzMuOi88PDcuOjM6ODowOjE2OTMuNjQ5OS00OTE6OzIyOTcyODEzNjQzOTU2NzM0NjQ0 +NzU0OzEyOTMyPTU2ODU1Nzg0NSw0ODozOSk1Ozc2PDUyPDZGTTtZYE9bWkhaVUtbW05YW0Zd +WElaX0teWE1cW0dcTUVNQj9FSEJIRTc7Ojs9QzY3Pjk7PzIuNjk7Py0vOjo+NzcyOzpDQzRM +SD5aTTBaSD1pTkJ3V0iBYkWLaEuWdEiZb1Gfek6mgFWqg1mqh1i1ily5jWO/jFjCkW7FlF3E +k2/LkGnJkWXJiWbKkVjJkGPEjGLHjV3GiV+9hFrAgVa0g1a8eFmvdEu0dlWud0iqdVCmcUil +Z02ecEeodVGibkihcE6mdE2oc0mZZEN+VURuTUBgRzlPQDg8QDc3QjU5PjE+RDhMUEBVV0de +W01aYERoa1FqbVB1c1ltcFlwcFxxcFV0clh1bk13cVhxbVlvb1JvbVhsbFdybldwcFJwb1Zt +bFdsalJxalJqaFVna1JqbVBtaFVpY01ZS0cwOzQ/OjktOzNBOzgvODE8PjcyOzc2OzY4OjY2 +OjM1OjQ0QDM1PTYyPTQ4PTg3PDM4PDg1Ozg0PjU9Pzo5OzY2Ojg3PDI7PT02Pi47PT03Ozc2 +Qzw7QTU1QDY3OzY3QzQ6Pjg7RjlAQTk+SzlEVD9NYz5rek+JlV6jrni3vY3LzJva4Lbf5sTs +887w99P2/tr6/Nz6/9z9/+P//+P3/+Lx+dvc7c3Z7cP8/+r///z5//T4/+////////n///v/ +///////2//L9//H+//b8//f4//L+//v9//3////9//fw/+r6//Pv+Onx/ezq+ezj99jt8ebd +5NXi6t3l6dri7uDs/vf///L6//r+//v1//D5/e3+/vX6/e/v+ert+ev6//D8/fL0+u7///3/ +//7///z7/+/5//H3//L+//zx8vHy++7z/u35++/s7OBYR0czPTk+ODkzQDE8Ojg0OzUyQTk0 +OjY5OzoyOzY8NzgxPDA7OTcwOi44OTUzOTEsOTc1ODg8Ojg1PDEwNzYtNzQ2PDMyOzUwOTEu +OTE2NjUyOC4+ODcyOzY5NzgyODE6OjguNDM3NzcvOi02NzkzOjIxOTA1NzI0ODU3ODY0NDI5 +ODc4OjQrODQ0NjIzNzI2OjMxOS44NzUqNTE7ODQsOS48ODgwNTA8NzEzNDc6OzYwNzM3NzMz +OTMxOjM0OTUtOTM+ODc2PTc7PTY4ODY3OTY3Ozk2OTQ1NjYyNjI3PDoyNy01Nzk3OzA3Njo0 +ODEzOjs2ODMxNjA1ODIxNjQ1OjQtODA0ODIuNjQ4Nzk1NDY8NjUwODM1NDE1NzQ5Njc5OTg2 +ODQzNzQwOzMyLjAxNjY2OjQzPDczNzM1NDc2Ojg1ODkxOi84NjUuNTE4NTouMzE4OTovNzM0 +ODUuOzg7ODMyOjQ2NjUzMz43ODMtOTI1OzM4OzoxOTA1Ozs3NzQwNTE0ODYwOjczNzUtOS80 +NTgwPTA3OTovNzA3NjgwOjM2NzcyODI5ODUtOTM5NjoxOTQ3OTQxNDMwOjUyNzYvODc0NzQy +ODQzNzI1MzM1NjM1OTYzOy81OjQvODU4OTwvOTA3ODkvNis6OjszOS82NzgyNiw5Ojw0OTMy +PDcxPDkzPzQyOzIwPTQvPDI2OTgzOjU0ODIvODU1NjwxOS84Nzk1PDE3NzswPTA4ODwxPDE4 +PDowOzQ6OTcwNzA7Ozs4Ozg1OzA3Ojc5Pzk0PDQyPTRCUURfWEhaUUdZUkpaV0taVU5VWExf +XEtZVEVVUEdKQztHSEdCQzhCQj83Ojs8RDw4PzYyPDQyOTczOjAzOjA0Py9EQzhJSDhZTEZa +TTlcUUFxVz1/Z0iObUWScE6geFGdelSyglGoiVi1hlauh1y4ilu5kmLCkGPImG/ImWTKl2jG +k2vKmGnLnF/RnXDMomTIjmPLkFvIjGfCjFy+h166ili8hVi6eVSueVezeVGzdVGncU6wakOe +cEyjb06ib0elcU2odUypeU2lcEmMWER2UzxmR0BORDRJQD09PjJAOzsvPzJGRDtERT9UTkZY +U0RhXUplX09gZVJtbVJsb1Vzcltyb1hvbFVra1RsbVRubVZtcFNzaV1ub1VzbVVqb09ya1lo +blNtbFlpak9maVFoaE5ka1doZlNXRz06PjY7PTA6NjU3OzY0OjU7PjE0OjQ7OzUzOjU2OzUy +PzI8PzkwPjA+OzY2PDJCPTcyPjY+PD4wPTY+Qzo4PTs6Qzs5QTo3Qzo4QTo9QDs6Pzo5Qzc4 +Qjc/RzxFVj5NcEZphEmIm1uvuWW7ypHL36TZ6L7h7MPo+NHw/tL0/+D6/976/+D//OL9/+T/ +/+H//+L//+T9/+L//+H6/9z0+9rf9dDQ5brK5Lz3/+b///z///b////6//r///z5//P9//P/ +///////7//z5/u/6//b7//T7//T6//T8//P4/+zx+ezq+eTw+OXl9+Lj+eLh+9nj8tzj9d3l +8uD9//z1//b5/fLr8OTs3Nbj8dzw7uXq8eHi8ODu++38//z7+fPs++jt++r+//Tx+/Dx8+nz +9+n5/fT/+ffy7uTl8+Lr7uvz9+v3+O7r8uLh39hNR0U7Oj86OjY2Pjk4OzU6PTY2Nzs3PDY6 +NzY4Ozc0PjQ1NS8zOzM6OTI1OzY6NjcuNTI7OTUyNDY6NjEsNTY/OTcuMzM9NjMvPjY6NzUy +OTQ5OjU2ODY2NzY1NjYyOzE9NTU2PC82NzI2OS8yNjExOjE3ODE2ODM4ODE7ODg0OzMyNzY0 +Ni8zNjUzNS82NTM7NDEvNjQ1NzMvNjAwODUuOTI4MjctNzM0NzYyMzMwOTUvNTI4OTc0NTA5 +MjUyOi87Njc3OjY3OzM7OTk5NDc1OjI6OjQxOTIwNzU2Oy42ODgyOzE4OTY0ODI5NTYuMzAz +OjMvODE3NzYtNTA3NjYrNjI1NjQyOzI0NzExOjU4OjItODU4MDQzNzY3ODQ0NTQyNjA3NjA1 +NjMzOTMzNjkwODQ2MjgxODE9NDkuODM4ODQtNiw4NzcoNzI4MzUtOTM1ODQyNDQ3OjY1ODEw +NjA0NzM0NTY1NjUzOjMzNTMyNzY4NzQ4PDkwNzE6NTc0OjM1ODgyOC0zODY4Ny42NTouNy0z +ODoyOS8yNjcwOjQqOS85NzQ0OjUxODQxNzE3PTczNzA5ODIvODQyNTY3NzYvNy81ODYrNzA4 +OTYuNi86NjcwOjM4ODgzNzg7ODQxNjcyNzI5NzczOS8yODsxOTA4ODcxOzQ0PTYxOjI5Nzgy +ODUxPTQzPDI1OzU2PDQyOS0yOzUvOjM6OTg5Ojc+Ozk4OzEyOTg3ODcwOjA9OTYsNjE3NTY0 +OC03OzozOSs4OzQxNzAyODQ1Pjc1Ojc2OjY2OjhGUUFbUUlgV0ZaV0tcVUtRVExaUUJZWEdT +TUVIRkE/STlJPjs6PDQ8Pjk3QDA8NTw2PDE6PTcvOjE1NDMzPDA4RUBJTTFZUUFWRztlU0Zv +X0SFaEGRc02cbk6aZ06lfVethViziGC4i1nAhWO/h2DJmmzGl2vNl2zKoHPTpnPOrGvUmnLJ +n2nZoXLLnWvUnmrMmWfNjWfNk2bNlmjMk2LKiF/Gi1zAgFa8flm2fE+yfVKyfFGteU2vdU+h +bUmobVGjdEmpdVSncEWqd1OhbEOJWERxRztWRjZYSzlLRDU8Ojg2Pjg2OTU7OzdIQz9FRT9X +UEdYUERaXkZkY05mbU9xbVhtcVd7cltubVh3bFVvbFR3cFRqbVJxb1hra1VralRya1VubVZx +a1dsbFVvZ1RqalFsaVNpZ05VR0Q8Ojc2PjI4PTw5PjQ6PDY4Oy82Pjc5PDM1Ojo7PjQ3Pjg3 +PTIyOzE3PTUyPTM7Pzk3QDRBQTs4PTc6Pzk8STZIUz9TaEJthUqFmmGktna4xJPO1Kzb4L7e +5cbk78nv9NL3+NX0+9319tf2/9n9/97+/+H8/9v8/+D4/938/9/2/9r5/9zv/dbz/9Hm/MXb +6bXX7a3K5ay/3KS0zoyauYKLpXR2j2iOtWz4/9////////////v///z///r///f5//f1//D+ +//P9///+/+/9//b5//T0//P9//ny+e3r8uDr9uH1/+nz+ejp9uLl+eTb7tHj793j6d7Y39Pl +8tjf7d7l8Nzq+N/z/vn///7////////0/fH4//Tz/+7z/u7l8uXz++j3/vj6//Tv//P3/ez+ +//X+//X6//j///vy9O72/fL9//b+//v/8OlMSUc/PTk6OTM9ODgwODA8Nzk2NzU2Ozo3OjY5 +NTQ/OjY0NDg+OTQ3PDQxOTU3NTQvOjU6NjQ1Njk0OS8yOzU5NTYyOTQzODcxPTQ7ODgvNi07 +OTk3OzA9OjwyOC86NjY0NzQ0NTYxMzY5OjYtNzI5OjY1OjY1ODMzMzM2ODszMzI2NjMzOzI1 +NjY1PDA5MzcxOjU3ODczOTM8Njk0NzM+NTgvNjE7OTgyODE7OTgzMzE1OTQzOjI2ODc2NDk1 +OTM0PDQ6Ozg8Pjc5OTQ3OTM6ODU0OzI7NjgtNjQ8NTsuNjE4NjQsNzA+ODQqOjEyNzQtODE6 +OjUyNjIzNjU4OjYtODUzNjE2OTA2NzQxPDQ6OjQwOjU0NzE2ODQ1NzI2Mjc1ODQ6NDczNy48 +PDsuOC0xOjYuNis1Nzs3NDIzNTU4NjoxOjA7OjY0Nzg6NDkvNzI1NDUzOzExNzMxOTUyNjU3 +NzguNzMzNTcwNzM5NzsyNTg5OTkuNTk4NzI2OTU3NzEtPDUwOzUyNzctNjM3NTgvODQzNjg1 +OTIyODMwNzE4NDIzNjM1OjIzNzgyNTQ2NzkyOTIyLzQ4ODk0NTwyNDAwODc4NjMxNzQ4PDcv +OjM6NzgwNTU4NzU1OTI2NjgyPDA1OTgwODU4NzU1OjY1NDoxOTMyNzM1Ojo+OzwzOzAzNjk6 +OT0wOjQzODY0NTQvOjM4OjYvODM2OTo2ODc4NzYzOTM3NDUzPDQ8NjkuODA1OTo0Oyg5Ozoy +Oi83Ojk4OSw3Ojk4OTc2PC00OC8yPDw2OTRNUj9XV0ldW0tZWkxaVEdVTUNXUUpMTEVOR0I/ +QDlDRD83PTtERTs8PTQ4OjQyPDs7OzgyPDEuOzQ2ODo7PTdHQ0JdSzhWS0JnTz10V0aGakCS +a1CdcFmigFSkd1ekhV26gWW4i1/JmG/ImWPHlmnQnmnVpXTSonLSq3XWrXnVp3HcmW3SnGzS +mm/OmGHRmWvMnmjUnW3Wk2fLkmTMjmTDjWDEhF3ChWDGgFm7fFW6dFOueFO2gVGve1Kvek6q +ckqmc0umcUurd0yvdleodVCeYEd+UUB8UUVdTTxZRj1BPjQ5ODQzOjY7PDU/PDs/Pj1JRT5S +TkVZVEhoYUphYk9ra1Nxa1dzcVxxb1hualpvbVN1bl1vcFRwbFdmbVFvblhsbFVqaVJraVhr +aVhpbVltbVRqbVRrZlJUR0Q1PzY8PDUzOzQ5OTQ1OTUzPzE2QTIwOjI6Pjg1PjU9Pjo0QzhC +RDs4SDhHTEJAWztrek6HlVqhqHe5wZbI0KfV4b/f58Lj7s7s99b1+dny+tv3/tv5/dv1/tz3 +/9v4/tz3/9z1/9r5/9fr/tDp+NLn9sfh8MPX8LjP66zG4qXB2pyryoqnwIKUs3uDoGR8kmVw +hF5uc1pXYlBXW0xVU0xQUElHTUxum07x/eD4/+r8//D///r///////////////v///r////2 +//T8/uz2//D9//3///34//Ty/er9//j///z9//n1/+zq9uXf79vh/tnl7ebd69Pa39b3//z7 +//jz//f+/e3y7+vw9un0/O35/Ov0/vj0/fbt8+X1/fP///7////v++jt/vH3//H6+/bx+Ojx ++Ory+u/v7uTl6+Ly/unt/ezv8d/c4tJMQ0A6QDc7Njk0PjY6OTQ5OjM2PTkvOTg/ODUzOTM7 +NjQrPC02PTo2Oys7ODg0ODIyOzgxNi04PDYxNjUvNzU2OTU1NjQzNy8zNjg4NTc0NDQzNTY1 +NTUvOzQyODQxNjA4NTkpOy83NzEuOTQ6NDYtNTU8OjczNTQ5ODM1NDIwOjQzNzQxOzM1NTQw +NzAzODIsOjA0ODQsNTI2NjE0OTQuOjAyNjY0NzAxODIwOC43NjY0NzM0NzkyNzI2ODc0NjA1 +NzM2OTY1ODQ6OTUxODA3NzMzOzE0OzQrNyw1NzUuNDQ0NDUuNzMwODIuOTI1NDU2NC4yNTIz +OTItOjY1ODQoNjI1NS42OTYyOTI0NjIyOiw1NzQwNDA3NTgvNjIxODQwOTE6ODUrNTI3OTQv +NTg2NTguOC41OTIyMzMvOiwwPjgzNzE2OjguOjUuODQzNTkzNTE2NDcxNjE1NzgrNTI4Mzcq +OTQxOTArOC02PTotNzQ0NzMyOTI1OzcxNzQ1NjQyODArOTc1NjQyNDI1ODExODcxNjAvODAy +ODAzNzgtOzAtOTQwOTAyOjcrODE0OTcxOS0zNjUsNjEtODIvODQzNzgxOTcvOS0vOjIzNjU0 +OTU1PDQyOjYzPTYtOjE0PDE0OjM2OzUqNzA2OjYxODQ7OzQsOC5BQTwtPTU5QjgyNzk2OTcs +ODUxODc2ODcxOjE1ODouNzQvNToxOTI3NzgwOjEuNTQwPDQwNzM3OzgzOzE0NjozODQ3Ozkv +OSwyNjkvNCs0Nzc2NjcwPDU5Njc4QzdEUEFRUkNRTENVUUdVUEpMSEFOSktDRDo8Pz45PDY0 +OTc+QTc3OTk9ODc2OzY9PjYyPDA1PDQvOzo/PjBGRjdaTTheSD9kUD50V0eBYUGXclObclOm +fVesgFa0hluxi2G2imvBmWnJoXDHpWzOpm7NrHXYrX7Tq2/bq3varHvWrnTYn3PSpmrUpWfT +nWjNpnDboWrUl2rSlGfOn2XQmGrKk2PNkGvHh17GhV+/hlzDflezfFO/gFOvek21eFO0bUqq +c0qlbk2nd0urgFSsd06ibk2dZUSDWD5wTT5kSj5WRjg9QDU9PjgwOzJBOTw3QDBEPjxERzVI +UURgYEVgY01pbExublR3b1Z0cFZybVZucVdta1ZtblRrbFd0aVdxaVVyalZna09vbE9nZlVu +bFFlaE5rZVRmZlNRQkI0Pjc7PjM0PDc0Ozc3QDQ+SjhOSkJhWk18bVuZh3KnoY67tqHNxq3b +1rzi38a+2rHt7M329tn1+9n6/d75/Nr5/+H6/9z3/976/9n1/9nv/dTs/tHl+srf98TZ9LrM +6K/I6KC02pGs1IWXx3eJtWl6pmBwj1ZgflJedE5VZ0tRWkdKVENLUUZISkI8Qj9DQz0+RUE+ +QUBEO0M8QD1BQEA8QD1ERkFtnUr8/+/////////////////9//r6/+v+//v///n///j///j/ +//f+//X7//vt8+nz9+b5//jl/eHo+OHw/+Tx+uzj8N/h8+HZ7NTh7dvh9ODm8Nry//r0/e7x +/ufy//P29/Ds/Ob5/u7x/+Lz/urs/+v+//37/+3z/+rl/+Hp/+v3/O/x/vP7//H6//b///7/ +//z+//3//f/q6+bm6t7r8uXi59lLREBEPTozPzc6QDY2OjI3OzgyODY7Ojs2Ny88Ojo2OCs5 +PDotNzA5OTM6PS47OTQxPTI5PjI7OzMsOy4yOjQ7NTUwOjc2Ny8uOjQ2ODQrNS80OzQzOjE6 +OTgtNjE4Nzg1Ny42OzQuNC46NjYvOS44Nzg5Ny83NjYyNzQzOSo4OjMvODQ0OjQyOS82OTQz +OTEzNy80OTUwNzAyOTQsOS46NzEvNjI3OzIqOC88NTcsNjM4OzMuOTY3OTUuOjE0PjQ5ODY6 +Pjc4PDc1ODAzOTUyOjQ7OzI3PDczPjQ1PDMxOjE4OjkxOjQ1PTgvOzA3Ozc3NzE0OzgzODIy +OzkwOzIyPy82PDAvPDA1ODUtOTI4PDMsPC01OjQtOi82PTIyOS8yMDEzOzM0OSsvPS0zODQ0 +NDU0NzMwOTQtODc0OTMxOzg0PjA0NTIxPDI2OjYzMjA2NzgzOzU4OjcvOy85NTUtOS4vNjQx +NTE5NjUuOjA2ODUwOjY2OzQ0OjQzNS0zODQ3PC8vOTcxOTYzNTA1OjkwPi02ODgvOS00OTcv +Oyw0OTUrOTEyNzctPC00NzEuOS80PTgrOy0yODMuOjQyPDEzOjEzOjU4ODoxOTQzOzY2OTM0 +PTExPDQvPDQ1OjozOC41NjgxOTE1NzIuNzE4PDcsOi00ODwuOyo3PjwzOjA1PEAzQTYvOTcz +ODI3NzM1OzQyPDMyNDE1OTM4Ozo4OzcuPDIyPjQuPDE3OjUuQDA3OjUuPC84NzovNy80OzYt +PTI2ODcsOjQ4PDAzOTYvPDQ1OzhBUz9VT0VRVEZRTkZMTz5OR0ZERjY7Qjc8SDYwOjA4PTow +PzQ6PTsyOyo3PDsyPDQ8Sjs6QDFDST1PRzlZTThgRjdkUD9vTEuDZkeSc1Cje1CmgVyzhlqv +ily3jWO+lmrLoGjJpW3UqXXKonLVrnzUrYHZq3PPpnLTpnPXuHrgsXXdqXDVsnbcq27Xo23c +o3LRpGvTnm3Sn2PYoGjUn2TVnWrPmGTOiWTJkGXMj2PCgF++fli7gFW9gFe6h1ivbkaueE+m +dUmoeVKyelayeFWydlSmdlWabUp7W0FlSj9aSDdHPj01PTI1OjM3PjA3PDg3PjU+RDlASjpP +TkRdXURbZ09nbFRzc1dzclZ0cFVwcFV4bVhqb1R0clpvcVdvblhqbU9za1Rob1Rqbllobldy +aVpublZwa1hiWUxsZViGeGugkIGvqZjEv6TQzbja3cPn48vp7c/q8tTx9dXu+tf3+9jy/dv1 +/NvM77X4/djx/dX4/9Tr/c3v+cre+cPe8rnM77DN6qK62ZKjz32Ww2+BsWJ3pl5ollVegU1Y +bkhIYkJLXEBGUkBBTEI5SDRCRT87QTQ8QDs5PjE8Qz88RDI3Qjk/Pzk6Qjw/Pzk6QTpBQjw/ +Qjk+Rz47RDs+QT1ARz+FpU/3/+7+//L///n7//T4//P9//b////////5/O/3/vL8//j4/+n/ +///6//b8//T////4/vD6//b2/PHn7OHm9tr8//vq+erb7tDf79rc49jb6tfu/u30/+/49PDd +7+Lt/enc2s/++Pv1/Ovz9/D29u/x//Lw+ejt+vH+/fv+/vH4/+7t/OL9//n///X1/+z9//Xs +/eP2//j5/fX9//7y/+/t7N1JSD5FQENBQTg7QDw2ODI7Pjo9PDo2PDg7OjQ7OzQ5Nzc7NzQx +Ojc1ODY6PDY9OzQ4OzU+OjoyPDQ9NzQ3OjREOTg5OTM7OzgnPjU8OzIzODQ5ODIzNzU5OzU5 +OjcyOzA4PDkzNC82OjMzOTA5NDQ1OzY3OzY3OjUwNy83OTozODQ5ODMzOy4zPDE2OC4zOzk5 +OzEzOTg4NzU6OzU3NTE1OS42NjU1NTI3NzU0ODQ2Ozc1OjAyODQzODY1NzcxOjMzOTM9PTk5 +OzM8PTowNDU2NzI1NTU0ODYwOzYyOTE7NDk1OjI1NjYzODI6ODg2PjU4NTYuOjM5ODUvOTM+ +PTgtOTQ7ODQyOjE7OjQzPTU6OzA6OTc2NjM4Ozc6ODM0OTU5NzI0OTM3OzQ0OTE1MzU0OTQz +NzopPS81NzcsOzQ4OjoyODU+PDktOzc6OTktOjY6OjgwOTM3PDU3OTYxNjg2NzUyOjY5Ojg3 +Nzg0OzcwOTc0PjQ0ODUyOjI0NzkuOTQ1Njk1OjM8NzsxNzE3PDo1OC03NTo5OjA5NzwyODQ0 +OjI1NDc1OjU6NTc5OTc4NDc2ODc1OzM2ODU1Nzk5ODw1OjI2OjcrPDE7PDgvOzA2OzYyOjY8 +Ozk2NzU5OzcyOzc0ODg5NzguOTg1NzozOjk1OTc1OzM1Ozg1PDY4Ojk1ODcyPjU0NjgyOjE1 +OzU2OTU5Oj03OTI5Ozw2OTg4Pjk2OzQ3PTY3OjE1PDc5OzczOi80PjE1PDE2OTc0PzE2OTk0 +PDMzOTU2ODMzOjk5Ozk8PjhFUkVSUkZYUUNSUEVQUUNJRD5HPD06PDo7QDM6QTwwPjM5OzU1 +QjU5OTwyOzA6OzgvOy0/Pz1SRztfR0BXSj1iTUtpUECCZUyMaEiieFenhlizgluuiVu2iVnC +kXHMoWrMo2/PonrKoGLTpWrXtXrbrnzWo23UpXTXrHDjs3zbs3rgpXncq3PaqnrZrnPbqnbX +qm7ToWzYoHHanGzTnGjTlGvOl2jSl2fMjGnJjGPDg2DFiFS7glW9hVe3flG4e1iyd0ynb0yt +eE2yeFeyeFS2eVmueVWZb06SW0hvUkBcRTlFPTg4Ozc2OzI3Pzc2PDY4OjU7PTs7RDhSS0BP +VkViYk5mbUx5bldvb1l6cl90cFZ4cV5yb1l2bldob1hwb1Fwaldsb1Rvbllvb1RzbVZvbFFy +bVNxfVuot4jP1rXi6srp7tPt8tDw+NXz+Nnw+9rz/dvz/tvz/9Pw+tbv/83m+svm+Mnb+MS8 +46DI6avI56ez15Ks0YmWwHaPr2t8o2Byklthfk9cbU1NZEhLVkJHTEVJTUBGRj4+Qj1CQzg3 +QT5CQDpBRUE7RjxARDs8QDtARD08Pjg8QT08RzVEQj4yQDg9Qj4+QTxDQz83RDxCPD43Pzk/ +QDw6RTpASDxBSESFnkvx/eb+//T///r///r////////9//v9//f////////6//v6/er///n6 +//Py++7y8+n7//D///34//f9//L6//fl8+bq+eba8Mzo9eDe7dXj8Nrs++nu9Ofp+Ovy+fbz +9fb+/vzz/en7//vu9eXm+e3z++/0/ezw/+37//T0//b78vn9/u30//Lt/fDx++Xh9uHt8+nk +7+P+//j///L5//Lb1slJR0NGPj1APzg1Pi87OzY6Ojg/OjY8OTc6PTY1OC49NjgvOi06Ojg0 +Ny49Ojo7OzBANTk3Oiw9PTg8PTE6ODw9PTA+ODE5Njg6OjM6ODQ0NDUzOjc6ODc6PDY3OzE8 +OTU8NjIyPDE3NjMtMy87PDUpODE+PDc2NTJBPDk1OjY+ODoxNDM4PTEzODE2OTY0ODcwNzM5 +NjQ0NTQ1NzQxOjE1NzMtOjEtNy81ODMzOTI0OjYxNy41NTk2ODE0Ojg0OzE0Ojs6OzI4OzU8 +OzQ1NzM3OzYzOzM4OzUpOi00OjIyOjA7OTkzODgzNzI2OTI3NzE4OTU2ODMwOjE0PTU1OTY4 +NTM6OjUxOzU1OTYzNzc5OTM7ODUxOzM4NTQ1PDA2ODgzOTE4ODYvODE5OjYxOTE4ODIzODIw +NjMyODk7NTM0NTYtPDIyNjgzOzIzOTUzOTIwOjE2Nzc2PDM1MzozOTI6ODkzOzE2OzgtOzE3 +NTsqPDA4OTktQDU2NzUxOS05NjcpOjA2PTcwNjQ2ODYzNzIzODcvOTcyODMvNzg0OjM0OjMx +OTcuOzM2ODQuOi01NjkvNjA5OTo0OC84NzkvNzA1Nzk0Ny42NzozODMzOTQzOTQxOTE1ODI2 +ODY0PTYxOTc0OjQ0ODAyOjU1OzgtODU3PTQvPDQ2PTcsPTM4OjYpOTU8OzowOjE3OjgtOjM3 +OjcyOjUwOzQ1Ozc0QDM3PDgtPjQ2PDgyQTM0ODUxOTMxOjQ4OzkxOzE1PTkzPDA1PDU1NTI2 +ODg2NzAyPDswPTA1PDRISzxUVEZTUUNGR0BEREJBRjg8Ozs4QjQ2OjQ5ODU2Qzs4PTMzPkA6 +PC8wOTU6QDY1RD1UUUFYSTxjSz1ZS0BhSzhvUEKKZ0uVdEulf1StglmuhFSvimO+kF3FjmXD +oW7Tqm/Mpm/NoW7OqG3ZsH3YrnTYsHnZrnTYqHPcqHTdtILiqXverXXeqW/YqHTaq3bYqnbZ +qXHZonTUpWraomvUl2bSmmrOlWXNkGXHi1jIiWHDiVnMi1+6hFK4elSweFO0e1m1bk6meUyy +dFCweFGxdViyfFWjb0yPZEV2SEBYSDtPSDxDOjc1ODQ/OTkxPTQ6PzwyPzI/PT85SDdSTkZS +V0Bfa01rbVBscVJxbVZ0dVx0cldsb1RycFpxblVvbFVvbVZvblJxbllva1RybFVua1F3blV1 +k1rE3aDg88v0+NHq+dHw/NLq+tHn+Mzl+szi98PX8bvL6rLC46e13JKp04SZwnuIs29xn15w +kldmg1JZcktWaUlMXkBLV0xLTkFHR0g+RTk/S0JAQjs9RDhDQTo7Qjo9PzY4QDc/Qzs5Qj07 +PTw3Pzc8QD84RDg8Oz08PT07PT07PT08QjdBRkM8PUA+Pj8/OTtAQT07PTs/Qj8/ST87QDw8 +Q0A7RzhDR0KBnU70/eH///////////7///b6//b+//n+//f9//zw/+r5//D9//H///////// +//z7//j///z7//T////x/+/v+unj9OLZ69jV7cLl9uTe8drj8N/x9Obh6Nrk9d/6/vP8//f7 +//Xv9Ovu9+L9/fXx/vb7//b69+/n7d7k+eb9//31//Lu/+77+/Dv+ent+e33/vX///Pk5Nzk ++eXk5tng6eDo49VRQEpNQz1FQD82PjM2NDQ9Nzg7QDc7Ojk6NjU5Ozc7ODM5OTI5Ni87ODg7 +OzI6NzZIOzo2ODVCOTc0OjFAOzQ5ODNEOjc1ODQ6OTI1OTU4Oi8xODc2NTU5Pjs3OjM7NjY0 +NTU5ODI0OjI8NTMwNzI4NzQ3ODU5NDU6NTY5OTM2ODM/ODU6ODY2Ni83OTY3NzAwOjU0NjMy +ODM2NTQyNDU2MzY1NTE6NDowNzA4NTEwNTMxNjUzMDE2Njk7NTEyOjU1MzM3ODg2PDA4NDIz +ODc3NjQ4Ojc0OTM2NjQ2NjMtNzM4Njg1Ojc2NzUsNy88ODYyNjA6PDQtOjE8ODUuPDE5ODMy +OTQ5NjMzOjQ1OjU1OTQ1NTMwNzQ3ODA3OTY2OzIzNi03ODY0ODM5MjQuPC05NTY0PDI1NTUs +NzU5NTUsOjM8NTkvNjY7NjcyNjI4NzQsNjM2ODY5ODQuMjM6Njc1ODY3NTYyNjQ0OTEuNzYy +OzU1Ozo2Oi40MjkyNTA0NDg0Myw6Nz0yMS00ODoxNywzNDkvODMyNjgzODU0Nzc3ODY0NzU3 +MTUyNDY3OjM3Nzg0Ni42ODMsNzY1OjUxNTU6NzYwODU4ODguOC80NzYuODA5OzQzNjE6OjIv +ODYzNDg4PDozPDUyNjc0PDQzNjU0OTIzNTw2OjE1ODY3OTUzNTUzOzo0NDM6NzwzOTM5Njkv +OC40Nzg1ODE4Mjc6ODcwMjY6NzgxOTk1Nzc4PDc3MzQyNjg7OzgzNzA1NDsyNjI0NTk1OTE1 +OTc3NjQxOTg8Ozg8SjtMSD5FR0BIPDs7OTk/Pzk6PTs2PDk2PDU6PDU3PTg0ODE4PTgvOS80 +OjYzOjRLPj5VSTViTEVgSTdfSEZkSTl7W0iHYkebdFileVysflCvjV+5imDBkGrGmG/MpnPU +o3HPoXDVqHjWqnXXqH3ar33bqHzbrnTgqXzdsXXouoHisIjfrnvcsHXgr3resnzbqHHkp3jh +pnjcpnDbrXPZnm3TlGTUkmbOi2PKiV7Kh13Bh1XDjGDEhV3Cdlq8f1C2fFe1e02yfVqze0+w +elaue1SweFapc0+YZEyFUkFZSDtPRj1GPDY7Ozk3PDI0OjU8Ozc0OTU+ODY5PzlIQTtKSD9Z +VklgYkxvbFJqaVNwb1dsa1Zua1NtbFVva1VzaFZvaFdsbFVtbVZoaVRraVJralRtalJ4ilin +z4XG5afG5KrD4anA4ai12pWw0o2dwX2PtnB/p2J0mGJsjFZddlNWaU1NXEhNVEpFTEFFTEQ6 +Rj1AQj9AQDtAQ0FBRD1BRD5CQDs4Pjg/QDo2PDk4PDY9PDk/QDo7QDg8PTY4Ojg1OjY5Pjk4 +PTZAOkE2QDI4PDotPzU/OTo2PDg8PTk1Pzc/PTk3OzlBOTo0Pjg+Ozs7Ojg8Pjc9QDk7Pzk5 +QDtEQTt7mlD5/uf////////4//L9//L+//b////9//3z++r9//r8//n+//D///7///r///39 +//r9//ju+Orq7eLi6tjh59jn793d6Nzd+NLk7+Hm8Nrm7uTx//T1//v3//fx+uvj7tzm9Obz +/uvt++jw/ezx8+zy+un9//zz/ejz+fLx+Ojl8uPw8fLx9unx/Pbx/vL9//n7/+338/H///33 +/fP//+/k3dRPOkRDQzpOOjczODhCOjk0PDJEOzQxNzQ/NzU9ODY+NzgyNTMuOjE5OTQ/OTE/ +PjY6PzJBODU4Ozg/NDY3Ozg/OzQ/OTI+MzQ1OzY4NzQzOjE3NTUzNzM7NzYxNDM9NS83ODU3 +ODM3NzM3NzUuNzE8PDY1Pi8+OjM3OTE+PTk+PDU3OTYyODA4ODU3Ny4zNjEyODQ3OjI0ODM3 +Mzc/NDAoNy8yNTM2OTczNjE0NzIzOTQ6NjUwNzI8ODcwNDE4OTQyNzA5ODYzNTE+OjQxOS48 +Njc1OTM7OzM0ODQ5NjM9Oj0xOi4zOzQ0NzI1OjI2OTU4NTY1ODMzNDI8NDQ1PDQ2NzQvPC03 +NzYxODU8NDg1ODM/OjgvOzM5OjUyOjc8Ozk1OTE1Njk2NTU4OTIvMzM4NDQ1ODUyNTM3OjU1 +NjYwNjM1ODE0OS85NTowNjI3NTguOTE2OTctNjA0NjU1Niw6Mj41NTE1NTQyNjUzNjcyOTQ0 +OzI2OTMzNDY3OTAuMjM1NTM1NzMzMTUzNTYuOC81NjYwNzE1NTcwNy40NDMvOzI2MjMyNTM1 +Ny0uMzQ1NzI1ODgwNy44NTk0ODY0OTQzOjU1ODYuODE6NTgvNzQyPDIzNjQ1NzE1OzozNiow +OTM2OjE1OTQyOTA0NTU0Oi4zNy02ODcwPTQ5Nzc0NzQ5NTgxOjA1LzUvNjY2NTIyOTQzNjQ0 +ODA2Njg0PC8xNjc1OTAzOzY0OjczOTA6ODEsOjcwNywuOzgyOSgxODErOC4zNTctOSs2NzU1 +OS04PjYzOy1DREBFST9EQEI1Py46OTsyPCo6PDg1ODg6PDgzPDg1OyowOzU1PTQzOjQzPDhA +SDVZRkRZTDlkSD1fSjRjTUVqUkKEXkiDY0WehFylfVq2gFq2kV3Gj2PFlmjKoHDMqWfNqnbU +qnjUrnTbuHzasXnZqXndsnndvHvjr4Ddu4TlvoXktIDhtYfjsojjrIHdr3bjs4bhrHLdrHnd +rHjeo3jcom/XoWzXm2vSkmTQjmLLiF/Jg2HBgFbBhla9gVTBgF+8gFOwflO5glS1gFa5e1iy +flK8f1ineFKrdE6FXUVoSUFIPjlEQTQ8Ojc2QjE6OzY1PDU6NzU0PDA/Ozo5RzdKRj5PTj9d +W0VgYE5haU5vb1FxalNqa1V1b1RrbFVraVNsaVVpaU1salVuaVFnbExwcFNsbVVsbVVqeVFj +eVFgfUxkc1BSakhYYkpNVkVPTklDTEJJRkNGRj9DQUQ7QTs+QDhAQjs8Pjk/QDg5RTg/Pjg+ +QT4zPTdDRT1BSjxGRkE5QDg7PDk7Pzg7PTc0PjQ+OkA1Pzk9PTszPTg4PTgzPjg7PDc2Qjg2 +OTJATTk3PTs4QDQ1PDY2NjM1Pzk4OTY7PTg3Ozc8PTc1QDQ7Qjo2PTU+PDk2Pjc+QTs3PzhH +Rj97nkz2+uL8//H///r///v///////////j///7+//z5//P///z///j///v3/vH2/e7+/Pzr +9+nq+trw+uz5//L2//by++3f8+Xl9tXv++vp8+Te6Nb3/+/t//Ts++ro9ef+/vv1/evq+N7s ++eTo9ebr+evr8d/d7Nvz/vr////////7/fH2/vX3//H49O3+/v35/+3y++/9/v30++r0/+v0 +9+vr5NpIQkJLQzhAQjo/QTQ0PTBBPTo6PTU9OjkvPCs9OzcuNy49NzkrNzI8OTk2PDJHOTY9 +PjU8PjI9QjVAPC47OzM9PDE/OzM0OzIzOTc6ODAxOi82OjguNjI4PDEyOTE5PTcvOTM2PS8t +Nyw6OTErODE7PDM3OzRAPDc6OzU/OS0/OzI1PC84ODY0Oy42NzUtNy43OTMwOTIwODAzPDQw +PTA1OzorNy01NTgwNzIuOjU0OS4vNzg1OSwtOTU9PDM0PC41NjA0OTU5OC4uOC82ODYtOjA3 +Nzc1PC4wNTE1OzQzODQwOjMyNTMxODI0OTU0NzM0ODMzOS8zODY4NjIzOzQwOTI3OTUtNjQx +ODYtOC05NzcwOjM8OzUwOjQwPDMxOS40NTQ1PDM4ODIsOy83OjUvPTMxOTItPDUxOjAvOjc1 +Oy4wOzA0ODEuPjUzPjcwPTEzNzEsOS0yNzUrOTIxNTYqNzE1NjUqNjIyNzguNzM1PTQsPjA3 +PDgpOTA1QDUxOS4qNTUyOzUuNDMyODEtPDUwNi8tOzMtNjUzNzMvOjEzNTkuNi8xOjMtOSg2 +NjUwOC4yOzsuOisyOzgtOS8wOzotODEvNSs2OzEzOjE2NDEzOTAxOTY2ODUuOjMvOjAyPTEz +PjYuPC4yOjgqOjM4OzgsOjA3OzYnPjA2OzM0OjU5ODY0ODgzOzM1OTgzOTIyODYuPTAvNzAu +OjAwNzQvPCwzPTYxOS0uODU3OzYxODMtPDMsOSk1QDkrOi8yODIvOS83ODczMzc0Ojg2NTMq +PDU3Pzs3RDtFREBAPDc6Ozs0PDA2Ojs2PzAyOz05QDMzODc6PTUwPjQ1OjEqPThARzhNUzxk +VUFXTT1jUTtcSEJkTzx2VkiFZkiccFCie1G0f12zjFq+jma7kmLPpnHHp2nOp3XUsHLUqnrT +sHjcs4DhvHvcsoXcs3/lvonkuoDqvoPouYjluYjjvojrwJPou4vls4nhsnbks3zevXzgu4Tg +sHbdqHLVqG3cp3XSnWrPlW3JjmTFh1y6hVnDiVe+f1e6f1y8fVW3gla5hFe4g1e8gVu7f1az +f1iudlaZbEuCWUJjTzxVR0E7PzNDPj0xOS02Pjk1PSw2PDgyOi46QDc8PzpASDpMTEFHTUBY +VUZbXUhmZk5palJrb1Zsa1ZnblVsa1Nrb1Ftaldqa1NobVNmalNvalJoalJoY09BSj5CRj4+ +Qzk8Qjw4Pzw8Pjk6PDs7PTY8Pzg2PTc6Ozs2PTk6PzY1PzY6QTc1Qjg2QjI1QT84Ozk1RDk0 +QDE3RztFRDpAREE7PTUyPzQ7PTY3QzQ4QTo3PTo6PDgzQjNAQDk1PTM6Pjg3RDg0NjkxPzgw +QDQ5Pjk2OTg1Pzc3OjY4PzgzPjQ2QTsxPDg6QDQ1QDY3QjU2PTY2PTQ4PzcvQjY5Qjk1RjqE +n1Hx/+P+//b///////7///r9//f6//L///b//////////////+/9//f///v6//jr+ub6//D/ +///3//X3//X0/ezn9uTh+OHl/9jh8N/d5tXU5Mns9uj1+/Ht8uju/PHz++b2/vb///n9//3/ +///7///3//f6//39//X1/+3q/un9//7/+/P+/vv///f1/+rx++bz/O3s8OHi8d79/vnt6OHg +28xNQUNKRT1FPzw9QDg/PDc4Qzo8ODY/PDM+OTY2OS89OTYuOzE4Ojg1OTBDPzdBPzNJODc9 +QC5INzk9PDI+PDU6NzNHOTs5OTE7PTc0OTQ+ODU5ODMyNjM6OTc7ODQ2OjA8OjQ9NjY8OzEz +NzI2Nzc0OjA8OTI6OTE/ODY6OTVCODc8OjE/NzY1Ny88OTg1OSs6Mzc1NjQ0OTUyNTA1ODE1 +NjY0OjM4NTA0OTM0ODE3NzE1OTAwPDQuNzI+OjMxNy1DOTk0ODVBPDUtODA8NzUuPS89OjY2 +ODQ4PDM1NjIyOTE0NzE5OS84OzIxODU5NzA3OTI8NzQ4Mzg6OjA3OjU3Ny46Ojk0Ny04NDoz +NCw5Ojk0Ni8xODYyOy4vOTE5MjQvPDI2OjM2OTQ1PjEvODA6OTM0ODQ5MjYzODEzODMwNzQx +NTI3PDEvOjg3ODUwOjEzOzQ4NjU2OzMxODQ1ODQ2PjczNjQ5OTUyNzQ3NzgwPTI2OTY0OjA1 +PDM0OTI1NDAwNTc2OjUyNjI1ODQuODM2ODQzODUzOTUzODU1NzE1ODQ0OTQvOjEzODItNzEy +NjUvNC80OjEuPTQ4OjcuNy84NzcvPS44OTUzOzE2ODEsODQxOzQvOzA1OzcwODEyOjY2NzA0 +ODM2ODM0PDQzPSs0OjMrOyw1PDMwQS8+NT0yODA3OzouOjM2ODwzNTA4NjYvOic2ODstOys5 +NzY2ODI2OTk4OjY1OjU1NzQzPDYuNjEzPTo0NzM3NzMyOTU0PS8wNyw2OjUsNzQ2NzMsOjA5 +OTgzQTVIQ0A2PTg3PDsyPDQ4OTQ7PTMtPDY1Pjo3OjozOzQ4OjY3Pzg1PDdASzhiVEJjTDxn +T0JnTTxnST9rVj1/Xk2OcUOcdFiifVOtglSyh2G/lGzCmmjNoW/PpnLTq3vZsHrZtXraqnnY +rXroupHrwY/ox5Xqw5Hr0Zn0y5/r0aDzwpfowpTtwonkvJDqwIrhvIfovX3owIzotofjsHzc +qXvaqnjUqm/ao3jMnWTTkmfFimDJkGS/hFrFglm7gFm/fle1gFW/g1m8glq8ili7h1m1f1er +fFGla0mJX0VwUz9fS0FKPzw+PTY8OzU1PC1APjcwPDA0Ojc0RTRCPjlCRTtIQD9ARTdOSEBV +U0ZhYk1jZEtpbVJtaVVtalRta1NtalZrb1Rva1Jqa1JsaVVmbFJqaVFkWk9DPz45PTc+PDoz +PTM+OzgzPDI/PDk6OzQ8Pjw2OjQ6QTo0OzQ2NzQ4PDY8QDU7PzQ4PTQ1PzQ4QDU0Pjc9Qzs9 +PjlARDtBQzo8Pjk3PTU/PDoyPzM8PT01Pzg9PTo0PTY9Pzk0OzdAPzk1QDY2PjY4ODY3PzM2 +OjU2PTY8OzY3QjZHRjw1QDQ5OjM0Qjw3PDU7Pjs4PTQ9Qj44OjA6Ozw0QDRBQj49STySpUz+ +//////3///j///////n+//j+//7///////n///76//j3/uj5/+/3//Dw/+j+//f6//jn9+L0 +/Oj4+/bj9N76//Dp/unf79Tl8N7t/ebi6d79/+/i9eb9/vz7/+vu9urp9Nro/uvx/+vr++r1 +//Hn9uL4/+719+v19e3p/en+//P8/+vz//L6//v/+fHq7Of0/PL+9fbt++fs9uTy9eHh3NFM +RUBJRDxFPzI8QDI7PDA/QTg7PjE6OzdDPTEyOTRCPTAzPi49PzM8OzZKPDM5PTJKQDVBOTVJ +PDVCPjM6OzBBOTRAPy9AOzc3ODFAODQ2PDM9OzI2PDM8PDQ/PTM5QC83OzE2OTI1PS42NzIu +OzI0OTBAQDVEQDVDPDU/PTA5OTI/OzQ3PS82Oi8vOio7OC8vOik6NjY4NzA0OjQxODA1OTIx +Nyw1ODExOS8wOS4wOCo1OzAxOS85OzE+PDA8ODM5PTE7ODQ7Niw4OjE4OzE5OjQyPC85OjUv +PC41ODEyPTI3PzAxQC04Ny8sOC43PC46OzA7OTE5PC43OSw5PTM3Ois5OjA0OTE0NjIyNzEz +PDM4NzI0PC41NjAyNyo5OjM1Oyg8NTUvPi47OTUuPC87OzUpODE5PTYsNzQ6PTEwOi8xOTAx +NTE0NjUzOzEvPDAxOzE2NzAyPTA0PjIwOSs3OjQyNis3OzYvOis2OjQvOi84Ozc2PCs3Ojkz +Ni80OTM0OTAxNzI3ODcxOzAwOikxOjEwNzEwOjE0Ny8vOTIxOS0xNTUzNzE4NzYrOSo0Oi8t +OSw4ODQwOi42OTQsOis0OTEyODQ0OjE1NTgvOjAzNzkwOjA1OTgvNy81OTQxOy8zNjQvOzAv +OC4xODc2OzI2PTcvOy40PDczPC41ODgzOjExPTc1ODI0Ojc3PTAzPDIxOzAyPS83OTQuPC01 +ODU0OC84OzoyPi42PTk1NzIuOzYvOjAxPzg2PzAzOjMzNi8vOTQzOS0sOzE4OC8xPTA3QDI1 +QDY3QzA+QDswRjI6QDoyPy0+PzgxPSw0QDMzOiw0OTM6Oyo7PzU7PjNJR0BiVDlnS0ZiUTxt +Uj1nT0JyVkCHZUaXbUuhfFOnflevhVu7jmbCl2vHmGbMpGrOoWnTrXLXsH7VsHbYr3vetojr +xJLhxYzrw43nzJDs0ZHq05vqyJnyyJ/w06Dtx6LuyJHwzZfuzJLrw5jtxJfkx4vot4njuHvl +sHnZqG3cpH3OmmPOjWbKkV3IjGDEi1TIjmHHi1m6hle/hVm6iFnAhli7il26hlmzgVWwfVGr +dlOGYkh6WEVXTj5TQzc2PTVEQDoyQDZBPzQsOzA7Pi4uQTU/PDM8PTg7RTRIRzlLTD5UUUNX +XUNoY01salBzalRubk9yalBrclZwaFVxaVRraVFyb1hpbVNsaVBkW0hDQjk2PjQ4OTg3PDQz +OzQ4PjAwPjM6PDI0PzE3PDMtOi81PTUxPTM8OzkwOy80OTU0PDQ1PTU3PjU4PTY4QDg7QjU+ +Qjk9Pzk5QDI1OjU2PjQ1PzYzOzQ4NjQ1OzA7PTo2PjQ+ODgwPzM9PTQxOzA7PTMtOCw/OTY1 +PjQ+QDk2OzQ7PjY1QC83QTI0Pzc1PC83QTU2QjIzQjU5OzY4PjY9QDk2QjRBPz6MpUz6/+X6 +//L///v7//H+//P///z///fv/+j8//P9//b1//Dv+OD+//j3//L7//P6+vPt8+L2/+37/vbo +8+Pq+uHl9t/g8t/Y7s3k8Nvd5tHa49jz//Lt+ubd8+Ps9uny6+fl79vp8uf0/Oz1/fnt8+fu +/e37/vj1/fHw+O7y/+Xx/Ort/ury/+////n9//z///Xx+/D1+fn////x9+Xp++rq39NDQTxj +SDtVQD9GPDU6QzZWQDtSPjpMQDhJOzdHOzlEPjo2OS82OTdCPTJTQDpLOzZOPTZJPzFKQDhK +OTY4NjlAPDdCPDVDPTg8OTQ8OTQ9NzU0ODQ0Ny80PDI9OTQ0NzJAODU3ODc1OjMsOCw3ODcx +PC5COzdCPTRDNzk6OjA9OjE0PjQ3OTIzODE9NzIxNjQ6PTU6OTEwOTgyNzQ0OTMzODM4NzMv +OS81ODUwNzEzNDEuNS07NzQ1OTJAOjg0NzE1Ojc5OjI7OjUzNi86OjU0OjI9ODg6NzgyOzIt +NzMvOjM0NTM3PjM6OTE9ODg4NDFAOTk3OjI8OzI5Oy4/ODczPDU+NTooNy87NjgwNzQ+PDIr +ODM4NDUzMzY0OzI5OjQ1OjE6ODMzODE9NC8yOys3OzA5NTk6NzAyNzItOTI3NzgvNyw2Ojcv +OzA8NjkyNC0yNTwzMC82Ojg0ODEyNTU4NzU4NjU8NzM2NzM3NzczOTIzOTUyOTQxODY1NzMx +NTQ3NzMvODMwOTcvNjI0ODgvODQzOTYqNDA0ODAyPTc1OzEyNzc1NzU0OzEvOy02NjUxNzM2 +ODczNzA4MzsyOjc3NzAvPjY3ODMzNDUxNjI0NzgxOS8vPDMyOy8zNjc4NjgvOjcyOjQvODQ0 +PjUvNzM7OjQsNDI1PjoyOCw7OzwxODMyPDwwOS83NjcuNS8xOTczNzI3ODc0OSovOjY0Ojc2 +NzM8NjYvOjc1ODQyODMwPDMyOTIxPzM3ODkvOi8wODYuNyw0PDMyODM4Nj0yPyw3PTk1QzY7 +PDgyOy8wODc1PDA1PjkvPDY1ODEzOzczNjQtOi8zPjYyPzdFQztWTjtpUj9hTkFlUEJuVD15 +VEd2WEiOZk+Ob0ilfFqselq6jV6+k2TMlWvLqGzVqXvTqHXSrH7Xq3zYuYjat4flu4Tgw4rr +yZbuwZzw0abp1p7z16rxzaT0w6zs16n41rHz26f02Krs1qD10qnxzKDtyp7wxJrqv4rosYni +s3veq3vco3HVmnLMkmfUi2rKj2LIimfGjVvIhWDFil29i2PEimS4i1y9gGCwfVawf1mid1SI +X0V1UUNfRz5JRDo8Pjk8PDg1PjE5OjY1QDA1PjYzOjFAOzkwPDQ3PTQ7PzlESzlHSkFPVUBc +ZUtrblFtZ1RsalJoaFZsbFJnbVRwalNnbFNualJma1RvalFhV0o+Oj01PTQ3OzcsPjI0OTc0 +Oi41ODk1Nzc3OjcxOTU6OTgwPTY1PDc4PTYsOTk0OTQyPjc8PTY4PDszOjU0OjM0PDM6Pzw6 +QTY1PDgwPDg4ODk0PjQ4OjUrPjE2NjM5PTU6PTo2OzY3OTc6Ozo0OTE2NTk4Pzg0Pzc0Ojk2 +OjM1QDY4QDc7ODcyOi46Pzk1PTE6OjgxOzQ+PDw0PTVBPj40Pzw/Pjs7Rj+XpFz6/+7///3+ +//71/+39//n////7//X4//X6/ur3//Hu/Ors997x/OTy9Of19eb1/PXu++fm9OH5//Dt++7n +9t7c79vX59fc7tbf6dvV583Y4NT37+Hh6+b69/X///76//n4//z/+/Pm+N7j8eL9/P7v8+Lm +7dj6/vz7//ny//T8/fHt+Or7/fL5/Pbz/ene9N/w+/L48u3y/Ov0//Ht7+Pb1ctRRkFoSEFc +QDpFPTdHPjVaQTleRT1URThXPT1HQzhLOj06OTE5OzlKPTBhRDpWQzVhQjdYPzldQz1LOzU6 +PTJHQTVVPDVNOzdKOzZIOjNAPDY3OzY3NzY3OzFCOTY9PTJCOTc2NjA6NDQuOSw3ODYxOC9C +OjZEOTE/OzlAPDRBOjY8OzM8NzA8OjM3NiwzODA3NjE0PDM2OTQ3NTE0NTQ0NTQ1OzQoNC85 +NTEpNS48NDcxNTA8OjU0OjJANzQ1OjNCNzU8OTQ7OTM3NzYzNjE5NDc2PDQ0NTI2NzAyODQz +OTI2NC5AOzc5PTE4OTM5OSo7PDY4NjA6Ojk2Nis9Njg6OS0zODgzNy42OTQ4MTQ2OTEyMjQv +OS40MjMzNjI7NzQ4PDI9Njg7OjQ5OjM0PTY4PC80OTM0MjE2OTQvOCw1NzUxOTE1ODEuOzU1 +ODQ5NTU3NjE3NDcvOC8zOTYtNTA0ODI1ODI6PTM0OjE6ODQ1NjA6NTM2NzY1MDA2OjEzNC4z +Njk1NzE0ODg1ODY2NzYyNDU0NzY2MzYxOTE2Mjg2OjE2NjY1OTI3NjUxNy46OzUxOTE4OTUu +OjE6ODQvOjE0PDM1NzU5NjUxNywzOTc4OTAxOTQyNjMzOjQyOTEzOToxOjE2OjU5OC46OjUz +OjA3NzQxNjA2ODIuOC05MjgxNzE6Oz0zOTI1Mjk1NzA1NTgwNDYzNy84OTgzODE0ODMvOjAv +OC82NzAzNjQ3ODYzOjYzODcrNzE1ODYvOC49PTsnNzE3NzUyNzI6MzUpPzQ8PDk8QDQzOzQz +QTI6NTYyPDQ1PjA2RDQ2ODQ2OTgwODQtNjg5OjgzOjdPRz1VUzxpT0xhTThoT0FqVDx6XEyB +YkWJaVGbdk6kfVWuhFy5iGO/jWDEoXLMo3PKp3DXqH7Vr3fZsYXZs4bcuIzkt4Tsy57t1Jvr +z5P40Zrt3rL23bHw2bL60q742a711KL026342KDuzpzx1ajz05zr0KDtyY/iuH7nvIrluH3h +pH3ToGjXnnLTnmvPl2rXl2rPkWnKkl/Ml2fHlWPKkWXKkWTAhlqxg1mweViqf1ikdFKSZUh/ +UkhZTThNQz1CPTg/Ozg2PzE6OzY1OzdENjkyNzU+NzouPDQ2PDM2PjU9QjtLRz9JUERdX0hf +aEllaU5ia1Bja1Jobldpa09vbFVrZ09ua1Nkak1ra05aWEc/QD0yOi46Nzg2PjA2PTYyPTE0 +OTgzPDY4OzI3OTU6OTQyNjYzOzUzNjAwOjIyNjI3PTsyOzQ6OjQzOjI4PDstOzM8PDs0PDU/ +PDswOzc8ODUyOzY8ODcxOzU1Njc3OTcvOzc6PDgzPDM4ODYuOzY1NzM1PjQ0PDQtNzM4OjM4 +QDo3OS81OjY1PSs3OEAzQDg4PTs3PjE1PTo5PjQ6Pjc9OjU2QTk9Rz6TqlT9//b+//r+//// +///////9//v9//7////////////////5/Pb8//r8//z7//P///n3+PT4/ezz/O7p89/u9uru +8uXz/fHl/eHo7+Ld7Nne5Nfz/er0/fzt/+ny/e/r+Oju+ezy/+319fDw/Ovt/ur6//z7//f5 +//jy++f4/vD5/+zy+fPz+O3x//H9//3///f9//v0+/D89O7z/ur9//Hl2c5XSUFoRkBiQjpD +QDpLQDRdRD1gQjlVQDhVPzZXPTRFQjQ/MzgsPDJVRTlkSztsRzldRDVkRjhhSDtQQTg9ODZF +PDJbRDlfQDNVPztTPzdQPTlNOjU6ODY/OzFJPzdOPDVIQDdFOzdBOi05OTU0NzE9OTNDPi5S +QDhGQDRIPjVCOTBDOTc4NjY3NC83PS89ODQ3NTU8OTI7NjMxNjE0OTI6OjIzOjA1MzQvOS8x +OTAvPC00OTM1OjBCOTc8ODJDNzc8NTNCOzk4OjA6OTE1NS00OTU6OTE2NTE4ODYyOTAyOTE0 +OTM8PDRIPzdBOjg6OTI4PDM/OTI7Ni87NjM2NjE+OTcxODA7NjYxODA3NDUwPC88OjIqMzM1 +ODAvOjE4PTQ6ODY7OzU+NjY4OjU4MzU2NzI4OTI4NjM2PDAzOjUyLy4xNzgxMy01NDYwOCo4 +NjUxOS00Njc0NCsxOjcyOTQ2OzM8NDQ3ODc7OTk4OTM3MTE1ODE0OjMuODU4OTM1Oy4uOTQ2 +NjY0NzQ4ODouOTA0NTcyNjI2NzUwOi42ODkyOjU0OTA8PDU3OTM3PDY1PS47NDQwNzE6Njg2 +OTM5ODgzOTE2NjEzOTIyNTIsOzM0NysyOjM1OjM0OzI3NjM4PTs5OTI0OzU1Oy0yPDE3OjM3 +OTE0NTM0ODQ1OjQzNTI2OTQvPDMvNjUwOzQxODQ3PTM7ODk4OjAyOjk3OTMzPDY0OTQvPDQy +OjMuPTUzNjQwODMyOTc1NjsvOC81PTktOS0yOzcrOyw4OTkvOSkyOjUwQDM3Pj41OjE8PUE6 +SDM9QEA2OTY3OjcvOjU1PzAyNzYzOzQyQDc2PTRESDxaTUJlU0VjTz1nVT55X0x8V0ODYUiM +ckahfVamf1S0ilu7kF7GmW3KoXPUqX3VqnjUrnXbsn/YtYLZuIXcwYvnxZPky5bq057y1Jnx +26b14bH447D54LXz1K753rHw36r11rDz2af12azx3Krz0abt0JXxypzqwIznu37ltXngrnLU +oWvRn2zRnWvTmmfVnHDOlmnIi2nHkWDJkmHPmWrBj2LEimC7hV2wfleje1KecFGUa057WEJY +SD9KSjlDSTg/RDU9PDc2PjA6PTgwPTA5PTY6PjI2PTMzOzI4OzQ4QzY4QzdHSj5FTztOVUVe +YkZmZkxqaU1sbldsbVBlaVZvb1NibFBqZVZoaE1ZVEw5PTc2OzUsNzA4Ozk1Oy4zOjMxPTE6 +PDUyPTUpODQwPTQzOTcuPjIyODI2PTY1PjU3PTMxQDg0PjM4PDgyOTI0OzovQDU8QDUrOjE4 +OzgsPTI4PTcyOzU3OjYtPzY2PTY3QDY0PTUwPS84OzQxPjMzRTI3PTgvPzM0PjMzQDUzOjQ0 +OTg6QDU2PDwxQTI2PTctPjE9QTwyQTY2PDksPjM6PDk0RzlERj+brFb9//P8//f9//b///r/ +//3///////////7///v3//Dq/+fx/t////////n///z9/fX6//Tx/Orp7eTt++b4//rq/OTi +8uHd9tLh9N7h8Nfn9drt/+vw+Ozt9+rq6ubr9eTs+vD6/vX8//H9//79//P8//X1//Dr8OH7 +/fLy+O/z+vX9//zx/ev09fH19uz4/vH1+fHt6+j4/vj1/e3x8Ojg1s1TQkdoSz1kQEI/OzdH +QDtaSztlRz5iQz5WQjxTQTpNODg4NjU1OzVRRzpqRzpsSTllSDxkSjhqRztQPTRFPTk9RDRh +Qz5WQjZaPj5UPjRaPzlNOTJCOTs8ODJQQTVWPjxWPzlUQDRPQDdEPDU3ODFBPTdWQzpWRDhY +QjtQPjhROjxFOTJDNjc0OTJBODc5ODBHOjE5OzNAOzU3NDU3OjQ3NjNEOTk3PTU5OTc4Njk0 +ODM2NzM9ODNBOjdCOzhFNzNBOTk+OzhANjk1OjA7Njo8OTI8Njs+NzY4Njo3ODI3Ojk8PDVe +UD1xT0JQQTlBPDg9PDVBOzo9NjJDOzg7Mzc7ODM1OjA3NTM1ODg/NzY6PDc2NDA5ODY2OTQ8 +OTc9OjZFOzpBNTlBNjZBODhBNjs9OTg+OzRDOToyNjM9Njw1NjY4NzQ1NzE9NTQ6OTQ9OjY2 +NTg6NzYwNjU4Njc2NzY7ODk7Oj09OjI7NTk5OjY5Pzc8OjkyODU5NTgzMzI4Nj4uNTE1ODc0 +ODM3Nzk0ODQ8OzgtOjg7NzoxNTU2OTY1NjQ8OzU3Oy86OTpCOzdBOzY7PzY3PDc6NjI7Njc1 +NTU0NjY3ODI6NDk3OjIzOTgxNjI4PDg3ODFAPz06OTA+OTw8ODFCOjxCOTE6Pjg9OjQ6ODI0 +PTAzOjg7ODk9OzkyODA6PT0zOTA6Pjk4OzdCPDs5PDZBPDg1QDBBPDw0OjQ8OjcwODQ+Nzw3 +NTo6OzY2Ojg0OjE5Ojw3Ozg7ODo4Nzc2Ozg1NzY4NTo4MzcxNzg5Ojg3PzFBPDs7OzE6Pz81 +PDE7Pz80PTE6Ozw5OTE2Qzs2OzE1Pzo/QTtHSzldTUNqU0JmT0VuWUF8XUd6WkaGaE2Xb1On +fVqsgVW3i2zIk2vFpnHXpnDOp3vYroHRq3vhtn3awIbfv4noxJPqzI3vzZnw1qD31q/236f7 +4rT76Lj847L2z6ry3bDz4LP106zy3a311Kfv2KD20aH0ypTtyZPlxYnsvITisoDlqHPcqXHZ +oG/WqnXXnW/Un2vWo3LOmmrPmnPKkGfMlWzJlmLHiGSzh1eweFqhdU6hclWabVCCVEZYRT9J +QztIRj1GQTg/PTg/Pjc2Ozc8PjQ4NzQ9Ozs7Pjc4OTkwPDQ+OzY4QC4/Rjs6RDdPTEVTWkJx +alVvalNzbVpra1NtallvbVhxaVRwaVJqak1fVUs9QDo5PTc9OzM2ODE4PDczNjY5QDgzOjc4 +OzQwNzM8PjsxNzU7NzgoODU7PzktPjc6PjY1NTc2Ozc3PDE4PDU8QDk2Ozc+PTM1PTI4ODQ0 +Pzw8OTg4OTg5Ojk1PDk3OTM7OTw2PTI9Pzo2ODE6Ozw5ODg0Ozw6OTo0PTY8PTU6Ozw/Ojs6 +Pjo9Ojk6Qjk8PDs1OjY8ODg8QTw6PTg8RDs7QDo7QzxESz+ZqVv2/+7///////////////// +//X///z///b3/u38//D8//r+/+z///z0/+7+//Xy+fjp9N/8//T9//vw/O7t+uLo8eTn8+Pf +79jV4c7a7NXb6tXv//Px9+fn/OT4/fb5/fDu7+Pl/OTw/u3k9d76//jr8+bz9+rx/ez7//ns +9+z9/vb59ejx/uj+//b7//fz//L5/fP69/H4++/3//Ty8ufZzchKSUZoTDxlRj4/PjBDPTlW +RDlkS0BgRDNbRD1ZQjhMQjg7OjMzPC1ORjllRztqSD5mTDVsSD5pQzdMPTk9NzQ+OTZZQDda +RzhbRT5SQjRZQjVJQDVDPDU3ODNSQDhQQjlbRThYQDdRPjNFOTQ2OCw5OjRMRzhhRjhWRjVU +QDVMPTVLOjY6ODI5NzE+OzQ/NDFFOjVDOy9EOTQ/OC0xPTg4OTA9ODY8OjAxPTU6OjEzPTM4 +NjE6OzFFODRCNzRHOTRBPDFFPTY6ODUzOjU7PjA4OTM+PzU7OTMzOTQ0ODA1PDJPTziXjmSw +mIB1V0g6PTQ2ODA+PDU+NjBCOTQ5OzA/MjYzOS46ODUtOjA5MzMxOTI6NjE2Oi44OjQvOTJB +OjU+ODdEOzg+NzRDODkzOjI7OC07NzE+OTM3OzM2MzAyNzE6Njg2OTA3MzktOzE7ODwvOiw4 +NzItNi84NDIqNy0/ODs0OTM+ODM2OTM6OzQ2ODMxOTUzODE0ODQ1OTM3NDEyPC83NTI1PDIy +NjUyOi03NjcxNDI1ODovOCs2OzkxNiw+Nzo9Oy09Ozk+NDNDOz09Njc3Ny00OjU5NjQ0Njg4 +OzU0OjEyOjAyNzUzOzEuNzQzOzszOTE6NzEyOTE5Ojg4OzBCPzo4PTZAPTgxOjQ8OjQ2NzY7 +NTc4Ojo5NzUzODc2PS43NzU6NzM8ODw7OzM+PDc8Ozg7OjE8OzcyOTM5OzczNjEzPjQyOi43 +Nj0xOyoyPDo2Pi44Nzg3ODQuNzI0ODUyOTM3NjYsPTIyOjkxPzM7Oz0zOzMyOzU1PTQyPTg4 +PzQ1PDg3OjAzOjs4OjY0PDc3NzY4RDtPSDtXSEVmTD5oTUJrXDt9X0SBXUORa0eceVGrhGGt +kFy9imu7l2jGmXDLqGvUs3/frXTdtYDbrn/duYbhx4vjwYjiz5XozI3s2KH4263y4qv45avy +4ajr4KP10Kbx3qjx36f01p/z26j1zKXpxY3zvZ7rxYfxxIjjwIHqv4jhrnfgrnLXpnHcqW7W +q3HTo3HVoW/gqG/SnW7SlGvLlmbHkGK+jmHDi2C0jFmtdlecb06dck+Na0Z8TklYQjVNPzpE +QDM/Qj8+QDQ8PztCPTc6PTQzPDU3PzM6OzY8OzgyPDc2PTI2QTY9PzM6QjdHTTpRWEVpalFk +a1F1bFhmaU1xbVJiaE1vaFFkbU5ualNgT1A3ODM0OTQ0OzE0NjUwOTA0NjMyPDM3NzUzOTU4 +OjUuODY3PDI0OjQ0OzA5PTcwPTI2OzcxOzEyPDwyPjQ0Pzs1OjAxOi43PDI3PjI5ODMxPDQ8 +PjguPDQ6PDYyPDY6ODMyPTQ4NDowPjU0PTA2Ojg4PDgxNjE2Pjc2OzE6RDM5PDY1PDc6PDAx +OjE1PDM2OzUzPTU7PDY6QTY7PDg2PjI3PTc3RjZBRj6WpVz6//D///////3///r///f///z4 +/+/6//L///n///////z///H1/vP5//L6//Tz/e/3/u/1/+/q+ufr9uTm9OPv+eLu+vLa6tDj +6tvh9dnZ3tP1//f0/PPx/PX1//Hr+eft8+3y8Ovu/vD9//v5//P7//v6//P+//fy//H5//v7 +//H9//j1//L1//jx/ebw/u/9//Tq8OPl/+Xz9+fy9evnyM5QRkhnUEBbPj9DPjs/PDhTSD5m +Sz9kRTxcQTteQz9PQjY6NzosPDFSRT5tTTxvRj5qSjduTEBjRTZNQjk/PDE9OjhRQDhZQzdc +QjlSPzlZQDtOPjg/Nzw8OjdPOjpWRjlZRDhUQTtQPjtHPTc2NzhDOzlVSTdkRjxXRThaQz1N +OTlMPjU3OTM8PjQ1Ojc/PDRLOzpFPzlHPDs7OjQ2OjU0PDREPDY5OjY6Nzk7Ozs3OTM4Ojg4 +OTFHPDxHOjZGOzlHOzZFPT89PDQ6ODhFOjdLPTlHPTdAOjg8OTQpNTI4ODlhZka0soPEso6F +YV1BODk4OzVEPzNPOjRMOzlIOztBOTo4PC46OjRHPzdLOjdEOjc+NDc+Ozc0ODI9ODdJPzZQ +QjpHPjhMQTpHQDdENjg0OjhAPDBCODU8PDU1OjU6NzE4OzY3NzI2NTc6Njg5PDczOyw3NDM1 +NzQyODM1OzU5OjQ+Ozc8PSw6OjU1OjM6ODowNzI8NT40NTQ8Njw2ODU1ODgvNzQ7OTkvNzQ8 +OTY3OjcwNjg3NzgxOjo5Njc9OTg7OTM/OjU/PjRDOjpAOjY9NzgzNjY7Ojg1OTE/Nj03NjU7 +OD8zNzM3OzgzOTEwODkvNTY4PTg8OTc6OTY8OzU+PDVBODk/OjQ+PTI+Ozk2PjQ5Nzc5Ojk3 +Ojw4Pi85NTwzPjg8OTkvNzc9Pjc2PTJEOTc/OzZCPTg7Nzk2OTQ2PTszPTM0Nzo0Ozc5OD41 +ODEzODg2Nzk0Ojc4PD8vOzQ1NzsyPTM0PDstNzEzOjowOzU6P0E3PTg5QTw4PDk5QUA1OTcy +OzY6OzQyPzQ8QDowOjM6PD48PzhMSkJaUDxpTEZpTjtzV0eHW0eMYEybcVGle16wiVyvil6/ +jWu+kGjHm3TUqnjYq4nXsIPZsHfduIbjw4rlwJLjxovpyZ3qzJ3v1Kjz1aD437r45bD64Lz0 +36v50Lf04bP43LP14Kz507L427HtzY/ryJHuxZfpwY/svoHltn/lpXvVp3DhqnLXonHYnnXb +qnXerHnUqm/Wp3HOnGTMj2PDkV/KjmfAkmW+hmGwfV2fdVObdlOMaE9/WUlzTUZDQTk8PDs2 +Qzg+Pzw3PjU2PDoyQTM8PTkxPjJEPDw0OzU7PD05PTI7Pzo2PTY9P0BQTj1LT0JbXEdlalFu +bFZnblFobFlpbFRubFBqbFJjaVNaT0w0OzY4PT0sODQ7PTwwOjU7ODgnOjU2OjQuPDc3NTk2 +OTQwPDc1ODc0PDU2PDwzOjk0OzkzOTc4OjYxOjM3PDUzOzY0PjUxPDgyPDY3PTo1PTcyODk2 +PC81PDw3PDQ2Njw7Ozg2PD81OTcwOTU3OT4yPDI6NjU1OTU3ODk2OjY8QTozOzg2NzY2PDk8 +Ozs3QTg1Pjc6Qjw4PT89Qj07OT48Qz47QT9CSECfqVv6/+/5//L5//D///////////////// +//////////3///v+//n4//T6//b0/+v1/+v2//D+//71//L7//X2/fnq9eTf8d/X7tDo+N/o +7uTm7Nvr/+Xz//n3//Lp/Ovr9er5/vz///////P1//Ls/e/t/ej9//vx9ejq8d3q/On1//X7 +//3///v1//L6/vHs+ePq9ezq6uD09u7t+ufx8uLTv7tHRkdtSkBdRjU8OTU6OjdTQzxkSD1n +SUBiPjdVRjhXQDkwODc5PjVKRThqSzlmSTZwST9mTjZoTDtIOi0/OTg+Pi5OQTlYPzFVQTlX +QDZUOzRRPzM7Oi49PjdIPDZaRDlXQTdePjlSPDlDPTU6ODEzOzFbRzlfSTliRDhTQDZWQThB +OTFHOjQ0ODQ9PDVCOzZBPTFEPDdKPzdAPjUwOjE7PDM7PjBBODYwPDA2NzU0OTQ0NTQ4Oi89 +PDRJPTZJPTFOOTpMODFBODY7OS1BOzZGOi9LPDNFOzE0OTM6OjEvPTBkaESytYDHupKHalhH +PTo5PjBLOjRTPjhRQDVMPTU+NTI0PS85ODFMQzhOPjpMPjVEQDhEPzM3ODM8PDBQQjhTRjdY +PDlSQTRSPjk/PzA+OjVEPDBWPzdBPzJBOTQ5OTU6OTUwOjU8OTc/QDRCOjc9PDU8OjU0NjYz +PC8yPDM7PDU7NzA/Ojc4OzQ8PTIzOy42ODguOyw2OTYxNjA2NDkyNzE1OTQuODI1NTQzOTc2 +NjQtNzYzNzUwNDMzOjpBPDBCPDY9OTRBNzVDPjM+PDY6QDI6NzY1PTU7Mjk0Oiw6OTkyPC03 +NzovOzEzOjkxOC01Ojs2OS86OjYzODI9PDZDPjhBPjNCPDdCPDM9OjE3Ny00PDI5OzQzOjQ5 +NTYyOy48ODowPDE5PjwvPTM+Ozc4PjI9OzY4PTdAPjYwQDU2PzA1OTYzNjA4ODEzOjU0OjQv +OzQ2OzcyPTcyODcyNzMxOzU1PjorODE2NzMtPTQ6PDszPzQ5Qj0uODFAPjs5PzUzPTU8PTMz +NjM1PjUzQDQ3PDcyPTNDPzpLSjliTkJoTT1sVkCCYUGJY0yUa0qUd1ind1OrgVmxhl23jWDF +mWTKpXXKpWrOsnnaqoDasYTduoHgvoPiwn3vypjm0ZLvz5zt1aL53a/02aX62a344aH43KHu +z6rz3Kf12Jry3qT56K/526fy1qTxx5jpypDtv5DktYHltHritnvhqX7bq3bZom3WpWrYq3ja +q3LYpnfVoG3Sm23KjmfFk2fDk2fBj2K6iliufFqack6VclOQY0h7XkZrTD9ERTc5PzU3PjM7 +PzY2PTozOjY8PTYzPjM+Ozg0PDM7PjkvPDA9OzkzPzE8Qjo6QTRERT5JSTxZWUdialJrbFJo +aFJrbVVoaVJraFNqaFFqZ1FaTUo+OzYzPDU2NzczOzI1OzUtOzI2OzUnOTE6OjQuOTI6Ozkw +NzQ7PjIxOzM4ODE3OTQzOy8vPDM1OjZJRDg0PjY2PjYwOTY2OzEvQDc2PTc3Ojk4OzE1PDIy +PjE+PD01PDA6OTk1OjA2Ojc2OzAzQTQ5OjIxPTQ2OjI0QDI+Ojg3QTU6PTY3PDc9PTk3Qjk/ +PTY1PDY5QTg7Pzg6ODg6Pjw+Ojk5RzlARkKfrFvr/OD9/+v///v////9//v0/+v+//P///// +//7///j3//b0/ub+//X////////7/vP2++r1/e79//v0/+z6//Xu8e3a6tPa8tTj89rh8tjo ++OP0++/s+erq9/Hx/PD///75/fnx+vXv+OXz/vTy/+rs+e3l++f3//z////u//P68fLs+t3t +9ury++/7/vX+/vz////////1//L29O38//nr0dNJRkZwUD9bRTtFQDk7OTNVRjlpSD1nSTtj +RT1WPzZVQDo7PDI0OjdJRTZqUT5uUTpxTj1rTjxmRzdNPzc9OzdBOzVHPjdeRzVaRTZYQTpW +QDZPPTc8Ozo4OTU/QjZYRjZbRTlUQzNaQDpEOi86NDg0PzFYRjliRzdkSTtWRThWQTdKQDhD +Pjo7Ozg8PDNCOTM/PDRGOTdIPzpCOzY1Nzg3OjE9PzU+QDQ4OTMyPDQ2OTQuODQ4NzU8OzRU +PjpEPzJOPjhHOzRCOTg5NzBFPTpMOztHPDNCPTQ8OzM2OS4zPTVfbUe5wIXGvJeFalhBOjM8 +OzdHPzZdQzlRPTNSOTo/PjVBODY7OTNVPTlRQThXQDlMOTpHPDc6NjdCPzhWRjhbSjdeRjpX +RTVWQDg/OjlCNjZHOzhWQDVOPTk9Oi5HPT44Oy43Ozo9QTBKO0BLPjdMP0BKOzQ5Ojs1ODc1 +Oi49PThAOTtCOzU+OTg9OjkzOjMzNzc1ODA2ODM5NTY1OTQzNjUxOTM4Njc8OzVCPDgyOTg1 +PDQxODo1PTIyOjZAPjNOPjdNPjlJPjlJOzZJPDs7OzY6ODc4PTM5OjU1PjM6OjA0OzUzOjMz +NjY0OTQ0Ozg1OTE/Oj4+OzA4PTo+QThCQDhEPDZDPTZHPjg/OzNBNTs6PjI2PDY2PzM8PTc0 +PDM4Pjk6PDQ3ODw7PTZDOjs+PzI+OjdDPjk9PDM3OzQ0PTU4OzQ4ODc1Nzc4ODMwOjU5PDQ1 +PDJAOj4zOzU2ODcyQC03ODg2PjQ4NjkwPTE6Oj44QzY7Njs1OjEzOjU3QDk2Ojk2OTsyPi84 +OTg5OzMsOzQ7Pzc8PTlLRzxXUj5mUEVzU0eFaEyFbU+XbVSXd1WlelqniFezhmK2kGfBiWDG +nW7OpnHUqX3StnjauIHcsoLhuo3pw4ngxIjr0Z7q0Zvt2qf22bf34az247X6167s3rT60rP1 +36j837fu3KD42qb10Z310KnvzZj10ZrywpDpwobqtYfmsnnhtn7gsXfgrHbfsnjcqnrerXvi +snvjo3fPmmrKoGjGjmbNj2W+jmW4gl2ogVqseFScblGNa0uFYElnTT1NPzpARDk+Pjs3PzI6 +PTYwPDU/PDg2QDI/OzU3QTg6PjU3PTY5PTQ6QDk6PjU7RDw/QjlJST9ZWkNjZk9ub01rbVZu +bFZma1Nta1VqaFFtZVNcTUg9Ojg0PjM0ODYvPDExNzcxPDE5OzY2PjYzOjUyOzc1PTQtPzM1 +OzQ4OzYzOTw7OjcvPzU0OjY4PDc1PDU4OzkwODE+PDgwOzA5Ozc0PDM2NjczPy44Pzs3QTY+ +Oj44NjQ7PTQ4Ozc7Ozc4Ojg3NzQ0Pzc7PjQ7OzQ6Pj04PjU8Ojs6QTU7Ojs2OTQ9QDc2OzE7 +PzYwPTFAOzgzOjVBRDoxQjhDRT1CRT2usmP///n///////////////////79//X6//r5//Hx ++O3w/uX1/ub8//P///r9//T+//r9//r2//Pu+OPy/+zx/en5//Tx//Pi89/e5dzb6NPa4tTx +/vLp+Nz0/PXt9+Hx/fD6//L///jx9uTz/O7x+/D0+ejt9Ojt/ePy//L1//L2//L4/e/5//X9 +/fLv/u77/eXj8OTq6+Tv+uv1/u7t9eDax75GRkdyTEFdQjVCQDk+OzdPRThyRz9rSzdeQjla +RDlYPDc3Oi80ODFHQzZnTTxyUT1zTEBwUURuRjxLPzlCPzU/PTVJOzNbRDdgQDZSPjZbQTpI +PzZAPDg8OTJFOTZUQjdgQztYQDVbQjxLODU3Ojc2PDFbRjhjTDhkSThYQDhTRTVOPzY3OTM3 +OSw5OjJBPjJKOzVKQDRPQDpAPTI4NDM0OC5APzQ8OjJBOjc1OjE3NzE0Ni87NjU/OzBLPTVJ +PzNMPjRGPDhBPC03PTJDQjVPQThLPTZGPy84OzI2OTA0OTRkbUTDwIfIu5WIaFs7PTNBOzY/ +QjRgQTxWQzVWPzY+PjE2OjZAOzNWPzpTPjlQQThTPzdBPTU4Njg7PTRURTZgSDleSTlXRzdW +QzVBOTg2NjNMPDpZQjNTQzxCPDBGOz0/OTA5ODxAOzBPQTtUPztOPjdOOzY8PjQ2MzI4PDRE +NzU/PDBFOTM7OzA8OzEzODQ1Njc4ODk1OjM6OjYyOTI8PDcwNTQ5PDJBOjdOQjc/Ojc0PDMx +OzIyOzE4ODZDPjRYQTtXQzZSPzdVQjZRPTU8Ozg+OzVEQzxLOzNBPjQ/OS8+OjU3OC02OzU2 +NjE1ODg3PzNBOzZCOzY2Oi9IOTlJQDRMPTZFQDRKPDg/OzE9OTs6NjA9OTs4PTI7ODo3PDQ8 +QTg3PDY1NjQ8OTNCOjZFOzg+PDdCOjY+OTc3OTc1PzI1OjEzNzgzOjA2OjAwPDA9Ozs0Oy04 +OjQ0OjE3PDs0PDI4PDk0QSw0NjgzPy87NjU5PzM6OTk3PjM3Oy4vQDE3Pzg1QTc4OTk2QjU4 +OzgtPjg7QDg3RjRNQz9cSzxtUkR0YUOAaE6Pb0mfcVCbgFirelifgFytfFe9hmC7imfInm/H +n3LXsYTbt37itYbfvoniwYnmtY/gxYbuz6Tp0Jbu2Kfy3qf147Hx4qn42bHz36b0zqvv2afx +0Jn33ab41qzz3Kry16fyyp/yyZbtw4/twI3rwI3rsX3ornrnsXjdsXjhsnjZt3fitHzasHzg +pnDQn2zKj2C/lGLJi2HCjl25h122e1umdVGccVKGcEySZU1tUkNSSj9BPjc9PjY+Pjc6PDcz +PTc/OjY3OjU5PDIzPTY2PzA3PTM7OzM2PzY9Qzc8SDtDQjpCSjpRTz9iYktka1BmcFFsb1Vp +bUtrZ1RpcU5raFJYT0M4OTY3PzQ2NzQ0PS46OTU0PC01OjEwOzE3NjM5PzQuPDM1PjItPDA0 +NzAzOzU3OzM6PDk4PC45OTYxPDQ8QDcyPDQ3PDYvOy86PTQ0Oy44OjUxOzE3OzI3QDg3PDY2 +OTgzQS85ODQ3OjQ3OTI1PTQzQTY9OjkzOzNHQzk7PTo+PTk7TzM4O0ExPjBCPD4xOzM9PTsx +PTQ/Oj0yPDY+QDg1PTg+QztCTDyVrGPx/+T9//X8//T///f///n////////9//v9//X///79 +//b///H7/fT2/uzq9uDu+eju+eD4/+/7//L5//ns+unu9+Xp9OHh/Nnl9N3q9+Lj693j9OX7 ++fHt9uj4++7v+vLy/+719evp/OP+/vry9+v58O3p8eP6++v2/vL6//X+//T///Hx+eXu8/H/ +/fX5+/b2++3t8Ofy7+bt7+f3/eXgvr1LRUNxRkBWPz1JPT02PTVSPj1oSDxtPz9dRDhnOj5U +PTNEOjk3PTJGQztlTDlzUEB0Tzx0Tz5qSTtQPTJFOzM/OjRNPzdhRThfPjtePThaQTZUPTo/ +Pjc/NDZBOzNdQzxZRTdfPzhTQjZPPTkyOTI8PzlXRDZtTDthRzhdQzhXPjpHPjNAODc7OTM+ +PDdEODVIPDZMPDVNOTVONjczNzU9OTQ9PS9FPzo7OC88NjUxOS5ANzUwOTVKPDVMPDdUPDdO +PDZGPDhBOzc9MzRGOzhPQTlRPDhNOjo8NjY4OzI4PDFtdU3HxJLOuqGJZVhFODo6Ny5LOTdb +RDFdPztSOjI+OTo+ODNAPDNWPTdXQDhUQDhOPDhDPDs5NjNGOjVeTTZlRDpaRzpiPzhUQjdD +NzQ+PDdOPTRaQjpTOTpDPTlDOjU+MTI3NjhNPjZQPTlVQThPPDlLPDg8NTg3NjQ7Njw8PDRF +PTZAOTJCOTc3OjE6Oi04Ozg+NzQ6OTo7OTRCODY5ODQ2ODI9OThNRD5VQzFEPj08NTc7OzQ5 +OjU3OjZKPjlgRjpmRj5dRTllREBSPjRGNjs+PjFSPztQPjZTQDdQPTdDNzg2OTE8ODZBPDk8 +OjZMQTZbQDpJPTNBNjRSRjZiPzpaQTtdQTlWQzZGOTg+PC5MPjtKOjZHPjZAPjNBQDxKSD1I +PkM4PDFEPD9RPjRXPz9OQDlOODdFNjc7Njc+OzdGOjZBPzBBOTQ3NjI4OTM3OzRFODo3Oy9B +QD81OzQ5NzgrODA6OzcvOTE6NDQzOzE/PTo5Pjg3QTgzNzw2Py04Mjs2ODYzPzM2PDYzOjc2 +PTg6PzNAQzdMSTtWR0FgV0KCZ02Ca0eccleddVardV2veVquiVq2hFq2j2zEk2nGpHLUqHrT +sHjjt4fbtYnnyZfpx5flwJPpy5Lu1Zzz06Drz53v2Jrr2aT42K7z26j/2af30K3657L43rX9 +3LH01K/61qD52qT31537yJPuzJHzy5fqw47rs4bpt4XptYHir3nitXzetHnksXzjrnzap3HM +l2LLkGLNkWnJj2LCjmPAi1zDiV+zf1uZbE2OZE97ZUd1UURVQjlGQT44QjZCQzg6OzA8PDg6 +QDhFPjw5OzE5OjZDQz5CQDw8PDdGPDxCOz43PjdDRTpWT0NVVUdiY0toZ1JrbVJra1RzbVRq +a1BvZU5iaU5ZSkYtODI9ODo3PDM9OzkxPDM8OjY0RDA8Pjk6OTQ5OTM3OzkxOjY2OTEzPTY2 +OTI1OTY3PzQ6OzU0OTQ6NzcyNzE4OTYzOjM7OT0tOjQ+NjUzOzc3OjctOzBBOjc4ODc7OTM3 +PTM9OTM4Ozc1OjM4ODc2PjE9NzU1OTU4OjM/OzY8OzU4Pjo5PDI5QTg8PDI/PTc1PDFBQj48 +PDU9Pjo7PTI4Ojw9QjlDST2fvG3+/+/////////////8//39//T///X////////8//H4/+r9 +/vT5//f7//P6//by9e30+e3w++34//Hj6d7p79z8//vn/ubp+tzj8uPb6dPT5c3q9Onw/ur3 ++fT18eXk7uPy+Onw/+n3/ef0//X7//H3//H5/+X3/ej4/vD+//X0/+v0+ujy/e77/+zz/+7x +++ns/eHw8+T5/vn9//nu8+PcvLlHR0FwRkBTQDxBPzk/PTlRQDJkSDtwRT9cQTlePzhTQzVE +PTcyNDREQDdgTTVwTUR4Ujh7TEFmRzdROzc8PDBEOThCOjFgRDpiRDtgQztaQDhNPjhKOzg8 +OjM/PjBZQjlbQTdgPjlaPzVNPzM1OTA7OTJQSDNnSjtjRTFfRjtTOjNOPjk7Ny85OjQ4NC5H +NzhFPi5LPjVQPTlGPTM3ODY3OjE5PDVAPTI+OzE1OTI3OTI0OzE4OjFLNThLOzRRPTdOPDZL +OTo4NTU+ODJBPDFUQTdJPDZLODI3OzY3PTU8Ojlvc0vHyJfNwZmJZVk/PDJANjFFQTNdQTNX +RjpTOzJDOjY2NipBOjRQQjBVQTxQPzBLQDhGPy80OTg9PTRhTj5kSTlZQTZiRDlQRjBEOTM9 +PDFKQDlaQjhSPTpDOTA7NzQ8Nzg3OjFHPDpTPThTOz1NQTdQPDU4OTQyODI5OjRDQTBDOjNF +PDE/OjA4OjEzNjQwODE7MTY0Oi87OTo7PDA6OTEyODQ6OzdFPThSPzdHPjo7OS45PDc3NTc4 +ODVJPjRlRT5kSDZeQzdiPzlVQTZBODc9OjBSPzpURjRaQTtLQDJBNjwwPC8+OTY/QDNDPDtG +PzZcRjlMPjRCODpSRDdoST9nQTtcRDVaQjhFOzdCPjVSSTtZRDdRQjtDPjhAPztQUE1PPT41 +NTY/OzlRRTVhQUFYRDBYQDpBOS9COUBKQC9VPzxQPzhNPjhEPDk2OSxDPztKPDFIOztANzg3 +PS02ODQ3PTVBPDc2OzVDNzo2OTc9PjszPDA6ODoxPzE6PDctNTA7PTg2PT06OzY1NzU2Pjg3 +Pzg6PjBKRDxWTUFsVkeCY0WJak+ad1mdeVmtgVmniVizhF22i2LBkmy/oG/MoXTPonDarHzd +t37ivorkuYblvpHkx5bry4/rzp3rzJLjz5f02aj12aj03qr74a714q/3zaf43an45rf/57X6 +2ar01aP21J/6yZvsyJD0yJbyw4zrvo7tuYjlwITlt4ncsHfhuHzivIDir3zarnLfp3jPn2bK +mWLNkGHHjVvCilnBkmTEjWK0hlmwcleMZ0l+W0NeSkFKRz9QRTk/RDhEPzxIPjc7PjQ6QjRK +QDtGQzhPRD5ERTlCQTw5PjBCQDo5PjFDQDVMTTxXU0ROTEBkZkxiaUpvbVRvZVFoa1NoaE9v +ZlBlYVBaRUY1OTVBOTkzOjI7ODYzOTI+OTk2OTQ6OjUwNzA8NzYwODI6Ozo0OTA4OjQ4OzQ0 +QTw0OjM8PDA6OTc0OTQ1OjYvODQ8ODI2OjQ8OjU3OjY3PDU4OTgyPjFAPj05OTZHOTU1ODZA +Nzo4ODc+PjQzOjU3NzYzOzM4PDY2ODQ4PjRFOTY7OjQ6OjAzOjU9PDk7Ozg8PDY4Pjo9PDlA +Pj48QDg+Qj07PzlJRUWhsWP6/e3+//H+//78//L///f///7///j6//j0/eX+//r6//75/+n6 +/+71/vHu/e32/+n+//v2/evn8+Dw/eb///rr9+3X5c3S78nZ5dPd4dba3dHr/OHj+OPs/erq +9+vu9vD98/jr9eX0/O/x/vDt+e/0/uj6/vL+//z///Hx9uvz/fn///7///3y8evf7t7z/fL+ +//7//f////Xy9Ovy8eTwrsJSR0hpRj5gQzY+PDhCQDdJQzprSj5wSUBkQzhkRzlZPjlFOzc5 +OTBBPTxhSzx0ST90TT95UkJsQjtNOTRFOzRCOjZFQjVgRDpiRDxcPzhXRDxXQDdCOTo8OjZB +OzZgQz1aRzhkRDpcRjhNPjg0OTI6PDhLQjdpT0BjSDpfRTtVOjdMOzc7Oiw+NTQ/ODVIOjdO +PjlNPTpOPTU/OzU7OzE4NDg8PTRAOzg5QDY8OjkyOy44ODUzOTNFPjRMPjVVQDRMOjVKODg7 +NjU8OTVGQDRPQT1OQjlLPTg8PDg4OTE1PDVqd0jGyJTQvqGIZlhGPTU4ODJJPDdaQzZfPzpP +PzpEPDY1PTVEOzZNQTdaQztJQDhUODo5PDFANjRAQTZjSTpkSTldSDZfQTlUQTZHOTVBODdQ +PTVeRjlUQDhIODlDPDU9ODczNzJMPD1UQzZWPEBOQTROOj42OC02Njs6OTFEQTpKOTlFPzBE +OTs1OjQ1NTQ3NjY2NzU1OjI+ODY8OzY7NjQ4Ozg4OTVLPztUQz1MQDs4OzBAOzw3PDk9PDVD +QDNlRztkRTtjRjpiRjtUPjZDOTtBOzNWPj1ZRTtYQD5OQTlGPTc0OTM5PjJBQDlCPzNOQjxg +RThQPzo/OTJURUBpSD9lR0RkSDVYQjtEOjVAQDVVRj5WPTtUQDpCPTM5PDtPVEJSP0Q8NDRA +PjxPQjdcQTdbQzdSPzg/PTM+PTxORTtXPjpQRzlRPztAPDgwPDRBQDRMO0BHPDVJODs7NzE4 +OjUzOitDPTg+QjBBOzk+QDNBPzw6NjU+PTY3PTY6OTw4RDQ4PD01OzM1OTk3QDo6PjU3QTk/ +QDFLRT1ZTTxrVkZ9Zk6Lc1GUc1GliVime1qlglq0hmS5hl29k3bEoGzNqHfKsXrdtordtY/l +w4/pxpbqy5XqzJ3r05fq0aHvzpXu0qXy3rHy47n02q333a/z2qb01J/53Jv43Kn83LH64K79 +1rL43KP42afzz5nz06LxyZjtxZDyxpPqvI7puIPouoLitITZtnzjr3vdrHPQpGrOl2fKkGTF +jmXFjGHLlGrDjGLGhmWvg1qjdVGGY0qAWEZYTT5PRj5JSENIRTpFQD9ESDtFQj1QSzxXRj9R +ST1VQ0BFQzdJRj84PTU9QDQ8Qjs9PTtQTj5HSz9SVERlZUxvbFVyblVrbVJwalFxalZxaUxu +ZVFWSUY4QDg6NzczODU7PDcyOjM5PDg2OjM0OjU2NzY+ODcwPDM0OjgxOTY7OjwyOzY2Ojk0 +OjY8Pjo9PjYxPTU1PDg4ODw1OjI2ODk6OzQ2ODUzPjc0OjU0PDU6PzU6QDdAOjk5PTZCOj01 +ODg8Ojc1PDQ4OzQ6Pjg0OzQzOjY6PzQ9Pjk8Qzg8QDc7PDw7QDk9Ojs4PzY+Pjs5PTk7PT08 +QjNEPEM4QjVHR0KfwGz6/On9/fP///////////////////z+//T4//T///3u/eX0++P8//D7 +//fy/+j6//T2/vXv++X9//j///v2/PLx+Or0//jp9Nrq6uLy+efy++31///7//f28evt++73 +//Xu//D+//nv/+f1/er2/+/s++fq++P0/u/z/+/9/Pr2//D7//jw/+38//v///////v0//Tv +6OLo8eTo8+j+//PepK1GRTxxS0dTRzpBPT8/OzdKQDpiUD52R0JgSDpoRkBXQTRFPTgvOTU8 +QTZjTDlzTT12T0NwTUJxSDpNPTVFPTdFPDVEPDVfRjxZSDplPjpTQDVWOjo/QTQ/Ozg9Py9e +Qj9iRjZlRD1fQzVPPTo0OTE2OTFPRzhlTzxsRz5jSjxZQTlKOjlBMzQ5NzI6PDJIOTRIPTdP +PzxEQDRLNzguNjFBOjczPC5DOzg5OTM+PTYtOTU6PC4+OTRCOjhUOjlMPTZSOjpGOjU/OTI4 +OzVGOjdPQz1UPzpGOjk7Ni81Ozg4PDNlbEm4wY3OvaCEY1A/PDc5PDFGPjtaPjdZQDdPQTU7 +PTU5ODM+PTBSPjZTQDRYQDlKPDg+OjU5OjJCQTVnSjdhSzhcQThgRjpVQjg+OjE8PTVSQTVb +QzZPOjdMOTY9Ozk5OjI6OzRKPzRcRz5RRjFTPjk/Py82NTIvOS8+OTNIPDtMOzZLQThJQDU8 +PTY2NS8yPTk1PC46PDQ7PDE+OTk7ODczNjc7PDZGQTZVQjtFQjc+Nj04NjM+NjU2PDFIPDtf +RzdrRT5hQTlnRD5TQTI/PDU4PTtUPzhdQTVWOzhRQDY9Pjc2ODA4PzNBQzZDPDVORTRlSDlM +PDdCOjtRSDZpR0BgRDZmQT1WQTJENjdHPTJZREJVQzFUQj1GPDc3OzpJTENPPj09ODo8PjVQ +QjlaRjhaQTdQPjc7OTE8QDdLQjhZPzlRQjJVPTs6OzM7PTk8RDRPPzxFQDdNPTc2OzE4PDYu +QDRGQDpBPjU3QTQ8PTU0PDI6OTgzPjMxOzc3OzY3Ojk6PDg7OzM4PDUzQDVAPTsyPDQ7RTxG +SDlhUkZmVz1+YUuJbk2adl2phmCqhWS5h2G8kmO+kGfDnmzNpHvRqnvZs4HdtIPfvpDfvoDk +xZTuzpnrxpvr0J7r1qD11KPt2aH827D15bf95Ljx1qLwyZz3y6313qr65Lj83qr85LP73rP8 +3ab42aX506ntyZHsx43nxILswI7qv4npv5HouoTlu4ngsnzgr3rYonLOk2jFkmzMm17LkmfJ +lGTGlGfEiWW+hmCwdVuedVKWYk2EWkNXSEFKRzhKRj1LRThKSkVKRDxMSz9aTEFsUkdfSEBc +RT1fQzw8PzxEQzw/PDxBQDZCRD1HSUFMT0FaYEZpa01pa09vaFVpak91blVub1NyaFJkZlBW +SUUzPTM9Pjw3PDM6PDg6Qjk5OzM9Pjc6PTI3PjY2OTY0Ojk1PDI0OzUyPDU7PzY1QjkzPjY2 +Ojk3QDU/OjoxPi5DOjkuPTI8OTUwPDM9QDExPjY6OTsxOzg4PTk7Ojk8PTY9Pjs5OjY4Nzs2 +RTk3ODY0NjQ7OzE1PzIyOjI1Pzg9OzBAPTo4OjE4Pjo9QjZAQ0A9Pjk4Pj02Pjg8PDhDQDw6 +QThAQD5CSEa01IP///r///z+//74//Hy/+j9//b///7///b///////////////j///////v8 +//jy+vPr8uH5//X5/vTv/eby/Ovo8ufU5tDU5sbZ79nV4MvM28ft/+30//X2+vHx9+nv9Obr +9ev2//X39ezq++v1/vj+//f9+/bx+u3z//rx/+jy9+zm9t/4/fX7//L3//Hw9+rx8+H48/L5 +//v///vy9+jckphJSj5xS0hgQzpBOz9BS0NhUUlmSUFoSD5nRkJiST9gRD85PjM2ODw6QTVl +Tj92VDh5UkR4UT1vSEBQPzdJOzZFNjtCOjtZQD1fPjhcQjtUPDVTPjg+QDQ/OzVBOzJYRTdp +Qz5gRDhkQj1FPzk/ODovOjNSRDNlTD5tST1jQzxYQzdMOjg8OzI7Nzc8PDREOjRGQDVTQDpO +OjlFPDY5NTQzNjI8PTc5PzQ/Ozc1OTA4OjQ0OC46PDlANjNSQDpMQDZQPz1HOjc1OzVBPDJF +QDJSPz1KPjZHOzQ4Ni87Nzg1PDRhY0G/wYrOu5p8YFdEOTY6ODdCOzVYRTVYQDlLOTU4Ojg2 +NTM8ODRUQzRYQDdRQzVNNTo3OjE6NzZDRTRlSD1fRTlbQzddRDdUPzk+ODJDNDVKQTliQjJT +QTtFODM6ODo3NjQ6OjtKQjRZQzxSPTdQQjtKOzw6NTsyOjU3OC9JOzxFODZIOz08OjY8NTkt +NjM3NTIxODI+OTk1NzFANzkxPDU5NTg4MjdJPjtTPThGPTY6NzM4Ozk3ODcxOTRIOzRkRT1i +RDpjSjxnRzVVQT0+OjVFOTlRQDVbQDhRPzVSPT09NTY7PTY8OzFDQ0JDQzpTRjVfSjpIPTk7 +ODZORjVpRztmQjxlSjVZQj1CPDlHPTdWSDtWQztNOzhIPDwsOTREQj8/PDdFOz45QTVSQjdg +RT1bQjlNPDs7ODY5OjtIPzdZQTlRQDpMOzo1QDMxNjRFPDNKPDZNPzdKOzc/NTc0OzQ8PTw8 +PTRCPD88OzI9Ozs6Ozg3PTo7QjcyPDw2PDcuPDQ2PDk4PDU8PDs2QDQ6Nj0zQDM2QzxMTUFe +TkFxVkd7ZEmDb0yZdVmpgVmuiV61jGe8kmq8mme/lm3KqHfTpIHcsYHet4DewIzmvY/iypfs +zJfqzp7szZn02KLxzZrt2KT33rbz4bT13bn01p/43bXsx6bz4K773Lv54Kr53rT626vy2av4 +1qfzzJn1xo7htYLnv4/muILku4XhwH/ou4bav4LfrH7SrXTZn23MomXRm3DEk2bHjme6kWDK +kmfAkWHCiV6zf1igc1KZc02MXkdURzpLREBGRTxHST5GQzpKRj1KSj5cSEJSSzhmSURjTDly +TERLQTU+PT46PDc/SUBUTURRTUJVTEJdXkZoaVRwblNwbFVtZlFsaVBobVRnaFFsYFFMRUE+ +ODctOjY8OjYzOjBAOjc0OzY/PDkzQDM4QDk1PTY3OTY6ODc2OTUyNjQ0OTY0Ozk0Pzg8OTg6 +PjU7ODY0ODg5Ojg3PDo1PjQ1PT4yODQ7Oj4wPjQzOj0yOTo6PDw6QTM7QztAOzgzOjY2OTY4 +Pjk4ODg7Ojo5Njk0OTQ/OzZBOTRBPjg5PTg2PDo6PDg5OTU7Oj04PTY2PD05PDdDQjw/QD0+ +QTxCRT+w2YDz//Hz+ej6//D///7///////////////3////7//f9//z1/+33/u/s/+j5//D/ +///////8//rv++js+ufm9d/z+/Hk7t/e8NPs7ePx7ef07unu+O/r/e70/e/y/O/0/fj0++zl +9ODx++vr+Ojx9Ofs/uz9//79//Ht+PP9/v7//f31+/f8//f///b0/O39//3///39+/P5//P6 +/fbl7tvSh5FMTEFxRkFaSzhFQjlRR0VHQDlrREFnR0RqRjxlSDtlRDY/PzE2OzI8QzdmTTl7 +Uj90VTl7TztpTTpPPzk/PjBCPjVDPTVaQDdkRTlZRDdcQTdRPjhGQD8+OzVIPTdYSzVgQjtk +QzhcRjtQPTE3NzM2PTVGRTZmSDhpTjZlRztUQTdOPzg2OjA/OjQ3OjBAPDVLQDNTPTdMQTJH +PTY7OTA4NDE4OzVFPTc8PjI0PTM2ODM7ODI8Pi9GOzZNPjVWPDZMPDRKPzk5OS9BPDVJRTJa +QjpMQDVJPDY0OzI9OjQ3OzdiZUW7wojOvJx7YVNDPzg/OjRDPjZXRjtZQzVOQDQ/PDQ1PTFA +PDNTQTZZQzhORDNNPjkyNy09NzY/PTVqRzxdRTllRzxbSDRaQDk5ODJBPDdQRDRbRjdYRTVE +QTc6OjM1NzQ3PC1NQDtYRTZUQTpTQDhEQDg1ODQ3Mzg0OTFGPzhDPTBJOzo+Oi88Ozg0ODA0 +Ojk7PzY5OjZAOTY5PjY6OjU0PDU2OTNHPzdURTpFQjk8Ozc6OTU1OzU8OjlERDVnRkBjRzpp +Rj1pRDlYRDw5OjVEPjtWQTlaQTNURTNSQDNCPTkyOjM/QzQ/RTdHPz5RRTliRz1IPjhCQDNT +SDVoSTpoSz9mSTVdQzpCPjhHQzhWQzZURDpQPzNFPzw7Oy9AQDhLQTo+OjREQjhNRTVmRT1d +RjRTPzs+OzI/OjxOQDhZQTpQRDVPPz1APDY2OTRIPjZPQThRRDVHQTk/ODUxOTQ7PzQ8OTdA +RDQ8RTQ4PS48PjcuPTQ5NT4yPzM4OTctPDA6QTk3OzA4QTk1Oy81RDQyPzA+QDlLSTVeUUNm +V0B9XEt5ZEeZflWbfVuqhWa3km+0j2e9l27KnnvKpnXNqnnUsoPdu4TgvYvjwJDkx4zqy5Ps +05jw16jx2aLx2J/t4bD746776b/03bj12q7z0qP40Kr44KT35LD036ry2qj02qjw1J/y06Xq +yZPsxZLivozlv4Xdr3fYrn/RrXfTrHzSrXDcs4DXrXXSpHTUmWvLmWnNkmK8hmHDkGXKlGS/ +imq+jmS3iFioc0+bcVCZZE9bTEBVRTw8PzhKQzxCRDlKPzo+RzpdSjtfTkN6T0KHYEuJZUps +R0k8PjhIRjtRTkBeVElVUkFQTT1dZUdtblJzblpwbFVubVRybFRsa1RyZ1JnZE9RQj03ODk4 +OjQ6PTg5PjE3OTc0PTYyPDU9PjI0PTE/OzUwPjU5Ojg0PDIzOzM1Pi40OTU3PDM5OzQ6OjY4 +OjYzOzQ2OzY2PTk5OzY0PTQ0PTc2QDQxOzM2PjM6Ojs6QTZAPDtAPzZAOTkyQTQ6Nzc1Oy85 +OjMyOi8+PzQ1PTQ/PTM/QTNGPjc3Nzg7Pjw5QDc8OzM7Qjw6QTU3Qjc8QDo8QjU+Qjs7QDZF +TUSv5Y7+//T///v////////////0/+79//P///j///r7//f8//7+/+////////////77//P1 +//Pw/+vo9eTr+OLp+N/n8+Th9d7k/9vp++Th8dza69n2/Orp8uDq/Pb7//Xz/u37/vv///35 +//L9//79//nv9eLi69jq8+j9/vb7//T5//L2//jq/+f5+vH6/fLz/u/u/u3x9ezu+/D4//D8 +9evbhYpSSkNwSjlaQjpDOzg/PDtKRTtiSD5sRD9iSDhnSEBZRDhPOzUzOzFHQTdoUjuCUjx7 +Tjt6Uj1uRzpJPzVKPDZBPi9JPzdUQTBkPjpVPTZdOTpNPjRLPTo8OzRAOzJcRDdaRDRjQjpe +QztRPzYyNzU8OTdGQDZhST5tSzliRzhdPzVQPDY/OTQ/OjNDOzVBPTFQNzZLOzhRQDpIPDI3 +OTU3OzE+PDc+OzJBPzU3OzQ8OTI0OjA9OTZGOjdOPjpSPTFPQTZJPzA8PDE4OjBRPTpWQjhT +QzlDPjY+Ozc2Ny4+OThZY0LIwI7IuZp/XFc7PjRBOzJHPzJXQTdVQzdOPzY7Ozc5PC0/OjVR +QjVXPzhRPzhDPjY7OjY4ODRJPzteRzdnQzpZSDVjRT1RRTZEOTg7OzJYPjRbRjZZQDhFPDhA +ODc0OzM3PDZKQThXQjtTQjVSPjhFOzQwMzM0Oi89OTdFOzNLOzlFPSxFOTk8OzA5OjYzNy4+ +PDg4Oiw/Pjo9Py47Ozk0ODA/ODlLQTpXQzdMQjo6OzI8OzM6PTY3OThLQzdmRjlpRjZlRzhr +QzpUPzVFOzs/OS9cQzpbQDVeRT1OQTVGOjc1PDE/PDZFRTtHQjVaQzpiRTZPQzY8PDRPQDhn +SDlwRj5sRzpfRTlAOzlIQTtYRDpVQzRVQTtFOzQ6PTY+PTVHOjk+OzNBQkBNQjNgRTlhQThL +QTRBODc4PzFPQzhWRTxcQzpRQzdBPDQ3OzBDOzpTQTRPPjVMQjE6PTc4OTg0PDRFQjg/OzdA +PjE7QDw7PzQ7QDo6PTA0PDI6QDc2OzM1PDc6QDc3OzI2PjgzPTA5OTc2QC9NTDxZVD1uVU13 +XEGAbUuRd1ONZE2ji2G4kW23kmq+l27CnXDJrXjStIDZsYLduozduYfdvYrlxZrmypbszJ7k +06Dz2Knx0ZPz16Py5ar35bf75Lj63ary3q36zK703Knz26Hz16ns0aTmzp/px5jqzpPq0pjj +xo7gtILOr37GmnG9nWW6lmKkgVilg1yumlvMqXHOpGbSpHLImmPNm2/DkmfFlGbLnWXJkGPC +jWG9jV29hF+sfFObZ1FdSj5IRjtJQDg8SDlISTxHSDtaTz5qUj52XEaPak2xeFane1mRVEk0 +PzdYUj9fV0haV09YVEZWT0NeYkpsb1Vua1dmaFVtbVNta1V0a1JoZ0xnYk1PQj05PTQ1PDYw +OzM5Pzk9PDE3PjY2OzA4Ozk8ODU1OzY7PDcuPi45QzY2ODY7PzU1PTQ3PTYzOzNBPzgwOTE4 +PDM2PDQ2QDU5RDM3QDIzNzU5Pjc1PDQ1PDNCOzs9PjdCOzE+PTlEPDk9PTc5PDE+Ozk4QTZC +OjY2OC84PTg4QDVJQDc+RDhAOTw1PTZAOjg5PzdBQDg3QTZAPzk9PTtAPjc8Pj5BQjZGSkiz +4pD4/+3////5//X1+uf9//b///j////9//v4//D///7v/+34/+j1/+vz/+bt/uf0++vj8N7s +9d36/+34/+71/urn8+Xa7NTY7NDS3czV38/S38v0+u/u/evx/PD5//Tw/+nt++Xx/+zv+ebs +++zx/vX9//3////////u/+jt/Ovr//H///v7+fDz/Oz4//P79+zk7drn6t7u9OLt/urs8tzO +gIlLSz1zTD9OQjdQQjxCQDpNQzhkSjxmTD5mPzpsSDxhRTxKOzYvOzJDPjRoTz19WD15UjuA +UkBmSThSPjhCQDVMPzk8Qy5WQTxcQTJcRDpbRjNUPjZGQz1BPDdCPTZZSDllSDphRjtgQztM +PTY3OTQ0PDNHQDhjTDxrTzptSDtaQDhTQD01OzRDPDk6OzJNPDdEOzVQPjtMQjpHPjU4OzQ0 +PS87OTQ6PTI/QTA8QTY8PTc3PDU/NTRCPDJVQDZNPzhRPzZJPDo8OzE/OjdNPzNXRT5RQi9G +Pzs3PDE4PDY3OzNZX0C/woPHuJl7YFc+PjU/PTZBPDRcQz1ZRTVPOTk6OTQ3OTQ9OzVPPzRW +RThRQDxHPTY4OjI6OTVGQTZmSDxlRzljRTVkSTpWQzhBODo/PDBXPzteSDhWQTdEPTM/OTQ0 +NzM/PDZMQTdcRDlSQjdUOzU/Pzw3NzYzPzQ8PDJFOzZKPTVHQDtBOTA3Ojc7OzgzOi9AOTc9 +PDA+OjRDPTFCOzs0PC45OzhEQzRdRj1EQjFBOzszPDU9Ojg5OzRNQjliSDppRzdrRjVmRDtW +RDk/OjlAPzhZQjpcRjRZQztRPzZAOjk0PDE6PzpBRDZMQzxSSzViSD1OQTNHQDlMQzRmRj5p +RjVxTEJbQzJAPDtGPDlYRjdVQjdTRThFOzo6OjVBQjlHOzQ9PjZDPjhMQTNlTDxfQzRUPjs2 +OjBFPjtOQzRjSjxVQzlXQTg9OTc9PjVJPzlORTRRQzpHQDVAOjU4PjM5QTQ9RDVCOjc8Qjg7 +PzU+PzgxPDU4OzsvOzM0PDozQTA7Oz82RDA3Pjw3Oys4Ozg1Oiw1RTdNRkZcSUZnVUZ1YkqF +bU+PdVOXb1CqmF6ximusimCzknTFpG/GqnrUu4PRt5Lfu4bct4zdvIPbv5Djxovmz5ft1p3u +2qTs1p/32Z344K/567344LP316r12qr1zqzt0prrxZnhxZPZvoTHt3a6pXW0qmq5qmupmmKl +m2GfhluffFefe12VeU+Mc1OGZ0mFaEqQbkmcglK2lF/BmWHDnmW8j2K8kWPElmXJj2K+lGK7 +iWGvhVaqdFOMYEVjSUFEQjZEOTlDRDtDRDxZTj2CYkeQakaYbkqrhVvMnHfJlHG0YVtAPTdJ +UUNfYElpY01bXkdcU0hiaUp0bllta1NzbFxsb1Vvb1RqbU1vaFFnXVFNQz43Ozk3PDg1PjM5 +Qjg6QTY4PjU3PDY+PDY8PzI8PjkyOjE7ODo3OzFCPTk1PjJAQTg0QDBBPTc3PDA8OzE8OjY4 +QjU+PjU8PjI6Pzo3PzY7PDQxQDQ6PTY1OTk+QDU+PzdFPzdEPzk4PDA8Pzg5PTJARj48PDM5 +Pz03PC48QTpMRTlBQUA9PTc4PzVAQDg5Qjc9QjkyPjQ8PjY5RTZCRjtDRzpBR0BGR0S65o39 +//j///z///////////////f///z///////z7//b7//j7/vD///j////9//z8//f///z7//fy +/u32/+3w/u7k8+Ll/ODh+dPs/PDe6Njd6Nb7//X0//L8//ft/e34/vHt9eb+/Pz///v79env +7ujj8+T0/u3y++n4/fT7+/Lz9uv5/vD7//b1/+7z/vD///j4//X///79+/T46Ofp8ODfeIlJ +RjxzR0ROQzNOQT9AQDJHQjpjSTpuSTxqQDtlRD1rQDtOPTQ+OTNCRjBuUEF4VTx5UTuBVDxy +SjdTPDJEOjJRPDY6QDVXQTtdQTpjQjVZQjpfQjRKPz1CQDhEPjpXRDpoQztiRTRhPzlKPzI7 +NjY1OSxGPDVhTDRtSjtoRDpiRTRQPjlFODQ9OTY+OTFFOjdPPTBLPTlMQDdEOzVCOjM1OjE8 +OTE9PzNGPjI2Oi89OjU2Oy1CNjNLPTFSPDVPOzFTPTpGOTRANzQ/OzZPQDNYQDpXPzhHOjg9 +NTU5OjA4ODZcXT66uYbHtpl5WlI9PzFDOTVAQDRZQjlVRTJUPTY5ODE9ODI7PDBRQTZVSDZY +QDdFOTVAOTY7PTJGPjNiTT9hRTZlSDhnSThWQTVCOTVDOjVVPzpkSjZcQTlIPTc/Nzo3OzNF +NjtNRDZiQz1VQzZXPj49OzU9PDcyNS1DPDhMPzRLPTdIOjNEOjg9PjU6OTM7MzM+ODk+ODQ/ +OTo/OjA9ODk2Ni8/OTpLQDFdSj9HQDE/OT4zPS89ODg5Oy5HPTpgRjZlQjhuRDpqQzxVPThA +OTZGPTZYQzlgRzleQzlXPTlGOjk3NzJAOzhBQTNJQDlYQzpoSEBMPTJHPzZMQzVrRzxnRzVy +SDpbQTVEOzlFPjpYQjhZQzdWQzdLPTs3OTREQEBGPzY+ODc9PjlKRjdkSD1kRjdQPDo9PTBE +PTxPQDZgRDtYQjZXQD9EPTc5PjVEPDNWRThWPjdIPjNBODs5PDQ+PDFDPzRLQT5ESDFCQD03 +PjI2ODw9Ozg1OTg9PS82Pjk9PTY5RTlDRDk8PTw+OzY0Ozg8QTlMSz1cSD5nWUhwXkaEbE2M +b02Zelmbg1qSdlOXe1aniGaynnbFsHrNtHbNsH7EqHHRr4XLr3TMqn/SuoHcwYzmz5nrz5Tt +0ZDxzJ7p0J3+3Lf44LT21qPs2qjsv57eyofVrnyxkWKjfGCCaU16W09oWkRqVkptWUV2YUaD +Zkp9YUZ7ZUt0WUaJZEiRa06Obk6WaEuUa0uSak6bc1GphVq9jmXAjmLDm2fGjmPBkma+jWOp +elSkdVaJX0RlSUZNPzdIRD5IST5TSjuCXkGgc07JiGG8fFqzj1vMp225gWOZZ1FHPz1NTT5l +YUpjXkpbWkVpYE1ncVF3cVRya1hzblNsalJ0alRsblN0bVVoXk5LQD81PTc4NjFBOzY+PzlA +Ozc4OzM9PTI7PTc8PzY9Ojk4OzU3PDc5PTNAOTk7OS44PjdCPjFDQDtBQDZAPjs4OzM9OjU/ +PTc6PDg4OTc0PTQ4Njc4ODg9Nzo1OTY/OThBPjJKPzlFPDw7OTg8PDM/OTZBPDw/PTo5Nzo2 +QDhBPTZHQjxGQTo9PDk9OzY+Pzk/OzZAQTo8OTRBQDw+QjhISDw8PztCRj9CSD7C7pb4//P0 +9+r3/+X///r///T///v1//T0/uj2/+7+//T2//Dz+uD///v0+/D2/+3+///x++31++jy++z2 ++Ovm79/n8eDc8djb7c3m8eHj79Xk7tzy/+3z/+73/u/4//T6//P9//v0++/2/vL4//z////7 +/+vt8+T+/vz///z///////Pv/+fv/evt9+js/PD5/+z4//Dt7+f1/+7///r///fXd31RST5w +R0BWRjxGRThGOjhDQzRrSD1qSztoRz1iRDRpPz1NQjA/PDY+Qy1tVEB1UjN9VT99UUB1RjdX +QTtGQDhJPDNCQDNVSDdfRDhcQjdfRThTQjhIRDY6PDFKPjFZRjRmST1iSDVlRTVLPzNBOTEu +PDJGQTVfSzZuSzhqRjlfRThNPzY/OzJBOjU+OjBJOTRMPzNQPTVKOzJGOy88Ojc5OTE2PThB +QDJDQztAQDBBPTk/OTE/OjVHPS9VPDtVQDRSRDdMOzc7PTc8QDNLQDVYRDlNQTJJQjczOy8z +OzIzOzNTXT21uX3It5t3XlI9PTY+OTNDPTJYQzhdQThNQDY7QjU2PS07PjVLQjlWQjZMRDRK +Pzk4OTE6OjVHQTJkTDxeRzplRDViSTZaPjI+PjJJRTZXQzdnSjdYQThHPjU7PDg3OC04QDpN +QzZYQzdWPzZQQDVGQTo2OC05ODU2QS5OPj1KPzROQDlAQDNAPTcyPjE/NDk1PTFBNTU7OjBD +QTo2OzI2OzE5OS9DQjpTSDNKPDY+OzQ5PTA7NzE/Pj1IRDdiRThlSTduRjxoRTdVQTVCPytM +PjxZRjFjRT9cRjBYQDs7OzQ4PTw8QTBFQjpLRDhfTD1pRD1NQTNBOjBQRDppRzttSDhoRzhb +QzVCOTZFQDdSQjNdQz9PPzVLPjs0ODBKRTdDQDo+PDU6OjlMQTlfSDliRDRPQDU/PjZBODZS +QzdgQjlaRDlQPzg7PDQzOzVDRDVXSThUQj5JQDQ+Ozo1QS8/PTc9QyxFQzxBQDFBPj88QDE3 +PjM7PzgyPjU7OTg0RDA2QzU9QDNAPzg0PjQvNjo3Qyw2QzlPSTliT0FpVEVuZUuIaEuGb1B+ +YkVuWUdxWkl6aEuMdU+Ke12DdFGMfFiAaE18Zk59c0+KfValjmW8oXDKu3rbxIrdw4XlxIvs +zIboypXx25jz3azs0pftw5ThsInTonSvgWGpdFWTa1F1VEZrTz5tUUBiVkF0XEl0WUdsU0Nl +WUaKX02NakyWaVmSak+Ra1SRbk2cdFmlflOhdVWaeFCziVqzh1fBl2DFk2DClGC6iliyhlav +gFSWYUdiUD1RRz5JRTliT0CHYkK8hl7PnmjXonXTmGa4hmDGomrKk3qwZ1hQQD9LUz5hYk1k +Zk1pZktzalJxcFN0bFlubVhwcVd0blhvbVJ0blBybU9oXU9IQzs9NzMwQDJAOzc5QDRJPTk0 +QDQ8PTUyPDBCOjM2OjM0PzM3OjM8PDM5Pjc6Ozk3PDk1PC9BQDZAQjNBPzo7QTk4PTNCPTg9 +PjU3PjE1OTE5PDgyPCw3Qzk6PDI/OjtBQTJMQDpFQT02PTY0QjU4PjI+Pjc4OzM7PDQ2OjRB +QjZJQjlEQzs7PzY4OTI7PjQ9PzI9Qjo/QTg/P0M8QDg/QTxBQztGQz5IUUjE8ZT5/+v+//b/ +///7//P6/+7///n///////z///r////9//H9//b8//j2/ef3+e7w7uX0/On6//L3/+33//fv ++OT19+7y/PDq+tvp8+Dn+N3m9ODm9unr9+rr/uv4/evs/On+//z///vx/eHq/+fr/vX///bt +9efw/u/8//L0//L+//j+/Pr4/vT5//Py9+jo/ej+//bu8uT8//v3+ezt8uTWc3ZSSkVtTDdX +RUBIPjNEQTtEQjdhSTtwRj9hSTVnSD9kRjhSPzo6OTRCQzhuUzp3UUF2VD53WD95TDpJPzZK +QDk7PTFFPDZPRDVlRDVYRDVeQTdRQzdFQTU+ODU/PDNdQz5hRz1jQztbQjJOPTQyOS0yNjE3 +QjZaSDpoSjhmRzVcRjZLQDQ8OjU6OTE3PDRCPTNJQzZSQTRDPDVDPDA5PTI6OTU4PDE/PDU4 +Py8/PDU4PTM9OTQzPzFEOjVTQjZWPjVMPTNGPjg+NTY/OThLPTZWRTdXQjhDQjc4OzEuPDE3 +PDFJVjuts3rKtpV4VUxFOjg3OjBEPzVTRTRdRDxLPjlBNzU3OjQ7OjNGRzdaQjxPQTdKPDY+ +RDU4ODJGRDxbSDNhPzpiRjZqSDhaQThBPjRGOzhbRDhmRD5VQzdHPDg3PDE3Nzc5Pi5VQzlT +SjdZQz1PQThJPDwuODM1ODQ6PDFKPzhNOzlNPjJFPjc6PjE0OTE2Ojc3NzE6OzM+PDU/Pjg1 +OzY1OTg0OjJIPTpSRzVKQz41PDI6ODU7Oy0+OjtIRDRcRD9pRzpqSjpqRD1TQDpCPTk+QDRY +RjxeRDZdQTVZQTo9Ojg2OTM3PTBCQjtAQjRjSj1jRzxQQDZBPTJTQDldRzpwRDxpRztXQjVB +PDVAQzVSQjxWQzdSPzhDOzc7OjhERjtLQDY/PDc8OzFJQzteRDtaRTtLPTFBPDs8PTFPSUNd +QzJcST9JQTY9Pjw7OzRBRThVRjlTQDFJPzc5PS07PTY1PjA+Ozo/QDVEQDs+Qjc3ODg9PTc1 +QDs4PTQxODQ0PzYvOzU7PTUwQTw5PTczPTg3QS84RzlMUD5hUEtgTT5xWkZvYUdtXkJYTD1f +TUFeTj5xU0hhVzxkT0dbUD9ZS0ZZUEJkVk5wWz51ZE+DbVGhg128onbUsHzcvYfis4viwo3k +xZHizI/jwY/gw4/mv5XRrILGnXKziGKpc2STZEh9XE11YUd0VEVtTkiAY0qIYUyVZ1Ste2K9 +lHbKo4XKp4LOnHvElmjDjHC8kmq/km3AlnC7lmu7hmC3lF3Bjmu3k17Ekmm5h1i2gVqwfVGo +bVaQX0V5V0Z9WUOcd0+1nWLfxI/qu4/esX7eoHS7g1fIrHPXmoC6Z2hORT1BSzxdXUdrblN0 +cFhqb1R5b1poclR6bVhrbFNybVdub1ZwalFuZ09oYk1DQD4uOjM2OzQzQDI8PjU6QDM4QTQw +OzI+QDM/PDU7PTA3PTozPTI9Pjo9PTM+PTs1PDE5PjpEPS9DQDg5PDY1QDI9OjYzPzQ/PDU0 +PjM2ODUvPTQ0PjUyPTE2PzU5PDc+PDZKQjtCPDo3PDc7OjQ6PDk9Pzk/OjUxOjA7OzU+QjdH +QDlCQT08PzU7PTk7RTVAPzk2OjU+Pzk1PTZEQzw+RzlEPUE6RDlHSkTE8pj9//j///v///7/ +//X8//T5//T6/+37//X///b1/+r4/+/z/en3/uf7//D7//L6//X///nw++zx/Ozn+eTt+ebo ++Obm+eXX9dLk79zc7tXd69b5//Pw++78/vzx9+fq9Ojq9ubp99rj9uT7/fL4+fD3/fH+//v/ +///x9e7z+/D5/u37//j///L2/PX5/+74/Pb1/fP68vTn69/1+O7z8ObPbXJRSEFsQ0BYPTtL +PTxFOT9FQzlfST11Rj5jQzpmQzxlQjlXQDo7OzJCPjpqSzuCU0N3UTyBUkN4TDpWPz1EOjVM +Oz1EODdVPTxgPjheQztjRDpbRDhKPTs/NTVEOTVePTlkRztmRTdePDhUOzc0NjQ4Ojc7PTVf +RD5nSzl2RD1gPjpTPjo7OjM/OTU7PTVEPjZNPjlKOjhNPjw+PDU/Nzg1OjY5OjJEPDY+PTU4 +PDU7OTE9OTY5NjJINzhRPTFaOjlMPS9IODs5NzE/OTpNPzNUQztVPjlEOzlANTUzOjI8NDlO +VDiysXXHs4p6U1JAPTRCNjdFPThbQTpaQThSOjQ9Ozg8Njc8OzhIPTpXPTtURTpKOjg6NzY5 +OC9DPDdfSjhlQEBoSTZpRzpUQTdFPDVBPjRYQzVkSTxcQzlCNjZBOTk2Oz0+NzNPPz5gQjxU +QTtUPjhIOT85NzM6ODg7OjZPOjRPPjxKPjFFNzs7PTc6Nzs2OTQ/Mj48NzZGOTw8OjE3ODgw +Ny4+NztAPjRVPDlEOzRBOz05OjQ6PDg4OjZEOjlePz1lQzpvSD5qRTxUQDtIOjpEPTdXQz5d +PTdfQTlWPDFEOTs1OTA9Oz0+PjBLPTleSTZoQkFRPjVHPT1LQDhiQThrRDlqRTxcPTo+OzQ/ +PDVTQTlSPDZXQDtGPDY4NzhBQjZHPTs3PDM9ODo+OTRYQjhXOzlTQT07OTVCOjxRQz9fQTpX +RjxRPjtCNjw5OjRIPTxXPzpWQjhLPTlAODc3OzMxPjFCNTtCOjRGPzxAQTBAOkM2OzI+OT82 +Ny44OT41OTQ5Ozo7PTc4QTw2Pjk0Ozc9QDc6RDdQTUNiUUBiTkFiUz1TRUdVRjxZT0dgTkZX +TUFjT0BSTUZfTkVVRUJRRjxGSUBiTENiVExyXEx+b1Wbf16mj2vApXjbuYrUsnrZt33izJHu +yJrixInnw5Tju4nbpH/An3DJmnG+jmjEk3K1fWOxfmK3gmK6kWvGnXPNpnnXtYzYp4PRp4TT +qILSroDYtIbUr4PRpHzNpHnTpn7HonPGnW7Cl2vLlG+yh1/Bkme/j2DDiWa3h17BhVqze1SV +cVGMZkegelG1jmG4gmLRq3DjwY3rv43nr4fOkWrCoW/UqYDEe3NGPj5IS0JpZkptZlNpb1Jx +cV51b1Zxbl1vbVlwb1hya1VualhvaVZraVJpW05HPz48Nzk8OzMyOzc8QDk8PTc6OTs3OTZD +Pjk6QDQ9ODs0PTk9OTo0PjZHOzg6PTo7OjQ7PDk/QjhIOz07Ozc6Njg5PDZBPDc6PjY6NzUz +OTQ6ODcyPjY3OjU7Ozo8QTBGOz1MPThCPT45OTJAODw8PzQ+Oj06OTg0NzM6OTk+QDhIQT5C +QDo8PDo9PDw8Qj43Ozg9PDw1QzY8PTs6PEBBPjtBQD8+QD9OTUjB6ZXz/+r9//by/vD+//T/ +///////////////9//T+//n9//j6/+v////9/fnw9er3++/t+uX9//P2/fH0/+r0//Hx9u3d +69/a6c7j7dvm8uDb4tj7++fs/ez0+Ozz/fLx/fz////7+e/6/vT///71//P8//b4/+7p+eD8 +/vv5//H+//r7//X///z////////5//P7//P4/+/9//fx++zr69zKb3JXRz1wSENXQjlLQTlN +PTlEQTdmST9yRT1qRTxpSjpuSD1XPThCPDk+QjRtUUB6VDqCTkB/VT94S0JVQjtCOjVFPjZH +OzlSPjZZQTleQTdiQT5YQjRNODg+PjhHOThfQTxjSjthRzZlRz1IPTM8NzkwOTFGPDlVRzlv +ST5nRTdiRDxNPDREOTc6NzM/OTZLOzdNPTZSPDlKOjRHPDM7NTM0NTI9PDY8OzVBPDI3OjA/ +Ojk9ODJBOTI4OjFXPTdMOzNVOThDOTRDOTg5OTdTQDpXPjhTPjdGOTY7PTM7Mzg3OTRRUDy1 +s3nHtJR6V08+PTQ9PjZCPDNVQjxeQjVVPT0/NzQ+NDs7OTFLQDpbPTRTPjpEPDQ8PDk8NDBB +PzZeRjdZQjRqQDxmRjpQQzk+OzRGODhZQzpqRTlYQzdIOzU9ODo2OTBFNTdUPTdfQDxVQDxU +RDhCPDY6OjctNTM+OTRIOzdKPzZPPTpCPDU+Ojg4ODQ8OTQ4Ny1CNzU+OzREOjQ4NjU9NjY6 +OTpCPDNSPztLPDQ6Nzg/PTY4Ojo8OTNBPzZfQDxmSTpwRDxoRzxZOjg9OzRAPDJSQzVdQD1c +QjJaQTg8PTA4ODg3PDNFPDpDQDRgRz1kRj5TPjtLPDNTPTtmPjlpSTlsQjhYQTU+PzJCPTlN +QTVaPDhTQDhPOjo2OTBEQDs/ODQ9NTY0PCtFPTxRQTRWQT5NPS9FOjw9OjRVQTxZQjtXQTRK +OzdAPjQxOTFIQjZYQjlWPjdFPDc8PzMzOTE5QTc+QjJMPzpHPDBGOTk1PDA3OTs2NzQ+Ozw2 +OzBAOzgzPjc2Ojg9QDg7Pjg1PDlAQDg/Pz9MTT5gVEZcSz9TSkFOST9MRz1fTERlVEaBY1eB +aFGNa1mEWkx6TU5pTkBoS0dpUz5rUkVuV0d9bVmae12tk2a2nmvHqXLQpG3Tr3jXu37iu4rk +tYnjtX3dqHPdpXfXn33QomzLoHrIjWW4kmLMn2zDm3LJoW2+oHG+pG/GpHLDp27NrXvKpnXJ +pnHCmWbKnmrNn3HQoHTPp3DRtXvYsX/VpHvIm2fDl2u9jV7FkGW+j2LAj120iVyvfU6idlOT +aEanflbCmXHTq37luIvsyprzzajsxJ3epYS/nWbVoHa0Z11EPzpETj1nY05sZUttcFZ1cVp1 +bFdxcFZ1cFlzblpycFhwa1hvbFNubVJpWUtIQDs6OTYzPDI8Nzg8PDNDODgwOTM/PDc2OzJD +OjkwOzM3OjY3NzU8OTlCOzM6ODo3PTQ7PTVIQD1IPTc7PTU0PzM8PDVBOjg8OzM6OzcxNjU+ +Ojg1PDQ7PDc0OjNAPDU+PDRTPDs6PTA9OTk1ODdDNzo0PDhBPTgzODY2OTQ/QThHQj1HQDo/ +OjVBOzY+Ozc+OzY+Pzg6PjQ/QDk8QDhEQTs8STNGQUNFTTrW9aP///////////j///v9//X9 +//f///7///3////////////z/uv2/+f9//T///f////7//n3//Hw+u/l8uHs9OHy/+zr/eje +9Nbq9ufh59ng7Nb7/u3w8+nq8t3c8eP0+evt/ev5/e79//H9//T9//z///P5+fDv+Ojz9OXu ++Of1/+3t/ej1/vH4//Tq9+Pr+eTr9+ju+OT0/O7x/+Hz7uHGcGxUSkFxRj5aRjlLRTpMRDZE +RDdfTD9yTUFrRzhnSzpuST5WPjtBOTdHQzdtSjx7VjqCVkB+VD1+Tj5dQjJIPTtFPDZHPjZM +RTVhQjxjRTpeQjZcQzdTRTlCODVHPjVdRTpmRDhgRDdkRDdSPDM5NDouOTBAOTVUSzVsTDxp +QzVjRjdIQTFEPDc9OS4+PDZIODJMPTJUQDlJQTZDNTY3OjM4ODI8OzM+QDM+PjQ8QDE+PTI5 +OjA+ODc9PTJWPzdORC9XPzk7PTNDOjY4OTBSQjdTQjRUQjZEPzJBPTY6NzMzOzBKWDmusHjK +tZh3WFJBPjQ+OTNFPzFUPzdlQzNXPzdDPiw9Ozk2OitMPj5aQzVXRTxJQjA6OTk8OS9BRDJk +SDpfSThnTTplRTlTRDQ6PzRLOzZfRjlpSj5ZQDhHOzg7PzY2NzJCPTZUQThhSjtaRDRYQDtJ +QTY4NzY2Ojc7Oy9JPThPQDVJPztHPjY+PDU3PC4+ODU5PjE9OzI/QTNGQDQ2Ozc6PjQ8OzdC +QjRXSTtMPjU9PTY/PjFAOzg9OzZDOztdQDZnRzlwSDpqRzpVQDdDQDJAOTdMQTFgRTpbRThZ +PTw/PzI5PTE4PzNDPThEQjVlSD1rSTpWQTtJPzRPPjVjQjNpRThvRj1YQzZCPTJCPDRQQDVa +PDtXRDVNOzo4OzI/Pzw/PDQ8ODc9QDdGPjpIQTJXQT9NPi9HOTs9PzZWPzxcRDRcRj9JPDg9 +Piw2PjNDQTNVPzVVRjZJPjM+Ozg1Oy48QjtDPjRMQTlFQTFGQDs2QjM7PDcwPi07QTc1PjE+ +Rjk8PDM4ODE3QTc3PTo7QTc3RDg1QDhMSztXU0dYSDpLSEBjTkRmWkOBZlKMdF6niG6ri2u0 +l3u3n3LAnXe8m2+/mHy6kWyte2qgaVaMdFyUdVOZfFihiV+tkWC6mWfFomfatovow5LqwJPk +uH3krX7dr3zOq3XLnWTClWzDlWy+lm/Cj2euimGyeViVeVGdb0+YeFeiemimfWWle1ylfVik +f1asiVq2lV/DoG3KqXLRrXrRuHfSqnrUqHK/i2bFmWTCh16/lFvHil+2gFWueFGWb02SaEmw +iVrdunzgwY7rxZDry5fuzZ3u0Z3pvprLlGzXon6qZltFPz09RTdVWEZqbk90cFNycVV0b1l4 +c1d4cFhvbFR1a1Z0bFlkcFVvbVdqXFBEQjs4PDYzPDE9QDg+QjRGPDo7PjQ+PTY4QjNGPjg7 +QTM6ODU1PzBDPTk9QDFBPDc1QDU5OjY+RTtGQzg8Pzk6Pjk9PzU5PTY9PDM4OzYwPjM4PDUz +OzQ7PDY2OzE/QDZEPTJSPTo8PzM/OD4xQDJHQDk7QTY8PjU2PTI8QDRDPTZCQjRBRTU/PDc9 +QDk5QDpDQTQ8QTw+PTY6PzpAQDJCRzpBRDxFQ0NMTz3J+KDy/+b6/uz///n///////v///v7 +/+////////////b2//P8/+z8//vz/+z6/+31+ezz++n1/+n4//P9//ft9Ozh79jd59jc8c/e +7Nfg8Nfc7NX6//3///7x/ev+//7////////79+3j9ubs/Ojy+e3x+uv9/fv///3x//X6++/p +9uDs8uz3/PPs8Or4+vr+/vv///vo7Or9//ru6eTp7+HIbm9PTEZtSj9fQz1RQTZEPzlCQDlf +RD1uSkJnSUFnRUJsPzdYPDpAOTdBQTVsTDl7UD2BVUJ+WEJ7TT1UQTdKPD1EPThCOz1JQTZj +QD9gPzhoRD5YRDlVQT1DOztJPDtgRztjTD5kSDtbRzZJPjY0PDQ1ODY/PDRMSThvTz9oSDhg +QDpJPzZCOjczNy5APjZAPDFQPjxGPTFMODk9OTI9PDU0OTA4PTJAPjk9Pzo0ODY4ODg9OzQ9 +ODY8PTFKPTVVNjlQPDtCPDU9Nzk4PzVQQj1PRThUPzk+OTVGPDctPzM5PDVCUTatrnLEspF2 +Vk87PTc4Ozg9PDROQjRiRDpSQThGQDY1ODY4PTRIQjpZRTdVQD1GPTI9PDw7Oi4/Pj5ZRTNi +Sz5qSzlnRj9PQTk+OThGPTJjSDlnRT9VRDtIPDY2QDc6ODU8PDpTQjlcRjtbQzlVRDdFPTs3 +Ozk1ODE8PDJHQzRNQzpKPjdEPzg7OzQ8Pjc7Ojg7PTM6OzQ3QDJAPjY3PTc3PDgzPDE/QjdO +RDtIPjs2PTg2PjMxPTE6PzQ9QjVVQDRnSD1vTDpmQz5RQDdDPTk8PDJHQzhZQjhZRTxSQTs8 +PjY6Nzk4OzVBQDhEQzhhSz5kRzdVQTxIQDROQDhdRjVtRT5rRThXQzk9PDU7PDNLPzlXPzpX +QTVAPTQ6OTk3PDQ5OC42ODU2QDI8PDZMPjVURTVIQjFCOjk8PzBTQz1ZSjZWQEFEPjM/Ojc1 +PC1DPThZQjNTOz5HPzo5PjE1Ojg1PzM+PjdIPjtDPjU7QDozPDk5PzYyRDc4PjkyOjU6Pzcz +NzA2ODwvOzE3PDkoOjRBOz0zPzNVTT9eUUNYRz9VUUhnZEl6alSLeleSfGKlh2umimmyl2mz +mHW6lmq5k2+0k223mXG8kmq0kWOlgGeccVqLb1l/a0+UeVugilS4omzYs3/h0JXmyI/mvoLh +sXzaoXXKmW3Aj2GvhWavkWC6jWmsblWLZk+XcVN3ZE96aUhvblB2d1Bwb017a0uMelWrjVyr +e16igFSolGG8pXDMpXLUrHjMpnDNnmvKmmu4jlu1ilu4k2C+jGe4gVioc1GXbE2ScUu1l2nk +xYrrxprux5vrxZnsy5vqz53lv5bEjmnNpHecXV5HQEA8Qz1QW0JlbU9zc1pxclV4cFpuclhz +cFhpcFJtcVhub1Vra1ZnbU9mVktEQj4zPjg8QDY0PDU7QTU7PDc2PzU3PjU9PjRDPzowQjM1 +PDcwPzE+Ozg4QjU+Pjk5PDU9OTU5QjNEPD02Pzg2Ozg0PTE/PDg3PTczPDY1PDk1OzUwPTI1 +PDUyOzQ6PTVCPTVNPzk5OzQ6QTkyPDQ9QDozPjQ+OTsvOy86PDozQDRLPjw7QTlGP0A0PjY/ +PDw/Pzg2QjU4Qzs3Ozk8RDpDSDxCQD5CSj5MUEPV/535/+7+//X////+///1//L+//z////9 +///+//j////9///9//P///r3//n4//H2+/L9//js+/Dy/+nq/+jr/+Hx/+zm++re79Lr9uLi ++N7e8Nrn+d7x+fL9//vp9ebq+ej0+uzs/On++vX59/Pp8uz9/vTx/+71//L6//v///7///n8 +/vL5//X8//n0//Xz/e77//by8OL4/uz4/+359OrQb25YRUNyRjliSD1NQDpKQTZEPzheRUB1 +SUFpRjlvRj5jSDhWQDg+ODVBPzdkUT16Uz2HVj+DVUN/SzpYRjJKQDhEOzVJOzlJQDdhQDdb +QDlrSTtgQjdWRDlDQTdHPDRhRDtkSDlrRD5aRjJUOzg3NzI5ODE8ODFTRDdpTDprTTphQzlK +PjFFPTI8Oi1COTVCPDBOPjhXQjdMPzpFOjc1PDQ4NzQ3PjVEPjc6QDU6PDY1OjM+ODk4OzQ5 +PDZOQTVTQDVLQTNJOzc+NzI8PDRIPjtXQTpLQTZJPzVEOTQ4PTc2OjVBTDioqW3CsY94VktB +OTc3PTFFNjRUPjFoRzlXQTVKNzo4PTJCOzRIPjheRTdUQDZLODY9OzJAODVBPjVfRTZmQjls +TT1qPzxSRDc8PTJMPDtgRDhqRT5UPzVMNzc4OjA6Njk6OTZZOzxYQzpaQDhSRjdUPTsxNjU5 +PDQ6OTNRPzxOQDVFQTVCOjc9Ojg2OjE3OzM/OjM6OzY6ODM/OTM7Oi88Ozg0NzBIPjtUQThJ +PkA2OzE9Ojc6OjBDPT5DOi9YQzpmRjVySz1oQjdNQDVEPjU7ODNLODpZQTldQzdVPjRAOTQ7 +ODQ6OzVHOzxFQzdnTEBjRzRZPzhJOzFTPzlfRDJyRT1uRTxcRjpBOjZAPTNMPzlTQjhWRDlD +OTA6OTM4PTc8PDg5OjY5PTQ7PDhDPTRVQDVSOzZGPjhBPC5XRz1dRjdbQz5JPzM7PDU6OjVG +QDVfQjZYQzpNPzs9Oi02PDY0OjFFPjtMQjdIQDc+QTc7Ozk4PTA2Ozg9ODk3PTg/OTc1OjQ5 +PzU2Qjg0OzMqQjs+PDE7QTROUUJrXktiTT5mVEVmYEaEbFWLdFeXclqVf1qjfVyVflmYgWGP +gFSOeVuQfVeSdFmKcU2OdFeTfFiggGGOaFaIYDx/ZkiQdVqtkGDVtoLlxYzpxpPiv4Xcp3LI +l2zJkmWvglmuf1argFKpc1qXaE6fbFKLZUxtSkZXTT5gTUNsSEdjSkVPR0NaUEFgW0VuX0CP +Z0ydcUywiF/DiWfFl2fSlm/Lj2PIi2e5g1u8imKth1G/hVuze0uta1OXaUaPb020mV3mvIH3 +3Kf416vxz6PlwpDrwY/lvY7IkW3Ml22QWFJTTjlJSD1PWURrb1N+clhvb1d0b1lwclV5bFlq +bVd2bVtwbFNvbVFuaVVkWkpDPDk0OjU2OzM1OjNEPDg/PTg8OzM2PjFAPzg9OzY9OTk2NzQ2 +PDg9Pjg9PDE8PTk7PzE9PDlFQjZFPj86NzY2PDlBOzg9PTY7OTQ6PTg4NjczPDU6OjY1PjI4 +OzY7PjRHOjpIPTY9PDQ1PDc8NjQ6PTg7OzM5PDQyNzQ9PTw9OjREODQ7PTs4QDQ5PjU6PTQ/ +PTMzPjZDSEE6PzdDPTpAPzhDPTo/QDpMTkDH4pL6//H9//n8/+79/+////z////////7//P+ +//j7//v4//f4/u32/+r+//P////+//v4//H0/+f9//vs8+vr8Nzr+OXl9eHg+9by+e3Y4tDZ +58z///r1/+zx/Ovz/vvx/+vp+uP2/vj+/+z5//3////7//308en1/vv///fq/+7+//P7//Pr +9uft9eXu9uv0+/Dy9+j48u3z/uf3++zl8NvAZG1RSj57R0BZRjpMPEFGRTZFPzxbSDxzSz5s +Rz1vST1oTDxYQTc9QT1ERDlmUDl8V0OFVkWCWkF2UTtmRDlKPDZLPjo4OjRPQD1dQTZiRTlf +RTJiQTpQQDdEPDVJQDliRjxoSTljQzpkQjZNPjcxODEzOzU2OTBRQjxrSztpRzpcQjZPPDo9 +OzJBOzM7OzRHOzhKRjhYQDpIPDRDPTk1OzA4PDc0PTE/PjpAPzs3PjQzPDM7OTM8PjY/OTFK +PjRVQDZNPjlJPTo8PDM7OTVAPDNWQztNPzZOQzo5Oi5APzQuOjZNSzqgpmXGsZR0VUxAPzg7 +PDVAOjBQPzdjRzZjRTtFPDQ5NzIxPDVGPjNZRDVXQjNIOjU7NzI9Ojg8PTBaRj1fRzJsSUBf +RTJMRTo/ODRKQTtjRjtkRDlZRjZEPTM9OzQ0Ny9APzlSPzZaRDdaQztXQjdGPjYyOzM0OTJA +QTZPPjxLQzpKNzE9PDU+PTc3PDI8OTU5NzVAOzY9PDg/PzFAPDo0QjQ5OTRCOzRRQjtGPjpB +QTY3PjU8PDQ6OzM/PjdSRDpqRDdvSTxnRTlQPjtBOjQ9OTVIPzVXQz5hRTdWQzxCNzk1OTM9 +Pzc9PTRIQz1jSjhqST9QQjdNPjRMPzliRUFsSzlxSEBTRThIOzU9PTZJPjZaQDdXRDhFOTc7 +PDs+PDc4OzQ3PjY9Ojo6PjRIPzhNPzZPRDY8PzBBQD5ORzFfQz1PRThOQjw6Oy06OTk9QS9X +Rz1ZSzROPj85PTA4PTs2Pjg9RDRHQTtEPzU+RDQ9PDwyPzk9Njo2Pzc5QTgwPTE/PkA4Pzg9 +QDo0QTA8OzorNy8/SDtMT0JwZktrYUZ0ZlB9Y0+EZ06LZVmMZ0+BYEd2Yk57Y1FtW0hiWU1V +UERRTEJYUEpcYUuBd1qDa0mBXUp9YU2DXk51Vz9zbEyhilvNrnnoyZDyz5rrs3rVp3XMkGnJ +kGq8fVm5flu7c2GuelSiaE6NXUGumHemb2FpZ0llVkJgVUd3Zk1wW0qOXkaaZlGnelbGl2vX +qnbWqXXUom3Vk27RpW7ZqXHXqHDOnmbAjmC5h164hVezeFWedEyXaUuPdEi1l2HhwH3x0Y34 +467qxp7jtoHesoHjt4rNoW7Sl3l+Uk1VVURXTEJdY0VpbFJzcVZ5cFpvclN0cFRvcVhxb1lq +bVVwbFNsbFZsa1NdWklBPj8xODMwOzQ0PDI/PDZAQjovPDY7PTQ/Pjk/PDQ4Ozg6PDM8PTk1 +PTdBPjw1PDU6Ozc1QTRHPzo9QDM8OjwzOThAPDU6PzA/NjYzPDY0PDovPDY2Pzc3Pjg7ODk7 +PThFRDVDQz05PDU8OzE3PDc5PjU+PDk3OzQ5OTgzPzNEPzhBQDNEP0E2PDg+PTk5QTZEPDgz +OjQ7PDs5Qjg/QzlAQzxASDw+Qz9OUD/i95/+//z///////3///z///////////////v7//rs ++eLy/ezx++D6//L+//r2//fy/eby/+/1/O7t9Ofs+ODx/+zt9OfV5tjR5cfX5tDj69nn7eP0 ++uvx/Pr79+vq9/H5+fP1/u/++fTt7+Tx++jt/e3+//L5//L0/+z5//P2//H3//T6//b///7/ +///////7++3p+uPz9vT5//P///L+//jXbXZGSzh8UENZSTdVPztFQTNFPzpeRzpxTURwTDxt +RztzSTtdQztLODlCPzdoTT6EWDqLWj+BWUCBUj9jRDhFQThSQDhCPDJQQjlURzllRz1hSDhg +RDZMQTlFPjhHPTlkRzhlSTxnSDVnQzlURDE7ODY0OzI+OjNURTNuTDxrSj9fPDtMQDRDOzRA +OjRBNS5JOjZSPzRWPztNQDFCODU+PDI4Ojc9QDNAPjVBPzk2PDU7OzQ6Pi09PTQ6PjNOPjlR +QDRSQzhNPDhGPDU7OzFGOzZOQztPQzhLQThFOzU3OjI8PzRHSDegpWzGs4x9WVBDPTM/OzY9 +QTBXPzZlSDZnRT1IPTI7OzU0OzBOPzdYQTZaQTZIOzZEOzk5MzVFPjdcRj1mSTltTDtkRjhR +PzpAPDVJPTdkSjtqRzleRDlQQjVBOjkvOS8/OzdSQjdfQjtaRjVeQzlGQzU7NjgtOS5DNzpM +QztURDhIQTFIOjU7OTQ2PDM5OTI8PTc8OTM+OjlBPDRBQDY5PjE4ODc9PjNZQTlIQDlCOzs7 +PjU/Ojk8QChDPjhRPzJoR0FzTDhnQj9PPjZCPTNBPDlKQDZcQTpgQzdYQjU+OTI6OjI4PTQ7 +PDtHQThiSUFrSUBWQjZQQTxNQjViSDhpRzh0SjxUSDJJPDc1PDZLPzlWSDZXRThIPjY/PTM+ +PTc7Ojc8PDc4OzM+PDhFQTVRQDlOPzk+PzNAOTJYRTRjQzlTQTRKQzs9PTY3OTQ9PjBWQj1W +RTRLQTtBOzk7Pzg8PDRBPzlOQjdFRTJEPjs1PzI3PT83PzE5PTc4Pjc0Ozg+Pjc2QDlAQDow +PTc+PDcwPzc+RjhRTj1sZUaCd1WLc1aXfVmXdFqXeV2JaEl6XktrV0NaSkJLRTtoUkRXVzxZ +TEKjdG9iYU5lZUuValmGZ0KbflGkbU+SWkqBXEaWhVTIqHbmzYjt0Zjpun7Tp2zQmmrGj2HX +pm7buoDTjm26dmGpaUydbk2sfGKXc1aWZVKniGKxeG+sfGCzgVvMo3rTpX3arX7SsHbMqG/a +s3ngvH3hunzasHPbqHDWqG3JlmK/k2O9j2G1hVascVWabUiOaEmSc0vFoGjnwnzrv4HuyIjl +soHZp3XcqXXQmnDTpXTNh3BnUUdWSkVOSkBlYUpqb1N1blx1cldsbVd4bFFvbFFxbVZsblJ0 +b1dpb1Fva1dZWEhNQjczPDE0QDA3PDRBPjM/Pjg6PDI6PTc5QDM/OzY3PDU0PDg1PzQ9PzQ7 +QjU7OTU6OzI5Py9GPzo/ODQ5PTg5QDM8OzdBOzE7QDYzOzM0PTM2ODQyOjQ7PDg4Pi9APTNF +QTNKPT45PTM7Ozo4PjE9QDQ/PDU5OjM1Ozg7QDdEQDk/QjY/PDg6OjhAPjs/PzxBQDU6Qjw2 +QDE/RDdBQjhGQz89QzhERTxLUULt/63///v///f///////////b///f6/+/9//L///v////4 +//vz/+b9//j+//f6//P///v3/O/x+eb9//P4//fw/uzr+ePi9uLz/+Pq++Xk89vg7NTn8uTk +69fo9+nu/e78//T4//X1/+/0/+v+//n5+/L7/u/6//n/+/7s/PH4/ezv9Ofz/u/5/+/4/fX4 +/fD6//j7//z7+ff5//L8//Pv8+PBYW1NSzx3TT9iRDtLQjtKPzhEPDlWTjtySz9tSzlsSEBp +RjtiQDxDOzhEQjhgSzmGWD6BXjmJWEOAWTlpQT9MPTBTQztGPDJPPjxXQztdPzRhQTtaRDhb +QTs/PThGOThiRDZlRjxoRT1hRjpVPjg2OTI5OzUxOjBVQjppTTtySTtWQjVZPzc+OjFBOjI+ +OTBNPTVRQDlQQThSOTlBOzU6PTQzOjFDOjc/PjlAOjc5Pjo+Ozc5OzRAPjFCPzhNOjJUPTdO +Oi5LOjw9NzM+OTk/OjBNQjlRPDhMPjVGOzY7OjY6Ojc6RTWenWfBsYd0TVI8OzVBODc8PzZU +QDZnSTpmPDxIPTc7OS88NTZNRTZeQTZcQzhNPDhAPThBOzg/PzhbRDhkRTlpTDRlQUBLPjE8 +PjVKQDBoRTtlSTZaQjRNPThCPjU2NzJBOTVSRjlbQzVXRTpZRzlGODs3ODIxOTRBOzJRQTdS +PzlLOzdDODs9OzdBOTY3OjM8OTc4OTA/ODtAQTFIPTk0Oi87NzdAPjRXQD1CPThAPDc5PzQ+ +OTQ+OTU/QDdSPjloRzpySzloRTlMQjRDOjc5NjVJPTtXRDZfRDdUQTZENjg0PTA7OzU9Pi9J +QjpiSzRnRj9URDRMQjpLQDNfRDtzSz9wRjpZPTo/PDc8PTRIQDlZQjlaRDNGPTc8OzI7PTc/ +PjU8PDQ+PT08QDdGPDhLPTlUOzs5OjRHPTlOPjlmRTpRQTxNPjU5OzQ2OjQ9OzdRRTNaQDdL +OTVAQTw3NzQ4NjhDOjdHOzhKSj9HOjU8ODo4PDRBPDg3Py88Ozo3Py05Pzs3PjQ7Pjs7QTA5 +ODY4PTc7PzhZTD1sYEl9c02RfFScfWSXdleMalJwU0JYR0BXSzRiTEaPg12gc3BtZktoTEVy +WVB0almLgFqifmebbFahcVqthWScX0uFZ0ORe1DMs3bgyYvs0pzst3vdp2rZmHPEil3JmmbU +s3DbtILQnXrEgG+3emPFj27NlHrWnpHUo47fr5Tjup/fvI7cwIbds4DXr3rgu4ner33lrHzd +qXTfqnbdqGvdr3zbpnLUmm7DjF27g1itfU6jblCbZ0iQYUiUdUvIrG/iwojov43jsYXLnW3b +voPos3/JnWzdpnu3b2FORUM/RzlSSkFfY0NxbVlub1h4cl9ybVF+bltvalJ8cV5xalRzblxw +bFVvaVBfU01BQTsyOTg3OTYxOTJCPTU8PjM/OzY5PTJAPDc7PDc8PDMqPDM6QDk2QDdGOT00 +PTREPjU4PjVCPzhBPTs4PDg2PDg/ODc9Ozc7PjE5PTU4Nzs8ODcyPTM5OzQ5Ozc/OzZFPjpG +PDNAPjs0NzI6QEE3PDE5PT04PDUzPTo5PjQ+PjREOjw4PTU9PDo6QTlBPzhCQDs/Ojs3OjY9 +Pzs/PTlGPz1FPz1ARjhSU0bi+pr8/+////7///////z6//D+//v////9//n9//X////////5 +/vH+//v7//j///f+//n9//L///b2/e/q+OHi9tzk9N7d8Nza68vi7uDi7tvX5dX////7//z/ +///09+fn/e35//Dy//j//e7r//P4//T6//v7/+7x/ez3+ery/vL99/f9/vf7/+3w/PPw9+Tt ++ubt+OHt9Ony/+39//jn6dS2X2VVSjt5SEJgPzhQQjxFQDdEQDpUQjtwSkJuRz5xTD53Rz1n +QzpIPzpJPjhoTD6FUUCDWkGJWUN/Uj9sRztPQDVVPzpBPTBRPDpUPzVhQDpaQjRhPj1ZQThK +PzpLPDhmRD5rRjtfQD1nSThYPTc+PDY0ODQ4NjdUQDluTDlrRD1fQzdWPTtDOzZCODk9ODFL +PjlNPDVbQzpQOzZGPDo/OTQ8NzdBOjJFPjZGOjo+Qjg5OzU2PDI8NjNAPDNLOzRYPThOPDZL +Ojg7NjNBOTk6OzZKOjtKOjNTOzs6PTZFODcxOTVDPjuNj12+ooN5VE5COTVANzREPjRUQjZm +STdpQjpKPjo9ODNAOTZNQzZeRDdcQjdRQTlAPDQ/ODo6Py5cQjdnQTVuS0FfQjFOPztEPDVQ +PzhmSDtmRjxfQzhRPDVDPTc2OjNKOjdYQTldQj1XQztfSz1KPDs1MzM5NzVCOjVYQz5JOzZL +OTo7PTs6ODg2OjI7ODc5Njc+NzFHPDlJPDVKNjo7NTY/Ojk+OzVSQTtGQTY9PTk7Pjc+OTI+ +PDk/OzFOQDlrRzV1Rj5iQTtPOjlEOjQ+OzpDPjFZPzpkPzlaPzRCNzY2Ni09OTk7OTRFQjVf +TDdjQj5QPjlPOzhLPzdbRDtwSTpwRT1TQDxFNjk9OTJHPzhXQjdWQDpFPDQ3OTY8Pjk9OTc2 +OTc6OjU5NzFDPjpNPThNPDg9OjVFPTxSPzhfPztTQTRGOTU9Oyw6NDs6OjVRQTdVQTJON0A7 +Ojc7OTA5NjJEPjVKPjdJPDhAPDc/PjY0ODM7OjM1ODQ/Ozg3NTI+Pzg3Pi5CPDw4OjFAPDoy +PDNDQDtFRztuY0yPd1uvkWStfWKaaE+Zb1mWalWOZ0yef2OgZlyNYUyEW1CHZUyXcFeng2Su +lnrClHyyjmnIq4zDoHK4g2iFXUePZU6Sd0zSp3Phx4PuyJLtt33Xp27Wn3PVq3DVmHXPpGjN +mHrDjGS+l2vKpHXVsoLcvY3gx57typnhwZHiwJPbtYThrnrXrn7cqHPUqXLbqXbhs3rju3vr +vIfjq3nlqXnXrnPapG/FhF+0fVWreU2hbE2VaEqTX0uOcEjGrnHWq3narnnNpXLTnnXLqXXV +o3zVroDdoHqgZllJQz5GTD5NS0RiYUxrZU1uZ091clh2cFJ0b1dvc1ZzaVlsa1VvaltzaFVp +ZlZeTU1EPzoyOzU5Ozg6PDVGQDpCODg6Nzc+QDRAOTo8OTdCOjo5OjY7NzU6OjM7Pjg5OzE9 +Nzc1OTRFPzg+OzU+NjY3OjBBOTU7OTQ5ODc1OzE5OTYzOjQ3Oi82PTg3NjdDPDVDPzhHOTQ9 +Ozg2QDU+Njc8OzRAPT0yODdBOjw6OzNFPTk8PDVDQDsxOzRCPDQ8OjhEPjg7PTc6PjY8PDg8 +OzVHPDw+PzhCOj1NTkHn86L///j///X7//L9//n///z///v///////v////////4//n7/+z9 +//34//D3/+/7/vX0+ej6/+zz+ffu8+P6+vfr7efl893p9dzp8ODm7tra59bq/+n0/+zy/+39 +//vz8+/3/f3x++3r/ej1/+z4+PH5//Ls8+bx+O3+/vv6//v///31//b3//P1/+/7/u/9/vz/ +//fs6eP2+fHw9+Li4tSzXWtSTT98S0FiTDxRQzxGPzlIOjhYSTtxRz1wSD1wSUJ3TTxhRTlM +OjNCPjVuTz5+Vz+MWEF9VUOIU0JlRTpWQDhLPTdLQjdMPjdVQzNcRDldQzZhRTpTRTdHNz9F +PjhjRT1kRzltSDtpSzlWQDQ2OTY4OjQ1OTNMQjNpTjtrSzpdQz1SPjlBPjxBOTQ9PTNIOzhP +QTlXQTlOQjRGOzc8OzM9OTc3PTRDQjg9QDU8Ozo9PDM9PjU9PTE8PjVMPTlaPzpUQTlNPTlC +PDE8OjJGOzZHPTdQQTZSQTtAOzc/PTgwOTVAPzmEilWypHdxUkxFQTY9OzZDQDhNRjlwSD9o +RzxMPTk7PTM4NzRJQzhdRTxZSD5NPzNCOTY6OTdDPDNYRzppTDpuRjxdQjhQQTg+OzZVQTxj +SzloQT5ZQjZbPDg3PjM5ODJBPTVaQz1XRThfQz1ZRT1FQTg1OTM1PDZDPjVTPjlMPzhFPjlC +Pjc+Ojk3PDA4OjU4PDI6Njc/Pi5RQUJHPTI/PDo1PDZDOzlMQDdFPjw7PDE/Qj5APjhAQDVB +Oy9SRDdqRTdxSD1lQTpLPTdEPDc8PDdFOzZZQzVkRjRcQUE+PjQ7Ozs1OjFCOThARDFqSzti +RjtZQzhJPTtLQzhcQTxsSjxsR0FTQDdDPDk7PDVGOjhXQzhaRDhFOzg8Nzg9PDo8QDY4PDs6 +PjU5PTtARDFQQz5LPjlDPjpAPjRXSDpeRTdUQztOQDs+NjM3PzU3PTRUQjxSRzdQQj85PTI5 +PDo4RTNFPjtMRTM6QTpFPzY2PDo7PTcyPDQ/PzQ4OTs9RTc1QDdAOzM4PTc7NzRAPT8zPDQ4 +OTpFTD11Zk6QeFmphmGuk2XDnHW4mmqhgV2ch1ariGavkm26kHbCmmzBmnzFo37SuJfOrorS +r4jUt5nSso61knKNZVCTfFCVa0mai1rJpGzZun/owYresnvdonXOl2HUs3TdsHjeqHrOl2XN +onHLk27OnHfOmXzIq3PTtoHcvIneuoHWuYPOqHbZnnLUr3jWpm3ZqXHitYPfvH3txY3ruIXk +uH/etnnlqnnRm2jFiGWze1CpdFWibkqcaEiQYUiOcUrLpm/Gn3K9kWXZq3ngrILFkmvRqXnd +tIbTk3VzS0tBRjtMRUBaWEZtZFJuaVh0b1lsb1Z7cVdxcFZ0cFNxb1lwblpxcV1vcVdyb1dY +Uks/PjkvQDc0PDYxPzNCQD09Pzk8QDU4PjpCPjVCQj02Pjs3Pjc7OC8+QT07PzM3Ozg/Qjs9 +PTxEPjg3PTQ4ODM1PzM5OTc+PzI9OjUuOzA1OTg0Ojc0Pjg2QDg9Ojo4PDVHPzhIPTk8OzY3 +OTY5PjU9PzM8Pzk+PDg1QTc+PDlFQDo8RTc+PDc0QDc/QTo+QTVHREA2RDk6Pjo3QTdBPTxC +QzlHRUBCQj5SUUHl+J77//X///j///b///3///X///r+//b+//j8//vu/ef2/+/+/vj3//H6 +//P0/+/3//D8//j4/+74//L3//H2/+7o/efl+d3P7Mja59PY4dDe49fy7d3m7eTk9ubz/uz4 +//T4+fL59+7r8djo/OP///Lz8+j7/vL//fLx+ejs/fH0/fD8//r59+jp9uby/erv//P///3/ +//v9//T5+fDt8ua8XW9SS0B3Tz9gSjlVPUBNRThJQDhURzdsRj9sRDxxSDxuTDxmQjlGQDZB +PThjSzyDVEGFWUGFXEOBT0BwRj1WQjxPOjRLQDhKOTtYQjlhPzpbRDRiQzhUQzZKOzpEQDhk +RDpjRTZuSD9mRjdXPDc7OjI4ODM2OTNRQTZiTDdvRjpjPzZIQDxFPThAPDc+OzJKPDhOQTZX +QzhWPzVGOzk3OjFBOjU5PzNHPDs9PjZDPzZBPzJBOjg6PDdBPTdIPzVaQDdWPDdOPzhHPTdA +OjJFOzZEOThUQDlRPjtIOjtBOzc6OjRCPDR/hlC6ooJ3VUtJPTw+OjRHOzlSPDl0TTppSjpY +PDw4OjFCOTVRPzdbQjtZQztOQTpFPTg7OTI/OjdZRTlxSjptRz9hRzhKPTlAODVWSDpoSzRr +Q0FbQDBcPj1DOTQ4ODtBPC5aRT1dQDhfQDlfQjxCOjc1NzA4OTNFQDVSQzhQPjlHOjU/ODU4 +ODQ5NzQ4ODU5Oi1CODlGOTZTQThFPDU8PDQ3OzREPzhOQTlIPTk5PThAOjE+PDQ/PDJCNzlN +QzNxTD1ySTxgPj9KPjZEPDU/OjpNQjtaQzpiRDhePjxGODE9Ozg7OjA9PTdKPzBoTEBkRzxX +Q0BQPDdIQThbQzduSzhyRT9RQzVEOzk9PDFIOzxfRjVaQzxGOjE5Ozc6PTJANjg+Nzc8Pjk8 +OzBCPzhWQjVPQDhKPjdAQDtWQztkSDtWQjhSQDg8NzU6OjY1QTRTQDlWPTdRRDs7PTFBOjw7 +OzJGPTtIQDRLQD9CQDM+Pjk8OTI6OTo3OSo5PTc9Pzo5PTA2RDM8OTA7PDc9QTY2Pjc7OzdD +SztvY0yQflmwlGq1lWvBmGi+lGfCj3asi2Svj2y1lW3EmnTErH3PrXrQrIHJqoLRsY7Zvo/U +vJnBmXaadl6lgVymc1KNaUyuhF3NmWnaqGrmtX7hsXjgp3XRkWHSonTYsm7ktITnq3nconvb +pXHft4TdqXzVqXvcrX7ZrHnVpXXVoG/WqHPZpnDOm2vWlGXgqHHptHzivH7tvIXgvn/xt4Df +pnbjqG3ToXDMjF63iVyodFCia0mWaEeOY0aRbkfMpHC4gFzNm3DmwovqvZXGlm7gs3vTpnvF +e2hVSURJSkBiXEloY0lzdFVyclZzcFR0b1V3cFt0cVd2b11va1VublJ2bVlqbFVxaVJhUkhA +QTkzOzI6OTc0PTM+Pzg8PzM8Ozc6OjM/PTc5OTY8OjcxPzU8Nzg8PDU8ODNBPTU1PDU+PDJD +QDc5PjY2OTo3PzI/PTk/PTQ+Nzc1PDI4OTIsOzI6Ozg4OjVAQDk9OzRKPTJDPzc/PDg3QDY6 +PjI8QTo+PjQ1PjY8PDdAPThGPDpAPjk/QDs5PzVAPTtDQjtJTz9APklBOz05RjJBPTtCQTlL +Pz5ARTpbU0fq/qL+//H///v///v///v///v///////z+//z8//P6//f///z9/uv///b3//T9 +//n6+PXy+ubw+un3/+72/Orn7OPg6NTr9ufj6tbn8uLn++Hl+ODx/+31/+71/+7z9/Dx/O31 +/+z4+e3x++n5/ezq+OLz/fH4/+z9//b9/+/z/+71/ur59e/6//X///7////7+/Pz/Orq7eTq +/Obx/+7s9OClWGFSSz9+Tz9mRjtTQj5LQTNFPjdXQjdwTj9oRDdzQz1xSzplQT1DPzJHPzpi +TTmBUkGDWTqLXEd/Vz5wRT5ROzdZPzhLQDJKPTlXRDReQjhiQTVbQjRVQTdFPTRGOjNkSDtj +RzVtRDxmSDZaPjk8Oi8/Ojg2NTFSQj5mSTdrSDxfQzlPPzlKPThFOjNDNzVIODFWPjVUQjVS +PDlGOjQ+ODU9PTI7Oy1JPzc7PDRIOzc9PDFCOTY0OTJDOTlGQDVaPTVRPDNXOzdCPDRAOzFE +ODhBQDFUPDZTQzdEPDI7ODA2PDQ7QDN/fUusn3R0U0s/Pjg5PS9COzZPPzVuSDxoRDRNPTk/ +OCw5PzVNPTJdRD1ZRjhMQDJGOjI9OTQ9QDRaRDhxRztsRjlhQTpMPjVJOzZYRTRqTzZlRDhZ +PjNZOzhBPTQ9PDhEOTRTQDtbPzddSjZYRDdEPDQ0Mjc5ODBFPDdQPztOOzhGPTNBOjo7NjE6 +NzEwPDI5ODE7PTRHOjJMQThMPDY9NzY+OjJFOzpSQDVDPTY9PDQ+OztFOC1DPjhEPDhRQThx +Rzx1RjZjQztKQDRFOzU6PC9MPjtcRjJlRDxXQzZGPDg8OS4+NjY7PzRLRTxlSztlRTlWRzhP +PzxRRThaQjhxRztvRTtWPjVFPDQ+PTVJPTdYRDhbQjhGOjRDOTg9PjVAOzw7PTE6PDg3Oy1E +PDtRQy9QPz1BPDFHPzhaST5jRDFXQT5FOzVAPDc2ODY5OS9PPjtWRTdMQTQ3PDE8PTY1PTNF +PDVJPzRJOzU5QDA+Pjk1QC08QDQyPC89PTcwPTc+ODM5QDMyPzE9PjU6PjM7Pjs8PC1DTDt0 +ZUmUf1aukmO9nW7Tr4TLn3XGkGq3kW+6kW20lW3Bl3PBo27KrIPMt3zKp4zYs5HMt5nKk3Km +fFy7i2WygVubaU2Tc0m3jl7SlmzTpnrfsXrjs3rjpmzZnmfYnWTUqWnir3Hhun3tvo/rtInd +mnHUnnHapXLWo3HPoGfQmWfLkWbNl2nQlGfVmWnZo2zop3PmsHnis37jrnzgsXHlvoHltIDi +pHTYsXLRm2qzf1imcVGhbUmZaE6UZkiRbknCn2PRnnbjxZDpzJfvwZrQrYDbrYPHnnSeaFlQ +Sz5aU0pfX0ZnaVB4cFd+bl92cVl3c1h3bFR0bFZzb1dyd1lvbVZsb1NrbFVta1JbTkQ9Pzg2 +OTY5NzQ3PTJDPDg5PDVBOzY2QDBCOzY8OTFBOTo5PTVCOzc4OjRCPTk4ODE7PTU6PjtCPjBC +OzM4PDQ4PDM7PDU9OjM8PDM2ODQ3ODI0PTE5OzkyPiw/PDk5QjBLQjVBOzU8PTYxPDFBOTk3 +OjY/Nzw3Pzc6Pjg/PDpEPDtBQDI9Ojc7Ozg6OjRIPzpESz1CQkQ4Pjs8PjZEPUBEQDhFRz9B +RThYVEn3+6b7/fH6//D///7///3///r///n///z///////////b1/u/z+d7///b///r2//Lu ++ur8/+38//P4//Ly/+f5//Py/+vq++fd+tPl8Nvd7tfZ5c/n8+n1/vv7//Hz//Ht8+jj+eb2 +/O77/vX//fjt8evy+ef1+ujy/O30/fXy9Obv+/L///7////w/+36/vX+//v18+zw7+/9+e/z +8urx6OGiWGZXS0F/SztkRTpKPzpPOTlGOzlTQjxtR0FrRT1sQUF3TD1jQDhSPTlEPTlkSzh/ +Uz6IWkCMVj+FUT9pRztaRDtSQTZROTpFOzdaPTpdRDdoQDxbPDZYPzhANzRMPTtoQTpiRz9k +RzlpQzhXPTk7NjgzNjA4OzFEQjVvRzpuSjpkPjpJPTVKOTk7NzBJNzlFOTNVPzhTQTZUOjhD +NzBCOTc4NjY+NDdCPzxDPDtCPDg/ODg9NjM5NjQ5ODNHOTRVPzZaPzlMPzZHOjU9OTBHPDlA +Py9VOzdQQTRLOzo4NTc8OTk5PDN6dkqqlHd1U00/OjY8OTQ/OTVTRThqSztoRjpNPzU8OzI7 +PTRNQjlbQjZcQzlKPjZHODw9OzBAODtWRDVzSD9uSThjRTtLPjFDOzhXQThqSDhrQTpdQjpW +OzZCOzk7NjNEOjRVPDpbQjldQTNYRDdCOTY3NTk0NTFFODpRRDZOOzxLPDdBODk7NDQ6OTQ5 +NzU5PDc8MjFKPDdVRDlFPDdDNjk1NzlDOzhQPzlJOjo8PzFDPTVDPDtHPDk/OzNSPzNySEFz +RThcOzpOODJDPDtDOjFJPj1iRDppRTlcOjtDPzc3NzM7NzQ/PDZAQDJhSkFfSDdWPzxQODRP +PTtbRjl0REBtQzlXQTpFOTA9OTRGQzReQj5ZQjRAPTo8PjQ+Pjg4PTE6Ozc2NzU8Ojc7PC9T +QDxNPTpFODpBPzBbQTxfRjVeP0E/PTJBNDs1Oyw7PDdKQDBgQD1IPDNEODc8ODU4OjJFPjlQ +PzhIPDg/PDYzPTU9Ozc2OjU8PTotPjU8PTg3Oy89PDozODBAOTo2Pi8+PTkzNThCRTlyZk2a +gWO3mWvFr4DOqXHTs4PXqITJmGrEoXXCoXbDqHrCpXHEpnvFlnO+m23Cn3m4kWmvfWS8nnDD +k3afakqQYk+ZckfEj2XNnGfUmXLirXziq3jfn2zbnGbZkWjRkGLYlGbOoGjesnXrxIrru5Hk +qn/dmXLeoGvSk2/YkmjOmGTXnmzOmW7domveq3rosH3lsn/qt4DksYDluHrltXvjrXPkrHfV +qWrWnG29hFmrblOXbESdbk+UakmPbkq3ll3WsXjny5DpzJXmvpLgr4TdroTAhWZ0WFFYUEVg +WkhsZ01ybVV7dmB3d2B6b150cFh5b1x0bVd2blpyblFwalhvb1ZzaldxaVZdS0g4PDg4PDc0 +OzM7OzdEOjc3PzI9PDg9PDY5ODY7OTQ1OzE8OTY2PTVCOTk8OjM6OjQ7QDNAPzY+OjE+OjY3 +Ojc/PTw7OzQ9PDQzQDE+QDo6Ozg3NjYyOTY3OTM9Ozc5PzdEPjVFOzo3NjI7ODk2NzNAOzg2 +OzI8Ozg6ODhBOjpDPDRGPUA3PjJFNz0/RThLOj03PjdDQzo8NzM+QzpCPzpCPjtHPz1BRjtX +VEXt+aL+//j///////v///3///////////z///////f///////////73//Hx9+v6/+////b/ +//b4/PXu8+fp9eHo8uPg79rY5dXb8NDg5trU3M/X3sv///bw//Ds+OTr/fn7//77+/P8//bz +/+7r++j8//z////x9+Xx9+f6/vH9//7///Xz/+zr89/t7+30/O7y//H9//X0//P+/ev8//n5 +9/CYWXFTSzx6SkFkSTtMQDxPQjNEQjxRSjhsSURoST9ySUNwQz1lQjpKQThBPDtfSDt/VkF8 +Vj+CWEB/VEFzSjlURTpUQDhHPTxMPjdUPzZcPjxiRTphPzxPRTZJOT1CQTdiRz9fRThoRTtl +RzZYQjk1PDI5OTYuOzRGQTVpTjlrSD1eQzlMPjREPTQ8OzhEPTRDQThTPTZXRjxMPTZGOjs6 +NzQ6PDYzPTJAQTk1OzNGPzY5PzVAPDkzOjVBOztHPjhcRDlPPzNOOzprZmBCO0FDPTdDQDJM +QTlZQjlEPjk6OzcwOTQ9PjVtcUamlWtzVUhHOTs5PTZDOTxURTVyS0FlRj1SPDkyOjI9PDZG +RThfSD5bST5QQjpBQDk9PDw4PzdVRDpvUj1tTD1jRjZOQThDPDlaQTpsTDpnRz9bRDZZPT0+ +PDQ2PDlDOTNTRD1RRTdfRz1SQjg/PTwyOzYuOzJAOTRKQzVPOztCPjc/Ojc4OTQ6PTM2PjY5 +OS8/PThEQTVSQzxDPjg6PTw3OzNEPD1LRDZFPjo8QTVHQjtCQDtKPzo9PDNQRjdzTEF2ST1k +QDpHQDlEPTg4QTFJQTpaRT1rQjpXQT1AOzg4Ozc2OzM6PjZBQTNYSj5cSjhOQjtLPjNHQjtc +RThvSjxsRztRRDlAOzg3PC5HPjpcQjVaRDxBPDc7Njg2Qzc4Ojg3PzA3Pzs0PTM6PThUPjhQ +QD1BPzdAPTdXRzdYRz1VQUBIPjo5OzU0OTM0OTVQRDhTQzhIPUA5PTE+Ozc1PjFFPz1GRTdH +QEE8QTM3QDozOyw4Pjw2QDE2OUA2PzM4Pjk3Qzg7QTU7QjlARTszOzc6Pzo1Rzl6cU2ahF63 +mGq8oHjLonjEq3LGonLFmmzHk221kWLClHG8j2u9jHC5kGe3hmOzhmG2kmjFkm3CnWm6hl+R +ZkuIakiaelK9i13Jk2XVonXcrnrgsXnjpXvbn3PdnGvOm2nYlmbSn2Xgr4DjvXvpu5PruoXm +toTjsILfrHbdrXrapHfarnfgsHjksIDkrnfpuIHrvYnuvI3qvIPhsXzot3jdrHHksXjTqW/R +mWK9iV2od0+Kakendk6cbk+Rbkupk1/StHbkvovdxI3gtYnevIXaqYWmc1xZVEZbXEhgX0ph +akx4b1d7dFh1dVh3cV9ub1dzbllxb1dwc1xtcVVpb1tscFhtblhraVZbTEc8PTsuPTY1QDc1 +OTQ9PzkxPzg3Oz07Pzc8PDk1OzUyPDU0Ojo4PDc4PDY1PDY2PDc4Ozc8Ojc7Pjk1Ojo5PTo6 +OzU9Pzo4PTU7OzYwOjI5Ozs2PTY5Ozg2PTQ8PDY3PjVHPzc+PTU/PDczPTM5PDQzPzM0PTk1 +PDU3PTc7PDpAPDg+PT07Pzg6PDg4PjxCRDxBRD04QDlAPzo9QjRAQEA+Qzs/QEI5SDlUW0zj ++KX+//T///3///////v+//jy/fD1/+n9//X////4/vzw/ujx/uD9//b+//r////3//jn++Tx +/uf7//nv/+r7//b5+O/q9unp/93o+enw/eXo+enq+ef4/u38/evr//D6/vP4//T09+Ti8+P3 +/u3y/+74/+n0//T///7z//L+//f+//n19e7+/vz////39+7m9+H7/vPv8OPs9evs/urv9eGS +WmZVTkN6Sz1qQz1PPjlEQTdFQTZTQzxvSEJxRDxqSz55RjpiQzhOQTpJQThiRjh4UD2HWESC +XT2HTj9wSTVbPjpTRDVQPjpHPzpbPTtcRDdmQzlePzhXRDhLOztIQTdmRTpkSDtpRDtqRzhU +PzY/OTM3OjA6OjJEPTRqSzhqSzxgQzpJQzFGOjQ9PC1GOjdEOzNYQjxVQzVTQjpEPTNEPDgz +OzM8PjU/PTZDPzY/PTg8Pjg4PTM7Ni9APDNIPDFUQDFYQTROPjpSQzxDPDVMPjg/PDJXPzhM +QTVLPDg2OzA8NzU7PjRtbUWijWx1VkpFPDM7OjI8PDVTQDVzTjtvSjtOQzM8OzQ9OTJKPzRg +SjRfRzpNPzREOTk6Oy49OzVXRzFySjxtRTRdSD1OPTZDPzheSzptUDdqQjtZRjtYRTg8OjRA +OjE/NzRRQTZPQTVVRTZQPjk/PDE2NTQwOjE/PzRKQTZLPjc+PTRAOTQ8PDM7OzAzNjU/PDM/ +PzdLQjVSQzhFPzU5PTk2Oy5AOzhORDVIPDc9QTRDQTdCPzZIQTZBQjJVQzdxSz56TD5iRTxQ +QTZDQTk+PjFGQDhcRDNjSTtdQzRBPjM8Ozs5PjU8QDhDQTFcSTxXRjdTQzlJQzRQQzpaRzN1 +SUBtQzVTQjdBPDM9OjRFQTVbQzlWQzQ7PjY8PjM+QTQ7PjY3PjY7PzU2PzU5QzJRQztORTRG +QjlJRTFcSjleSDZYRT1DQDJDQDs1PCw4PTdIQDNaRThKQjZBQTU4QDQ4QDFBQjROQzVGQjg9 +PDc0QDA6ODY1OS86PzA4PDQ8Pzo1PzM7PDgyPS9BQDc8RjdDQTQ1OzFHTDl6fE2pjF6ujGiv +mGLCmW/EoHPMmnjHk2fBi166hF+3gGG4j2S/iF63glu+k2rKo3fGn2zKonXDkVyrcluJY0GR +blame03AjGLNmGjVpG7iqHbitXTlq4bbnGjcqG/coWzamWTXomfYp3Pjqmriq3vgtnPjr3vn +s3zaonXjr3ngrnvlsHXktIDkun7ltn3psnXmu4zuvYPmvIPpuoDlr3veuHvfsHbXqXPOmGbD +iliwcVOObUKkcVCebUqVa0mhiVDPnm3VsnXft4TdtYDcsH3Ilm+KZFFZUENnXUdwbFJ7dFd6 +eFl1dlpzc1V5b1pwbFR6bVRxd1V0bltyb1Nzb1pxclRxbFhtZVVcSkc5Ojk6PTcxOTM/PTlA +Pjc3Pjk6PTQ9QDg5QDQ1PDQzPjU6PTQzPDJDPjk7QTU9QTY2PzFCOTU4PS9COzo2PDQ7OzM6 +QC9BPjkxPTQ2PTM7PDU3PDU7OTk3OjM9QDg/PDdEPDFCPjY5OzM4PDE2PDE+OjY1PTA4PTQ3 +PTJEPz0+QDQ/PTQxPDBEOzc6RDJHQDY0PzFFPjo/Qjc/RTlERT9DRzpBRTtDRT1ZVEPw/ar/ +//3////////7//L+//D////6//f///////f///3///3///j////////////0+/X8//P6//Lw ++ejv/uHx++3j/9/d/N3f89Hk79vh8Njg6tfy8eTr+OX49eji9tzp7tzs/en3+PP4/ev9//n5 +8/Pv9+37/vHt++zu9ufq/ODz++79//n///j1++T5/fj///j///Tx8uv+/vT0/+nx8OWXW2xQ +REJ/R0ZqQj1MQTpRPTlBRTpWPTtuRz92Rj5pST9xRT5mPzlPQUBEPzZgRTx+UTWNVkOFWD2L +VUN1RT1jRDpQQTlPPjtLPDVUPjhhSDdpSDhjPzldQTpGPjZIPTBeRzhpRTplQjluQD1VPzRB +ODg0Nik5PDdJPzRuRz1nSDZeQzxOPjNOPjg8PjNAPDNIOTRVPzNYRzdYPjpFPDY+ODI7ODU9 +ODQ+OzRGPjpDQTdHPjs4PTM9OzU8OjRNOjZUQjFgPjdNPDVPODZAOTJIOjdGPjhUQzVYPzdE +ODQ8NzU5Ozc+OjZkYUCiiGh0VkxIPDU/ODlDPTVXQzp4SzZrRUBLQDREPTk8PCtRPjxiRzVi +RzxSQDRAOzs9OzQ+PDNZQjduTDpwRjxcPzJQQTlFPjRlQTtySTtqRjxeQjxXRDNANjk5MDBM +PTdXPjVWPTZSQTRPPDZANzg4PDUzNTM7Oi5IPzhIPjlHODc/NzU8OzM7OTQ/ODY3OTJEOzxJ +PjlWQjhEPjZCPDA3OTdBOzBMQT5FPDJBOz5JQTVCPj9FOzJEOjlZRDd0TDp8TT1hPzZMPDdG +PjdDOzpEOjFgQz1pRTpeQD1BPjY7ODY6OzA+OTVDQDVZRDlZSDdTQzZLPjdOQzRdRzlzSz11 +RDtZPzlFOzI+PjNGQTVeST5YRjtDNzo4NTNBOTo7PS8/PDg1Pi05OTo3Oy9QQj1MOzJKPEBH +PTJcRD5hSzVWPzpHQTs/PjM4PDM5OzdLQjlTPzpKQjtAPjY3PTc9QTY+PjJSQDpEPDRJSDw4 +PTQ/QDw1OjI/RTg7QDlDQT44QDhEPz0+PDQ7PDhAQjdAOjU8PzlCTDeCc06YhWClgmWrima+ +lWfLnXLNnnTPlXjJmGrNjGzFjGPLlW7KlmbSqHTUpHvYqoDUpnLJn3LGj1+idFGUZ0aOakqm +fFC2j1/PlnXTrG/otnrkp3zdpnPZmWrVpXHgoWbSnGvdmG3VqXfmsoTsqoXhsnzhr4DnsHrl +qXnkrn7pt4TmsXzst4PtuIbuv43uvIzxw5Dtwofyxo7nwYjnr3viqnLYoW/Wp2vYnm/MlGW3 +eVuNaUifdlClcVKTZUqiiFfUnmzQomvYrHTVsXvPom6zf2BqVUlZXElybVN9eVp7c2B6cVp3 +cl92cVt4cFxzb1d4bll2cVZ0dVl2a1hwbVl1bFZ0bldzaFRaSUc4OzM1OjM1PjNBPDk/PTg5 +PTk8PDVFPTg5PjI8Nzo2PTRBOj01ODJDPjs8OjRBOzk8Ojg4PTg+Qjc9OTc5PjY7PS1CPDY7 +OzU5OTY8OzY4OjU+PDU2PDQ+Pjo4PTVHPTtCQDBHOzk6ODNEOzk2NzVCPDk0PjY+OzY3PjRK +PzhAPTc/Ojk+PzQ8PDZDPjtGRThBOzs9Qjw/Ozs5PDtGQTtCQT5CQzlER0VYVUHk9aH6/+z/ +//////v////8//D9//b4//Xv/+zs9t/5/ej9///9//H////7/PD9//z///b///////37+/n9 +//vt9erf79rb6tni9tjo8eHh6dve5Nf6//jt9eTu8vL8/PLw7fH5/vv///////nt+en5//T9 +//n///P3/fP7+e/v/u36//P8//j0++P8/fju/+38//j//fX8+/v////5+/Dq69OPVmZNSTp9 +UkRkRjtSPztOPz4/PDhTQz9oSz1wRz5rQj5vSD5nQjtIQTdEQzxYRzl5UD9/VjqHWUWBVjh4 +TT9VRTVcQTpFPC1JQTxXRTZjQj5qRDRfPjpbQjdJPTVCODZdRTlkRTtkSDdkRzhVQDc8PDI3 +OzMxODNLPztkTTx0SD1XQjhUPjs+PDVGOzlCOzRMOjZKPTpcRzlSQTlAOi88OzU2OzM7PTU3 +QDVCPDo/PjZEPjg6OzQ9OTJAOTNFOzFbPjpXPzVSPTtLPTRGPjlEPDJNPzpTPzJTQD1DPjY4 +ODg6NzY3PjNgWD2Vh2B1U0pAPDA7PTU/PDZUQjhyTDlzRkVHPjk6PDg7OjZJQDRfSDpgRzhL +QzY9PjM7OTU+PjZdRzlxTjtsSTZdQTlNOjFHPDRfSjxxSzxlQzxlQz1TQDlGODstODFNOjZa +RTljSDtbQDtRPzs3PTg5PDExOjI5OjNIQThINzVANzk9OjM7ODY/NTk2ODBAPDlBPjRPPj5S +QjhLPDo1OjU8OTk9PjhPPj09PTVDQThAQTZBOzVBPzZIOjpTQTp4SkB/Sz1iRDtQQjZEOjJA +OzZIPDlcQzxsR0BbQjlEOzc8OjQ/OjY6OTFEPDlVRjVYQjxNRTVPPj1JPTNbRjpySThtQUJR +QDVIOjs9OTpDPTNdRTlXQjtCODw2OTRBPTw+PTY3Ozs6OTsxODE5OzZJQDhRPzs+PzROPjxZ +SDhlRz9PRDhNOzo3OjQ7Ozk7OzVLQTtUQDdMPjg/PTQ6PDc7OTg/PjRMQTxLRDhAPTs1QTYy +PTE4Ozg6PDA3OjsyPDE9Oz41OjBBODw7OS49QUE5PTQ6OjlCSTl6ZE2Ve1eff1muh123lmbJ +lm7Kpm/SoXrNqHPXpYHUpnLSnnfXo3PSrH7YsYHTpnvNp2vCkW++hlueelWTakuGaEylelO+ +jWTNmW3fsYDju4jqrnfdpXHTl27Ynmvdo3nhsG7nq3/puYbxwI3pxpTwxZfowJDtso3lrX7u +vIvluIftvozrwozwzpXz0Jn40J7zyp35xJPrwov1uYfrtoLmr3zZpXHSnmvXrHPLlWu0e1SW +ZUqZdUyqdFOUaEqZiFXYqXncp3LVpXbLnHDFjGWBZFNoXE1yb1d3d1qCd193eF57dmB7clx8 +c1x2dFt6b1xycFh5bldvcVF0bVxvblR3b15vaFVwZ1VWRj43PTc2NzQ1OTM2PDZBQDg6PTU3 +OzU5ODY7PTU3Ozc4OzgzOTQ8PTU4PTRCPDg2OjVCQDs6OjFBOzg9PDdCPTc8OzY/OjQ3OjM5 +PTA5PS82QDM2PzswPjY+PTo7PDlAPThDQThCPzk2PDQ0NzY6Oz42PjU3OzsyNTM8PTdCOTZB +QDc5ODA8ODtFQTQ/Pz1CPjg6PTY7Pjw2OzE9PDxAPzpAPjw4QTlBRT9UVETr+aj9//f///r/ +//r///n///////z///////7///////z9//Pz++X0/+n7//v8//L9//nw8uvm/eDs+t30/PDv +/Ojw9e3m++Ti+dbX49DZ59Lc7Nz1//n0//P9//n5//L2//X///7z/vH9/vP2/+3w//T1//b8 +//X+//77//z///f3/PH09/D+9/L5//b///L09e3y/O3u9+n6/+z4//H///CLT2hPTUWASkJn +RzhRQTxRPzxDPzZTQD5oSjtwQD5tRTR4SEFlRTpSQEFDQjJfPj14UjmLVESFWECCUkB5SztZ +QzVZQTZTPDVIPTZaPTpeQjhlQjVlQTpfQTZJPztNOjdbQTtqRjtiRjlvRDpUPTVBODQvOjA8 +OzY/PjRsTTZrSz1lQDpONzhJPjRCNzZDOjVMOTdTPjRbRDlRQjdLOTc8OzE+OTI6OjE4PzBD +PzhAQzRDPTs9ODNANzg7OjFIQDpaPDFbQzdRPjRJPDRFPjJGODRLODZUQDlaQDpBPTQ7Nzk3 +PzY4NzRcXj6VgV51VUtHPDY8OjU/OjVSQzhzTjptRTpRQjc7ODA9OzVOQzJhRThgRzhQPThC +PjI+OTo3PTBcSDZyTjpwSj5bQzJSPDpLPzZjSjpyRj1qRj5fSDpcQDtAOzs6OzNLQDpkQzpj +RT9lQjRUQTc8OjY1OjE0ODY5OjNNOj1LPzRHPDc9PDRAOjgzPTA8OzQ7ODNENjtJQzVWQDlA +OzU9OTU6Pi4/PDhMPzlLOzpERDVCPDtEPTNGPjhHQDVYRTpxTj17Tj5lRThUPTlHOjNEPThE +PDJgQztpSjdfQD5EPzNBNzk4PTA7OzlDPTJWRjxXQzlSQjlTPjtNPzVeRTZ0TDdwQjtVPzlL +NzlBQDZJOzRdQjtRQDZFOjo2PDM9PTg7OzQ6OTQzOS47NzY1ODFTRDpMQDhHPTRKPjVbRzhk +RT1RPzlKPT0/Oy00NTc3PzRLQDpSQTpNOzlAPjo4OzE8OztCPzFMPjxDQTY+OTw2Py4/PD06 +ODQ9PD45Oyw6OzQ8OTQ2PjY4PzY3PTNAPTw9PTM7PDhASjd3aFSOek+ddmKtiV68l2rMnnbO +oHHbq3TXsn7hs4XXqHHgsHjWrILgsHvVqoPgqXrQmm3IkWjCimWjc1OacE2Na0qhe1G5iFrY +pHvitoHtvIforXbgonLYnWfan3XYqWndrnnisH3wxpT116L10K741az1z5nrvJDzv4/yxpb2 +wZvxyJj61KX11ab41av40pv61qTuz5X0x5ztwIjsuoLks3zkp3HVn2jUo2vNmWq7dFyXbU+a +c06bbEyQZkmVgk3Pr3ncq4LSonfAjWOhdV5vYlBsalN2cVd9eGN2e1p9dFx6dWGAdGFzdV95 +cGFvcVZ1c1x1cF1ybllzcld0b1NtbFZyalJvZFJTRkI2PDU4PjU0OzE4PjY5PjVCPTc5OzVF +OTUxOTM7OzczOjQ7OjMyOTFAOTg5OTo9PTQ+PDk9OzQ6Ojc7PTA3PDU5PzU7PTU1OzA7PzY7 +PDg7OzQ5OTU3PTM2OTE5OjBBPjlEQTFCPDs3PC83Pjw8ODE/OTswNjU1Pjo+PTlBPTxCPTc4 +PTU6QTc4PTVCPjY/PjZBQDQ7Qzk7PzlCPDtHQjo9QTo8PzpHTT9VUUX//7P///X9//X6/+// +//n////////////////////////9//X3/uf9//D7/+76//T7//P//v36/+78//Lv++vx/+T9 +//Pz/ffr8trj7OHb69nc6Nf1//T1/Ozk+N/q9un9//X4/+7v/eLx9+r7//P09fPz/Oz0+e3r +9+b4//H8//f8//T+//b+//379+jw/fb////+//X18+75/fP4//Dt6958U2ZLSUaETz11RkRU +RDpPQz9IRTVNQj5nSD10Q0JnST1xSz5sSjpKPjpEQDVeSDd5TD6JVUCKWkSHVT13TT1dQjhU +QjhROzdKPjdXQTtbQjduQz9lQDZYQDlDQDRGOjZZQzVjRTtkRThrSD1YQTBDOjowPTQ3ODE/ +QDFjSTtySzldRzVQQDZGOjY9OTNEPDlGPDNOQjhbRjJYQzlFOzRBOTk0PzM9PDk1PjBHPTk+ +QjVEOzo3Oy9DOTc/OTJHOjlTQDZXPTZUQDtMODZGODREPTRNQzdSQThVRTpFOzg8OjE9Ojk0 +OzBWVkCFfVN3VUlBPjRGOj45PTFaRThtTThySD1IPThFNzg4OTJMQTZpST9iRzlRPzlBODQ6 +NzQ7PzVeRTd1TEBrTDteRjtPPy5LQDhdQTNwR0BmQjdjQz9QOjA/OTk5Oi9OQT1hQzRlSTxq +RkdSPzlDOjQwOjk3NzU8PDZQQThJPjZHOTU9OTQ/Pjo4PTM8ODVAOTY+OjRJPUBSPjtGOjk2 +OjU3PTQ3NzJOPTRFPTpCQjhEPTtAPDVHQDhFOzdYQTt2Tjp6Sj1eQDdQOzpIQDRGOTVFOTJj +RjpwRj9aQjVDPDk8OTI5Nzc9PTJIQTtTRjdURj5PQTdHPDhLQDtgQTt1SkBrRzhWQj1DODFB +NztEQC5gQzlUPzZBOTY2OTA7PTw5OTU2ODQ7OzM6PDc6PTNERTZXPzdDPDxKPjVgRD5jRzpW +RDpGPDg+QjszPTQ3OTY9QzRWQTtLRjRDPTs2OzQ+PDk7QDFNPTxDPzFBOD03QDQ7PEA8Pi08 +PDk3Nzw3PTM9PzU5PDY3Pjg9Ozw5QTU8QDQtPzFFTD5wYUmIb1eah1q1kW3ImmjOpHjUp3rd +torZsYbhs4LcrHrhrXrfqHvdsIDcsH3hsIjUrXjNnmvBlWeYbUydcFSUbFKjelu6iGPVqnjv +xJTltX/kp3reqWzenXXSnmjZk3TXn2zasHvlwXvnxpHsyY7wz4vw1Z7y05z5x6jz1KD42bD/ +3bv+37b726374LT82aT1z6P6z5vxyJb1w47lt3/rsn3gqHbboWvLpGzUpGm3gV+daUacd0yh +ckyPaUuFa0iil2LBp2y/l2igfFqBbVtzb1Z5cll4dFqBd1x2dld6dlt8cV57dFp7dVl0c1p0 +c1lzcVZ0bVt0a09sb1Z1bFhvcFdva1hsY01VRkQzPjY8PDg4PjU8PDg7PTM6PzU/PjY/OzU4 +Pzc1PDQ0OzU5ODo4OTQ/RDZAPjM6OjU+PjQ4QTU8PjI4OjU4Pjc7OzY3PDQ/QDcxPjQ6PDY1 +Oy08OzQuPDI0NzQ2PTBDPzM/PTU+PjI4PDNANzY3OjI9OTY1OTg5Oy86PTZFPzdDPzk9Ozg+ +PTU9ODlAQzdCQT89PjZBOz0yQTZFPDtBQzhHQzw+PTRMQD5TVUH296X9//T9//X///////39 +//b3/+r+//H+//z+//n////z//H3/ej////6//vx/+T9//j8//b6//vw/+Lz++vt9ebf8N/V +7s3k+dvl8d3v8uDy9+7y7vDw8Oz09/n5/vHv//H1/vD2+fP2/9/2/vH8//L5//fz8ej4++3z +//D2/u/7+e/x8ubs++j6/PXv/+jz/vH2/+r69/Hy/+7+//v18OB/UWlJUT+CUERySD1RQj1K +RzhJPzVKRT1kTz1uSzhpSzxrST5rRTdGRDZJPjpXRDl8UD2CWT2KWkF+Uzx6ST5aSDdbRzlG +QTNKOzZTQTdpQjxtRj5pQztiQzlFPzZCQTJZRjhiRztoSTloSTheQjY6PjU3ODUxOStDQDdg +TDRrTTpZQDRQPjZAOS5GOjZAPjFIPDZQQDdeRDxWRjZLOjg7PjM8ODI6OjU4Py89PjZFQjhD +OTBCOjY5PjRCOTdIPTRaQDdVRTZRPzhGOjBMQDU+Py9OPzZSQztZQjc8PjQ/OzY5PTU5PDRO +UTeGeFh2U0c/QTVAODU9OjNTRDRwUTxwRzpNQDQ7Ny1AOjNQPjRjRzxaQzZNOj5CPjA9Ojs7 +QTRcRDl0UjdvRj1fRThKPzZIPzJjRjpwSzxiQjpiRzdOPDc+Njc7PC9OQDJeSjxmSj5jRjlO +PjVAQDsyOC81ODI5PDFOQjtMPzhFPDQ/PzM/PTc5OTg7PDE6PjQ9PS9LPjpSSDZIOTo6NzM9 +OTc+PDNNQzlBPj5BPDVBQTxEPzRFQDpFPTRaTTZ2UTZzTD1fRDdRQDtJQTNCOzVHPDBZRDZr +ST1aRDpJOzw8PTNAPTg+RzdIRD1TRzdXQztNQjhLQjJJQTRdRDhxTjhtRTxVQDhFPDg9PjFE +QjdgRjlSQztDPjU9ODY2QDY/PjU2OTE9OzYzPTA/PThKQzRWPztGQzNNPzVbSDdlSjxQRjRN +QDxDOy87OzQ2PDBGQztSQTdKPzA8PDc7PDY4OzREPzNLPTJJQTg7QDQ9PTcyPzE+Pzo0Pi86 +PTgxQjA+PDozPjU/QD03QDhBQjo0PTE7PzhEVTuCakiHa1CjgVe1k3DHoGnUrX3VrHvZsIvZ +rnjZrHrhvYvkuYjguYPavYbjv47hvYjfsoDLoHS3iWqUb06NaFSNbkqpe1a7nWPds3rrwZbl +uofmrXvdrXriqHvZqnDZpHHPmGfPl2bNoWLYp3fcr3nUqXfXt3XXtXzjyYXkzJP00qH136j6 +4Kzv267+3qP22a7z15v11J/10JHyxYfiunzpuX7esHTZo3XNn2jMpmu9jl+haEyUd0ujdlSX +ak2FZkeJf1qCeV+GeFyBd1l9dFyAeFyAe1x8d1t4eV5/d2V2eVl9dF92dlt5dGBxc1h7cFlz +dFd6cWByclZwc1lsbVhvcltucVhyZlJQRjs7PDw2PzA7QDQ8OzZAQzc6PjRAPDU9PjI4QDM3 +OzFAPTc4OzQ+PTgzRDU+QDY2QTFAQDY8PTJBPjM1QTQ3ODU7PTJCPzoyOzM+OzU3PTQ7PzI6 +ODgzOys0PjQ5Pjg+PjFCOjg4PDQ4QDU1OjM5PDM2PjA4QTgzOjBCRTdFQzRMOjszPTZCQzk1 +PTVFPzpBQjdDQDg5PTo4Pjg+RDY8QTVDRDw9QjlFRjhbW0Pu+6f///n///////////z///v/ +//////////z9/PT1/ur+//z///n8//r4/+n///r+//n5//Lx/uj8//b+//35/+/u9+np9uPh +9Nfc69be9djT3sz1/+zu/+/5/+z5//L6+fTx+OHx/PP3++Xp9eT0//r6/evw++////P9//v/ +//f1/+70//j///L1//Lz+e/t8eLs++rz9PPz9+309e/z/eF9VmlISz+ATUNpQzlSQDpMPzNJ +RTpNQDdjSD50Rz1rSDpwRj9mRDZLOjdEQDxWSDl/UTqGVjuJVkWCVj99STxcQjZaQT1NQDRO +PjtNQjJmRTpqRTJrRD5gRTRNPD1COzVYRDJlSDdkSDNsRjpbQDM+OzU8PjQzOzY/QDVdRzdn +ST5XRDlVPDNBOzBCOTg4PTFLPTlLPTZaRDJMQjVNQDI9NzY6OzY3ODY7Ojg+QDRFQDlCPjk6 +PjFAPDI+PzFCPDZWQjZXQDJMQzVMOzRHQzJBPjFEQDlaRDVVQTlBOjE8OTc2PTA3OjJHTTaB +dVFxU0hCQTU/ODU7OTFTQDduTzZrRztLPzdANzM7PDJMPjRiRjhhSTlKPTk+PDE5OzQ6PjRZ +QTl4Tz1xSjlaQjhMRDlGPDZmSzdvQzpoRDpgQDxMQTRBPjU6PjBUQTpbSTtrQzpbSDpUPjg4 +PDU7OjY1PjY7PTVOPztTQDFBQjZCPTU4Ozc6PTM7OTQ7NS8/OTVOQDpQPjhIQDszPC04PDk4 +QDRQPz5APzFEQTk+QTg+PjNBPjJGQTZURjZ3UD9zSzxoQj5OQjVNPzlDPTZERDpdRTVqSTlY +RDhDOjY8PS08PTk5PjFMQT5SRTZSRzpLQzhHPjhJPjBaQz1ySTdtR0FRQTNHQDg9OS5HPDhZ +STlURzo/QTY5PjA1PDU4QDE5PTE3PTI3OjQ3OzNAQDFROTY/QTVKQTlZRTNlST9MQjdLPjg1 +OTA3PDgyOjdIQjdOQTRORTFDQDQ1OTU1NjNAPjVJQDhEPjc8Pzo0PDY7PDg4PTc2PC85PDQ3 +OzM9RDg6QjQ8QTs2PDE9OTo0PS85PjtJVTx1YUaMb0ymhl2zk2jDmGzYr3nUuYLctILjvojq +tYzlxZTpwprrw47lv5zluovcuI7asIO+kWaoeViYcFeSak+Ndkyqfli+lWzguHnt1aTwwYvi +qHzbp3PanWbQlWnZnGzQkGTOj2DDklzLl2bNkF7RnWfLl2TBkWa/o2Lcs3vcwH7wy4/w0Jfs +zpPz25r21Jbsz5Tv05XuypDswo/jt3fhsXrbrHXZn2fLnmjQoGq8iluha1KJaUShd1OObEOD +Z0mAgFiFc2N+eVyHfWN6dlt4el19eV18eV19eF56dl54el2Adl11dVx3dVp2cVt2dFhxdFlx +dFttdFhzcFxvc1tvb1VtbU9wZFdKRjw8Ojg3OjFBQDk1PjQ+RDc5PTc4QC87OzU6PTY5OTQ0 +PTU+PjQ7PDQyPDNBPjc1QDE7Ojk0OjQ7OjguPDNCOTczPy5AOzk0PTQ8OTUtOjM4QDAzOTQ4 +PjM3QDU2PTRDOTk/PDU5NTkwOjE9OzQzPjU6OTU0OzU1PjE8QDVDQTdDPT05Qi9GPzw7OzJF +QT9AQDA+Qzk+QDU5Pjs8Rjc8PjZAQjs7Qz1HRT1aWUPw/6v7//H///3///L///////////// +//j///3///r////1//vt/ub3/u79//X///r7/ff2/Oz3//L5//Ty/+rw/+v0/+/r/+vq897x +9Ort+ufg7Nvb7Njs+fL7/fLz+e3y+unw9unv/O34//P2//X+9/Pt9OTt+eb4/fH5/+b19+b0 +/PT+//r+//n/9/L+//3///////3y8er8/vf1++jw8uV1VGdLSUF+TEJvRztWQzpEPj5LOzpE +PjtmRT5rQz10ST5pST9nQTRPPDlJQTlWRzd6UDaHWkKFVD6GWUB1Sj1lQT5VQTVWPztKQDRU +QjVgRjZpQTtmRD1dRDhPQD5IPjZUQDtiRTlnRD5pSDZdRTtBOjc0NjU3OjQ7PjVfSDlnSD1d +RDVNPDlDOTQ8Py9AOzREOjNUOzpTPTZTQDlGPDdDOzc6OTY9NzY1OTM/PzhJQDg8Pzc+PTM7 +PDI+ODRHPDZWOzNcPzZMPDVTPThJPTNMPTlEPzRaPjhWPzFHOTg2PDQ6Nzc3MzBNSjp8cFFw +T0ZAOzU/OjU6NjRURTZzTENwRjxROjU+OTc9NzJQPjxnSTpjQj1NNzZEOzgzODQ/PzldRzh6 +SkBpRDpjQj5EPjVRPjViSjd4RT9nRDZoSDtSPjc5NTU7OTNTRTZhRzhoRz5lQj1MPjs8NzQu +NjYyODI9NzVOPjZRPj9DOjNCODo7PC85ODY1Oi07OTU8OS5JOj1SQD5GOzk4OTQ4OzM7NzlJ +QTdFPThBPjtEPThBOjdIPzlHPTRcRjp8Uj94ST1jRj5QPThMPjw/PC5MPTheRDhvR0FWQzpI +PjY6ODc1OzI8OTdEQDVVRD1TQzlRQDxKPzROOjtWQjV0TT5rRjlUOzZEOTY4PTNHPTpaSjVP +QD0/OzM4PTk7PzI3PDw3OzE2ODg5OTI5PDVEQDdKQztNOzlMQjRfQ0BbSDhUPz1HOjhCOT05 +OjQ3OTlHQjZTQDtFQjY/Ozg6OzM3OjRGQjpHQDdJQz48ODc9ODQ3QDpAPjQ7Ozo8QDQ+NTw5 +OzBAPjcyOjE/PTc1PzU/Qjs7QC9VVUV1WUWIb1mifVavi2K/pnXVqnnTpnjUtnniv4bpwovn +yJbox5TmwpriwpncvJTbqnzFm2+qdlqUc1GVclqNZ02TcVSpgFjMkWbZs37w0KjtupTlrH7c +pW/Ul2zUlWjRm2/Rj2fNj2LTlWrThm7LiWPKlWzcn3rUmnrGiXO6kGfFpmzgs33ivIflwYzm +xY30yY/tx4rzwo/tvIXrv4rqrH7lrnzgo3PXoGjOmWzLoWG9jmGsck+La0ugdU2bbk14YkOA +el2Ce15+eGOGeGB6dVp9eGF4c16Dc195eV+BdltvdF1/dGNzcVp3dlh6c112b1t8blhydFVy +bldxcVt2cFtybVhybFdrYExORUU5PDg3PDU7PDo7OzVBOzs9ODY+Nzk8OjE/Ojg3PDI3Ojg5 +OzE7OzM8OTY2PDNANTg8PjU6PjU0OzJBPDs3PTZAPDY9OjU0Ojc4OTg3PTQ0PTU4Ojc2Nzg6 +ODU9OzlCPTtBOjU6ODg9PTc5Ozk1OjY1OTc0OzM8Nzs8OTRHPj1BQDVDPDw6QjdCPEBAQzhJ +QTs4QTg/Pjs6QTpAOT07OT1CPzk/QztHQjxdVkrw96L+//z///////////H4//r8//v9//b/ +//////3///bz/+39/+////////v5//jv/eno9dz1/Obo++Tp9+Hm9t7u+Obb69vP6cbf7dTj +9N7g7Nz5/PL0++71/fLx9e7u7OXt/PH6/fT0/+nu/e3x/+z1/vH///7///j6//P9//f8//T1 +/+33//D+//77//T7//H///j18Ors/Oz69/Lf5NN7TWVESjl/Tj9zRDhZQjtRQDtDQTtHQztc +QTtsSj1uSTxsRT9oQjpLPTVIOjxQQzR5TDyIVDyEWD9/WTl+SEFgRTNeQT5OPjNTPjhOQTFi +QTprRTlmRDtdRDdKPDlFPDVVQzZjQzhoRjtqSjxZRDQ/PDY4PDIyNjJEOjZaSjdrRTxbQTZZ +Pjk9PTRFOTk4OS9KPTNGQTVbRTpOQDZMOTU+OzNBOjE6ODM2PDNAPjpDPzhDNTY7Ojc8OzU8 +PTREPTVPOTNROzRQPzpMPTRNOzVBOjFOOzhRQTNVQzlFODI9NTk7OTE8OzVHRjl6a01vVEBE +PjQ/OjQ6PDJTQzZqTTZtQjtJPzhAOTY3PjNSPTlkSTZlSDxKPTc9NTI8MjU7OjVdRzp3TDxx +Qz1WPjlNQDVNPDRlTTV0Qj9mRTZmQT1LPDRBPDo7OTFYQD1gSThnSD1fRDtQQDg6OzQ8OTU0 +NTY+NjNKOjZNOzRDOzREOjQ9OTk7NTU5OjQ6PDM/PzRKQjlMPTRFOzg1PCw7Nzs8PjdOPj5B +PDFDOz0/PzlGOjs/PTFCOjRYRzZ7UT90STxjQDVSQDVDOjdDOzZEPTpYQjhpQztXPzVDNzU5 +OC48Njg6PjRHPjtNRTlRPDxKRDhMPjpGPi1YRT1vRjdrQDpOOzBIOjc/Oi5AODlZRD9QQTdD +Nzs6Ozg3QTU6OzM1OjU2OTcyNzU1PDRAOzRSOztEPTVTQzlZQjRZQTtMPjdJPzo2OjA7OTY1 +NTJIPzdSPzRJPDRAQDo6OzI4PDU+QjFLPTtEQzY9PDU3PDY8PjQ8PDc2PDM8PjYzPTQ7PDo2 +OzQ8PDszQjM7PTo8PC8+PD9NT0ByV0iJc0ydgF2vjmbGqnPXsH/Uo3TdsoDivIzjv5DftYnb +u3/jwY7jwpDXsYTKpHLIhWWVbleeeFSbc1agblOVcE+6g1jJoHPdvX/wyaXrvY/lpHfWmW7S +lGzTmWbcnG/VkmjalnbToW/YlGzMjWfUnW/crHbdo3vetIXdl4K4gly1nmvMp2/aq3zat4bi +xX/kvYfvv4jiwH/tvoPfrXTYqHHbrG7Yo23OmmjNm2e+imC1dliOa0eba02DZkN5YkuBelqB +eWR9eV2Fdl9/d1x8d2CAeV99dV9+dV1+dFt9cVt6dWF1c1l6cFhyc1hya1ZycVlvbldvbldy +bVtvcFh3cFtycFRvYlVMQj0+PDo1PjM6OThCOzo2ODg9OzU5QTA8PDA3OjE7Pjc2Ozc2OTI5 +OTc8OzI4OzY4OzZAODk4PDFAODU0OTM8OTg0PTVCOzwwOzRBPjc4Ozc9OTU3OTE5ODM3PTQ4 +PDVAPjhBOzU5PTM3PTU7PDA3PjI2PTIvODw1PzVBQDhEPjZDRTk3PjI7Qz03PDBHPztFPDk/ +QD89Pjg4PjtGPjlBPjo/Qj4+RThGRkJcXUP0/q76//L+//z9//v9//X///v///b///////f/ +///6//b3//r2/+n9//P///n5/vP6//T7///x+e30+uj+//vv//Dn8eLq+eL1/uji7+He5drS +59L1//Hy/u71/+37//D6//L+//7z9ePz/Ovy/PL5/Pj7//b6//L3/+3t/uv1//Lo8eXw9Ovs +/ujz9e/1/ent9+bw/uvz8+74/e/z/+7//f6EV3JRSUF5TUV6Sz1RPjtPPjU/PzhKPjRZQj5x +SjhrSUJyST1tQj9LQTo/PjtORzt+T0CCUz+HVUV+WTx7Sz1hRDdZRTxYPzRMOzRRSDtfQTVn +RTtlRjVjRzxROTg/PTlSQzpeRDpnSD1lRzddQzc3QjU5OzkwPjU/PzhYTDlqTD5dRTlTPz1G +PDFDOzc9PTVAOTVSQDhXPTlTPTpNPj0/PTU7OTI7OzU7QDJBQjlJQzZBPjM+OjU7PTJBOjpA +PjBWPzRVPTJWPTtLPDJOPDlBQTdMQTdYQDdYPzhFOTM7PDQ6OzU6PTVHSTx6bUhtVElDQDg+ +OTZDPDJSQjNySz1rRztNOjo4OTY6OzVLQjRuSEJYRjRRPzo9PTY8PDY4PjZjSDxuTj1rRjtW +RzhTQTZSOjdkSTRxRTlpQzpkRjZMQDg6OjY7PTNZRjFoSD9mSTxhQz9OQTg8PTkwOi45Ojg4 +OzFPPz1NQS1IOTs+PDE+Oz08PDU8OzNBOzdBPDdQQjdRQjtIOjg3Ozg6OTw8PzRHPT1EPDhC +QzhEQDs9PjFIQDlAOzVfRDh5Uj96SkNbRDRTQTlKOzlKPjhEPzxcSDZwSD1aQzVGPDo4PjI+ +OTk4PDRDRDZLRDlVRDtPQjxJQTdGPTpTQThtTUFlRDJUPzpFPzVAQT5DQDRZRzxNQjU5PDs0 +OjM2Pj42Njg2QDY7OzM0PzE6OjtAQDFOPzpHQTdTRj1gSzZeQz1ORTpIQDk8PjIzOTg7NDhG +PjdRQDdLPDlFPzk3PTs+QDlAPzxPQjlIQzk5Pzg9Ojw4PTM/QTo7PjVAOTs3PDc+PD07RTRD +OT0+PThBPj48SjZBPUFXWEJrWEl9cEudd1unh13MpnnUsH3ZtIPdtYLgvobguozcto/Wq4HT +rXjKqnHKqXHDnmrEiGiMb0ugelydcVatdFWielaxkGPEo3Dlu4vpypzuvJXlpHnWmWvZoHHX +m2vapHTdr3PaqH3UpHjVnG3MlGbVtYTjo4DZrnnpsIncpX/NlHmxeFijhlm4lF/FpXLXrXji +tH/juILlvYDktYHhr3jmsnPisXrfq3fRmm3KmmXJk1+5fVqYbk6Qbk6SZkZ1Z0CHeFp9fVuG +eGB8eF6Bd2B1dl2BfV59eV58eVt9eGB8dmB7eV50e1p4cF52dFd6cl1tc1ZvcVpwbVl0cVZy +cFhzcVZxa1trYVFJQkQ0NzczOjkyPjQ4Pzw8PTc9PT9CPjU/PDQ7PTM1RDM7NTY2PTI1Pjky +PDQ9Ojg4Ozg7PTs9QTE7QjI0PTk3PzU4PzY9PDk7OTc4PjQ7PDg1Ojo9PjU3OjY/PDg2PTdA +PTVFQTg6Ozo4OTU0OzQ7PTs4OzU5PTc8QTNEQjtEPjhCOjc8RDo+Ojo6QDtGQT1FQTw9Qzo7 +Qzg9QDU+PzxCRDg/QzlBQzxJSD1aW0T1/7D///v///X///r///7///////////////////3/ +//////////b///73//X9//v6+/ry+eb4/+3////w9u/m8+Ds9OPk9eLY7s3i89vs+eP08+7y ++u3x8ers9Obz+/D+//35//H7/+/7/+3u//L///zx++fk+93u/en8//b+/ff//vv////5//P9 +//v////57uzm9eH9//78//Hy/Onz+OWCU2xJS0GASjx3STtaPjhJQTdKPzhIQThfQj5sSjly +Qj5wSEBrPzlMPjhCPzlLQjh7TT2CVTiGU0OJVDqBTEFgQTZhQj1RPTRQPjhSPzVZQTRnRTRr +QjljPzhOPjNHQjlbQzhlQzdoRTpySD1eRjNBOjM7PjMwPC4+OzhWSDluSDtbRDVbPzlCOjVK +Njg+ODNKPDBVPDZaRjlWQzlLPDZDOzg6OzM9OjE4OjJAPTRCQDZFPjdDOzc9OTFEOjZCOzRV +Pj1WPDdUOzlSPTJMPDdIOjFLOjlbPzZURTxENzQ2OTI9NTU2ODNKRDd3akd5UkRFOTRBODNA +OTVSQTdySztzRj1PPDhHODc+OjZSQTdySTpjQDpTPThAODI+NzM9PDVhTjhzS0BrRjxdPzpR +RDVPPjloSDZ3RT1qSDlkPTlKQDZEOjk5OjZZQTVmRzxvRj1kRj9ROzc6PDE3MjU0ODk+OjhL +OjpKOjNFOzVDOzU/PDZAOjY4OzRCOjo+NzJSOz5QPTVHPDs5OTA/NDk3OzJEPDY+OjVHQDo9 +QjJHPDZFPjZKPzlcRTd4UUF3RDxfQjlSPjZPPjRKPTVLOTZbQjNrRT5dPjRFPDY5NjA/NTk6 +PjBJPTtKRTNSPT1NQjFOOTxFOzRWQD9vSTdpQTxUPTVEOjBCODlEPjhXQTdOOTlBNTg7ODM5 +OjQ6OS81OzU3OjU4QDI7OjU8Pi5NPThHOTdVQThaRDZhPjtGOzBKPTg8OTA7PTM2PDRGQzRP +PThIPTNAOjs6NjQ7OzdAQjROQDdHRjo/Ozg7PDc2OTBBOTc0PzQ7Pz42PDQ6PjwyOzRBQT49 +OTg8PDg6PDM+QDlTUENpUUN6Y06ZelioglvDmnDOroDXs33droXftovcsYjXtYPTq4HRpHDD +mm/HqHPHl2i4eVuGZkmhelWXdk+kelapfly8il7Im3bktYPry5/00Kr1waDet3ninX/VqmzX +qHXSqXLSn2/Kn2XEiWPNoG/br4TUoHLSp3rdrXPhqXrQj3C7hl+dZlOOcUycg1i8nWTKoXPY +rnrbuXzhtX/brnffrHHctXnbqXPPnGzHlGjAkly1gViSbkySa06GZkl5YkSCdVyIgWOBd119 +d2F9eVt9dmB9elx9dV13d1x6d1p2dl19bWB2d15+cmF1cVt7cmBzblh4bl5vcVF1c1pwcFFy +cV9tb1ZrXlRORTs3PTQ1Nzk1PTY8OTQ+OzY9Ozk+OjY7PDU8OTQ2PDI1PjE2ODNAODg2OTU7 +OzE4OzFCPTk3PjVCPjczOjM9PTo1OjU/Njk8OjY5PjQ4OzQ3OzI8ODg5PDM8OjU4PDRBPTBF +PDpAOjU9PDg8OzU6Ojc0OzA3ODo3PDRCPjxGQTJGPjo+PjZBODxBPDJEPjxEQTw+QDU8PDc4 +QDtEOzw9PjlDPTo/RTZKQzpjX0f0/7H8//X9//z////////8//T7//P///3////8//b3/+n7 +/+7+//P7//D////2//Tz/+n8/+/+//Pv+evn9Nb1/un5//Dd79rq89jt7eTg5dbb7tP1/+/t ++u/7/vb3//D0+ezs/uv0//D1/vHt9enz/fD2//L1+Or1++79//Xy//P6/+vs/97t8+bu/Orz +//P4//X///7/9/L//vv/9ezh5dB9VmJCTDp+TEN2TTtbQTxGQTVFQDZIRjZgQjxySjdoSD9t +SDxhRTZSPzQzPjNVRzdtUDqEVT+BWz+GVTt2UDxlRzVXRjpVQTVNPjpNRDZfRDVkSTFqSjpc +RDZQPzc+PzFTRDpiSDpqSjhpTDtaQzZAPDY2NzMzPjU3PDJYSjluSTlcQzhRQTRBOzRCOTQ7 +OC5DQDZHQjRZRTZSQTJMPzk6OTA7OjI5OzA4PTI9PjA/QjNAQjU9PTM+PTE+PjJDPjRSQDNZ +QDNMPThOPTVLQDVFPzRKPzZZRTRTRDlGPy4/OzU2Pi8+Ozc+RjN9bk9xU0JJPjE5Oiw/PDZS +RTR0TTxsRThQODY8OzQ4PDFPPTxsUDRjRTtIPjY+Oy81OjM3QC1gSzpwUDhpSD5VQTRSQTtM +QzJsSD1wSDtxRD5XRDVRQDg1OTM/OzZURDNmTDxpSz1jRT5OQTo2ODYyNzMwNjA2OjNBQTdK +QDZAOzQ9OzFAPjk4QDE+Ojw+QTFEQTdIQS9PPjhAPS07OjY3PS03ODRCQDNBPTtCPjg9Py87 +PTU/PTVGQTRWSjZ2UTx2Sj1gQzlRPThMPzhIPzJAPTJZRDVpRz1fRDlAPDBAPDcyPTA9QTI/ +RThQRDxLQTlPRjhLPzRCPzJWQjxwSDZqRzlLQTRDPDg9OzdBPTVVQzlQQDw6OjQzPTU5Oz02 +PDE8OzU1PDQ3PTo5Oi1DPzlIPjJEQDtPRzNbRzddSjlJPjhGOjU7PDY6PTEzPi1DPT1LRy9K +QTg6Oi42PTQ0OzBDQDVJPzdCQTtEPTQ2QjU6PDU7Pjg8PTI0PDg6PC41QTQ3PzM7PTc5RDQ6 +PDY3RC08RDpGVD1qVEZsXUSMdU+fiVa1lnC/nm/Gp3nMqHrSqYXNq3DLqXrJoWq5i2W8mGvJ +l2y8hWOtflaCXkiAcUuDaUiNcEyri1vCi2bHmmvgwYjs2abx367w0qrtvpjdrHvZqXPLpGrF +k2e9jGTLkmzOoXrPoXTHkGq7lGHAk2XNqGrQpXHJmmy+kmawfV+Va09+X0h5b0injV6+o2TV +qnvTsnHer3vcr3jbr3zYtHvUpnS+lFnDj2a5i1WcbE6NbEiJaUN1Z0uHeVeAfmN9dF58d116 +eVp9eV15dl96eF58eFp7fFyAcl13eFl7dGFzeWGBcllxdFh6dFtwdVp3cllza1lybFl0cFl0 +blZsYlNFPkE2PTgtOzQ6PjY/QDI8PTM9OjM8Oi46PS83PDA1OzQ4OjA1QDU4OTI8QDo6ODM4 +PTZDRDI8Pjk9PDQ1Pi46PTQ1OjI7OzA0Py89OzUxPzI0Ojc2NzU4Ozc0OjA+PTY+QzY7OzQ+ +OjU3OjI3OjU3PTAyOzcyOzAyOzU/QjlEQThBPzpBQjg7Pzg7PjJEQDw8RDRAPjo3QzM8RTk8 +QzhBRDw7QjlIRT5HSz5kW0Tu+Kv+//37//L///j////////////+//r2//D+//b////////9 +//H+//Lw/e31/+r7//H6//P2/+/y8On2//L7//vv9+3j++Dh/Nzo+OPh8eHi8tv1/+/1//P1 +//X6+ert/Pb6//X0/u/7//fz//L1/+79//f9//7///Hy/en3//v////////9////+evx8uf8 +/u71/u/z9fH1/uzu9+Tp7OeBVmZNSUB+VD1+SkFUQThMQTxAPTVFOTZaSTp2Sz9qQzpwRjpq +QTlMPTdEOjZQQTh3TzuDV0CFV0GKVzd6TT5jQzdXQDVbPzlFQTdSPjtZRjNsRjplRDllQTdL +PDJFPTRPQjRlQzpkSTVoRj1cQTc/ODwyNzU6ODI2PzJWRDVnSjdZQjpSQzRDOzU/PTFCOzVG +OTVUPjpURDlYQDlDPDVKODY5OjVAOjY2PTFFPTc7QDBJPTo9OjFAOzU9PTFHPzlUPjNTPDRQ +PDpSQDZNPzdDPTdNPDVdQTlZQjlDOTc5PTA7NzY2OjFCQzx2b0l3V0lBOzNFOzg7PjBYQjZu +TTlzSD1KQDZGOjU6PDJPQjhqSThgRzZMQDg6PjY5MjY9PDdhSTl0TjtpRDpTQzdRQDNXPTts +RzF4S0BsSDhlRT5KQDE7PTk9PDBWQjhiRDhmSD1fRzlHQDQ+ODI0OTQ/NjY4OzNLPjlFPTNG +PjVCOTY8ODRBNjc+PDdFOzdBNzJJQDdIQDVJOTYyOzU2OjczOjVCPDM7Ozg/PzdBPTo8OzBA +PTNAQDdZRjpoTjluRj1ZQjRTPTNJQzdHOzpFPDZaRzZnRz5XQzZFOzU9Oy86OzU4OzFGQkBP +QzZPSDpPPzhCPzNHOzdRRjRsRDxiSDNVPjhAPzM+PzM/PDJXQjxKPjM4ODg0PTA3PzcyOS40 +OTsyOzI1OjszODA9OTNJPDdIPThWQj1cQztZQTZLQDU/QjE8PDYwOiw5NTRAQDJPQDtBPTZG +PTc2OzRAPDk+OzNKODlBQTFFQT05QjJAPT03PS07PTw6Ozs4PSo8QTo+PTc8PTc8ODk2QDdB +Qjo4QTNGVTxoTz5oVkF+dEmeflevkmPDo2vBomzNpXrBpHbHmm+tjWCme12deFauh1uwhl60 +iF6teVukd1mOWkV3T0BiW0SAc06sjmTSrnneuIndvonfxI/tyZbdsX7UlXS/k1q5fmauiVu5 +lWy8hFq5imK3fFueelWZfE+jdVOfeFemdlClh1uOclKMeVOBYENtWERnVEBkW0CTgFHCo2/W +sXbUsXvkt3ratHreuXjOmXKwi1jDkV+6gVuZZk+IYUaKZEV7bkaEfWF9fFyEeGV6e1qCdVp5 +d1d7dF56eFyBdmF3eFp/clp4clt3d1h7cF96c1l1c114clpycFh1blVzclx2bVhyblhycFln +YU1IQEA0PDQ6PTY3QDQ+OjU2OzI+Pjo1PzU3OzQ1PjI7Ozg2PTQ5PzE1NzQ2OjI3PDQ3PDg/ +PzgxOTU2OjI+PDY4OTQ8OzU1PzE3PDUzPTI3OzkyPi88OjMxODJAPzg/PTNEPjY/PTQ+Nzo0 +PzU7PDg4OzY6PzY4PDg6PDVBPzxLRjVDRDw9QTlBOzY9PTZAQTRFQjs9PTdCPTc3QjFCQjw+ +PTZFRj9ASTxKSkdbXUT3/7D///////z6//H4++z7/+////////////7///n///b9//n6/u36 +//P///n////////6//j+//n+//j6/vji7ODd69fx/Obm8eXc39Pf6Nfl6tnl/ufy/ent++33 +//Lx+e71/+r0/Ov3/uv9//n+//D2/vD1/+nt8OPz/vv///P5//P3/+7w/+nt+e7s9+r5/fjy +++ns7unz8O36/PP7/+2AWGlIS0B8TEB8SkBfQTxNQTdNRztARTZdSj5tSTtxQ0NxSD1uQTtI +PjRCPTxJSDt1TECFWDyIXEKHWEGCUkBrRzpTQTxNRjVKQD1PQD1eQTpoSDtvPzljRDhSQj1G +QDdSQTxiSztqST1nRjhhQD9APTI+Ojk1OTdCPTpURjdrTT1dRTZVQzxJOzg8PzI/OzlEPjVS +PzlXPjtWPztMQDhFPjFDOzg2Ojc8NjY6PjdIPjk8PjZDPjk5PDNJNzo+PzRYQzxVQzhbPDtS +QThMQjdGPjpKQzhZQTtSQzVLQDg9PDc/PDQ6PDRBRjVxZFF5W0hGQDtCPjI/PjpWQzZ2T0Bw +STxUPz9BOTU+QDxQRTVpR0BjRj5JQDNCOzQ1PDRDQDZgTDp5Tz9oSzlcQTdNPjhcQTxtSjh0 +TD5rRUFgPjtPPTs9OTVGPjpcQzpnSTtoTD5gPj9IQzc+PTU3PTQxPi81PjZLQjlLPThEPTBD +Ozs8PjVBOjg7OzFBOTU+PTJHQDpIQzo/Pjc5Ozo9ODgzPDY9PTNBPDpDPDc8Ozo/QDU/PzlB +PThYSTpuRkJrSTldPjpLQTlMPjhEQDRKPTpTQzliQ0FSRDxHPT06PTQ+PDg5QDBGRDxJRTtO +QT5PRj5PPzlMPThRQjttSztnRj5RQDpIQjk+OjZDQDtWRzlQPjk3PTE3Ozs1PDc8Njc3PTQ8 +OTs5OTM7PTo7PTRKPT5MOzhXQkBjSjpcQjtKQjxFOjZEODk+OTQ4OzY+Qi9SQjlJPDg8PzRB +Njc3PTZEPTlJPTdQRT47QjJCPzs4PDE/Pzg2Pjc/Pzw2QTVBOjg6Pzo6Rjs8Pzk7QDw4QT86 +OjhETj5wX0peWkd7ZkmQfVanh2K8oHG/nXO/nHW9lnCpglyTfl2aeFajdlChf1eddmCXdlSb +clqVc1WOZkx0WEplRzZVVUB1eka6pnTQpnTGpnHKsnHSrXrOm3CygmGdhVmqkmacaFiNflKi +flWQbVCXYk6CWkqCa0p+XkeTbk2EXUqCaUeEY0VxXEZqTEFsVkZbTkBWTz9hXEmsmGHYrnfd +un/eu4Pcs3zOrm/AimWpilO+mWW3hF2YbFCMbUuCZkp3ckiEgmKFe2V9eGV/eWB7emB9dWR7 +e11/fmF3dlt7cl18eVp6d2V1e1x8cmJ6e1x5cF5ycV+Ddlxyclt2cltxc1lzcFZ4b1ZpXlFE +QDw3Pjk7PjM6OzY7PDM7Pjw5PTpAPTo4PTY8PjY0PjE3PTk2QjU8PDc1PTQ+Pzo1QDVDRD43 +PTY8PDY2QDg5PjY9QTc4OThQUEk2PTk2QzU1PDY3PDc7PDQ7PTI9Pzg+PzVDPTs7Ojg9Pjg3 +PzJCOzwwOjU7PTo1QDpNRjtERTpLRTo8QDk9QTRFPz1EQT5GPz5CPDg/QTw9QDtEQzlBQztC +QzpEQz5FSTtlYk7y/Kj8//n///z///////////////X9//j8//D////+//f5//D9//L///79 +//jy/+z4/fD6//L9//H5//T2/+37//j9//jv/Ord9djv+uXs/efp9uX7//n1/+/r+eny/Pf4 +9+30/uvv+e3t++H6//T3/fH4+/D3+ej8/vfy/ev48enp8Nvo9eP5/fb+//v///v9//T5//T7 +//f9//7////57uN2UVxISkWAT0F3TT5lREBGPTpEQzxBPjNiQkBrSjhuQUJuSDtxRj1RPTRE +OkBIRDVzTEJ7VT+HV0KDXDx9TUNhRTtYQDZSQDRLOjdNOD1fRDdpRzlrQztgQTlSPjhEPjVQ +PzpiRTptRj1pRzZcRzo6OjI6OTgzODE8PDtRQDlqTEBcQzZRQztFOjk+ODI+PDg9PS5OQTdU +QTxXQTtLPDZBPDQ/OzY0NzI5PzU5PTBGPThAQDQ+Ozk4OzNGNzs5PTZYPDtQPDJUPjlMPTVJ +PzVGPzdIPThaQjpZQjZJOzs9ODY7NzU6OzVAPjZyZEZ0VEdIPTtDOTRGOTlOPjVxTUFvRzhS +PDxBODA/OTlXQTRnRj9dRDZKQjs+OjY4NjA9OzdgSTV6TTxhRDhXQDtUQjhWQzpuTT12R0Fr +RztiQjtMPTo7OTVGODhYPzdnSjphPzdbSDpDODg7MzgvNTkzOTIzOjdFPDVGPzg7PjI9Ozk3 +PDQ8Ojs0OzM7OzY0PDA+OTg0NzU7PjUzOjY3ODY5QDk7PTI3PTc5OzY2OzozOjQ8OjtDPTBV +RTdtTDtgSjtYQjtFPTVKOjxARDREPjpSRDVkRj5TPjVKPEA8Nzg9ODk9QS9GQztIQzhQQT1N +QThJPjhDQTZTQDdqSz1kQDhOPjdBOzg/ODNAOzRPRTlLPj46ODI4Nzc2OjY6NTozNzQ1OTcy +PC45Nzk4NzJLPz1HQTNZRUFfRDZYQUBNPTtCOzZAOzU7ODQ3OzU/PjZMRDlHODhBPDo8OzU2 +Oy1GQDxLQDdHPTw7PjI7PTozQDM/PDszPDQ6QDczPDU8Ozc0PjVAPDU6Ojk3PTc6Pzc8QDg9 +Qzl1Y0tlVUeBaEmJdVSmhGOvmmq9mHO8l3G0g2F/akmBZEp8ZEmBZ02AYkF8YVRrY0WAZk58 +WEdqT0dfQkVbTEBkSEVLTDtsbUuPf1aFdFaBb0yRf1qLc0t7ZVB1YEeHfFaGaUxoU0h4YUaC +W0x8X0dyV0R5XkptT0lzVkJmWUJ8XkluWEZpWEJjS0JRST1UQkJLSTxgT0KJkFnRtXbgun3i +u4TasXrOr3XBi2y6k2G/kWSwhliQaU2IZ0Z/YUV7dk9/gmSDeV57eF9+dGJ7emB9d2N1d1x9 +dGByel57emR+eF18c196c1l7cFl0dFl4b1t1b1V4cF9wblhzblhyblt0cldvalFiXFFEPzw4 +PTk5PTQ1QTQ8PDQ+Ozo7OzM9Ozg0PTE7PDcxOzM+ODc3OzI/PDs2Pjc9Pjg3OzFBPDw4OzM9 +Ozc4OjdANTY5Pjk7PjQ+Sz5AQkY4Pjc3Ojk3OzQ5OTk6PDY7OjdCPTQ+OTY2QDg8OTc1OzVB +OTo0PDc9OTY0PzFMOzpDQjlHPTw7OzxBPTk+Pj5IPz8+Qj4/Ozo/Qz09Pzk9RDxDQUBBPzxF +SD1ERjpmXUrq86X6+ev9//j///////f///7////////////////////7//j4/+/+//j///v/ +//////z///f9//P2/uvr9ubl+ebq++bi8+HY7tHh89rb7NjW4NLy+/D0/fb+//r2/+/p9+Xr +8OHs9+vs89/r/uj8/vf9/+rx/+n0/+////35//L9//z////////7//X0/e77/vL///f49On5 +/+7y9+vv8uZwU2RPRDiCTEJ8S0FYQjxMQDhCQDlKQTdVPjlzRDtrRTt1SDpmRjdYPDU4ODVJ +QDNtTTyFUzyKV0SDVT18TEBjQjheRThPPDZLOzdHQjpkPztkRjhsRDdlPTdRPjRFOzZOQTRm +RztsRzRpQj1ePzhAPDc7Oi80PjI7OzJPQzVlSDdgQjRRPDhHPjM/NTZAODdFPjdMRDdWPztW +QjNOPTg/Oi87PDQ6OzE0OTM6PjJGPzZAPTU7OjJENzM5OTZCOzFOPTVVQTZTOjhSPTFTPzg/ +OzJQQjhYSDteQTpHOjNEOjk4OjRCOTY9OjB2Y0pvVkJIPDk8OzVCOzZTQDhzUDprRz5TPTVG +ODc8OTRXRDZqSTpZRDlOPjU/OzA5OTQ8PzFnTT5yRzhoRD1VRTBZRDpRQzduSzxoRzx0RD5Z +QztROzk9OzQ7OzRcQzRlRz5jQjpaQTpGPDczNjczPTE2OTA7PDBJQDtAPDVBQTk1PTA+PT44 +QDNAQD83QTA2Ozo1ODQ9Njk3NzEzPToyNzM0Oiw1Nzc0OTQ6PDg2Pzc8Ojg8Pjg/OzRNRzpg +Tj1bST5LQTVFOzw8Oy5BOzs9QTNRQD1WSTdcPjpFOjpFPDg1OTQ8Py9EQD5LRjhQRDtOSDtH +PjdBPS5RQzpnSDZkQjlKOjRCOzZBPDVAQDRWRT5PPjg9ODgzPC45Qz41NzE4Ozk0OTI3Ojk6 +PDE4PjVHOzhKQDdZPzdfSDlcQT5EPTNCPTpDPzQ6OTcwOzI8QDhLQzRGPzlHOTQ7PTs6ODRG +PDxPOjVDQDhAPTY4QT1APDY4PTY2PzY4QDQ4Ozk+Ozs2QzE6PzU1PDM8Ozg3QC87PzU2RS1j +ZUxoUzl9cFGDbkaliWO0lmG6mHe3mGmJYVNvXEVqTkNiT0plU0ZcU0RgVEVeT0FoS0RbTD5c +RENVS0FfT0R3Wz5mS0BWRDphT0VyXUhvU0pxUj95Y1OHbE5lUUBtXkhyV0JqR0FdVz9yVEdg +UUdwVERnTEFjT0JkSz9iTjxoUUdjVUNnST5ZVTxSRj1BRDVORD5TTDmUjVfRtHrdtoLcun3Y +sXfHqm7EmWnBnWrCmmeqe1uNaE2HYkh7Yz99dVSAfFyCf15+eWF9dV99d2F4dGB8eV11d2CE +fF9zdF1/cFp4dF1/dV91dl57cl91cl13c1t1cFl2clZ0blhzcVRycFhxblVoXlBGQztBPT00 +OjQ+PDQ2PTU7PDI+Pjc8PjQ6Pjo6PzE9Pzs2OzU4Ozo5PTI5OzlBOzI6PDg/PzQ6PzZDPzc6 +OzI8PDU1PDM6PDhIRzc+PDs6PTU5QjE4PjE9OjQ4Pzg9Pjc+Rj08PzM1PTM6PDU8PDY6QDM3 +PTEzOTk5Oy9FPTdFQzdEQTxBQDc+Qzo+PTlFQT9CQDo/Ozw0PzlGPTk8QThGPjxDQThFRDxJ +R0BoYkf//7v///////n///v///////////////////////7///j9//r9/+////////////n/ +//n////4//L9/vfz/ufy++vr+ePv9/Df79X6+e/2/evt9+zu++n3/fDt/evt/ev09/Hw/Or9 +//7///n3//H9//n29fH0/Ovz/vL3/fT///bt/+z0/uzy+ez2/vX4/vH9//H0/+747vH5+/D7 +/vHr9tt0UGZMRz2GU0V8SkNkRDhGPjhIRDhEPDVYQzpsSjtzRz5uQz9rRzpMQjNEPzZCRTNv +Tz2BVzeDV0KAVDyCTj1mTDxaPTtSQDZKPjlPQjZhQTVpRjRlRjhjPzlNPzhCPDVRPTlcRTdp +RThkQzZiQDc9PDI8NTUuNzM/NjhOQTVjSTtZRzVXQjtEPDNEOjhEOjBEOTZSQTVYRTdTQjlM +OzZDPjQ8PzI5Ni82OzA2PDM/PzhBPjI9OzI8PjJGOjU9PTZUPjZRQTJcPjlOQDNRODk9PDFR +QjtWQztfRTdMOjU+PjE+ODY3OjE9PzZvYUd6UkhDQDlAOjM8OzZURzd0UUFwRjlTPzc+QS4+ +OzhSQzRrTT9cRTZIQjpAOCw6Nzw/ODBeSzx3RzleQzhbQzpSQDhYRDZsSjlxRzdqRDtjRDlJ +PzpBODhDOjldRThnSj5jQTdYPDlDOzc7NDcyNzI5OTQyODlGQDk7OThAPzc2PDc1QDY3OjM0 +OzE6PDU1OC82ODkyNTE1OzYvODM4OzUzPzk3PDE4PDY6OTc4NzY7OTQ9PTY6PDM/PjlEQTRB +Pzs/OjI5Ojc2OTU6OTs/OTdAPzVLPTpEPTlEOTs8PDE6OjY5Py9HQjxHRjhQRD1LQzdKPD1D +OzVPQTlqRzpkQDhMPzJGPTZAOjM8PjlUQz1MPDg5PDU3PDQ1QTQ8OTcvPTA3PDYzOSw2OTs0 +PjRKPTRLQDJaQzlZRDNaRT9EPzZDPD0+PjQ4PDc2OzA8OTNMPjZFOzM9PTg7Ojk4PjFEQTdN +RTVKRDc8RDM3PTc0PzVAPTozPTFAOkQuPSo7PTs0PTE+Pjo4OzM9PDk2PTs8QDc+PDhMYUp4 +XUZtakyHd1iiiF6yj2u4lm6pcV9zYUdiTz5UTD1MSz1OSEBPTTtUTUFZSTxZSEZTRjlXS0FP +SjVQSkVoVT5jTj9WSkJcT0GDe1KCY0JlVEFhVEJ/aExpTjddSD9pVUNeRkBtWURnSUBlUz1t +WUFwTkFYTT5kTD9aT0FwTz5vU0SKVT9zTkBnSzlbRD1KQjhYTD2kk1bPsHDauXvcuHfJp2rH +pGq+oGnFpG7BlmGldFODZ0d/Y0Z1WUSBe1qAe1+BfGB9e2CAeV17e2F8d191d117dlp9eWB6 +eF51dF57eWJvdVd9dFlxc1d5c1x2c1R5bVxzcllxclt1blhzalJ0blRoWkw9Pzw5PTc4OzA6 +QDg6QDU6OjU7PzU7PDI5PzI8Pjg2PjI0PDYyPDQ9ODUyPDI+PDU4PjE/Oz01PC49OjU0OjU5 +PDc4PTI+PDs5QDU8ODc5QTc5OzE1PDc8OjY7PzU9PTU/PTY+OzY0OTQ8PjE4PzA7PDcuPTM3 +PTQ1PzBGPjpBQzJHQDs1QzI/PDk7PjVHQTo/QTw9Pzw6Pjk5QDdBPjo9QDpDQj5CSTpMRj5o +YkTy/6n///////////////v5//b4/+z+//r///z///7////9///8/+31/+/3/+z9//P////z +++3y/erx/fDn8+Tq+ubk797b8drn/Njp8+Le5NbX3c7r++zp8ubl9ur0//T///vu/+3z/O30 +/uz2//zp8uT9/fv59/Hw/Ojs++Ty/+79//7z9ez1/vLx/ez6//vy9+f9/vr7+/D9//v79evk +39dqTlxBSjuHTkJ9TT9sPzhJRDtGPzdEPjlSQzhsRj1tRj1yQztpRTZSQjo7OTRHQDdtSDR9 +VUCCVT6IVD54Tz1kRDhVRDdUPTFNPjZJPTZcQzhoQThmQjpiQDpRQDpGOTRFPjhfQzlgSDll +RT5cQjdBOzUxOS86OjY0PTJQQzpjSjtgQTtOPjRHODs6OTE9PDQ+NzRQQDhURDlXPzdMPTVB +PTU/NTI0NzQ4Oiw7OTM+OzdEPDY7PDA+OTg+OzRKOjlJPzBXPTpOPzVZQDhIPjRFQDRKQTZe +RjtWQTZOODU+OjM8PTc6ODdAOzFvY0NzVEhGOzk+NjM8NTNLPjlvSztwQz9OPTZAOjk3Py9U +PzpkRzleQTxEOzRBOTowNzBDPDdeSzl7Tz5dRDlbRDlWPDpdPzdzSTt1R0BvRzxVQTxIPTc5 +ODVEPTFbSThhRDheRzpTQjhGOTkyOTAyOjcvOS04P0E3NzUxOjUzNTQtPDQ1OzQwPi8wOzIt +PDAyOTcuNjIyOjIyPDMyNzcyNTQ0NiwxODEzOTI0OjYuOS85NTYyMzI3NjUyNjc+PTk2NjM5 +OzkzOTQ1Oy8zNzUyODU6ODU7OzU+ODs1OTQ8NTk2OzU6PjdARTtKQTdHQTdKPTlGPDlGPTdS +PjpoRTVjPjpOPTM/PDg5ODFCOTpTPzVLPzs7NzEyNTI2OTcxOTE3ODc2PzY7Nzg1Oy82PDhG +Py9PPT1cRjdhQz1YQTZDOjtDQDQ/OjY3OTIsOzBAQDZGPThLPDk5OjY8PzE8ODhGQjRRPzVD +QzY+PTsvPTU8Ozc2PzI+OT41PDQ+OTw0QDE3PTs4QjE/Oz84QDQ3PDg/Qjg7PDlCTz1xZE9i +X0uSfFGskmmniWq3l3OlclRoWUdPSEBDSjxDRj1DVjxSRzxESDdYST9ISjVRRkBFSDhJRzxO +UDdiSz9RRkFPTDtcT0aAa1ecc1mEaE96VkZ7akR5WklxU0BxSENNST5kXkdbTT1eVEJuTkdq +S0FmR0FSSzttTUNoTj1+V0x/WD6RZ1KlcFVyWEZSRzhWVEOsl1/aun7atH3WsXnSqXXCoGXE +pnTInGe6jWCidFaAYkKFZERuX0mHfmB9emOBfGV9fV6Ce1p5dWJ8e2V5dF98dV98e115dFx6 +eWJ2c1x4cl57dVx8dV1zblp2altzdVxyb1pwbVxzblZzb1N1bVJhVlFBQjk3OjU0PjU2QDg+ +OzM8PTk8QDI3PTo/PDg3OTIxOjIzOTE0OzA4OjBBPTY6OzFDQjo5QDk9Pzg0OzE7OzY3PTc3 +OzQ2PzUyODM+QDc+Ojc7PDI5PTk4PDA1OTE9PDFBPDU7PDI3OjcyNzA/Pjk1PzE9PTsxPjU6 +PThAQDNKOTlAQzhBQjc7QTc9PzZBQDdFQzg5QDlBOj03PjZDQjpEQj1BQzdBRj5HRz9nXEfu +/Kj9/+////v///z///j///j///7///v////2/+77//X6//T9//P6//b7//P7//T8//T6//n3 +/vTr9eTy/uf+//f1+urn8+jf+dTh8ODZ5dPg7df7//n+//7z9enr8Ojl++bx/+/6+Pf//fL9 +/fL8//v5//X+//z/////+fXy+uv+/vv5//P///r5+/Lz6uHu++rx8evp69/1+Ofl9eHu7uNx +V2hKR0R/VEeHTkZoRT9RPT1FQDdEPD5OQjlwQ0JrRDxwSUFrST1VQTs9PTVEPjhoTD5/WkGK +WUSGUz98TzxnQzxTOzhSPDxLPThPPzpXRDZoRztqQjhoPj9OOzlMOTpJPTBgREFnQjlsRD9X +QjZBNz4+PTY3OzI8NzlRQDhjRTtcRzxRPzhKQDhBOzdEPDhCOjhVPTlXQDxYQD1OPzdKPTo4 +OTI/OTcyOjNBPzZAPzxFPTo4OjFDODhDPTtCPjlKQDdTPzhXQjtTQDROPDRAOzROPDlaRjhe +QDpRQDlEOzM9Ojo7OjRCPztwYUVzVk5JOzU/PDw+OjFRPjp0TD5ySUFSQDpAOTBAOjZUQzln +RjpURTtGPzo8PTU7ODQ/PTdlSTxySj5iPzdVPjVVRDdbRzpyTTZzSUJ0TEFgQT5JPzhBOzlE +QTVeQzZjRz5hRjxVQjo/Ojw4PEAvOC83PDcvOjY1PTYuNTc4NzgrOzE1OjcxOzc2OTUvOTUz +NjMwODUyNy81ODg7NjYzOTkzNzIzNzcyPDMsNjM0NTcuNjI2NTotODE0NTkzOTQ2NTszOTI5 +NDswPTE0ODgxOjI2NjUwPTM1PDgxOzM3OzkxODE3Pjg7QDdEQENOPjtMQjpCPThGQTtMRThp +SD5fQThQPT5CPTE7Ojs7PCxVQTxMPTc+OjkzODI+PTo4OzE4OTw4NjY6OTk5OjQ7PCpKPTlP +PD1aQzdgRTtZQDlJQDhEPDlAOTYzODI4OTE5PzJMOTtDPDVEPT82PDM9QTw+QDFYPzlDPDdD +PjsyPzdAPTk/PTk2PjM8PThAPTU2Pz01PjA9Pj05PTQ4Ojg9QTM3PTc8PTQ5QTdrY01yVkaH +f1qjoW23lHK0m2W9gXRmTDVDPkJDPzdHQUFLRT9GRz1QSEJKRT5NQTtGSzlJRUBQSDlRVEh4 +TD5WR0NUVjyXdGS1kGbDinW7hmibeWDIi3OzgmulaFd/XkxiRj14YUxtUUaIW02CVEeNV0ho +Rz1HRT1WSD+PaFiZdFS2gGbNpHqxg2aebVNvTkt5ZkfKqG7Wt3zTrnXUsnzNo23GqW7OqXnH +mmm1g1eabU6DZkd6Ykt6bE9/fGGCe2mAfF6Cel58fGF/eWJ4d19+dmN6emJ/dmV6el+Ad2d5 +c1t9dmF7clp8bl5wbll4cFxwcFx0blh0cld1b1dzc1dxblxoV1FCPz42OjQ1OTc0PjM8ODc8 +PjhAOTo8PDNAOjs6PDU5OToyNzE6PjUtNzRBPTs6PTY8OzFBPTdAOTk9Qjk8PTk6PTc7PTk0 +OjU6OTc4ODM+Pjg0OjE9OjwwPDVBOT01PzRJPkA3PTVBOTw0ODVBQTk2OTY7PDk1PTY5PDlE +QDxJRTtEPTo/QT1DPDpBQjtKPzs/Q0E6Pzk7Pzw8PDg8PEFBPzlDR0NIRD1RRklrX0Ht+bL2 +++j9//r///////////z8//b+//v////////////////+//j+//j////1//Xz/+v3//P+//n/ +//f8//j3+e3y+eDt/+zl9tvf5t3p+uHg7d3u9+Ty+PL1//79//n7//T4//z//+vz//Dz/u3+ +//v1/ez0/u/6//b///3///n///ft/ezw//H6//v///z////7//vz+ez+//3///Xz8OVoV2BI +RUF/WUOBTkBlRzhSOz5BPDRHQjlURT5kRjxyRkBrRTppRDlTPzJBOzREPTtgSzt9VEGFWUGH +WUF4TzxrRD5TPTVTPkBLQDVPPzxYQjJqRj1nQDVkRT1KQTJKOzpMOzhfRDtjRThkRDdVPjZC +OTQ5OjY5PTM4OTFLQzlfRzhhQzdXPzdNOjg+OzE/OzY6OzRSQjlPQThcQDpGQDRMPTNAOTk8 +OjQ1Pjg9QDRBPDhBQDlAOjM/ODdBPjY/PjZMPDRRPTlUPjtTQjxNOzVFOjZLQzZeRT5bRDZQ +Pj5DNzI/PT07OTQ6OzduXkJ2VklNPDpAQTZBOTlORDZxRjpvSThaPzlAODdBOjlVRDhnQzpV +QjdDQDU9OjU5ODA5PTdoSjxsSUBgQzdWQjlaQTphRjVsSjtwSjluSEFcST5HPDQ/OjhIPjZZ +QTVhRT5aRThNRUEyPjc5PjQ0OzQwODExPjY2ODEyOTc3ODI0OTYzOTU1NjcwOzQqODwzNjMx +MzM2OjMrNzMyNzcyNzU1NjUtPTE3ODYxOS40NzkuNTE4ODQvODM0OTcxPTI1OjctOTA3Njgv +PDIzNzU3ODQvOjcyOjMvOzY0OjQzODAyOjEzODg0OjZAOzhDQTlOQztGPTRDOzdIQDNoRT9c +RjRPQTo9PDA+Pjw7PjNTPkBOQDc7Ozk3ODc0OS87PDQ4OTg4ODY7PDQ0ODQ7PDRBPDdPPzlX +SDlfRDdRQjRMPTs9OjNCOTg1OTI+ODs4PTNRQDpCOzdFPDo9PzY+PjRCPT5PQDtJQT07QzQ6 +Ojk4OTM6Ozg4QC04Pzw6PTc6QDQ6OjwxPDg9PDk6Pi06QDo1QDhAQTw3OjdQW0VyW0x2dVCj +l2+7nX20nG67mnKEREBJRjtPQkJjUEeGVkxhSzxRQkBQRTVQR0FVRTdFRTxNRzdWT0GAXEpu +TEGEXU+rf1u3j2Gvhma4iWW5k2++i2yyhWW8hmjEf228fGjQqYnSp4HCn23DnnesdmGdbWJz +SE1tUT+ZaFG6fWDSr4XatoLHl3XBgG2FXkyokV3TtoDauIXVqXLLqHTInGrJo3POpnS+mWax +fFuHaUh7ZEtuXUeAeVmDfGCAfmV/d1yCfWB+e1x/eV94dl98dF19el58dFp5c1Z+dGN/dV51 +eVx3eFt0clR2clt9b152cVR1bFtscFlycVpxblR1a1dfWE1FOzwwPzE5OzYzPDRCOzk7PC8/ +NTg5OzU3OzY5OTc6OzE4OjQ1OzM5ODk6PTM5OjM6OzI/PTc+OzUyPDQ/Ojk2QTU/PT00QThA +Ozo0PDNBOzcqPjE/PTowODc+OTU6PTQ/PDU8OzMzOTA1NzM3NjQ2ODExOTI2OzU6PjJGPDhG +PTpBQDRBQjo7PjJDQDxERzZBPj8+QTM+PUE4RDM9Oz88RjFBSUFFQz9FSz5rZkj2/7T+//v/ +//z9//f2/+3///7///////3////////9//z4//X9/+/9//P3//Dx+uv4//Pw/en1/+73//Ls ++uHl9N/1/e/j+uHe9Mzh9eLc7tTi8Nj1/PHr+ePm9uTv9+79/vz///3t8d7o8uf2+PH1+fbr ++u/9+/z5/ujy+PD8//L4//Xx/+/7//X5/fXz//Xt8+r+//v99fH4/e/8/O79+/t3VGZIRz9+ +TkOCUDprQUJLQj1FNThKOzZJQjxoST5rRz1yRUNiQztXPj09QTdJPjldSDl+Uz6BVkWGWj58 +SUBmRDhSPjlQPzVLPjhKPzhePDthRDdrQThkPzRUOjVHPDdRPDdbPjppRjthQjpSQDdCOzU1 +PDU2OTU4OzRMQD1aRD1cQzpVOzVJPDZEOjZAOTNJPTpDQTVWOTZRQTRTQDtBPjBAODg8ODg5 +OTI2OTRAQDpDPDU8Ozg+PDc+OzNBOjhJOTtWPjlTQztXPzVQPDZBQjdKPzxdQDdfQDxTPjhG +ODk7ODFDOjU7PTRnV0NtVkNRPDg5NzVBOjVJRDdySD5rRDtWPTxGPDlAODRTQjpmSjhXRTZF +OTc7NTM7ODRAPzdrSDpwTDtlQzxWRDlfQDtbQTRzRz1zRztxQ0JVQDhNOzw7ODVHOzdVPzlk +Rj5EQTg4Pjc1Ojc2PTQzOjQ1OTs2NTk1NTUzMzQzOjUyMjI3OTowODM0NjEwNzAxNzYxNjA2 +NjkuODA2Nz0zOC83Oj03NzE0Ozs1NzQ1NS8yMzQzMzc4NjQxNzc4NzM1NjU1ODgyPDM3NzU4 +ODcwOzU1NjcyOTY2OTUtODI0OjUrOjI1OjUsPjI6PTg5PTdLPzhBPThCPTVQQD1lRzliQT1R +QjhDPDk8Ozk9PTZRRTlQPjk+OjYyOzc8Pjw5Oi86NTs5ODE2OjoyPC45PDNHQDNSPz5bQjhb +SD5VPjtFQDxCPTc7OTg8ODc2OTQ+PT5JPjhIOTxAPDI9PTs5PzNEPz5UQjhKPDlBPjc1Ojo7 +OTc3Ojg7PTc9OzhBQj02OTs6Ojc6QDo6Pzc7OTk2QjNCPTs0PTE9Pzk/TThyYk9nZEicg2Gt +rG6+onnDp3euYGFgRzldVEh9dFOufmetdWObYFZ+T0toQTpBQD5TPzpeU0OWaVaMalSteXSO +aEyudma3goKuc2WqelnOk4Pho5nXo4Pj5qLr0aHkzZPr1KrlwZq3kmK0qWmnnnTGqYGXXlOg +Y1XBf2LVpXfctHvWtHzdqXbXpXiwdVzGpm3htYDZvITWqn7TsHXNqHbDo2fKmHS4j1yZd1uC +ZEd/ZExtYEqFfVeEe2SIeGWDeGKAd2CBeFx5e2B+dGF/dmB4d2J8dFx6d1p7dV12cmGDc2Jx +c1x8cmB1c2B3dGBub1l6blxvbFt6cFpzblp1b1dlVlM/Pjs2OTs5OjVAPzk6PDRCODo8PzpB +PDk6QDo6ODU7ODk7PTY6QDs6PDU/PDs9OzRCOz09PjY9PDtAPjo6ODNAOTo2OjQ4OTUzOTU7 +PDk9OzhLNzk3OTY9OTk6OTQ+OTxAPTlBPTk2OTszNDg5OTo3OTQzOjcxODhBPDlEQjhOPjZC +OTtCPTxAODtCQjRKRDs9QDpDPD46PDVDPDw/QzxDQDxBQzpNQj1KST9sXU3q96n+//j///// +//v///////////j///7///72//H2/+r7//z9//P9//j3+/L+//n7/Pz6/Pf9//P1+fLt/Ojw +/fHj9tvn8OXZ6tHl5uDh79vg6dvr++z6+fH5+vb3//Dy/+fl/eLy9+3x9+Tm9ePq+eX0/vLy +/+/4/e77/v3///v18enp9enr9ufw/O7///v///f///ny8+n9//D1//Tp8t9xTl5IQ0V/U0WC +UD1nRTtNQj5MQjhDQTdQP0BvST54R0BzSD1xPzxbQTU8PjdJQDhbRDmCUz6AVj6JUj96ST1r +SDxQPTpWPzdKOzdQQTJaQTRrPzlnQDtaQjVSPTtGPzZSOjpXQjRnQjpgRDlcQjc+ODU5NzU3 +NzYzNi9FPzpfRDZdQjlXPDJHOTdDOzg+OjhEOjVNPzdaPDlVPz1PPjlCQDNAPDY3NTc7Nzs+ +OzZDPjk8PjY/NTdCOTdFNzdEOjdPPjRSPTdWOD1YOzpSPDhHPDdKPjleQTZgSTpVPzRGOTg/ +ODQ/OTY7OjJlUz5tUERNPD09OjRDNjhJPTZxSztvQz5TOjg+PzhHOTlTOzxnQTxVQDxGPDY7 +ODY8PDJCODpfSjdwSDpdPjlaPTNTPjZbRDZyST1xQzdwRj1XQzZNPTlCPDdKPThSQjhHPUM2 +Njg+ODYvOjc8ODYrODE3MzUyOTMyNTYxNzMzPDQ0NDkwODUuPzMvODAsOjIzPDgxOS40Nzgu +Ny0tNjUwNy86NDkwOC03OTguOio3NTwxPDA3Nzk0NjM1Nzc4Nz0tNzU4NTIxNjQ1NzgzNTMx +NzQzNzU1NTM0ODUzNTM2ODUwNzU2OzoxNzY7OzkxOzU/Ozk4QC9GOjpEPjVpRTdbRDtRPjZC +OzU8OTQ/PDhRPzdRPDw3Mzc3Ojk6PDYzOzgyODQ3OTc2OjU4NTc6QDZIPDVSPjdaQTZdQ0JR +QTdNPjtDOzg/Ozw7ODIzPDFBPjVOPjVJOTc/Pzc9OTo4PSpJPD9SQDRLPz1APzc3QEE5PzM5 +ODxAPTY2PDU/Nzs3OTs/QTc3Ojg9PzQzPDc+QTs2PDRBQDg4Ozs/QTdgWEluYkmNfl6vmm3D +qom8pXXNo4mxamKGZlt/fVS4jXWth2K2jnalZ0+ZVU9tTD1KTD5da0ylmXupqn3Lw5fKrIzc +zbDk1q/ksJzey5nx57T10cHz2qzy5bD02rTexYbo15fhv5XZsJ6/kHSyhWuriVuyd1/CkGvP +pXfbs4DguITbtX/brH3iqn/SonbWsnbgtn/ivYXbtXnPp2/KnnDBnGjDk2ergFeTa1R9aUV9 +XUx5bkuIemd+el+GfWuCdmOBe2l9c1x8dl2CemB6dl2Ddl58dF98dl16dVp1cl98d1x4cFh6 +c1lzcFl3clp0clp7cF9uc1lya1tubFZ4bVldU0lCQDkzNzo9PTY6OzU3PTQ/Ojo8PDk8PjY2 +PTFAOjY4PTI+NzU1PTRAOTg9NDs+NzdFOTw6PDM+PTw7PC9APDk4OTI7Nzw4OTEwNjo9OTQ4 +OzU8ODQ9OTNBODU7OzdCOTw+OTZBPjk3PzQ/OTk3OzQ6Nzk5Ozw0PTY5PDVCPTZMPz1CODpA +Pjw8PDRDPjhGPj1DQzs6Qz1AQTlDPzw9QzpDQD08RDtEQEJORT5wXUjz+qn+//v7//b///// +//////////////7///v///z////////3/u/+//b////6//P3/+////z8/vn39+39//v4/fjt +9+Tw/u/f/Njt/Ofq++be6dz2/+j0//Hx//Pp8+bk7+Dz+/b+/vz///f++/L9/Pvs9eDj6t7s ++ury//Lt8ej9/vn////////5//r+//Tj99/y/uf08uby+ef3+u7z6uNyUmRESTx1UEF+TT9q +RT1SQTxGQDZGQzlKRDhoST9tRjxxRkJrRzlXPz09PCxCPjxeSjZ8VUKEUz2CUkN6STpiSjda +PTVQPTNKOzVQPzdiRTtuSTdrPD1nQjZOQTxOOzZHODZiQDdjQTRlQzNROzlEOzUzOy88ODIp +PC9MRDRcRDdZQDNRQzZJPzREOjQ8ODNHODJCOzRWPjpVQjZQPDhEPDhCNDM2OjU1OC87PDc6 +PjNEPDg9OjJAPDVDPjJDODhKOy1MPzZVODpYQjhTPDVAODVIOzRdQDhhQzhSQTVLODc+PzM+ +NzM6PzJpWkBuVUZJOjo9PDA4OjVLQTVtSzpxSjtUPjVFPjY/OTJWPzldSDdXQDVAOjM9ODE6 +NDI+PTFpSz5rSjpeQjVWQzBcQDpZPjZ3SThxRjtuSDlZRTlLOzJAPjVEPTVAPj43OjU0PTY7 +NzY1Ojk6PzI7Njo6ODI0NjUxNjYwNC41NzM1OzM2NDktOjA3NzktOCw2ODguOzA3NTkvODc3 +NTguODQ5NjIuNS81NzEyNzA3NzYzOjQvNzUxNzEzOTE2NDQyNzg2Ny8yNjcvODA2OTU3ODE3 +NzgwNjY7ODkxOjA0ODotOzI+QD02QjE5NzozNDY2Ozo4PDE/PDJIOjNdRD1fQDlJPjVDOzg7 +OTk5PDRSQTdPPTg/OTk3Njk8ODc6PDA8Ojk1ODE7OjkvOSxFPzo9OzFSPjZWPzVeQzpQPztE +OzhBOjw+ODA1PDQvOTE/OjhOPThJPThCPTQ6PTs/NzVIPDlRRDdHQTFCOzw0PS84OTc5ODI+ +Pzo+PTI6QTs9PjQ8OzQ+PjIzPjU/PTw6QDE/QTQ8PzY9QTQ7PjhIT0JuYEd5d1SemGy2rXrR +rH3VwojftYzBeG+cjVe7lHG5lWmyjmiqclOgaVWeaVCKV05eTzp4fFOMq2fBwonFyoro4bzs +67zs0q/s46747b/33cTz2q3q4JPj1Ybs37Dkw53GtHPMuIC7iGOsdla5gF/Dh2LKlW7VoXjg +sH/ovIrpv4rlwYzltHvhr33cu3vetoXYuXrTrHzIo2y7nHG1ll+zhV+Rb0t9ZEt4YklyX0SA +gluEfWOGemF9fWR+eF6BfVt8eV6AdVt8dWF9dlp9eV18eGN6dVt3dF91clh8dV1xdVp1c1dy +dFd3cl5scVN1alhxbVZxb1hzcldybllmUk5APTo6Ojk0PzQ5OjA8PDI3OzI/PDY7OzQ7PTY3 +OjM8NzUzPTA6ODc3OzVBOjY3PjVAPTU4ODNDOTc4PjdCNTU6ODc+PDU9PjY6OTQ7OjU2PjE1 +OTQ2OzI7ODU5OzlAPTVBPjk7PDE6Pjc4Nzc/PDo1OjE3OjQyOjFAPT1IPTRHPzpCPDM8OzlB +PTpCPzhIRDo9OThEPDc4Ojg4QDo7PDVEPD46QjhHQTxLR0FyYEr0/7H///////v7//P6//T4 +//H///v////////////////1//f6/ef///z9//T9//X////0/u3l+N77/+/1/+vx/ezt+ebh +7dre883m+OPa5dbl69r0/+/l6+nl59zo+ev+//7t/+v0//H8/+/5//H9//v+//31/fD+//z7 +8e/+/vv///X4//fy/+fy9+Tq+On9+fD08/T/8/r9/PL99O3q8t90VGRBQj52TUV6S0ByR0JT +QTpKRj9BPTpQQkJoSD55QUBwSUF0Rj5KOjhKPTlBPTdfRz17Tj2FWUKEVEB/TD1jRTtbRDtS +PTpMPzZMQzViQDhnSDluRD9cQTdVPjlJQDhQPkBXQzJlQUFcQjZYQjlAPDE5Ojc5ODQ2OzNI +PjpcRDZjQDlMPTdPPTZAPTRBPTZDOzdHPjhaQjtVQDtSQDlDPzVIOTo1OjM+Nzk1NzhIPTk6 +PzVFOzk4OjpCOThGOzlKPTZVPDxXQDZaPjlQPTZJOzhLPjteRDheSDlXQjVLODhHOThBNTo6 +PTVjWER0VkRQPj1COjA8PDhHPC1sSz9tRTtUPjxGOzRCNzhWQzlmRDxXPzZEPzU/PTY3OjNA +ODdnSTpxRT9aQzdeRDdcQzhfQDlxSj1zRD1sQz9UQzxLPjw5OjRBPjszQDk3PjY4Njc6OTY9 +Nj45PTc8Nzk0PjM3MjgyOTg6OzkuOy85ODkvODY2NzUyPDUyNTQ1NzY8NTcyOjY0MzU3Mzo1 +Ojg2ODgxODIzOjk0NzQ4Nzg2NzcxOzQ1NzYwOjI2NDU1OTA1NjkwOTE3OTUyOjU6OT0vOTY1 +NjYvPzM5OjgvNzE1OTYyOjM3QDg4OTUzOTk2OTc5OTc4OzVBPTdORTpWRDxPPjhCOjk7OS08 +PDVPQzhUPTs3OzQ7Ozg4ODY5OTgyOjA6PDgyOS82Oz04PDNIPDlQP0BcPzxfRDVUPTxFPztB +PTs5OTk8PTkxNjRBQjREPDdLPTs/OTY+QTU6OjhJOztMQjVRRjk6Qjk+QTo4OjlBOzk4PDg/ +PDc2ODdAPjg8Pzg6RDQ0PDw6QTc7Pjg+Pjg7Ojk7PDg2QDc9QTpZWEFyZlSOilqzoXfCtH3T +vpDex5Pju57XnH/Kony8lWe8k3ewdl2XcFeebVuYbUmaY0yVa0+aW1SWhFe1wYjq4Kjo6bXk +0p/N0Zrn66/13Lvuz5zhwIzUtnLczYnZuH2+l2bCe2K4fV/JfF7NkGvNn2fYpHHUr3zowI3r +zI/xypjjvYznv4Tet4Djv4jit37au37OsXHEp3a/mWi3kGiogFyOcEx8Zkp/ZU53cVKGgl6E +f2WDe2OGgWKEe2R3fF6Gel12fF+AeGh2dWF4dmJ3eV2EdWh0dlp+c2F6d1t3cV53dVp3dlx3 +cVt6cVt5cFt2b1t1bldyc1p0bFljV00+QD88Ojg0PDU8Ozs7PTNBPjs7ODVCPDg8PTY/OTk0 +OzI8Ojg1OzE/Pzs3OzQ8QDs8QDdFQT07OzhAPTU4PTg9Ozc6PjM8Nj03OjRAPDY6Ojg5Nzg2 +OzVAOjY0OzQ/Ojc6OzJCPjk2OTRAPzYyPDg+OjsxNzhAPDw8PjRMPTtMPjw/ODo4Pzo6PTZC +PThKPThDQj06PTg8QDg7QDtAPzpERUNDPD1HSUJOSkBuXk3z+63///////7///////////z+ +//f+//L3//H5/+////v8//f+//X8//r8//P///b9//f1/fX5//H////z+/Pt9uXq8uXl8uTi ++dbp9Obd6tff49fr/OX4/vn+//7/+/fq8d/y+Ov6/vX+//v+/+7s/PT8//L6//L1/+/6//D1 +/+j4//Xx/u71/fH+/fr//v7///f8/+z1/vn///3r9OXr39d0T2lEPztvTjyCTENuRjtaO0FE +RDJJOjtJPzhqQz5uRDp5R0FpRTlTPTo/PjVGPDliQzl1TT54VTyBUT56SzxjRDpYQjhVOzZL +PzdVPDhYRDdtRD1lRDttQD1OPC5OPzZJPDdeQz1fQTRfRj1RQjI+ODY0NS4yOjI3OjZGPjRd +RztdRDZaPjtMQDhDPTU/OjRBOy9MPDVTQDdYPzdMOTZNPTg9OzM8ODg3NzU/NzQ6PTNHPzY3 +OTRAODM7ODZEPDZKOjlUOzZVPTdTQDVTPTRDOzBIPTBdRTliRjlbRTROQDZBOzc/OjFBPDZg +VD5zVUpGPjY9Ozw7Oi9LPTloRzVuRj9WPjdAQTZBOjhQQzhlQTtLRDRGPTc+MzM9OTs4QTFk +RztsQTtZQjhcRDdaQjleQjptSTdySDprRjpSQDk/Ozc7OjU2NzQ4OzcxODM3QTYzPTsuPDg7 +ODg0PDs8OzUvOzI3ODYvNjQ0NjQsOC85ODQtNzI3NjEwOjc5OzIwODI0NjA3OzYyOTMyOTgx +MDAuPDg4PS8vNjc0NzUsOS0wNzUuODAyOTIyNi01ODYuNTM2ODkuNy44ODctOS82OjouOTEv +OjQwOTE2PTc1Ojc3OTc4PjQ2Pzo4OTgzPjY2PzU0PjY2QjdFPDZEPTJIQDs/OTg6NzY6PzFQ +Qj5MPzhDODk0ODA6QT01PTI3Ojs1Oy02OTkzNCg9PTJHQTZVPTxdRjtdQDtSQDhBQzlBOTI/ +OzMxPDM0OzM5PDRNPTdLOzVFOTE2PDBCPTpAOzBZQDxAOzI+PDgwQTA6PTg4PTQ6PDc5OTU2 +QDY9OTs5PTg6PDMzPDMzPzg+PTo2QjY9PDY1Pzg9Ozw2QzdLTEFmZ0yGfVaclmS6roTNvYDX +xo3fyI7duYvNqnTBoG7AkmuwgV2beFCZcVOPX1OTbUusgV62h2G8hWa2fGG9hGC7iWC1dWCu +dlm8j2XJkmi/pnTTom7HkGfLknHMj2/SkHLRk3LTkGfJlnHNkGnQmG/bqHbgs4bkwYbuy47h +xIfpuoLowIrpvITav4Hdu4DTq2/CnWrApWy5lWmvhV2VcFR2ZUl9ZEx4XEZ7c1GCfWKFfGJ+ +fWOBfGN8fWB9eWN3eF96eV53eFx8dWB0fFx9fF97eWB/eWJzclx4dF95dlZ6c193clh5cF5y +c1l3b1l0a1VvcFZxbVZzbFpbVEpBPD01ODY3PDk2Pjg+PTc8QDM9PzU2OzJBNzkvPjA3OTcz +PC48OTg4OjE9PDs5PDI6PDQ8PjE4PDc/Pjo3Oy07QDQ1PDU5PTY7OzQ5PTQ7PDc2PDVAOTcy +OjE+PTc7PDNEODk1OjM8NDoyPDJAODwyOzM+OTcvOTY/OzlBPThLPT1DPTo5Pjc+Pjk+PzhJ +RDo7PzU+OzY8Ojg8QTRBPzxCQT1DRT5ERDVOR0NsYULz/LL+//L////6/+////////////// +//////////71/+/3//D5/+3///z1//j9//f8/Pj+/u78//j0++/4/ev0++/y+Ory/vPp/+Hd +8Nrf59Pf69f///n9//v1//D1//T+//35//H9//Tl/+jz/vL5+fDy/vP///n/9+z5/ff///35 +/O3z//H3/vX5//b3//Dt/+/+//z19/D19ePp++z5++xyVGo/QTtzTUZ9UT18TUBSQTtNPjtB +PjZSOz1mSDd2Rj9zTDxxRzxVPTpEOzdDPjxaRzt3Tz+ETz+CUD58TkFkRT5UPTVXPztQOjlP +PjljQjlnQTluQD1iPjRXPThJPTJPODpaPztjQEFfQzNaOzg/OjI8OTc1ODY4NTRHPzZkRDlb +RDdUPjlMOzg/NThDOjRBNThKPThXQTxRPjhNPzpHPTVGODk1OTNAODU1NTNCNTs8OTVBOTk6 +NzNGOTs+NTVLOjlPOTRVPTpYQDNZPDdGPjlJPjRbQjpdRDtZPzpNPDdCOjVCODo9OzVcTkBu +VEdMPzo/PjRFNjpFQDJyRz1rRTpZPTs/OjVKNzhMPzdjRz5PQDtMPDM/OzU3OTNAQzZhRjpt +RD5aPjleOzheQDliRThuSkFvSzxfREJFPTk7Nzs9Ojk5OD87PjM6Oz44PTQ7Oj04NTc9OT81 +NjQyODQ2NzkzOzc4NzcxODQ0OTkzNjU2MjYyODQzNTcyODQ1NzUwNzUwNi45OTsvNTM5ND0x +ODQ8NTswOjc5Njk0ODc7NTEyNTU3NzIzOTU1OTA2ODkxOjY3NTkvOTI4NzgxOjI1ODkxODQz +OjM1OjM1OTQ0OTY1OjE2Nzk5Ozc/Oj86Ojs1OjY1PDY5OTlAPjU9PDlANz07PDVFNjlLQThS +Pz03OS82OTc0PTM3Ojk7ODc7Ojw5OTM3OTw5OjJHPTlOPzZaQEFhQ0BSPzpDODVDODg+OTE0 +Nzc6OzdAPTZJOTVKOjxBODk/Pzk1OS5PPjxMRTJOPz47OzE+OEE4PzQ8OTs7PDRAOz04ODQ/ +PD82PzM8Pjk7PDc6PSw7Pzc3QDM3Pzg8QDg3PTc/Pjw6QzdXU0xyak2PiWGtpmzCs37DtInd +xIvbwYnVpXy3km3Ck2y4kmqtdVuWaFiVaE+gaVKgdVeve1utdVW2iWXLlXbNmnLTmXDQkXTU +iHLTkmnSnXnVnn3foozjtqPnrpnesInWo3jTk23TlXLZnnHYo33crXbqxo7tyo7wwpDlt4Ho +vYfmvYbdu4PWrHzXtXnGpnW4lGa0kWetiF+cfF+HZ1N8aU1/YUp3YUiEck9/e2ODfWJ9fWKG +e2d8d2F/eGB9e2h1elt8d2N7dV18dmR7dFl7dF99dl5+cFx5b116c2F7cF53cV52bl11cVpx +bVx2aVhzcVpycFZyb1phVk45PkA7Pjc3Ojk+PDY7PDNAPjY6PzhFQDk5PDg8PTk6Ojg7Ozo4 +PDU6Pjc+Pjg7Ojc/OzVCPTc9PTVAOzc9PDQ8QDg7PzhAODg6Ozc1OjQ7OzI3PjY9NTk7ODc7 +OzJCPTg+QTVBOTk5OzA/ODk1OjY8OzQ1Ojc7NjQ9PTVIPjdEQjlGPzw1PzlDQTlDPTxJPTpA +Pj0/ODM/PDs7QDlCPzhCOzxGQzZHQEFVSUFwXUz2/7T///////j////7//n7//P2/Oz+//// +//////////////v+//T6//H8/e7///76/fT///z9//Tx+uv7//X3//Hy/uXq/O7Y7NDm79v2 ++u/x+urz//Hv9+fu9uj1/v37//H6++/p6+n+/vz///nt++35//P3/vP5//v///n0/+v4//X5 +/vf+//vu8+jy+Or5/vT5+/ju9On+//r///r19ex7VGc8QD1xTkR7Tz12SUVWQjxHPjtCPDRM +PT1rRjtvRzxzQzxpRTtdPDg0PDlEOz1TRDyCTUN8V0GCUT12UzxnRDhPPTdTPDtRPDlOPTVh +PztkRTltRj1dRDlTPTpFPzpQPUBTQzlmQj1jRjZaPTk/ODc0NzU1Ozc3OS87QDhaRTtTQDtK +PzdBPjU5OjI2OzlCOzlEPDlZQDlTRTpSQTlBPjdEOTc2NzM6OzY2OTU/Njk8PTJBPDg9PDE/ +PDVCOjVFPTVOPzdVPTpWQTVXPTpGPjRFPzpaRjhbQTtYRThOPzdAPDNANjo5PjVjVkNwWUJN +Pzo5OjJBODhDOjVrSjpsST1VODg/PjhEODtNRTxdRDxOPzZDPTc9Nzo0OSg/PjZfQj1pQzxV +PjtbRzlcQzpZRDxtRT5YRTtFPTwzOTQ/Pj00PDU1OjgxPjg8Pj0wOTY9PD8sPTY4OzkyNDg1 +Ojc1PTYwPDg1ODQ1OTczOTM1ODcxOjAvNzgvODMuODUxODI5NDgqNzM1ODctNzU2NzsvOzA0 +OTsuNTI3NzwxMy4yOTgxOzMuOjQyPTgwODEzPDUxOTQ0NTctOjc2NTYzOTo0NjIzNDU0OjU3 +OzgwOjA3PDkuOTM5PDgyPTg3QDcxPDY8QTwzOjM2PTU0Pzw9QTc+Ojs7PzY4PDhGQjJQPTw5 +Ojo3Ozc6Pjg2Njg2PDU1ODg5ODYzOjU8OjZFQDVRPjtdRzlcQz9RPztCPTtAPjQ8Ojk3OTAy +PzI/PDNGQDtGPjw+PzA7Ojs9PjdIPD1PPzhPPjw+QDQ4Pjw4QjQ0OTs4PzQ0PDs7Ojc0Oz05 +QzQ5Oz87QzgzPDk/PTcxQDo4RTo2PDgzPDg6PTs4QDRCUEFiXUZ+b1GRi1m1mnu/s37MuIDV +u4LLr4m4nmu6lnG8jGu3g2emeFefdVugeluqelimdlm2fl+uhWK1g2rMnXfRlnzOn3barI7V +r4rWr4rcwpTjv43TsXTPmnLSlW7YnHTRm3LasYDTpnrarH3etYTsxI/tzZTqyI/iwY/fuIHh +vYTcvYnQqnnGpXO1lGOwjmiqjWOsimSJblGAcFF6aU56WE+LZ0mAcVaBgF6CfGV7fFqEfmd7 +e1t/fGSCe2B9dmF7emJ6eWJ9dV99d1+Bdl5xdlp6d2F2dmB2d115eFx1c1h5cl1udFp7dGFt +cFZ6cFprclp5a15bT1E6PDowPTc7OzY3PDo8PTRBPzk+PDZAQjg4PzU6ODczPjQ7PTc3Ojg7 +Ozg7PTY/PjdAPzw8Pzc9Pj48Ojc7QD08QzY+Pj03PDY8PTpBPzc7PDw3OTY3PjQ9PTk1PTRD +NTg8PTlBPjkyOzU7Nzs5Pjc2PDg1PTY2OzU8OzRIQzhIQTxANzk+Ozw6QDpIQjlFQjhCPj45 +Ojw8PTw3PT4/QjpBOzxCRThIRUBLRUJ7a0/k86T3/+z7//P///////////////7///////// +///////7//vt++b6/+39//n1/fP0/Or+//Py/PL3/u/6//rm+Obs/+Ln9uzm8tXr9PHf8tvf +59zr9+Lz//D5//z19+nu/eT4//f+/PH3/+zu9+z6//r7//Ht9ejp/ebu9+Tu+vL+//T6//L5 +//f///3////w+e3q9uzt9+f+/vj5/+jt8+B2VV9DQDxuT0CASURyTUBeQz1DQDdJOzhHPTpo +RzlxST5sSz1tQzdURDhAPDdBPzdXRzR4UD6BUTqEVTl4TTlnQDxNRDZWQDtRPzFVQT5gRDVt +Rz5uSjhqRjpPPzdPPjZLQDxVRThnSTtkSjVYPDQ+PC82Ni8zOTA0NzI7PzE9PjRAOzg3OjI+ +ODUzOzA8OzQzOiw9OjRCQTBeQzhGPzNQPzU8PDM+OzI7NzA4OjE3OzA+PjNCQjY7PS9BOjRD +PTVIPTRSPjVYPzZbQzZWQTRIPzVEQDNZQzxdQzVYSTxKQC9FQjc+PDFCPzhgWDtyV0dOPTU7 +PjFCOzJEQDNtRjxvTDlVPzg/ODFCOjZNQjFhQDhRQzU/QTQ9PzY5OTA/PzNgSzZlRzpZRDVh +SjlbSTlbQDZaSDpJQDk6Njc5QDc+Rjw1QDU5OTk1SDQ/RDwyQzk6PDYzPTk7PTEvOzY5PDU1 +OzE1OTMuPDM0OjExPDg4ODUwQS80OjEtOzctPTIvOjMzPC0zPDUwOTA1OjU2Nzk1PDI1PTcz +QDQ5PTgxPTI2QjMwPCs4OTU0PTA3OjgtPTEwPDYvNys1PDYzOzA1ODI1PTMyOjQ1OTQzOzEy +PDYzPDAyOy80QDcwOCw2PTo5RjQ8Qjk1PzU7Pzs1Pi46PjM0PC8/QDo3PDJCPTxLQTQ9PTs3 +OzU6PzY4OTk3OTE9Pzk8PDMyOzE7OjNEPzJURDtdRThcSDVQPTpFQTc/PjFCPzUuOyw8OTU3 +PTdRPzw9Qi1EOzM3PTBDPzdKRDhXRzpQRDs+QjQ8QDc4OzM6PDg9QDM4Pjs6PDM7PDk8OjY8 +PTdGQTo4QjM9QDg3RTRARDo4QC9CPEE0RC87Qzw6RDBMUUZxYkN9eVeVkGOqnmy/qHPHuH3J +s4HCn3S2k2y3kWnAjGqqflyceFegf1eliFm1hWS3gWW8hmi7fmq+lGXEiG7MkGjDlHfDkGnO +j3LIimDLk3XNkHDRk3LRqHfaqYPTrnrYpHjYr3vpuInpxInxx4znxYztyIPryZDjvorctX3V +uXzPsXfFom6yk2etkGapjmmggFN5Z0mJbU+BY0qLbUyRaUuHeViEfGGDgGJ8eWGAfGN+fmGE +d2GAeF58eFx7eWB+eWV+d1l7dl16e2d+dWR8dlt7dmCBeFtyd1dzcFR3cVl4dVd8cVhxcVVz +cFdybVZ0bFhaTkdCPD82PjI9OjY4PDNDPTc+PjRCOjc+PTQ+PDs6PjI4OzQ7OTc4QDU9QDo8 +QTc+QDY7ODBBQTM+OTc/PjQ/PDU7PThDPz84OzVAQDk4PTNCPTY2PzBBPz07PDA+Pjg1PTZF +PTM6PTA9PTQ1PzQ3PTg7PDQ4PjU1PzU+QzhJQDdEQjhFPjY6QTZCOjdAQjlGQDRCQEA6Qi9B +QT04QjNFQUBCQTZEQUJHRDlPTUNyYUbw+Kf////+/+/8//P9//D///X///b///b///f///r7 +/+79//v///z///v8//nx/+z+//j9//f8//T2//Tm9OLn89/r9uTZ8tjd+tDu8+Hk6t3b59P0 +//Tt+PXt+eXp9u7h8Nz6/fP4//Lz8ej4/e/r9eHk9N/+/vz9+/n9//7///////Xw/+vt/Oz4 +/vTx//j///7///3/9fXx/e/2//H67ehvVWBCRkZpUj5/T0FwSz5WPz9DQz1EPTpEQThpRTl4 +TENpRkBuSD5TRDc/PDU4PjNWQjp3TUJ/UzyDUjt4TztpRzpSPzNWQTtQQjdXOT1WQzRvQjxq +RjhqQT9LPTNRPjdNPjtZRjtfST5aRTZJOjY3ODE2OTcyODYxNjY3OjQtNzI1NjU2NTc2NzQy +NjE7OjYvOjI5NjU2OTNMPTo+Py9QPTU7OTFBNjc1OTc6OzI2OjVAOTlBOjU7OzNBPjQ/PDJH +OzVLPzhWPTZXQDlWQDVCPDNFPTRXQztaRTZWQTtNPjZDOTw7Oy49PTlbUTptXkdIQDY6PS89 +NTNIQTpnSjhtSDZVPTVDOjZEPThTQjRfQjxMQDdAOTg3Ozg3NzRAPDNhRjNhRD9VQDFZQzxW +QjlTQTRPPjw5OjoyOjU8QDc6Pjo6QDc7QTw3Sj4+QT0yQDg/RD4zQzo5Ojw2PDc0OjQvOjEz +NjIuOjUyOTEvODA2OTQtOTczOTIzOzsyOjMvOjY1ODUvPDkzPjUzOjUzPTUxPDU5QDo1QTY3 +OTYxOjQ7Ojk2PjA5PjgvOzE6NzsyOjE2ODcuPDI2NzYuPDMzOzQ0NjM1NTgxPDUtODQzOjIw +NzczOyswNTkvOC80OTU0PTc6Pzk4Pzc7Pzs0PDQ8Qjs1PDM8Ozs4PjZEPzhKQzE+PDs1OTM3 +Ozw1Ojw2ODQ3PDM3OjU1Ojc2OzZBQTZSQj9ZRjlZPjtMPzlFPTg7PzQ7ODkvPCk6OTc5PjFN +QjU8QDREPzo4PTNDPztDQTRVRjVHQkA4Pjg0OUA4QDg4Ojk6QzM6PjU0QDQ6Pjc3PDQ3QDY6 +PTY1OTk8Pzs2Ozc8PDswOzQ8PD86PC89PT02PzA+QjdHTzlva06HfVmch16vlmmzrHG0mnG1 +oXO8nnu4k2G5jG+2iWGre1ufcVibfF6egFymlma8mnC7nXjDmHm+nXbJk2+9lXzJmHbEpXvM +mWjCoG/CoHLFqHXJrXXKpXDRrXfis4rdu4Ltx5Hrw5LuxpHkxIbsvITjxIXevIXYtIPMrnm+ +omewjmOfkmOujWmZhGKJcFF7bVCGaUt/bEyeeFWNZ0qAe2N+fGCFf2V+emGAf2N5dWCAfGmA +eF97d2J5eV14eWN8eF97dWJ3dV2BeGJ0d1x6dV57dGByb1p2c1dyclp0cVpubVZvdFh2cV5y +cVZ4bllWUkk+Pz06Pjc9Ozc7Qzg8Pjk7PzFCQTk/Pzg+QDY0PTY6PDgzOjA5Ojw9PDo3PzQ8 +Ozc8PDJCPzg6QDg/PDlAOjc5QDU7PDY0PDc9Ojc5PTA6PDotQzU+QjkxODBCOTo4QDhHPjky +PDU8OTc1ODY6PTk9Ozk6PjU1Ojc9PzRBPDRDPzpEQDo/Qjo+PzhCRjpBRTxAPjs8QDg/RD87 +PzRDSEA7QzpERkJJRTxPS0V0ZELz/bT7/e////////////3///3////////////////////8 +///+//H9//f4+e39//z///36//Px/+ny/en2/e37//f1/e/q8+zl+dnq9uXl793j59/p+ef0 +/u38//f4/PLw+O7r6+Dj+uXx/Or///3////7//P4//H9//P7//T7/+z+//j5+vL7+u/0/Oru +/e3s9d7v/ury8Obs8OXy+uvv+uh5VGhDPDxpTUOBUD55SThhQDc+RTNMQD1DPzRiQThtRjh0 +RUBrRjtUPT1BOzQ+QDZYQDhyTT+GUz58Uz18TDxnQzdVPjhUPTVKPjZVQDhTPjRtRDhmRjZt +RTtMPTRQPTJEQTVZQTpaRDdTPzUzOjU3ODUxNzYzOjE2NjM4ODI4OToxOTIzOzQtOzE5NzYy +PDI3NDI1NzU5OTQ8PTk+OzVGPzY9OzE1OTQ1OCw1OTRAOjE/PjdGOzI/OjQ+PDU/OjZMPTdO +QDdcQDlYPTVWPjVDPDZHPDZVSDVfQztWRDNQPTZEOjREODJFPDdgTz5tVEpJPzpAODZBPDdD +QDdgRTxwQjpSPTZEOzFDOjVMPzZcQj1LPzRFPDo3NTM3Ojc4OzNhRTlYRTRXRDhPQTpWQzdG +QjlDPDc4Ozc5OjU5PTw7QDY4QD1DQTw/Pj06PTs2QjtBREA2Pjk2NzQxNjM5ODovOTExOjcu +ODQ3NzgvOjAzODYvMy48ODsqOjI4ODs3OzhBPjcyODc8PzY3PjgyOTszPjY4PDU2OjY1OTc7 +STs6PTk0OTg1PjYzNzUxOjYsOio2NzUvOzQ2OjowOTA3Nz4xNzA2OTgwOSsvPDUyOTI1OTo3 +NTc1PSw1PzY0NjE4Pjs6Rjk2PDY4OjY4PC03PTU2ODY8PTo0NyxAQjpBPzc9OTcwNTRBOjoz +ODE5OjgzPTU/NjQxOTU+Oy9FOzVPPTlfQz1bRDhOPThBOjREOTg8PTQ7NzQ2OjE9PDRLPTdF +PDU+PjQ0PjE9QTdJQzZXRUBHQzRBREA1QDM0PDg5ODA3Pjk7Ozg6QDc8OzY5PDc7PTk5PzA2 +PDk5QzE+Ojw+RzE6OT05PjQ3PDxAPDQ3OTlCPDQ4RTxeUkVoalGOf1mSjmWymmmunXGrmGy2 +lm68kWW+mGu8lG29g2aqfGGveVekgluihGCliWSmhWWrk2yzlG23lGaujGa8ima2kWi2i2e+ +jXLHjXLTmXnYrYDjsIDow4/pxJLqwo3wyJbuypftzJLqyY/rvojeuX7VsnvEqHbEnXCuj2On +gl+qi2Gok2eKbVGDc1yJdFKCZk+WfVOqfVOMak2BeF6FfGCDfWGAe2B+el6AemGCe1+BeFp/ +eWF9eWGCc2F9dl18c192dV17dV1zdVmBe2J5cV16c2JvcVV5b1pzcVdzcVlwcllzclVzcFht +Z1VWUkc8Ozs1OTY5Ozo+PTZGPDs/OjZBPTs6PDQ8PTo4PjhAPTozPzE8PzQ2OjVCOzk2PzdD +PDpAPzQ8PzJDPDc4PjQ8PzU3PjU6Pzg4PTQ6PTQ3OTU4ODI2Ozc5PDU/PDs+OjVFPTg8PTJA +PT45PzI7Oz86PDE1PTk1NDI/OzhLQTNEQTVCQDY4QTpAPTpGQDlFQD88PzU9OjY8QjY9QDk/ +QTpCQjxDQzxLQjxRR0F1ZEf6/6////r+//b+//X///f///v///z///////f///v///v9//n4 +/uj+//v///////77//T+//n2//D+//X4//P8//Pw/+zr/uXk/dfm8+Ll9+Lk7+D1+u/z/uz4 +/vT7//z///////n79/Hx/ubt/Ony/+/9//7/+/H19u71+e75/+/3//Dx/+j3//r9/fX9//X6 +/fn//fL29vX2//L6/ezu5tp1VGg6RDlqSEV7Ujp5TURaRTJOOEBGPDRJREBgSjh0ST5tSDxt +SDdcPTlAPjQ8OTZWQzVwTz9+VTh6Tzp5TDliQzhWQjdPPTZZPDVKPjViQjtlQzpzRDxhQjdY +QDhSPThSQzdRQjpWPzhBODU0OC81NTUvOS45MzI0Ny80NjAxOjI4OTM0OzI4OjE1OjE3OTI0 +ODI1ODE1NjY3NzU6OTU9OzFCOjg8OzE7PTQ7PC83PTFDPjc/OzBDOzg8OzRGOTVCPTRSQDZV +QDVYQz1TPzJKPjVAPjVcQTZeRzhZRzdSRThIPThDOjY+PDVhUTxuVElOOTdCPDNBPTBOPTdm +SjduRj9PQDRFOjdDPjVQQjlUQjZQPjdDPjNEPTk0OjZFPjhWRTthQTdQQzZdRDpPQjtCOzc4 +PTc3PDM8PTk4PTY7PDk3Pjo4PzdCPT4/RT9CRkJBQT1APzwyOjA1ODQyPjI5Mzo0PTE4MjYv +OzM4OzYqOjY2OjgyOTM2PDU5PDQ2PTg+Pj49Pz85OjY6ODk0ODc3OzgzPzI2Pjk1PjI7ODg3 +ODQ9OT02OjE3OzgwNzM8Oj0yOSw4NDgzOy03OTszOTM1MjU2ODUyOy0zOzYzPDU4PDI2PDE5 +OTU7Qjc3PTc1PDQ1PTY6PTg1ODg5OTg3PzU7Pz4yPDI7Pzc2PS5EPTk5OzY+Pzc6OzY5OTY2 +OjA1OjM3Ozs0OTI5PDdGPjZZQjtdRDdeQjhOOjdBPTJBOjo8OTI1NTQ3OzJEPzhHPDhMPDs9 +PzVBOzk6OTdPQjlTPjdPQTxFOzk+QDg+Pzs4QDg9PTg6RDQ+QTk7QDE8QEA8PTQ6PDk7PDQ8 +OT1APTg3PEA+Qzc0PjlDQDQ2Pzg9PzI4QjhBRTZARjxhW0JybFOGfFWVkWOlj2azl3C3pXG5 +om61lWDDmXO/k2bAim22iGLEjWy6j2XAh2m+hGC9kXTDn2zLlXXJn3HKm3bNqYDYpnjZr43l +uZLlwZfqwpLtwJL3zJrwxZDrwpHqyI7vx5Dkx4vtwY/pv4fduYPJq3DLoHGzm2epiGOnjGSy +kmuWe1d9cE2PdE+Abkice0+sflukeVeRcUyDfF2DfWOAgF6Ef2R+fWB/emN7gF9/e2B8eliA +e2F3dlp+c2J7dFeEe2R5ell8d2F/fFt8dl58cF11dFt8dF10cVpyb1V0cVdzcVZ0cltxa1dh +Ukk8PTc4OzY1PjZCPjw7PTRDPTo6PzZEPTo1OjZGOjc2QDE/PDYwPDNAPTU8Pjc8PTJCOjdE +Pjg/QDU/PjFEPDdAPzU8PzM4OzM8PzFAPzc6QTI7PDU6PDA/PTk+QS9CPTpBQDFAQjs4PTQ4 +PDc2OTI9ODs6PDQ2PTdGNzZFOzxJPDpDRDdFPjc+QjRKPT1ERjZAQTw/QDc9Pjg7QTdAQTdD +QD5DQjtNSURPRzxvY0by/ar5/uz6//D+//f///////////r///z8//T8//H///////////X/ +///3/vL6/+76+Pzp9t7z/ujq+eju++Lf7d7m7Nbh6+Hg88zp+OHi7NXY4tP+//np/O34+/P0 +//P5//Hx//f///3///T///j1//z9//v0/+79//L2//Xz7eHs8en17+32/u31/e/1/+/8//j2 +//Pj4NXw/un0+uPq5d5yUWA+Pz5kR0F5TUB4Sj9XPTlQPzs+PTJQPz5aSDh1R0JwSjNtQzxO +QDNBOzo6PzNRRDtsTj15TD1+TT1wSztsQT5VQDdQPThXPjVMOjhYRTVkQzdsRjZgQzdZPDtI +PjJMPDw6OjhENzU2ODU/NzYwNTU6NTQxOTIzNjMzOTYzNzUzNjc1OC05ODIsNDA3OTIvNzM1 +NjYwOzUzOTU1OS87NjI8Ozk2OC86OjY0OS86ODY/PzNBPz1BMjZBOTxHPTZCPDNRPDZVQTZZ +QTpVQzhPPDhEPjRcQjldRDtZQDhQPDdLOjZBOTg8ODZZSjxuU0ZIPjk8Nzg/PDdGODRmSTZo +RTxWPTY/MzhEOzJKPzxXPDZNODo9OzQ8ODU6OjBDODZUQjhXRDtQRTpPQT0+PTo7OjQyPDg7 +PjI2PDg5PDY1Ojg4OTo3Pz5GSkI7QkM5Pjk3Ozw4OTszOzU1ODszODU4ODUwOzYuNzkzOzE6 +NzwwNjU3OjwzOTc3Pj42RThVUU8/QD86ODwzNzk1NzovOTU2ODY3ODs1ODs0OjM0OzczOTc2 +Nzk0PTU2OjYxOTE1PzY0OC80PTYvOCw3OTgyOTEuNjgsODA4NjsyNTQ4Nj0zOTE2Ozk4ODQ8 +OTZCREA2OjcyQDQzPDc2OTk0OTk3OjY6PzQ6Ozg1Nzo0OjVCPj00PCw7OzsxOTQ/NTwtOTU/ +Ozo2OjQ3PDczPDdGPjxWQDhcRjhYQjxKPjdEPjVBOjdBOjk2OTQ4NzQ9PTNFPjtIPTpDPjVA +Ojo4PC5PPDxSQjVOQkQ8PDg/PTw6PjI6Pz46PzQ6Qjs7PDg0PDQ+PTc6PzE7PTg3Qjo8RTk4 +PDg8ODg8OTE3PT8+PTU6PDs8PDQ1ODs+QDs2PzlHR0FXU0hzbU1+cFOSiV2ahWOmmGqtlW62 +lWrGnHLEmGfFi227lGXEm2++mGrMpX3Nm3XTonzSpXfZpHrPp3TbqorbtonkuI3dvpHiv5vp +w5PtxaLs0Jr0zpnuwJHnwYnjwYnsxY/kvIjgwonbu4fOqX+9nHC1jWWVf1qok2SvkGuegGOB +ak+LbFOMcU+SdVCphFa5i12teFmIb02GeV2DgF6CfmSAfWJ/emGCeV+AfWKEfWZ/eWF9dmJ8 +eGF8fGJ4d2J8dGR0eF19dWJvdlh7dWZ2dVt6dF13dlh2cF11dFxzcFt2b1tzcFhyaFpfUEs8 +Ojw6PDs2OTg+Ozc/PjpCPDo9OzZCOjg3PTU7OTc3PDQ/OjozOjQ9Ojk4OTlEPjo/QDdFNzc3 +PDdEOzZAOTQ4PTc6PTg5PTM+OTY7OTM+PDM4PDg8Ozc4OzU6OzQ8QThCODg+Nz00OjM5Ozs4 +PzI6OT00OTU6PD8+Py9MPD9DPDdFQDo/Pzk7PjRDPzpAPj5AQz1BQDk9Pj45PTVBODo/Qz1C +RDtFRD5USTx3ZEvs+7D+//n////////9//j///7///////3///77//T+//X6//b9//L7//b7 +//f6//j7//f6//X////8/v32/+/6//r2/vHd9uHd8dXc5tff6tXW6dLy//j5+e7z/vf6//Hs +/uf1/u3v/+nw/+Xv/+7n8+bs+Ojy8+3u9uX+/v3////////q//T+//n///7/+fXn8t/e/Oju +9PL9//v//fXx6NtqUmM7QjheSUF8TkN4QjxgQThGRTdKQj5CRjhhRjtxSjh0SEBqRDNVQTo8 +Oy9BQDtNQjFtTD99Tzx+TDp6Sz1lSjpcQTdSQTZTOzhKPTNcQzdqRD1pRjljQzdOQDlMOzc8 +QDM/OjQqOi8+PDIrOjU4NDMpODA3OTMxNTM5ODEyODYwNzUuPDctOTMyNzMvODI3OjQsOTA2 +OTYtODMxOTM1ODA9OzQ4PDQ3OzE4PTY1PDBDQDpAQDQ8QTk8OzY9Ozk+PzVLRDxZQTdXQzRY +PThHQDhEPTdWQjlhRTpVRThTQTlFPDU9PjU4OTZcSztnUURPPTk/OzI9PDFBPThiRTxpSDxT +QjxGOjU8PzJOPzdUQTlIPzRBODc3PDM7PDQ3PjNOQjhNQDhIPTo7Pjg7OzUwPDM5ODk0QTc3 +PDMxQDM2PDc+RjxCTEA6QTw7Qz01Nz03PjEyOTw1PjkxNDc0OzQ1NjM2OTkxODc4NzkqODEx +OTYvOzM6ODw7STpNUVE5RkA/OzouOzU5QD0yPjg4Nzw0PjY1PzY0PTQwPDQyODc1Ozs1QTI5 +NDk3Ozk1OzgxOjYxPDktPS8xOzUvOCw2ODgxODE2OzkuOi03ODsrOzIyPj0vOi00Ozk6QTVG +Rz9EQT47OzQxODUxPjQ1PTk3RTc8QTg2OzIzOzg4PzQ3PjQ2PjcxPjY4PDkvOzE6PjgwODI/ +OzovPTQ9Ozc+PjFTQztYSDtYQzlMPjhBPTNCOzg+OzY6Ozk1PTE7PThIQTRGPjdBQjg3PzM9 +Ojk+QjVWRTxDQzg+PjozQDE7PTs4PzA0Pzw0QzE4PTY2QDM2Pjg+Pzg1RDs5PDM2PTc7PTo6 +QTo7QTo3PDU7PTw5PzEwPDs0QTgzQTw6QTY1RTxJSzxNWkVwZkh2ck2GfVeOh2Ojkl6tl2u5 +mWzDpnjNnW3Klm7Il27RpHfDm3HPpH3QrXzTpX7UsoPYrX/gr4TftYfjvZXrwJLpxY7zxqHs +w5jsvJPpyI3tx4/jwY3ox4fqzJHkv4zZuH3Uqn+7pnCvkWWghl2ghV+tmGmmjWx+cVCJc1CO +ck2QeFaujV69lmS2imCofVuOcEuMflp/fWGBd2J+e2J6e2B9fWJ+emF9emF6fV11e1p6e155 +el59eWN3eV18cmNzdWF8dFt9cFt7dGF1cFt6dF91eVp2dl91clZydVtuclhubVdYT0s6QTc5 +PTc1PTg3PDY/Pjg/RjpCPzg+OTE4PDM2PTE/RD00PjU8PTk1PTJBPDUzOzRDOjk6QDVDOzk2 +PzdCOzg/PTY4QDk5QDg9QjE9PTc5PTw7Qzg3PjY7OTY3Pzc/OzQ+Ozo5PDU6PT03PjM4Pjoy +PDI3Nzw6QzFDPjpJQjRFQ0NBPzdCQD9BQDhCRzNFOzk8Rj09PzY6QDg7Pjg8PzdARTw/QjtG +Sj9RTEF3ZkXo9rL9//n////3//T6/vX1/+ns+eb+//f///////////r8//f8/+7z/+36//Py +++3z/Or6//ju/+z1/ert+ubr8ubf69rf8OHY69Lg89na7dfi9Nn+//Tz//D6/+/w/ez19/L4 ++O/5/ff///X+//7///v9//b6/PX///Dy/+v6++7s+eX6//jz/+b6//X///v//fb+//j+//z/ +//T3/uv19eppUGNCQD5jRzx6UEF7STpcOzdKQTxJQTpQPz5jSTl3S0NySTxrRUBUQTNFPT02 +PTBWP0BpTDl+U0Z/TjWCTkBrRThdQzlTPzpUQzZUODRZPjNrRTtvRDtjQzxRQzdIPTlKPTc0 +OjVCNTY2OTE+OTIrNzE8OTMwOS9BPDIyOTE+OTIvOTI3OzczODU0OjA4Nzk2OzMzOzIzOjE5 +NjU3OzE5OTM4ODM+PDI6PTA8OzU4OzlDQTlDQDo6PTNBPTdDPTNHPz1QPjJXQjldQDVaQzpR +QDVAPjVbRDlgRDpbQzhSQDZLOjtEPTNBOTdZTzltWkhQPzg/OjlCODRDPDZjSzprRDxTPzxM +QDlFQDdNPjVXQjhOPjdIPjc6PDM8OjFBPTtNRjtOPTw5PTQ/PDcyPjE8OjozQzY9ODk3PDc9 +QDg2Pzx0bVpAPkA8QDc9PT48Pzc5PTs3OzQ6Ojg5OjM9Oz06PjU7OD05Njo4OzY4PjwyPTQ6 +PjlDT0NNR0s7Pzg8OTw2OTRAPTk4QTdJSkM+PDpBQD02QT09Pjo4Pzc/Qjk4PThAPjpAPDw6 +Ozg5ODc0OTY3ODU4Pjo1OTA7OTc7PDI1Nzg1OzQ7Nzk0OS09Oz0zOTE+Ozs0QDNAQz5BPDlE +RD5GQTc7PDk1PDk1PTo9QT5DRjw9PkA6Ojc9Ojo+Qjo/PTo6PDw8PTw6PDg0Ozc8PTUzPC86 +QDcxPzRKPDxSQTZgREBaQzxTQj9BOzlJPjo/PTw0QTM0OzU7PTdQPDhNPjhDOTs+QzlCQDlK +QjdWQjxJQjhBQThGPDw8PDdBOjw3QjBBREA8PDlCPD86QzVAPzs/PjlAPTtCOTo6Pjc/ODg7 +Qjk/Qjs7PTg8Pz83RDY+NTxCQTo7Oz5BRTg3QzlRTDtaWEtvYEdrZE2Md1eOhV6zlnGylXe+ +qXTTqnjSo27Nn27MnWnQn3HZrnzZpXfOnmvarXzZr3ngpoTkv4XuxJnsyqHtzKfqyp3txpfq +uH7lv4Xnv4fjwpLfxIrqwpbatonNqn+6n3C0lWmgg16TfVaolGetimaOdVSLdE2OdVCVeFuv +iVq6jmPCkmW9immtgV2RbU+ddlSNeV6AfWGJf2OAfF+Ee2N/eGF4d15/dFx/elx9emB5dmB3 +eV95eGF5eV99dF56eV19eWB0dF1/d15ycFt0bmJyclp1cmFvclp2cF1tbVNbTE45PzQ9Pjw6 +PzZBPTNDQjhDQjRBQTc/Pzk1PTc3Pjg8ODU7Ozo7PTc/PTY7PDZDPTs6PTRFOzo1PjFFQjtD +RDxFPTs4QzhFPzk7PThBRjU9Ozc2OTo8OzY8Pzc/OzlAOzhFPTg/PTY9OThBODw8PDg5ODk9 +OzI7PjY/PjJMRT5JSDlKPj5BQTZEQD5BPDBIQD1EQjk/QT1AQTk8PTxGPj1EQjdMQj1HSD1V +RUN7aUr4/7P///z+//r+//r///////7///////////7///3///z4//z5/+z+//f///r+//f+ +//n8//j3++76/vD9//zz/PXt9+Pj/uPp9Nrk8N35/ezl6uP18Orq8eXp8unu9ubt/O/2/uv6 +/u76/+Xz//T5//v///n4/+ry/+/4+O7+//3///////f2+e/p897q8OT4+/D0/u/48+32//P0 +9Ojb481vUVw3OzZhSj98UECBSEFcSDdMP0BBPDZJOT1gRzp0SUJrRz1tP0FUQDhEPTg5OzlO +QTZxTDl/UD97Uj96Tj1mSDlcQzhNQDVTQDpMQzVdPDtjQjpwPj5hPTZNOjs3NzA9OzkzOTA2 +Ojc8NS8yOTc4ODg2ODE3ODA0NzUzNzEzNjQ3NzE2OzEzNy86NjYzODQ5OjMyOjE/OjszNzI3 +NDQzODNBOjsxOTJDOTgwOjM/PTo8OzZKPTQ4Ojc+OzFEPDVDPDNTQTpZQDddQTZeQTdPPTpB +OzpUQDpdRTpgRzdZQjpKPzRDQTg+PC5cST1uWERTPzs+PDRAOThEPjVfSz9rQz5LPjRFPDdA +PjdMPjZRQjdJPjo8OTRCOTc0NTNBPTdBPjk7PjU6OzY3NTc8OTk0NTdERD04PzU3RDg4PTtH +Rz4+QkA+Qjk9Qjw6ODg7Ojk2Ozc2NzcxNjY4OjQ0OC46ODczODQ1ODYtPDQ2OjM0QTlOU0NB +RUQ8PDk2Oz09PTU6RTlCRj5ISUdHTEQ/QkE7QDg5QTk4Ojk1PzU1OzgwPTM1Ojo2PTA0OjYx +PjA0OzQwOTQ2NTcxOjI4OTgsOTIyOjQxOTE5Ojk2Oy02PDMxPTE3Ozg5OTc3Pjg6QDY/RjtM +SD5JPDk2PDQ7Ojw5PjVAOzw1OzI4Pjc0PTA3PDg4NzM9Ozs4PzY+ODk4NzA8Pjw2Oi42Ozc8 +PDZJQjJVQzdbQTNeQD1NPDhHPThEPzk7PTQ9OTk2OTpEPTVHPDJKPTs+Oy5DOjw+PTRQRD5S +RjhNPzw+RDU/Qzg2PDhCPTg4Pzc2PTc9Ozo6QjI/PT0+QDU9Pj88Pzs2RDs5PDo8QDk+PDw3 +PjQ9OTw3PThCQD08Ozc/Pzg6PC9BQz07PS86QT9FST1WVk1hU0lpZUiBdlyaimm0k26zi2G/ +oXLIpG7FmnXKpGzQonjWp3jTrX3arn7TroDdt3ziuIvpxpfqxqL4057u1a7txJrtvpDlwYrm +wYnmxYncuIrcv4beupPXqnnFoXS5lWuagl6NflWnjFuuiGGLcleLd1WPeFCTdlSqjmLHn3DK +m2jGmma7i2G0gVmUb1SjglmkdVV+cE5+eWN/fWaBemd8e2SCemN7eFd+dV14eVyBeWZ3d1mB +emJ2dlx+eGB6eGB7clxzdlp4cmBxclp4cVxwblp0cFV1blZwb1p2blZgSkU4PDc6OTk3OjY+ +OjM6OjFEPDk7PTREQDo8OzRBPj07PjU9PDw8PTA9QTw+PThBOztEPDpDPjs/Ojs6PjVAQDs8 +ODg/OzM9ODY+QTRAPjU+OjY8PTk6OzU8Pjo1PDBDPDk6OTZDOjs+OTREPDw1OTJGPTwxOzZA +PzlEQDhPPz1MQj1DPjxDQD1CPTlIPztBPjc/Pjk9PThDPzpBPT5DPzxHRD1GRTxPRUNSSzp1 +Yk30+LD8//H9//H////z/ur+//b9//b8//P+//r+//H///v6//79//D////9//v3/+/+//z3 +/vL8//by+uzl8uXx+uT8/f/q+Oje9dbl89/e6tve5dTu//H4++/7//L///vx+ef0/vj78+Xk +9d3s8+bs+un5//Hx/fT///7///P4/vT3//L6/fX///n9//j9//n9//3y++7++/f7//D4+fHu +8O1xTmc3QDljST17Tz19SkFaPjxKPDtEQDtJPzxdRzhzR0RrRjlqRzpNPjhEOzs7QDJJRjho +Sj1/UUGBTz13Tj9xRztaQTRQPjZWQDdMQTdcQTRgRjdqRjphQDVHQDo0OTU6OTszOTA5ODUx +Oio6NzcwPC05ODcsOC81OTUvNjU1NTU0NTQwNjE3OTY1PTU3PTQ1NjQ1NzY4ODU0NTM1MzUz +PC0+ODI1PC8+ODkuOjQ/PDo3PzNFPzU2OzU/OjQ5OzNKOjdJOzNYPzpYQDZdRzpMPzg/OTVN +QDZXRjhhQjlUQTlPRTlIQDg/OTNTRz1pWENQQTw8Pi9CPztEQC9gST5mSDNSQDdFQjJEPDlL +PjdNPTpIPTk5PDZBNzg1OS4+QDM4QjQ8NzkzPzE3PjcsPTE6QjY2OjsyPzU2PDxAPjw7Pzw7 +Pzs7QzozPzg5PTk1PDU3PzQyOjQ0PDMtOzI0ODIzNjYvPi80OTo1PTU7QjlCSkJCPz81QTg3 +PDk2QTxKS0FIS0ZJS0RFTEVBQ0A4OTk5Pjg2PDo4PTk0PDc0PjEzPDg2OzQwPjg0ODM0NzI3 +ODYwPjMzOjguNzIzOTguOjA6PDwvOjQ2NjowNiwzOjgwOy43PjYuQDY3OjY7RTNGRTtfU0Ji +TUk/PTs0PDQ0PDUyPjg1Pjg7PzsvPDc1PTczPi42Ojg0QTc/PTc2OjA6OTc3Pi89OzwzODBE +PTxSQjNeRT5YRzNZZklJODhCOjA/Pjc3NDc3PzQ9PzZFQjtGPjpCPTRFOjo6PTJMQTpSRTdJ +PTw4QDU+PjguQDM4Pj4uOi09PDcyPTVEPDg2PDQ+PjA6PDc6PTQ6PTc6QTo7PjM0QDc8Ozg8 +Ozc3PDc6PjY3QDg/QT83PDM3Ozo2PjU/QTg2PTNDUEhVUUBUVkVmZUOBfF2hiWKwkmqliV+y +m2nEmW/DkGjNnnHNqW7VpHvTqnnarILXt4bgu5rrvovkzp3tzaftzKbtyKDlwI/tuZPdvYzo +v43SuIjZuYLUuITNona5lnCnhmOKfFeajmKqj2aOelGDcU+QfFGffVimi1u9nWnNoWrGoWnE +mWjAimGtg1mZdFOlhVeyg1ike1qIelt/d2J4e2Rye2V4fGl5el94dmF0e158dWN4eVt8emN0 +e196dl5ye118cF53eGB4dGB3dlp1cmF0b1x0cVpub1lycF5wa1lSTkc9PDMtPjc1PjZCPzs8 +PDpAQzhAQDVAOjc2PTY8Pjg0PDE8OzgwPzA7Ozk7PjdDPDg7PDhCPj06OTVAPjY2QTY+Pjg4 +OzM4PDlBPTQ8OjQ7QTc1OTE6PTg/OTc5PTZEPzo8PTQ+PTg3OjU5ODk1PDQ9PTYyPDI/Ojk8 +PzRNQTpGQjxHPjw5PzZHQjlDPTlHQjo+QTZBSTg5QD47OTVBPjpAQTtDRz1DTEBVTTx2aUn/ +/8H///z///H///////////////z////////////////////7//T3/fD5/+7////19/Dv++f6 +/+/y/u/8//f3//bu+ufl9OnV58z7/Pfr9+ff7NT//P/t/e33/fDx//T7+/Ps/+z+//z7//P7 +//fs9uz4//n///np9uD1/vv///vt++b6//H7//fx/ejt/u75/vX7//bs6t/o9uX6/uzt9ONy +Umk7QzhfRjpzUj54Sj1bRDZHQTs+PDBHQDxUSTlyTj9qRj1oRD5TPjdEOjk9PTVDRTprSz17 +Tj1/Uj93TjtqRT5aPztMQTdXQzVNPThcQzRmSDpqRD1ZRDROPDg0OzA+ODozOjM1NjgyOyg1 +ODUuNTI5PDgzNDQvOjAwOi8wNzc2OjcyOjI3NzM0PTQzOjEzOzMuNzU0OjUwOi80PDQwOzI7 +OTk3ODM9PDczODM7PTQ4PTNCPTY4ODY8OzFAOTVEQTNPPjZWPDlcPTtcQjZOPjY4OzlMPjNZ +PzZdQzxZPT1NPjo/Ozc/NjBRSTpnVUBRQz06OjFCPjlCNzNcQj5rRzdNQz1GOTpAOzhKOjhP +PztGOzw8PTQ8OjU2PTM7PjI5PTY4PDg1PDQ0PDQ7Qzw5Pjs9PD4zQDQ5QkA2Pj8/Qz47RTo8 +Qz01PDU2NjY3PDo0Ojc0OzQyOjQ0OjszOTU5PDgyOzk4Pz1CTEFMS0g6Rjs8Pzk8QztEQz4/ +TkFCQj84QUM+Rj89QUE+Pz83QD42OjA6QTw4PTkyPTQ1OzszPjQ3PDYvPDM0OzcyOTUyOjku +OzA3OjQuOjEzOjUxPDY1PT0xOjU1PjsxPjI0NDQuOzA1NzUzPDYqPjU4PDQ8QTpMSz1ZUUFL +Rz47PTk4QDQ6QTg6QjU6Q0A2QDk9Ozs1OTQ1PTcyQTQ7PjsxPjM4Ozk2PDI4Ojs1PC1GPjtV +QDtbRTJYRj9SOzlEQDtDPTg8ODU2PDQvOzNCPjhDOjNLPDc/PzlBPDs8PTZNPj9PRDlQQD44 +Ojc9QzcwOTc6Ozg3QjU+Ojo6PTw0PTg3OTs4PTU4Pjc1OjM9Oz08Pjo6Ozk1Pzo1Pzg5PDc6 +OTc9PTwyPzM/O0A5RDA9PDwyQTA6P0E1PDE5PDRDTzlUTkJRS0JrbEyXh2OaiGOig1uhiWKz +nW7Do2zDn3XJp2/JpHnNqXfOr33er4ThvJHqwpXl0Jzs16bk0qjz2q/qzJ3pzpnlxJfjxI3Z +vY3MrH+9o3WxlGacgWSDdlOehmCkjWKOe1iEeFGafViqh1uyiWK/mmjQnnjNoGrIlmfHm2TD +k2ezg2Ced1Wph1e/lWC9kGqwdlp+c1VVYVNJZVNEZVNKblhSc2Vidl52emV3dF53dWB6dV9/ +eGB1dlt6cl1udVh5b15zdFl5cVlyclt3dFt0b1tsbllwbVRUS0g6QTY7Ozk5PTg8PDc3PTVB +Pzk4PThCQDouPjc+QTk1PzU8RDo8QjQ7PjM5OTNBPjk4PTVBQjc6PDRAPztBPzk9QzI8Ojg4 +Pjc6PTQ4QDI4PjQ3PzE4PjI1OjQ5PDFBPTo+Pzg8Pjk2PTY9PDkvQDI8ODouPzQ/Pjg+PjZJ +QTlERDk/Pzg6PjZBPjhBRT1BPzg+Pzo7Qzs/Pjw/PzxBQzw+PTxCQjxGSEBTST93ak/+/73/ +//j///7///7////+//v+//X////////////7//f5//X8/u35//T+//b1//D8//n///z0+vPy +/OX4//Dw/erq9urZ8NTl+t3i8d7e4tTi8tzp/+bt8+ju+uv1/fX19+vy/vL0/+zp+eLl++fz +/O7t9+Xt9+j9/v3///r///n6/fP6/vn5/vb9/fv//////fr///71/fb//fP1/u3t7NxhUmJI +Q0FVSEF8R0F5TkNkRTw8PT1RQD1EPDxkRDhtSUBwRkBmR0FPPzlAPzg2QDJPQjxlRzt5T0N/ +Uz19TT1qQjhaPzpRQDtVPDlMPjdWOTdkQzhpRDpjQzlLOzpBOTk2Ojc4Nzk2NjQ1OzM2Ozcx +ODM7NTMsOjU5OjQzOjE6NjsuOTY5OTk1PjY2Ojc1NjQ5OTQyNTU9NTs2Mjg3Njs1OTo/OjVB +OzozOTg2OTU7Nzc8Pjo7OjY7NzJDPzc9PTdFOTZNPjVcOzxXRDRqQTtQPTdEOz1LQjpfQD1X +QTxbQThJOjdFPDk+OTZOQj1lUUVSQDY/PDc8OjZGNjhbSDtjQzxMQjhEOjFCPjZBPjZPPTpA +PjQ+Ozc0NzE/Njk2OzZFNzsvODY9Ojw4PzdDPj41Oz05OD87Pj42PDw7PUA6Pjs2PDo2QDk/ +Q0I6Pj05ODYyPDoyOjM6NzoxOzI5Nz02OjRGQEJFRTxJRUg8RDY5PT83QTNCSElDPz1AREBB +R0BCRT1GRkdERkdKRUdGQ0Q9PDs2OTg0NjkzODgzODM3Ozk0ODU0OjkvOzM1OjcyOjU5Nzgw +PDU4NjcyOzM3ODgxPDg1OjM2PDk1PjY3PDY3OzI3OjgwNjU9Ojo1PTdHRj5YTkFfTEdoUEpJ +Qj06Qjo3PDg6Q0EzPTE8Q0BFRT0+OjwvOS41Oz00OC82OTs4Ojg6ODczOTU2NzVHPDtOQDNb +QkNYQjVQPzpCPTlCOT4+Ozc2PDw0PTI7PDtKPTdGOztFPTM9NDtDPDpLQDtWQjtGPjc+NzU5 +PDczPjc3OjM3OTQ/ODwwPzA9Ozo0Pi07PTgxOzE2OzoyQzBCPEI5PTQ8OD03RDBCPTw3PC0+ +QD86PDY6QTs3PDo8Ny81PTw2OjU3QTU5OTc1PTRETEJJPDxVYUNvc0+YflyVfFyVfF6jkmW0 +l2q7o3PMqoHLo3nYponXsYXewpfkuI7pwJjlwpfgzKDmy5/k1KTeyJncwpfawpbZuo7PsoDK +qXSslG2ag2l/cFShiWaajGOOdWGFbUqcgV+ujV3EoW7HpGzPq3jOnmrbpnTEmGXGm2a/jmSz +iWOmd1isi1zEmWrKoG3Jm221g1+Sa1ZgTU04TEVEUUJJaFdSb2tTc2lreWNwcmF8c2FyeF96 +dlx5d199dVx0cmV5dF51c2J2cVtycFxvcFlybFZtalNZS0c4Pjk6OTk8Pjo8PzZAQTxBPjtH +PT0+OjI9QD88OTE6QDk7OzQ7PDk5OTY8PDw9PDdFQTU/PDg3PjVBOjk8PTg/PTg5OzRBOT42 +PTc/QDU4OzU9Ozk7Pzo8PTY6OzdCOzlAOjk6Pjg5QDY6Ozg6ODg4OjszOjY9PzlIPzVHOj1H +QjxAPjtAQTpFPj9CQDZJQEFDQTlCPDs5QTlEPzxAQTxGQT1BQTxJRz5USUF6Z1D3/7T///z5 +//H9//f///////z////////9//r////7//b7//r4/u3+//X9//b7/+/6//T//fby+uv8//ny +/e7s+uTn8uTk8+PY6tHo8+Dk7tvd5dr///v++/Py6ubp++v6//nu+On1/PL8//H3//Ls//D+ +//77//P5//Xx++3x/+z+//f1//D4++zx//L7//b7/+ry/PLz8+v4//D4/+/u7+NpTV5CQTxa +RTxyTDh6TENgRDlMRTtDOjdDOzZfRTlqRkBqSDlhRDpVQTo4PTFDPzc/QDRsRzl0Uj+AUT16 +TztyRjRZPjZSQDNPNzdMOjdXOzZiQjlpQzxkQjVVPjlJQDNMOjo5OzM4OzU1OzIzNzMzNzQ2 +OjIzNzc1OjA3OTY4OTI/PDk0OjA3Ojk5Oi80OjU2NDQwODM4ODEqNjQyNDM4OzFBODU1OTA4 +OzQzNzMzPTk7OjBBODY3OTU4OzQ/PTRBOzJJPjVVPDZYPzZiQjlSQDQ6OzRNPTZZQzlbRDVW +QzhGOTVEPjY5PTBJQjVhTTxLQzY7OjBCOTM8PDReRDJjRzVPOjc+PTI/ODhDQjBKPDQ5QDU5 +PDI1OTkxPC0xPDUvODEwOjM9PTc4QjY3Ozs9PTpFS0Y1PTg1ODY6QzY7PTszQzFBQT0zPzVA +PTwzOzU9PDkuODM7NzUwNjg7PjZDRT9CSEE9QD02QzsyOTk2QDs3OTg4OTU0OC48Pz48RTtD +TEVITkhIR0I8PTY+RDw4PTI9Pjw0OjA4PUAxNy00Ozg0NjA0Njk2OzU1Ozg0OzQ3OjI3OjQ2 +OzU1PDY6QDc4OzU5OjUyPjc3ODU3OTI8Ozg2QC8/PTc2QDlCQD1FSTdZTkBjWUd/ZU9mUUVL +Qj8/PDw/Qzo9PDs0PjQ1ODg4OTQ0ODY2PDY5NzQ0ODM4PTo2OzM0NzI2OzU+PzJSQTpcRjZa +RztJOy9DPDxCOjE7PDY2NzI4PTVAPC5KPzdCOzk+PDQ/PDQ6Oy1JRT9QQTdIPz1APTg2ODhA +OTc3QTc4PzI0Oj87ODc5OTU/OTY1PjdAPDY0PTM+Qzk5PDQ/QD01ODc4QzM5PDU1Py86PTcz +OzE9PDMyOjU6PDsyNzU6Oj05OjA6Pzk2NzI6Pzk7RDA/Qj1EVUBwcEmEeVSOgF6QiGOljWe0 +lnK6pnbSpn3Ts4XSs4Xcu5HZsovgvYnZvorbx5LYwJLWvI3TvIbUuoLKp3u+oG+0mm2ohmCG +bFSTfF+ajWGTg1+Eb1GRgF6yjme6nGzJp2/WsnfVrnPOrnLRrnnSp3PNqXLNnWq9lWO9jWem +flavi1q3mmHVrHvQqG/SpXm8jmOwfl6KZk9bR0VIZFNQcmdNdGtLcWZQcmxacmNnc1xueF51 +d1l2b11zbl95cVlvdF14b11tcFZ6cVpmcVtzaFhVTkI6PTUtOzRBPjY9OTY8OzRBQDhCPTg/ +PDg8Piw5QDY1PzE+OzgxQDU9PTZAQzVBPDVBPjZAOzU+PDc9QDRDPTw4PzU9PTs2Oy48PTVB +PjQ4PTk7OzU3PDQ4OjQ7PTc/PTU7OzU7OjQyOjBBOTc0PTg7OzgyOzY4ODpAPjdMQDpIPjg8 +QTVAQDpBQjdFPzdAPjc8Pzg6Pzg/Pzg4QThBQjxHQUJIRj5JREFOR0B2XUr6/7f///r///v/ +//b///z///////b///v///////////z////7/+z///X3/vb5/u36//32/vD8//X3+vTt8+Ts ++ufn++Dm/eHg99Th6uHY58/c6Nrx/+/9//v6//Pz//T3+fD//fn1//X9//r79+r6+u/s9+Tp +/+r4//n///by9O/88Oz07e79/vz///v7/O/+/vr5//Tx+fH4/O34//T98+xtT2E+QjpWRz94 +T0N6SEFkQTpFOzlIPzdCPjlURDlrRT5uSThrRD5NPDNHOzo7PDJPPjhiRzl1T0B7UDx/Tjtw +RD5dPTdVPThSPThNQjpYPDRlSDppRjhiQEFVPzZJODlOQDg9OzE5NDIwNzE9OjcuOTE6ODQx +OzM6Nzo1OjA/Njk2OjQ/Njs5PDU5Ozc2ODM0NDI6NjQ6Mzk1OjI0OjY/NjQ8Nzs8ODY6OTQ0 +ODNANzc4OjhAPDc3OTFCNzo4OzBDOjRKPzZdPT1aQjZpRzhPPzRFPTlEPDNeQD1ZQzVkQjhP +QjpCPTI/ODRDQzhfSEJNQD1ENjVEOTs8PjVdRzthPjlPPTtAOjFCPDU/OzVFODk3PDNCNzYy +PDQ8NDUxPDU+NzgxOjU6OjQ3Nzk5OjhBQ0Q0PDg4ODY7QT08Qzs2PjxJTEA7Ojw3NzU6Ojo8 +QTQ7PD03OTQ7OD05PjVEQkNFSzw9Pj41OzQ4PD02PDAzQDw1PTQyPDI4OTo2PDo9Pjk+SD0/ +QD1BQz9ERT5HRT89Qz41Ojo1OTI6OTkyNzEyOzIzODM9PjY0Oy49PDo2OTY5OzYyOzY4Ozg3 +ODM2OjQ4Njk7PDY5OjgxNzU2OTU2OjQ5Njg0PDc7Ozo6PDtJPkBXTkN4Yk+HdFdsVUZKSUI9 +PTc8QDxHR0JFQkQ+Pjg9Ojw6OTY3Pjc5ODM3Njc8ODw5ODE7Ojo2OjJCOTlOQDdhRT9VQzVK +OTw+OjRCOzU/NzY9NTk6NzRAOTlOOztAPDZGPDVAOjtAOTVNPjhTOzxGPjs8Ozg3QTQ6QTE/ +PTk0PjM+PDk2Py4/Ojc6QC87Njg6QS87Oz05Pyw/PkA0OzM6OTs7QDA6Pjs6Oz84OzQ6OTU4 +Qz1AVlo4NzcvODQ4OTsyNTc8PDsyPDU6PTc5OjlCQD07PThIVT5fbEh7c1mDcVSRiGGii2mx +mXa3q3nCqX7Jq3vCpH7FrX3Ru4zGq3zIsn2+o3fIq3y+nHS6mnizk22ejmSIglmBdFuVflyb +hmd9dlKJZ1akjWHEmnnVr33atIvgt4biuofYsYDSpW/QpXHWrXzaqnfPpXHFmmy8j2yuf2O3 +h1vCk2DLpXLSrHbZq3nGmm7HknCof2B6ZlVHa11SbmdDcGxLc2tGb2xLaG1HaGRNbWVdcWpo +dWFwcl51c115cGN2dF51cFptcVd1ald0a1hWSEY4Pz00OTY9OTo7OS5GQz9CPTU8PTY+PTI9 +Ojw/Nzc8Ozc8OzZAQDlCODpOQDpEPDs8QDRBOzw7OTJDQjk5PDQ/PDk7NzQ+OTs3PDNBPDY3 +PTU7PDU8Ozg6Ozc5OzVCOzNEODc3OzhAOzc4Ozo2OTQ9Ozk2ODI+OTxCPTZVPzxHOzZGOzo9 +PjVHPj5CQTpCOTo5QDlEPTg/QTxEQTo+PDxIPzxAQz5MRTxVRkVwXkft96v9//b///j///// +///7/+/9//n///////r+//b+//X8//j1/ub9//X5/PD9//r1+ez7/O/8//f+//n3//T9//jw ++O3j9OTh9c7m9t7r8+Lb7drr+ePw++j9//7v9+3z/vD+//Hx/ub7//b///L6//X59+/w7uPh +/eL0//P9//77//f3//j8/+31/fP9//X8//jr9uLk8+z1+uv5/ezu9d1fUl1BST1YSDx1TEN0 +SDtlQjs+QzJMOzo+PjZaRjlrRztwRDtiPjhNQjRANzY5PzVEQjdgRzl5UkF9Tz11Uj1wSTpY +QTVRPjhOPTJUQDpQQDdoQz5jSzRkRTpNQzNQOj1JPzFKPDdBNzM3Ozk2ODA1OTI0OjI1OzE0 +NjQ2OzI4NjM1PTQwOjExOjAzNjM2NzQyOS04OjItNi47OjUwOS5FPDU0PC9AOTM1OTA9OTQ3 +OTk9QDg+PTQ7PDU3OzQ+ODJDPDdPOTlVQDtcPjhpQzlRQjU/OTNFPDpYQThcPzhZPzVQPDs9 +OzFBOTtBQDFaSj5JQTA+Nzs9NTBFPTpbQTVgQzVIPjU9PTQ7OjRCPDRDOjw8PjM5NTY4PTQ2 +NjI1PTI4PTY0OTYvPDQwOzQ6Pzg9PDs4PDY8PTozPzk+Qz0/RUE/Qz47PDs2OzM3Ozs5OjM6 +ODgtOjE8PDo9RzlJTEU0PTM2PD4yPTs5OTcwODY3OTIxPTUzOTUzOzg7PTI4Qj88QzU/SUFM +S0JLTU1BRT07Rj83PjkyPTI0OzYzPDA8PjwyOzQ5NzowPDY5Njk0OjI8OTsxPjQ4PDU1OjM4 +PzYxQC83PDUzPDM2PDU1OTUtOzs1OTY4PDk4PjM9RTdFSjlaV0JuaEV7Y01fT0JMQj45QSw9 +QDxATEBKSkM9Rjg5PTowOjI5QD8yNy86OT02NzM6PTs1Pzc3Py47PDlSQzVYQzhUQTtHPThD +PzY+Pjg9PDYvODc1OTk6PTRGOTo7OzFIODs6PjRAQDpFPzhUPzo7QjREOzszQDQ5PDU5PDo0 +OzY5PTc6QTY0PDQ5PzQ2PTc7QDg0QDc7Ozc2PTw8PDg2QDc7QD0vPDE8Oz0vTD4/Wl4zU0hB +YGQ3Pjk6QDovPDMzOTpDRzxcRzxDOzw5PDc7PTk6PDU6Pzs9STZNVENgY0dkbkx6elR+elaL +iVuRiWilkmmdjGadi2uRh2WWh2COjGWdi2OVjmSUiFiFelxzbVN6aU+RjFqWfmCCelCDbFCq +h2PLrXbNr3ncsn/ixInkuYvguX3fsX3asHfSrXnTs3ncsnvSsHTSpnTJomzClmO4i2XBk2PA +lmLMqXPPq3XXsX7UsX7PpnqtjGpxbmZKbmVQc3BCdWxGbW5Ha2ZMdWhKbmdLcHFFbGxIeXlP +fX1bcG9rcFpnb1trb1d0b1ZtdVxraVZOSEI3Ozo0PDc4ODg1PTRBPDs8QDdCPTw4QDM8Ozcu +QDE6Ozk0PzRAPT08PzY+Qjc7PzQ/PTg8Ozk+PC89Pjc7Pzc6OTY7QDU7PDI+PzI8Pjc8Ozo0 +PjE9ODk5PzFBPTo/PjRJOzkzOjRAPD4xOzJCPTwyPDY7QTU1PDVDPjlIPzxCQTtDPjo7OTY/ +OTtBQTpFPTpAQDpBRj49RD8+QTRDRj9IQTtDRUNGQzhXTEduZkL0/7r///////////3///// +///7//P+/+////7////3//b+//P///D+//f7//n////8//vt9efy+eT8//ny/ez3+u/1//Lq +/ujf9dPY5tjh6tfp9+X1+vLx/PL0//f0/evw/u/2/+vr++nx/ejx//D6/vT0//T5+/n///z/ +///t9+jw+O31/+zt++ju+uvz/u36+fD+//j///n///7u8Onp79t1T2c7Pz1WRD9zTj51RkBo +RTxFQjpLQDk4PTZZQTliRzpxRj9hRjpRPTc9PDk9QTNDPTlcRjhySz54Tzt8T0FsSjtbPjtO +QjZWPjpLPDhZQTdaRDVoPzxoRz1SPjlMPTdIOzhJPjpSPjRGPTUzNjEzPDg0NzAtOjU3ODYz +PDU4OzItOzM5NjguOTA3NjMzPjQ2NjQyOC80Nzk0OjM3OzE+PDBAOzc3PjE0NzMxPjM4OTM9 +PjZAOzY5OzM0NjZAPDY8QDRGPjdSPzVeQjdkRDpTQTRAOjlBPTJYQTpVRjhcQTxMQDhFOTc3 +PDRFPDxORzVNOzo6OC88OTVCQThZRTdaRDtIPjU+QDU6Pzc6NjI7OzkzOTA3OzMsNTA7Ozky +Ojc0PTwwOjQ7QTkyQDRAQD0xOTVAOzs4Rzw/PjguOzs6PjgwPjY4Ozk3Pzg2PDk3NzgtOjU5 +PzdBQj9DSEU7RD8yPDExPTkxOzU0OjktOTMzODgvNjI0OjwvNy04QDc9RTg8R0VFS0FNTk9F +QkZMUUdDREMxOTY0OjcxPDg3Pzg2Pjo9QD02ODkzOzU6PTcyOjg2OzgwOjM0OjkxPTY4PDky +PjI7PDkyPjQ3PjcvOzc4PzUtOTcvPDU3PDUzOTc5QTlPUEJraU59alN7ZVZSSTw+Pz0+QzxE +RUNDRUI/Qzo9QjszOzAzOjgzOTI1Ozw0OzUzOT01Ni4/OThEOTRNQzhYRTxQQDNGPTo9OjRB +Ozo3PCw2OzYzPjQ7PT9DQTpDPjtDQDg8PjhDPzRCQDlRRThAPTtBPzE3OTc7QDU1QDk4PTM2 +Pjo4OzA4PTw0OzQ6Qjk6PjQ8PEAwOTU7Pz0yOzA9PkA2QTQ8QUY7WUpBXWs1VEo4UUlBblxQ +VlZqUUBXRUA6QjhKSUNaXE1zZ0hiP0A6ODw7OzlCPjo5QjY+STs/Rj9QVUNPXkZiYk1kbU1o +c1Fuck53d1VvdFhwb09bYUZcY0hbW0VrXFBqWkuBb1OUgWSRi1yGdVN6Z1CTeVe8nHPTtoXg +vYjavI7nypboxI7rx5Plwo3jvYjatHvgsIPatnfZuHzZr3PWq3vGo2vBnmq8jWXGk2nHm2nJ +rGzTrXTQr3fUsX7LrHO3lG5kfGFLeWxLcmlIcWlMcWlCb2lGdW4/cnZQcm5CcHNSbnY8c29M +cnpLb3FgdF9obmFqcFpycVxmalpSREY3PTg/PTo0PzQ/OTk7PThCQDk9Pzs8PDY4PTc5PzM1 +Ojc6PDM5QTk4QzU8QTw4PTY8QT46Pjc7PjY+QDc4PTY+Pzc2PjY8Ozg3PTY9PDYyPzE5Ojc4 +NzQ8OzU4QS1APjs7PjY3PDYvPjQ5PTM6PDc6OzU2PDY3OzdCPDdIPjtIQDhCQTo+QzdFPTg/ +QDNFPjw5PTk8PTw6QTZCQj4/QEJEQjpAQDxOST9TUUJuX0rv/Kv+//31/fD+//j3//P4/+/+ +//////////////////////////Xz/fLy/+rq+ebl9OP2+er+//ny+/X3//D9//7r++bp+ubW +6dHj7N7y+urt5+r0//n1/+nt+u3p/ubx8uv1//H6//bu/+bw++zx/Or7//z////9/+/6//D/ +//r///3///////379+z7+/Hy++3z++v0+O3y8+v5/Pn79ex4TGE0PDlbRjhmUTp6Sz5eQD1M +Qjg/Pjg9QDZQQjtiRzdrRj1kSDdRPzU4PjY/OjhASDdjRjlrSzp6TjpzTDhpRzhYQzVQOjhO +PDlRPTlTPzdgRDhmQTdkQTdRPTlNPDBKPjZNPDNQQDdSOTU7PzIuNTMuPS81NjUtODA2OTMv +OjA1OTMwPS8zOjE1ODA5ODI0Ny41PC4sNzI3OjU1OjU9OjQ8NDAwODM4Ny01PDU4OTI8PzA1 +PDI8OTc3OTFBNjU9OzNMPDpUQTVeQDhjRTZZOzk4PDNFOzRSQzVdSjdbRDZQQTdBNzE7PTJA +PjVQQjdJQjc2ODQ7OzQ/QTZWQjVYPzdFOzE/ODM3Nis/Ojg0PjQ8PDUvNyw7PDguPTI4OTou +ODQ9PjwxPDxAPTkvPTQ4OTM+OzowOzM0OTU1OjY8QjY4PTs2PDUzPDk4OjU0PTU8RjpGTUZB +SEY7RDwvNzIyODkzPDA0ODcvOi0xPjctODIyOTwvOjYxPDQ4PjQ4RzxERz89QThHQkBPUUlK +TEc3Qjk4Pjk3Pjo9PjU7QTk6Qz09QTsyPTQ6QjUxPDQ1OjswPTE5PTUyOTU+Pjk0PDU4PjE0 +OzQzPDAzOzQ0OjYzPDYzPjQ1OTgzOzU3PzY1PzQ4PzI9RTxXZkRtW0tTRj0/Qj07QzlDREE9 +Qzw0Pj5AQTg3PToyPjIsOjUzNTI1PTc8OTgwOTA2OT09PzRQQTtVQzhQQzhFPTU9OzZBQjU4 +OjU0PTMxOjU8PDFCOjdEPTc+OjFAPjM7OzJHQjRMQDlBQTI6Ozw4OzE5NzcwPDM4PTo1PjI+ +Pzg1PTA1PjkzQjE+PTs3ODE4PTg0PDE2Pjs3QjM9Tk9Dal9BZGw/YmY7U1U7U01FaWVUcVuB +dVluU0I+PDxGUT1kXEh0aVCNdVR3V0JJRzs3OS8/OzouPyY5Qzk8RzBDRj9ARzxXSkZOSkBf +UUFdV0lwakt+bFSBfFiJfFyUe1uJflyFf1eBeFZ6cEx3ZkSXd1e5n23Kq37OuYPbsX/kyI7q +x5Poz4zpyIvmwoTovYLevH7Ztnvas3zbuHzdu37UsH7OrnbIpm3Emm28lmLBoG3JpW7HpWzL +q3HOr3bOrHPDn26miGdVfGhReXJDcmtMcGtAcmtMcmtEcW9Kcm1KcXZIdnlKd3pCbXFAbHBH +dXJJZ2xCaWhWb2Fdb15laVhGS0Y0QDVMTT05Ozo8OzM8OzA4PzZBRDM+PDo2OjE5PTUyOzQ1 +PDk3PTQ1PjQ9PzY5QTQ7OzY6PDI+PzU4PjJBPjc6QzU/PTc1PjI6Ojc8PTc1PTMyOzQ9PTc3 +PzI7PDM7Pzc/PjU4PjY0PTc6PzEtPDYzPjAvOzM5QjBDOzhFQDZLPzo5QTQ+OzozPjdEQTc7 +PjdCQTg3PzM9QTk3QjtEOj49RjlJRTdGRjpUST1oXUnz/a3+//j////////////+//n8//f9 +//n///r4//H///n///z///T///////71/+/7//r7//n5/+/2/+74/fPf7d3k7NTj+d/f/dPq +/ebn9eLb5NLy/+74+fPy8+fy/e/3+ejq+uX7//P6/+z1/O32//D1/vL6/+r8/fX+//7///fz ++eLx/uvv/+b4+ev0+ebp/Oj6//r7++3+//jy9ero6N1tU146RDhYRzpxTD50TTxlQj5HQzhE +PDZIQTlTRzZmTz1nRzxsQDhLPTVJPjY4PjdOQDVeRjx0Tj56Tjx3SjluRjhWQDVWPDlOQjVZ +PjhXPTVnQjhmQzdqRzlVPzdSQjdSPTdNQDdZQDRaSDRMPTQ3OC85PjU5PDA5Pjc7NzI7PTQ/ +OzQ4PTM5OjM9OzE9OzA1Oy8+PDUzPC06NzQ2PTQ8OTc9Oy87PDM7PTU8PTU4PDY9OzY+OzU9 +ODMzPS8+PDFEPDRLPjVcRDRcRTZpRzZgQjY8OTJGOjZRRTdnSDtiSDlTPTlBQDFDOTc9PTNN +QDhIQjZCODc3PTBCOzhTRjZmRDlEPzZDPDVBPTU9PTA5OzQ4PzI3PDQ1OC83ODM4PDozPjc+ +Oz08RDRCQz44OjU7QEE0QDdAQj01PDk9Pjg9RDpEPT01OjVAPjY5PDs6PTlETj1LTE1BQUM3 +QTw1OzYzNzYyPDQwPDQ3OjUzPTY0OTM4Ozc1PjU8Nzw2PThEQEA8QDdERkJNU0JLTExLTD1H +RUhBRD1BQ0I/QkE4PzJAQjw9Qzg/QDk+Pzk5PjY5PjU8Qjs8PDc5PjY3Ojw4Ozg/PDk3PTVA +QDw3PTBDPTw5PDlCQD07QDdAPjo2Ojk7PDY6PDlBQDpRSj5iV0dTRj0/QjpDQTo9RDhHREY5 +Pzc8PTNBPUA7PzU4Ozs3OzA8PTY3Pyw9PD03Ni1BOjxRRThYRjlTPzRKOzxEQzZAPDhCQTg4 +PTc4ODc/PjpMPTtGOzREPjhAQC1BPDdKQjpTRz1LPTU+OzlAPDo9PTdAQTo0PjY6PzM3QTpB +QDc5PzRBQzQ4PDU3RDpAQDU/RzxCU1k6Yls/WllHbmtKcW5DaGZEXGA+XUxJb2JcfVuNeWVv +VERERkFTUjtlYEl8a0yKe2CdiWSedVd9WUVeSzlEQjo/QjdAQThEQzxGSj9OTD9QVkdhW0he +XkpjakhpaE5salRsZUVyZ05jX0d7YkyMcFC7nG3GoXzXroLWtIjbuoXiyZfxyJzs0Zjs0JTl +ypPrzJrnwYbmvYnhunrlt3ncu37btYLduYHeroHOrXfPoXrEpW3Dm23KqWrQpnbOqXDRqnrR +rH3Fo3K2l3CEfGVVdmpOdXBQcm1MdG1Ocm9Kc2tJcGtQcW1Ic3RRdXlGc3ZRcnhKdHRMbnFC +cW5McHRBcG9ScXdIb3RMT1k4Pzw5QDY6Pjk4RDVCPzlAQTdCQjtDQDg+PjhAPjU5PDU7Ozc9 +PTI/QTk8QTZDRTs/OzBCPT49PzFAQTo9PjM9PTpBPDE0QDY8QTU8QjE+PDU2QTA/PDg0Pi49 +PTs8PDZDOjg+Py88PjY7PTI3PDQ1PDE7OjY3PDVGQjVKPzhLRDlJPjxDPDxFQzc+QTZGQzk7 +PDs7PzRCPTtDQTZLQjw/Rj5FRUBMTDxZTkBwZkX6/7j7/+r+//j///////////////////// +///////////8//T9/+3///3///7////////////3+vfz/+jy/O72/Ov9+/3j8ODd79Te8djY +59Hc6tHq//L9//z9///////7//z7//n69+Tt/en0+ev0/vX8/e/q9eT8//f0/+n8/fj49+vt +9u3+/vv///7/////+/fq7t7r9eH+//L9/+/s8ONmUF0+PzpURDtvST9zSz9iQDpKOzNBPjRF +PDVTQzdvQTppRTpqQzpMPDdEPDY3ODBLPzdZRTRvTEB1UDp4SkFsRjZaQTpMOjRURTtVPzRU +PzljRTdlSDdpRjdSPzZROTZRPzNMPDdWQTdaQDRRPTMyOyw6OzAwOzE+OjUwPTA9PTQ0OjFH +Ojc3PDI9NzM2PTNAOjE2OjQ3PTMxNTI0OjI9OTc7OTE7OTM8NzU8OTQ2PjI9OjM8OzI/PS86 +Ozk/OjJAOjlIOzRZQDhgQjJsQjpbQTE+Ozk+OzBWRTtiRjdhRzlXRDhFQTY/ODY6OTNIOjdF +PjZDNjg7PjNEOjVUQzdfQTxBPTU8Oi84PzE7PDE+PDY5PDU4OS82NjE4OTE3ODZAPDg3OjY8 +Pzo6OTg4PjY4OjkwQjM/Pjs2OzQ/OTo8PTQ8PDkyPDY+PjoyOjY7PjRFS0FCQj41OjY7OTIu +NjQzOTE0ODwxNzIxNzEyOCw0Nzk2QTg0OzE2PDczOzY8Ojc4OzE/Ojw7Rj1RT0lUUUxTTElK +UERRRkZCRDxHSUA/Rj8/Nzs6QDhAQTw6PDc+QjhAPTs6QDQ+Pzo8QDc8PTdCQz5CQz1BQTw/ +PzRLQjhGSDVXSD9TTDpTSEQ+QjFBQz1ERjNFQjxUSzpdUUhSRzlDQ0A+QTg8Pj1ESEI/PTc6 +ODY1OjY5QTU5ODgzOzgzOTM1NjY8PTw3PC1AQTdQQzlaPj5KQzRJPDc4PThHPDo1PTA5OjUv +NTU9PDREPztDPTY/PTY/OjM/PzdOQzNRQD1GQDdCOzs1QDI4Pjc6Pjg7PTc8OjouQTg8Ozk3 +PDFAQjs2PzA6TUdGZV1IeYlQc39EdH1FZ2JIbXNDamJDa2tEZWA8VE1Ba2NWeVyFbllcTTtO +T0ZcUEJkVkl8ckqPeVyjj2amiWqtjWqlhWSZbk91Y0aBYkh2UUdyVT5nU0RpTz1lTkNkV0Jy +X0B2WUWNZU2gfFuxjGu8pHTPq3zOsX3ewIvau4nex5XiwpDryZftzJTt0Zzs153u0Zvt05/y +x5foxpDqw4PhwIrjtoXet4XhvYPiun/duH/UrHzMp3nLoW3JoGvKp23VqnzPrXbRq3zAnXa7 +n3OolXJjeWdMcmtKdG1Nc2hPcGxHcHFHc3FIb25KenVJdn5GdXtIc3pPbnlDdHlHbnZBZ3FF +Z25Dcm1Od3pJgHxQd4JFb3pFVGc7PD9HRj9BPTtCQjtBOzhDQDo9OjY4PTU5OTQ6NzY+PDQ/ +WDpWVF1DOzY9PTdFPjs5Oi49PDQ5PjBFOj01PDBAOjk2PTNGPTs1PDE9PDY5OjY/PzI3PTVE +Pzc/OzY/OTE8PDI6PDU8NzQyPTI5OTE5PTRKSTdGQEFGPDM+Pzc9PzZCPDpEQTRDRD0+PjRA +QDo9Py5FQD1DQTdCQEJERDpFQjxZSUBpYUbx+K79//j////3//H6/+79//j+//T8//L4/+39 +//b8//H8//r8/u79//P9//b5/+7y/ez2/+z0/+78/+/w/unz//Dz//Do9+Tk+d3i7d/p89rt +++n5/+30/fDy/+vs8+fx/ej5//D5/vb7//75//X6//v+//z9//v+//3///f9//T+//n///n7 +//f8/+7x/+////3z//n/+ez5+/Lx9+v08+BeUWA6PD9PRjhpSTttTDxiQjtGPThJQDZAPDdU +Qz5oRzlpSjdnRDhRPTY9OzE3PDZCQjdhRTtqTjx5TTx1UEJsRzpVQzVRPjRPQzZWPj1PQzVj +QjxjSTppRjhVPzZRQzpMQDVMPjhXQC9ePjZIQDM6ODk4PzE1OzE0OzA0Pi83OTI3OTI6PDYz +OzU7PTM3PzU1OTIzOjUwOjQ0OTcwOzE5OjcyOi84NC47OTA9OjUwOy49PDc1PS48OjU6PS4+ +Pjg7PjNNQDdVQDZiRTlmRTtWQjFBOTRAPzVTQTReRzhiRDpRQDpEPjI/OjM0OzJDPDU9OjQ8 +OjM2PzBCPTlMQDZVPj07PDVFOjktOjQ+PzQzODk7PDY0ODQyPDQyNzExPTg1Qjg3OzQ4Ojk1 +PTU2OjQsPTQ2QzU3PTgwPS81Pjc0QDM4Ojw1QDA0OzwzOS86R0BFQkc2PD42OS0wPDczNzEx +OzE1NjoxODUxPDMxOzMzNjQwOzgzOjMvOzYyOTE3Pjc3QTU+RTg7RjtVX1FRW1FbYFRaXExX +XFRNS0JGSEI+QUVERUBBSEE8QDtBRkM8QDlAQj48RDtHRz9BSj1CRDxDRztORj9RSjxmVEtq +XkmNe1mRcWCNcFqDaVR3XkptWER2Y0lmUEVjVkBiV0pPRD4/RDtGRT49QzdEQj86Qjc6QTgv +PS03PDosPjIyOTgxOi42PjkxNzM2PTc8PTVMQzxTRTZMPDtGPTU7QTlEOjkyPTo0Ozg0PDY7 +PDlDPzM7QDFCPzI+PzBCPzZHRDVSPDg+QTVAQDkzQTA7PzQzQDE6PDk4PTQ6QDsyQjA3STo8 +YVBFdnpFf4hLgYJFeIJKeYNHb4BIdXM/a2dCZ2M7ZWE8Y2A2T0s/amJIbF1tV05MTjtcXE1d +Xz1mYEtmb0ySfWCbj2qvk3Gun26ym26ljWmVfGGdgmCTh16ei2qlj2Omg2Wkk2uul3aum3HA +o3LLqXzJr3vTs4TTw5HixZHZv5Dmy5vm05nozJ7ozJfryKLmzpbs05rs1JXq1JXu0JTp1I/o +zI/mxZHlwo7kv4XjwI7mx4zhuIPbtILXtHjQsnnKpm3MqnHMrXvUq3nOr3vLpHW1lGysmGxp +emVVeG5Lem9GcW9Mc21KdGdKcWpEcGZNcm9EfX5Sen9FeXhIdX9DcnlKbnc/cXRHa3BAb3JC +anNCaHBCa3JDb3ZId3dIgYRUfIRIanxDUVY+QT07PTg5PjQ+PTkyPTM4PTY6PjU+PDk4QDs/ +QD44QDM8PTg4PjU9PjQ6PzM7Pjg9PTg6OzYwOzQ5PTg/Qzg0PDs2OzQ9PDo3PTE9PDg7PTQ9 +QjY6Qjg2PjMvPjQyOjgyOC84PzMyQjdLQDhAPzdIQDo+QDxAQDo6PzZBPDU6RTY2PDo/Qzk+ +PzQ3PDlAQDk/PzlFR0BHSDtVS0JpcEr6/8X///////////3///v5//H9//v///////////// +//zy/+76/+b0/+z6//j///r5/PLy++b4/fH4//nz/e7m7ODe6dfi9dzi+dvk8tns+ujY4tLx ++/T4/vT7/fT0+e7p/ej0/Oz8//T+//j8//j6//Hv/+74//jo/eLx/uzw/uz+//r///Hs/uj8 +/+799/Lm+9z6/+3p9Of6/vD///v19+hbUWM2RTlSSjhvUkR2SkBdRj1GQztEQTs+QjZYRDtk +TTttR0BbRjRURDw/QTVAPjxEQTZZRjxrSjdyUT5zTz1rTD9TPzhNRDhYQTlSQTpZRDdhRjhk +RjZjRThTPj1PRjlRQkBSRDpYSDxbRjhCPzQ/OjQuPzE8OTcwOzY4PjgtPDU+ODY6PTU8PzQ5 +ODc4Ozc2ODk2PjA0OjUwQDA5NjMxOzM6OTU0OjQ+PTQ4PjU5PjQ3PTY4PTM+PTw+Pi8/PTU+ +Py9JRDhbQjleQzxpRjZbRTlGOjc4NzFWRDheSThkSUBSRDlHPjs+Pzc/PjVBPzZBPTk4OzJA +OzVBOjpNQzlQPTxDOTU5QDQ5PTM6PDU3PDI6PTMvNDY0PTQ0PDQ1PjY8QjozPDM1OzkzPjE5 +QTY1QzM5PTsvQTU8OzozPzg7Pzc0Pjk3PDUuPC85PTk4QDw4OzcyQDQwPDQvPDo0OS0uOTU3 +OzQvOTAzPDYvOzg0NzwzPzM3PDkwPTM1Pjk1PzA5Pjg3QzhFT0RHUUNfY15NT0hRT05VXVRX +VU5NUUpRU1FVV0xKUFBKTkJWU1NQT0paXlJUVktPSkJMTD1SSURMSj9hVUV2aUuUg2ajfm23 +noK/mHTCpIi2j3OZeWWfhWOacmCAZUp6YVNtXUxeVT9UTkFISkE+Rzw4PjY2RTg+QzsvPjM2 +QDgzPTU5OjgyPzk5OzUtPS8+Qzw6Py9TQztQQzZVQzZDPzdFPzg9PTdBPzY7OzgtQDU9PzlF +RzpEQjlCPjhBPjxEQTdNQkBORz5ERjg/Qjw2Pzc8PkA6RDI3RTs7QTU/Qj80U0FDamREc25D +eHxEeH5PfYtTeoRGen1IbHFCd3NJbm1BbGhCamw8Y2E7U1VBZFdLb2RhYEVVVklvaUxlY05z +YkpqcVSNgVifiWiyn3OzpnTBpniulHCpiGGmkmatkXCuk3Cvm224pXq+rH3BrIbBpnvStYnO +uYnUv5DZwZLkyZnjzZfkzpnl0Zrp0p7m2qLszaHs05bw2Jvr06Dq1J3qzpjrzI/p0JLqyY3j +yZLmyIflxozlx4/hxIzdv4jUsX/du4XSr3bQrn/Lq3LQrHjSr3jSr4DApnOrl25qfmRPeHNL +eGdBeHNHd3FJb29EcHBJcWpFcWpKfHdPe4NKf4RNfH5Gd31Cd3lKdndCcnJEcHc9cXRGbHU9 +ZmdDbnFDb3RCbndGeHhJeX1ShIVSgodMZntASlVBPzw5Rjg5Qjk3QDk3PTQ5PzQ4PjU6QDo1 +RTZGRTs6QzNDQDszQjVFQDovOzQ8PjcxQzhBQjg9PTc8QDY5Pzg2QDg7PDY7QjlCPTg9PzQ6 +PTc5QDM5OzQ5PDs6PjAwOjc6PzhIRztEQjhGREJAPzVBRD4+QTREQT8+Qjg7QT9AQjRBRj0/ +QjdCPzlHQj1GSj9ORkNXSkF2d0z//9P///zy//b+//b///////////////v///////3///v/ +//////f////+//b+//f////////6///r++bi9Nzt9uH9//vu/u/e79Xh8dzf79vl8N73//X4 +/+zs/uz0+eTj9eb+/vv9//X//+3z/fHz+ebu/ef5/fX///j9//Py/efx/+fz+en5/+7t9N7r +++P3+vH8+/nx5uT5/vL4/+jx9uJiU2Q8PzZUQD1nTDtzRj9cQDhFQjpIQD5HPzVQQz1jQjRq +RD1lRjlSQDVFQTxAQDRIQTlZSjVtTTtySzt2TkFuTDphRT5MQDVXPzhNRzRaPzthRztmQjdk +Pj1YQT1JQjlQOj1OPDRIQzhGPDg7QDUzOzIzOTMzNzA6OTIxOjQ3OTk6NzQ6ODotPzI9OTY0 +OjJANzc4OjI5ODsvPS82NTYuOzA5OjU1PDQ7PTU6OjMxOzE7OTI8PDlCOjk/OTc4OjE+QTZI +OjRgQDhdQzdnSDZYRTZEOjY6QDBVPjlWSThnSDtOQzlKOzU6OzdDPzQ6OzdBOzRDOzU8PzI+ +PjRIOjhFQjc+PDc4OzE3PTU/OTU3QDY6PjU0Ojg3OTQ3PTgxPDA6Oz41OzA8PD0zOS1CQDw3 +OjM4Pzo4NjU2NjM0PDgyPDUyOTgtODM6NDMyPzY2NjQzOTI5ODU0NzUyOi8uOjE0NjQ3Ozkt +PjI0OzQxOTQ6Pjg0OzM3NDgvPDM3OTcwPTY9Pjg9QTc8Qj1JTUdNUUlQUUxdYFFYUlBWW1RX +YFNQVk1XVklJVEhQTUlTVktUVlBMTUdNT0NUTU9aTD9iU0VrWkd9bFKoj3a7mYfLtI/SuJLc +wpDbwIzVrovFnXPLqX+7kW2wf2uYcWCWd21wW01YR0NAPzc/QTc+QDc3PDg7OjU4Ojk1QDQ2 +Nzc5PTo4OTc2OjM0QDk3OzU+PjZHQjdUQTxLPThHPj08PjRBOjo1OzM5OzQ3QC9APTdHQDBD +PT0/QTNEOzlEQDVUQUFOQjFIRjtCQjw5QC00PDw5QDk+ST1DYGJFb3lDa21GcHVLdX0+aXFE +bm5De3dLfX9Je4ZFZG1Hcm9Lb3lHbGNIaWY8ZGBEU1w/Y15QbGhfXFBWYEdvcFR5a1V0bFB0 +c0uGeludh2SnlG+8n2y3nHa9nnq1pHi+mHWtoHG7oXq8pnzMrInMtofHtIjLsYTVxI7eyI/c +wJDdwpTaxZPnx5LhyJXlyZjp15z23afy2aDz06bw1aL016Dxz6HszJbxzZ3qzZbtx4nlyI/s +vo/hxozmxonhw4joxYveu4Ddt37at4LOsHnRrH3GqXe9o3W1o3GUj3RaemtTcWtKcWdLcXVN +d2xMeHFLdW9Kc3BKcW9OfoFPhoVOdntFdXxOdn1CdHZHcnRFcndCbXE+a29CbXM+b3JDa3FF +b25GcXdDcXhGdnpDdXdGdX9FdHlMfXtJeH1UZnpARFc/QUA4PzY8Ozg4Ojk5PTY7Pjc9PTc9 +QTc9QDY7RTRAPDk6PTM7QDc5PTM/PTU3PzM/QDYzPDA9PTQ1OzY7PjY5PTRGPzg8PzE8OzU3 +PDM+WT9sXX06ODg5PTZAPTNHRDZIRjtJRTw5QTg6QzU/PztARDZBQD0/QDtBPTs9QzlCQD1B +PjZIQ0BERTdRR0RTTD92dUzy/7z8//f9//b////////9//v///////7////////////9///9 +//T///z+//P+//f1/vPq+eTt9uH8/f/8//P5//Lr9+jk9ePh+dPr+Ofi6tzg79rq/+bm9OX0 +/vP+//z////z/+v19eTk+eP5/vX9//X8/e/w/On2//f///z9//H7/PH///3///n6//L///7/ +//P9//v1+e/+/fPx9uTu6+BTTVU7PD1ZRDtsSzxuSTtgRDxLQTpEPzhEOzlQRDVkRjxpRzhp +RTtRPzc9PjVEPTREQDhhSD5nSzx7Tz1yTztzSj1XPztSOTdPPztaPzhTQT1dRTZnRDhgRDVP +PzhEQDNCPTs8PTQ6NzYzPzI8NDYyOzEzNzI2OTMzPDI0OjU1NisvPTQyPC42OTc1PSw7OzY4 +PC8zOzM3PC8xPDE4OTMzNzQ2OTMwOjA4OzQwOjE5OzQzOjQ8Ozk7PjY+OTc9Ojc+PDRJOzZW +QjhgQjhnQjhZQzZCQDY+OzZPQzdfRTlhSkBXPztEPjZBPDFEODU8OjNGPjk4PTQ/Pjg6PTZG +PDhIPzdEPDo0OjQ7NTg1PzMzOzQzOzY3PjM0OTI5OTs2Ozs4OjM1OzY3PTY5PjQ7PDg4OzY9 +PzoyOjE7NzotPjY2ODovOTE2Ozk2OC47OTstOzM6ODopOjA/NDoxODc3OjEzOjU5Ojs0NzM4 +Nzc1PTQzODQxOzU3Njg2ODQ3QTc3PTY3QDg1OzE7Qz5BRTpJTEdHSEBKTUdMTEVWW1RPVUpI +S1A/STZES0dESDpIS0dGQ0FGRDtYVkVkV0x4aFGOd1mSflyokHDHpo3Pw5TfyKPgxZrfw5Hk +xI7UrX/UtX3XvYzUqoLCoXu6kXarh2uDZVVjVk5TRT9DQTw5OzY8QDs3PjA2PTM3Pjg3ODsy +PDU7PDg1NzY4ODY9Pjg9PDtMQzxTPzlNPkFDPjNAPj07PC45PTkyPTE2QTs/QTRDQDxGPzE+ +QDZFPDlEPzlPQTpRQThJQDw8PTM5SUA9T0lDY2xDbnFEdH1OdnZJbHNKb3NGeH9NbHI8aXVL +bnVEc3dSd34/cHdQdHlGbHtHamxEaWZIaWU/VFg7ZlpNcGxRYUtlalV9dE+NbluAdVZ9aVeD +e1eZhmWnime2o33ArG7CroLErnvDo4HAp3rDpX3Jq4LDuIDQuojOwIzVs4zWwo/ZvYravpPi +wZPsyp3r1KTx1Kjx1qTw36bx26Xz2KTz1qLy1qXx1p331qLwzZ3s1ZTvy5LpxYvqx4zqzZDl +x43xyZnlxY7mwo3dvYveuoTVtH7TsoTKqnvAoHamoHZ3g3FScWZRdW5FcGFNc3NFeGtOeHVJ +cG9NbW9Mc29Gf3lYhoxMd35NeoFFen1MdoBJbnxIcHlGc3dEbXdAcnRAa3VHaHA/bXJJanA/ +bHJKcHdBcXZNcHpCdHxJbnpDcHlHc3lGeHdMdX1HYnU+RlQ9Pj00QDQ+PzpCPzlGQzw9QDg+ +PTk6QDY9QDU7Ozg9ODdAOT06OTU9Pzs9QDM5Qjs3OjY+Pjs5PjQ/PztEQDg+PDs/OTk5NjY5 +PzYzQTs4OzUvQDRTRj1HPzhLQzpCPzdEQzk/PTVAPDVDPTw/Ozk9Qj06Qzg6QT1BQTVHPjtB +RDxGRTtLRj1ZTj91blHj8b76/e78/e/x/+n6/vH////2/vf+//D///////v9//v+//n+//f/ +///////+//v5/+3////3//nx/eju/Oj3//bm9+Ho9uje89jh7dvY5tTc5tj///D3/vz////z +/e/v9uXy9/T6+vPx/PDw/+////f///z///P6//H0/PL9//z////z/Pj///7///v8//r///f4 +/fL7/fH+//Pw/+nq4cpZTFI+RTxRRD5pSj1wREBfRDlHQjpFQDo/QThTQD1hSDluRj5lRjxa +QTk9PDBEPztMQTljRTxmSzZ7U0F1STlsRD9WRjZHQDtFQTlOQD1QPzVVPzhTQjpMPjpCODc3 +OzM0ODg7ODg5NzE7NDcyOTI2OzQwOTM/OjYzOTU9NzgyODE+OTstOzA/NzgzNjM5QDc2NjE7 +PDs7NjQ1OTU7ODU2OzY3MjczODI1NjI6NzQtNjM1ODQvPTE2OzI4PTI6OzM5PTFMQTtVRDdm +QTteRjZiQDo9PTNAPDhHQDhjSDxkRztYPjhFOzU8OTc6OjM6PjE8Ozw6PjFAODZAOzZHODZE +PTw9NzQ8OTk2OTQ3PTYzOjE5PDo0OTM4ODk6PTc3PD02PTM8Ozw8PDg7RDc0OzUvOTI4Pjg3 +PTU5PDcvOjQyOTMzOjQ5OzM6Pjo4ODc0ODk2NzM0NzU1NzQzNzQzOTE0OTYyPTU1OjkwODM3 +PjYyODw1ODUyOTcyPjo2OTE2Ojc1PDgwQTY8QDs3Pzw8Ozw1PTg+PDhCSENFRUFBQUJBQDk+ +Qj07QDY6QTo5PDlDRD1XUUNwZlKNelmpl3y8pYW+moLMtJHZzqXcxaHf1J3lyZ/ox5vkxZfi +wo3nx5zixZXhv5TRqYHHo3m4i2mQcFhyXExdTEVIRD89PjxAQT01OzU3Ojk0PjUyPzY2OjUz +OTM0PDMwPjE+PDw5PjZTQjlKPjRJPjpCQDFAOjs9QDJANjUzPCk7PT8+PTJEPD5EQjdDQj0/ +PTtHQzZNRUBMR0BJVktJb3JFdnpHdXxCdH1NeH1Ge4dMb4E8dXpKcndFd3lOeIM/a3NFaW03 +bmtQd3s+c3FKeodEdnlGcHRIaG47aGU/Vls/V0w+ZltMcGhpbleFeV+JeVmFeF2FeFmJelmB +h2Kml3O2oG++n3zJpnDIsoS+r3jLr4bIq3vKsoXXt4nUvpDcyJ7cv5noyJ3ozqfl0p3l2p7q +2qnt2afx2Kny3Kfw2KXy3aP43q3026Ly0qTz0pfw0Zvy1Z7p05nwzZ3qx5Tr0Zjnzpzmypbq +yZbpyJPlxZfbw4jguIfKt3zFpnyck3FzhHNSdm1PbmtCdGtPb29GdnJJdnVKeXROcG1Hb25H +cG9LfYBZhYdHd31Ld3hEc3lIcHRDc3hIcntFc3hEcHlDcXxDbnZBcHZEa3hAbXFCanQ9cXJB +anNDcHNBcXhAcHZHb3dBbHJBbnE/aXNHbndKcHZGdHdMbnpAWHdFS1lDPkU+QDhAPj46QzdC +QDs7PzpCPDs2PjM9PD05QDdDQDc1PDhCQTgxQTc9Pzo7PDU+OTpBPDc/QDk2Pjg+PDg7PDU2 +PDQ3OjY0PTdEPzxLPzdJQThJQUBBPDVDPzo8PjVEQj4+RjdEP0A4RDdCQEI6PzhFPj89QjlK +QD5HS0BYTEJqhkv//97///7////////9//n7/u39//f///////3///n////6//n6/+n0/u30 +/+7z/+v6//P4/+33/PP2/O75//zx/OLw/u/m+t/a7tDk79/p/OLg6tnz//fx/+/x//D6//b6 +/+v6//b7//f///79//Hz/e/t/Oj9/vn///L5/fL2//H8//ft/+r4//L3//L7//f9//f9//f1 ++ezx/On38uvp4NpTSU86PztSRTlwRz1pSzlbRjo+QjVJOjxDQTJQRD5bQzpqRENgRDFPQz4/ +QTM6PD5KRzdgSDluSzx4Uj1zTD9jSDtMOzo8Pzo1OzY6PTo8PDZCPTg2OjM9PTYtOTY4ODcq +OzM1OjQyOjA9OTYqOjM0PzEtPDA4OjEwOTUtPTE2OjUzOTA2OzYuPzE0OTM0PDQ3OzUzOjY4 +OTY7PTg8PDQ6PzUzPDQwODUwOTA0OzsqNjM1ODcwNi0vPDY0NDA0PTw1OTE9PzVIQDhRQjtc +SDdUQDZCQDs3PDZHRjxbTDplSkBVRzlFNzg/PDM6OzE4PjU5OjQ4PjM4ODI8PjxBOzVHPDk6 +OzQ5PDY0OTg5PTg1PDg1PTU1PDgyPDQ4PzkwQzcyPjoyPC47PzoxNzU2PDMvPjM8PjUuNjcz +ODIpPS8zPDIzOTk0PjcuPzguNzMwPToyOi0uNzQ1PDQuOTM0OzM1ODQ2OjguODI1OTk1OzE0 +NjosPjA3PjgoNzIzOTUuPDU1PTkyPDU4QD4zPTk5PTkvPDY6Pzw8Pzw1PTs3PTg5Pzo3QDU4 +Oz45PTdLRD9RTEBmYEiCb1OhjGm4oX7Hp4HYz5zjz6/k0Kzp17Xr2KTqzqXly5voy6bozp3k +yJzhyJLkzY3Wt43Psn/FnHisg2igd1uQZ1J/WkZYRD9BPjxDQj0wPTk6QzsxPDEzOz0sPzY7 +OzUsPTc6QTozRDVJSDhFQkRIRUA+QTg4Pzc7QDw6PjY2PDstQjQ/QzpFQTlBPTlBQjxBPzhB +RD1FVVdFb3BFdXZDc4BCcnRJb39EcHhGc4JAen5IfoVMeoFFdYZDb3lEeHdJdYNAanRBZ21B +cHRJeIFPenhJc3w/b2hDbG5BZ2U8YGg/SE4+XllNdG5UeGeDfmOCfVyNgFuLfWaMfVqOg2CX +kGuqnHGypXTEpnjErHvKsH3FsYDKroO/rX3LuYXNuIXVwYbZuI/ixJzo0Z3p16bpxJPpz57n +0p/s3J/t2Zvx2q/x2qTu06Pw0KTqzKLq0Jnszprr0Zzrzprm1pzryZXjyZPnz5fcz5rhx5na +ypLgwJLOvICzpn6JlXFrfmtReW1MdG9CbGZIa2dFbm1Ed3JPdHNCeXBJdXBHd21KdHdPhYhP +gIJLdH5Fe3pMd3xDd4FMdH5CdnpNcXo+cnZHcn4+cnZEcnpBcG9Db3dAanE8bXZDb3hEcnxI +b3lDbHhBbHg8b3ZCaHE/bnNCbXVBa3M8aW5EanE9bXBIb21Gc3JKc3o9ZHBGS184QT5APj08 +QDxAPj4xPzY/Pz07Pjk6Pzc4OTg3OTc5PTc2QTU8Pzk6PThCPjw+Ozg7PTU5RDw8Pzg+QDk2 +PDU3Qjw+QDRGQTtDPzdBP0A/QTU+Pzs+PTNHTEQ9PzM2Pzo+QDU8RTlEPzo7QzxFQT9APzlK +SEJUTUBzgEz4/9L+///7//n///////////3////////3//f6/+/+//z5//T7/+3///////z7 +//r8//ry/fD2/+r5/fvq/uX1++zt7eve69za98/h79nd7trj8tnv/+jw9+vw/evy++/r8eP5 ++O/w//Lw8d7m++ry+urw+ebt9+f1/vP+//j///7x/er1+ez18+Xv8ezz/uf+//n+//f7//P9 +//r+//z19+VZSU47Qz1XRDtoSz9tSD1eRz1RQj1EOz1FPT5HRzhsRT9oQjxpPzlPPDpHOzo3 +QDlQQzpeSTpqTjxzTz11TjxqRD1GQTU/OzgxOjQ0NDgzOS86NzQ0OjM/Nzk6OTc0NzM2NjY0 +NzQ5NjUuOzA5PDM0PDc0Ojg2OTE1ODc4PDIzNzY3ODMxOzU7NjksNzM4OTczOjE6NzI2OTU/ +NTo3OzM7OzM3PjUyNzEsOzEzNzY1ODE3Nzc4OjEyOzU0ODQ3ODY4OjQ1ODk/OTc8ODZBPTJH +PjdAOjI5OTZFPzZdRj1gRztdRDxJOjFENzU4OTE/OjY1OTA+ODY3OzM+PDRHQDZDNjk8OzU1 +OjYwNzM4OTQ3NzQ3OjIzPDY1Ozo0OTM1PDk4PjY3Nzc4OTM6OTcwOC81Ojg0OjY5NjksOzA5 +NDYyOjM8OzssPDU9OzsyOTQ4PDU4NjIuMzgyOTUyMjE2ODcyOjE1NzYyPDkzOTEyNjc1OzU2 +NzgwNTY2OTMvPjQ5OTk2ODE8Ojs3OTI8N0A1OjU3PT05QTU6PEA+Ojk4OzM6Oj02PTZAQTtN +ST5aTUhjVUVyYk6NelWxpXjKu5DZzJ7l1K/l26ft2K7s2rLy26/n16js2Kno1qTuzqLnzZ3q +zJfiyZrfv4zWs3/QpX7BmHfDnm+7knGphmWSZ1ZaRThEQDo0PTk4Pjo0ODg2PTM5OTk1OjM5 +OTs5OjI7PThBQzZEQj5EPTlAPztAPTU8PDlBPjs3ODc7Ojw9QjhEPzxBSD9GW1g/ZGFGanVF +bntIcnxIc3lIcX9IcHZFbIBEbG4+b3lIb3pIdoBSeH1KdohMcHg+ZGpEdHtJbn0/Zm5CaWw8 +b3NMcXlLenxMaXk4bWVHZ28/ZWNDTl09WUlIYF5GeW1rfmmHjmGSf3CXhGSPhGWShWWVjGij +kW+7qnLIr4fOsYfPq37NsYfJsYjNsIPKt4XTsIfVuYfdtovZypXqx5bi0p3qzKLk0pnq1Jzr +1qX32ajt2KLw0Kbv2KH11p7r1aPoz57jz5XnzZnjypTqzZbmzZnq057hzZnez53ZxprGuo6k +o3x6hXFbeW1SenZJcW5OaGpDZl9FaWlEb2lJeHdNeXZIdHZKeHNIe3VNe31RgohTfX1NdntK +cX9Kd4FMdXlFcXpId31GcntMcnlGcXo9dHpKb3lDcnRIcn1BcXZKcng7bXhJb3RCbXlDbXlH +bnpDbntEb3xFanhHbXY/a3NLbXM+bHFCb3Q9aXM/bXJFbHRFam1IZ3BDbHVHa3M9WFVGSVQ+ +QDo4Oz45QjY8Pz08OzM5PTk7PjU1PzY6PDY1PjQ8QTg4QjRBPDk3PzY8PTs3OTI8PTo9PTs4 +Ozg/PDhHPzVGPTpFPTw+Nzs/OThAQDs9OzY/PTg8PjhAPjk9Pz1AQzlERD9FRD1HQT5LQjxZ +SUhrfEf3/8z8//j9//n///f///r+//3+//z///3///7////+//32/+/7/u/8//X9//T////9 +///9//T3//X5//D2/PDs+ubr+uTr9efn9dj19PTd6NrX5NX7//L9//77+e38/vz9+/Pn8eLi ++OT4/vP///3///////v1+ej7//r3/+3z/fv////7//T9//f///z7++3y/ez5//P1+/H6//Ls +9enr5thRQ1U9RTpYRjxpSjt0TTteSjZPOzxHQTlFOz5MQjNkQzxiRDVmQjpOQTVEPjY4PzRL +QjheSjpnSj91UD91TTxlRz5QPTk1PTs+Ny8yNzYxNzU1OTI7ODo3PTI1NTUsODM0Pjo1PDE6 +OTQ0PDI2OzkwPTI3ODY1NjczPTYxOTI8ODYzOTU3PDkxPDMyOjU3OzEvOjM4PDE4PTo8OjY9 +PDU7PzZBOzg5NzE2ODUyOS81ODUwNy48PTctODY7OTcvNzI2NjYvOjE5Njg3Oi83PDQ4ODE/ +Pjc6PTc/QjFWRTlbQThaPjlIPjZAOzY6PDQ/OzI/PDo5OzNAPjc+PzNHPzo+OzRBOTg1PTFA +OzUxOzRBPzoyOzc6PDM0OzY3PzU6Ojc0PTc7ODg0PDQ1NzM0PDQ3PzIxOzUxODc1OjYyODI4 +Ojs2PTY/Qjg3NzM5OkAyNS87OjozOC07OD8zPTA3PTk0OzA4Oj02Njc4ODM4PDMzNzQ3PTUy +OzY7ODQzODM3OzUzODUzOzI4PTY7Ozo7PTgzOjJAPD44PDU3Oz04OjY/PT09RDhdUUdjV0tx +WUlrXFCHeFaskG3Dq4nawJ7m1q3w4Lbx4bT13rfx463w2bPo2anp0qHlzpfpyZDqyp3pz5Tp +yJnctYHcuYvWs3/TrYbSpXzFmnO7jGqleGGGXUxKQjY/Pjs3PjU6PzgzOTE3Pjo2PzE4OTk5 +OTA5PDs/QjZBQjtAPjc9QTxCQjtCRz89Ozg2PjU8TUJHZmNOcG5Fa3BCbWZJcHlFam5JbnhD +b3NCbHhJc3JJb3lGcHlHcHtAb21GbXg/bXBJdoBGdH9KeoZEc28/bHNFe3RKdIVDZ3FIaXVB +bnJHbnZFcHc8Y2A/bGpHZ21BY2ZDWWI2XFVHbGJJc3NrjHGOimaekW2ciWyeimaPimOjm3Kt +pG7AqXvEtIfSu5LRrojSsoPKr4HLtYDUuIXUv5LcuZfjxJjnyqLky5flz57t2qTr2Kvr1aXs +1KDqz6Hm2KHx26jk0pbqzZPo1Jjs0prl0pTp1qPnz5nZypTPv461womHoXlihmxZem5TeGtP +b2pObGFFaWNHa2VCc2tIdG5Fdm1QeHhEcmtMdW9AdXNPe3xJgH9XhIVKfIZYfIVHdn1Jdn5G +dntJdntGdIFEdn1KdntKb3tIc3lDd3tKdXtAb3hMcXhEbXlGb3VDb3dEcHVIcnpDcHhFbnlH +cXdHbnlBcXRDbX5EcXxBbX1NbIBBaHhIbn5CaXpHcHo8bHlIcXlAbG9NZnRAbWJFa3RGaXNC +bHY9Xm9DSlY9Pzo9QDc4Qjo7PDk+Ozc+PDlBPTdBPjhFQT07Ozw3Pjk/PTk1Pjg5PTo6ODZH +PT1JQT1MPz1CPTtGQD1BQTxGQTpEQjhHQD49PT5CPzo/PztBPz9DQT1JQTxGQkFMRDpYR0Fz +jUzv99T+//H///////////////////3///n+//36/vD6//L///////7///v////////z//P9 +//ft++vz/+j6/+z6//rp8+fg8dzd9dHq9+Px++bq+O32//Ps8+/2/O7s/+30+er0/v3///n4 +/+36/+/1//T3/uv2/fH3/+3+//r//+39//f///v+//P2//T8//j1//P++/Lu7un6/fDu9N7e +49dLRkc6PTpRRDdoST9tP0BdQDtLPDhEPjg/Pj1OQTphSzpqQTthQTlNPjpEPjg7PDpJQjdi +ST1oSDlyUkBuTjxkQzpEQTM2NzcwOjA3NTkxOjM5OjcvOjA4OjcyPDQ5PDgvOjQzODcuODQw +PC40NDQ0NjE2OjY2OTQ0OjQ1OTc0PjM4ODUuOTA5NzYzPjM7OjkzOjE7QDU3OzE5PDY2OzNB +PTo7OjI4PTY3Ny80NjIzNzc0OjMxNy83NTgzNzI3OTAzOC82OTM0NjM0ODQxMzI2ODUwOzE+ +ODY3PzBYQDhWQDhcPjpCOTBDOjU1ODA9OjM1NzI/OjY2OTE6OTxAOTg7NjU3NjA3PjM1PDAx +NjIyNjM7Nz04QDM1Nzo1Oy83QTo6OzQ3PjkzOzI7Pj8xNzE2Ojk1OTI1Ojk0NTQ2ODc2PjE3 +PzYzOzUxNzQyODU0OjI2NTYtPDA2NzEyODIyNjc2ODQ0NzY2ODQyOjA1OzUvOjMyOjIxOjMy +NjU0OTU6OTQyODY2ODY5PTk3Njc7Ozo2PDc5PDcwOjM4Pzk0QDNLQjtiUUOBZVaKcVuKa12N +dlW+qoLHt4nZv5TgzaPt4LXy3bfz3LLy4Lvr2avt1qPsyp7qzZrv1qfu16HqzaPiwIfhvIjZ +tHvduYfYvIDbtoPOrnjGnXG5jGi5i2ige1ldP0BFPjk6QDg0OjY0Ojk7PDcxODc3OzU3Ozg4 +PDNANjc7QjZDQDk8QjdAQTxBTD9IV1ZFWFBGXVxGaGdGaGtAamNEanFCbWxHZnk8aWpDcnpE +bHdGbnNFb3RGb3hDcHlDbnVBaXBBaXM9cnxHb3hFfH1OeYlBa3hDX2lAeHBUeYQ+Z3JCaG84 +bGxIbXU8Y2ZHbmJCa2lEaF48amZDZ11DV1Q/blxNdW9klm2Sk3GhjHCcjGubimqck2qtnmut +onLOs4LNt4jVvozQuoPVvZHUvYjVuY3PuYXVvY/gxZLkyp/iy5rk1Jrizpzkz5zn1aLk2Jzp +zZ/izp/l0qXm0Jfkz57izZTay53Wy5m+xJamsoBwlHRfhXBQe29Tc2pEb2dScmdEaGBKZVs/ +Z2REbmlFd3BGe3VLdnNDc2xIc29Ec3NQdXhJgn1UfoVHf4BNfIVLdX1NeHxEc3pJcX1LdX5L +dYBNdYNKcnxIdXxEcnlBdXxIdXpKdX1Kc3pAc3xCbnZBcnpHbXtAbnpKbnpAc3lHbntAcXpH +cH1Dcn5NeoNHc4JEc4hGdYNGb35FdHxIcn9FcHxEb31DbnNCb3NGbns9Y2dDaHpDbHdDbnhC +Z3NBbnFJbHtEYGtGRlcyPTc6Ozs2QzY/PDg9PTRCOzoyPTc6Pjk9PzY6Pjg3PTQ6PjVIQjtG +PzpEP0FFPjtDRDtDPzw8PzpGPzw8QDk9Pjo6QTpEP0M7PDhFQEU/QTxGP0BJSDlWTENqkkb/ +/+v///////////////r///r///v///n///j////////2/fj0++b+//jz//Xu8uH+//r9//vz +/uvz++r8//b1/+3z/e3j++LW7NHe8dPd7dfU4M36//H+//7z/ePq8ub6/fL4/+7u9efx++n1 +/vL5/fD0/+/+//v///P///z7//L5/fHx/uj6++/7/vP6//Pr/ePt/vDx8uLx9uX0/ej+/vpV +TUo+QzhPRkNoSzpySzpfQzlKPzlHRzo4QTdLPjhfQjBnRjhcRjlSPzo5QDU9QTxHRjRhST5o +TjpxUD5wTjllSDs8OzQ1PTQyPTA1Nzc0NjMzOTU8OTQ2PTczODIxPDQwQDQ2NzUwOzQ2Oysz +OS45OjY2OzI4ODYwPTE9ODg3PTI9OzY1Oy87Ozc1PzE6PjU0OTM3Pjg2PzQ3QTc8PDY8Pzc2 +PTIxPzQ2PDQ2PDI0PTM1OjI4PDM7ODgzPjM2NzQsPDIzOjUuPDE5NDMyOTI7OjcsPDA8OjQ5 +PDJVQjZbRDpaRTdDPTpCPTc9OzY6PjI9OzM+PDM/PDU6PTk/PTg4PjY5PDE3PDUzPC0zQDU1 +Oy05QTYyPS0yPjU2PDE9RT42OzA2OjU2PDQ2OTk1PDQ2Pjg3PDcrOjA1PjU1QC42OjQ4QjUz +OzUwNzE1Oy8zPDcwOjQyOTEyOzU0PjYxPC45PTc0QTI1PTYxNzc1PDM0ODU3OzIwPjUwPzE0 +PTY3OjI6PTU2OzU6PDo2Pjg2Ojg2PTU6PTQ6Pzc/QTRZTjuBbU6NdVebgmONb1ebe1mvmXTU +uZXgyafn0KXv3Lb167/w5MH05rbx4bTs1qjp2qTu0aPqzZrq2KPn0JrlypzkxJHjvo/YsX/a +vInatYPUroTNqXTIoHa9l2m3kW2id11jTT9EQj84QDo1PTQ2PDg2PzQ5QDkwPyw5PjcyQzNF +RDtARDU/Qzs3STVCUU89S0JEUVFCWFVBXFtGY1NIZWhCcGNHb3pFbXJFcG1Dcn1GdH1DdHtH +dnlAeHVIdnlFdn5HeH1GeX1Ebno8cXVEc3U/cW1KeX1FgX1PeYM3bWdHeXhGe4RGeINAb3hH +aXZAbXI6Y2FDbmREb2hIaWVDa2Y8ZmBCZF0/b2BPe2xihmuWkniXjW+djm2ZjmWrmW+sqHHG +r3/JtYbVtZDRv4XXw5HUwJHXu5PWwZHZvZLjyJPdypfiyZzcyp7dzZrj0Zji0qDq1Zjl0afi +xpvf1KHf1J7OxpfFvomQpn14k3RfgG1ZgmtMd21Rc25FcGVOcGVFbWZJa11IbGdEbmZJc3BF +c3JNeXdEc2pFcmxEc3JEeHtJgH9SgoZLiYtRgotSgIhMfX9IfIFKeYJOfINNeoVLgIRMdHtN +eYJMfYBFeHxIe35GeXpKc3xEe39Jc3tDdXZJdH1BcndKdXxAc3hFdn5DdX1IdYI/d31LdIFF +d3pIc4NId4JIdYVGeoJJdopNd4REfYZHcH5DbHtEcXtDdH5EcXZAaWtFdnhEbHtCb3tFb3k/ +bHFKcHZDbnhLcng9YWw/RE03Pz1FQzo8Qjc+Pjg0PzY9RDZARkk4PjE4QzY+QTZAQjhGRTZF +PzlDQz1AQThAQzo8PzNEPzg7RDNBQTw0PDdERT03QTZHPz09RzlNRT9IRjxZTkJzk074/9r/ +//31//H2/+n9//T///v///v///////////////3///r//vL9//b7//f///j////3//D2/+r/ +//v1//L0/+f2+vHn9OHt+uTk6eTa59He6tj1/fL6+vPy/vL4//T2//T3/+n4//Dz//b5/+37 +//v////1+enx/ury/+n3/ej8/v3////7//X0+fT6/P3//////fv19/z///7///vx6d1TSFE7 +RDpUQz1jSD1nSz5cRT5KQzhEQEBEQT1JQUBjRDtgQztlQzpKRDlEOjk1PjdJRjpaSTtpST9r +Tzp1TkJXQTc9ODgrPzM6ODcwOzYyPTgsNDQ2Ozs+OzczOTU1OjYzPTg4Ozg5OTU2ODc2NTcw +OzQ1NzQwNTc7Nj03OjQ9OzczOjM9OTcxOzI5PTcyOjY/Nzw4ODg2Njo5NzU4OTg5ODY5OTQ1 +OTU1NzM5NTQ5NzQxOjc2OzYxOjU3OzozNzc1NzcxNzY1NDgxPDA9NzkuOjc6Ojc0NjRDOjxM +QTxiSDxRPzxIOThAOzk2OTU/PTY4OzY0NjQ3Ojg6PDk0PjQ5OjozOjU3PDI4Ojc1OzQ4Ozk2 +PTY4OD00Oi88PkI7Pzg5Oj4yNTU3Nzw1PDE6QTo8NjwvPDg2NjcxPDQ7NTk2Ozg8OjotODQ1 +PTU2OjcwNjc3NTc0ODczNjowOjU2OjgxPTM6OTs2PTg0OTgsOzg3Pjs0OTc4OToxOjk0PTk1 +NTs0PTQ6OTw2Ozc6PEA1Ozg9PzpCQDldQ0J7WEmlhF2hg2OvjGqrhGi3lW/Oq4ncxZrj1bDp +2bLx37vz47vw4bjz3Lby37bw06jv2Knw2qnr0qPqzKHiy5Lmx5bny5flv5rgvYzeupDdvYrc +tYnWq3jSsYPOnHTFlnS7mWyhdGBkTUFFPz9CQzw0OTo1OjQ1OjgyOTc5Ozg4Ojc+Pjw/RD0/ +QEQ6Qzo7QkY2S0M9SEc8UUNCVlw7UVdHZWJFX1xHbWNHZmlJcHJFb3JKdXpNfItMd4JNfH9F +eYhLd4tNe4NKeoVUe4dEeH1Jbn1DcHpJcX1BbHtEcH5DdoBMeYg9a3ZJcHlJgoVVfpFJeIlR +doQ/cn1BZ2VEbWpDc3RBbnc/amdEYG08a1xEbW1FdGhVenJci2uBlG2ZlHObmWyrpHm6sX7I +s4XSvIfUw5LTvZLZxJrSxpDYzJTXuZPbypjdzJrdyZrbzajZzJnbzZ7Vx6HMxpq1x46UtoZ1 +oXFiiXJafWxPfXFVc21Gc29PcW1JcmlRb2o+bWVKamRDamlFbGQ+ZmpJcm1Cd3BJeXdFb2tG +d3RLcnBId3hUfYFOio9cjZNNiI9WiZFOioxOgYRLgINSgYhMfIRNeYNHdoNKeIVKe4VOeYJK +eYNLeoJMeotLeXtGeH1Jd39Ie35LeYNJdIFGc39Fdn1Kd4lDeYNRfIRGdn9MeoZAeX1IeYlH +eIlJeYtIfIVPfIpHeohKd4dGdYpCc4JId4VFdH1Gdn5HcIJAam9BcXtHdHxBbXxAb3pJcH9E +b3lFcHZDbndGanhDcXhQYXY/QUo7OkM2PTk+PT42PTdAPTs3PTg7QTs8PD1CQTpLRz9GQjxA +PjtDQUJCPz1IPkFBRj4+Pz84OzhAPTk9QDpKPz47RjpIQUE/RDxVSEFTSkJ8llP6/+P8//b/ +///////////7//f///////////b6//f9//r4//r6/+j////////6//jy+uj+///6//H8//b2 +++3r9enf89fn/Obe+9fe8t32/enm8uT///Hp/OXt/uvt++bw9ejx9e33+/Lp9N3p+u3y/ezr +/+3v+efs9Of08Oby/vT+//r8//D7//D5//D1/+n8//n9//b09/H0/+709O/f4tJWQU08QzdP +RzteRzxsQ0FXQTZOOjw/RDU7OjdERzZhQT1ZQzhYRDNHPjk8Qjc2OzZIPjdbSDxnRDJsT0By +SD1SQTY3NzQuNzIyODcoOTI2NzQuOjM2NzozOzU5OTsvOzI2NTgxNzIxOzgwPDI5NTAvMzI4 +PDUtNiwzOTQ6OjMtNzY1OzMwPDQ6OzM8Nzk0OTY7NzgwOzU0OzQyOzMvOTQvOC03ODYwOzQ5 +NTgvODU3OTYwPDA8ODcyOjE1OjgyMy40ODk0Ozg0NzY4ODk2NjQwODQwOS81NTQ6OjZHPzJZ +RDlQRDZHQDU5PDM8NzYrNzI3OzYsOzA6ODktOTA+OTQwOjQ7OjUuODU1NzYxNTUwODU6OjQu +ODY5Ojk2PDo1OjMvPDgwPTQwPzAvPDE4PTYyNTA1OjgsOi83PTgxPTI3PztHRzszPjouOzEy +PDYwNjIuODQvNzIyNTE0NzQxOjQ0OTQuODU1ODIyOTQyOzcvODUxPDYzPzQ1ODQ2PzU2OTM4 +PTYzOjQ+ODc4PjVCQzpRRzp2VEGQZ02ti16vi2a3jWy8jnfFl3rZv57ex5vp2Kzq37Hw37vx +6b7y5bzv5bz24b7w2bHt1Krs1azq1aTmz6PjyZHjwo/nzZPlyqDixpnivorcuIDYtYfYsoLP +sHvPqXXKpXLBn2+0j2WMalVjTEFCOzs0PDMzOTsyPDcwOzU0ODMyODg0PTM6QDo6RD06Q0U3 +RkQ3Rz87TEgzSE07RD03SEI4S0ZAUVY9UUhBUVI6ZlNEa2ZFcmtMZnFDeHpOeodKfohMeIpH +fYNQeopJfn1MgIpKe4FNd4JKdHhJdIY/cXw+cHA+d3xGeH5FeoBIdHdAdXROgotOfn5OgY5B +e4xHaYI0YmNGdnQ8cXJEaXA6cWZIXWM0YVtFZV5Db2xPd3VLfG9eimt6jm+NoXSmo322rYG8 +sYjHuonOuY7JuYTSwpbOxqDNu5vPxJq7x5G3wY+kvYqTqYB4onFtjnpZg2lVfXRHempVfHlJ +eWZJbmxFbmpEbmZEamJEaW1EaWU8ZWVCaGlBa2NJdW9Fdm1FcnREc3FCamtGcXE+c25PdnRC +fH5Pho1SjpFYiY5Nh5Bbio5PhotRgIhLgIVNh4dKeoNKf4JMfoRCeYJIeIZHd4FdfINHeoJJ +eYVFeH9Jd4JKdHtId4JKeoRLen5BeIRLd4BLd35Dc34+coVQeYRJd4RKe4JDfIhPeIRCeYZK +eoRHf4dKeolJfYlMfItDe4RKdodFdIJFeIBCdH1Gc4JEbnBGcYZDc31HdH5BdH5Hc39Bb3tF +b4xHa3U6b3dEcW8/bnhAX240QEo4QDY4Ojo1PDY5QD4wPTo+Ojk1PzdGQjlCQjlGQDg/Qj4+ +PTg5QDs+PDg4Pzk7Qjk8PTo7Pjc3QTw5PDQ+Qzw+RT5HQz1ORz1UR0Fyk1Dy/9n///z///// +//v////9//z8//L+//r////////////+///+//f///v9//z9//b8/PX1/+/5//H1++72//Dt ++Ojq9eHq8+zg7dbt+ufh9dzT4dPy8Obx+PD+//z+//z///3///z5//j///7///37++v4+/T+ +//v///3////////t9+Pp9e/4/vH7//v9+fLx+O35//Lu9er7+/Dz+u727e1TSUc/Pj9RQD5j +ST5xSD1iQ0FKQzZFQjZIQjxEQTlkQUBiQTpiPjdGQDlKOjYyPDVKPThXRzZnRTtqSz5tSjZI +OzU3PDQ5NzgxPTY3ODYvOSwxPDYuNzE8ODU3OjU1ODQtOTU1ODQzOjA0OTA3NjIyNzQ2OjU2 +ODM0Ojw3OC82OjI2ODU1Pzc8OTg0OjI8OTwvODA7NjYzOjU7NzUtOS03OjgyNTI6OTU0NjI0 +PDUwODM3ODU3PzQxOjQzODU2NTU4NjEsOzU1NDM1ODkvNjY4MzYwOzc4OzY4OzFKQjpYQjdT +PztEPTk/OzczOzY3OjIyPDM6Oy8xOTE4OzUxNzM4Pzc4OTI4NzU3OjY3ODA3Ojo2NDU4PjM6 +OjpCQTo4OjsyNzI4NzU0OjUzNTEzPzQ5ODg3PzU1ODUwPDE6ODwyPTRdT0BPSj87NzgzNjU3 +PTQ4OjY5OzY1PDsvNzcvOTcxOzY1OTUyODQ1OC82OTc2PzU4PDg2OzQ8Nzw0PTM9Pj08PjNE +OzxEPDZxT0+UZlCsgGa8kWvJoIHEm3i+pXPProfXuYrdv5PjzqTpzqnq1aTp2anl1a3r2qzw +3a/w4qz24rzw2a7x3K3r16Hw0qbq0qHsyaTqxZjtxZnlyJHlxpXev5TgvoPguobbt3/WroHK +pHXKonq/m22rg2J+YE1nS0FCPzw8QDg2PDo6PDo4Nzg3OzIyOzk0PzM7Q0U6Rz8+REM6UUQ9 +TFk9T1U9T1Q8UFQ6UVQ8SE03ST8/TUo+Vk1AVVQ/X1ZGZ2pBbGZIdn9LfXxKfo5RgIRPgI5N +f39Mf4RRfIhKf5BOhIpPfotPdn9Le4pNdIhIdoFGdHpNe31NgIFRe4dBeHdKeYRLhIJTiJZL +hY1NdYs7amdEc3NDcW1FcW1EdWpHZXBBYFhFbWQ7b2dFdWtJcG5NdW5Qd29WgWldh2tkmXJq +oW9zlHFun3RvmXNdjW9lgnBTgG9UfXVLfXBNdXNJempUdXFGbmdScXBJcWNQenJEbmlNZWZF +ZmVBa2JJcGVDbWpKcWVJbWtFcXJGdHJEdWxJdXBHdnBLcG5GbnFGc3JDdHNVf4FTiopah5BQ +io9YhpFOh4VUhY5SgYtRg4xPfYRLfIJNgoRMfYNSgIRQf4NMf4dNfIFJd4RSgIRJfYdOeoZK +fIdLeIBKdX9OeoVCfoJQe4dKfYJTeolAd4NSeYdHeIhRgIhIfIZMeYJGd4VIeoRIe4pJeohL +eYZGe4lRfIZEeoRKfIJFdoJNdoVLd4JJd4JIcoVFbXBHc4BJdYBMdolBc31HcoRFdHtIb4FD +cnw+aXlGbntGandHaHtFaHhBRWM2PDc1PDo4Pzg9PT45QTtFQD9CPDtLQTtHOzlCPzlAPztC +PztDPDxAPTxEPzlBPjhHQzw/PztFQT49REBAQTxIREFUSUJWSUBzmE74/uX///r///v///f/ +//////////r///3///z9//b9//X///n///f+//j6//ny//P+//b///z///j6+vnu9+f2//Hu +/PTk/OLr/93o+OPi6Nv38+n3+ejv/urz/+/x/O7y9OLl7eDv+Orr7tjx/ff///7///v7//b6 +//H0//T6//r///j7//f4//L1//H///31++/t7en6/vP+//Lq9uTl5tNPSUdAQUFURzlkSDxq +Rj5XRTVOOzxEOjc7PTZLQjdfQjpmRjpZQzZNPjk+Pjc8OTw5PTRcRD1fSjdvSEJhRTVKOTs2 +OzA4OjgvPDQ4Njk3NzM1NTc3OTg0OzY2PjYvPDQ4Ozc2OjQzNzg7ODMvNzUzOTI0OTk+OTgs +NTM4OTksOTZAOjUxOzRAODctOTM8ODUsODQ8PDQ0ODY1OzY1NTo2OjIzOjYuOzA3OTYvODU4 +Nzo0PDYyOTIxOjQ5NTgzNjU3OTM2OzY0OTU0NzYxOzMxOjY0ODE3PT09OzJGQT9SQzlMQDpE +PjU7OzY8OzMwODE3OTI1ODQ4NzY4Pzk6PTU3NjY7OjYzODM1NzYzOjg1NzM1OTQ2OTI5RDg8 +PzcwOzY7OzozNz0yNzc4NjQ3PDkvOTIyOzEwPDEzPDc5Pzc5PDM/QjZTSUMzODA5ODc1Ozg7 +OTUvOTQ6OTIxOjE1PDIxODo0Ozc2PTo5ODM8ODg6OTk4PzY6OTg7PTZHQjxURDx1WEmTclak +e2K0lnDCoHq+p3HJqHe+om/Lp3zWu4vgwZnbwZLnyaPq07Dq2q7q2a7r1a3q1Z/n16nt3afr +3Krq1ajs0Jzqy5rszqDq0p7w2aTq0qPt0KDszJ/pxZnau5DatonZtHzbs3vRt3bNqILGqHDH +o3K6jWaVcFWAYkhiTEZAPTs4Pzk2OzU0Pjg0PDc2NzMvPjU6Pjo1Qzg8SEY9Tk47S1AwS1E+ +Tk86UFNCUk8zUlE8TlE4TEM9SU41TEZDS0I/UlBBZmBEYWY+aWFHen5OeX1ThI1Rg4lOfohQ +g4tOhI9Rh5BVgodRh49LfohSgpJMfohNhYlHeYBIdoRBeH1IeoU/fYRPfohFfIlJfYJVi41Q +h5FRiY1HcnJEbGxDcm9BcGpDaWtBbGpCamQ6ZltAaWNDbGlHbGRBcmdFbmQ+cGZEdm1CbmlR +eWxIc2tMcGVKa25PdWtIbnBJc2dJcGw/bmlKb2tEbmZJbWpJdmhKaWc+amhBZWFCZ2FIbGtB +cm1EZ2tFcm9LcXZFdWxHbnJFb2xMbmxBbW5Jdm5CeHlLen5WiI1bk5VZjpFci45VkJFbiJRW +iYlRhpFNhpFLgJFKfYhQfYhKe4VNeYhDfX5QfolHfoRUgYtMgIZPgIlNhohKgYpQfIRMe4JM +gIVMfYhLfINJgIhKfIVQd4JBfIFFeIRDfIRLeIVFe4ZJeIpGfYtMeo1HeIlKeItEeIJLe4pF +eYdIf45EdoNFcH9NeYNDdH9HdHtFdoJFdoJJcG5HdoVMd4pHdoFKcoFBdoFIbn0+cXhIcH9D +cHpKbn8/aXFEa3k/bHRSdH02QFw9PDwyOjY3QDc3OTc8Pjk+PDxDRTxEPTo8OTpCQzhBQj9E +PjhAPTs7Ojc8PD4/PDpBQD0+OzdAQUM+PDdCQUVMRzpVUUp4oU////L8//36//T////9//z9 +//f///////3////////6//b3/e/x/eT+//b///z////8/Pzv+ez3//Lx/e/1/+zz+PDn6tzl +9N3X89DZ5dTl9Nvi7uD5//Ly+ezz/+/8//z4//X9/vX///7///f1/u/6/u/z/+78//T+//X2 +++nr+u3z/e79//36//T7//b7//D///n///759fT7/fD8/fv16eVaSVA+QTZPRT1eTDdpRT5f +RT1NRDxIRThCPTRCQzlfRzpjRDxZRDpKQDk+Qz4zQzJDQTtUQzRfSjllTDdbSDw5Qjg+Ojkz +OTE7NzgvOy84OjQvPTE6NzkxOTQ0OjYuNTU3OzI6OzEqODIvODAzOzAyPDM1OzMtOS4tOTMt +OjQ2ODQnPTI5PDcyQTE2PDMqOjE1NzgxOjA2OjcvPDE2OTcsOzQ1NzYwPTA0Nzc0NzY1OzQ3 +OjU1NzAxPTItODcuOTI1ODE5OzE1OTgtOS82NzMxOjQvNzUyODE9OjU9QjBRQzlHQDhDOjky +OjI9NzczNTU8PTc1PDM2OTE6OzczPzY2ODc1OjU8PjQyOzQ4OzMxPTM4OjQ2Pjg7QjM1Ojg1 +PTM0NzkyOTA3Ozo6OzM2OTo1PTQ3OjkyPDQ0OzY5PzlESjlRSTxDRTw8PDUzOjQ2NzgwQDU4 +PDYyOzIyPDU2PjQ2ODg3PDo3OzU6QjgzPTVCQz5XSTt9W0yNblWecWSrfW67k3a+mnvCoHPF +sH3Ksn/Or4PJsHrRp33YvJLdwJPayYzlzZjm1p7n1qDk16js2azu2qzq2KPo2a3q1afv16fu +1p/vy6Ltz5noxpXp1ZLr15rs1Zrt06HtyZ3lyJLkv5nfwYHht4rauIPbt4DRpXjFo3HEoG62 +kWKbcVR5XkhfSkFAPTs4RjU2PzY2Ojc1Ojg6PS8xPTcyRTc7Rz82Sj47Wl1AW1k9WFY6XFk/ +UlU6T1I9UlE6UVE9UVYyUUs9TVM3U0Y+Tk08VVpCXFk/YldEcWxJd3lOeoFMfIFShIpNgopO +go5UiJFRgoxMhIZThpFOh45Qg45LiZFRgIpKfoVLfYhDiIVQgY9EfIVShpVKeodRfolKh49Y +ipBKfYhMcH1Fd3c/dm9EbWxIdm9CbntBcmw/bmxEZGM8aWVEaFtDZFpDbWFCcWNIb2ZCb2NK +aGNEaWFNZmI/b15KdGxEaGJEbmhKamU+aWhDbGpGcWpHbXFEbGlJamxFb2pIc3BDdXBDdHFD +bmxGcm9JdnJJb3BIdGs/c29OeHZCe3ZVg4dRio1kj5lVlpdjlpdSlpddj5Zai5NUipBSjJVQ +iY9QhIxKiItRgIxNhIVSgYlLfIJPgIdRhIlNgolLg4hQhYlRho1QgY1MiY5RhY5MhIxTg4pM +f4xMgYxJfYlLfX9GfoNDfINKfoRMe4hFeoJKfYdOhIVRfYlFfIBLfYhEeoRMfYlHf4RQfYVE +d4RKeoRIfYpKeY5FeoJKdX9GeIdIfIJHc3ZFe4lLd4VIdodCcINEeYRDc4JDc35FcntGb4A+ +cHtGa38/bnFBanlBb29McXozSWI8PDsyPjhBPz41RDk9PDo5QDtCQ0E9Pj07PDJBQDxAQDw+ +Qj49PTs8Qzk/Pjw+QDlDQzxBRjtIQ0BCQjhTR0BOTjx3mFP0/9z9//f///v///////3///z9 +//L9//P///////n///r///////////z8//f5/+/6//L8///w++zv9+P7//X0/+3v/+no/+jg +89fl6eDj6dfZ49b5/vnv+e3y+/T5/vf6//P8//T8//D1//T///r5//j5/+zu/+rr9uvw8ej4 +9u/v3uXs5+j3/vP59+3m9+H4/vD7//T5+fT5//X6//Ht8NxTQ0s7RztSRUJfRjdqRT1ePDhE +RThEQTpEQTlHQTpYRTlkPz5bRjlMPzc9PDM7PDlBQDpQPjliSjxWSzhNPDssNzVCNDYyODQ7 +NzI0OTY8NjUzPjo7NzQ8PDs1OzYuNzUxPDE3OjczOTA4OTYvODU4OjM6OS4zNzQyOjIzNjMy +OTYwODI8PjUxPTM0Ojc0OTE4ODY3OjEwNjUyNzM1PDk2NzMsNDU4NTcwNzQ1ODcmOjMxNzYz +OTU4NzUxOTM1ODQvNjM1ODkzNzI3ODMwOjM2NzY0ODM3Ojc0QDNFPDhUPzhOPTxAOjc3OzU3 +NzM4PDYzOTE8ODkxOjA4PTYyQDc8NTkzOjI4OjcvNjY3OzUyOTc5OTY1QjVBPEE3PDg2PjY3 +Pjc3PTY3PTc8PTo2OTg6OTYxPDYxNzM2OzU6QTlGRjdJREI9PDY5OTo2OTM5OzwuODM1ODss +NjI4NDkwNjQ5NzYvOzQ8Nzg9QDhoSkSMdVikf2mxjW21k3C3lG7Dm3PDnXXIoXrFpYDKqXjJ +rH3GpHbIqXrTtozdypHgxJbfv4rlzZzlyZrpxqTnyqLoz6fozpTtzqjq1Knt0aXs0aTp1aLu +zaHsyp7pyJroxpjrypPoxovq0ZjryZjqx5flwYfkv4zjtYnbu43ZtIfRqnvJnHPBmGvAh22U +dll1W0dbRkY+PTY5PjsxPTY1PTc6PDQ3PDoyPTc7Q0Q2REI6Rz49VUw9Wl08W11BY2s/WmBA +V2c8UVY6WVc6UmA7Uk88UU04TlE6S0k7T0ZBWlxAWlg9X1JKcmxIcHZFd35MhoVRf4tOgYNS +e4lKgIVSgZJQgIlMf49PhYlQg4xQgIVLh4lYg4pShZJThIpJgIZUf4xKfI5TfY1Jf4pPiJJZ +hpZNfINPdYdHe3dMd3pDcXBMa3dDbWpIb2pHbWlQZ3A9ZVlDZ2g+aF9KbGJFaGNEZmlDZ2dK +aW5CcmxMc2hFZ2lHcmdAbGVGc29Ecm5Kcm5AbXFAbmlCcG1HeHZAdHNMeXdBeHZJenFGcWdJ +anJDbmtJcHVEf3dSgIlKiIlaiItVjpJZkJVfkJBOkJNaiJNTipFRiI5ZiY9Uio1Xk5JRio1S +ho1RiJRUhJJSiY9Tg5NOioxXjZRQi5BTh5FNhYhVh5RPgodRiY1ThI5bh41Ph4tRgopWg4tQ +f4pLfopIeYZKe4hGe4hKfIpMfIdMfoZMeodIeoZMeoxDfYdQeolHeIZQe4REfIVVfYhGe4ZQ +fYtIf4pNfIhJd4JKeINHe4lEeYhKcntJfohNeoxLdYNLdoREdH9Gc4BEdoJIdoRHcYZFb35C +b39Ab3REbH1CanJCcHVKbnQ4SWw4Tko1Qz49Ozo4PzdBPjs8Pz5FQj0+PDlEOz0/RzlCQEA6 +Pjk+QUFAPzk9QDw/QjlHQj5ERT9CRDtNSEBQSkRpkVHy/Nn///3///////////////v///// +//////3///X////+//3+//f///z////9//v6//b+//T+//X////z+fTr8eTv8ePn/Ong+9Ln ++N76//Dp7OP///T49/X+/vv2/uz0/+/y+evq+ODk9Nvr9er2/+71/+v6/vj7//b5//L5//z/ +///////4//P3//X9/u/1/+3y+uTh7t/h8tns9ebk4dhUREg4QjlTRjlcSjlsSkFaSDpMRj49 +RzdEPz88QjFcQT5iRjxhQz5DQDhCPzc3PDc5QDdSRz1aRThURjpGPTU3PDcxOjUzOTY1Oywx +OjQ4OzYwPDM6PTUtQjQ5MjMtNzE8OjgvNzQ5ODgwOi07ODYvPDI3OzkwNzg4ODstOzM3PzQw +Ozc0OjQ1OjQ6NTY3OTIuOzIsOS41PDQwPDM0OzMsNjEyPTgvOjI4PjUyNzM4OzYzOjI3OzIv +Oi85NzQyOC45OjQvOjA4OjU0OzE1OTgvODM1OjY2Nzc1PjJCQTZNRDhJQTlAPTc5PzM3Pi82 +PDI2PTUzNzA6ODgvOTI3PjUwOjAzOTcyPDA3OzMwPC82OTQxQDM8QTgxPTU6OzM0PjA1PDMu +PDQ2Pzg+PDw1PTQsPTM2PTg2QTY3Pjg2PTNDQjk8PjlAPTkzPjM3QjgyOzE2Nj0vOC85Ozs1 +PDA2OTs2OjFCRUJSTz1wYkaah2WvlnC8nHHEpnzHpHrBoXPHoXLLqH/Jo37HpYDLqoDPr4PN +qn7OqYDUuYfbwI/cwZLev4LhyJfnx6foyJ/r0afl1q/o1aPlz67p2Kfp0qfw1Kfz063vz6Ht +0Z/sypnryJnoxJPqyY3myZjnw5bjx5Xjvo7fvIveu4jat5DYsYPOpnvJpnLFm3O9kWand193 +V0hZTz1APjw5Qjs4OjczPTE5Qjw2PjA5QDw6Rjw5SEI6SkM7UEo9WFI9X109Z2E/Y2ZEb2s9 +Z2o9Zlg8aGpDaG08UV89U048TlA4S0o6T0c6W1E9XlpDWldJdXA/dW5PfoJKgIZUgY5Je4RQ +gIxLfYpRf4lMeopQgY1Lh4ZMfYpQho1Pgo5Ri4tPhopSg41Qh49Mf4lPgY5KfYpXg4pKiI1U +h4dGgIRKgIVJgn1Ke3xCcXVMcHE+dW1KcHFDc2pHbWtAbGVEZ2VFcGJEb2tJaW1EcmxHb21I +dHFEb3BEdmdFbm9Jd3BLdHZJfHdCeHNIcnVBeXFOenhAeXNEbXI/cWRFbnNCd21GeXpJd3lQ +hZFWhYVRio5WkJVVj4xXipBVjJBajo9Uj5JWipBYholSiY5Sio9QiYpQhZFPi5JViY1TiZBY +ipJSh4hfj5FRi5RckJJOjJFajJFWjpBZjZFSiZVVhI1QgJFTiYlThI5QhIZVh41RgohQhY1M +goRPf4pKfodPf4dMe4RMfoVNgYhQgYRMf4tKe4dHfYtGfYBKfoZLe4hJgIpNfYRJf4xMf4hJ +fYtMe4tDgYVLfI1IfIlKfYZGfHxMfYZFeoVGfYxHgYhLd4VGeoRKeIVIeYBHdoBFdn9HbXhF +bns/anlFdXo+anFCcHBDbHJARlk8Pzo5QDo4PTkzOzU+QDs9PThARTw4QTZFQDk4PjhBQzw3 +Qjk9QDo+QT5DQTxBQj1DQjxDRj1PSDtPST5vmE32/N7///X///X///f///n////7//b+//b5 +//P////////////6//D9//r2//n4//L+///8//T1//Ly++r5//D///f////n9+3i+tXt/O7m +8+Le7dXs/Ons/uzx+e75+/j///b///7///////////fu++z9/fj4//H6+e39/vz///X9//bz +/e3x/+v9/fT+//z///fx+/L+/Pv////////38udZRUY2OT9QQTlhRj9kSTxhRDtMQjhHPjxA +OzhLOzZVRjVjRTlaRTZIPzU9Pzc7NzY+PTVSQTdcSTlMQDc6OTU0OzIyOjU1OzY0OTg6NzE0 +PTYyNzQ3Nzc5ODo2PjQ6NDg0OjU6ODkyOi82OjYsOzE0ODg1OzM0ODMzODI7Ojk2OTc8ODY0 +PTUzODc2NzI+Ozg2NjY3Pjc7PjY0Ozg1Njg1PDM0ODM1OTMyOTEyOzQzOC83PTUvOzA4OTMv +OC48OjYyNjA4OjUzOjJAOjY0OjM0OjUyOzM4OTg4ODg7PjVLRTpJPzlFQTk7ODc3NjQ7Nzk3 +OzMzODUwPDE5ODcxODA3OTY2OzM4ODgwOjA8OTguPDJCPzo0Pzk8OzcxPDQ7Ozc3Ojc4PTVB +RD46QDY3QTM3OzI+QjY9PUA8Qjk/OztRSDtMQj0/QTE5OzkzPzU8Ozw1PDA2PTs2Ozc1PTs1 +QSxJR0JkWE10a1qbhl62nXK8oHXJp3PRrIDJpXzDmmvJqX3Np4rHp3fHoXnJpnXNqH3Ep3rH +rH7StofOt4zYtYfTt4zgyJrfyKHdx5ravZbiwZ7fxaTlzafp0KTp1anq2qzr2Kvw1qfv1qnx +z6jpzKDrzp7oy5fqy5LlxpTiuIffv4njwJHlvpXiuoPct4vSr33Pp3nGnWO/k2qpg1yOaVVX +QDk6Pjc7RDgzPjM3PDo1PjU6PDs7RTg+RkM2QjU7SUNAUUQ/VFg9Y15DbHNFampCZWRGa3A9 +ZWpDam0/Z3FHdWxAWmZBV1g4UE49S0s7VEk8WVREWlk/Vk5GcnFEdXFTgYdNgoZOgIROhoRV +h5BKhIpVf4pHgolMhZNJg4tThZJShYpZh5NPiJFUiJJTjZlRi5BPhZJRgYpPiY9WjY9Vj5lV +ipFPiJJKdX5BeotVjYJNg4ZLeIBFd3hKdn5Db21Kc3NEcHJKbnFIdWtJcHBGam9Ke3FKdm5E +dnJJdnNHdHJJcXBGdHVFdXBPcmtNbXNJdXNCbnNFc3BJeXhOgoZLhotYh4ZJh4hZi5FZkIpm +l5taj45hkpldk5hUjZNcjpJVkZVUipNUjZJcipZTjpRWipFRi5BXi5RVj5FQjpVXj5BUjYxf +lZNSjo5bi5VQipFcjJZQjYtfi5NNiY9XiItNiZFXhpBLg4pRiY9VipBRiI5WhI5PhotUf4pJ +gYpPgotQg4lOf4hKgohQhIpPgIxMfo1JfItQgIVQgJBPf4VKgItMfYlOf49MhYtNgIxJfIhH +gI1RhIhKgYpMfZFKgI5KenlJgItQgZJOgIlMfIxGe4hOgZFOfYlNeYVJe4BJdX9DcX9Db3pI +cnhAcHpBbnRHbHVKbHNHYnhCQUo3Pzs2QTg4OTk1PzdDQD1AQDhCPD49QzdGPjs6QzQ9PDY4 +QzJBPzs8PTlDQjxAQjlIRzlKS0BSRj9ul079/+v///////r///39//H7//X///////////// +//z8//T2//D9++3z/+zz++n9///8//X7//v5/+/1/+3+/vzw+Ozw9+Xj8t7l+tvp8t/h9dnp +/uD1/uzw9+fu/er5//Hu/ert9uPi+ubv/O71/+z9/fb+//X9/fr9//z///////f+//3///f+ +//P6/fD5/+/z+vL///z5++vs9eHm+ujp8NhQS0pDQDpLQTpcQjxjSTllQTxEQzZJOTo9QDNH +OzhVQjdrRzxRQTNLOzc7OTM/PTo1OTZPQkFTRTZEOjctODU4ODY2PTQ1OzM0ODA6NjI1NTI6 +OTMwNzNDOjsvNy82ODI1PDY7OjYzOjE5NzUzPC06NjMuOzE+NjczOjI9NjcxOC44OzQvOC82 +NzM6NzQ3OjE1OTU0NTI1OjQuODI6OTA7OzMzOjM1OzI0NjQyNTQzODQ3OTQ0NS84OzcqOTJB +NTYvNjU9PDQyNzY4OjUvOTM5NzYzOTY3ODE3OjI5OzFDPTNGQjhDOTg1PDY0OzQzOzUyODIz +OzI2Ni8yOTc5ODI7PDkxOTA6OTgzOS84OTs2OjM8OT0yODE3Ozw3Oi8zOzw7PjU5QTZBPT05 +QjY5Pjc4RDZARDtCPz1CQT1CPDhLRzw8Pjs6ODQ0NTU2OjU5QDs1PDI4ODY1OTk6PDU5PTVG +Rz5hWkuBbFWnj2K4mmq9m2vGpnfPrX/Mpn/LonzKpXPIpnvIonnDpHa7lWm7kGuykWu0lWe5 +qnG4pXK3sHC4rnq4sne6qXa6qn3Gt4XJwpPTxI/ZxJrax5ffzaLk17Ho2rHt2Krr2qju0qXr +1J7t0aTqz6Hrx57qxJHkvI/du4PqwZPku43gt4Xbs33ZqILMpnTHn2+9jmCtf1+QZ1FeRjw7 +OzI9Qjw0ODM4ODkvPDM5PDs4QjdARD84Rzg9Q0AzQz1AUlY+W1ZHY2xFdHFObHVBa25FYGxF +cXdDaGdEZ2o/XFxBW19BY149V1o7T0c6U1BAVVY4VFdEalhBc2dIdnhGeoFPe4dJfolUf4dG +gX9Tho5OiZRVh45PhZBZhYxRhY9Wg5JTiY9UiIxPgpNUiJJSg4xQh49ViJFYjZRWi5VPiY5V +ipRPhZJMfIlGd3tEfHhVgYpRg4lWfYtJenZKdHVDc2ZMa29JZmpEbnVIantFdHVIdHBEcm9L +d25JcnJMcnpIfHpNeH9Lc3xVe5BSgIdUhIZRd39NfYlfh5FUiZZikZlSkpFakZdXkJNej49U +io9cjYpRi5FUhZJWk5Veio5fkJBWipBZjJNOj5Rfi5dSkJBdjZdTjJFZiZFZkZVfjZdVj5lY +i5NVi5ZXjpJYiptWkZZUjZRYgpVRiJFSiIhOi49RiZBRhYlQhIpNgIZQgIhQiotRgI9MgIhb +ho1LhIhPg4xLgohPgY1IgolRfYlLgYhNgopNhItQg5FOhYlQhJFTh5BLh5NThI9Sh49Tg5NX +h5FRhI5ShpVKh5FNg4ZMgpFNgIxIfolSfIlFgIRQg45If4lRfIpKeoRNd4NDdYFLdoRCc4JE +a31BZ3lDZ29Db3FCcXBBSmw6Pjw5QTk7PT02Qjs5PDk6PTZBQzo6OjhDPT02PzU+PDo4PTRB +PT06QThFRDo6RTRMRj1NSUFRTENwoEr8/+n///T//////////////////////f/2//L///v8 +//T8//T9//X///////////79///7/vH3/PT7/+/v/e3p/ePs++zl9+Pb89Xd69fh7t7d69v/ +//////Xy+/Lv+u7p/er8//37//f6/fH0++j8/vf5//P5/fPv/ur1//Lt9+jz/+/+//Lz/vD+ +//n9//b1++/5/err7OX7/fj7/fXp6NhYQk47QD1ERT1hSztkTD1kRDdGQj1JPjw1PjpDPzZP +RjhkSzpiQTxOQDo2Pjc2OTUvOzRCQjdLQjo8NjUyPDUzOjEzOjc0PTYyPDUoOzcyODMvOzMx +OC44OjY4ODQ1OjQyOjE3PTUyOTMyPTU2Ny81OTY2ODItODM0ODQwOjQ4NzYoNzI1OjYzODMv +NjUtOzAvOTEuOTA2OzkxODMzOTAxODI6PDgxODc1NjYyNTYyOjQvNjMzOTI3NzMvODwyOzkz +OTY0ODQ3OjkwOjIyOzMtNzE3ODYxODM4OjkxPjJBOzVBQTpCNjk1Njc5ODgvPTQ4OjY0OTI1 +OjMzPTQzOTc0OjkyOzE6OTUyODYwNDI0OzcxPjM1PDcyOjM1PDYzPTI3ODo2PTVBPkE/STpB +Pz47QTpER0FBS0BAQDw5QztGREEyOjg6OTk0PTg1Ozs8Pjg3Pjk0Njg4Pzs5OTU6PzhNRDxu +Zk2hg1+xkmu8nmvAonbHqH3Npn7GqnvFn3XCo3LJp3fEoHC4k2e0hmOlf16TdVR6bUpwaEtr +X0d1ZU1xXUdxYElzZ0lwZElqWktsZE1/fFKVl1ukpmy3snPVx5XZz5Tm06jl0qLt1qnpzZvs +yJ7nzpnlyZTjw5Tdv47gv47gv43hv5DgvIjbt4XVsn/Tq3zNpm+/k26rgWGLZlFXSEQ6Ojoz +Rjs0PDIzOjw1PDY5Qjw6RTs/R0g7SEA3RkI8T0I9UFA/Zlk/ZXNDZWM8aGhLd4BEbXtCc4FC +am9GbHpCYnQ/XmZBb2hCYG4+WlE7T0xFXVE4VVxAaVY9aGdDdnhGfH1OeXlEfXtLgIVNfYFJ +gIVMhopMiIxOio5UjY5NgY5Eg4hLhY1GhIlPhZJQi41QgYhOjYpShZNRioZWjZRPiotMjJZM +iYtZi5hUjZJQhI1OfoxLdIJJfYZJfX9Ef35LiopMhIVSfY1KfJFNgJBMiIVNhIlRgY9Yi4xT +i4lKj4pJhIFNg4dLd39PfY1UhJFgjJpakJdVkpZYjpFYkZhWk5FXkpJRj5FTjI9QjJBLiZJM +go5WipJWiJBTh41Sk49hkJRUkpRViZtUjZJckJpPlZBajZdVjpJelJ5UkpZbkZhZkpdWi5VX +kZVXjpRajJROi41WjZVWi5JShpJSi45WjJFHiZFKgIxTgopQhYtVgY5LhIpSgY9EhIxQgYtK +h49TgotFfIlOfopHgJBMgotUhI5Oh49TiphNhI1NiZJPh5NPg49Uh5JQiZdRipJVh5JPhpRR +h5JYjJlWh5VNhoRRhJNRiJpNgpNOhZFMgI1Jg5RPgolNhI1KfpJHeolHdodGdYdJcYJFcH5F +cIJDbXpCZ3VBbXhGZ3A2Sls4RD8yQDcyPDU7Pzw/Pzw/Pjw8PTk6Pzg5PTk/Pzg7Pzc4PzU/ +Ozs9QjVBQEJCQj1MREBFRkBtlVP2/93///r////////////+//31/+/6//L///////////// +///5//bx/+v1/+v9//Xy//Pt++X6//D7///u/Ovt+OPg9t/d7Nna683o9Off9tzX4NH8//fx +8+fp9+X3/f37+/Hx/uz4//Pu8+n+/v38+fH0/vb+//b9//Pp/uz3+/D7//b3/+3z/vL2/+z8 +//ju/+fj/eT89u/x/ujs9OHh+OVYTVI1PztORjlaRj9lST5lQz5RRjpAPTs/RThCPDpURzhp +RzxUQzZPPDk+OTA7Pj05OzlEPzlHQDk6OTQwPTYtODg1OjQxOjU0PDE2ODIzOzg3PDgxNTc7 +PTEzPDMvOjIsOjU7OjsyOjM0OjYxPDA0ODQvOjE0OjYtOjA3NzowOzU5OTUvOzQ5NjM2OzU2 +PDUxNTM3OzgzOzQzNzUxPDU2ODo4PDU3NzgzODQ2PDsxOzIuOTUxPjAwOzYrOjE3OTYsOzU4 +OjYvNzI3OTY0OTY3OTgzOjM4PDU3OzcyOTY5PzRAPjU3OzIzNzM1OzM0OzMwOjU3PjMwOy80 +PDUvPTE3OzgvNy03OzUuOCw3MjcvOi88Pj0sOzI8PDswNS4/PDk1QTpFPjhCSj1FSD9CRT84 +PzpDST9HREE+OzxARz49PTgyNjg2PDQ1PDhARzlBQEE2NjQ8PTk/QTlCPT5LSTVwVk2OdlGq +iGm7mGm9m3TBoGnDonbHqHLGo3HCn2zConXGo3fHn3rJn3rEoHbFmIC7hXa5dnSpa22jZGSb +YFuLZlGGXVF6XUp3Yk5tWkZvVlJiUEJdVURmY0d3dE5/hlCVlVu7tXPXv4/lxpvjzZbnyqHk +yZnpxZzevJTfvY3fu4jlwYvgvZLguZDasoTZrHvYqoLTpnbFlnewf2CIbFZXQTw3Pjo6QjY2 +Pjg2PjkyPDg7Qj07S0E+RkY7Sj43QT84UkdFYmRAX1xCZWo8ZFtCa3NBZ2pFcYRGfH9JdIhI +cn1BbnNDZHI9Y1xFY2Q2X2Q8UlI+WVE9W18+YlhDaWlHc3pFeX5OfYBFeH1Nen9Dc3tQfYlK +h4RPgYtMhIZVipFPhoJQgJRPi4pWjY1Hg49YhY9Si49UhY1MjopUj5BTi5hSkZJVkZRTiYpR +iYpVjY1Pjo1ViJNLj5JcjJZQhopYgJRBfYZVgIxJdoRPgoZJfX1RdoVDeYFOeoZPeItPgolP +hZFVipJajZlajpBWkJhdlJZSk5dbjJlXjJJTipJWj5NXiJFPjJFXj5dViY1Xi5ZSjIxViJpc +mJFZipRUjZdZjJRWjpRXjpNUiYxXjJFYkpNhk5dXj51djZlbjpFZk5ZWlJ1Vj5pVjZVVjo5T +j5VdjZRWiY9Uio5OjJNVho5QhotOhYxJiItShYlPhJVPipBIg4tNho1Kg4tSiZFMfotFhYpR +g4tMhIxPgY1OhZFRhpBQhY9OiZBQiJdShY9PhY5NgI5Mg5NOi5BWj5dRho5ShphYhZdWjZhW +jphQjphMhIJPjJFWjJdTipZRiJVLgYdThZFLh5ZOfo9HfI1Lf4tHfItFeotLd4tId4FGdIJH +b3lAb3xBbndDam1CWWw/QkosPzszPTY2SDY6QDRCQz8+QTg9Ozo3QTQ9QjwzPzE/RD88PzhD +Qzc6RTpISTtFRz9QSkFijkn1+Nb///n///v///n7//H9//j///////79//r2/u/8//H5//D+ +//L///7///////3///j///v///v//////Pn6/ff1+ez1+/P4/+7p8+bk7Nvx9+vv/+z0+O3v +//T7/e71//v///X1//L5/+nz/vb///v0//L8/u34/+76//n///b1/fL+//r///v/+/j5/vP/ +//j8//H///7///v19Ov17OBZS1E5PTlHQDxZSTlpTUBaRTlSOzpBPTw/PDU/PjhZRjhgRTpg +RzpLOzhGPDo7QDY7OTc5OzBCOTYwOjQ4PTkxNjU5Nzg0NjE1OzMqODM3OjkvOjE6OjQ4OzIz +OTUzOjErOjY2PDI2ODMzOjA5OTQvOjU3PTczODM2OjoyPzQ4OTknOzE2OjIvPDA6NzQwODQ/ +Ojk0OjI3OjcwOi04OTc1Oi8vOzQzPjgwOjEyOjMzODIyODM6OTgwOzM0ODYwOjMyOTIwNzM3 +NzUyMzE3NzQrOjI8OjcvODE8ODUvOC09Ozc4PDY+OTMwOi83OTU1PDYyOTUyOzUzPDY0ODYx +OTIzNzcxOzI6ODgxOzUyODQ4Ojc6PjYxOzIvODE3NjY0OjQ8Ozo8PjRGSEI/QjVDQ0E5PTg8 +Pj06Pzo9QTpAQTs1OTQ4ODoyPjRBPD07QDtDPTtAQTxLPjxIQDxdTkJ3YU6Wd1uthWW2kGK8 +k2+9lWnCnWzFmW/ElW/EmmrDm2y+mnPKqHHTrH7XqX/PpHrSrYbTr4XNtH7RtI/MsovUtYTO +rIPTpYrLlIjDfIGcZGR/U0tqTUdhTEBTSUNOSj1XTkRdUUBrZkaTkVa9rHfYvoPhxpfnxprl +xJjjuIjdvYnivI3fwYvivJDfv4Pct4Xbr4HTqXvLpnDGpHWxiGiHYVNMPjs2PDk/QTkzPzw1 +OTc7Pzc/QT40SD5FSEU8Q0U8QTo8UUhBaGBGXmk6Y2VDYWQ/aGlHbHBEdHpPeYZEdXBMcH1G +dXJNdHw4XlxDbW8+ZGBBY14+UUY+XmY/Vl1DbGRBb2pJen1PdYNPdXxFdH1Oe4FHfopRfYZM +gYVPf4tKhIVUgY5KgoZPjJFJg4tVhIlGiIpShpVOiolTiYtRipNXjZJVj5RRkpJZjJRXjJNY +kpdVjJtSippWipdUkpRQj5VVl5pblppZjJddiJhakJJbiplNiZBajpdViZFeiJhZlZVblJpV +kJNViplOjo5ZkJNVjpFWj45Ui5NTjpNai5dZlpFdkplUiY5TiZFak5FYjpRekJpVkZdgkZZT +j5Jbk5VUkI1fjZRVkJFbjJhTjpZekJRPjpNZk5xWj5VUk5RakplSjpRah5hQi5FWjZZXjoxS +i5dUjZFZjZBPho5TjpBNh5BRiZJRiJBRg45Tho1Qh45Ng4xSh4tOg4lPh4lHgYxQg4xNh45S +gYVIhoxRhYxHhIhKhIxQhpBViJVNhZJQh5JIgYtXi5dUi5hcjp1Ukp1ajJtWjZxWjKBYlJxX +kp1ShYhXjplZjZ9RjptWi5tThpRFgYtShJBGiJJMeoxKfIxNfo9Ke4lMfI5Fd4VJcYRHcXlF +bXo/bXVHbHdEa3FDTGsyPjw3Ozc4OzQ9PTk7QT08PTdCPTs+QTxAQDpEQURHP0BKPkJAPj5D +QTtCQTtMS0NEST1ll1D6/+n///n9//b9//j///r////////////9//n+//z////+//v+//L8 +//33/+78//T8//f5//L+//by/PHw/+Xr+uvr/ODg9uHY9srg79vj8tnn8+L5//D6+fHt+O/1 +//Lx++jv/+/3//z///P8/+/4//X+//P6//f9//v8//r39+j4/ur///n5/+76//D4//D+//b3 +/+3q8eT5/fn////5/+VUTU1ER0BERDhfSkFlRDljRTtNQzVFOTxCQDpCOzpUQj1hRThfRTtH +ODdDPjk7OzY7Ojk5NTo9PD04ODE0OTI2OjgzPTI3Pzc3Njc2ODk1OzQ2NzYyODU+PjorOzI4 +NTI1OTg6Njs0PDE4Ojg3NzU4OTg5PDc4OTg8PDc5ODY7NzYwNzc5OTQ1NzkzPDQzOzc5ODU7 +OTg0OzQ7OTg2Ojg7OTY1NjQ9MjgsPDQ5PDsyODE/NTs1NjI4ODgxOjQ4OTw0OjM2OTo2Mzo4 +NzQ5PDY3ODI9OTo3Pjk8NzY2OzM6PzNAPzo2ODY7OTcyNjA3OjksPS49ODgwNzQ/OT4tOTVA +NjgsODNBOzU2Nzc8PDgyODo+Ojg3OTIyODc4OjQ3PjQ8PThBQ0JBQD09QD9APjo9Pzs+QT08 +Pjk8PDdEPz04OjY+OT4/PjRqS0huUkhoR05TRj9NRkVkUkVyXlGae2GxiWm6jW68i2zBj2u+ +mG7Il2/BlWvFn3LKoHHImm7PpHfOqnzSq4LVtYfWtI/Yuo/Zuo3WtIvQro3Mr4fQqo3NsYHa +toPavZHYuobXqIvHnYC9fHeiZ2GIW1NyUktrSEZhS0VkT0huYkyfkF/LsXnhwZHgwZfgwo7k +v5PhvIbdvY3fuonctoXfsn/dtInYqHvSq3rQoHvCnm6whWuCZlJPQkQ2PjY+QjwwPzQ/Oj45 +QThAQT08RjxITkZIUEg/Q0M+Tk0/ZVpDbW1CcHVIbXhEa3JIcHVDcnVOhoZOeoRLdoRIeHRG +dGtHZ3RAWVhKbHFDYl1EV1pBW1hGXlpDamNMcXxGg4BRgZFPfYdQgIpLfYdQhpZPiIpQiI9V +goxTgoJMg4dVf4RRgolQgYlMg45SgI1PiY9ViIhVg41YkY1SipFWiY5Wk5VXjZpVk5VkjJlZ +jpVWjZhUj5laipNVjJFai5ZZj5pbkphZipVekJxhkI9Wk5JZlJJUjpNbj5ZWjpRZj5dcjJta +kZNZj5hWkJJaj5hVkZhXi5xWjJVYhZldkJhZjplXjI5gkJhakJRjkZldjpZYi5RckJtglJhi +jZJajZpZjphWkI9djpZfkZpckZldkppbjZhfkplUkJVgj5hUkJNijJVQjZRfi5FRipFVj5RS +ipJYiY5TiJJTi41YjZJNhI5ThI5RiZFTg5BNiolRhZBPiJNPiJFOh5NRhIlShpBSho5Qh5FQ +hItWhpBUipBbhphTipNVjJFShpNSiZNVjo9VjZZajZdVlZhcjJxXlJldkZ5UjppbiZ1Vi5pU +iIpWjpVfkp9Wj5lVhppNgo9OgYpViJVUhphMgpRNgZRQgpBSfpBPeIxGfIpPdohFcodFcX9D +bXtGbXhIanlHYW9BQV47PT9EPkFAPzlEQUA7RT5DQUBCQzxMR0NKSUBPSUZKSkZGQUNGQ0FH +RjxJQklOSEBlhE30/9n///////////////////n///////z///////3///////////77//T+ +//////3///n///r9//j0/+r9+fPy9ev6//Tu9vPn89j08+v6/vfn7uDt/+zw/+/5/vL29ezw +8ef6+Pv////t/Oft/eH0/PP3//L0/e78//f9//b+//z///fz/+n9//35+/Hy//f4//H6+/P9 +/fP///nz++fW3dNWTVE7PTlJSD9ZST5lSDxgRjpVQD1FPz0+QDlDOjlOQztgRD1aRjpOQTY7 +PjY/PjcrNzU4OjszOjo9OjIwOjg8ODgyNTg3PTU3PDY0Ozg4NzgxOS82PDUzOzE7OTUxOTQ4 +Pjg0OTE7Nzc3PjIzOzU1ODQ5NzE3PDU3OTUzOjg2PDI3OTc0OjM5ODc0OS42OjU6OTU5Njc4 +PDY4OjI3OzcuOzQ5ODgxPzM3OzY2OjU4NTcyODQ4Ozk0OTI3OjYwPDM0ODQ0OzA7NjYzNzk0 +NjgwNjEyOTc3OjA0ODc2ODY5Ojo5PTg9OzQyPDI5OjcwOjQ5ODcwOTM/OTk0Ojc8PjQzPDU6 +NjU1OzU4PzQyOzg6PDY4PTQ0ODE0QDQ4Ojg3Ojw7QDg8Pzo4PDk6Ojk7Pjk2Ojo7PT82PDVC +Qj49RDg+PDtIRDhvUkx0Ykx5ZVBfVUNWRkVSTT5wVk+BZ1Cnh2atjWy2hWe7jm68jXHAkW/A +km7Fl27LpnjNonvOonnTrHvYt37ar4bTtIDRsH7TsojOtX7NrYbHrYHErofGr4XOronVtH/Y +t47ZsoHWqn/Tp3/Srn3NqX3Dm3ewf2OndmCiZWGZZViTYVSWd1jAp3bavYjav4vfvIrhvIjc +uIzZtIrctYbVuX/btIbVr4DQqIXMqnrGonWwi2SVd115Zk1PPj88Ozs5QTo2OTwyPjc2QTtA +QjtARkBDTUZFSUY/RkRAVEtEXF8+Xl9Hc3dEbXVKbXdHc3dCYWxHenlMfoVUdXpCaXtDZmw/ +Z2ZAaWk/bmtDWGY9WltIXF1AY1lHZWpId3ZPfItOhY5SgpJQfodSh5dRf4BPg5VWhotPhZVd +iZJPhY1UhIxLfo1UhohPhY1Sh5FNiIxLiIpTho1OiZNUjJRRkJBbjJNSjZFZipxVko1XkJdQ +i5NUi51UiYlajpRRjZJUiZZVj5hYj6FakplbjJJWjZVYi5dajpRajpRcj5NdkZ9XiZZdkJNN +ipdbiZVXkJNdjZRNjJFaippWkZVajJhOioxVhpZUipdShJJSjZNaiY5QjZBdj5lfjI9MkZJa +j5VakJtZi5laj5VVjpVWkZpXkpdajJpRhpNbj5lajZVaj5lUi5NciphTjJVZi5lLiZFWi5JU +iolVh5ZViJBRiY9XipBQh41PipRQiI9XhZBYiJNOf5FNg4pPh49RhpRNhpVWhpdThJBPg41O +iY9Xi49OjJJUi5VNh5NZipdNiphVjJhVjJpejZpQjZpWjZtVjZlXiJdWi5dUjppUjp9Qhole +kqJbkp1XjJtWjJ1WhpdMhJZUi5dRh51TjJdVippUiI9NfpZMgo5IepJMeYhHdYxLcoREcoBJ +bHtCdHxEandLZG5FQ1E4RTtBPz07OjhBPDo3Qzk+Pz1ERT1DRzxHRkFBQ0JFQ0BMSUFEQ0FJ +REBKR0Zcekr//9n///////v///z////+//z8//L+//v////+///8//X9//j8//D///z1//X6 +/+v9//f///v8//r+//j2//f2//L2+/fs++fs/enq+ejm9uPi79r1+u/t9+bu/u32+uvz//X/ +//T4//X7/+r+//3////+//P7++b3/+f5/+35//P8//Dy8e3u8+b9//vz/+/0//H9//z5+fD6 +/u77/+7q6NZYSk43QzlERTtUQD1mRTlgST5VQjtBQzw6PjU9PDtTQDxcRzpcRj1HPzU/Pzo1 +PDc4PTczOTE7OzgwPDA1OjkrNzE5ODozPDE1OjguPzU3OTMvPjE1Nzk6OjQ2ODg2OTMtOTY3 +ODQzPTQ2OTU3ODcvNzQ5OTY0OTA6OTgtOjQ3OzQqOTAzOTUtOS87OTctOjE5NzU0PDI9PTg5 +PjM6OjMyODA6PzYzPDYxPS84PDgzNzM0OjU1PDUyPDU0PzMyODQzOTYuOzE0OjUzOzE2OTct +NzA4PTcrNjM8ODcqOy09OTgsOTE5OTMrOTQ4NzU0ODY2OTU3OTE2OzU1ODYvQDM2ODYvODE5 +NjQ2PDY4ODIuQDI1OzMzOjM3PDI4Ozs6QDRGR0M6PTU3PTo3PzA8PT0zNjA2OzoyPDQ7QDpE +Rz1ERzqFbVuDblKJbVl2ZUlwVk5TSD1UVERuWUWOd1KlgGKpime1jGu2i2O9i2bBlmq9kGvC +oG7JonDMn3PUq33VsoLct4bVuH3WroLIqXXLp3TBrXPAqW/Iqn7Ap3bDpH3AqnrJtYbNtoPT +s4bPq37PrHbLpnbJqnLHoXS/lGi6i2WygFywi2W8kGy4jnLJp3PZuoXau4Tevonet4rasoXU +rozRr3jSroTLsX3Kqn62nWmmjmmPi1aHeFpoYUpdVUhKRzs2PTgxQjg4PzY2QDc1RjxEREU6 +RD9BR0E9RkM8STw/VlA9XFZBZGc8ZmFFa29AcmlKeX5CaXhEcWhJe39Fb3FBcXdBZ2k/dWtE +Ym09aFtDXVlBYFRBYF1BWFpCZ25EbnZKe29FgINPfYtSiJRPi49Si5BTjZNVjZVVh5JQjZNZ +iZVLiYpVipVThY5aipZQi49Xi5ZKgIhai5VYlpldjphVjo9Tj5FXjJJXiZJRjJZXkJJajJ1c +jphWi5VYiJRRjpVPipJUkpFcjZVSkJdbj5tQjo5dkppUipFgjZZVjptalJlZjpBXhZhWjpJb +iZVfkJRZi5NaipdPj5JUjZNRjJRXjZdejpRZkJxejZJYjpNej5BYjZNbkJhWk5RejZZYlJVf +kJhUk5hcjpZTkpphk5hVlJlhkZVXjZVZjZNajpZUjplVjpFVj5VTiZRNhI1Wh5JRipRYh5RK +hoxXlZVnjJVViY5ThIxSiZRQiZJQiJFSiJVSiI1TipBQh5JMiZNXjY1QipFThoxRh5FVi5RP +jJNQipdWiZBUhpZWi5hXjZVWlZlYjppSkZpUi5tdlJpVkJxXk55dlZ1dm55dlKJXkotflqJe +kaJYk59ZlJxakKFPipFYjp1ZkJ9Yip9YjZ5Th5lMgY5Oho9Jho9NfItEe4dJd4dBcH5Kb35F +dn5Lb4RCbXdKUG46Qzw+RDw1QDw7Qzg+Pzw7Pzo+Rj44QTtCRzxCSj5CQT9CRkJBQDtDQkFA +SThddE7r/8n+//L///T///////7///77//39//b3//P+///h9Ozr/t/4/+r///n+//r+//70 +//H4/+v1//P1/PLs9Obu/eLl+Nvm+uff9dbo9+bi8tnm89z1+u/2+efw/vH3//T7/fL6//D6 +++r6//Hu9eT0/u37//H5//j/+evy/PH5/O/9//f///77//T1/ery/fP8/vPy/e39+fX5++32 +/erw6dtZSFQ7PT1DQztdRztkTD9kRDxHQzxOQDs/QDdDOzpKQz1iRD9hQzZLPzc+QjY5Ojs2 +NzI0NDM8PTQ2OTc1OTY3OzIyOjs6OTEyNTQ9NjYzOTg5ODg1ODRBOjg1ODg6OTcyOTY6PDYt +OS86ODkvODA5PTYvODE6Njo2OjM4OTQ4OzU5OzUqOjIzMzM6OTQ3ODo3OTQ8ODQ4PDI1OTQ2 +OTU8OTI1PjM4Ozs1PTk8OzcxPjM8PDoxPDQ4Nzg3OjI5NTc0ODQ+OTcxOTI8NzczNzM4Ojc4 +ODk1NTM4OTkxOTEzOjYxOTU8Ojc2OjM3NzI3OjkxPDI4ODUxOzE7PDkwPS87ODotPjA8Njwq +OTU7Nzg0OzQ9OTcwOzM7MTo4OTg/PT1EPz85PDc3Ojs7OzZBPTk3PDc/Ojg6OjpEQTg+PkFP +STyIc1uEZFCCZlCUdFl0UVVaRzlaU0p6XkSVdGCeflmthGavjGO5hGi+jWq6h2u5h2PCk2fI +n3DMpnnYsoDetIHfsoTXqnfRm3bMl3G/iWaxfWOef1iaiF2kkmSxmHKym3K4oHC2n3C+pXPB +o3jEoXHFn2/Dm268lGy0hl+zhV61h2O5hmG/k2rKm3vQrHnatofasoXcs4Xct4XWqYDRp3zK +oXHFnm6/mm2pjG9/blZhVUlWSj9ORURPRTtDQ0FCODc2OzU6QjU2PzQ/PTk7QTtGQUY5RDhH +Rkk9Rjw8T0RBXFpCYWlFYWNDbG5Jc3VHanhJc21JdYNJdHBOfIFPcXdMfodKeoFOeIRCZmdM +cGxEXFRJYV1EamBFYWBBampMdnNBcGxRfXdRioxbiZdShZBZiZVWj5JTi5RYjJFXjpZXj5dV +jJZTipRZjo1ViZVXjo9Xj5lbiZdYi5RdiZtSjJZgipZXipVfk5tXkppYh5BVjY5bkp5ZlJNg +kZdLipBXiJJPiI5cjZZWkZdaj5tSiZRZjpVdiJdejZNYipthj5pVjJBbj5hXkJlUlZdZiJhZ +jpFUiJJWjZJVj5FYjJhaj5VejJVQjZBZkJVVjY5WiZVUjI9YjpZakZNZi5Zgj5Nfk51djpJY +jpJYjJhVipNYjJZVj5hWkJRaj5RRhpBXjZJVjZZcj5NSipRfiZZUjY5Zi5dNipNdh5VMiJFY +h5NLg45ahY1Mi45YiY1ShpRQiZFXho5Oi5BZhJZOhYxUg49PhJBUhpBKiI5Who5Wi5VQiI5T +iZFRiZRTi5dUhpRWh5ZVipJXjJtRjJhUj59ekpZUkJ1ZlaBckp5jlqFdkaFWjoxfmJ9clKVX +jZ9bk6NYjZxPhJBYkJ9ZjppUj5ldkJ9Yj5tXi5tLhJZShpVNf45Tfo1NeY5EeItMc4FHdoBI +cYJLbHpEZ3BFQFM8PjtAPT48QTlBPDs7QDhDPD83PTtBQT9DRD1GP0BEPkBEOzxERT9IQ0BY +fk33+dL///7////+//v+//X///////////////////3///3//////vP///T6//T///v////9 +//n9//H2//Dx+u7y+O/4+uzz/ffl9dfo8uDo7eDa5dbs/PL1//P///f//vv5/fD0+uv+//z/ +//P7//T4//f6//j9//T6//D+//z///v0//D8//j9//v/////////+/Px/N/z+Ofz++3u7+Xt +7N1fSlY0QTdHQT9ORjxmRT1YQzlSOzw/Qjs/OztAOzVLPzpZPjlgPzdHQDVDOjs2OzU8NjYr +NjQ6OjcyOTQ6ODUnOjE4NzgvOC01NTQyOzA5OTU0OSw1OTc3Oi43Ojg0NjE6Ozo3MzYzODMz +NTEzNzU1MjI3OjI3ODI7OTczOzc3OTQzOzI6OTkzODQ6ODUwOTFCNzk0ODI/OTcyOzA7Ojcz +NzQ9OzgzPjQ8ODM4OTQ2PjcxPjU3OjQyOTQyPzA0OjktPDI3MTUuOTU0ODY0PTM3NTQ8NjY1 +OTE1NzgwNjE4PDg0Ni82NTo1OTAuNzc0NS8yNTQxOzE5OjQ0ODUvPTI8NDkvOSw5NzQuOi83 +NjYzOTM5OjQzNzI5ODg9Qjc4QDg9QjszOjc4OTc3PTg1OzUyOjM5OTk6PTRAQjpHQjxKSDt/ +b1R7aFGGaVSQdllsU0tuVUhTST9xXkeMdFOhhVmqhF2kg1ywiGaviGG2g164jGS/kW3DmnHN +oHPUqHfYs4TbtojdsoHcsYTXrHvXrHrTqHvDlHCja1l2WkZ9fFGrlmu4nXu3kXC3jnCwiWiu +hWaigFigfVqSfE+dclSle1C1h1y+j2zCkm3Ko3LVqXrWtX3WsofetIPUrIPFoXC7lmytjmOd +gFyPcFVwUU1ZTz5PSkQ/RDlDPzw7QTREQUI5PDQ4Ozo2QzA9QT5ESkBLSkZJREE+QDw+QkM9 +QzQ/Sj9CXFVDXV5GWGVDal5GbXNFdXZNcHZFc3BDYGRHdHZLcIFFeXNMcnVDc3BKZHE/Z2RH +VFw+YVpGZGQ8Y11LZmhGaW5IbnBLd3hOhItSj5ZYiZFVhpZSipZbkZRajJdThZJQiJJNiZNT +h5JOhZFRhY5Vho9VjZdZjpJfjJJTjolVjpZZi5NOkpRajpVVjpdYj41XkpJWipNLjI5YjpdZ +kJJZjpBXj45ei5dVjpNYjpdbjpNTkZRhjJJZlZ5ekpxViplgkZpVk5tbj5hajZdclZNWhphZ +kpNYlJdakZddj5dZkZJakplUi5hYjZlQkpVflJxZjZZcj5tVj5NVjJVXkJFakZlakpRYjJdX +jpdYj49bkZRZkpZai5BVjJBSjZdWi5BTi5FViJJQi5NZiJJTi49ZjZlShJNZipJRgYpWjJJS +io9Sh5VSjI9WiJJRhpFTipJSj5JUjJVVi5RThpNThY5UiI9Wg45KiY9WhZFTipFWipdYjJhX +j5dbkZtZkZpciZpQipBYj5dZkplikZ5WlKBhkp1Xm6BdkZxZkpxalaNTiItllqRYl6Bfk5pf +lJ9biplTjZRglaFemqNZl6VbjqFVjJhPhpJRhpNOhJJPgJNOgJBUf45Dfo5LdYdFdnlOeIRE +dIJJcnk+UGk9PEU3PDxBQTo2PzU9Qj09Rjw6RTw/Qjw4QTY6PTo+Pj5GST9DRj9HRD1Xbk73 +/8P///v////////////////////////////////////+//7+//v///////////n///r///jv +9vHn7+Dv/eb5//D0//Xd7NjX79Do9eLn8eDt9+P///z3//P6/+r0//P7+fHs++v1//b5//H9 +//7x//X+//zt9+jy/vb///z1//b78+vr++32/+31/+vw9e/9/fv///7/9//+//z5/fX79eZb +TV06QDtDQT9NRDxeSz1bQjpPP0I+PTlEQ0A3OzRPQz5YQjheQT1PQzg7PTg6PDguOzY4PDoz +PDk2PjM8PjY5PDQ6OzEzOjc6OjUxNzc2ODgzOjM6OTguODU6NzUxOTI6PTcsOzUzODcuOjI3 +OTUyNzQ2PTcxODM2OjYwOTU2OjUyODUtPjUuOjE0NzY5OTgzOjQ6ODU9Pjg0OTg6OTk3ODU9 +PTs0OTM3Ojo4PzY3Ozk4OjE5Nzk0OTQwPDw4OTQvPDQ2PTQxODM1NzcvPTM6NzUvOTM3Nzgy +PDg3ODQ2Ojc2NzY1OjU4ODYzPzkzOTg3OTcyPzY3OTU0NzQxOzY3Ojg3NjczOTk0ODQ2PDgz +OzM6ODo1PDM3ODw5PTg9QD02Ozc8OTYvPTE7ODk1PDk0Ojc2PDc1PTc6Rj1CRjtGTD5oW0h9 +aE6JcFGPcGB1XEx9YFFSRT9pVUOHblGZfVakf12lhVqxjWm5jWm1h2eshVvAlGrEm2vUpX/R +rX3esYPVtoLeq4XauI7gvY3dtorfuIjWrIHHlnekbFqEW09tVk1vb0yFjVSonWyrlWyui2ig +fluLaVKAbEaqiWHJmHvXqYjIm2vUqn/csX/et4vmv5jlvJfdr4LQpnvBlWifelmHbFaKaU+X +cVijb12bZluIW05+V1N7VlFgT0lKRD8+Pz0+Pj08STxMT0RPWE5PTkhHRkBHREY0RDg9Rj81 +TEFDWVg8XldGZmM+X19GcHBKb4BKeHlJanE8X2FJeX9EbHBFenJKdH5FaW0/bnFDXmo9WlxB +Y1lJaGJDdndFY3k8ZWBEcHpJf3dTh45RiI5TiJJWiZVRi5lZjphRjpNZkJdSjY9WiZxVi5BX +jJlVk5NXiZdRkZVVjZxQjpxTiZhZkZdRkp1gk5dbj5xikZ9ZkJldjZNTjJ1ejplbj5pcjpZa +lJNSkpNWj6BSkpdbjZtWj5dil5pVj5hfkZhVk5Ndi5tXjJNYj5hZjY5akJhWj5NckZtYj5pP +jptWjJNaiphRio9WkJZTjppRi5Rdi5VWi5hPj5hfi5dTi5RgkZtakppclZZakZNbjZlakpRf +jptUkZpelJtTkJhZjJdRkZpVh5hUi5RUipBUio9Ti5Nfj5NNi5JWiJJVjJNQh45TiJJQjJRT +hY5OhoZShIpNi5BSipNSjZZWiJVMiIxSf49PiY1WjJtUj5RajpNSjpZdjZlSj5pXjZdYkZNe +kZhbj51Uk5ZXjJtVjZ1ek5xfk59ZkqBej59clKBflKZbmqBjmqZQj5FdmKhXlJ9jlKBRj59g +jJ5Pi5JgmqFamKdekp9Xi5tUjppQhpxPhZBRhJpTipRLf5NNg49RhZZJeIxHcX5Bc35Jd31C +dIhNbXc7RWA2SDc9RkM5Pjc8QUM5Pzs6Pj88ST08Q0Q8PEI8RjxCRkBFR0FCSEJRaUj//9T6 +//n+//j///////z9//T///v///n///////////n7///+//H9//v9//r////1/fD5+ev8//b9 +///8+fvy9+n8/Pfy+vTv+9/29/Do7+Lf69vv+vLt9evz+/L2/fL0//f9+e7t++rz/enr+un5 +/fj0//Pz//P1/+/69e/0+Oz9//v///f5/+fy8u/5/vv///7///fq8uju/u79/fHo6thZRls2 +QDlDRD1SRzpZRTxdRTlOPjhBPjg9OTs3PTlFODhWQztXRDlPPjdANzwvPjQ0NjQsOzQ6OTYv +OTI2PzYwOzM4OTYuNTQ4NzgrNTM5NToxOTM5Njo0NzE5ODsuNjQ5Ozk3OjcqPDQ1ODM0OjQx +NjUzPjczOzA3NzMuOTEzOTMyOzAyODUwNTI8Njk0PjU/Nzw3ODM8Pzk0OjI5PDo3QDE2ODg6 +NzEwOjk0NzQ3NzMuNzYzOTA1NjczMzo5NDg2OzMxODY3ODcwMzI2NjYsOTQ5NzktOjY2NTgr +OTQ8NTktOTU5NjQpPDc4OTMvOy85NzUyOzQwOTI2NDczNjYzPjY1ODYwODMvPTYzNjQxOzY4 +NzQwOTY1PDY3QDc2PTo7OTc4OTg4OTw1NzY4PTwwOjE8Oj4xPDY+Pzk+QDY+PTxbUUNqY0eE +aVODa1R0X01uWEVbTENfVkR8ZEyNdU+XdFaYeFang161iGu1hmW4gmW/lWrHmnTLp3fSpHvc +rYPcsYbcr4bivYncwInfuYjdsoPatX/aq4DQmnexcl+DXkV7WUlYS0JeUERcU0ViUUdbSkVm +TUSOZ021jljYvoHguYzPnXrXsn7huYzmvofqyZ7tz57gu47So3a1iGKNaFOYcleshF63j2W/ +mW68lm/AmG22j2mthGeWelpkUUxAQDs+RkJFSUNFT0hTTExGSEZISDs/REE+PTw3OTo8RUBA +VVdBW2BBWlw+Y11EanBBeXhDbXxDa25JanJEeW5SeYxDeHhLcH0/Zl9GcHJBYmJCZmtBV1BK +a2lKdXhNcHw+ZGJCZXBFc3BRg5JRjZNTiYpWi5NThpRTkJVUjZJMiJFSiZNViZdcjJhKiZFT +i5lRkI1WjZlPh49TjZlOkZVWjpxVh5NdjJdTipBgkJZYkplRkpNWi5JUipJUiZBYjJJRiJFV +jpFVkZBdj51Wj5dYkJtYkJdZj5pbipxejZpPiZNajpFTi5RajplXkZJYjJ1XjpFXkJdZj5VY +kZRbiphUiJdZiZVXj5hRjZdUkZZZjJZRkpNakJtbiJRQjpRZjJJPipJYipRRhZdYjpVVjJZa +j5RPjZdZjJlOi5hYkJhViphPjJVXjpdbkpVaj5hVkpNZiZNPho5YiY5RjpRZiJdRiJNXh41O +iZRQh5RVipJZjZlTiphTjIxOgpFRjJFTiZlWio9Si5RQiZNTjJlTiZdVjJNUi5ZOjpZbkZlQ +jJtZjJpXk59ekaFYlptWk59al59bkaNXj55Xi55ZlJtZkZ5TiolWjppXkZ9bkqBelJ9ejqNU +k5VelKVYk55alJ5YjZ5VjJ9OjZpUiplQjJVTg51OiJZYhZVPiJZMepBDc31KcoFFd4JKdYpE +ZoFGVHM6QEQ7PTs3PDw4PTw8QkI9RDg+P0A+QTxEQz5MRUJKRj1GRUVHRT1YZk7z/8T///// +///////////////////////9//r9//39//v8//f8//D9//////7///z7//X9//v////5//fv ++ej0/u3y//Dc9N/b/dPk+eHh793d5d/u/OX+//7t8+Xr8eHo9uD+//719eXt/O35//Ly++vs ++ej2/vX9//r///r///v6//D+//X5//H5+/Hx++zt/fDs9ejt9ez8/vLy9+jt5NlWTl1EPzs8 +QzxPQDZbSDteRzpSRjw/PDM/ODg6PzRDRjpXRDxdQzdGQDVBOTo1OjU7Njk2PTQ1Nzc4QDQ0 +OjQ2PDk1ODI0NjgzMzQ2NTc1NjMwNzA6ODQ1Ozo2OjE1ODU8OzM1PDU2PDAuNzI2PTQrNDI2 +OjksPDE6OTYvNzI4NjU2NzQxODcuPTU7OjU4QDQ3PDU2OTE9Nzo4PTQ4ODQ/PDg6Ojc6OzQv +OjcyOTU3NzkzOjM6OjUzPC04ODUwPTE4ODQxOTc7OTg1PDE5NzguOC89PDkzNjA3OjgzNjUz +NTQzOzU6PDk3PTk1OTQyNjYyOjU5QDY0PjgxOjM1PDQ2ODQ5Nzk3PTM2NzgwPDU3ODkzPjM5 +QDc0PTFCQDw1Qzc+OzowPDZBPTo1OjU9PzUxPTU3PTo4PTg5QjY8Pjw9PjpCQjdNRT1iVEJq +Wk5kU0FlUUJnVj5jTz9xY0OVcFKOdk6gb2SkflSre1+xgVu6kGnBlWnJm3bOnW/Rqnncrn3a +roDbuIbjxJLhwY7gu5LftIHitoDfsHzZuoXdsILQk3WrY1eEVkd9WkRsTkVgSz1rTkV5X0Kt +g1vJqHHatIPdt4TaqH3atoHduIHivIjqyI3rxqTguITQonixhWOYd1SfgFmqgFyvkWW+mWq9 +om3BoHC+mXGohWV+alpWTUNFRkY/QztCSEY/QjtCRUdDQjg/RkE6Pzw4Qj07QD09RT9GWlBC +YlJDWGM8Y1pHbWxJcmhLe4NKbXNJcXJGcmVQeX1Me3xRgItGaG1GdXxBY1pFa3pMbGFFcWVS +e3RKbHJLc21Lc3lJc2NUioxQh4tUiJJQj5Nbj5dTiopajpVVjJhXkZlVjZNXjpVTkplXhZhS +jpNXl5NWjJRXiJlWi5dZkZ5RjZlSiZJRipFVi5RZipNTiZZSiZNTjJJOlJFZiZhLjY5ejZJW +kpNejqBWi5Vdi5VRkJNaj5ddi5VhjpZUkZhai5VUh5JWj5VblJdQlpZakZhWjJZUjZdSi5RW +jZhViJRWlJRekJVZkJNjiptRko9bkppVi5ZVipRRj5FdjZhXj5VZj55RjZRajZxTi5BVkpdU +j5JVi5NbkpVXi5NXjpZbj5RZjZFVjZRTi5NVi49QkJZWjpVTj5JUiZJNjZNdi5NVjJlVg5FL +ipFWiZFVhZRajJBQio5XjJNRi5FbiY5WjJVWjZRUjZRYjplUiJtTj5VdipdXjpdZjphXjpdf +lpxXlJpblJtdlZ9XkZtXj6BUlJxfnKZfk5phlKZelaJZkZFdlaVbk6NYj5lUkplZjZtTlJZk +maRXmKNhmadfmZxajKJWj5xYh5pTjJNXkZxVi5pbjpVbh51Tfo9IeIxGeoBMeYBLdYJLdYRG +a3tEUWI4RUY7QDs4PT45PDxAP0A9RjtQTEFbW0FgXUdmYkVoW0ZfVUJwalD3/7z+//T///// +//v///////////////////////3///z///////P///n6//T6//X+//r///n///zw9O/y++n8 +//rt+O3p9Obk9Njp6eTc7NLg7dr8/+zm9uLz/e////7///f6/+/9//z9//T7+/f9//z///n0 +/fH9//f3//D///v+//f0//H99+z8/fb///f///j///719Oj3/u77//Dv8OZjT1w/PTpFRjhK +QD1fSjlUQjdWRDg9OTNLPDo2PjdGQ0BSQD1aQzhEQDdBOjU2NjQzOzE0OjQ1PjA0NTI3OTE4 +OTgyPS45OzYrNjU4OjY1NTQ8OTQ0PS47OTI6PTM1NjQ4OzU5NzM1OzM5OjY3ODA5NzU2PDk1 +OTY1NjQ3OjAwOTE3OjM0OjQ6ODc1PC0+OjY6Oi08OTg3PDQ5Ojc8OTI8OzU6PTk4OzYzPDQ4 +ODM1Nzg3OjYwPDI2NzY4ODI2OTU7OjMzODQ4PDU4OzI0Pi01OjE3PjA8NzYzOzQ7OTcyPC43 +OzUzOjA6OTMyOTE8ODc0PjE5PTUzOS06OjM1OzM4PDI4OTU7PTg5PDQ5OjY2OjY8Pzc+PDU3 +PDA7QDlBPjw4ODA9PTk6Ozc3ODQ1OS49Pjk4QDhCPz5CQT1DPD8+OjpNQT9PTTxkTEBfT0Zq +UkNsUUJ2XEZ3VkZ4WkWOb1GMaUuVc1OkfF+wgV63gmS8i2DGl2zNlW/PmHXQoXDUp3rYsX/c +sI7ivIvnwJDqxZLqvpDpwJHjtIXfsX/ar33VqXrMpXDPm3fKjm67fVyvcFOwdlC0dVDDjmPV +qXHgtYHlu4jdu4fcs3zXqXzgtYbhvIXswZTesITToHOqdmSIbUuSdlaef2CpfWSkhFiqi2Os +lGOijGiJdF5dSURHREBDQjw9Pz49RjlAQzg8QDZBRDk8PTc4QT44PjU7Pz45QTQ/UElEVFZA +Z2pAZVtHa2dLb29JenhRdHhIdnpJbGtLe3NMcn9Kf39FZXJEamBDY2RMbm5LZGJLbmZPd3JM +cmxDb2tMen5GdWVYiItPf4pUjI9QhpRcjIxRjpZZkJhXkZNYi5JTiZNSiY1Th49Qi5NXjpdR +iZBXiJVOiotal5NXkZNWiZNWk45aiplVkJNWkZ9TjItZiJVdj5ZcipFXiIxZjIpYjpFdjJNY +ko5ekJZXjJdbkJVWj5VhjJNZj5Vbj5VZkpZYkJpXi45Vi5RZi5Jfj5lXlJVckJdVkZZhi5lN +ipNfjZVcj5lRi5Vbj5dakpVbi5VZjpJaj5dbi5NXjZNXkZdajZFaj5NSj5lgjphVkJNdhphS +jZRgkJdWl5dei5tWiJBTi5ZXjY9ZjZhPjZNXkpRai5NRjY9aiJJUhYxYiZBVhZBVhIxYjpNX +jI5aipRUjJRYipJWio9XjpZQi5FcjphZjZhdjJhQjpVckZlTj5ddkJdVkZlckZtekJxekplc +jptalJtblp9alZ1clqBdlaNilJ1dlZxelKBYkKFYj4pbl6FglJ1WkaBbkZpbkqFblZdclqNl +mZ5flKVdlaBZjpxai5pVjZdajZtWkJpXiZpRjJlXi5lUjJhQfpBEd31QeIRPf4RPdohFb4RH +ZXo9QVU+Pz49PT06QTk/Qzk/QjpJSz9VUT9cWEJcWUZnY0RlZUqIg03u9rz+//j///7///n/ +//////7///j////////////////7//v+//H///v///v////9//n///P8/+36//P////z/Ozv +++Tt/+bk/9bp++Xt8uba5NX0//T0/fD8/vr0//D///Lw9ej9//Xr9ePs/fLx/ej9//T7/+7z ++/D0/e7+//X8/+z9//r////////9//P8/vH6//b3+fP7+ezt7+Dr7+VmUF47PjVEQTpEQztV +RD5RQDxMQzw8PTs8Ozo5PzM9QTdFPjJPOjxAOTI/OjouOS84MjgtODI7ODc1OzE0ODIuPTQ2 +OjcwPDQxOjQwOTI2OTI2OjQ8ODU9OjU8Nz0vOjM9OTk1ODExNjMxOC06NzYuOC46NjgvODI3 +ODUuNzEyNzczNTE5NzgwODI5Njc4OjczPCw3OzQ4PjE6PDQ6PDMzOzI7OTc0NzQ4ODY5NTcx +Ojc3OjQ3ODY1Oiw3OzQqOTE6ODQuOTE8OTQvNis4OTYzODMzOjI2ODIwPTUuNzEuNjU1NTQz +OTAwOTQ2NTI3OjkyOzQ3NDMvNzQ1Oi4wODY3ODQ1PDY0Nyo7Njo4NzE3OTg4PS46OTo5PjA3 +OTo7OjY3Pzk6NTY3PDc5OzMyQDA5OzQ1Ojc5PzM+TD07ODc3PTdBPjhaST5mTD5iT0VlVj9i +U0ReTkBxXEV4V0iIakuKbE6Tc1Cge1iqflqyg166jGbCkXDIm2/Mm3LHmmrYonnWqn7dto3c +t4rlwI/mw5XowZPhuorhr4Ddq3vdqnTVpXbUonDLj2u/jWO+hWPJimHSm3neqYHnvI3rwpXl +wJrluYncsoLSpHvOpnTYqXPetn3lwIzes3/Sm3WtfmN9bFdYUUVvc0+glV+vhWqdfmKAZVVo +ZEdiW0dKRz5CRz5NQ0RCSERARjs8Qjg4PjtBREI6Qj07PT03Ozc2QzsxQTpAUEs8WlBDYWA4 +T1JDYV1AZWVOd4dMdG9ReoZEaGFJc29Ga3dHeYdFZnJIal1EdnBJcW1Lb25OaWdHeHRFbWtE +bGVLaXFBdmxXiJFPh4pakphTjI1cipRTkJVXkJtPipdbjplLiZBXipBQiZBSkJZTiJJUkZVY +ipdUj5NakZZSk5RXjpZSj5dVippYjplRk5pYjZlZkppalJtaj49ZipJUiZBViJtSkI9cjJpR +ipJRkpFZjZJbl5lbhppZk5xaiZhckZJYjpJWkpRZj5ZSkI9akZZUjpdZjJVWk5pXjJZWj5dQ +i5Jij5ZSjpVejJNUjI5bj5tVjplekZhNjJJcjpRei5ZYjJJSjZVSjZlTi5JUjpRRiZRUlJlW +jJtWjZJXiZRakZNfkp9XkJdYjJhUj5NSiZFSipFUh5FVhpZVhZRRjZJYipRWiZVSi49NiJBV +ipRSiJtVi5FVjJFek5RVjJNZkJpVj5ZZjZhUkJRajp1YjZlclJpUj5lak55Wk5tbjJxXj5pd +k5xhlaFfmqdbk6VdlKVkn6BknKdck6VWkp1Ti4ZWkZxbkp5WiZxSkJhak6FTl5ljnKBYl6Vh +l6hYkp5XjZ9Qh5tbj5ZWkZxakZpXk5xXkKFWiJpUjJhNf5RIcoZIdYJHeIdOgY1KfIpJe4hH +Zn86RE8/QTg5QDk/RT0/ST1DQUJASD1MSkVCUT5lYEdjYkOViVP2/8P+//b8//L+//f///// +//3///X///3///79//n5//D4/+z///z///3////v/O/2/uv////6//H6/+/v/Orq9eHs9uPe +6+DZ8crt9+nm79zh8OH5//T5/+36/+7x/ev29/L3/u77//D2/vH9//z///////Xu+ev8//3/ +//f19/D5/PX1/fX8//P7//X6//D2//P5//T99/H9/vf///71++lrT1s+QD9DQD5IPz9LQTtW +OjtFPzc7Ojc8OTg9OzlDPTVJPTZEPzU2OjM7Ozc0OjI6MzYwOTQ9OTkwPDE1OTgvOis2Ozow +PS46OjYzODI2Njc6ODg7OjVBOTYxPDIzNzA4OjU4ODc3PTI1NDg3NzA0OTM4OTQ0OjM6Njcx +ODI7OTcsOTA8ODguODFAOjQwOjU+NzYsOTU/ODk5OTc4PDQ1PTM5OzY2OjY2PzM/Ozc8PTY/ +Ozs4Ozc5NTc1NTU0NzU0ODIwODIzOzgzNjU4ODk0NTE6NTkyNjM1Ojs3ODEvODc5NjU7Ojk1 +Njc3ODU5ODgzOy45OjcxOjQ3OjkwNjE5OjgzODQ6Ozg5OTQ4Ojc2PDE1OjQ4Pjk4NzY7PDk1 +PDU8NTY4PDQ2OzU4Ojc4Qjc1OTc4QjU6OTk4PTk+QTo7Pzs/PDxLSThrWkhtUERyT0JhTT5c +TEFlVUOBak2KbE+Lak6ObkugclOtgFy6iGG1hWnAk2vGlW3Nn23PpH3VpXrbsYXduI7kvJDm +ypXqxpvpwZ3ktormrI3crHbhs33YqXXapHTWom/Zo3LWpnPhtojpyJLrypXqxZXtwZDpv5Tc +sYbYnnDPo3PZp3bapnrbr3rer37dr33Rm2+we1+KYE1kRz9KQ0BNTj1ra0x8d1N1Yk91XEdZ +R0g8QDVCQT9DQjw+Qz88Q0I4PDg5PDg5QTg8Pzg3Oj44PDo5PzY4PT04UUY6VFRAVFc7UVU/ +UlQ9X1pLa3Y+a2BTfIZGc3FJb3JFdHNSdns+aGZMZW5HdIBGbGNMZ2tCbmlGcXY/bmJOcnpI +aW5BcW9Wio5ZiplTjphXi5lWj51Xj55ZipdQjZVZipRWjJNaj59WjZdUh5JPfo5QiZFUhpFT +jplYjYtTlJxcjppYkplnmJ1XkJRZiaBSk5hYj5lWkYxaj5dWjIZZjJBWh5BWlZdekJVVjZxd +iJNTkJddjpZTiphfjpRWiZ1ej5xTlJdZjJlVjZhVlZFZjJdSiJFbkZZYi5BdjJdRjpJdipxX +kpRbjplUjY9ckJhXipVai5NVi5hYj5ZWjpRai5JWi5FVi5NSjJRVk5lYjJpYjJRZjJtXipdY +kpNfj5VRjZNYipNWkZhejpZTjJJajZpTiZFTjJJRh4xYjZlXjpJch5dRiJVVjJVRh5FWjJBQ +ipVZiZtYh5ROjJZYi5VTjJdQhZdWi5RMiJFXjZlVkJ5cjZtZkJdakJtYjZhejpxQkZhfkptc +laVlnKlXkJ9fkaNbmp1claFamJ5dkKJTio1Yjp1YkZ9Wi51ckptbl59VjZpgmaVclaRakaNY +jqBYjp5RiJhWkaBUippWi5xSipdilZ5Xk6Jbip1EgJFPc4dCdn5QeYdNfo1JgItKfo9Ld4pI +Vm88Pzc7Qzs+RDw9RDs6RT0/Qj0+RURDRD5dVENlZUKLhVb6/8L///3///v////9//j6//b/ +//////////z////////+///+//L///b///z////////9//z6//T////9/v3///z3+/ji9N/m +/Nnx9u3l9drl8t3s/fP9+ers9+Xw/urz//H9//73//X7/+3x/+z0//Lw//H6//L1/+/z9+3z +//L8/fPt++b4/fL9/PH8//f4//X7//n7//D8//Xt8N3q7tlhTF09RDg9Pj5EQjZLPDxMQDVE +PzU9PzYxPzk6PDU1PzdCQDc3PDQ+PDcxPDc1OjUqOTQ7OTQ3NTc7NzYtOjI1PDEzOTc5OjUz +OTUzNTI4OTI1PTA5ODU2Oi83ODktOTI5NjkzODUzOzA3PTEwOjUvNTc1NDM0ODczOy41OTYz +ODQyNzYvOzQ0Njc2ODAsPTI7NjU0OjU7OzQ0OTIzPDY1OjE9PDY1QDU8Qj86QjlCPEE8Qjg6 +OzY0OzA1OS81NjM2ODYyOTMzOjIsNzA1OjM4OTMuNjU3OzEvNzUtPDQxNDMyPjIzNTUvOTU3 +NjQ1Oiw0NjYsPTU4OjMvOzg0OTguODU3OTYyOjE6OzUvOzQyODM4PDY6QDgzPTs6NTc5QTw5 +PjY3PjkzPDY8RTg8OzYyPDA5QDo0PTY+Ozs6QTU+PTo2PTJFQTpRTTlcR0VfVT9pUUBnUkNs +TkZ4Zk2UcVOLaE+ObE6geFOoeVe1jly8kWrIk27KnnfPpXfQpnnVpnrXrH/dtIngv5Xkw5Hu +xqfowprsxaLmuozhq4XdrHrbqoLZpXHbqn/fsHjlsoLer4Dgu3/lt4LqypTrvZTdsYDZp3zU +oW/UpHPZqH3ZqHzar3nZqXfdrn/Plm68g2agc1R/WUpuUkNhSEFIRz5MSkNWV0KUd1RdQ0U6 +PDU7Pjg2Ojk3Ozk6RDk6PDw1Pjc/RTk6Pzc6OzkyPDcyPTg2QT03RkY/U1Q9UFA9VFY+VU1C +YWA/bG1FZ29HbWtFcHVLc4BDb3VJcXU/a3NJal5BaWVHbGlLcm9KcGtJdG1JaGpJcGhKY25J +f3xXipNekpdalJxckJZRiZZWjZRZjJhbkZ1SiZpXjJRPh5JbmY9YiplZiZdWkIxZlppTipJP +jZRVio9Tio5aiY9MipFYkpNSi5NaiZhRio9VkZdYkZBWkJVZjpVXkpdajpdXjZhajY9YjJ1Z +lphZi45YkplflJlXkJhakZ9XjphWjo9Zk5lfjZZRkZdTkZhTjpRSiZhYkZhUjpdNkI9alJlP +jpZek5lYlpRgk5pWkJpZkJpajZRZjZdWjZZZjJNVkplai5FVjJZhlppZjpNWi5dVjpVaipNR +jo1ZkpZTkJVajZxVkpRci5lYjphWjZRSh4pYi5lRjZBVjJVXjZhVipVVipNSkJZUh5RSkJVT +h5FSjJFTjJBakJZXjZpak5VUjZhYi5xVj5dZjZ5QippejZpUj5tZi5tSj5hekJpVlp5ll6Va +l51clJ5alJdYlZpXkpdYlJtdmKFIh4pVkZ9Yk6FXjZ5TkJRclJ9SjpVflp9el6Fbk6BdmaNV +iptTjJZSjZVbmKRclZlZkqJclKFbl6Raj55PhppNeItEeoBOgIlOh4xNhZNJf4xHbYdBYnQ/ +QFE5Pj42RTg5Qzs8PTk6QUE4QT1BR0JcV0BhXEd/gE3y/7f9//////z///z////////////9 +//39//////////////r///X///////n///D0//D6//L3//T2/+3r/+fo9+Ln9uby/+zp/+fs +9Ojl6N/h6tv5+fDy/vH+//rx/+75//Lt9eHw/vD8//bx9/Hs8+r6//f5/ffx/ez+//r0/+74 +/+/6/ezy++j4/PH4/+/7//zr+eP49fH8//b//fnt6uVvV2Y3RjM8QT9EQTtDREBJQDdEQzc8 +Qjg7PzU4Njg5PTY+Ojo6Pzg2Ojc0PDIxNjcvOjAwPDQ5PDQsOi8yPDcoPjI7OjIqOjI2OTQr +ODQ3OC8zOjI5Ozk3Ojk7OzYwOjg2PTU1OjIvPDE5OjUyOjE0OzUyOzE3NzUrOTQ0ODMsNzE1 +PDA1OzIzNi0yOzQ1ODM0PDUyOjI3Ozc6OTI4Pjs+QTg8SD9HST9DSj9ER0E9QDY5OTYxOjI0 +PDU1OTQ4Nzk0OjI3ODY1OS81PDIyNTI3ODUzPDIwNzQyPTUyOTA0ODU5ODM0OjQ1NzY4OTQv +ODM0OzIxOTQxNjI3Njk1PDU6ODkwPC04PDYyPTA0OjYzOTM7OjYwPDM1PTYwNzRERTs6QTw9 +PDo7RTpARTtAQD42OTc5Pj05PjQ/Qzo8QzU4OTc1OzU3PDNQTD1XSz5lVUNwUkV5VEhpUUCH +Y02Gb0uMbFCMa0ufcVamgFWyh2C1jmXHlXPEmnDKoHHSpXTXqX3Xr37fuI7mv5fnyJnwzazv +yKPtyZ7nu5vltYrquonltoXmr4LksILnsYXkroLir4zfsXrkt5LjuX/iuJLcqXnXnnXXn3TU +qHrWpHvWpHTWnHPZpXXaonHWn3S/hWSsflmlbleWY1F7WER2TUNeSDplVT6Nf1ZqTkk5Pzg/ +PDw0QDU6RDszQDhAPT42QDQ4QDg8QD01QTg1QDU0QTQ2RT84TEdBU0o8XlA9WFk8Z2NBXmhD +aWlHcnhCX2BAdWxMdoBAbWJDZWQ/ZlxFdXFBZ11DcW9Ha2xEaGZMeHhGbm5NaGw7bWxPfYRU +kY5ck5xSi5JZkZpbkplWi49UkY5ViJNUi5NSiZVXkZRRi5JZjZZRh5NUiYNTkZNXj5JSjJFT +jZJTkJdXjpFRipVTi5FXjJFWlJVajZhVi5JakZxTkpVZjpZRi5Rhj5lZj5ZclJpbiJRYkJhT +j5Jajpxfj5pakplZjplZjJJTjZBhkZpYkpNZj5JUjZdYkZZTlJNYi5NVipZUiJNRiZZckZhS +j5halZVSjZNajpJTjpFVi5hSjI5VjJpQipRWipFQj5NblZZWkZdakphYjpZRjJNXjJVZkJJX +k5VelJtYkJpaj5hSiZZai5dQh5BZjZNVkZZbj5xUkJFakJRNjo9ciZRWkZZWjZxZkptViZhW +i5ZViZhUjJtRj5dWj5lQj5lVjphXkphajZhWk51ZkJZcl5lgk5xckpValZhclJ9WkpdfkJ5T +kp5hk6Jckpxdkptal5himaBPh4tbjp5Wi5tYj5RPipNUlJpXjplalp9clqNYkJ9jlKFPkZtY +j5VXkp1ekZ5YlaJakqFbk6BamptcmaVSjZpLfpFMfYNHe4tRi49RgZZMe4JPfpNHaYM+TWM7 +SUE7QD0+Oz83PzlAQj5CRztIS0RZWkNnY0d8fUz3/776//34/+7///////z+//r+//3///// +//////f///z////9//b8//H0//P5/+r7/fL4++7+//f3//f2/e32/+/7///l8uXV6Mvd79vk ++N7t/+X////p8+Ps+ejx/+z4//n8//by9+f4/vHt/+/+//z///Xy+/b5/fX9//L7//3///// +///////////99/Dl7uDz+uvt9e70/u71/+vs9d52VWw8QDo/QDtHQDtFQD5HPDlAPzM4PDY4 +QDY2Pjc6PjU5ODk3PDQvODw9OTQzNzM6NTktPTQ+OzkyPDtCNzksOTY6PjcpPTU7OTozNjs8 +OzQ2Ozg2PDQ+OTU0ODU1NDQ6Pjc0NzQ0PDY7OTcyODY1OjQ1Oy43NzIuOzYyOTI1OzgzODAx +OzQzOTAxPjUyOS44PDkzNjI2OTw5OjY8PzxCSEBHRUFERUA/Rj5DRD8uOTI0NjU0PjQ0Ozcy +OzU0PDU4Ojk1NzgyOjM4OjIxOzI1OzMxOzUyNTU4OzgyOTU2OTEzODUyOTIzOjUxOjM0Ojgy +OjI3PDgwODM5NzU0PDQ3OTkvPjM2NzU0OzY2PDcwPTdDQTYwOzg1OzU1PDVBRDxCSD5APD07 +Qj8+RD86QD03OjI6OTk7Pjk3QDg8Ozg2Ojc3Ojk1PzhFQD1QTDxuUUhhTEBnTUh0WUOHak6C +Z0iRa1aTck+oel2ohFm5imq5jWrHl27KmnTKoXLPpXfSpHPWqnzhvojlw5Xozpjz3rn43MPz +0LHtw6flv5fquZTnuYnquIzou4LltIvkt4Hhto7ksn3lupHqvJHlsIjdrH3dqnXdo3zUpXLa +pHzWoHnbqHTXqX7Wn3PVnm/LjmrCi2a1fF2rhFuoglmofV+kcFWrdFatimN/V1MxPzRAPT03 +PTg8PTs2Pjg7Ojs5OzkzPjg1PDg0OjU1Pjg3Qzk8QUE4Tko8U047WEo/XGI/XV4+ZGZCam9E +aWVAXV5AdmxMdHpAX1g+XWdCaWRGaGxDcmZAamhBXl1BbmZQfX1EcHpLZm9EcW5NhoxWkZle +jptTjpROhJdUjZNdj55ZkIhWiplYjJhTiphci5NSjJRWipNPipRZjJNVipZVjI1Sk5RWkphY +kphWj5ZbkJlVk5VZkpdTlZpdkpxOkJdYkZdOiZBYk6BZlpJai5ZSk5ZVjZdal5VakJhQj41a +j5lXjZZZjpdXi5JWjJdSj5hWj5RUjJZajJhVjpJaj5ZVipZYkpRRipNXj5lckphVjZtRkZVX +jJRUkJRXj5hVipdZkZZOkJVYjJpQkpdUjpVXk5lZj5tYkJtTjppUj55Vi5hVlJVakZlXkpZc +kJlXjphVkZZXk5hajJlXj5VajJ1Qio5Uio9VjJBaho5Th4xWhppTi5RbjJhXjZZYjphXkJRa +lZVYkZpWipRXkJpYi5lbjZtek5pUkJlalptZlqFal51ZlZ5akZ1blZ1glZ9Qkphdk51Sk6Fg +k6FVk5xbj59YkZ5al6FSi4tbkp1VjJ1Ti5lWjZZalZ9Uj5tal5lalKJYlKZYkaBUi59XjppV +jpxckZpblaJekqVaj6BckptalqNalJpHgZhIdoVGfI1MhIpJe41KeX1SiZRLeZVFYHU6REc7 +QDg7Q0Q2Qzk/PT87Rj9BSD9VU0daWkd0ek7q+a/7/+////z////////////////////6//P/ +///////////9/vb2//P+//z////////7//X2//Xl8+Pw++v2//Ty/O3m+ub1/+Tx9fXn9t/h +8Nvu//H4//Lp8ebo6OLk8OD19/f9//j09ejv/un0/+/5//H7/+/5//D2/+37//T9//3x/+7t +8+Hq/e7///3/////////+/n2/O7++fvs7OBuU2U6RT46QDpDPT4/PzpJQT88QTk7PjM2OzQ5 +OzozOTZCPDsrOzE2OzgzNzE1OzorOi45PDcvOy82NjUuOS44NjowOTQzOzY0OTE2OjU5Njk3 +PzM4OjU0PjQzPDcvOjIxPDQ1PDQ2ODI2OTIxOi82OzUwNjU1OzYmOTI7OTkuODI1OzQqNzA4 +OTQyOjQwOTM0OTQ1NDMwOzs0ODhBQT4/RT5DQ0E+Rjs9PzsxOzU4OjcsOjQ3OTI0NzYuOjI3 +OjgzODExNDgzOzAyODovOTIxPTUxOyw2Pjo1NTUuOy8vOjMwOTI3ODQyOjM2OTIrOzM0OTMu +ODE0NzIwPzI2OzIzPDQwNzQ5QjUvPDUyOjU0PjI/Qzc2Nzc3OzM6QDk7RDhCQkJBRENCQj9G +RD49Pzs2PTQ6OjcxPjQ6QTswPjI9OTcyODY2Nzg2PDhIQTpRTj5hTEBqUUR2YEWBZ0uMbkmS +a1qVdlaofmCshFuziGS7imnDmm7HnnjOpXfOrXjVon3WqXvbtoXiwpbmzJ336Ln++dP/8tj6 +4MT0zrLvxp3vxZnnxpHqvZbnuYbouIvjvoPnu4niv4jnxZblvYvntovdr4PesYHcrH7drHzX +q3jbqXzSo3PUoXLSoG7KlHLAmWTKkm7Ah2G+hGO+ll7KnXbHn2/BkG6HXVM9OTk4Pzk7PjU0 +PTo4PjoxPTYyPTQwPTE0PTcuOzcvOzMzQjU6Qj8wRTs4T0c3S0Y9WFU2ZVtGbGY8bGRBVV02 +aWpDY2I9YV5BWVxAWFdDamNCbXNHdXVCa2dFbmVHdnVSfX9FaGhEcGxGcXFWkZdclZ1ak5lU +jpZWiplTipNTi51NjIxXipZSi5JWjp1UjZNSiZ9Lj5JYjZBTj5hPj5RWjplRjZRMi5dWkI1X +kJlTlI1WjpdZjpRPi5NTjJRWlJ5ZkZRPkZZUiJNNjpdkjZRYjJRhi5pTjJtYkJpWkJlXiphU +k5hYi5JMg5JRio1SipZRj41UjJZTiphXkJdWjJlSiZhTkJBVkJlMiJdRjY5Rj5VVj5NTkZFW +kJVUi5dckJ5Qi41YlJhVkJdYk5RVkp5aj5RYjJRbkZlTkJdVj5RWkJFUjJZNj5NYj5VLj5hX +jpVSkZRWj5ZQj5RXjZFPjpNWjpdUlZdYjJpVkJJYjphViZBTkJdVkppZjppRj5dVipZVj5ZQ +kZhTjZhVj5VOjpRVjZhOj5ZZk5hXlplakJxVlJ1bkZtQlphflp5amJxflaRZkZtXkaFZlqJc +lqFXi5tXk5lbmZxSj4pak6NRjKNSiZlWj6BakaJXjptclpxhl6ZZl6JclqZPjptYkZtWlp9b +l59amZ9fmKpXmKNdl6JWlaJckqFajJxFfo9Geo1HeotFbX9Ff39UipROhJdDYYI3RFU7QD49 +RUI5STxDREQ8Qz46R0BBTThKUUdfaUf4/Ln///z///////z///////////37//f///////// +//v////8//T9//z////2//Hz+u79//r5//T4//T////0+O/s+N/w//Pl/OHm9N/r9+Xg79zz +/+n4//37/+n+//z5//H1//X///j///7////////v/+fx/+/x/ur09+7s/e78//r///3/+/3r +/vD4/vT0/+30//f7+Pb///75/+307uRpUmFAP0M7QTpEQD5APztDQTlCOzo2OjU3OjY1PTI1 +PDc1OjcrOTY2OzcyNzU6PTg0ODUyOTcwOzEwMzUxPDM2Njo1NS0+NzswODM9PTo2OTI7ODkz +PjQ5Ojg0ODM1PTUyPTQyNzMzMzY6NzUyOTEvOi8yOTgzNzk0OTQ0ODgyOTQzNzY2NjM3OTkz +ODI4PDUrOjE3NjYwPDI+PTo3QzlGRT8/REM+Pj02OjY1OzA0OzMxPTIzOzU0OS8xNjQ2OTQ0 +OzYwOjIzMzM0OTg0PDI0Ojc1NzI1ODkxNzA3OzoxOTAzOzo2ODI3ODs2ODMyOToxPTIuNzcy +PTczPDUzOjYyOzM3OTc2PTY2OTg1NzU5Pjo+QD85OTg1Pjc7PzQ/Pj87PzpGQUVFQUNNSkRE +PkE7PDgzPTc8Ozg2QTk1NzUzNzszPDc5NTg9PjJIQT1OTEBeTUFkUj+CYlCFaU6RbVGCa02Z +dFWjg1e1iF+6j2vBlGjDmm7IoHPLpXXQoXPYpHzapH3broblwZbsyKH14LP39cj99dD87cz3 +2bnvy5vrx5rowI7kuYjkt43ds4neuX7jtonguIDgtoThvobov47etoPbsH7Xp3rVnXfXonfX +pXneqYDYn33Rk3HMlHC9kGjHlWnKnHHHkm3Ik2fKnXDEnWzDmXaPXlQ/PEA3QDE7OTszOzE4 +Qj8yPjQ6Oj8yOjAxOT01OTozPCw2PDQ4RDs4R0Q6RkM4S0I9VU0/Z2BHYmVAWFk8XFY/ZmJA +W107ZWBCUFA6ZmFLZm1EbnVLams8bWdIbWc/bl5JcHE8aWdBb2RFdXBRkZZZjZhUjpVVjZpV +jJlVipBTipNQjJRWjJhTjJdYi5RRjZNUi5NYi5NajZxTlJNaiZlWkJdVi5NPj5VYkKZZjplX +jJxVi5lSjpFSlp5Wj5hciZdRjZFYippUh5ZSkJddjZZRjZ1Ui5tRjptgjJZUjZNZjJJYlJNo +jplNj5hckJRTj5NajJpRjZ1ZkpNVj5ZXi5VVj5Faj5BVipdRiZNWiJVSj5ZaiZVSkJVajZdR +jJNSjpBSioxWjZhYj5ZYkJtWkZhajJdTlZlbkZNVk5dZjZhck5pXj5RQi5tYkJpYkZZWkJZQ +jpdakplXjJhWjZJWlZpajJ5Pj5lZjJxPjI9UipVQkJdejp5RipNVjZZVjZtai6BWjplajZlU +jZJXjphSiJlQiZlQjJVWiphRj5pZjJtZk51TjJtUkJxdkJtZkp1fkaRXkZ9cl6BUkaJflaNY +kJxikJ1Wkp9SjY9Wk55UjJxSi5lUi55cmJ9RjZpclJ5blJ9bkqBZkaJTipdWjphakptZkqJb +lppik6Vcl6JhmaVWlJxaj51WiptQe5RFd4NOdYI+cXtPgIdSipRXh5VFcotAUG0/R0RUWUlk +aFxfYlxLT089RUVBRT09SEJQWkb0/7H///v///////n///n///3///////v3//b9//P////5 +//X5/+n///////n2//v///////f3/fH6/+/4//b8//L2/ffj9eTd9NTr9+bl7uLX3tL3+vT1 +//H5//Ty/+T3//T2/e3w+O75//T1//P17+Xt+PP9//77//z///f+//7///X4//T///7///// +//3//fLx/u7t9+/w/+33/e/0/vN5VW86QjlCPD8+OzpCQDo9PjY/PDo9OzU1Njg4PzY9Ojs7 +OTU7ODU3OjM6NzUzPTswOzM4PDc4OzMuPDU8PDg1OjU7NzYvPDU7ODYwOjY9PDk3PjA5Ozky +PDI4OzgxOjE/OzsxOzE4Nzg4OTQ4OzUzOjA3OTY4OzYxOTQ1OjM4ODY1Nzk7PjgzNzE3OjU2 +OTM6ODYwOTI7Pjc5RTRDQj44Pzs/Pz41OzM3OjgtOiw2NzMsOS4zNzMxODE4NzY1OzI4OjQ2 +NzkzOjQ0OjQ3PTQwODQ4OTkxOzA2OjQ0PDIuOTMxOjQ1OzosPDI6NjkwPTI8OzoxPTM/OjUs +PDU7NzoyPjc3PjcuPjU2Pjc5OTo0PDY8QTY0PTU7ODo8QDlHRkFAQzlORkM7QUBCPzo3PDw4 +OzE8Oz04Qzc+QD80QTQ9PT41QDY3PEA1PDNDQkBRQjlbTENhUkRpWUB0XEmEa0qSbE6Nb0ui +gVexlF+7kWm7mW3FmXXDonLLpXXOpXXWq3zbq4TYsYXhu4/kvo7tzaDs1anz3bHx3LLx0Knr +xJ3pwozlvIzhsX7fq3zWp3fYqXfVrHLcs4jcs37guonatoLXpH3Nl2nJkmnSnXXUoHDWnW/Y +nm/VonjUmXPLjnK+hmLHmnHNnW/QnnbOl23Fl2rInGrBl2uZalc9Pzk4PTw0PzE3PDszQjc3 +PTk1PDU1Ozo2PjIwOTk1OjQ2Ozw4QTU1S0U6Q0Q6TUZBSkpBWU9GV1k7WFVDYFc7VFVBXlVD +XmJDbWdOeIRIb3JJbnRGZWZFcnJCZ18/ZmY9ZWBJa2pDZV9OhYhSj5JZj5dPh4xWj5ZXkJNV +iZJTjJBXjJlQio9OipFVj5dUkZRRj5NXjpRXjI9VjZhRjIpakZRclJZcjJZPjo9ak5xJiYhW +iZdRkpRdkpdOipdbi5VOkJdVkZpZk5BZkJlelp1Qi5dakpdakpxcjZpYkZhal5tfjphYkphU +kppbiZxVjZtemJRcjplUk5daiZpSkJJRi5lOkpdajJdSjpNUiptXk5Zbj55flJdZkppaj5NW +jJdYkZFXkphVkJlajpRUjplalZRZjpZXkZpUjZ1alJdakZdfkJpXk5lilJtZl5lbkplZlZph +lJlSjJZWjZNWjJNWkZpXkZ1ajplUi5pPi5NXjJZakpZUh5VPiZNTipFTkJVWi5RYlJZdlJdc +kptYkZZXlZ1ZkphYkZtYlplYlZ5hlJlXkqBWkptZmqRglZ9Wkppek51WlJlgk51clKBclJ1Y +k5ldlKFSjo1UkKRUiqBQh5tRjZtclKFajp5gl55XkaBakaFclZ1XjphZkplak6BdlptZlZ9f +nJxdmaRWlqNck6ZalaBej55NgJNLdYZFdIVIcHxIg4hUhZFQipZSe5dGZn1SXmJmblhwdWRr +cWdwbWNhZVxRT08+RE1LW0Ht+qz+//n///////z///////v////////////////////+//79 +//L+//r///3////w//H8//b8//X////1//bt/OXv+OXq9One89Lp9+Tn8Nzd79fv/uri8N3s +9Ojq+un6/fL2//Py/+zw+OPq/vD+//z///31/+ry/+/6//b///77//Hz++fu/+z+//z9//X4 +++/9/vzu6enl8t7p8uTk5dZ4WG49QztBQD5EQTg+REA8QDc3QzM0PTY4Pzo8PDg1OjczOjc2 +PTA6ODk2OjcyOjc2ODYwODI8PTYtOzQ7PjktOjc7OzYsOzY9NzcwOTY+ODkyPDI9ODU1OTU4 +OzQyOzc7OTQ5OTkyPDM8PDg1Ozc6ODc0PTE0OTY2ODc2OzYxOzYzODM3OTw6OTI3NjUzOTAy +OTowOzI8QTk8QTQ+Qjw8QzY2Ozk3NTEuPDU0NjUzNjI1ODcsPDQ5OzgyNzc4OjgrOjI2Ojgx +PDM4OTQsOTEwOjUvODQ1OjkyODY1OTQvOjQ2OjgzOTY1OTY2OjQwOjY0OzUzODcyPTc9PDsy +PTU/Ojw4PDQ1NzYwOjE3PjgyPjY8PTgzOzU9Qzg/QThDPkFARj5LRUM6Qj85PTk9OTk5PTk3 +Oj09Qzw+PTw4Pjg8Pzs7Pzk0PDY+QTg+PzVLR0FPTD1jVUZqW0Z2VU55YkONblKHcVGkfmCs +iF3BlWy8lG3Hmm/Fn2/OoW3RpHTVqn7aroHZq4HjtYjcs4PlvIjlwZjswJnnwJXlvJDjuo7h +s37frofTnnXMknHMn2/VqH3Yo3vUoHrWo3PXpnrSpXHMlXjIkmvIlHHTnXHSmnDYonTYmXrU +mHfQj27Li2u9i2LElm/NnmrRpHTTqX7Om3bKm3TAjWGbZFQ+Pzg+Q0A1PDU+Oj80RDg6PjUx +Ozg9OTg1PjgzPTo0OzsyQDQ7QT05SEg3SEM7TUU+UEs7SEM/TU4+WU4+WFRAW05DXFU+Zm1L +fYJGa3VLbG5FampHanRBbGlDW1xAX2RDbntAY2RFcXhSj5NXipJSjJJWiJZSi45Uh5NSkY1X +jJlUio1WiZRPiYtOipFgkZZPipdZjZlUl5pekpdTj5ljkKNRj5ZZiZRakphilZpUipZRi5Ra +j5RSlJNTjZhSkZFTjaBLi5hakphWjpJWjpBRipdYj5hbj5tej5lYjJBWhZ5Ui5lbiptZkJVa +h5hVkpJWjJdWlZxcjpVWi5JZkJZPjpJelJlViZRWkZZTlJRdj5dVl5FZkptPkJFXkJhbk5da +k5xclZpcjppXjZRYjJRVjJlYj5VVkpdWjplajpROi5lVj5pVkJpcj5pajZhZjpdZk5hZjZJV +ipFVi5JVjptSjJZZjpdXjJpYh5lTjJxajZ9WkZZWipxSi5VZjZpUk5hZjptZkppTjplZkZpe +k5Zol5pcmZ5XjpxXlJtZk5xclKBalp1cnKRcnKVflaVamJ1gmKBdm59jl6JVlKFhmKJZmJ1f +mqRRjoxfmaJPi6FRiplOiZhZkptalqBTl5tcl6RXkaBaj5pUjZdakJxYlp9akaFZkp9dk6Bd +kqNXkJtYkqNglp5cjqBRfYtKdIVHdX5Ea39PhIRTjJRajphNhJhHb4lOaGxmbF9mb11tc11u +e2VubWNnaF1WUVNMVEz0/7X///////////////////f////+//71//T8//b9//f///f///n/ +//35//P9//X///////z3//T2/+70//Pv/uzy/+zl/+Tw/+Py/fXi7drg8ODx//H8/fr9//v/ +//H+//v9/+/7//P+//L8/+/7//r+//Dy++Tw++v///v5/+v9//z////0/u70/O76//r+//39 +//v///////D5+vLt9+KEWGk3QDY8Pzo7RTlCPjk+Ojk7OTY1PjY0Ojk2PTMyQDQyNzg2PjIt +OzM1ODguOjM6OjcyOC47ODUuOy00PTMpPS89PzguPTE7OzgvOi48PTo6OzE4Ozg1PjE4PjUz +OTMzPTI2OzUyOzUxPjUuPTM1OTc6OjM1PDQ4OjEzOTI1OTUxPTUzOzYrOi48NjMsOjE7PDYp +PDFCQjo4QTdBQTw1QDk3PTA2ODYxOzE0OzQ0OjA1ODMzOy0wNjAzPC85OTEyPTA7PTI+OzY6 +PTM0OjU5PDA1PjUyOzE0OTMxOyswOzE2OS44PDkzODAzPDQ0PTQwPTM2PDEzPDU7PDsvNzU3 +OjoyPDE6PTYvPTU1PDg7PTM4OzM1OzQzPjM/PjY+QjdKRj09RTo9RDs2QjQ1PjQ5PDc+Rz1B +Qz05QjY3PzY7PzY6PDRCQDpAQzg2PTVEQThVSj1lU0FpUEB3XEaBakiKaUiHb02ceUywg1+9 +lWS+m2zFm23GnHDOpHbPqn3SqHjTqXnXqnjXrn3dtIPhu4rhtoDiuYXhtIvfsH/csILSq3fS +onPMkWzaqoTaqIPMl3rIlmjbpH/WpnXXpHzXqHjZpHrPl2zPl3fQoXLWp3req3TgsIHepXzX +mHbSjnDGjm69kmPPoXHTpXTVqHvLonPOnHe9iWiabFZDRTdBQD07Pzc/SDw2QzA2PjsvPDM6 +Pj03PTM0OzQ1Pzg0QC82QTw5REE7RkI8R0A4TDo8Skc+Skg+VUw8TkU/Xlk9b2RPe3pNh4tL +c3pCa25GaWhBXlpAWlo8U1JFaWFJb3FKdHlRiZFOjIpQhI1RhY1QhpNOjJFWjZZXjJRalJpc +jplPhpNRi5lWjZFUh5RXkZRdkaBVi5dclJxTipdcjJ9WlpNakJpakItZk5lXiJBVjZVSho1T +jJlalpVWko1akZZRjYxWj5lhlZJZjqFZipNYi5dXkJBWl5tdk5pakZ5ijZdYlZhikZlOkp1g +lJdViptZkJhZkZxTkZhTkpRWkJNRjJJPjJFXj5ZWkZJajZdRiI5WkJVUjpNYj5dXjpdak5lZ +jJhTiphSjJFVkJNclZVYkJhWj5JZj5hWjpxVjphUkZdclJxelqBbkpxbkJpfkpxWjpBbjZpU +k5VRiZxWkZBXkJ5UlJpcj5pOjJRSjplTkJFZj5hSi5RYjJhYj5tXkJtZk5tYkZhbjJVWk5ZZ +jphZlJpalKBbk5dYk5palJxXkpxelp9dlp1elKRalZlckKFSkZxalKBYlZ5il5tZlp5ZkqJT +iIZZkJxRiJVXiZRSkJlbmp9akp1UkZZflKBWlqJblZlWipZVkplfmqJblaBgk5xak5xdk59Y +lZ5dlKJWkZxbipxHgI5UeIdAcnpJcHhHf4JTgo9UjpRYiZpMe49LbHZkb1xnbFtnblZtalVu +c1ptcVxgYVVbXlbq+Kb9//n///j////9//v////////9//v///7///////7///v///T///// +///8//v5//L2/+36//H3//Dz/+vq/+Ts9Ovo/ejj/N3l7eHf7tns/Ob///z3+fDs/+Dt//Hx +/+70/e71+eby/ez8//n//f35//n//vTz//X+++71/PX///T4//L9//v9+/H2/u/r/+j5/+75 ++fX+//7///f59eiEWG1BRkA7Q0BERTo8RTs/Pzo0PjE1NjsuPDM7PTkzPzM4PjssPzI0OTow +NzYzOjg1ODM9PDc8OTQ0OTU0Ozc1Nzc2OTY3PzUzPTQ6PDQzODM5ODguNjA6PTcwOTU2Ojgt +OzM7OzgwPjA+OzkzNDI1PDszOTU3NzcwOi81OjgsOTA8ODgxODc1PTU0NjY1ODYwOzI0Ojg3 +PjY6PTo5Nzk0PDc0OjI4OjUuNi44OjoyODI7NjkwOzE9PDMwOjJBOzc3PjU9PTc7ODk/NjU3 +PTU0OjY2OTUzOzQ5NjgwOTU3ODUzPjU2PDU1PjU2PDAvOzYyPDM5Pjg7QTw1PTwzNzQ8Njo2 +OTQ4PTo2OzM3OTw1OjU2Ozk9PTc3Pjc+RDo7QT49QD09QDlDQjk6QDQ/Pjk4OTU+PTs1QDg2 +PTkzPTM8QTQ6OT04PjVBQzk8Ozg/PjpQSztjT0NqVkhsVEV7a0mOa02ScVabd1arhl+5lWS2 +kWrBn2TGmm7Jo2jNqHnOom7ZrXnRrH3aqoPVr33ctofdrYnjtIbar4Xaq3vLoHzHk23SpHvi +v5jozaTou5zQloDEkWbVq3TjrH/is4TgrIXbrn7Zo3XPoXXYpn7gsYbsza3tyKPmuYzltYrd +qYPRoHHFk23KqG/XqnbTpnvUoHjKm3a7jGyZaVdBPTs7QDY+PTg2PTQ4RDYxPTU0QD0vPTQ6 +OzsxOzg9PDowQDQ4PDw1Rjs9QkQ6SUc6RkA5TD5CTUdCUUZCU1JBVlJGa15CbnFLgoFEZ2lB +aGc+Y2M8aGI7X2NAXF9BcW1Ga3FRi5NWiZdSkpJSgZFLfohWh5RPh5JcjJlQjJhfkpZYkJZb +kJRVlZ1gjZpbkJpWlJ5VjJxVipJSi5xXlpVWlpxXkZRWjZlakJhXlJpZjJNRlZ1UkpZSlY5Y +lqBNkZZdj5tUk5hcjZ5Zk5VejqNRjphZj51bj5dYjZxYkppbkZ1ZkJRRjJRbj6BWlJpXkJ5b +i5lTjJFcjZtZjp1ajZVPj5hai5VLiZZdjpZRjJRai5VQjJBgkphVjZlcjZlVip1Xj5ZVjZhY +kJpVjJtakZhcj5tWj5tdkJxUlJtbiJVXk5tZkZxWkJxZkZVZlplajZVYkJpUj5dQjpRbi5JX +kpRflJpWkZdVi5dViJdUipVWkJ1Xj6JTip1bj5pYkplckp5WkpZYiplSjY5cjptZk5ZZkpdW +lpdblZ1ZlZhXkZ1TkJ5akJ9YkJlYkKBblppckp1YjpxPjZtYkZ5TlJ1cl6Bgm59bmaRYlJBX +lKJYi5pOkJZakJ9UkaBfkKRSjZRckaVVlaBkk6ZWkJpXipNZl55blJ9dlJtck6Jbl55ckaBZ +iZpUkJhUjZpRgpJIeYpEcH9BcXhMf4ZOiZFViZlTi5hViphLd4hacW5ib09sblhebU9kbVVj +b1NqaFx1fmLz/cL///z9//v9//v///////////r///z////9//f9//P////7/+/+//j3//Xw +/On2/u/y/ef0//L1/+X7//z6/+/q+uzm9N/a7tPe7dXg8Nri9Nz///j3//T9/vv1/PHu7er9 +/v7////+/+f0//Hz//H2//P///r+//n///3///f8/u3z//D5/+3q/+j5/u////3////u7OTx +++f1/u3u7tyNVWE8Qjk/QEE7PDU+QDo7QDg6Pj06PjM0OjM0OzE2NjY0NTY1OTEzOTY1NjIz +OjU0OTI1PDY1PTQxODI3ODQlODU1NjgyOjIyPTcyPzY+Ojg6OjQ3ODcoPDE6OzouPDFBOzkx +OzE4ODkxODE5OTMwPjQ3OTcuNjM0NDc4NzMqODczOjQ0ODg5ODM1OTU2PC8wODUuODE7Ojcw +OzQ5OjcvOzE2Nzc0NTI2OTYuOS40OTguNTM9OjU1OjE5Ojc8ODQ8PDU0PDY4OTU6ODc3OjA1 +OjIvOzE0OTIyODMzNjIxPDcyODM1OS8tOy83ODQyODQ7PTg7QzhCPj0zOjU3OTQpOjI9Njst +ODU+PjU2PTVGRTk4QTc1QDU8Pzk5QTU8QDw6QTs6PDc6PTg9QjY3QzM7OjdAQT0xOjE6Pjs0 +Oy9IQj82PDE3ODo5QTM+Pj44Oi9FPz1dSzhnUEdtUEN2XEOFaEmSc1Kie1WlhFq5jF69lWjC +k2/ClmvHmnDJonvLoW/SqHTPqHvUqYDSrnrarIfXq33YrHzMoHfGkWPGkWzdsIPpxZnvy57s +zKHoz5riuJnEh3jAmmzTr3fesYjiuoXnupHbp3zWqHvXrYHhv4rx67X32rTvzqXswJPjs4/Z +qHzJmXXIoGrZq4jYqXzVqX3QonzAkmqZallFRTg8Pz87Pjg6OzkzQTU5PTcyPTE2OjU3PDM2 +PDgtQDAyPTU5QDk1Q0A2PzsyRD49Rjw7RkFATUNAUUhAVEc9WVBDaGFCa2Y+a1tBYmI9Y2NG +a286Y1s8X1w8XE1MdHNMiI9Yi45QiIhSi49WjI9XjZpSi5JYkppXjZpXkJpZkZdZjKBXjpxZ +k5Zak55YkJNUmJlclZ5XlpRajJlPi5hXkaBRiphVi5lPjZVXjpdOjJRWiJhRkJNWkZxRkZNX +kZ5TkZddkppblJZikpJclp5gkJVXjZlWjplVkZpTjJRcjZhZjZVaiZBWjJtYjp9bk5tXj5VZ +j5tblJ9jkKJTjJdZjp1YjpJVi5NTlJhXjZhRj5FRjZVYkJhbk5pciZVZkZdakpVWjplaj5ZZ +lJhfkppXkpZWlphYj5hXkpxZkJNXj5JbjZdTjplfkZ5QjJlbk5ZUjppZjZJPjJZYj5VVjJxX +jplSk5lXkJZXi5tTjI9UiphVjJRUjZNSjJZYk5hSlJZWkJRVjZRWjZVUkZtXk5ZXlJ9Ykp1e +lJ5ZjptZkZ9ckZxblZ1gkZ1WkJpXlZpcmaFYk6FZkJ5bkZ1amKFTjpxYlZlelpxSi4xaj5tP +jJZSi5RTjZVbjp9ak59Wj5hUmJxhlqZajqNUi5pYkpxdlpxYl6Fak5xelp9TjpxUi5lXi5lU +jppPj5tQhJlLdYpDb3tAcnxFeoJRh5FTh5RZj5tNj5pXepVKbHBjZFBeZE5kY09jZU5dZU5b +Z1F0gl3s/7r+//v///////////////v///3///////////r///v////////////3//P///// +///////4+frs+dny/+f5//ns+eft/+jd9tbr8ePi7d7l6t3v/+jw9+n3/e////r+//v4//f/ +//b///j79fXp8efs/uTm8+Hx/enx/ub09+31/+78//Py+uf6+vL7//f4//D7//T+//v9+/Dq +7uLd4tSNVGk0QjhAPTs9QDlBOT03PjU9Pjo2OTY4OzU7ODYxPDc5Ozk2Ozg4PjU9ODY2NDg2 +PzUzPzc3OTUyOTQ1PDQwOjI6ODcwOzE6Ojs2Ozc8PDQ1PjA6PTcxPS4yOzo0PjM4PDkzOjU6 +Oi01OTUxPTU2PDg5PjgyPDM3OTUzODQ6OTM2NzU1OTQ0OjI3ODY0OjE7OzYuPTE7Pzg2OzU9 +PTcwNzFAPjctPTI3PDUxOjQ2PDAxODA1OTM8Pjg6PzI9OjY2PjM8PDY2PDU6PDc4Ojg5OzE0 +Ozc3PTg2OjkxPDI2Ojc2PTQ2PDg4Pi87Ojs2OjE5PzxBST47QTw7PzYyPjU3OzY0ODY+Ozg1 +PzlAPzo+Oj0+Ozs9QDc5PTc9PjhBPzc7Pjo5PDg8QTk+PjpGRTw8PTxCPjw4QDc/Pjk5PzlE +RTo1PTw1PDg6PTg9Rzc7OzlHQjpaTkBpWkR5WlB9XUh+XkeCck6jflupiVu+m2jApG/GoXS/ +mWrKmmzMpnTMpHTQpnvVo3zPoX7MpXHRpXrLpHTClmy/jGzMnnjdtILlwZXuy5ns0Kvvy6ju +xKXnv53gtJXHgXe0k2bKpHPUr33ctYzWrXnYrXzYs4Xdt4XnyYvtzpbrwZTkvpDmu4rfr4LK +nnLNnXTWsHrWqXzTp3rLoHfClGWOZVY8PzVCQDw9PjU8PTs2RzY8PDs4QTM7Pjs3QTA6QDw2 +QDU1Pjc8QTpASD84PDg5Rjk1RDo9Ukg8S0FCUUg+S0RKbmlBaHNEaV5Cam9DYWNCY2FAUlM7 +WlRBXl1AbGNUi5VLg5FYhpJMho1UjZNXjZNfio5XjppVl6BbkKBZjJpbk6BZkJpcmKBgmJtZ +jpZWjJNbk5pXj55WkplXjphVkpVYipJSjJRZjZNRkpRgk5lXjJNXjZlVj5lVkZpVi5hVkpZZ +ipNXkZlYj5ZakplbkZ1VkJFajptWjpZalpdZj5BglJdijppRk51bj5ZVipJYkppOjphlj5VW +iZZgkJFLkJFZj5BajJlekZlSlJFalJVXjpZYjpVWkJFZko5ajZdWkJNjlphbkJZYjJpZkZhZ +jJlUj51elZ1em6FemJ5ak5xZjplYkJlakZtZk5xWjpZbjZxZkp1Vj5xfj5dVj5VekJ9ckZZf +l5lWkJddj51QkZNZj5tVk5JWjphWjphXjZhRjZtXk5tZkptWjppZj5pbj5dWk5lblJdakpdX +jp1fm5tgl59fl55cl5xZlp5Ykp5Ymp9dmaJYm5tjmqdal59ekp5dl5phnKNUjopekJtUjJhW +jJpVk5lWlplXlZtaj5RgnZ1flqBemaNYkZ9Wkppcl55elZ1ckptck5tZkZpXkZlblJlXk5ld +lJ9XkZlReJJAcH9KcHxIgH9Xg5NTjZpYjZ9XkJ9dhp5FaIBbY1dfXktaYkxWXUxMVElWVUdc +bFLq/7T9//j+//j///////////////////////7////9//33//Xw/+X7//v+//r3//j1/+j9 +//b6+/T2+eT8//vq9+Tl+ODo/+ni+tTl+eD2/+vm8Nv///r9//7///f7//P1++X2//b6/+3y +//H+//j7//D29+zz9vH9/vz///z///////X0/+39//3///f1//T4+e7u/eT19+79//H4+/P9 +9+2IXmg7QTMxQjdDPDY1NzhDOTgtQDM5OjgoOTY+OTgyNzQzOS4zPDE0ODM2OzI2PS41OTcw +ODA5OjgoOTE1NDMsPS84NjU0OzM1NzM5NjU5OzAzOjI0MzM2PjIyOTU4PDM4OC8xNzI3OjEu +MjQ1NDUqNjMyOTEwOS04ODcwOS83NzU3NjI8MjguOS47ODUuOjI3MzQ0NjM8Ojs2ODY6NzQq +NzU3NTkxNzUzNzUzOzQ1NzU2OzAsOC86ODQyNzMzNTQ3ODkzODM9PTkzOjI3PjM2OTI5Nzcy +ODI3Njc0NzU7NjYvNjc6OTc1OTU6NTQ3PDo5Pzo4QDk3OzkzOjU3Ojg5NTw4NzQyPTQ6OTM8 +PTA6OTY5PzM8QDU2PzQ6OzczQDQ7PTc4OTJBOzk1OzVLQEA4QDhCRD0sOzVCOTw5QTVCPTs3 +QDg4OzE2ODQ1PDU6PDRAOzhJQD5eTT5tWz+BZEuDXkSBX0qLdEmrhVy3kWe5mGrBn2vClnHG +pXDRp33SqXDRp37UqnfPqYLPpnjBk3LDi2nOkWvZqIXYq37huIbpyJ/vzqLvz6jsy6nq0Jzs +yJ/oxKPkt5nKhH+0d120iGSzkWDBn23DnXDPq3bTr3zbtYnduIfitYnfuIjhtoXaq4LElXDG +nnXRom/PpHbKpnrEnHC3kGp/WlNBPjk8RTk5Pzk3Pzc4PzkyQDE4Ojk2NjU7Ozw3Qjg2Ozsy +PC82Pz87Pzg0Qj03QDo0Qz88R0E+Qz9ATUk+WE1BYFRAY1tFcHZFZ2lAV1g8TEY6VVU7WlJA +aWhOgolRhI9SgopQiZJQhJBOjJVajJRWjJ1UjJldkqFdkppSkZpXlJhZkp5Xiphdj5pak51j +jqNXk5pfkpxWlY5YjpRVjJhVi5NQjZJVjZlTjI9cj5xbjpFblZldlphakZtVi5pWi5ZSkJRZ +jpJWk5laj5lWj5RSj5pVj5ZVhpdTkpZZkJlOipZUiZdSjplcj5xRlZNgkJlPkJRYj5xWkJxg +jZtYjpZhkppVkZ5cjJpbi5lNjZhXjZxclJpbkppWjZZXjpVbjplYjZ5dkp1XjZdWkJRUkZJb +kpxXjphdkJpakJNejZlakZpdjpldkphZj5tUjJJej51ejZdakpdVjJVWkI5ckZdXjphbj5ZX +kJpbjJtWjZNakp1ckZdPjJZXjZhVkJldkZpZkZxajZlSkJhhkZlUj5pfkZtUjp5ejptdlqBe +lZZXmp5Xk55ZkaFalaFhkqRZlJ1ZjZpbl5xfk6Fcl5lelJ1Ykp1VlJhSjYxXiZ5WiZhNi5RS +j51Xj5xZlaFYkJtamaRdlpxZlaNXjJZWkZtfk51dkppWjplXjZlakJpRj5tdkaJUjJZXkJdV +i5lNfo1FcX5EcX5KfYRLg49Ui55WjppVl6NVh5tKcpBMX2FWWktVXVJSVEtGTElDR0ZRXk3n ++qj+//f///v///////////////////n///j///////////////z7//v6//v8/+/5/fP+//X7 +//Xz/urs+eXz/ur8/Pfn9+fa7s7l89zo9eLk79/m8+bj9eDn9ufx/v37//nx++vw9+rs8uXs +/Pf///7///////nu/+fy/uvy/+f9/vX7/fHy/+/7//P9//b8/ez+//vt8OT8/vH2/+/29OWb +WGo7QjY+QzU/QDk9QDYvOTU1NzkzQjc4Ozo1PjUxPTY6ODUzNjY2PDgwPDEzNjIoODI4OzIx +PTE+PTMtPTQ7OzMxPTU8PS85PDUtPTcyPTM0OzE0OjUyPjY3PjsrOTc5OzQ2PzIzODU3OjIz +PDMtNzUzODQ2NjctODM3OjYzNzI4PTczODAyOjczOjIzNjc4PTUzOjU1ODEtOzM/Nzg0NTQ3 +OTgwOjIxOjUsOiw4ODkwPTc6OzovOjI0OjIqOC8xPDI0OTc1Ozc0OjQzOzQzOTQ4PDY0OzUv +OjM1PjczPDc3PTY1QDUzPDQ6OzgxPzk7Pzs3PzU6ODsyPTc7OTo0OzY3OTUxODI5NzI2PzQ5 +PDU6QzU8Pzo2Qjk/Pjg2PTY6PTk9Pjo2QjVBRUBCQj0+PjhBSjo2Pzg1RDg8QzdBP0EyPTcy +OTQsPTI5Pzg2Pi0/PDY9RzhgR0NuWEB9ZUiQclKOaFF7Y0eliFa4jma/l2zDnHDBl3HEnG3K +pHTRpXLMpXTSrXvQpX7CmW/LlnnRrXbWq3nZuYXfvpboxZPw0bPy2rP21a7u1arwx6js0Jzr +zKbjwpDnv57cupbYsIzNj4K0b2Kge1WtjGTBmXTRq3fZroParn3ctIPYrYbMoXm6j2rEm3PL +kWvKnXXJmWu7jm6qfGFbRkBDPjwzQjk7Pzk1OS81Qzk1OjQ2Pzo2PDYzPjA1QDkzPTQ0PTws +PjM4QD02RTk6Qzo1Rzw3QjY7S0Q5SDw6SUU+VExEXlo/WE47U1A6YVpBXWY8W1Q/eXpJeXtO +hoxOgodLh4lYipRVjpZZj5dXlJpajp1dmZ9bkaFdk5lZk55ak5pXlJpcjZ1Tj5pak5dak5hX +ipJVkZtVk5ZVkZlcjY9PkJNVkJRSj5RVkZlWj5VZmJxZhpxPmJpZjZ9alZhglZpOkZVWkpha +kJdcj5hWlZZdjJ9Rk5hdhptRjpdYkqBck5VYjpRWkZZakZhYiZZYiZpakJZhkpZXk51bkZlV +kJtWj5pSjZZVjpNZk5hVjZhVj5Rbi51Sk5VVjplWkZpYj55Wko9gk5pVkZxcjZlPj5hdl5lh +kZhTkppVlp1bk5xbk51Vk5pXj5tXk5dUjZhXkppTj5VVlZ1Xk5ZbjZVPj5ZajJ1VlJpfkJ9V +j5hTjptakZldkJtVkZdTkp1Xk5xaj5dZkZpRkZpYlp5ZkZhTkZtakZxalp5fmaFckp1ekZ1U +kJ1akJ9ZlJ1bkqFYm6BjnKZUmqBilp9Wl6Bjm6FWl5xYlZ1WlKFWjYtUjaFQjJlWj55WlaBd +k51flaNelJ9ZmqNdmZ9XkqBYkZxUlaBWkZ1ShJlRiZJWj5pVjZVZk5tYkJZWkZ5ZkZ1WkKJR +fZZBc4JIc3tFfoRMhYdQh5lcj5xXkp9blJxPg5ZHVnM9SkJDSEdAR0BASENESkJDV0rp/6X9 +//L///////////z///////v///////////////v4//j7/+7////////////////////4//Xv +9uvw/uf8//nv/e/v/+7e9dTw/ejs8urj8Nz////////////2/+vx++n0/u/9//7///f9//nt +9+jx/Oz1+/H///7///////P3/vz///////b9//n4/+74//v5//n/9/X///X1/+z49O+wXGw7 +OzdAQTlDPztEODg2PD03QDk4PDdAPjorNzQ7OTgtODRBOzUsNTU7OjsyNzk2ODQ2OjZCclk9 +Pzs4PDI4PDEyOjQxOTc3ODU5Ozk3PTU5NjQuOTQ3Nzk3OzUyOzYyNDo6Ozo6Ozg5NjQ3OjU1 +ODI2OTc2OjE0OjgzNzI4OTowOTUyPDY2OzUzPjY3OTIzPC40PDYxOjM6NjcwNjAzODkwOTU0 +OjU0ODE0OjcxPDQ1OjQ9Ozg3Nzc4Ojo1Njg4NjY4Nz0/OjowNjg7PTQ6OTQ1OzU3OTM3OzE8 +Ojg2OjY+PUA3PTQ+PTkxPDQ9QDs7QDs+OzU0PzY+PTozPDY3OjgxOTE1NTI1ODg4QD02PDdB +PDg2QDo1Mzk0OTk3OTc4PTg7Nzg3PTNIP0JEQztFPUBIR0FEQkM2PDY/QTtDQ0E/N0ExOTg/ +OTozOztAPT09OzhBPzxWSD5xWUV4XkqIaE6MZEmEYUqXdFGujmC8l2nHnnLKoW/GlHPEl2zL +n3XOqXnPo4LAj2nNnnTTrX3Po3/MnGvXr4Xft4zlx5rnyZzo0bHnyZ/uzaTv0rXmwZTlw47o +wZDmwY3duIrWsYrQqILCmXHAmHeqcla3jWXAmW3NoHvMq3/RqYbFoXi1iWuujGO+jWrCjmjE +l3C8lG+zgGOJXVVIPTs6PDs0PDc5OTs1NjY0PTg2PDo3OjszPDo2QDUxQDc1PTY0QDsxPjQ6 +PkEzPTc4RT42Qjo1SkA8QDU8QUQ4Pjw7R0M+Ukg9V1BBUVQ+WlhAU1tCb21JdH9JfoRViJFS +i49Vi59alZlkk6Nfj55ZkqJbmaNak6hfl6BYj5ldjqBblp9Zk55TkZdfjppVi6BajZ1Yko5Y +i5NZjpNVkI9dj5ZRkpVaj5ZWjJVVipdXkJVhkqNTkpNilJ9bk5dbjaJUkZFYjplVkJVWkJpW +jo1amJJXjZpVlZ9TkJhgjZJYkplahJpSkpVakJ1gjphYkJZZlphhkaBVjZdglJhWj5ZYjZtS +kZZYiZhNjpNUhpVVjplbjptTkJVYjpdXip5gk5tfjJZVjJdWkZdWkZRejptVjZZUjplXi5da +kplijpxYkppYmJxakJVhkJlalJtclZpXjZNck59OjJFTjJhTi5hakptXjZNYjZlZlJhaj6Ff +lKJakpxXi5lVj5dZkZpVkpZemJlXkphWjplXj5lakZxZjptXkppgkJ1XlJ5hkKFXj5hikJ1T +k5thk51Uj5tdkZxVk59ek59ZlJxZkKBTkpxWkJxZjZ5clp9VioxRipZOgpNRjpVXkqJZlJ1e +l6Zak6Rcl5tYj55WkZtXjaNZlp9RiZ9OiI9Qh5NUh5dWjZtWippZmJxZkJ9Vk55bjJtOhJVL +b4FAdXZOe4JMhI1ViZdQj5xWkp5dmKJZhZ9DWnw/PkZAQkI9QD0+REFARjtHUUvn+az///// +//////////z///3///////////////r///z///////////n///z///v6//P4//P6/+75//P1 +/OXx/u7z/+zl++Xg/dfq+ebv+ubv/Ovx+ejr/u36//jx/evs+Ojl+OX6//fz+ejz8+z+/vf/ +//n1/+z1/+/y/e79//z5/ffs/Ojz/+38/fn59/L/+e7y9ent8+Px/uj9//zu8uOcX2k5QTlI +Q0BJQjtEPUQ2PS46PTw5Py86OjouOTA8Ojk4PTc1ODU0NjYzPTU8OzkyODc4OjU6Ozk2OTU2 +Ni81ODs8PDU5ODY+PDQuPDY/OzY3PDU5OzkzQDQ+OToxODY9NDg1OTQ6OzE0PTU9OjUxPjQ2 +PDQ6ODczOjQ3ODU1PjY+NzcxOzQ+OjoxPjY5ODo2PDg3OzM3Ozo4NzE0Nzc0PTAyNDw2NzQ5 +Ojo3ODA4OTo8PzJCRD0/OzMzOjU8OzY4Pzc9QDQ4OjU7OTUwOTQ3ODgzOjY3OTUzOjM1OTY3 +PDc8PD43Nzo6PTk5OzVARzs4Pjg6OTY3ODg8Pz44OjYyODY7PjYzOjc5ODQ8QDo1PTVBOjs0 +OjY7PDg0ODg/PDc1PTNAPDo7QTdIRjo9Pj5EQjhCRT1DQjg6QjdCQDk/QT08PzUyOjU2PDQ7 +Oz9APThCPjtHRDhKRzhrVUh5YUaMcFGde1iccleObkmog123ll/DoXLInW3Fm3LIonDUo3fL +oXLJj2/GlmzSpHnNpm7Op3bUqnvYr37cuoPat4bdsoTes4DgvIjo1abt2Kbtz57txZbrvpbk +vobku4zUpHjHmW+/kmqyfWeph2Cri2eykmO2k2yujmOigGKEZU6deFaqgWOzhF6/iWS5g2mt +gGWVblRfR0RAPTk3PT06QDg2Nzc6Ojc1QTk3ODo1Nzg+Pj0yPDE6OjsxPjU8QTw1PjU8Pjw0 +QDxAR0E6RUAyPzw8REg4Qjs5QT06Sz1CXmFAWVdAWFtBYGU/YGZHbWdGd31RiJhXj5lglp9e +mJtfk6VYjpxckZxalZpclKBckZJai5VXkJZSjJpZlJxZk5ZZlpRYk5lYlZpTio5akZtYi5lZ +j5lRiY1WiphZkpZZkpdXkplblJxYjZlVk5tdmZRZjJhhlZJWj6FgkZdQkJdUkpZZj5dYiZNW +jJlWjJJVjpxRkJZjjptTkKBYjppUjZVhkphRj5JbipRPiIxWipRckZlakJ1Wi5FakpVajZpW +iJVZiZJRi5VYjZdWjZZUj51ckpZYk5lhkJtVk5ldkZpdk5pVjZZakZdXjZhakppfl6BXkZlV +lZ1XkJdXkZ1VlJpakZtVkplgj5lYk5pZkppYl5pglpxaj5tVkJpekJpXkp1alp1hkZ5ckJta +kZpZj5hXk5xakpdekp1SjpRfj5lVj5hhl5lWlJhbjptalJlil6BdlZ1bk55TkJxbl6RXkp5a +k5xdmKFZmKBakZ9bkZtdlp9alJ5akpxXjZlXkptflZ9UkIxWi55NgZVUjJVPi5ldj5xUjpxd +jphXkppekZ1YkZxekp5PjJpOf5RQh45VjZdQiphVj5dclZ9Wkp5ZkJxTj5pakJdNh5dEcoRF +cXxGd3xRgI1VjJFZj5xekpxhlKJXi5tGbZE9QlU/Q0Q9Qzc4REBBRj9FVEXw/6j///z8//v7 +//b////6//T9//T+///7//b+//T////z//Dz/un5//D6//T6//j6//n2+vH6//H////v++3w ++Ojp9+bw/+rd89fh99vn9eTb6tP///nt+ev1/vH8//P9//X9//b7/eXw/Of4//j5//P7//n5 +9+nx8un1++fx/vH+//n1//X9//z///////3//////////f/9//X3/eni49agW2w2QDtESkBN +RjxEQjo7QTQ8QDMyRzQ2OzY1NTMzNzEzOTU3OjYtPS80PjcxOjg2NC01OTY1PjcsPzcyPDc5 +OTY6OzQxOjA1OzUuODE9Ojg1Oi8yODYzPi45OjkwOjI6ODQpPzIzNzU3NjM4PTMwOzQ4ODY0 +PTIxNzQ3ODY1OzY2PDQzOTozOTI2NDM1OTI3OzUyOTU5OjQyODM4PDcwOjJFODw4PTM7PjY1 +OzI9RTk7QTJBQDc0PjM6Pjc9PjM5PzQ6Pzc5QC8+PjY3ODQ0OTQrOjUxOS8zOjA1PTQ3PTg4 +QDQ2QDUzPDA4QDk4PDM+Pj0vPTI+OTkuPTY5OTgyNzY3OTIsPzY4PTU4Pjg3OzY2PDQ1OTU0 +NjM5NzUzPTEzPTE8PzI6QDlDQjlBSD5BSD1FQD06PTQ/Qj42PDRBQTs5PTc5ODs6PS06PTk8 +PTNBRD5NRTdKRz9nV0NwXkaJa0yYdFagfFiQbU6aelSylWPHoW7EoGrFm23NpXHQp3rOpHXE +lGnQqnnKpXXDom2+o3DPr3vMsHzOsH/Pq3zWsoHYt4bkwpHo0KDs2K/r0KrqyZ3sx5/lwo3j +uIzbr3vToXnIlGq/hWWobVuQbVCIblKBZUp5XUZ8WEWbcU+uh2Ghelyge1mpf1qgeleQblRu +WEVDPz47PDw2PzE5ODk2Py01PDY0QjQ2PTwyPjA0Ozk2PDE1PD4zPjU2PzY1PzU1QT01QTM4 +Pj04Qzo2QDk5SD45S0E8R0A5T0I+Y148YFM9cWlCbGs9ZGNJc3ZPhYxbkplakpldk6ZZlple +k6RblJpek5tYl5xZkKFakpldj5Zak5pZlKBajZRTjJRPjZVTiYlWipVZj5ZXjZNak5lZi5JW +jpZblJpgkppXjpJckp5TmJdYj5hTi5dajpxPjZFWj5pLjZpgjZ1SkpdXk5VZj5VakZVZkphS +i5JZjZlWj5VVk5hWj5JYiphZlpZZkp1akpVXk5xajZdbipBdjp5YkZhdkptPjJJZkJtVk5VZ +jJxRlZNaj5dWlZRcj5hTjpBRj5hXkZpXlZphlZdckppZkppVk5RZlJtYkJxgjptYkJZTkZlZ +kppXkqNdlqJVkptflKNVlJtgk59SkJlhkptYkZ9ekppUjppclJRXkZpZk5pflZ9ZlZhZk5xW +mZtZk51XlJZdkJtUkZ1ckZpUlJpYk5dalJtak5tdmp5Tl5tdlJxbk5tem6Rdl59cmJ9glJ5Y +lZ9Xkp5ZlqRgmKFaoKRbmqBZl6FWk59Tk5lgmaFTjotXiqBHgpROipZQkJlWjJtXlZpcj5pa +lqBakZ5WmKBYjZlSipdMf49TiI5ajZhXi5lSjpxYlZ9YjJ5ZkppYkptWjppXjJdEc4lJcnhH +fH9PhI9Pi5Zaj59WlJlekJ9UjJ9Sd5U/UW9DQ0E9RUBDSD8/R0NNUUbd+qD1/+r6//T///// +//////////////////3///////////r///////////////////n4/ez///z5//bx/+r5//Lx +/+/n+erP68fq+eXj8N7f6tXt/eb0/fDy//fx//T3//v///by/fL1/ens/OH59PHz9urx+/f/ +//7///////n9/vPy//v////t++fz/u/5//f6//Px+ez+//v9//Ty+ee4YW9AQD48ST9JR0dE +RkI/Pjw/QzxCPkEvPTc7Pz8zPzY6OD4zOTM6Ojs0OjI7OT4uOTE8Ojo3OjM6OzwzPjUwOjc5 +NzQ1PTc6PjcuPTc0NzI2Ozk4PDcxOzIzODc7OTY0ODc+PDYyOTU7OjUyOy85OjksOjE6ODgq +OTY+NjgtNzU4OToxPjg6PDI1NjU0PTQ5PDo7QTw7QDlASTk6Qjc2PjhBQTpAPDg+PTg5PTk+ +PjlDRkBAQztHRUI6QzZBQTo6PzE/QTlBQDY9QDs8PDE6PTk7PDQxPTY1ODQvPTU8PDg1Ozc8 +PTgvOzI9PzszPzk6PzwzQDc8QTk2Ojo0ODY1Ozo2OzE1PjczOTg5QTkyOjY5QjQ2PTk8NzY2 +Ozc3Ojg4ODk5QDY8OTs8PjRCQjs8RTdEPDw3QDpBQD48QjhBQj40PTs5Nzc6QDk+OjVAQTxH +PztEQTpSRTtZTz9xVkiAYk2ceFGogV2ecVWPblGpkV3EnHHClXDBmGzMqHPSqnzUpn7Jmm7S +oHTInGire2OKaU6LaVGQa1GVbVCaeFimgmWsimS/k3LGr3bYw5LgvZPfwI/kwJDiwIvgs4Hj +tobcqH3TnHHPmm7LnHHGlGe+iGKqc1WgbFScdlKqf1iohmKjeVuddFeYc1yMbE5xVklNQTw9 +Pzk7PjY4Ozk2PDk7OTcwOzY3QjovOzcyPDczPTQ5OToyOzk6PDozPDk2OzswPjk5PTw0Pjw8 +PT03QTdARUI3RT5AQzw1S0dDVVc5WVdGZmZDa25If4JOhoxWk5pYkZ9blZ5bmKdakZxil6Fe +l59ckaFXj51XjJpYjphTjZRUiJ1Si5ZVipZUkJZglaBXj5Nbj5NcipVYk51Xj5hXlJxai5lV +kZxakplYlppakaJckKBakJlalJtjlaBYkJhalp5amp9WkJpgjppWkJ5ai49UkZdgkptRjJpZ +kZJOkJhgkZdWi5ddkaJdipxYjJVYkJlTiZJWkZFdiZlYiZxQkZtXjZxdlJthkaJXj5dYj5lR +kZpajpZTkpVZi5ZXi5ZZkJpekpVek5Zekp1el59cjp9ekZdTjZlaipVWmZdakJlSkJpcjppT +lJZZlZ5WlZ9cl59alJhek6Bck5pcjpxVjZZbjZlUkppZk5lZjJhZkptYkZ1flJ1akZxflJxb +kp9dlKBZkJ5ek5xakZ1dl6BZl5tfk59clZ5glaNVmKJXlJ5cnKFik6ZYmJ9jmadcl6Bfl6da +lqBklqRZkZdfl6JcmqtalahTkaNalJthlaBXi4pYjqBPhpdIiJVXkJ5ckaFVkp1Xi5delZtW +l6FcjZxUjZpTgpZHgYhVjJhQj5ZXiphMjJdflaFUjZxYjZhbkZtbjZ5Ph5hJdodHdX5JdYBM +gY9XkphakKFdlKZfkqJXkaFQgpZFYoM/SUdBRUc9RD1HSEJVWUjp+Kn+//n////////////6 +//P////////////////////////7//T////7//r5/+zz/PL5//D8//3y+e74//H1//P5/fDq ++ent/eDq9eXp8uLm8OH///7x9eTq8N7q9eby++b1/uv5/+7+//H8//r+//v///b7//n9//T/ +//77//b++/f0/+30//X///z7//ju+ufl8+T08u/+//35+evt8eO3X2o1QDpDRz5DR0RIRkFJ +RUNNSDpJRkBEQD0/PT01PzU/Ojo6OjdBPTk0Ozk0Pzc3Ojc2OTc6Pjk4OTgwPDU5OTY6ODY6 +OzU2PDc4PTY/Pjs2OzU2OTw4PjQ3PTg1OTUzOjY/PjoyNjU6OjUsOTE1OjgzQDI9OzkyPzM1 +PDYwQDQ6QDcvPTMzPTcwOjI9QTdNUUJbUkdcW0VcXUpYTEFJRj1FQjw/Pzo0PjI6PTc7QjhH +SD9NRzxLSD1DRzdIQj8+QzNCPTk9QDdAPzc/QDVCQDk4RDJBOjkzPzM3PDw0QjQ/Ozg4PjQ8 +QDc6Pzw3PDM4PDs4QDY6Ojw0OjkxODU0ODg4PDE2PjA1PDQ4OjwyOzI8OzkzOjM8PT0wOjc8 +Ojk2PzA/PjwxOTRDPT85PjhHPz4+QTo6OzhCPz0/QDo/RD48PTg4ODc9QUA6PjpCPDpKQzlG +RD5STD5hUUJuVz6IcVGaeFSrgGGleVWadF2ulF/EonfBmWrElm/Lom7VrX/TpHrMpXDRqHjQ +p3vHiHOQeFemmWLLr4u0fmW+jGi+h2q3d1ixdFq2fmO5imfAlHDInXbVpH3OnnnRknDNmW3Q +m27OnWrVoXTNmG7JmWzBj2y4gF6eb1eUeFWgeFqhfFayh16idVqNZlZuW0pLRT0+PTo6PjU8 +Ozw3Pjc5Ozo5PjM1PD42QTQ2Pzs6Ozs2QT02PTA2Ojs6OzgyPTo3Pjk3QDs1Pzs3QDU6Pjs2 +QDw/Q0Q9RT08TUU/UEQ/UUs8YmBCcHRPe3tUj5RfkKBelqhdlppamKNhl6ZckaZhlp5al6Jh +lJlel6Bgkp9cl5palJZajZdVk5pclJ9WkZpgkpxVjpRekpdakpJZj5lTkpVakJ9YlJlfkqBa +k5lbmJpfmphXmKFakpxfl6BamKNgkZdakZpdkZlalZ1YkJBYlpdalZZTkpZfkJZZkJldl5pZ +ippXjJpSkZtliqJSi5hckppVkZdfkJpQiZlckppakJxakZhhj6FZj5VdlZlajZxajZ9Zkppa +kJxilJ9Vkpphj5ZWkJhfj5lVk5delZ5Yk5ZilKBcjpldlZ1Vk5pajZ1XlJVck6BYk55ik59a +l51em55elZxgk51ikpxelZ5aiplXlp9ak51fkZpZkp5ek55gl5tekJtalKFakZtXlp1ekp5W +lp1ilqBTlp5hk5dWk5tck5lRkZtakJ5fkpxdmJ5flp1cn51hm6Ndm5xcmJ5Skptbm6Nen6Vd +k6Jemp9ZmZxcmqZdlZlYj51clplcmqlWjopXjJ9Ng49Ih5VYlJVckaFckp5Zj5phlaJaj6Fe +j6FTj5hPgZJKgohajpdXj5ZVjJZaj5pYkZ5Zk51ViZpXjppYi5xRhZRLd4hKd4JMeoFRioxZ +kJtclJ5WmaVkmKBWi6RVhplLeJFSbG5XX2NITUhPUUZaXUvt/a7////////+//v+//f///// +///9//v////3//T3/+32//X9/+/////////////////////6//z7//H2/Pb1/+71//Ty//Lm ++9zn9ubm8uPi89rz/+76//z9+e76/vv18+z3/Pv5/ff+//z///3x/+////n///Ty/O3t++jr +7+f9/vr////z9+zy/vH9//v1/+7+//n///75/+/4//H28Oe3WWk8QTxDSD1KR0FGRzk/Rj1I +RT9DQUFNSEE6QjZFQzczPDc9PDMyPDU8OzEzOjY5NDI4PDU1OzE6OjQxPDI5OTc8PTc7PDky +Oi87NzUzOTE9Nzg0OTMzODM2PTQzODI6OjU4OzQ0Nzc1OTM3OzYxOzQ4Pjc3OTQzPTc0PTEw +OjU2Ozk3OzY7QTpITDd6YEWGZEl7WUppUkFnVUheUj9eSz5TSjlMSTc9QDg/QDM+QjdIQzlI +SDxKQT5EQzpFPjlAQDU7PjtEPzg8PTVCPjg9Pjk8PjQ8OzU4OzA4OjY9NzRAPT41OTE8Pzk1 +PjY8PTozPTU+OzIyPzY2OjUuOzY3PDYuOy81Oy84ODk5ODQ1PDY4PDM1ODUwOTY0OTI2OzQ5 +PDc4Ojg0PDY8OzYzPTFBPz41PDU8Pjc+QTpCQD46PDZAPjsvOTQ9PTc3QThARDdNSDlLPz1O +RD1fTUBsVkKEaEicdlqhgFmmfFiYdVOskl7En2/GmmvGnXPJoWfVsn7VqXzTo3HRpHLbroDe +r360dnCkoWHVxqLEpX/TuYrKl3vJk2zRoHXmx5j10sbamYi/f2O1fly9hWi/h2fEimzEhGi+ +fWLAg2S4eFy5f2GrfFWse1qbd1KZc12felm3jWDEnHWpdVx9XkpURz5AQD06OzQ8Pjw1OzU3 +PjQyPDU4PDkzPTM0Pjc2PjM0Pz01PDQ0NzA2Ozk0OTU8PjwyPzQ4Pj00QjY7P0Y7QTg3QEA1 +OzY3Qz87R0M/VU5CW1c8ampGcnRGfHxWh4pajZZfkJxVi5NZkJpXjpFYk5tdjpdZkJZbjJNY +kZlZjpRZjZRej4xSiZBXiI5SiZJajJBVipZZhYJYh4pViItXiJJTiJBXipJOjIlZjpJVi49b +kZFXkpddk5RVkpRajptVkZJaiZBUipZXj5hZjZFSjptWjI5el5NVjJNckZZXjZlgjpNVj55d +j5dYkpdjjZZSjJRai5tVjphZi5pUkppRkJtVjZlckJxZk5VZjZRWkpdakJhakZtYjZdTj5NY +k5lUjZVYj5lbkZRVjpVZjZlelppZiZpZi5pVkpZckZpakZpXj5hYlZpgkJxXlphcmZtamp1i +mKRblJ5dlJxbkZhbk5pWkppck51VkZZbk55alJpakplZjZZak5hWk5pak59fkppbk5hckJdb +lZhYlJpelJhXkZlbjptWkJhbkJtUlJlklZ1VkJtblaBblZphlKNXkZtgk6Fbm6NhmaBek6Fb +mKJcmadZkKJZkJ9Uiptbj5hcmKFUjo5YjaBSgJ5Jgo5Xjp1XkqFdl6FakaRalJ1Tj5tclJ1a +jp9OfotMg45VjpRUi6BVipdVjJddjZxRjZpYiJZOjJlZjZxPhZFMeYtDc3xNfoZNhJFYjJlT +jpdamqZbjZxaj59XjZ1PeJNUbH5faGdSUVZLS0ViY1Dp/rP///r////7//z////////9//n8 +//T///z///z///////////b///r///X9//n7/vj6//H6//Ty//L1/+ru+/Pi9Nzd8trc9s34 +//Dv8une59ru/O70/e/+//fx/+vz/+/x+uXu/+z1/+36//X09evz/+vt/er8//r7/vX5//b8 +//f9//D6//b0/er0/+/1/vH+//Pv8Ojz9+7z+Onp9Nq4Y2tBRTtHTEBFREJJPj5DSUBEQEJK +SD1ERDxLSEBART89Pzg2QDg2PzkyPDYzNTUrPC06OTo1PTQ9Pjg1PDJAQDo1PC4+PDg6OzI8 +PDk2PDQ1PTUyOTUzQTU4PTovPDc1PjQ6QTc0Ozg1PTU1Ozg2PTcyQDQ2PTY3PjQ5OTk7QjRk +UECGbUepg1atiGC4jGexjGu5jWqqflioe1aYakx9Y0WBYkB2XkFlUT9RSzpOQztGRjtKRDlF +RTlKRjpEQztDQDY+QDc9PzdBPzw5Qi89QDk6OTI3Pjg4PzA3Pzk6PjI1QDc4PzE5PzU6Ozg4 +Pjs9PTkzOjE7OTc1PDQzODY1OzU3OTQzPjM8PDgwPTI4OTM0OjIyOTEyOTUzOjI2PzAyPS85 +OzY2Pzk5PTAyQTM3PTg4Ojs4PTY9PT03OzY6QDg1PjQ1OTcxQTFCPDpBRTZQREBLST1URz1k +U0NoTjt4X0yceVOdelephVqcbVWpkFnFpnPInW3Go3HMqnTYsX3ZqX7Nqnfaq3zas3nmwova +sJDAiGqVhWSZkmPWzJXYsZHVsnjt0p3w3J768Mb338XproberYLWnH/AgGS6e2W6fWW6hmm1 +d12qdlimd1mcb1OPZ0qJZ0isi17DnXDUuYvInHKTbFZVRUw3QDU8Pjw0Pi48OjkvPTA9Ozk0 +PTU2QDsxOTE5QDk0OzMxPDw1OjozOS82PTQzPTE1OzEyPjszOzkzQzY1QDc6Qz0zQDw3PkAz +Rjg7SUU1UkpBXVg+c2lLbnFCd3hWg4hTk5FZj45SjZRcj45YjpNTi4xZi5NbjpRakJZSjpdX +lZtSiZJWiI5UhYxNiI9PiIhTiJJUg5NSg4pSfYdJhIhTjpROipBTiZJSkIpUiJFOioxYkplR +kZBajJlVjZNRjZRXi5ZLjY5Ri5JPko5LgolShotOiIpSg4tQi4lLgohLhI9ShYxJgItYjYtL +jZFZgo9OhZBWh5FSiYxVi5JVi5dRiZNRipNdi5JXj5JLh5BViI5Qio5NhotPg4ZViIlMhYtX +gotLiIlWgYlKgYZQfodPfYFKfotPfYVNg4ZLf4VSgZBQg4VSgIVUfoRUhIBXiYxUi4pZjo1Z +kJhZl5xei5ZSjpJalJZTkZdYkZVTkZVZiZdTmZtdl55Zk5xalJ9bmp1dkqBbl5takplYkp1c +lKBUl5lek51alZ1bk6JfmJ9blp9bnqJglZtZk5xakp9WlJ1clKBcl6Fel6JblpxdlKBalp1j +naNZmKFekaBSjZJYkp5TkJxSjI1ZkZ9NgZdKgo5QkJNakZ1hk6BVjJ1SjplTjplclZpWh5NM +fIhNhYhYjJVQjZdWjJFRjZZTiZdRiZhViJNJj5Fcj59PiZVQeoNBbXdLfYFRhYpYlJpZj5lc +lp5ZlKNXk6RYjaFTf5JOan1YcmdgXGNNTk5cWE3j/6b///j///////////////f///////3/ +//////z////8//z+//j///b8//n1/+7w/+78//nw+/Pu++X6//T7//n8//vs+Ozf8tTh7N3f +9dvl7uP///328+fs9un6//P+//7///n2//b2++vv/PT2/fP1+fD7/vX4//b///7+//n5+evw +/fL6//z7//L7//v///ny/ejt9ur+//v+//j///LUZ3I5PTdBRkBDQTc/PjZDQDxJSD1KQzpO +SD9LQj9OR0NESD5DQjs4PTo5PDYxOjg0Oy8vOThAPTk3OTc6PDUyPTU/Ozk5PzU9PTo0NTM7 +OTc0OTA6OjU1OTE8OzU3PzQ0OTg2PDA1NDU2OzA5OjUrPDM5Ojk9ODYzOztbUj2Vck2kf161 +jGi4jmnFlHXDlnHFkXPCnXLDm3mwjmq+km6thGOtgFube1GcdFmRbk2Jakh3WkBnSzxIRjdG +PzlDPTlCPzhCPjlAPzY7PDY4PjA5PTY5OTM3OjQ6PTc2OjNANzk9QDk+PDw4OzM/PDk8PjM+ +NzgyOzU9OjY0OzU/OjkzODY+ODc7PDNAPDg3OTU3NzY3OTIxOy8zPDQ3OjU4ODU1Pjk3OjU5 +PDY5OjY4Ozg8Ojc5PDs3PDQ/Ozo2OjM/PD00NjQ6Ozo6PS8/PEA7PjVKSEBSTT9WUT9oWURj +TkN0XEiQc1KhfVqkfVWcaVOlh1HFo3HJpHLKonLKoXDVrHfaqn7OoG7Xq37VtHvlwYzmxI7f +qYjEiWqqhm2wq3u2p3bf0JTy46ju06vktIbz3qn21azrtpflv5HsvZTao3nSjW3JhGy6b1+l +Z0+OV0V1UUWIXkm8l2bLpHHXupHVsH2lgW1ZR0NBQUE2OzM1PTk4NTQ2OzM1NDY4Pjc6ODg1 +OjM6PDgxPzQ5Njs1Oi83Pj43OzQ2Ozw3PDE3PDY6OTU9Pzw2QDc3Ozc+Qjs5Ojw9QD47Pj87 +SEM6V1Q+Y2REbnBDdHRMe4VOh4lTjZJSiZFZjJdWjY5ai5lOho1ThZRSjJFYh5dNiY1Si5dR +hYpXgZNTiodVipNSipJUg5ZPiY1WkI1XiZNVipJPi5VVkZlZi49TfopPiY9VjI1Mi49Vh41X +jYtRiI9PhY1TkJFMjIpSg5JOipFVjI9LkZZVkZFWio1WiJZYjI1SjJZUj51RhYtRhY1SipFO +iZFViZFSiJVViJJRkJdQgZJRh5NaipROjZBUj5JPiJBSgZJMfYVTgJFMhpFRhJRPio9Qfo1P +g4pUhoxKfItSg5JXg4tMg4tNfYpRg4pNf4lQfoJOfYlOgIdQf5FSg4xRgotSfolVfodWioxP +iYxah49Kh41YhIxEfoxUg49Pgo5Rho9OfodPg4xSfYtXh4xVgY1SgohUgYZThoNZiY1WjY1c +jY5TiI9Wh45SiItcjIlTio1ZkpFYlJpfkJZXjZdak5temKBbmKJhk6NZlplgmqJnoaVhoKNh +kJ9Tk51blZ9Ylp9bk55OiYlci55JgpRHfotWkZJci5xZlJtbiZlVk5VWjJpdk59Ug5VMfYRS +g5FSiZNZipRXiZhQi5FUiZVUiZpOhZJXhphYj5lUgpNIdIJHbYFFf4JWiJNSjJVakqFVkp5g +kKFYmaBbkZ5NhZ1KcYxOWmNWVFBQT01gWlDR86D5/+/9//v///////v///////////7///// +//7///j///r///v///////////z///z////9//b////7//n8//bw/vLy/+vi/NTq8+Xg5trW +5dTk/+Pz/vX9//7////0//T+//38//b///76//n///7///////Pp8ubu+ev7//j///7//fH4 +/e/8//f7//j6//v////5+fT4/Ovx9ejt6d28ZXFLRTw9QT9FPzw7Pj0/QTs/QDtERD5FQ0BF +SD1JRUNKQ0RKRD1CRjo/Pzs3QDc8Ozg2PTU1PDw6QDc3OzUyOzY2PTU8ODk4NTU4Ozc2OzUx +OjUzOzc1Pzw7OzU4OTY5QDM1PTY6OTYzPTU6ODYyPDc6Ojs+SDh9akqefFGxkGzAnXTIp37L +nnbBjmvEmXbLoXjGl3LEnni/nXrGmXe4i3KwkHG2i221i2iqgF+ohlqefFmbb1OMbUhzV0BI +PzhFQjs6PTc5OzU3PjI6ODs2PDM7Nzg4RDZBPDo5PDU8QTo2PTc7PDg3Ozg4Pzo4Pj43PDQ3 +PDYwNzQ6PDY2PDM1OjQ1NzI8PzY6NTgvPTU4OTUrPS83NzgrPDI7ODQtOjM8ODYvOjQ9Ojcz +OjVAOzkxQDQ5OzM4Ozg7PjUzNTc3OTc1OTcwOjM3NTU7Qjo9PjpHQj5MRkJbU0FuXktxVkVx +WEiHdFSWdVCjel+afVGnhF7DomrGpHfKoXDJpXbVsXrXsX7TqXvatYLeu4nfv4rdvYjfv47X +pIfHj3WpfGOUeVLSzY7v3KHnz53o2pj598386cnvxZv46Lj2473rvarbrITgs4jOm3jGkXSh +almbaUS7m2DFp3rZvIPXvYa3kXRnUE1FPz82Pjc0PDgzQDQ0OTY1PDAzOTE1OTo1OS84ODox +PDc4QDkyPDE2Ozo4NjY1OzozOjUzPzQ2Ojs2PDk2OTsyQjY1OTs2QDk8Pz86Rjg+R0U6TUU4 +S08+VkxCZmZFg4pMgYVLhoxJiY9Ui49PiZhWkJVTkptXiZJSj59XiplTjJhNgY1XipxQh5NR +h5hQipNSiY9PiYxTio1QiYxViJFVkohZjqVMkpZTjZhXj5lTippVjZdRjZpPkIlRipdRi4pR +hpNJiZJLfYhMgYpLgYNOf4tVfYlIfYdTfYFKgopLg45GeIRMfJBIgIdNfolJf31NfItLg4NU +hZNEgIZZg4pKfolWgI1JhopRiZJRgIxQg4hSh49Kho5Rf41KgYtQhZBLgolPgYZVgoRUh4xN +hopNfIZPfYBKgH1SgIhNfoZViIxIhYxUiI1WholXj5VWkZBXj5ZVipBVj5ZZipNSjZdNi5VN +i5RNipVMi41YjpJRi5RRiZdUj5hQjpVTh5FLg5JNg45Qg5BUfIpIfYdQfodDfYlOe4dHe4NW +fYZJgotQgolPhItQh5BPho9SipFSgJBTioxXio9IiJFUiY1Qi4xbk5RcmJpbmJlbmZ1jm6Jd +kaNYjJlbkqNZlJxTjYlYj5lSiJdKfYdRiZdZjphWj55Wi5RNjpVViZlRi5tJfZRFfIhJhJBN +ho9ViphPjpZbj51Sj51ShphMjJFRiJhVkpRThZVDcINHcXpNe4dMiJVTj5pYkaFXkZlWjp9Y +kaFXj55Vj6RMeJRKWGtMTkxNT0lYWlDT/6n///v///3///n7//n///////7///3///////7/ +///////9//z6/+/9///////5//r3++n5//P5//fi8+Pi89zp+ubp/ObU7tDs/ODu/+zx+uv0 +//L9//z5+e/v9evt8ebq++/y9ejs9uTz/uzx9uz0+Oj+/vr///////37//X09ez///7///// +///3+/L6/erz//b9//j///f4/e718efTbXJBQ0c2PT1EREI8QTo8Pj08PzlAPD8/RDpFQEFE +QT1FQkNLSEJNR0ZLSEJFRD9BQT1CPzw8PDk3OTo7Ozo3OjE1Ozk8NDc5OjU6OT43PTc9OTk3 +NzQ9PTs2OTc7ODw7Ojc7OjwzPzQ/ODkzNzdEOj1HTjuBZkufeVSogmK1imi+k3XAlHfMronP +mXrAl3TSoIHQqYPGmHfClHfLp3/FmXmyj3DAnHq/lnS3i26yiWq2iGeniGCojmiVel5+XUlU +TTtGPj08PDZBOjg+PTw9PDo4Qjo3QTc9Pzo7PTw8PDg/PDxAPD4/OTs+PDw8PD84Pjg8OTs2 +Pjc6OD0yODg9OT4tOjQ+PjwyODs/OT04Ozg+OTo0PDM9ODg+NzM3Pjk7OjU7OTY4Ojo0Ojo6 +ODw7Ozw6PDs3NUE7Ozo9O0A2NzQ4OTo0OTM2OTw2Ozg+QEJFRjZMSEhUSj5pWVNoVUN1WlCI +bFKWeVudfGCgeV2timG8pnDKp3bHpnfGoXTWtHndtYXZr4PZrYDbtYTguojkv4/gvZLku5rT +n33Pl324hWbHtnjcy5zNq4Pj5aP688/37Mf46rb/+dX78s7x0bLs1aH04rriv5vcxaO7lWyu +h1u+onDTsnzcvZDGmnt8WlZLPz88Oj46OjY5Ozw3OjM5Pzg3NzU0Oj83Njc8Pj06OTg0Ozo2 +PjoxPjY3PDswOTc8PTwzOzU6OEA3OTA3Pjw2Ozg6Pz82PTo5QkE5Qzs6QEQ8RUQ4QEg9SUs8 +S0hIb2ZTgo1ViY1OiItPh5NVjJVWhJJVjptVkaFhkKBalaFckKJSjppTi5lUkZxcjZxTj5ta +jJRUhpRNjJFPiZFYhpNTi5dYkppajp5ek6NZiZlfkJZUhZRVjpRXjJpQipZOjpZTiZhSipdU +kJpPh5RTipNOiZFPiZNMjpFOgpRDhopUiZdJh45Rh5ZLi5JUiZdNjJNYiJdSiJpRiJZSjJhP +jZlYj5tWi5pUjppZj5lRjpZYipNSj5RRjplUhpFYjptKiJRTgZhOiI9WiZdKiI1bhZRPhIxY +h5FRj4xUiJpQio1Rh5NUiJRRiZFVgpFVh49RhpZSh5JXgJBNg4xKhY5MgI5Tf5BQe4VNeoxR +hY9MiI1WjZZNiJdRiJZOhpNXgZBKfo9af4pPipJYi5RVipNUgo1Th5VRiZFPi5RVjJJRi5hU +jZNRjZdVjptTiZdLg5JQhI9QgIxXhYpQg45QgY9PhZJQgo9TipdZjJZUi5lbjpZdk6BflZZd +maNbkaJVjp5ViIhPi5xThJZFfYdXjZlXk59cl6ZWhZtSgpFRj5RWjJtNgI1KeoVPhI5Vh5VP +jJVXi5dcjplYjKNUipxaiJdWippZkZ9Rg5dGbYJGbHpLfIhVio9Zj5tRjp9VhaJXjppek6lb +lKFdj6RLgJpMY39OTVJSU0tSXFLR96f///////////////////////////////////////// +/////vb///n///////3///////z9//74//f2/+v+//r///3h8+fg9NHn9unm8uPe7dz5//Tx +//X1/vH5//f9//j5//P///v7//P9//7///////vx/+74/vf///z///////vv/vL9//j4//T/ +//Hw+enu8ufj6tr0/vT///7y+eq9aW49Qj5CQz01QTk/Qzs3PTdBQDc2PThERTU6PTdLRD1J +QUFRRUFKTkdPUEhJSUJIST1CQj9ARDg6PjgzPzY6QDozPzM1QjQzQTU5PTU5PDQ2OzU3PDQ0 +PjY6NzYzPDI4PzU7QDU1QDc0PDQ3OzdUTzaEbkmoilzAmnXCjnS/jWy7kW6+kmm+mXDSsoW6 +j22rhGWyjmy/nnLAknW+nHXMo4K5jWy8lHO3mXOogmmch16hgl+MbldwWlFrWEpvVUl1XkNy +W0BtVD5XSzhEQjg/PjUyPzI+OjZDRDk6OD0zPTU8Pzc4PTg8PDg3Qjg8OzwyPDM8PDQyOzMz +ODk0ODc2OTc3QDk2Oi86OzE2PjUzQTQ1OTg2Oy42PDkyOTA3PDQ0OzI1OzMwOjI3NDszPC44 +PjczPTE7OjYxQTE8ODoxPDM5OzgrOS87PDA2PDhDQT9HRDlOSkBJRzhbTz5jUD5xXEaCaEuN +cVGeeFagfVmmkVy9mG3GoG3KpG/HpGzSo3TWsXfcsH7Ys3ndvIbduIjbuY/mwI3ixJngvJrS +nn/OlHDEg2O9j2e/o3rOyIbk46jx5LT18L/7+NL69c7y5rX59Mjw58Hy577kzrCwgGufg1jD +onPYxJLLoYF/YFRRQUQ5Ozw3PTU5OjcwPjU1Ozg1PjI1PTUwQTUzOTo3PzM6PDU1PzY1Pzcx +OTQxPTc6OzgzOzMzPTkxOzM1PDYzPjU3QTwyOTczQjs3OzU4QUE2Qzc8TEQ8SEE8SkVAS0w7 +VkpOdnVLh4FXh5hTkZZXiZRRholWjJlclJdhl6VbkJhZkZ1bjpxXj5xWjpxMh4xYio5PgYxU +iZJMipRTj5VZlZpXkJhVi5ZPh5BQgZJMjZZRhY1QgY1PiJlPi5FVkZlTkplXlpxRkZdaiZhP +f4pRiJVQiJBLiJRMhYtPjZZNhoxRkJBQhJBRjI9RiJVQjJJSjpFYkZhSjI5VjZpVjZRaipZP +jpJYjZVVkpFSjZdMjI5ThpRNjZJdiJNOi5BUipBTj5JWkplRj5VSkZVZj5NLjI9ZjpdVi5hU +jZpbjZJPiZJUi5JViplRjphQhI1Sh49Nj5NVi45QjY5fi5VNlJtbjZhRipZUkZlbkpZYk55W +lpVXmp9alJhXjJdZkJlTkJ5Ti5ZOj5NTiZRRh5dKipdLiJBPipJMipdGg5NUho5LiJBShZVD +gopQfotNgYZWgIdHhYJYjIlLgYtSjJBPj5lUjptVjJpPjJpRhZdRhYtVjo5SlJZUi5pRi5NW +jZZXkJlOhINRi5hSh5ZHhZRRiZNZkZ1Yk5lUiphOfoxTkJpYippNg5NMgIhKgZNUi45RjJhX +i55UkppYjptTi5ZViJRPkJpakJ5OhZdKdolDcX9LfYZNiJJTiZtTkJpWjaFXlJxXlqNZk6Rc +jaJRhptNa4ZPTVlFTkpaYU/K76T3/+7+//v////////1//P9//3///////////37//n4//f3 +/+7///////3///3///z8//36//L5//H9//b4//jv+Ozn/+zh99Pj8+Dk79nf8uD////z9efy +/Or9//v///3x/+/8//b1/+X5//jz9+7w/O/+//P4//H3//f1//H+//X09+7x9ujp/Oz9/vj3 +//b+//j1+fH9//X1/+/x9unHa3FCREI8QDtBPzs6QTo6PDs6Pzk6Pzk7PjxCQThDQj9LSztM +TENPSEVPS0ZKRkdDRjxKR0E4QzhAPz00QTk/RT82QTVDRDs4RTlHQUA7QjI9QDc1QDU6Ozo9 +OzY2OzE2OzQ2OTY5PDc1PzVbVUKYfFiwkmrJtITNsIzCnnnAoHnJnHW4j2ixg2e5oneccl2y +h2TLkHO/kG+8fmSVdleYd1+DZlaBa0+IaVGCY0mDZE+Kb1CRa1OGaEqDYkmCZUuHZ0uKbE6S +bFGRbkyMX0VWRj07QDJCRztGQzs3QTs3PTU6Qjs6Pi82PDw+PTQ2Ozk4PTIzPDQ0NjY4OTc2 +OzkwPzI8ODg1PTM8OzcxPDQ1OTgyOTMxNzQzOTU4OTYzNzc6OzQ2Ozg0OzU0OTY3NzYzOjk7 +PDg7PzQ2NTY2PDg1Ojk1QTQ1OTU1QDU2ODg8RDhFRTtCRj5LPT1LSDthUEBwXkR8YUqJb02c +eVSdf1eykWLBmXHDnWvJp3THoW7PrHLeun/ds4LcsoDZt4Tbv4vduYnfx5Tix5zkw5njx5Lq +0rLjwp7ToYPKjW25fmC3lmq8o3HV3Jbw6bvs6sXh2KXq57Xt3rXf2J/OqYiZb1Slj2HWv4bN +qIGAZVZJQ0A5PDk4PDg0OzA0PDUvOi03PzgyOzQ7OjoxPTQ6ODszOTQ8PTwvOjA3Pz4zPzE1 +PTwzPDQ1PDcvPTQyOi44PDk2PDUyQDg2PTo5Ozo1PD40PDY7PEM2Qj08SUA3Sz89Wlo4TUJD +ZGlGg4VTho1PholQhpBTkZRgk59amaNekZNXh5RakplXjppXip1RhpRUiJJQhpRTjpxSkp5Z +kJpSgZtUiJVOgIpOf45HhY5NiZVMi5NUi5JPiZlUg5lRiZNXhJZUho5PiJRTiI1ShopOgotO +g5BMg4pKhI1Pg4xPio9RiZFKipFXkZNOjotUipFXiZBLipdck5ZZiplaipNYkJpYkZdUh5NW +ipRQjJ1WiY9MhJlVi5FRiplakJhSh5NNiJJPjZZRjJJSiJNRjJNUipVPipBXh5RTj4xaiZBP +jJBZi5ZXjZRUiZJSi5ZTipFSi5JTjJZQj49Yj5VVjJVYjpVVj5pYkZVZk5tXjpZYkpZXkJdV +j5hZkJtVkZlWj5pTlZtUiplVlphZkZtVk5lZjJpVj5laj51Rj5NVj55Ukptck51Wkptak6BX +mZxZkpxWj55RjJpXjpZQjJZKhJNOhJBMfotRgYxMg49Mf4pUi4pXkZdPjJZRgpRKi4xWjZJS +jZhPhoVOg5dOgY9HfodLhJFUj5tel6NQhZhHf4ZTjZNVjptPe4xLgIlPhI1PiZJWipdTj5lU +i5NQippNiJRTg5JOj5ZdjpxOh5ZMcYU/c3xQfZBOjpBej59UkqBZkqFVi5tYj55Ykp1UkaRV +g5tJdohIVWtDTkdYXU/S/6v///////////v////////////////+///4/+/6//T///b///v9 +//n7//z5//D6//f4//T4//H1/O7y/+zo+uTw/urn/ubk+M3w/O7o9OLl8N3+//T8//3///fu +/+n3/u31/uv4+Ov7/Pz3/fD9//7///37//L+//v39e3p8+ny/uz///39//P6//Px/+77//X9 +//79/fb4/+34//H5/e7SZ3xBPT9COzlAQD09QTo9Qjo7QjVCQD4/QDdIPz5APztGR0FLSD1I +R0JNRz9FRUFLQEBCREFLQz48PjpFQkAyPzpGQDtEQjxCPztDPTxCRjlCQT5CPzo5PDk6PzQ3 +ODsxPDlDQDk0PDRtYEWjf125jnLCnHHRr4jRsYvLn3qyi2qxlGa1iWmZdFWXbVmWcVC4jWzS +nXXYroPQroLBhHGgcVmca1eObk2VcFGid1ucd1ald1ujf1mkemCddVqfelyafFOefVugeF6q +gV+RaU92U0ZJQjhHQDdCPT89PjlBPDc5Pjw7PTc4PDo2PjhBOzo1NzQ3ODozNzUyNjgyPS88 +PjkyOzQ7OjY3QDI6OjUxOzQ6ODY1OTM7OTU2PjY9PTY3OzY5PDM0ODc2PjUzPzc2PzA8PDg2 +Pjo2PDUzOzQ1OjM5ODo1OzM7PzgxPi9BQDs7QzVGQj9GRztTQj9bUT11W0xyXkOCZk+ZdVam +glqxjGPBmHPFn23Eo3DKpXLRrXfcu4PeuITatHzdt3/guoXbsoDWsH/duYrew5fivZTixZfl +zbDp1arwyMLYkoTJe2q8flfAkGm5m2y3p3SzonS6u3SwnXOTbU+balKObk3DqXTMt4iIalhI +RTw9Qzw3PzkzOzc5Ojg4PTk1OzgvPDE7OTsxOS87OjYzOzQ7Pzk1PTU9Pjs1QDQ5Ojc5PD42 +Ojo2OzY1PzM4OjU1PjQ4PTg1PTU3QDw0Pjc0PzQ4PTo3QTg5Q0A4QUE+TEs+VFI9TEs/Xk5P +hpFRi4tUiZFSi45WjZtekphajJ1ZjpdVjZNXjZdPiJJZg5BOiYtWjppYj5hcjZ9UjJJOgJBU +goJOfo1KhI9Lio1Ti5VSkplfkZtTjppciphPgo1Vi4xThpNQjpVOhZFOhJFRg4xUiZJUiZFR +i49WiZpEgopgi5ZKiodYh41PjZRYjJpVjZFalJ5QjY9Yj5ZYjI9RjZRVhJhVipdWiZRYjZdV +jZlYjItTiJdVjppVjppRiplVjJBZi5pRiZZSjZRTjZFPiZBIi5FZh5NVjZJZiZdOi5dTh5ZQ +iZRXkJZakJNgh5hXkptdjZpbjpdSipRZj5hVjpFXkJdekpJekJhZjpZUk5lakJtVlZtZj5la +lJddkplSj5dblJtQjpddkJ9Xj5pdkZ1Wk5xekaBTjZVZj5tXiZhVlplbk5xclZlXkJhalJhc +kZtalZtZkZpgj5tYkppakJpXj5dVjZtTjp1bkZ5Si5hZhpdHg5FQfIhMfYBWgYpGhZBRgpFE +cXZNf4dRiZRPhppPhpZYk5FdlJxbiphNfYhNjJdZhpVHdIxIfolNg4hTho1WiZdUjZpYkZ5U +kZlOiJtLiJBWjJNVj5dTgpdJcYNFcoFTfoVRipJflZ5Yj6NXj6FXjaFbj6FalJxdlKdShJhL +dIxEXXRFSklOWUrE75v+//j///////////v////8//3+//z////////////////4//n3//P9 +///////+//3+//f///32//H6//P///r7//nj8OXW9svq++br+eTl9eTp/+by//D5//z9//P8 +//z///f6+u33//b9/+zu++/x/O3y/er9//3///////P+//7///X9//T///31//H+//bz/ez8 +9/fu9ej1++/09evXb3pEPT87Pjk+PTg8PjY8PThBQThAQTo9QD1ARTlHQzpEQUBNQD9JSDxV +RUNEQj5JQz5APjtNPTw7PzZFQDo/PzxJQj1COjxBPTxEPj5CPzlCPztDQTs/QD00OzI5PTU3 +PjJEQTlUVkeoh2XBnoK6kG/BnnXJpXfXso7OpoLEkHavemGhe1+HV0lmUUeVck+7imnOp4Db +u5TcsYfQo361hGaqimWmc1yohFa1hWWsflutgF6wimS1g2SpflyofmCtiGa2iGish2ixgmih +e16DXUpYSDxJRz8/Pzk4Ozg8PzQ9OTo/QTg8Ozo2QDU7PjczOjQ8PTUuPTM8OTswOjZBOzs2 +PDU+PTg3Ojg7PDkzODU9PDY0Ozc8QjU8PDY9OTU7Pzc5ODI3OTg1OTQ2Pjc0ODc8Pzo9OTk2 +PzI+Pj03OzM+Nzk0PTQ8PTg0OThGPj47QjdGQT8+RDlMQD1UTEBvWEhuWEV+Y1CVdVOlgluz +k2a7mG3FmmrJnWzNpm/SqXbdt33jv4fetoLctIDit4Pguofcs4beuYzavYXjwpTfwJTcu5Tg +xprivqHhwaHbmYrWl3bUj3nRkG7Ki2nAc164cFmxbFSubE+lbFKlhFPRt4WUc2BPRT8/PDs4 +Pzk9Pj83PDI9PDsxPjY4Oj8yPjI+PD4vOjY/PDcxPTRCPzw8Pjk8PTgyPjw1PTY3Ojw3OzY4 +PDQ0PTY3PTU6Pjc6Pjw5QDo4PzE4QDw2PTc6QTs4PzU6Pzk1RDxATUg7Skc/UE9EZllSgY9V +h4tWi5JXhYxdjpxXi5dXj5Jaj5tWipFYjJxViYlWiZpZjZlch5dUhopPgIlMe4dCeYVQf4xQ +iZpXj5NTkJxZj5NMiYxUh45LhotXiJJRhI9XjI5PhJNTh4tWipFOhohPiZlRkJVXiZFOhI9W +jppPh5JYi5BYj5RajZdVkI1fjpJYkKFYiJRRi4dTjZdXiYxZiZFVjZNVkJtakZpWh5RUjZdY +j5ZWhplWjpRVjpZahZNOiphaiZNRiJFZh5VUj5NVipBViJFViZJLioxYj5VQipJWjJJRi5BZ +kJZYj5dakJZZjJhSkJNVk5RUj5dTjpZXi5JLhpJVjJZUjJVckplXjphej5VTjZhXkJxVk5Ze +kJpblpVfl5tXl5dcj55WkJhVjJ1bk5pbkZtYlJdel5tajppclJ5elZ5ak5xelJpYl5dclZpc +lpxclqBimJ5blJlgkZxXlp5gj6RUj5tflJ5YlZpcjJpUkZlij5xOi5pZjJpPhZVNfZBKdHZI +fIVNe5BOi5BZk5xXj5lai5pOe4RIgIlWjZVVhJVIfo1MfohKfYtSh49Wh5dWi5lcjp1Vj5pS +iZpMg5FVj5tbjp5RgpdIcYNDeH9RhIhQjZRaiptZjp5bk5pckpxbj6BWkpxflaRZjZtShZJL +ZnxFTU9UU0zE7Zz9//f///////////////n////////////////////2//P6/+7///////// +//3///37//j4/+74//L3//Ht+ubs9+Pp/+zg9NTg8N3i69Xj89z6/PLu9uLq++jy/+/t7+L3 +/f3///Xs89/r+PD///7///n5++33/On0/ezz//L5//j7//D///7///f9//3///f5//Hq9978 +//3///Ly8OHJeGxEQEI6OjM2PTo6QDU3PTU2OTc4Qjc/PzY9Pjk/PjhBQjRAQDxFQTRCPTZD +PDU6OzU/Ojg1PjU/PTcxOjQ/QTQ6QDRHQDs2PDZCPzY2PDBEOjc6PTc8PjY5PDIzPDQ9PzM7 +QTh3bFK1m3HFmXi6nHG8knDKp3zWsobTsofOo3u8jGuvdVd+TkFWQziEZUmphF7CmHvUsonX +tI3SnnO/imq2hV+xfmGvgVa7lGS3hGeoflu5l2q4kGquhGirjly5knC2imapg2ergF6ie2Fy +VENKRDlDPzs3PjU7ODg9QDQ3OjY6PTc2PTUyPTM1PjI3ODM0NTY0OTMsODA3PDU0PC8zNzYz +Py87PDMzPTA3ODQ1PDI7PTczPTk5ODY3QTo1OzMxOy81ODIwODM7PDMzOzU8PzY1OTc0PDE1 +OjI0PTU2PTU3PTM4PjM3Ozc7QDJIQDc8PzRFQzY7QTFWRT5oWT5wVkxyY0WLbUydhFuwkGK4 +mWvGmmjEmmjRpHLbsoLbsX3iu4LbtYLasHzgtojet4bYtX/atIbbtoPct4neuZDas4XbrobV +tYLWsoPOn3XToXfTnm7OinDGh2XJhmjGiF/DfWizcV2VaU61pW+Qd1hIQDg6PTk4PDI2PDc0 +PjI0PjE1PjQ2OjMzOjU4PjMzOzE2PTYyOy07Ozo0PSs/PT0vOTE9QDwvODU7PTkzPTQ6PjU5 +QTk4PTE3Pjc2QS83Qzg1PjU0PTg6PTU8Qjk3RDo0Pz00Qzg4RDk7ST8+UExBcGhLf35ShYpS +iotUho5YkqBag5lXkJhXj5hXjJJRg41YjJNSiZRLgIhHeYRLeoFKfZRMiJZWj5ZbjJxYjI1W +i45UjpFNiJRNh5BSiJBNjIdLiIxVi4lTipNTjJRRjZRYkJhVh5JWjZJPkJdZjZRQiJJSjJZV +i5BWjotVh5NQjYtSh5BOi45UippOi49SiZZZiIdUipBSi5lVipVajZNbkZNXj41ZjJVOjZJV +iZJNj5JUh45VjZBTiIhNiZFVjJFTjJJak5RRh5JVi5JRgY5Ui5RMjpJUg5NVjZBTjZNPjY5U +i5RRko9ZjZZGi5lZipdVjphbkJtVj5dZj5ZSi5NVk5ldk5NTkZlUjJhWj5RXjZtXkZVSjJpZ +jpVSjZVfmJpRjZpbkZ5Vk5dck5pWlZhalaFXlJdclJ9Vk5Ndk51alZdakZ1akppakZpekZpZ +kp1ckZ9UjZZfmJtckZ5am5xajptYk5RZlZxbj5tcjZhYlZpakZtTjJtXiZxDfJBIcnpEdIRJ +aX9AenJRiYlKho9Yj4xVg5NMhItXi5pShZBPho9JfYdEg4RPjJBTjJhTjJhXipdTiZlWiJNJ +gpBSi5RYj59MfpFGcoBGcXJLgYtTiJRXj5tYk5pYk6Zbj5tWj5taj6JZl5xhkKZSgZtNb4Q/ +TFhTUUTB7Zf+///6//P+//r+//z+//////////3///3////9//v9//r////////8//bz/+z6 +//H7//n+///8///1/+38//P0++zl8uTe9dH2/vPs9ufs8uHv/+nr/+z48e/y8uv0+PH1/u/0 +//T///b///75/+34//X+//vy/+r9//3///P3++/o++j0//P1//b6//H///3///v5/fj///3s +6trg5dnTc3xBQjk/QTg7Pzk5Qzc6QDg1PTU2PDc0Pzk6QTw6PzZEPjk6PjQ7Pjc9PzRDQToz +Py5BPz44QjY/Pzw9OTBBPjo7QTNAPjc/Pzk+PzQ6ODQ8PzE9PzU1PTc6PTQ3PjU4OTQ+STuN +dFq5n3e6lHa9knavkGfEn3nNrn/UrojNqoHPpnvEmXS7eWR2TEFrXEGbfF24k27LqXrTroPR +qX3HmHTDhme2fmKtelq4k2O8jGm0iGm6km+0jGeuimezk2+2lG2wimiriGKrf2SWb09eS0dD +QTQ7QTg3PTAwPDg6Ozg+Qzo8PTUxOjI3OzQvPjM0OjUzPC01PTIvPDE3NzMwPDcyODM6OzY6 +QDc3QDg5OTI1PTQ1PTI1QDY2PTc/RTk3PTY4PzE2OjQ4OTIxPjMwPDI3PjktPjUzOjMxPDM1 +PDgwQDQ2OTY3PTZAQD1BQj1JQzw/QjhGPzU+QTlLRzpiVEN0WkVuXEqDa0uahluoi2KxlWvC +pnDJqHbRq3jVsXrcuYDiv4rhvYbcunzht4jdv4HeuYLauITbuIfZuYfbtY3Wt4jXq47MpnbR +l3LGjGvIiGzAfF29dl++fl27gGK+gl6xeVqfaE+RbkqWfl5HRjs6PTc2OzcwPzEzPTQxQjIx +PDUvPTY4PTYvOjA2Qjs0PC40PDkvQTIyPjczPTM6QjgwPjg2Rzs2Qjs1PTozPjczPTUwQDUy +Qjs2QDc1Qjc2RTk6PDksPzQ3QjYxQzdAQzw2Qzs9Q0EwRTU/VkQ6VU1DbWxFen1TjIxNj41Z +jY9Xj5hSkpRTipRNiZBTi5pUkJhQgINDdYFFhI1Rk5hWkplam5xWkKFXkJVSio5ejZdRi5JS +ipNMi45Ri5lVjY1VjpRVkY5akZxdjpZXkpZZjZtViphTkZhWipRTjJVSjpFTiZxRkotPiI5Q +iYZRio9TiopLjJNVipFQiI9ZkZFPi5NcjZBRjZZZkJFSjZVeippUjo9VjZRPjI9Qh5RWiZFS +jZJLipBRkpFUhZJIi41bjJpOkI5WlI1Wl5RYjpJPj5FSiJZLi41RjJpVj5JSipNRj49Si5NP +kJNWjpRSjpdVipRTj5RbkZVPkpdYk5dUlZlWlJZRlZhhjJVLjpdWkZpQkphYk5hPlJZYlJ1V +i5RVkZlZlZRZk5hSlpZYlZtUj5dalJhZlJpaj5lWjpRVj5lTjJVSjpRUlJhXkplVk5lYlJ1a +lZpWlppUlpdXkptUkZtZkpxUjZVWkJdVkZhQjZlVlZxclJxWj5xWkJpOfpJCbXVGdn5EdIND +dYJHfIdKe4FKhIZPgZBPiZFPi5JYjZZQiZNMfopHgYNSiZVOi5RXjZ5SjppPhJlHhI5Sh5VK +iZNYj5hFgY5IdINEeH9Qh49Vj51Uk6Bbk6BQkJ5ckp5Vkp1Wi6BYk51flqVSjZ5ReYxFXnNT +WE2335b9/+7////////////////+///+//n///////3////////9//r8//f+//j////6//j8 +//X4//j2//T1//Hu/+7o++Ti+t/f/9jf7d7l9dzm7d/s9ePt++f4/vT+//v8//Lz9+/2+vL0 +/Onx++7z/+/6//j5//L+//f8//b///z5/+zx9+3x9e7s7+b3/vHr8uPq++j99fX///33+/L7 +/O/rf4c9QDtCPj4zRjY9RTw2OjQ5Qjw2Pzk7Oj45PDNBPzs4PTRDQzxAPzc/QDg4Pzo9Pjk8 +PDc6PDg3PTQ6PDc4PTRGQzs+PjU+OjY7QDY7PTY1PTI2ODMsPjY6OzgxPTM8Ozg9RDaEeFyy +lHGykHSvjWaxf2S6k2vFo3fQr4bSsofZr4XPo3vGhmapYE9pTT+JY0iphFzAm3LEonTLoXrF +nnvDkne9h2qyd1iwiFm+j2yviWm3i2iqh2e0imaujGi2kW2rimyrimapf2N+VkxLRUA+QDg8 +PTk2PzI/PTg1QTo9PDg4OzYxPDQxOTE0PDY1NzgyOTQ2NjktOS83PDY0PTI4OTg1Ny08Qzw9 +PDY3PDs5OTc5QDY7PjY5QDVEQDozQjU5OTUyODI6PjItPTI4OjU0PDgzOTI6Pzo2OjU5Ozk8 +PjM4Ozg6PDZEPztKQj1VSkFQSz5KRzlAQDlGRTxYT0JnWkduWkd5aUaXfWKdf1ysjme7onLF +oHfNqnTWrIDWtn/dtYPhwYHiwYjkyJPnv5DeupHhu4rasYnbtYnYs4bXtIHSsYfQoYDMn3fN +lW/Fhmy+fmS5f2S8fGO3e2K0cmKfaE+MXEyUg1xYR0U3PjM5Pjw3Pjc4PDYzPjM1PDkwPDM0 +OzgxOTU3PTQ0PjQ2PDI4ODgvPDc3OjQ3PDU5PTg1ODY1RDY8PkE4Qjk7Pz4xPi45PDk3PjE+ +QTs4QTQ/QT4yQDQ4Ozw1PTM4P0I6Qzc8R0U2QTM3Q0A4QUI9W1BHZ3ZNeYZJfYZRgIhSgYNW +ipJPhpNUgZJWj4xVhpBHcodKdYpCh41ak6BXlZ9fkZxUj5hciJtHjZRYjpFRjpZVjJhVj5Fh +kppVj5lblZlXkJhej5lXi5tYkZJTj5ZTi5hViphKi5NOipJRiY5JiY9VhJJSiJVZhI9Fh4tO +gJRGgYVRiJRKj4xWjpBRkZVWjJJRjJVVi5RNho5TiZNWg5FQjJVWhI1Rj5BUipJSiYtUhZBQ +iZFViJRSg4xOhpFSh5FJgpNWhpJQipJWhI9PiJFfiZNSjpVVjZdTkJNUiJNSiZVTjpZOjpZY +jZZVjpVTlJhZkJlTk5dSiJVVk5NYj5lak51YkJlYkJdZkZVYj5hYkZVZkJ1ck5VYmJ5ZlJ5b +l5xckqBZlp1hmJdbmJxck6Baj5tZkJpYkZthlJpTlZ1bkptUlZNbkZtYk5palpxbmZddmKFV +j5tdkJxclZxdk59VlJ1UkJ9PjZdYj5VYipZTjJlVi5VWjJpRj5tThZ5FbXQ/bXlDcX1Dd4JM +hY9LhI9LgpJJcoNNiY5VjI5Xj5lUg5NDeIVPg4ZMh49TjZtWjptTiptMiJZMhJFLg5ZNhpNX +kphOfpFJcoBEc4BRiYlck59WlaRakqBWjJxZlaBUk55XkKJWlJ1glqhUkJ5TfJJDcnZeZWXD +5qX///////////////39//79//r////////8//n6//f8//j+//P///////////////30//Ds +/eXz//L2/+3////2/fXn/Ozg9tbq+uPw/ejt+en3/+/2/Pr49urh9djx/vD9//75/+/1++T3 +/fb7++3y/vH5//D9//z9//j6//n///vx//P///7///////////3///7y+e/x9+jx/ujy9OrT +fn4/Qj1BPT42RT1BQzo6Ojc6Pzs8Ojo6PDg+PTc9PThCOjs8PTVDPzs8PThFOjs2PjBJOzo2 +PC9EODszOzBAPDo6PDU/Oj08OS85Pzc+OjgzODQ7PDc6Pjk7PDsvOzM+PTlJRT9sZU+qg2Sv +imipimiqgl6tiWm6mW/Mqn7StY3Xq4zUtpLfsIzImHa+emWWW0qbblWmfl26jm7Dk3O/kW7C +jXC9iW+4hGa3jGaziWSef2ClfmCnfmOphGeogmWqgGeogmSlfWOTal1jSz9IQD05OzVAOTsx +OzFBQj00QDI2Qzo4PTI0ODUzOjQtOjU2OzYuNTE6ODYwNjQ2ODkwNzc5OTU1PDc+QTQ/Pzs2 +PTY0Pjc8Pjc+QTk8QjhDQkA5OTg0Nzg2PTg2OjQ4QjU3PDc4OjkxNzM3PT00OjY9Pjs3PjU9 +OztCRDlKQz5HRztdSUBNRz1cSj9CPzxCQzdHRUBsVUFoVEd0WUaOdFacgl6okGa3lW3Dp3TI +qXLNqHfPq3PbroDhvYLfxpHow6DmxZXmvJfguIratIjXsYDfs4jdsoHUpoLMonzOn3q/mHO7 +jG+0h2u6gWm1fWerdVydZlWIWVCHaEtpU1A9PTU5OTQ4OjU1OzI3PTQ2PjozPDIzOTgxNzc2 +Ozc0OzU7QDo2PDc7PTsyOys3ODs4PS07OT42Oy84QT1CREBHREE6Pzs1PTA3Oj44QjY7QjdA +PTk6Pjs8PDszOzM3PDg+RjpDQjszQzk6Qz81Rzo6RkU+cWhOY25HhI5Xi5JPiZNUhJRMiI9X +h5NOgZFKc4ZCdX5GgI9SjZpXl5pfkJlbkZpbj5pXjpdOjppThplRjpZXlJRWjZZflZ9Zkp9X +kJhRio9XipFVipNUi5hPiotUiJlMiYFMhpJPh5BRipFRjJNOgpFPhZFRgIhOgotQgI1KiJdR +jZRSh5JSj5VZkppWi5NOipZajZJSiZVcipNJiZRUi5JSjZZai41KiJlUkY9PjJRViY5TiJpP +iJFNhpJTiJFUiZtPj5FYiZNPj5NYiJRRio9dlZlUiphUjJlTjJRZjpNRjJVUi5dQjJhYjppT +kJhXkJZckphWk5dSjppSjZJel51ek5tYkZxXkZ1akpVakZhSjZNYkZhWkplajJhXjZJZkZlZ +kppdlJxUlZlbkplSkZdWjppWkZhVjptWkJtZlptemJxVjZVYk5NXkp9XlJtgkp1alZ1bk5xW +l5hajZhZk5lalKBZkZ1ViphRj5NZiZlTjpNWjZtUjpVXh5xLh5NEaHg8anVEbn1DfHxTh5VN +fYtPjJNNgYxJgI5Oh5VXkJ1QgZBGfYxKgolTjJVUjJhYi5tSiZhQh5lFgY5Pg5FPkJFZjZxH +gJJLcYJAeH5Xi4pWk59hladVjqFRkZtbkZtXkJ5YkqRcl6BdlahajaJPfo9LbX1dc27M5637 +//f///r///b///r////////9//r9//3///7///////////r9//36//T///z///z////9//r5 +//X7//f5//Tu/+3i9+XT88zv+ufr+ebi7t7///r5/+b8//35//P3/ent9OX1+u////Lx/vH/ +//j09en5++vt/+/+//P5//v///z6//X7/PL+//7///L///T4//b19Or+/vz///////TUeolA +RDhDPEA8PzdEPTk7QTdDRTo6Pjc2QDc2OzFBODtBPzpCPDo9QTpBODdBPzdCQTs9PTtBOjo4 +QDY/OTI7OzY9PDk/Ozg/PDY1PzdCOzowPzNBOjs1PDdAPDs6PzFUTUWJa1OWZVWUb1OlfGGf +el+mgmKsiWS3k2/Fo3rLp33VsIPWsYrdrYvbsY/cqIrTnn7Fd2aoaVKec1isgGS2g2a2h2mx +g2SvfmefflqXdFyVcleNbliOb1KbdVyXdmCbdWSpfF6bcV57WFBPQzw/QztEQDlBPjo6PTY5 +QDo9PTxBPjk9Ojg3OzY9ODk3OTQ7PDoyOzU8OjkyOTM9PDgxOS87Ojc2PzhLQz9JSEJHQEM8 +RjpJSD9DQTw8PTpGPz9APTg5OTo5ODU+Ozg2OzQ6Nzg6QDs0PTQ7ODs8PDM/QT5ARTdAPD09 +QjdJP0ViUTtnU0ZlUDxnT05PRDlEQDxMQjxaU0RmT0dwWEWDbU+SelighFyvkWm/mnPHpXLN +qnXLqnXTsojhu4Xjw4vqxprqyJ/syKHnwproworhvYnjvI3YsIjXpoHLoXrKlXW9lHG8lXK4 +iHSrhGaffGOPbFl/Yk+BakxrV04+PTdAPTs5Ozo9Oj06Ozg2OjQ4Ozo5OzI6Ozo2ODo4PTo0 +PC05PT89OjI2PDs0ODA2QDk6PDg5PTw7PT07RjdFRUJNU0hGRENAPjxFSEM5QjBAQD1JSz5H +RkZHUkZGRlBBQT8/RUZMTUtCTEhETEZCSk1GU09Ha2dKenxQgoxQfoVTgoZNe4BRfYxHdIFK +bHJHe4hRiplWjJ1YjJpXj5ZbjJxVi5RZi5pViJpXi59ci5Vgi5pRiZVXi5hSjZlZiZVSiplM +iI5TipVWhZZWiZdQg4pPgZVPho5JiY9Vho9LiJJXiZFMiI1TiJJRipVahpVLhYxRkZNKj5FZ +i5FMh4tXi5ZRi5NZj5JWjpZYjpRViJhOj5BZkpdWiYxYi5lThpBMhpJSipZaio1ZiJRRiJBT +jpdPjZJbjptQi49Wi5VLjZBZjZhWjphaiJhSjZFakZpYjpVZiplbkppclplXi5ZWk5hbjZpV +jpphk5hejZlakKBYj59akJtbjJZVi5lXi5hZj5lek5ZWkZxfkJ1ZkZZjjppSjphhj5hRkJ1k +kJxakaJek5ZekpZZk5dbjZtalJtglaRhlqBfkaNfl6Fhlpxckptbk5xalptbjp9clKFekaBc +lZ9ckJtckp1alZ5fjqBZipRck59SjJlYjZ5fkJVUiphQhJhEcnpGanc9bHVMf4RRhJRKfo5W +kZdTgplQhoxQjJZYj5VKf5NHdIRSiI9VjZRUj51aj6BXj51ViJdMgY5RhpJUi5xZippRgJFG +b39IdYFOho5Xk51ak6BcjaNXi51Zkp9WkKBhkqVZj55il6dVj6RXgplOc4Jadnm+2qT6//T/ +//////////////////////////////////z///////r///v///v////4//X9//v///7////2 +//Py/PHi9+Hz/u7w/+X9//np9uXb5dXx+Oby9Onm/Oj+//v5/+////3+//P0/Orr9OP4/+/+ +//z///38//Pw9e3u/e36/vr////////+//Ty/ej7//Tr/OT6/vf///3+//Xv6+LZgIpGRUEz +QTxMQj49Qz5ERT40Qz9DPj85Ojo7Pjg9PTlARTw9Qzk7Qi9CPjs+Pjk/QUBBQDs+PTc6PjhC +Pjk6QTk8NTU8QDk6PTY7Pjc2PTc/Ozo5PDk8Pjo8PThOUUOdel+rimnElHK+i2yrb1yScFen +fWKti2u5kXO3kXG/oHbFpHjSr4DXt43hu47fvpfeuZTgr4zXooPKhm65c16gbVKXb1aMa1KH +bFR5XEptXE5yU0pvWUx3WE6AYlKLblaaeVycfWSIZVZaSj9IQDs7PzFGQDk5Pzo9NzozQzU+ +PD0vRzo8PDowPDk3Ozc2PDc6OzU4ODM2PDYxODYzNjY1OjgxOjQ+QzhCQj1VT0hCQT5CSj9L +S0VESkFMR0RHQz8+PD80OjI7NT41PjU7PjorOzE8PTk1OzlAPDo1PDZIQ0A7QjdGQT1HRDxL +Rz5kU0RzV0VxXkuDY1RfTkNISDpEQj9SS0JkUD9zX0l7bk6NeluWf12pjGmylGu9o3TNq3XR +rn/QsX7YsInVrYDfv47kxo/wzqLpxaHiuZXht4rfvI/cs4LbrYHWpHvGnXTEmHC+kG20h2is +fWKfc1aYclicdlmPa1VGQj4+PUAzPDU6PTkzPTY6PDkzOzo8QDYxPDcyPDE4OTo0PDU1Ojw4 +Pzw4Pzc0QDg4Pzc2QTo7Qjw7Qjs+RD5ITUNMTUlQSktLSkhKREI9RTs6Pj46RzpKVEdQSkdM +UVBJUk9DTU9MUkpMUUlKSklETklKT1RFV0lPXmtIYGVPbG1Pd3tIbXxLc3pFcHtMd4FKgJBc +kphUkaBWiJlVj5pbkZNZk5hikJxWjJpVi5ROipNWjI1Vi5NRh5JPgpNOiIdUjplMgYpVh49P +iZJRg5JOg5RTiJZLiYpWjJROjI5RhZVMhY5ViphSi5VQipROlZ1WkZxVipZVi5NUkZdOj5NS +jJRVjphTjJdVkJdUjJRWiZhPkJJYiJlNiIpRi5RNh5lUiptNjYlSiZFTj5RVipdLjo1ai5hT +jZZfjpRSkZZVi5ZUiZFKh5NWipRYipdWjZhVjpRTjpdajpRYjZpdi5pUkJdWj51SjJVakJpO +j5BYjZhVjZZbjJpYkJRYi5tWjZddj55WjZlTkZdakZhYlpddj5xYk5tYi5pWiZFdkZhXk5ta +jZlXkZpcjp1bj51ZjpdXkJlTkptek51WjppajpdYk59nkqFSlJ9kmKFVlJxekJdYj51ekZ5V +laBbjpxbkJ5Zk5tVjJlSipVOhZVWipdajphSj5hXhppCb3k+aXw9aXhHentLgpJHfIFTjJJQ +gpJNhpBXkphTiqFNeo1LfohQiJBVjJpXjZtXj59ajp9NiJhRe5FJhI1XjJlSjJROgJJAa4BJ +eoFOipFYlJ9bkqZYj59YkKBZipxWkJxZlJxak6FalaRglKJRiplSeINSenq806D+//f///// +///////7//n9//3///////38//v+//f9//r7//b+//f////7//3y//H8//X4//bx/+nw/O/s ++eT3//jz//bh/t3r8ebl89jf7Nv0//T5/fL1/fL1//T9/fHs/uXr/On9//v6+e3k9Oju/ej+ +//T9//L+//v////9//f6/vP7/+/4//b7/+77+/f+//f78+z8/vf+//L7//DsjZM8RTs7RD84 +QDdAPT08QzZAQDkzQDY/PTo6OzRCOzs2PzJAPDo4OzJHPDs2PjNCPDw4OzM9OTg7PDU8PTJA +RDc4QTQ6PzI3PDM5PDY3OjY8PTk7PDk2PzZNUkGPeFbAm3i8mnjSon/RrX/MnHi4gGCmcVqo +glm6j2yyi2S1im2/k23GoXvYtIbdu5PeupLcu47guZLkx6Hjup7YqIjPmHOfVU5WRUBRRT9h +Rj54TkaLWEOdWkl4T0R6WE57YEuJZEyKZElzUUpLQD1KRDo4OjhBPzc9Qjg2PjE4PTY6QDg8 +Pjw1PjcyOzU0PTQ8OjczOjQ7OzI1OTc2OTE9ODcyOTY4OzVAQzZLS0RRTEZIQkJGQzxST0ZI +RDpHRUNLR0E3QDY6PDk0PjM/Ojs1PTc5OjM6PjU6OTc3OzU8PDk8PjZEQz5GPzg/QDdKRD5o +VER/ZEV2ZkmTeVZ3V0hNRUFHQjxSSjtcUkJ0XEx4ZkyFa1KSeleiil+wkGu6mW7EnnDCpXPP +q3zKrHrVtYXcvIrivY/gwpHowY7oyp/mvJHiuojouoXgtYrarX3ZqXrUpHfNmXbGkW/Bkm6/ +i16whV+uhmR0VExANzo2PDA5PDU1OzM7ODU5Piw2PDU0Oy42Nzc5OzM6OzozOzY4Ozg2QDE7 +Njg1OTY+Qjg+Ojg2Pjg+OzU5QT1NVEZUTExIR0ZJSkZLREVETEQ4QDNGREVJU0ZbV05RU0pS +WVdBS05OWVhVWkxQSEpEUEhNVlZFUUVOXmhCYVpHX3BHaXFNbXJFb3RGe4BPiI5PjZBZkJhW +jZFXkJdUhpNOi5NSg5BRjJJOgpNLhYpRhZZMjY5XiJBPiY9UjJVIiZNTiJRJgJJPiZJQiZBV +ipBUi5BLiI5PiYxPjZZPhZlTipVZjKBViZlTj5pVkZdTkp1Vi5dSh5dTi5dTjJRbipdNh4pW +hpBOgoxXiJJRgotSh5RYhotUh5JMgoNSiJFXiI9PjJJLh5BRjJVYjJhPjJRSiZlUiJRTipZX +hpBTjpVXi5BakZxai5VWjpNaipdOipNfjpVWjpRklptSi5hbkZRQkJZjlZZakJNakZpYj5JY +kJFajJhbkZlcjqBVkJVZiZlWkZpckppdmZhTjplWk5ZUjZtakptXkJxalJxdl51fmqBdlJ9e +lJlZk5tclp9ilpVflJdakplXmJ1UjJlTj5lekZ1WkJNgkplamZpilKBYk5hYkJ9YkJlXj5xY +lZRgjZxZkJlYi5pTjZVYiJxSiZBbjpZSgZVQhZBEbnc/bH9AZnJId3xLfI1Je4hTiZBVhJRN +hIpSjZJRi5ZQe4tIfoNSio5Ti5ZZkpxTj5xXjplJgZFOeY9Jfo5Xi5hXjJtLgI1Gb4BFfIFR +i5Ndl55dkKBXjJ5WjZpYipdXi5phkp1dlZtbjJ5XjZxXi5lKeYRaeH+61qL///////////// +///////////////9//v9//j///////3///n+//3+//v///////z7//b1/e37//X///////36 +//jr+uvd9dHt+Ori7dzs9+fv//H///719e/6/vf4//P///n5//bz/+z9//7////z/fTu7+Lv +/vD+//7///v///3////////7//n///7///X9//L9//T5/+z19OXo7d/WjZk7Qzg9Qj5ISDxE +QjxARDlCPT02QDM4OTY7OzU7OTRBPDZCQDc9Pzk9PjY0OzU4ODM6PTM+Ozc6OjM3PTE5PTA7 +PDY7PjQ/Pjk3Ozo9QDs2OjI6Ozo0Qjd9cFmuk3LFn4S8n3vKoIHOroPYp4XVqoTOnXy8gGer +fFqti2Gvh2exiGe9k23BnnTJo3bKo33QpXzQsIrXsJDUsIrcqIXYtoPTmH+TW0lxTkJnVUWX +c1iffmO4kW67jHO2fWeSYU+GXU5wVEhkTEVLRj1EPzc8PzU6PTY4QjU1ODY8Njk7QTc4PjY6 +ODowPTY6PDc3RDU/PDsxPDA6NjcrOzJAODgtNzA+Ozg8QjhJRD49SEJKQUFBRT5ISTxAQD09 +QThRT0VEQj0+Ozo1PzVAODc2Ojc1OTc3PjY0PTRBPjk9Pjo8Pzs+QTNEPz46PDBJQj5sWj6C +aFF1XEKJclWEY1RPR0BRRj1QRztlVUJ3ZUx9aUp+bU6Cb1CPeVihhF6qjV+5nG+1kGa5nXHI +p3TOs33YtoLasobgs4jdtobjvYblwIzmt4nhsITdrX3XqXzRqXbOpXbRpHbLm2zEkmq9iGG0 +imKifmBQP0JAOzkyPDczOTYyOjQ3OzQ5PTQ4ODk5PDk0OTY3Pjw3PTY4PT81PjIyPDk2PDE1 +Pjs6Pjc8Pzs7Pzg+Rz5GS0ZLVkJXTk9DQjw7PkFGS0JBOz44OzM5QDtDTD1UVU9LU0pJVFFK +VVpIUFNOV01OU05NWFdMVFdIV0lPa3lFWmRLYWFFaGxNbnlMbndLbXdPgn5VhYtShI5ShY1O +iYxRhpJJg45PiJJMh45WippLhpBWhphPj5Jckp9ajZlYip1YhZNWj5lVkJhWkZVVkplRjZNT +iZVXkZRRl5lYiplZlJhVlptXk5RZj5RTi41bkZxUi5paj5pLhphQiJRKh45UipROi4pRfoxN +hoxUhIxPh4lJho1Rg4tTiZNQiJNSjJFQg5NRiJNSj5NTi5JUkJZThZJLiZJUiJRLjI5ahZNR +jZBdj5hZlZZZjpVSi45VjZVUipdYkJhalJFYk5ldj5NWkpdVjpdalJhZk5lhj5lbkZpTjpNZ +lZdVkJVWkZhVjZRUjJdYlJtSjplckZZOiZhcjpVNjplaj5pXlqJdkZlXkp9blpxVlJtdk59a +laFZmZdal5pYlJdalJ9WkptgjZpPjZJZkZZYjZpWjJpZlpldl5tWl59bjphUjZZXlZhhk6Bb +kptVjJ1TjZpPjJZVjppQiI9ViZNNipJLhJRBa3Y6ZXY4am9BdnxHd4FKgYlQj5NTfpVJeoNO +hJBRhJhKeIpJfYZSi5FZjJhZjJZXj5pYjJtNg5ZLfoxOgY1UjptThplOe4pCbn1Je4JJh5Ba +kJ5TkZ9ThJlLjphVg5tSjZJakJpVkJxekqBWkJxVipROfo1TeoKmzZ/7//D+//7///////// +///9//z9//n///////////////////z////2//P9//j///z////9///9//n1//D2/+3y//Ds +/O7j/9zh7dvs++Ty/fDu/+7n8uTy/u3y//Lx//X///v+//T19efr+9/q/e78//3///////z/ +///4//D4//H6//b2//Ly9+jt++z6//Px/vD99ff4//T5++z+//floK5EQ0A8Pz9ERDs7RTxF +Qj41PD1FPzgvOTY6PjQwQDdAQzdAPz1DQzg8PDk4QzU7OjU6Pzc+Ozg6PjQ2PDk1QTY7PTk6 +PTRAQjc0PjY8Ozg8PzY+PDo9R0GNdl2zmXjBl3i8pny9lnXCn3jLrYDTsonar4bSqIbPoHa9 +f2erd1ingVu4jWu2kHC/kXK9k2y8i2/GqoPRsZXXv5rivafixavctZu6iWijc2N9VElwV0h6 +Y0+YdVmjf2OliWiwi3KIaVd0WUxqTUVLPzlAPzkyOjU7Ojo4QDk+OzkvPjJAQTs3QDc7QDcy +Pzg8Pzk1RDo+PTovOjM0PDUvOi44ODUxPTUvPzY7PjxCQj4+QT4+Qzo8QTpBQj07QTk8QzpK +TkBIRUBCRDs7RzxFQT4/Pzo2ODI/OD8sPDFBQTk3QTpAQD47RzxEP0A8PzZMRT1rVEN9YE+F +ZEl2ZEZzYUlSSzxMRjpkWECHbkyDak6DbU2Aa1GAblODb1aOelqbhl6mkGCvlW60lGa7nXfC +q3fOpoHVtXvdtozasILYtYjeuYLftYrapn3cpXzVoXTSpW/SpnfNnXPKlnHFjWe1glywgFyC +ZVE/Qjw2Pjk4OTkzOjQ4PTsuPzQ4PDYsPTI6PzszOzY7PjQ0QDY9PzkyPjg1Ojg1ODw4QTU+ +QjxBRDlGR0FNTEVPTk1SVktUXE9FR0Q6PztCRUE4Ojk5QDk1PTI+RkBERz1GTElGVk1KWGdD +TEZLVlhRWVBSY19STU1RcWtjeIZLXm5LXmdJZGVMZ3JNanNKbnNPc31MdYBOfIhJfItKfYlM +e5JLh5JRipNVjZVWlZ5Wi5ZTi51Uj5RTkZxblZ1Yip9ZkJpPjqJVjppTiJxVjZdRkZZWlZlY +iphWjZlXkZlRjZdckZxMipZXjZ5PiZhYjZpZgZhYjZZTjZRYjZZLio5ViY9PiY5OiJBRiY9U +f4dNiYtNhJBPgpJVjJFNkJFXiY1RipJaho9KjYtZjZZSj5JSiZpOjZBPi5NRi5FYkZVLj5BW +kZVNkJRYkJhTjZdXkplUjJNTkZdQkJJViZVWj5RSj5ZUkpRakpRXk5VZkZpYk5ZekJ9XkZZb +kplSkZxckptWj5hekZtSk5NakZdPj5NVjpRSkplYjplTkJdWk55YjZ1WlpxelphdmZtalZta +kpxYl6BbkZlWkqBalJ1XlaJbkZ9Wk5xckZ1SkpZakJxQjZtYlJpSjpZcjphQlJhbjZ1UlJ5a +lptTjppNi5BVjJNSjI5TkJpTjpVQg5c+cXJBZ3k9ZXFDd3hEe4hMgYZVjZRIe4pCcn5PhIhU +iZFJfodFg4tPh49VipNVjY9SipxTjZhKgpZPgIxLg4xTkZZTi5hKe5FCb3lLfYNMiZFbkZ1V +jp9ViZxOgZtRipJQiZVWjJhZkp5blqRdmKRVj51Vh5RQg4uw06j5//b9//v2/+79//////// +///////////////////////6//T////////////4//n+//X7//r9//n8//b2//Dw/uvm9+bc +89nh8dzd7t7d5df8/+/9/vn///798/Py8enw8+js8Oj7/vL1/fD9//z7//P5/+3+//fz+en7 +//j79/P9//z///35//r///7z+ez4+efp8eH9//X5//X+//PiqK09REY6RD9BRjtASkA9Qjw9 +PjtDQzo8RDpESUBBQ0A9PzdAQ0BIRz1CQUE9Pjo9OjNBPjwzPDZAPTktPzZBPTg1PDU8Pjcz +PTpCQT4vOj0/PjU3QDdBSz6GeF+zkHe7jnSvjG25jnGzkmy+mXTNrH3auJHbu5DetYrcqIPM +l3vEgW2wd1ung1+sh1q0jGi0gmG+nXTCn3jEmXrIqILRvIzdtIi9hWelhV6qgWqNYFVrUEN3 +W0h7YkiNbVJ1XUd1V0ZyWElWSURAQDg4OzU4PzM1PDg1PDg2PTcyOjg5Ojc5PDk0NzY/Pjk2 +Qzw6PTg4PjouQzA2PDExOC41OzQzOzE5Ojc7QDg/PDw7PjZAPzw5RDtAPjs2PjU9QTpDUT9H +R0VNS0FESEFJRUNDPDs6Ozw8PzI5Ozk7QDc5PzxBOjxCPztFPTs/QDRQSz9rV0d4YUqOdlZo +U0ZIQjtiT0R2UkaUcFKQelyTc1uUeF2Nb1t+aVGCak6AclOPfFiegFuhhWWli2Culmuzlm6+ +onbLq3fYtIjYsoHbs4LasX7etIjbr4XXpXzVonDVoXbMpW3Tn2/NmmrFi220flugeWBdT0g6 +P0E2OzszPTQ4OjsyOjUyPTY4Ozc7Ozk2PDc2PDQ4Pjg2ODo5QjwzPzY6Ozg3Pzg/RD47RThN +TUVSUEhWTk5LT0ZMTkk/SUBJRUo2QDw4RDs4Qj05PD02QT9ASUBCREI+Rj5KVVhGUFRHTE1Q +WlZTVl5VYWJPXFRlhoNkf4tZZX5JXXRMX2tQZ3JRbnJLam5WdIJRcX1Odn1XeotLf41Rh5NO +iIxbi5JSjJNUh5tQiZhRiJtTj5NWippUk5BUjp5YkppZk5tZkphSjqBdi55TlaBXj5ROjJVX +kJhajZ1dkpNXjZlVi5dUi5VUiZNRjZlSiZRVipNOipRSipZPjpBVio9WiY1ShpRRjI5YiZFa +hY9OiJhRhoxWiZZUi45Vi5dai45WjZVJh5ZXipdSi5RSiZJUjpJRhpJUj5ZWj5ZVkJdShZRQ +kJVUjJRMjJJUjJVSkZRXiZRQkJRZiZhOio5UiZNXkpFbjpRTkZVVk5palJxYlJlckphWkJlZ +j5lXkJhVkJpdjplXj5pXkJVZkppckphZlJhalKJXjpZclJtZlp5gmJ9YnqJcmKJZl5lglp1X +l6Nfkp5Yk5xbkppcnJ1blaFdkp1bkZVWkphXjZdhl5hXlJpYkZtUjZdTjppUkJVXj5pViphU +kZhUiZlTjZdNgZFJhpFUiZNEgJRPbHc4anlBZ3I+c3tJe4JGg4tWi5FGc5BBdH5Vi5FPhpZN +folMhopUiZhVkppRjppTk59Vj51Ng5NIfYdKho9ZkphZjJtOeYpFdIBMiYJTiZRXjpNUjZ5U +jJlRiZ9PhZNPhJRWjJpTjp1fkqFbl6Jajp1ViJRWg5Kw1aj+//////////////n1//T+//// +//v////////////1//X9//j9//r1//P6//f////////9//X8//n7//j4//Pw/evm+uXg/Nv1 +++z///vw9+v2/+fo68z6//T6//L9//z////+//z///////ny/e/z/e3r9ODl/Oz7//b///z+ +//n5//T4/+/0/+35/fv///n+/+/z6uTt/O36/u3u9d/VsLBAREE9QzpCRjxCRzg2QThORUBC +SUJYSkVFT0hRR0BDSEZcT0NGSz9LRDg8Pzo7QDU8Pzk8QTk6PzU7QzM8Ojc2PzU8QDgzQjdA +QjY8PjQ9Pzc9Qjs+RDtralaojG6ukWyogmWugWOrfV+xjGi/oHTOsIbbs4vgvpbeuZLYsYja +q4fUpYDOkXG5eVuwcVmreVa2hGenf1mzi2e7jGzCoXXEo3mzj2qzgG6dgF2gfGOTalZnUkVk +VUZlT0VhTUJoT0NNS0FNQjw4Pzg0OTRAOzY3PDI5QDY2PjY2OTg2PTM5PTo1PjY5OTs3PTg5 +Pjo1PzQ9PjUzQTI5OzozOjM7OjYxPTU2PTg0PDk9PDQ3PDk+Qjc3Qjk9Pzs5QjNCQj9CQT1J +QD9ERj5IRkJGRj5MRDpBPzpBPTpASDdIQUI8RThIRUA4RDhIQjpJTj5xX0ltVUVyV0dTST9Y +TT2gglilfmWVg1SXel6ZgVimjGmgfWCKb1uBb1F8Z059akuMdlORfVmafGKYflerjmqyl2XA +p3bGqm7RrH3MqXfUqn/YqHjVqXncqX3RnnXOlnLMl2nSm3PMmmvAjGasf1+CZFRKSEc8QjZF +REA3OTI9PTkxOzM5Pz8zOjE8QDkzPjI6PDsuQTU5PDo3PjlCPzk9Qj0/QTo8RDs9PzhKSkpV +Vk5UVVFGSUFBRjtCSDpBRT44Qjg0Pjk2QTs3QDY7RT06RDhASUQ9SzpLUlhFTkxDTkxQVVFU +X2ZTXVRbdGxwhY1riZtpdItRanxRXHNNaGdLaHRLZ2lWcYBeeYRYbX9UfX5VhI5TioxLholZ +i5JQi5VZkpVQjZJWkJNWkZpejZlRj5daj5NZkpVkk5NdlZdZlZZimJpUj5tclJpRjpdcj5hR +jY5cipJRhJFSh5JPiY5VjZJPhY1Sg5FRiYdRiI9Lh5BUhpNOjY9Vi5lLjIpVk49ZhZhgiJdU +kZJbiJpRjplaiZRVjpRVj5dXkZpWkJpPjZVWjpZXipFZjJZHiJRWhJhKiZNThZJLi45Wi5NK +io9YjJVSjphQi5BWh5BOjpJUjpRZi5RWj5dZlJZZjppYkZhXlJtajZhWj5dfk5lUj5dVjpdR +lZZekJ1Xj5pWjppOjZdVkZ9XkplcjphVk5RZkZhVlZpilqFVk6BjmZ1imZ1YkJpekJ5Wjphc +lJpYlJpXkZlaj5xYj5lXkJhXkZlZjZlWjpJXj5dUmJhck55TlJddj5lQkZdfkJhSjJlgj5dS +iZZZipVThI1Ph4xOho9Lf45EZ3A7Z3M8am4+b3dIeH5KgIpTh5VLeIxLgIFRkZNNhZVJfIpT +ioxVjplZjZpWjplZjZhTj59PgZJJfIpUiY1RjppXiphHd4lHcH9JfIJWlZlRk51dkaJTjJpS +hphOgY9RjJJRjZZelqBblJ9ck51XjJlShZRTgo2o1Kb+//j///////////////////////// +//////////////////////////////r///7////8//P3//P9//jw/e7w+ebk9+fV8cns/ezu +9+Xk8dv1+evr9eXr7N30+vH8/vX3//P5/eXg+9vw/ez9//33//P6//z9//z4++39//z7/+/6 +/vL7//z5/fH9//z///////3///v7//v////1+/blwsg9Q0A+QkFDST1ESj9KR0VcUUtTVk5X +UkZKTD9YTU1MT0lYTktFRz1EQT85QDA8PUA6QDI8Pjg/PTk8QTg6QT07QTY2QTs6RDw+Pz09 +Ojk+Pjc9Pzg7QEBNSUR7dVeghWedgWCjeGGWeF2ogWWtjGrHonvKrYPUsYfOsYTatYrXso3a +sYndrIvbro/VpoTWpYvUooPPlHrKhXPAfmOsgl+dglqliWKqjm2dclydf2OWaVh0V0laRTxZ +TERQRD5QREJGQzw/Oz88Pzc3PT48OjY1PDk6Ojc4QDk4OTg1NzM2Nzc3Ozc3OTU1OTY4Njo1 +PTI2OTY2PTI5OzcwOzY2NzU3PTU1NzUyOjY0OTI8PDo6PDY6PDc6PDU+QDg5Qjg9QTk7ODo7 +PTY/QT1DRztNSENDRD5FRkFFQUFERD5GSDhGQT0+RDpKQjxJST9eT0RhT0FYSkJ/YUOgc1aa +fVe1nHGbeWiPdU+0k2u7n3WujWymg2WScVeDZlF+aEiDa1KJcVKNdFmLd1mRe2CUgVyki2mw +mm7CoHbEqXfNqHzKoXnMoXPLpHbRnnPMnm/Gl2zIoG+6jnGwhmCNdFtlbGpOVV1DQz5FRUQ/ +Pzo6PT0zQzU6PjU3OzI7Pjg0Pzc4PDs0Pjc+QT85PzJAQEE5QDM9Q0E1Qi05QT9BR0VPTkhN +SEVFRzw7QD85Pj1AQTw4PzY+RDo9S0I9R0FDQ0JAQUFCQEM/TkNIS01ARkdLS0tQX1tdYWFe +dGZpf4ttkZ92jJtsi5x4j5tsb5FIXGZOY251o6t/qbKGpaljeYpTcIFVc3pTg4VMfYZLg41V +i5JRipRXkZhYipVSj5ZZj5lVmJpci6BNi5lZkppci5BakJxTkZVSkplakJlMkplOjJRVjYxa +jJNPjZNajJlTlpNSkJhTjJNYiZdVh41WiJRTiI9RiZdWiZRKho5ViY5Qg5RZi5RRkppYh5NY +h5JWjppPjppekppVjJdXjJFUiJRPkZFakpJRj5dZipVRjZZdippRio1YkJRQkJNah5VSi5JY +kZxRkJZSipNNiZNWjZBWi5NRiZZYjpFVjJVUkplajJJXlJhgmJpXk5ddlJhYkppdkJpVlZZf +lqBdmZpakZhXlJlWk6BXjphajplZlpZXjqBck5pgkJ5dkqBflqFYmp9blZ9XjJdVkpRblp5d +kZZXj5dbk5pWkJxTjJtVkptUjJdQkZlakJdUkZpelZpUjphaiZhPkJJdkphVipRXiZdMiY5S +iI5MgIxUiZBUipJHeI48ZnA9aHo5ZXFBb3ZIdYFMgIVMho9OeYtHfYVVjpdUhpVKgYZRjJFW +jJtUj5JaippNkZhah5tHf49QeohOh4tekZxMhJVLdopBdYBLgo1alJ5VkKFWkKNVkJpTiplM +gZNSiZJQiptbkZhdk6dfmaRTjZxVh5RZipqq1KL9//z///z///////////////////////// +//////n+//j+//T///////////////////////n5//Xu++fx++j8///p++vg+tf1+/D3+fPp +8+X3//X1+e/4/vz////1++3s/uvy++r9+Pn0/+/0/+z+//z///////v///72/+v1/vH+/vz/ +//////vz++/s/efw/+7y++j6//H///b4//ru09JGRUM8RTpJR0pWVUxaWlVeYk9bWFBQU0NS +TEVMUEZdU0xOTUZVRj9ARjg6Pjc4QDhAPzk0Pjs5Pjw/Rjw9RDlBRz09RDs9Rz48Qjc4PTc6 +QDY2RjlZXEmNZldrUURqXEl7a1GKdVCSc1WaeVysjGm3mGzAmXm9oHjEm3nGqXvUsH/dtoro +vZvnxJ7hvpzgw5fjwZrYs43UtYjUrIHKkX28l3HHlX25g2qtemWLaVGKb1R2VkdhS0NYSEBL +Rz1AQDpGQz44PzU9PDk0PTQ8OTg3PDI+OTk7PDY6Ojk2PDY5OTcyOjg5ODYyPjc6Pjs3PjU1 +PTQyOzU0OjYwOzY8PDsvOzE/OjkzOjM1PDYvNzBBPzsrPjFAODwsODM+PjgwPjc5OzksQDc7 +Pjk7RTU9QTtJTkFOS0lDQz88Pjs7RDVCRT5DRT9JRT5JQzlSS0FaUUB6XE2pj1yukXKee1Wc +jF+Yc1arkGjCpHDFpXzBn266l3KoiGefcl+EZU5+aEeCaU1+cVGGb1OEcFN/bVOHeFKXf1qi +hmKukWi0lm27n3XBnHO/knK7kmy1jmm4mG2zj2iqiGqBc2BcXlRNXWROUk5ETUJTVUpOTkpC +REE4Pz02QDQ2Pzs2RDw4PTw0Pzg9Qzs7RDdAPzk7QT06PjY3QkA6PDU9Pzo1PzNDREFFRT4+ +Qj83Qjk6QEA9Qz1AQUlASUc+UFA/R0ZBSkZCQD44QjhAQ0A5SkJGS0xNWFBcaGtdZ19ujJpu +jp5slJx7oKV4lKd8qKl1hZhHWF1rn5uJpqx8o6yDpaeDqLNid4pTbX5OdX1Rh4dShoZOgodQ +f5FUio5Gi5RZjZ1SipJelZxRi4xhkZpPiplXjZxViZlcjp1Nho9alJpXh5NZkJlTipNVkpdP +j5VWiZRXl6BckpdTjZhXk5pOkZNRjZNMi5BXk5ZSkY9Yh5NLiZFViphUi5RUhplVi5Bai5hV +kJVak5ZSj5FhkJZZi5NWjpdXipRGjIxWi5VUjpZXh5lYhItLjJFVipZVhZFVj5VYjplZiptJ +jI5aio5Oi5NakZdUkJRai5RVkY9YjpxZk5tYk6FajZRaj5dal5pflJxcjZdVkJpelJhXlJtj +kKBYlphdlZtdkJpZkJtbkJ1YkJ5alJ5enaFbkJ1Xlpthmp1al55dlZ9Wkpxfl6BXkJtilJtT +lJpVjplXjptXlZxWk5pbkppbkZlVk5Zbj5ldlJtak5tYkpxcj5hbk5xai5pTjJhXhY5OiY5R +h41PiY1Tj5VKfo5AaW9Aans+ZWtAb3pCdXpGfYZMgItGc4NHd35OioxPgJRLiYpXjZRbmKJY +jptTi5pTjZ1NhZRLeZBKeYRKgotUkJlThpRJeYlHeoVUio5alZxSkJpalaBcjZ1PjpdUg5JM +go5Pj5Vakp9YlKBclKhWkqBTi5dWi5Gh06f6//D///////////////////////////////// +//////////v8//z9//v+//v6//T9//b////////9//z6//P6//D2//fu/+D1/vfr9urd6tfs +/Obz/Ovw/+ny/+/y//L6/fL+//z9/+36//D4//H6//j0/+v4/+73/vP7/+34+/Lx/O/x//Dt +/+ry+e328+/+8/jw+fH4/e3l/uPv8OHc1M5JPkUzQDlMSklRUklaWUxgWVNTXE5STkxNTUVP +TVRTTktRSktFQD86Pjo4OzU1PjY5OzgzOzY9OzU0RDM/RD5IRDc9RD86QTU+PD03PTI7ODU4 +QDRwZ1KuhG2phmifbmB+U0VkWEdvZkqJclKWfl6sjWu2lm+4nne8lnW+nHXOqYHUq4fXsojX +uYrasorTtonYrZrUrJXfsp3WtJfdr47Fl3nRu5DWrJXIo3rDj3qeYVB9U0hjTkNVRz1GRDxJ +QjpGQj09OTg5PjY9PDgzODc0OjE3OTs2OTI4ODoxOi4zNzwzODA2ODo3NTI2OTk2ODAuNDY4 +NjkxPjc0OTczNzc2PTg4OzM2OTYvPTI3PDkzOzgzODUzNjE7NDUyPDQ0NS84PDMxPTA0Pjc3 +PTU0PDI/SDRDREJAOjs7Pzc3QDk6QDo+Ozc8QDRJQEBLSDleUUGOcU2fgFechVaPalKWck21 +lGuzmG+/qXPKroK/o3a+nnm8lm6tkGykfWOPaFR8Xkl1ZE1/bEx/Zk15Yk5yYklyYkhyaE2C +c1WGfVqXiGWbg2SbgmmYf1yYgmeMfF+FfGRbZFBJS1BLWl1MTWA1QDo6Ozw+SDtJTUc8RD01 +QTc7PjkuOzc2RDQ+PzswPzc8QDw+QTtFRkQ9RD9BRkQ2Pjk3PDguOTQ8Ojo3Pzc9QD80PTM8 +RDs2Qjc+Rkk8R0lCTF87SUZAS0c/PEE2Pjo7Oz47Rj04Rz9FUE9WYFlqdIBqipRzjJ9zj5h8 +k5t5laV9lKZ2laNqaopEa2SMrbGFqrSCprR5o6yBqquFoLNdeoFefIVWdYpXfodPgI5ShZJL +jI5ThZZTh5NTjZlWjZtPlZVWh5lVi5NSkZNVjJZYjZxVipxaj51Rj5NZj6JOjJZfhaFVjplW +ip1Yh4tRjZlUipRRiJpQjI9Rj5hZkJVLjJFUi5RTj5NWipdVkZZLjZNVjo9WjJJWh5JQhY9Y +jY5QipVXiJFSjZFaiJJJipdZjpNQiJlYi5tTiZVSi5JMjZZTjY1PkJJUiZlPi5RRipNakJpO +jJRViJdUj5BXiY5Wj5RXkZZVjI5XiZNUj5tUiI5WlJFakpxYjZlVj5pWjp5WjJVWlJpaj5pa +j5xYlJhYlZhWkZVYlZdcjJlVk5dbkppXlJ5fkJ9bkZxak55SkphYjplQjZVXjp9Sk6FZjplT +j5lWkJpTj5ZbkphVjJhTiJhTh5NNi5dakpxWjp1Ti5hSipVSj5dYjpVRhpJOhJBEg4pXjZdH +f4hQhoxCeoBDYW04YnM6YWs8anFGcXxCeoNIeo0+bH5Cd4BQjJdHfY5IgopSjJBTi5hWkJRS +jZdUjJ1PhZg/dYhGdYJIgY1TkJdPg5hDeoVKfYJLhpBcjJ1Wk5tYi6JLhJZVh5hIhZVRhIpN +ipdbkp9blKFfnaJVjJ1ViZdSiZaj1KX+//f////////+//f+//z1//b9//f///////////// +//////z////9///9//j////7//j2//b2/+7////////6//vo++Pj/9nm8+Di+Obr+eb3/e74 +/vz9///r9+/1+evy/fD8/+3z/+j5//Dw+e/0/unw8eXo+eXz/fH7//b9//j5/e3v9+T4/fj/ +///8//n+//v5//X///7//f3///Lr19VQQ0g7QjpKSEdRT0ZXV1FWV01cVk1QU0tOTUlYVk5Z +T0pOS0dCQzs/Qzo7OzkzPzQ/PDo4QTlFRD9ARj1KSUJBSEJGREA3Pjg4PTk3PjI5OzgyQDR5 +Y1Sqhmanimmlf2GdfWKXZVR1UkJxXkd8blCVe12ihmiti26xjGy0j23IpYLCoXjLqn/Oq3/K +ooLPso/ZtZTavZ7hwaXiz7LmxqvJnHvLtYnVuJDRpIXEnHa/lH6vcGWEU0ZkS0RXRj1MQT0+ +Qjc5PjdBQDk4PDQ2PTUxPDQ3ODc0PTI4OTkxOi84OjktNTQ7NzkuPTA9NzkqPDQ7NzYtNzEz +NjYsOzU4NTgsPTMxPTQyNjc1ODQ2ODU3PTc0ODU0OjM2NTQ6PTktPTQxOTQzOjMzOTkyOC80 +OTU0QDg2PT00Ny46Oz03PTE6Pzs5PTM2QDlHQzlFRTxuYUSFbU6GaEyDZ0WUcEusiGO+lW+3 +lm/Cp3PMs4TDrX3Dp3/AonG4mXC0jWOohWWVcFh9WEtpUENkUkViWUhqXEptXUNxWEppXEZl +XkljYExmZE9paFJqa09jYU5SWEtQTkhLUlpSW2VMWlxGUVg1QDo2QjQ7Pzw8Qzw9Qj83QjQ7 +Qzs1Pzo8SFQ5RTs1QTs9Pzg9RT1JT0FHRkI8Qz8zOzY0OTguPDI1OTg4RDg/QDwyPC81Qzw4 +QDg7SERGXFlCSVQ8Skw+Rkk6Oz44Qjw6RkI9QENGSUdMVVFrgod6mKN3laR1jaNslZ55lKV6 +oKt5mKJyjp9jZoJQeHeMrLWPvLaFprF4n7N/nKd/qax4f5hhiY9egY5UfH9Rho9JfIJQiJNP +ipFXkJZRi5lTiZhTkJlVjptTjJZZipxVkJlXjpNVlKBZjJRTk5VXkZtSkpValJpUjZNel5tT +kJBajZNLiZFSkJlOi45WhpFLiJRRj5Vbj5JNhZhWiZhXh5JQipZTiZNWkJhYjphTi5hZjJpU +iZZRh5VJh5JWiZhQipNTjJNUkJdhhZhOhZBWipdUiI5cjpdWj5RRiJlXh49YjZZVjpdLj5NW +i5ZLio9XjJhWj5dYkJJbi5FZjJpWkppXkZRgk5takZxflZ1Zkp1akZpUkplckJhUk5helJ9V +lJpilpdVlJlglqFYkZtal5halJ9XlplbkZ1YmZ9WkpxXkZpdk6NZkphZlJxZlJtbkptWkqBX +kZlWjZ1ckJdYj5RYipxTiKBQiZZXjqBbkJhVjplXi5BTjpdUjJRMhI9Qfo1Ki45XiZhKg4lL +gI9FdYVAZW5BaHE8Ym84Z3FDdoBDeX5HfYg9bHZHen1NiZFNeItLhJJQjZZUlppUjp1Yk5ZX +jZpPhZFGd4hGdoJJg4pWiZVMgpZDc4RHfIJLhZFXlJ1Rkp5ZkJ1LiJhQiJNHh5ZNf5dSjpZY +k51YmJ9ak6RalZ9Wh5hTjZml1bD+//b6//T1//T9//n///j///////////7////////1//r8 +//f////////////5//n6//f+//v1//j6//Xx/u/p++Pl/ePd+djr9+Tr+ejf69r6/e7z/+/6 +/fP2++zq9+T9//zz/+33//H6//b///75//P2+Oz0/vP9//r7/+/7//v//////+38//Lx/Oz+ +//r0//D6//P4//L1/+3s+93a1MpERz86RDhGRkZOUkpWUUtYWE1ZV05MUElRWE1bXUtRVlFb +VUdMRkNSSD9STEZSUEdSVU9bVlBMTUdSTEc9SkJUVERRT0dFRD41QjlAQjc6PDo6QTlxaVKp +hWWjf2WkgWKZd16XfmGee1+YZVl8VUhxX0yBdVCOdl2WgV2jiWW0m26+nHW/mm2+mXe7jWvA +poC/mnjHpX3JnX7Nq4bSqIPFmXLIpHnNtJDPqonLo3jCpHu4n3e6kHqXcGBzUU5URT9EQD09 +Qjc9PzgyPDc3ODUxPjI5PzY0Pzk2PTQwOzQzOTU0OzIxOjg1PDQ5PDgxOzQzOjQwODQ3Ojgs +ODE2OzcvOS81PjYuOTc7OTcuOjQ5PTcvPDQ4PjcxPDQ1OTMvPDMzNzIzPDM3OTU7ODc1QDI2 +QDk3PTE0OzY1PzczQDQ4OTo1PTE/QDRBQjdKRkBQRz1mUUNrVkSSak6lgVm6nWm8oWvVsYrM +qHnQsoLCp3nHqH/BpnnAoG+5m260kGeuh2alfl2haFSIUElzSUFwS0J3T0BoVEdWSTxJQkFD +RD1DR0FCQjxHRUM+Qj5UWWBpenlkdodQXmJNU2I/REg9Oj05QDc9QThATEJISkJAQT06Rz1M +WmVKW2o5RUUyQDg9RztKSUFERUFCR0I7Rj07Pz4uPzQ4OzsxOzM+QTo1QDg8QjoyRTk7Pj40 +QD0+RERBRkI7RT08Qz8yQjU7Pz87SD1FTkhKXlNegY1unJyCoqZ1lqFyjJp1l6J5nqJ3lKJ1 +n6h2jKNcZ3pgio2EqLSDqrV6oq1+oax7mqF8oKGNprNhhIRogYtff4xegYpTg45UhY1MjpRZ +jJlUiIlYjpZXkJJVipxUi5lSj5hUkJhTj5lXjY1ShplVkJlTiZRSjJRRjZVXlIlUl5RRjZRJ +iYpOh5dViZlKiY5NiZJPio5Xg4xOiIZPhJBOhYpUiJJRiZBRi5BRjotZh5JNiZNViI5YiJBS +jJJPiY1OiI9Qi5JVgZNRiplVi5JYkZlWiZlPiJdXlJlQj45VhJFQiZBVjpJTi5NSj45RkZRV +ipZWk5JYjZlPi5NYjJZTjZpcjpVSmJdckptWkZhfl59alp1YlJpakpdXkpxaj5pZlZZZlphg +kptZk5lelpxbnJxcl59SkZZhk59WlZdblJtalZhglZpUlplfkaBYlJhalZxalpRflppblJlW +lZlXk5pakpdYlZlUjZVTjpNZlJpVkptWkZZTjJZUjJVWkJRQhJFJgIhShYlRjZFWhpFGg45L +dY46ZmlDZ3o4aHBDaXc9cnlLeIZKe4dBaXJGg4RSh5ZJfopRkJRTiZdUjJlSjJhUkJdYkZ1O +hpNHd4VCeIRQiIZSjZtNgo5GdYRKhIRQiZpVjZVWjqFOi5dNh5xRipJNhZFShpVOi5lZkp5X +k6hdlaZclqRYiJxVipGj1rL9//b////////////////////////////////5//n9//b////6 +//39//v///////////v9//72//H6//P2//D7//rm++Ph+dns+uvf5tTe8tv///n5//P1/vXz +//P7++7p/ur5//f6//T+//Ly//X///j///j9//X5/+/9//X6//L6//v///X4+/D///3///fy +/+71/uz6+/P9+vL///vy49pLSEJFRkFETz1WVE9SWFBZV09NUkVKSkpLU0hgWFBZWVNaWFVW +Xk9kW1RWXk9dV09TV09ZUUhUUEdJTEBERUJFQz9LS0RAPjc6Qjk7Pzg2PjQ+PzxRV0KZe2OX +e2CjfGOVdV6ZeGGZfV6miGmui3CzgW+YZVB9VFBrWkZ1ZVWHdlibe2OigmepjGWlfWKsiWiw +hm2sjnG1iWzCl3m+nn2yim3Ipn/Uso7MqofTsIrDnny+lHGrg2mdc1yLcVd0Wk1VSDxRSD83 +QjlBPDc1OTQ0Ozg1Nzs5Pjw3OTY2Nzc7ODo1OjQ2OjgzOjY9OjgrPzI0ODYzPDgwPTYsNzQ1 +OzYwOzU0OzM3Nzk1OTI5OTs7OzU1PzcyPDQ0PTg3OjUvQTE6PTU1PDkzPjQ2OjY4Ozk2OTc0 +OjYzPTQ5OjwyPDY5Pjg4PTc4OTZAPT1BRjtVSD9lVECAaEmNglKshWK8kmrNqXLVvIDbt4jY +r4XKqnXKtH/Lq3nFp3e8oG+/nHS/nm7AmXHLqXPSr4LWr4XMm3O8hGalZFF4TkRKQzw+Oz88 +PzY/Qj5TYV9fcXxjdYFjfYRte4hVZ3NKVWE9QkA5PzgyPzg7Pj48RztBR0k/TkJSY2xXeIBY +an1HTFU7QDxETz5VT1NARjw7QT4+Qzk6PT01QDoyOzo2PT44RDw9QTc3PTs3TDo3QT07SERB +S0o7RT47RUU4QjlARUJGUEdYZWpigYh1iJZ2maWApq92o6Z2l6R2lJt3lqp4mZx+oqx3oKh8 +nq18lq2Qs7yHrbSDprZ1pKx/pLB6lqN5n6KFs7F7hZphh4tyk5lujZZagYxOhYxRhpRNg4xb +i5lTi5RZj5NWi5FajpNJi5JYiZdOgo9TjplUgpJGi5JXho5KhYpPgY9Og4pRhpRQiIpPjJFK +gIlFf41Oh4tNiZJRho5KiYhThZRLh41Ugo5EgYJSgo9UiJJVhZFPh4tSiJVTh49Mj5BVjZNW +jpRYiJVNiZdQhpJVi5hWiJdYiY9TjJVSi5hQjZNVipdNhpFUipJMi5FWjJVQiY5ajpROj5Nb +kZZVjphbjZZOjZlajZxWjJZVj5lZk55bl6JkmqFTlZ1ajaFglqBgkKBXkZtZk5takZZgkJ1b +l5phkpxXk5tek55dlJ9flZtbmqFck55bjptil55dlKFZlZtcmaBXlp5ZkphelptWkpxblJtc +kZlZj5tUjJNZhpRSiYlUjJlWjZdVjJhPiJNYi5lQiZZQgZhEfY9LfotSipRUg4tOhJRMc4xD +bG87Z3c+ZW86bHY9bXlCd4BGcIZDbnJIgINUiJZNhJFOhpVSjZlZjZxUiZlfj5lTjZtUgZZD +colPdYRLhYlXh5dLfotMcYdHho1PjJdRjaBYjptZj59QgptKhpJPgo1KhZNYiphXlZtimKZa +mKFbmqpajp9ckZuX1az4//D6//b///////////////////v///z////////////+///+//v/ +//////3///z4/vfv+ub5//H9//bv/en3//D3///t/+H5/fr3//Tw9vH6/+/t/u3r/u7y/u38 +//j4+ev9/vrz/e74//b8//X2//L+//36//P///n7//L///33//D4/vn///b0/+nr7uDy/Oz0 +9ez6/fH9//n7/+3n4tNHRj4/PUNYV05TXFVZU0tRUk1ISkA9SUBJST8+SD5UWFNaX1NhZ1Vd +X1lfW1FSVVRVVExLT0dRTkVFQ0I7QTs+Pjk6Pjk+QDxLTUBHOz4vPzc9Ozw9RTxnX09/b1SU +dF6FcFSMa1KNd1ycf16qh2mzlHi1lnyzjXWmeG2da2SPXFZ/WUp0UkxyWElqWkh6a1OSjF+k +hGegf2elfmidg2LGoITLpYXIqYPEr3/FqIO1lm+ximunkHGfhWyPh3F3aFxMU0ZLSUtDQ0o8 +QUNAPj4vPDk3PDg2Oj03ODc2OTo0OTc3OjkvPDI4OzotPTQ1NjkvOTQ6PDYyOTU2ODgvOTU1 +OTcxPDQ1PTUzOTY7OzQ4PDo3OTcxODg3OjExOzgzPTYyPTQ2Ojk0PDgzPTk0OTc2PTkuODQ4 +OTkuOTE3OT4wPjc8Pjg0PjVAPT1ARjpkR0FrVz6CXlChd06+lmXOsnvatIPZtoTYvIbauYTX +toLYtYnUsIXTqH/TrXzXr3/Zs4Xdu4Divovdw4zevYDdvYTcuY3FoG2se2thSkI9P0Q8QDZO +W1Vld31jfohidX5neodrfI5XZnBQYXBDSFQ8QDw2Qzo7QTw/RkNHUVdac35hfYRifIpddoNP +U207SD1HTExBSEZCQUM1Pzg+Qz41QTg7Ojo0Pzs3PTg0Pzk1Pzo2QUFBVFVDTmA/R0xCSEo9 +RkVGS05VXWpha3xpgY9ukpZ4oKaDpamDoq9/oLGCoa57oa14jqZ3nqN8nLF4oqR+p658oqiD +r62MrLeIqbSIn7N1n7GAqLB7l6J4mKOFqambpcRohYh3mJyJrbB4gKVYhopLhI5PiZJPiZRV +h5FKiZRTh5ZMiJVUhZJLhY1OgIxJgZNMhYxSgpNOhI5Mh5NNiI5LgJFPg4xMfopGfZROg4xK +h5JQh45MhIxUgI1LioxMgo9NhpBPhZJLgIdRiI9RiJVRiZNJho1Ti5RMj5ZVipVPhZdPgZZO +jphUippNjZpZkJlRjpZUjJ1VkZxXjZlQk55bjplZkZNYjJlPjJJVjZdQipdekJ5TkZZfjZhV +ipVhlJtglZhQkpdYkplYj5ZZkppdl59enaJalJ5gk55ekp9bl5pik5tXkZVcjJlOjphej5xU +mZZflJxWk5Zfl6Ral55il59WmJpblKBakp9ajZlUlJdZlZ1ekJxal5tblJtbl5dXjp5Zi55Q +iZRUjZlUiZZQiJFRiYdWjplVjJVUipFUjpBYiJJGh5BMfYlHgoRWipBLgY5UhZJHdIo+Z286 +aHM6Y3A/anhBcX1IeYRAbohFdH9RiJRQhY9QhJFRh5hWkJVYjpdakZ9bj5xSjphRgZVFc4lI +eIhQiZlSh5hOeJBLeYJGiZNUj5dWk6BViJ5TipxNhp1HfZRMfo9PjJFXjJpYmaRcm6hbmaNe +mKdclJ5bkp2X1rH3/+z///////////////////////////////////7///////z////////6 +//n5//f////////////5//n+///2//rm+unX/M7h+9nh9t3k8+Ls9uP49+zt/vP1/+75//H3 +/+7n+d3y/Oj4/vX8//b6//P8+fD+//7///H2//T///74+/L///7///n9//f///7///Px5uf9 +/vzy9+bq7N/j2tFLSEQ/Sz1fWFNUUkxaTk5GS0JCPz09RDxKSEM4PztLTExfYVZiYVlbYFRc +XVVSVUdUTEpLSD5LSEBJQDo2PTk+PzdAQjlNSUpZW1dgUVROQUM3PDlAQT1JSTxUTENbWUdr +XkpwY0V6Y098b06XeFuWg2ClhGSlflyzgWu3hGvBiXXGhXS8e3qxbWWpZWOuZmWqXFuhVVSD +UkpmUUCgh2DCon23l3SzmHaplXSIgGR2dmJocF5mZlpTYldWW1xQUFtPR09CS1JOSFdBTVRI +RlRBQEc4PT82Ojw2PDY6ODY0Njc5OTo2PTY6NzQ2Ozk0OTYxNzU8ODk3Ozo3Pjc3Pjg6OzQ6 +ODk6OTM6Njs8NzM/P0AzOS87OTw4OjM2Ojk9ODQ2PDc5Ojc1OzQ8NTI3QTY6OzcxPTU+Pz05 +Ojk5OTc6Oz47OzhEQjk+QTtLQT1iUEKDZVGYc0y7mmXAmXHGpW7Os3rctoDYvIvcvnzbvILc +vYXau4HauIHVtH7cuHrcuH/au37euYjcwITnx43fwo3atYjLqHXAk26JWVRGQT5ERz9kd3Vn +eoNhdXhnfIhpgo1rg45fbH1Xam9fc3tbW3peVnliaH9ldoxsfopnfohlgo9jgY9ab4BPXnI/ +SkVQT1NJSklERFA6QDk+RD45PTw9QDw5PTg6PTk9QUE8SkxSVmZddHxteYptdZBfaH1oeJRn +eYdwiJVxl6F0iaNylpSDpKx7pq+AprR9oqaEo62Enql9mah3oaN+max4m6WEprKFo6h+payD +pbGIpqyIoLd7nat/oLOEmKx8laCFqaiQtrp6gZNtmJeMsrCVrb5se5ZOhYpYhopNi49UhI1G +hI9TipJJiIxQfoxMf5FTg49Qi5RaiZJSh4pShZNPgpZRho9Oh5ZTko1Vi5RPiJBRh4hRh5JR +iZBYi5RUipNZhZhRjZFXhpRNho9Vh5hTjY5dhp5SiI5bi5ZUiY9VgpNZh5NYiZNViplUjJdW +j5BRipZUjppWkJRYkJtfjZNVkJFXiZRQjZFSi5NRhpVajpNYjZpci51Tj5FZkZNUkZldi5lW +j5xfjZhXjJphkJ9VjJpZlZhakZxglZdak59flphcl6BfkqBgkaBhkp9fjJ1clJZik5xjlp9z +nqmPsL2brsGHqryAobVmn6lij59bl5xgkqBblZ5fkJlcmaBclplWkJdUjphXj5haip1Ti5Rc +iJpKhYxShJRLiI5VjZdQiJRSipRXjpFXhI1KgIxMe4dIeopQg41PfoZSg5RGdItHZ3E/ZnE6 +Z3REa3NGcnxKeYVIdIRJgIRWjZROhI5ViZVSjZdXipNSj5JckJpVj5lbjZ1Lfo5IcIFKf4ZV +i5dQh5NIdoxLfIZRhpBVip5XkJxbkqVTh5xNhpdQgphMeY1Mf49Vk5hhmaVflaRglqBelKBi +l6dckp2X0rP6//L///7///v///////////////////////////////////z5//n1//Xz/Or8 +//79//b5//X+//X9//j7//T5//Pl8+Lc6dHg793q8+Xr9+L5//L9//b9//T4/+zw+/D5/u/4 +//L5/+Lq+en4/u36//Lx/+n5/+78/u78//P7//T3++/8//Ty//P///v9//z/////+fT5+O75 ++/H9//z/+/lRQkA/SD9TVklXVkxTTkVRSz88QjpBRUNJQz1ERDtEU0RdYFBZX0ljV0xXUEVN +Sj9KRkFIQT9CRT87OTc1QDg2QDVKSkNcXE1eZFhlY1ZcYFVXSURBRTlJTERKVkpYT0xVUUCA +XFODYEeFYlWJbVKheWCyhmrEknfRqYHZt5fXvZvivZ/cr5bSpYvUp47Qp4zUqpTIoYesbmFq +UkiBf2F+eGZobVplZmBTWlBRV1hMWFhTW11RU19PUFpLVFxRUGBHT1dJTVpDTlxLTl1DT1JC +SVJFT1Y7RU06Pzg1OTMyPDg5Ojk0PDE0PTAzPDU0PjcyOTM1PTQxPDU6PDcxPjQ2PTgsPzEz +OjUuOzE6OTk1PjQ6PDotPDVEPTUvPDA6OTg2NTY4PzU2OTQ6QTU3PTc2PDI3QDUzPTYzPjc2 +Ozg2OTI5PDZDRDhFQz1WSjtcTEBhVT2DbU6rl1jNqHnOqnTKpnbVtnvZt4PdtH/TuIbTt4Xc +vYLbuofYvn7cu4LduX/lv4rkwIzjxJHoyo7gwYfQsXzEqXS6mnOSblpgTEhWYVhmenxifoBs +fotkgYVrgYptjJFkcIFVcXdheYZhgIVofohpg5BqhZFkgY9cgIdkhJRhgYxgfI1OXWhAR0lL +UUxLUUxCSUk9QkI6PkE3QDg9QD85QjY6QEE5R0BXb35jdYFqjpVxkJxjfIVvjpN8lKJ1kaFz +kZ99naRzkKN3nqh/qKyCprN+qLF5oa6Cp6iCqal4mKJzoqt5oad9nad/oa9/prSAo7GEqrKL +qLGFpLSBnKeLqLGBoad7l6Z+p6eSwbuSjaVkjoiAubOYwMSClqVffYtLi4tXiZJRjpFZjJNW +ipFXh5VPjopRiJNVjJFRiJ1OgpFTjZVSgopNhZRMhJVQhI9OiJFThoxPjZZOipZPjppOg4xK +jZFXkI9SiZJViZlPioxVi5VGh5BXiJBVjY5UkJhSipJVj5dSj5RUjpJSiZBYiJNTjJRRipVR +iJZSj5NUiZJYk5hWiJFVj49RiZVXhpJRipJMiI5Ri5FYipNOiZBThZdRi5BcipVRj5BXkZRW +kY9aj5xVjpJUh51TjpZakZhakZtZlZ1hlaBXkZ1akptajZhYkJhdlZ1dmqCBtbSGurhttql+ +wbyh0ciGvL6At7d3vq+Mpb5XlZ1ik5xYkJdhk5xdlZ1ajZ1Xkp5XiZpQi5dTio1YjpZZlJZb +jptNhpBOhoxSi5JRhpRTjZJRhpFQhI9LfItMeoNNf4VShY5KgYpNiJZHd4M/Z24+ZHA9ZW9B +bnhAdYBMgINBcX1NfYRQjJBPhpBNiJFRjJlUjZZTkJxVkZ1Xj5dRiJdDdo1AcH5NgopTi5NN +hY5KfoFMg4ZPh5RWjJhckqFYlp9YjZpKiZhMf5ZJfJFLhY5TiZZanJxfmqVbmaFdlKNXl59f +naKS0rH+//b///////////////////////z///z///v6//v////9//z///////////////// +//////v9//T8//z6//T2//X1//bt/+L0//Hw/+bl8ejx+eXs/uny/ez1/+v7/vf///7///// +///////u/OTm/+fz/vP+//35/er5//b9/+/9//3/9vDt/en6//Py+er+//3y9/X///7///f6 ++eHY18hISUFAQEFSV0ZXT0tVT0dJRkA9QzhBR0NCTD9EOjxCTEBcSkJbSUJZRkJOSTxLPj1L +OTdCPz8+QTo5Ojk8Pzk/Rz1ZYVVeX1FZZVZfZlNfaFtkZV9dY1ZkZF1cZ1taWVJfXUybgmeg +fmaXeGCdfmWyjXKzjnLImXPIrYHZtI/Xu5Dhv5fXtovQp4XIq4HMqovMpYa8nH6WcGJWW1ZV +WVlQVllMWVpUVmBQVV5QV15OXWRXWGZIW2NNWGRMWmVRV2pHUFxJT1pFV1tPVWRHUllHUl9G +UFxHWWVDTF46Pj43R0k5Qkk0QUEzQTg4QDw1QT42Qj85QTwrPTY3PDkwPjM1OTo2PTU8Ozwv +PDU5Njo0PzU7PTgvPDFAODgyPTM6PDUvOjU5QjU3Pjg0Qzk4Pjg2Pjc0PDcyPDQ1PDg5PTlC +QzlJRztTRzdSTD1aUUJ1Wkl9VkaEWEuVd06/o2rQsn7Pqn7QtXXZu4fdvofat4jeuYLdu4fe +u4HgvIXmyJbozpbsxJHozIjjyozdwIrStX3Iq3bFqni7nnCVel9oZWZhcm5yhYtogItvi5Rr +h4t0i5BuhotmeIhUcHhsgotmgpJqhpFhgJBihIxoh45sgo1kf5BhgYlkeoxNXW9JU05ISklL +U1FHUFVCT1U7RkM3RD00Qj8zRTtDU1lVZ2lnhZdwipRngotyhZlth5t4mqGEo6t0kaFvl6Z+ +pa54maR6n6uEq6yBqbJ7pa6AoKuFq6uDobN6l6B7mat7pKd7m62Aqad7oq17oKF8q6+HqK2F +n7WAn6iHq7CHpbB6laOBo6SLs7aTo65uf49soJOTw8GSqbh1hJtLfX1QhIlMhItXipVbmphQ +i5NPjJNTipVRkJFUjJdSko5ZjpdSjpNTlZlUiplWk5RWkZlRjpVOjpJSkphOkplWjJdLiZNa +kZJNh45Rh41KiI9SipRRioxUjpRRkJdPjJlOippZl5BVkZRWkZZMiIxVj5BYkZdUjJVUlZZL +hoxSjI5Sk5JNj49QjI5RkZVSipJPj5RZipFPiZBRhpJRkJRWj5ROlJtejppVkphfkZ5WkpVc +k5hTkJRalp5ZkZhdk55dlplXlaBdkZpamZpfl51ol6Bkm6FlpKONwsCHwL2cxcluq7GX0seb +zcae08h5pK6AwLWUzMCOs8Flm6pWmp9hlJ1VkZxgj5lUkJpbk5dQiZNPi49YjJFRiZJUiJRM +gIdOgolMhYhThoxNgohRiI9NiZBKfYhFeoRHfX9RiYhMfY5IgI5CdYI9Z2o9Y2o8ZW8/bXFB +cXxLdH1BbndJhIRTjpVSiZdRjJNYjJVRjJlajZlOhpNVjJhQi5NJb4dCeYFPhI5RjJdYhY5K +fYRPi41Si5dZkaFXl6NWk6FXjJpMg5VMf5BGgo1SjZhWiZhTlJhelqFYk5xdlKFYmJ5hmKOY +17P7//D///////////////////////////////r///////////z///v5//j9//j////8//36 +//X////+//z8//js/+fn/+Tf/9jy/e/j+t7w/ej5+uzx/vH6/u3y//f///bt/ev1/uPq+uD2 +/ev7//f///f1/+v2/+/+//3///X///Po/uD5//D6+/j9/vb2++7t/ejw/uf2//L8/+7+//Tq +5dpPSEhCRTlUSkRKSj5NRj1KRz89QTY7RUBJRTlDQkBJR0BdT0BbRTxSRT1MQTxEQzg+PjtB +QTRGQT03PzVARkNTWE9dX1RaX0xiXldeZlJpa2FubWVub2ZtcGNlZVxVVEpfWUyAclaPf2KP +dFeZf12tjHC7jHPCnnnGq4DRronUuIjVuI7ToonLoXjPqozSsprHpoWdhnNtZWhZYmVWX2ZN +XV9UWmdNXWNXXmtRXnBQXm1TYW9SYWxRYXZQYmxPYXBMZHFPWXBPYmxPV2dJVWBNY2hIVmpK +WWlMVGdBSlhbbnlUcIBkaYlGVHBMUm87TFxES1g8Sk09PT43PDk0PDU4Ojc4Ojc5OjgxPDM0 +PDc5Pzc2PDYxPDszOjM1RTk2PTA1PDY0PjMzPDc2PzQ8OD43QTg6ODwvPzQ4PD04QjVJRz9b +UD1mUEZuTkhrUEB5V0KPb0infFquiV+9lGrEpGvOp3nOp3LQr3PYt3vavH7kwYjowo3mx4nd +xYHox4vmypLky5Texovav4PYtYXWs3rNrHXDpW6vlWt3cWRmeHxvhYJ0iJRrho9ufYxrfoVt +iI5nhYtofoBieYFqhYpxhY9wiJBth5ZogpJri5Zth5JtipBqgIplfZBNVmJMUlJOVEpPYmVV +XmlOV2NBREVDR0VESU9FUlNWaXFdfoBzmKZzkJ5zipl9nJ17n6eFqaiGprR3o6h0lap3nKd6 +mKd9nqWHrLGIpbF8pLCBo7CBrKyIqbB5naZ5mql4m6N4nquAq7WFrK6HobB8oqeFp7F+nq+B +paqHr7CLn699nqCBn6iEt7Wjvct5hpdejpZ5tKidwMaOl6lif4tMhIRUg45PiZJVipZWipFM +gIlMiIxRiJVJjpJVi5BMiopWi5lLjpJdkp1PjpJWiJxTj5daiJlKjZlSi5hKiJRYiJlUjZhS +kJBZjZRRjJJQi5VViZRRgZVUjopOjptMio9RjZFYjZZMkJVbkJpVjZRXiJlRkpVYkZNUkZNh +lJ5VjpNThpZUjIlZi5ZSi4xTjo5WiZJMi5JTjZhakZRUipVVj5BVjZdUkJNYiZhZj5tdk6Bc +jZpYk5RilJlak5hhmJpZmJxekppYjZlfl5xamptinqWQzb+HzsCXyL+PxrtqpaVhn55ioqNj +o5xluaOP1L2a08aJv7aJqrldnJZck5Rbl5dbkJpVkphYjZlRkZhThpBQiY9Ti5JVipJOi4pL +fIZQh4lTh5NKiIpRipFOgoVLf4pHc4BFen5Qg4hJhItLgI5AcoA9YGs4Y2s8anFEb3pHeYBE +cYBBdXpLhI9TjJpSi5hajZdUjZpTkplTjJpYkJhYjZtKf5hFcoBCd4JRiI9XipVJfo9Lg4pO +i41Ujp9SlZlamaVRjJlUhpxGgZVKfY1IgpJbkJpckp5bkqBdlp5ck6Fak6FamqBboKab1Lb1 +/+3///3////////////3//X5//H+//z///////////////r////////////+///2/+/6//Xp +/efv++bu++j6//Pl+ufh9NTu/enw/uvp9ufx//f3+O3z/vH4/vL09+rz9ej9/v7///X4//v/ +////////++/y/vH98/L5//f8//L9//r4/vH9//r///7///////n27eb5/fT9//b4/e7q4thJ +RD09PDxESDxNQ0FMRztKPj5DQztCQT9URUJFOjtFQUBUST5PRT9ORThGQjhDPjo3RD1DQUE/ +RztIQkJPVk1iWVRUWVFbWlZUZVdeYl1fbF1ucGlubml0bGRhYldVUE5PT0duXk+Ccl+AZVKI +dVimgWevjm26l3vBonzLrYfKpoLFpH66pX+qmXaYlXKFiG5ydXBlaGpXZmldaXJRYWldW2lW +ZmpOYG1QXGxTaHNSZW5UYW5candVanpQYnRUanVaaoFYbn1WY3lMXGxPZ3dVbH9SYXFMWm9L +WWdLXGZVdXpigItdgI1gdI1aeIxdbYtRYXxUWXg6QFo7Pj0vOjk1PjYxOzc3PDQ2OzkzPDg4 +PTk0ODc5Pjk1Pzw1PDY6OjY0PDQ1PTg1PDc3OzwzODQ6OzozPDY8OTo3Ozg9QEFaVj90XE1/ +YkqEZFWHZ0aXaFaedVe1iGW4h2moiFjBoG/Cm3DOqWvRqnfcv4Hfxo/lyJPjx5Dnw4vnx5Dm +xpDkx5Tev4ndu4fSuIHSrH7NsHvMqH6+oXWTf2xpbHBtf4pkhIhsiopqgZBqgIlogY5phIhr +fo5jg41ufoZog5JshJJsiJNwhJhog5ZqjJRvj5NriJRoiJVgcodLVmJKTlNLUF5ZXV5neYJo +fYpfaYdQXW5OWmhSYXBRbXRlfpRtkp94iqRwjZp7mql9pKKHprmHrLF/mrFxkZt1mK15nKV5 +nq+JrbWGrLSBp65/oLN7oKyCp7V+m6lynKF8m6eIpbCBsKyPsbd/o62DpKuCpauBnK2DqbGO +rrOIqrGCmKR8oqCQtbmbyMOTnK9dgYBulpqGvLeJorNje4pbdo5ShYpPio1Rh5dNiJFPiJRU +iZdMhpFYiJVSipJVjpNVipVXiZJPjZVTiplVk5xXkZ5Sh5JcjplUkZZajJdVjphhkZFRkpNR +ipFRiZJbipRVi5hRkJJVh45YjJRaiZ5VkY9OkJdZj5JTi5dXj51ajJxbjqFZlJthjZxShpRa +j51SiZNYjJxRio1UhZdRjpBYhp1SiYtYipVOh5FUkJdTjZVPipNZiZdUlZZhlJtgmKFYjppZ +kpxUjppZjZpflpxil6Jelp5jmqJhmqVmlZ5qta96vbSIxsGTwLlcoaZnm6RblqBhlZtimJ1g +m51fpKGQ0L2Xx8SFwbVpl6lXjplVj5hWjZhXjZpbj5lYjZdTiJFXiJNMiZFUiZJRgY5KeIVO +e4RNg4tJf4NRgYNMhI1EdoZFdINIdX1HgIdQe4lEeItAboM9Y2ZAX246aGpJbXZEdYNDZ4I7 +eHNNh5VTipZSh5dRi5hSiZZMhpNTjJdOjJlRip9IepVEcHZGfYFRiZdakJpJfJFQg4tSi5Ja +j5tbkKdSkJ5YjaJKippLe5JFeY1Rh45SkpVcj6FVk51fkqBZlqFilqZdlJ1nnKWc2bj9//b/ +//////7////////////////////////9//r///////j///////////////7///////////// +///////////s/e/m/9/0/O3s+Ofo8uf5/+/v9Ovm8+nw/O36/+/6/vP5/+/t/ez1//Lt+ejo +9+H0//T+//P4//P3//T4/vX///z//+zx+fD5/+77//n7//T+9/P29eTx/ev2//Pu2NdERkZA +QjxOR0BBQzlQRD1HRjk+QTtCRz5USEY/PTlBPz1USjxJQDdKPj46Pzs9Qj8wQzdEQkA/Qz1U +UE1TVElYVlFTU0lYVFJWWVBiYlljalZjal9obGBmZlpbXVNOU0tXTUpTU0VuXk92Wkt9Z1WW +fmKfgWSkgWioj2+nkHGUiHiEeXRucWdoZWpcaWZhaWtbZWtbZnBWbHRdaG5VYWtUbG1UaHJW +am9WaXVXaXFWa3FabXZYbHhXbHhXa3tjd4VofoVjeIdcbXlRaHVZc4Baa4Fab3pRanpMYGZZ +dINbb4RPbHtVbnZifo9hfo5cfo1heYxffIRXbYBETGM6PUYzOjY6Njs0PDk4PzsuPjg2PTox +OjkyPzk8Pzg2PDo4ODo6QDk3PEA2Ozg3Pjk1Ozw4PjsuPDk6PDcyQzhASDtYWVBralOHd2OY +gmWfgmGzk2y9kXDGpXfIoHiwgV3BlG3FlGvOqHDKo3DftX/fxYzkxZPoypHqzI/nzJPlxZbh +x5LcvIbZuofRs3rMr3fIq37Cp3SpknBudF9sg4tZaHlESEw/SEVJUE5afHdmgYxkgIFof5Bk +hY9pgoxogItrhI9riZRwjppripZ0kJh2i5hphJFrhpNaa3xOWGNKVl5QYWhidYJng45ukZpj +fpRoepJjg49lco1UcHpoi5ltk5l3nqRylZ98oK51l6CBqLaBp6h/n69wlqB1lal4oah4oayD +rrSGqbR5n6h/o6x9q7SEq7CCoK54l6J3oKqEqrGDqquNr72ErraLp7V+oKmHoa6Br6+Rr7aL +praDm6t4oqeNs7eWwsSYqbdkcoNcgo5qjpZ8p6d6jaFif4lUd4NSi49TiZlSjZVVi5NRiplO +ipVTj5lNiZJRhZJSiI1WjZlRipVPiJtTjY5Vi51SipNRjJtZkZhPi49SipZNjZJUh5dWjIxY +iJhSh5NYjZRLiZJVjJVWio5ch5VPho5UipVYj5NQgpZcjJRWkJpbipJNi5Zai5NSi5RajZdV +iJZUh4xRhJFWjJRTjZdUiphYjJRRiZNQjY9TiZBVjJdRj5hai5lWkZpck5hZkZpYjJ5VlZla +jZtbj51jnaKUwL6ovMmErL5+rrSKsL2ltb5wpauIv7x6qLFloKdxp65mm6dkm6JvmahllqFm +m6Rtu6d7obNxs6p4pLdkl59rnKlclZlgl55ll6JdjZpQiJNWiY9RiY9Yh5VOgo5LfIdPhYlS +iJBMgYhRgopGgYdGdIE/dX1Hcn1Hh4BSfYxIdoxFbH83ZGQ/YXA3Z2hCcHxFeYJEZXlDfHpT +jpVXjZZVipNOiZdLgZBSi5RXj5tWj5lNiJpGdYtGbX1He4JYi5VRiJNJe4lLho1jmJtSjJtY +kJ1Ri51dj6FJg5NPeo1FfIpTg4lSkpZhlaVXmZxbl6VbmqRem6NematfnqeO0rjx/eX+//b/ +//////////////////////////3///////////T///r////////////////0//P2//D4//P4 +//7u/+7p/ujr/uDv+Obw/urr8+n6//f8//X9//35//f4//H1+/f+/P37/+/9//X+//P///z7 +/+/8//nw/en+//v9//T6//P+//z9/ff18+78/fD7/vX7//b///v3/+/49+fe2MdLR0VCPjhK +RTxTSDtRQz9GRjs/RT5FSDxDRDpNQTs6PTZQQjpBSDlQPzo9PjdKRDc9QjhFQTtJS0RKTUJT +Uk9OVkpUS05TVk5iXldfWU5jW1VaZ1RnY1ZbXEtZV0xTVUpSTktLSUNQSUFRTUhWUkhiWlFi +XlBZYVJgYlFja2dpbWtlbXNiZm9XYWpZZ2lXZmhba3FfbHlhc4BhdXhkc31ebXdgbn5Ybndf +bntTbXdZb39Wbnhba3RebXlieYJnfYlneoZfcn5YZ3hhc31ifYpmfIlnf5FmdpFbZH1Pb3Ff +fIxmfpBaZ35aa3ZacH5Yd39geH9kdYdlfI1bcYdJT2o2O0FBODw2Ojo6Ozc3Pjk9Ozo3Ozk9 +RUI4RUg+PD06Pj87QDlARDs5SUM/SD4/QD83Pjs+QDw2QTlDPkNFTUhYWGRidHdzeYJvfYBz +cXuNl4DFsoPNt4DTpX+8jVzWsILasIDdtYPfuovdvYPcxIrgwIbqypHmz5bixIndvYbdwYza +vI3Vt4HSuIXOrnbKqXS7oW6LdmRxgn5mcYRcbG5rbYRlWIRGQ1M/RT5UdWlriJBxhZRlfXxp +f4lvhYxugpNriZNzg5FtgY9ui5F3jZdyjZdpgo9dbHhVaXRXbHhcboNsh4xxkZtqiJJmkZ91 +jZ9tkJ5pgY1jeZNghYxoi5dzmZ11kpx6pah+m6h+pKeEq7R/pKx2lqt1oaV2m6F4n6p8qayH +rLOCprCHqq+GqKyErLKDoq53mqZ9o6mApa6Gp7KLr7aMs7SJrLCEpKyGqbGKr7eQuL2GprN6 +mqWDqauLrLCUurKltr5wgJBbgX1hiI5wnZmJuLV+iJhddYdUd4BQjZBRjJRRhJFUhpRMjpVV +i5BPg5lSio9SjJBVjZdVhphTi5NXiJNRjJBgjJRRjJZVipZVjY5YiZZRiJFYhZRUjYtYjJha +jIxUhphPk5Jal5tXjZhejpVOiZRUjY9RiJtViZZRjY1WkJJVkZdajZRTkJhViZdGipFRh5VN +h41Yi5dLi5FZi5VVi5VbjJNMiJBei5RTi5BYipRUkJJej5hWkJlhi5Zbk5lTkptVkpVbkp1j +lpmU0sfd+eTb792R0Mbl+eTc9uCczMjT89rd8uSX0cbc9OLf9OOz0tTa9N7f7OGfzsXg8ePV +693C5djj9+S00tfM8drX7t6Zx8Pd8t+0zs1Xk5tYjJJNiI1ZiYtTiY9ShIxMeYhJfoZVjJJM +gopThY1JfYtQdYJDdX1Td3tMgYJUfYlGeYhHbIM8W2RBYWg9ZG5EdHNOeIY9aXRKfoNUh45X +jpZVipJViJJPiZJTjZFTkJ1ZjpxOgpRBb4FEc31KhIJViplUgIxPhItcjpJckp1dmJxdl6Rb +jqJTjJRTgphJe45Od4RVhopbk5pdnaRgmalgmqhflKVenaVemqRhm6CQ0bX+//b///////// +//////7///////////////////7///v////////////////5//r1/Oz8//j////9//3m++L2 +/er3//ro/dj0//Xj8t3e79Xz++n3/vTt/ebt/ef4/+/9//Du/eb5//L8//f9//z///77//X+ +//T7//v7//L89ev0++32/+3+//r///39/eru++n6/fL7//L2++X2/vP98PJNQ0NEQztARztS +RUFNRztKQkA/RzRIQkA7QDREQT47Pi9GQz5DQDZKPDpBPjk6PDdDQDxBRT9MTENQTEVPVUxS +V0tTTUlWVk1dU1BbU01eVk1cWlFVWFBcUkxQTkdSTUpQSkdPSkNKSkVVSktMU1FZVVRYWV1a +V11YVmBaZmxdbHVabHdYZ3VTYm1aaXVWa2tbcHhhcXxgc35hdn9neoNmfIZgcX9gcHxca3db +c3thcHpfcoFdcn1jdIZne4ple4pje4dab35gbXVgfYRqhZBphpZziJdmhI5rhZdcdotVan5a +fH5edYVUY3RRZ3RMYGxTZnFTb3hfdn1bdHxSX3U/RVM9Nz86Ojg0PDU+PDY3Qjw6Qj9DU1BA +RlI+R0Q9PzxBQj07Qj5CO0A9RTpBP0M8Pzw/Ojk7Qj1GR0hUYFtXW2VhdHlwfI5mandmbHhv +gnyJkomhm3nFmm7EpXHYvYfhvojix5Poy5DkyJTgworpxZPlx4nly43dwIbmvYzbvIfbu4rW +toHWsX/Nr3zHp3eqlHJ1cWphf396g5Vne4pxi5J8kJxsc5FOV2xEUE5efXJsfolqgotuiZRl +fo5pfYZphpBrgIpriY1tgZNshYl0h5Rkd35ld4hkeoZnf41pfpBsiZlfeoBvmaR8nqd2l6p1 +kKZsi5Fsh5xab35khY1viphskJd5pqiAoLGAoq6Jq7WIqLZ3n6d1n6p2nad5kaN7paqMrbmB +p7CGq7OBpaqGpbKGpqt8l6V8prCIpq6CpLOEqbOKqbiDrLOAoq6DqKqMsreYtL6JpK18oaqC +qrCOtKqUurypysmBjZhheIJkhYVzl5txj5V2k5lug41ZcoZWeYRSh5RYiIlSi41WjZFYi5JX +hpNTj5paiJNRjJVVi5JQkZJYh5dViZNVj5hSlJVVipNakI5RiJhRi5ZTiZZYiolLiJZZh5FE +iI1ViI9Xi5VciZVOhJFUh4pSgotUjpJRho1RiZVWhpVLiZJYfpJUjItaiZVPiZJUi5JJhoxV +h5BPiZBPhZJUi49Zio5Xio1TiI5SjpNXhZJRiJFYjJNVjZZTi5FVipZbj5dTkZlek51hraTI +8drY9OCcwsbC8tPg/ea75NPI89vl/uPM39m06s7o/ufB4tnM9N7l/ua73NfT+Nro/+mv2M7T ++d7f8uPC69Tg/OScy8nF7tbO6NtwmaZbjJNZjpZUipJPiZBXjJdMhYhQgYpJgYhWiI1RgohX +gohIeohNcYI/cX1Gd35MgIZRf4dMeo5Eans6YWk+YGdEZWxCcXVFbXxCa3BIfYFVj5BQhpNR +g5RLiJFViJhSiZNZkZ5OjJdQe5A5aXpIdH1LiY5ciZpIfYpTgY5Ui41bkpxcmKJZkZxajJ9S +iplQfYxGeIZLhYpTjZVelJ9dnadfmKNim6ZdmqVgn6pgm6lgn6d8x6b3/+X+//X///3///// +///////////////////////7//T+//T///3///////////////////7z//D5//P9//n///zw +/uze+dLm8+Ls9uH2//Tx/Or19fL29+7q/fD3/u/z/PT08efk+OHs9Ovt/ej5//Pu+ef1/vLz ++eno/ur8//j5/+39//f7//T7//P+//v///319+vx/fD///L5//Hx4NxHRUM6RDpGQD1NQTtA +Q0BGQTkzOjVCQDg6PDo+QD02PTs6Ozg5QDg7QTM3Pzk2Pzs6QTw8ST1FSUNETUJJT0ZJS0VP +TUpMTURTTUNSTUFVTkRNT0ZPSUNHS0dMSUJETEZHRztGSUVESUdJUlVKUFpOVFxQWF1PVVxP +Vl1UYmpYa3VSanlaa3hOYnFYb3hYcHhWaXlbdHpidoFZcX1jdYFfeIFlfIxedIRgcodebnxZ +c31ie4JjeIZoeIpmfYtjfohgeIZXbntid4VkfohuiZdxiJdwiJ1niJRugpVggophfYxYb4hQ +XGxMamRObGc/Xl1IZVlXc3pdbotSboFabYFRaXhNY3RNY3FVandGT2tGU2RGVW9HX2lDSFQ2 +QEA2PjczOzo2QDlASUdBR0U9RUw6SUk6P0g+QD1LSVpRWmFbZHFXgWx0iI9cen9ugIxrg4tx +iIR5fIaPmHqxlm/QrojRvYfhx4zmzZnozJ7fw43lx43jzI3hxYviwofixpfav4bcuovOtXvJ +rnvCq3aqo4aBio9wdYaBl599jJxvhpR+m6l+mqhtfY1ziZ9ZWHc8Q0lEWkxbentkhY9niJVu +gY5vh5VsjJduipBsh5pthZRvio1qhpVuhpVlipVoipNXeXpjg49tjaJvjp1tkaZvmqJ2lqVx +maRyjqdjd45TcnxgiopsjKN4oaSDprGCqa2Eq7SHqbJ3nap2kqx4oKhwlqhwm6CDqbN9payH +prmBp7CCprSCqa1wlqWCqKuArLCFq62FsqiPuLeGrLF+pa99rrGOubuivrqKoad/oaV7oauM +r7STtbiiwsKMmapke4BTe35jhYhljZNtkJ5jfYlefYdWcolRgYNRhItMhZJThpNRipJYiZVM +h5NVjphLkJJaj51QiY5TjJVNiJZTkJhMjJNZi5NPi5VUi5dTiZRKfopOhoZUhpBRhJBRh5dP +gJZSh5RNh4xSiItRh5NQiZVGhY1TiJdRhJdTiJJOiJFViJdLjZJSgZpNjZJQh5ZKiI5UkZVH +iI1ViJdSipZUiZVUiZdbjJNSh5FUjpRZipZPjZhYjp1YkZpTiJtWi5ZWkphalZhluaR1yaxx +u6x3zbWP4rmT0r2A1rer7dCj6M+n482y9dG96dea38fA+Nmy2syh4MnI+tie0Maq58rH892L +ysC/9tiv0M2b4b+h4sVqmqBXiJNTioxTi49WipFOhotTiI5DfYVMfIpFeIVQh4dLhItSg4dF +eopEboE/a35Kc39FfohMf4lKfIdAbn48XmI7ZWw5Y3FAd3dAYns7a2pJf4dPjJVVipZMiZ1M +ipZQjZxRi5RWjplUhpRGc4s9anZNfoJTjZVShpZOhItShpZTjZtTi55YlKFUlJxXl6ZKgZhK +eZNEdoZHf45PipVglZ9ZlaNhmahcnaRdnKxgnKZdmqdfo6WAvqz9/+L///////////////// +//3///7///z////////////////////+//z1//X5//f+//v///z7//39//j9//j7//zl+Ovd +8dTr9+ns9ujl9OD7/+zy/+37//r0/+v8//bu/+T+//3//u/3//f+//T0/+f4/vH9//T///v1 +//Lz//D6/vL+//v///X6//r///X+//r08en3/vb9//Ly/+zi38xIRD5DQDw/RjlIRDhCQjtL +RTxGQz48PDY8Qzg1PjM6QTg1QzI+PTc7PjE8Qjg3PjdFQTpCRTxERTpHSDtIS0FKTkNOR0BK +RkBNSz1LTEJOSEFHRTxKQzw8R0NJRDpFSz9KSUA+RURBRk1FVFVQUldGVFJVWmNKVV9PVWJN +ZGpdc3VjdYBic39Ua3FdbHZZcHhgcH1mf4ZpfIxje4FreYdmfIdmf4prfYVjdoVfeoFicIVl +eH9jeIZoiJJohI9feoZkcYFVcn1ogYxoh5Jwh5Vvi5l5i5hohZFwhZFafodlfIdfe45gcYFU +bnhSYXlFX3JOWW5NWGxPaXdNbnhZe3lceoFXc3hSdnRab31IbWdBVEw+Q0JAPko4QEE9P0A2 +Pz1EPT80PjpAPkA7RUBHS0xFVFRFRVM5SERTYGZYamRXZXZaaGN0jJhviZN8mJp0jJlth4t/ +gJR/fJVygXmfpnnOtoHdwozjw5LoxZPcyIrlx5Thy4vixYzawIXbvY/Us3nRtIDMqXq4oXiS +n4iGmZqFkZt4jJSEoaV7mKSBm5mRr7Z/n6pmfYSLn65maYtJV21BRF86TUZFXlVFcVxdh3ho +jotlh41Yh3dXe2lJb15TdnBXcnhWcG1Yan1ZcoFie49fhIxliJFYfoVbeYRjhI9xlp1zmql1 +lqdvi6FgbYpfhIlpjpZ3nKaAp6qCq7KEqauEprR4l6h0k6Z5mqZzmq13mKKDqrKHpbF9orCF +qrWCqLODp650maF7oqyBqaqCp7KBpK6Eq62LsbeBoq+Iq7GLrLmMsLV+n6uBnamDpqyKsbKK +tbuavsWdpblvfIhWcXhXfINcg4ljiZNugI5ZfHtecoFVcH5Vg4dOi4tPgohKioxSiI5JhYNU +h5lPjo5Sh5RUhopQhIxQh4hSi5lPhIpUi5dXiZFPg5JOh4xRh49KiY1MiZBQiJNSgpJNgI5R +go1NhpVRiI9Kh5BRhYxLg4RTgpBMh4lRhopOhYtShZJPjIpbjJROj5NXhZFQjJFUhJFYhIpJ +h41Qg4dShItQio5Lio9LiY5Vho5LiY1Vj5JTkJJZjpFYk5hYipNTk5RhkptSk5Vikplak5Ze +k5pbmplimaGNwbiGqbdmqZ+AqrRrnaRtoqtmmKNcop1jo6Fgo5xnqJ5loKJvrKCTwbydwsSq +28qHvbtZlJtXkJRXjpVWiZVah5FJioxShoxLfodWhopEfYZMd4NEe4NOhodPhYtOgoZLf4lF +dHlCbnRBbHNHfH5RgYhNe4k/aX0/YGE2YmhDZ2dDdXw/XmtAdHZVh41TjZtUiZVXhJVSiIxR +ipNXjppYkZtOfJM9a3lDbnlOhIlWjJJQgoxYh41PjZVWjZNTlJpYkp1UlJlWiZRNg5RGd4lJ +d4NKhIRWkJVYnKRhlqFfmKBdlaFhoKJfm6RdmZxlnqN4tKv6/+L///////////////////// +///////9//z8//b///z///v///3///r///3///////n///z8//v6//j1//Xv/e3m/+Tr/9ry +//Hn/OHk+d7y/fD7/PX1/vHv/eLi7dz0+O/0/vL//+vt/efh+eT9//v+//Xz/+77//Hy/+/9 +//f9//z///P1/fDy//Hy9uft/un6+vb///389+vv8uLv4d9LQkE3QD5BPDo/PUE5QTdDRDk+ +QDU0Ozw6Pj06PDY4QDk/PDc4PTY9Qzo2OTU9RDs1RTlDRkJBRUBDRkA+Rj9DQz5BRT1BQkNB +Qz1HREE/Rj1BODs+RD1DREE9Rjw+SEZDRkY7SUs/SEw/UFJKTltHUlpOWmVMUmNLWGNUa3tX +b3tfdIRWc3pTaHVTb31bbX1Zc39tfJNif4dne49nfolmfIpef4dngpNheIxleIhjeIVic4Zl +fohph5FlgJJqfI9bc4Jie4dqiJNsiZVtipJyiJxqiph1h5Vng5VoeYlef4pug5heeYxkcYRP +aXxSY3NQa3RfcoZZbX9ab31XaXxSa31TbnlPandMWnc5RFU7TVlGU2lGVWk7RF04RUU7QEg5 +QEI4PkQ2Pzw8QUY7RkFTT2g/Rk1IXF5KUGlBVFFETldrh4OCn6RvhJ9dcnxde350ipN3mJWI +oKt7epp/e4rBrXzfx43hy4rdworZvYrYu3/Zw4zUvYPWwIjSt4HVsYbPsn+4pXiOloeFmaN1 +jpZ2j5V1mpWFqKOEm6mKrKuNq7SAn6pzhYeVsbpyfJhgdI1abn5UZIREV2lUd3qDm6lxdphV +XHZic41ie41gdYZkg5BrjJdujZhpiJZheYdffYVfbYRZeIJjfYlgfo9lh5Rqj5Zuj6Bzmal2 +kKRnfphaeoFniZRwlqV7oqx5obCIrK+GprN4nKd5mql1mql3oqtxk6B9pqmJqrWKp7WDpq1+ +pbaCqLN8mK15prCBp6+Aqq6Ap7KFrrGKsbSGpbGDqK2AqKeMtbV9oqaCnq1/oaeEpa2KtLOe +xMSoscV5iKBfe4lVb35ifI5hgY1nhI5cfH1Tc4FVd31Tcn1QfopJg4xQh4pBe4JMfY1GfIlP +hZNQhZBRf4tBgIFVfZFFhIVRh5JKh5RQhI9JhYxIg41GgIhQholPfIhPg49MhI9NgI5JgIpK +gYlJfYpNgZFLgo9Qf45HfoxGhIlNh4xNfpBIhY5RgpBJhYtSg45KfolKgo9JgIpSg5FOgY5L +h49Rh45TiZtJipBMho1LhotOhpJUhI1VkJFRiZFQiJJRiJNTjZVQjpNZk5Nhn5yku8WPnrdf +kpVipqXG7dett810oq+RzsG/4dOk6M6rsMVhm51gmKFqnqV0qa+8yNHB3dnJ6Nm559J3pq5W +kpNckphOkJBThZNJiIxUio5Qj5JQho9Og4xNgIlJd4ZJeYFEdoNHeYVMiYtMgI1Mf49Gb4U3 +bXJBaW9DfoBOgY1GfYxEaH84WmI+XGw7bG1HcIA0XmlBdHlQio5Oh5NMhZJMh5ZLho5SiZZP +iZVOg5hCd4Y9bXVEd39Wi49WjZFCgYxTi49PiplXjppYkZ9TjZlUjJZOiJROfpRAdIVKeYlN +jZBXkJxVl6BflKJalaJakp5fnp9emqJcl6FhnKJ3yK/9/+b///3///z///////////////// +///////////////+//7+//j////////////6//32//P4//b8//n1/+7t+uzn+Ond/dby/PDt ++Ozs9eP3/+bw/ef9/f37//v///79//P5/ezy9fL///7////7/+n0/fT1/vLz//b7/+73/uz2 +/+fy/e/1/fP7/vn///7y+efu9Ov19/H+//3////u8txbR082QThDQDk4PzY/Pzw8Sz08Qzc2 +Pzg8Qjc8RTc2RTU3QTc5PTY5Qjg2RDc+Qj1DQTk+RDlCQjxARDpEPzw/QjtARD4/PjdCRT87 +PjY/QD43RTQ7Pjw9RTlBQkI/RD1FR0g/SkpGTE89U1VSV2JFVV1JWGJVXHFPZHJadnxld4Ra +doJfbn9RbnxbcHtdb3thcIJpgI1kfo1pgI9rf45mhIZpg4tigYxfeIhif4hrho5hf4Zke4Ri +fIprgI5hfoldd4pjgo9ohZFziJhvjJR3jZpzjJh0jplrgZNjeodogI1jho1thJBidIVccXxN +bHhjeohgeYpldo9beYVgb4RRcnlneYJadoJeboVDU2xHVFxHWGFLXGlFTWQ6R1I/RkxGTlY9 +Q0RBS1A+RE1FVFpIWV1ARU1IU1JEUVtHUFFKW2h6lpSHn7Nsg5JbcnZVbGdyhI53jpJ7mZ+O +pKehqbXKsYrYv4zfvYndvIfVt4LXuYfdvYXUwYDXvoHVtIPRs3+2o3x+hX2BlZl2lJpxipR4 +i5V8l5iDn6WCm6KRr7GVr7mCnK91ioeRsbR4hpNvg5JthJFdbolLXW5acXmDpZ+EiqdgfIJt +hplpjZVmfZNkgY1qjJRwjpxohJJifoxmhY9ufZR0jJp1j6R3k5x1kqZ1k5puk6dxkJ1xmKZ1 +jKFWa3xlkZNrlp18nat6pquEqLN+q7F+pbF1naZ3nKJ4n6d0mKd3m6eFqbeDqrOHrLWFqrB+ +r7V8ma15mKeDqK2Bqq2JsLOIqrWNsruNqLqFrqqJp6+IrbN/o6Z9naKAo6t9pqiNtLOSwrun +wcZ8l5p4k5tadn1agoljfY1if4pafIFcd4VTdX9UdHpKd35SfYBJeIFKgIdMfYRGgIpFgIhK +gYZFgYlMf4hEfohRhn9FfoNMf4pKhodLfY9Gh4VUeolFhoFQf4hCf4VOfIdLgIRKg41JhIxN +gIhRholEhZBGfopLfolKh4xUhoxIe4RQiIlGgolLhI9QgIxQiYpKg45Sgo1IgotSgpNIhYxQ +hIxOhoRZh5BIh49QhpNKgYxQipRMiZRVjJdNh45SiZBXj5NSj5FYkJWMz7es2s/A0ctsnqpv +vKu26dS14tas1se96s2szsuw5syduMSOqbeg2MrX7eLH5trD8NKZ48uy59CPwr1Ul5VZjZlb +lpdYkJ1UjpRNho1Hio1Qg45MiYtMfpBMhIlNf4lMeYdHeH9Bc4dNhIVOg4xNfYZJdYY9Ym48 +Z2hDd2xPg4hMfYU7ZX0/Xl05YWdAbGtGcnk7XGo9e3hViptNiJBOhJdGhYxKgY5Iio5Rh5dP +gpNDbII5anNKd35VjJNPhJZRi49Rh5ZUj5hYkZ5Xk5xWkqFWiZdKhpBOfItEcopJfoVTjZVc +mpxamqValZ9fl55bnaNflqNamaNglKdcpaiFvbj9/9n///////////////////////////// +//////////////r////8//v3//Xz/vL2/PH+//n///z////z//Px//Tn/+Xk+t3o/+Xr++jt +/erv/e/y/Onx/+70//Pt+ej4/evx//H4//Px//Tu++br8+n0+Ofx/+/4+/H1//T9//r5//P6 +/+/3/fH1/+j3//P4//T///j+//T1//b09eTj49hHSEU9QTs7PjNBQjg8Pzg4Pzk6PjkzQDo7 +QDQ1QTg2Qzg5Ozo2Pzg4QDc1RDk2QDI6Pzg/QDs7Qzs8Pz06Pzo/Pjs5RTc6QDg1QjM7PTc1 +QjM7Ozk3QTU8PTs7PzxBRUNAS1BGS1hBU1w/S1NFV15NVmFLVGVxfpB9h59eeohmfoFeeYZa +coVXb3xccntdd39fdH9pfYxpgYxphZBogZBxh5RpgY1sgJJkfoxtgpNmgIxseotkeIJle4dk +fYZeeIVhgI1nf49mgY9miI9viJRviZh3ippzjZtkhZdegIdgfIhmhJBniJNpgJRkdY1hc4hi +f4pnfJBeeYhkfIddeINhc31Yen9fcoNedINPWXVGUGRDV2ZPYnVJWnE8SFs5SFBea3dJXGVf +cnlSYHJRWGlOT2lKT2hLV2tDU1hdZHZjdISDoKiKrKpwfpljYmhPU0xti4d6jKR3jJV/np+c +ravGso/atYvZvYnZuIjStIPZvIzTuYfVu4fStoTOsYSpoXl0e4B7kqF6k5p4hppwjZByjI95 +pJ6BmqV6lpqUtrCQtLKFla1kiYCMrax0gZl2jpVyi5tfdY5LYHdLbXt9p6KKmLJjdYZmkJRw +iZxmhZNff4llhIl0jZ1thZZ0jpx8l6eBo6x8oa9/oauCoa57oal0mKZ2k6Nul6d1k6VzmKdi +bpNZhoNvkJp5nKx5nrCBqK2FqrKCqK17oq91mKZzkKV0lZ91kqGApq9/prKEqbOBpLGBqLB/ +pbN1oKZ6pLB9o6x8p62Fs62Ps7mCrrSErax2iY2BprR/oaV8pKx4oKmApbOGsLCbwb2hwsCG +laBvkpFxe5NVeXVch45ee4RdgI9ZgIVYb4FMen9Nbn5GcoBJeYJEdYNJeYlEeoRFeoNGfIRN +eoZIg4JJhI9FeoxRg4tEe4tNe4ZFfn9NfopFfYZNe4dBfYFOhIQ+fn9KdoNDgIRRgopRgIxF +hYxQfYpKgolLg4lIgopNgYtOgIpJfYpGfYtJf4NJfIVFeohLho9JhYpRgo9DhYhUhopGgIdS +gZZRi49QgZJKiIFVho9Nho9OhY5Rg4lNgYtQj41ajZFWiJBdnp7F5NaEuLmWzci04NPG59vA +5da33dacwsiL47+z3NK84NTX5OPI7dy+8teq5s+l28Vlo6Nlqp90sq1bkZdcjZVXjpZQjpdU +i5pUjJhRjZFTipJUho5VhI5Lio1VhIxKf4dLfYhDd4VJeYNOhYZShYtHfYRKdoI+YXQ8YWQ9 +dXZMf4dMgJBBZoAxXmI8YGc5a25Hcng4ZmRNgIJOhZNNh5JHgYxOfY9Lho9SiJVPiZVLdow7 +ZXc9cHtPhoxXjJRPgY9Pi5BTiZpWkJ1VlZtWkZ1UiJpOiJVMh5NIfoxGeYhIfY1UkpRdlqJd +l6FilKhYlaBfmKZZn6NioKNen6lnpqmHv7nu/dL///////////////////3///////////// +//////////v///7////////////////////9/vrv9e36+/D9//ry//bi+Nft7+nc7Nrk9+P2 ++fDz/fn1+uj4/fL7/vb///77/+np+uX1/vj///77/+/+//77/+/4//b///b///71/+jy/+n4 +++vz7+ft9uP+//nv+Ob0/+v2/+v5++zm49dUSEk/PzxGPzo9Qjs2QDM5PTk9NTg1RDg3QTk6 +Qjk8PDkyQjU8PzkxPTQ+QTc1Pjg8QTw9RzU/Pjs3PzVCPTw/QjdCQTw4QjQ/PzY8OTdCQjY5 +PDg6PjZEQjk1QUE+RURGUFlKUWVJUV5EUVxVZHNLWWdPY297mpyWo69pg5BsfY5gfYlmeYpZ +bn9ab4Fjd4dicohigIVogpNuhIxxg5Vsho9xi5FuhZVlgI1mgo5oiZNqg49lg5Blf5FjgJBb +dYNqhYtie4tohZBriZB6iZtwkJZ0i5xri5pwf5the45rhpFkhJVthZtliJRnh5Fof5Jmi5Rs +hZJheopgeIdfeolcdIRifYpedYdacIJSYXtLWmRLWmlVbXtPX3JKUm9BWF5vi5BfbYBviJFw +fpJYboljeoBdbo5dbHtLWHlKZGRzjIx8nKSJqLN2gJ1tdHZZUkxjfH1+j518jZeBmZ6TqqLL +tIvVt4nYwI3Zu4TRuITUvIfQuIrXtonKrYOsmX2CjYuBk6CAm6WAmZpzlJmSp6B6d4JbhG5x +i454lZCJpax9oKNudZRacXFxjphieYRohIdlfY1keIVZboFWbXl+qJ+ZpLZpdodvkJ50kaVs +ipZifZZifY1xjpt1jJx5n6KBpLCEqbKHpLd7pKqBpLOApqt+mqxymqF3lKp1laB1n6xuiKFY +enVniYh8prJ7o7OBpq+FqqyCqbJ2nKN2k6F9mqp3mKp3laJ+qLKIqLWGqbWDr7CGrbWEprh3 +nat8pKqGq7KErrCFqrOLsLWLq72Cp6t3hpqIqK5+prGCoaCCn7CGpqyOsruZv7uryMyUoqxz +kZRthJJacoJYgYhng5Bge4phdYRZfoFbc35McH1Tb31BeXxLeohGd4dOd4xJe4FOe4U/fIFO +gIdIfoRTfIlDgodMfItJg4xMf4tLe4xIfIZNd4lKg4pKeoZKfIhJgI5KfIJKf4xQfYxLhYZK +f4pJhItTgZBJcYBPdYxMfYhMgpBKfoJKf4xGe4FOgJBJf4hPf4tKfYhLgopKf4xJh4RPg4hN +i4xNg4tJgIdHhodMiI1Ogo1RiYpMgo1PhohSi5BZjpBZo5u959DC6tnT8t+s2NLK4tOq4c6x +69B9rrCPwLaDrq6M4MC+59WX2sJ2t6tmpJ1dmZxcmZ15qatWlJVaj5NQkpRXjZBUjo5WiotV +h49UhopRipBWi45ThpZRg4xNhIpNfIRHfYVMd4JIeodNgI1Ph49QgYdMeoM/Y3I4YmdBcndO +fYZNg4xBbn88YGE9ZGVDb25GbYBDbmtKgoZUhZZNg49KeoZJfoRQho9RiJNSg5JIc4c9Z3VG +gX9QiY5Mh45Th5BUjpZdj5tZlqBgk5pVlqJXjp5RhZVOhJJCeIdOeodMiZBclJxZmp9ZlZ9Z +m6BflqJhnKBdnalgoadkoatjp6p/wLTz/93///j////////////+///+//v///////////// +///////7//v////6//v8//P///3///r7//j+///1//r3/+/n/+ji/9f2/+3p9urg7OP8//n5 ++e35/vPy//H1//Lz/+/9//34++X3/uv1/+v5//T6//D+//r7//b///71/+z5/vP9//z///39 +/+////79//z07OTp7eby+un7//Dx7uBZQ0xBQj1BQD5CPjY2Ozg9Qzo0PjQ9OTo1QDQ/Pjc1 +QDdEPTgxPjRDPDwyODY/Ojc6Rjc9QTU4Qjo6Pzc9PDg8PjY+PTs6QDY8PDw7PzU+Ojo4QDQ+ +PTc4Qzw/SkJCSk1LVl9bb4R9eZVab35fbXtXYXRkc4aIpa2WpLJqfpFrf49de41ndYNfcoVi +c35hb4JjeIdke4JsfI9kgIpthpJuhpFvjZlyipdogZBmgIlug5NogpBmgY5sg45pfo5heoZo +hJNsf5NqgpRyiJhzjJt1jZx1ipRyjZ5xhZxmgZBof41mh5Bvi5hkhJJse5Bpg5F0jJtne5Fr +f5Bpf45ph4pnfolpfIlnfI1qf5JbaYdPYHFRa3tnf4lfbIZQYHNKVmdniYN1hqBzh5Z5i595 +iqlkdIZuepBtgJVxg5hTVXZcc25wkZKOqKiHm6hmaoZWUlVtg3x/lKSBk6OAi5qYoZ/Rro3V +u4nZuYTVtIXQsH3St4LRtH7Cr4CZmHmAkZRqi3xge3NXcGdaYmhmd3OJnplqeXpra4V0gISB +kaSNoKWFj695hqFfd354gZRjcH5acX5dc35id4FgdYNWaHhyoo+cqLpsfY9sjpdwk5prg5pk +fJBieohtlJZ7oamCo69+qbGJp7KEp7J9m6Z7oauCm6N/lqp7lKV0kKp4lqV0lal1k6dfcote +goV5oamCo6mCoq9/pa6EprB4oKN4mKh0l6p+mKJ2lJx/qKqNqreJqrKGpreEqLGFo7N3kKJ/ +oa99p6h/qLGCq6yLtLmOqbN6l6V6i5WKoLKCpKt+oKl+obCCrbCNrbiVsriiysWhq7d0kqF2 +i5Jnd4Bden9hfYZ2i5lmfI5mfoZfeI5ab3xTbX1Nb3pKd4ZLf4hLfYNOeYVRgIpFfIZKfIJJ +fYNPgYtRfoNTeo5NfYZQgJBKhYNFd4lJgYRSgZJPgYJRgo9Je4VPfJBBfolMhYpLfYVVgINF +f4BLfY9LfY1MeopFfoVLgI9QgYxRe4NGfYlKeI1EfoZRhZBKfoNKfY1KfoROeY1Be4NNgIZP +hY1UfYpHfYdMf4lQfY5Kg4pPg4xPf4pNhIlVhIdUkZCS4be64M5617SP2ruX275lop9ZlZFS +kJKZ27204NDJ49d9pbJqnKhmmJpsmqh8rKxqoqVelJdYiplVjpBgj5RXiZVRiI1ThY1LgotP +gJBQho1Tg41TiJNWg49Ph4pNf45Mf4tIe4VLeIJIf4JXgoZHf4JVdoQ5Y3NEW2s9aGZQgH5N +iI9Lb4Q5Wl89ZmpAb3VFbH5AZ21MgIBUh5NIe4RGeHxLe4NOgoxLgY1Oe4c7ZXpCb3BMgoZQ +g5FMhpRSjJhZkZ1YkZlWkKJXkJdXjqJWjJhUh5tPf5FHd4dRfIlVjplalp9fkJ5Xk5xdmpxh +naVdoKZknKdgnqZgn6ZhnKGLwbX+/+L///3///7////////////////////////////6//f7 +//L////////7//T///////38//f0/+7s9ujq997n+una8tni+9jr9uru+d/w/+3s/Ob4/vb/ +/ebl9eHh7tzp8+Ln+ur4/vjz9ej0+u77/vL2/+7w/+r4//f4/+r0/e/7/vL+//b1//L8//f5 +//P5+e/y9u/+//7///X18un08O5USkc7PjtBPDg7PDU/Rj05TEBPQT4vPDQ4QDsyPzdAQkE7 +PjM/PTw1PDQ8Pj02PDM5Pzk3QTY2PTA1QDYzQzM7PDgzPzI7PDcuPjM4ODY3PTM4RDc9Pjk4 +RD0+Q0Y/UVVSY3F9m6CCnaxviJdyeY9cd4N3hJGCqqiYqa9igIxpg45shpdle4lccodYdH9k +fIhfeYhofIhljJJxh5Vrh5lyiZlxjJZvgotlhpFqhZFripJrh490iZlsf41leo1og4xriJZr +iJFug5Rth5JwkJx0kJt4jplyjp5ti5hrf5JefY9qhpZsh5Rqg5BkgIpjgYxpi5VqhZRmhpxg +gIxjgYxngI1nhY9uiZZthJVph5Z5iJ9lgpFwh5hbcYRWa3VHWnZpiIWElaZwio5+m6l3mKVu +f5dmiZFxiJVzjp1wf55DU3NbeWt8mqCMoqxldZBaXG5ih4Z7lqF6lp54jJiDmpnMsIjXsYXX +tn7Ss4TGqnu/qXq1pnSBi3lea3JncHyKlqeHpauAoaVwjpZveH9oeoJrfYJ8o6GbtriKpKqX +sbSCn6WGma9ohoKDlqxiboJabnlgdH9beoZedn9aboFvm5Kcu7x5jJ9vh5pxlJ5vjaRnhJNn +g5Bjh4l+oqp/p66GrLeGrKyMr7x6ma92m6V4pqWDobB9n6h1la1zlaR2nKl1mKttfpxXfXtv +naSBqqqEqqx/rK6Co7Fykah5n6d/o6R8naZ5l6V7oamFqbeKr7SEsbWLq7iFrbF6mKd1prCA +pKh/p62Ir7WGsLGIrLR5lqxriImHrK17paeAn6aBpKuBsrOPtbiVub2dysWcrsGBnKdymJp0 +hZRYfn9yhZRvmZuGmatpgY1hd4lRdYFec4hMbnZLhoRTh45PhZBPhIxQhpFSf4xRgoVNfYxP +hopJgoxFgopHfoJKf4pMgIdKgItKhY1UgopKiJFMgIlEholUh4hKgoxRgIxIh4pUgohMeoxK +d4tThpNKgJBHeotPg4tKfodKe4VOfItJe4VJfo9GgYZQhI9JfIdKhIdLf4VKgIpEhYZMgYxR +ho1Of4tHhYdRgIlFeoVFfoROfYVQhINLiY1TgoZSi45Vi45PjItakI5VjItWh49Rj49akJlW +nJljop5YmpNfp6BmrJ5ppaBZmZtZkplUkpdbiplShJBUjpNZj5RbiZdQiYxNiZNRh45SiJJS +iI5Rh49YjYxjlZVJf41LgIpGfn9Ed4RFe4JGf4VIhopRe4pEeoZCZXc3W2VBaWxHgHhNhY9F +dIk+Ym09aW8/b3Y9Y3hCdnBTjJJOgpBGcn5AcX9Lg4ZLg5BGgI5DbYE3Zm9Gd39NiItOhpBQ +jZVakKJVkptklp1OkJlZkZtQi5VXkZtPiZhWgpVBf49QjI9SkJpTkJlel5dclp5cmqFbmKZg +nKJamqNelaRbnqNioqOKwrv0/9j///z///////////////////////////////////////// +///////////////////5//L+//f////6//b///zx//Pq/+Dt/unq++br+ef3/+n8//X0/+r6 +//z////9/e/3/e30/+/+//3////5//Pz//f6++X0+fD///3///////n9//f2/vb///X3//D6 +//f6/fH8/vP+//r///Lo69xUQUw2QTw+Pj48QjZAPz9RYlZnW042QD0+Oj01OzY5PTk1QC88 +OzozQTU6PjcyODM5Oj41OTk6Ozs3PTUyOjc6PDg6PTk9PDk4Pzs6PTo6PjY1Ojg2Pjw5QUJA +TE1IVWZqh5SHoKuGmaJ9jKBteI5Zf4d6jJ18oJ6QqrBigJFrhpdtiJBrfJNjeYtfeYdke4pj +fIxgeYlphYpuiJhrjZdyjJ1zkJttiZVxh5VrgpRphphriJZuiZpkh5dsg5NnipZ0iJlviZFz +g5Jpipl0i55tjppwhp1nhZd1i55jgZVpgpBni5ZuiZdpfJNdfopof41th5Rui5ttjJtngZNk +ipZuiZZ3jJ5wh5lxjZt3k6GEnK16jZ5/kaxbbIRZb4BNZXlWdnyAoZx3i6Z+mZx7l6d4iKdm +iZVzjZ1ukJp9lahjbZZIV19tjIqAoahofZlUbXhxj5B0jpZ8kp12jZ19j5Wvo4LEnnXLmnjN +qYDHrH25oYCEhIJteoV5j5x9maByjpZoe4dVaXZacXyIp6iKqq6MorGHpKWYq7mGn6mKpq6L +prCLm7NffYGGoq1vgJVbcX1YboNddH9edoZieop2n5+evsCDmKp1i6Fwj59zlZ5shJZog5Zm +gpFylJt9qqiFrLeCsLGLq7iDpbJ4lal0mqR2lqR4nqp4lKp3mqd8na53mqp1haVOcm1slZl/ +qKt/qK2JqrOMq7uAn690maZ7oKl5oqV6nKp7nKyCqLCJp7GFrrOIq7aCrLN+l6d3oap7o62A +pK+GqrqErbKKq7hxmaVrjYuKo7CAnqt8pKd8oq2GrLCMsLGQuLqUw8OpzMyfrMB5jqB1i5Nf +e4Brj5N1namTsr52hplphZNYe35Xcn5LcX1ObHhMgoRThJZFgY9VhZJKhI9Rg4xMhZhPg41I +hJBLf4pIiJBNgo9NgYtQfolKhIxTgYtNg4ZOfYlFg4dPgItMioxTiItKhIhTiJRKg45UgJBF +fYtKgJNQf4ZTho9Rh41LhYhOfY1MgZFLf5NNf5BMfYpGgIxSgI1GfYROgo9Mf4hNg41IfIdE +e4RLeodJd4hKdYZEfIVQe4VEe4ZQfn5FfYJNf4hGf4JRgIVOgYtQiI9PiohVio1Ri5JSiZJX +j5ZUjoxUjpNWkI9WjZpUjphYkZhRiJBViJZTjZFXh5NVipBUiI1TjJVTjJRUkJdViZRTiY1Y +iY5Qh5BNhotMhotPf4pMgIpMdohBeIFMfIBKg4ZPf49GfYVHbX44X2c+YGdGeXRSho5Ldok+ +Y2w6anFFcng8ZXBDcm9Lh4tLepE9bXtEdXpMg5RHgJJIdIU8Ync+a3NOiYhPiZNNhpBWj5Va +kZpRj5pWi5RZk5laip5Qj5ZUjJpRi5hUiJVOhpVXh5hXjJxakqFXlphflplblJ9enKNamqhg +oKhinKNdm6dioqd/xbj9/+b9//z+//v////9///////////////+//n+///6//P+//f///z9 +//j///z+//z7//L9//3////0//f8//b9///t/+/h+9ns+Orv/+zo++jt/+fj8uD1/fXx/+n6 +//H5//P6/vPq/OD0/ej4//T8//X5//j0//L7//Pw/+74/+/x/+30//L6/+/q9ujy/u76/vP5 +9fH8/+77//H7++nt6uBMR0lCRkMzQTE9Qz81QjRCUEZGTT0/QEMvPzU9Pj04PTc0Pzc3PDk2 +QTU9QDkzPjU5Pzs0PzU5QDs1PzU4PTY7QTcyOjk6QTk1PzU6OTcyOzA9PDgyPThBRkpCUFBN +aXqAp6WQqK95nKl9l55xgY9ZenxqgIpmlZaLn6tif49qgZVpiZVth5VkfpFccotce4hkfoli +e4xjg4tvi5xriJVti5hyjZhwiZ1vh5dug5tlg5FojJpph5Rlg5VnhpFriJRwjZpyj51whZhx +lJt2kZ1ukZp1jZ9njJlxjpxkhJRphZJsi5pthp1sgpZoeo9jfotti5VrhZZqhZhlhpJnhpVz +jZZukp90jpptkJdyl6KEoqWIoKSSrrV2hKlacoVXcH1SZ3FtjpN+j6FvkJaBlqp0j6Zsh5Nt +ip92kaBykqJ1iqFNWHVlhHZ7m555kKRwhpp+k6FrfYOUrq+Al6t7kJugpIzJqX3EpHPFpHO2 +pn2FjYNkenh8kqd8nJ59jqCAqKxkc5BOanV2jZaMq7GGl62KpayHmKZ6kKB1ipmAl6KOsraF +nbdZcX+AqaV8k6NkcYNacntccX1bc4Nlf4l4mp6ZvLqPlrN0lJ1zh5hvkJpzjZtpiJNviaBq +kJh4n6iArK2KrLWMrrmLq7N4nad1l6R4mKl3m6Z3nq54mqt2nqh1nqhylaZTYnVjk5SApbF+ +qauGqbGErrOEo7NwlZx7nax6n6x+obFxmqqCqLGCqLeHrrSHrLN+q7Z3mq1xnKd7qbKBp65+ +pa9/pbCAqbBtjKBsnIqNp7F+naV+o6+BqLKEpa+Br7WOsrmVu7mlzMypzcOasMJ6k5ptfIxc +g4Z8nqaatbmFmaZ4iKBkgopfe4VafotbeIFMd31UioxJiYpRiJFNiJJLhZBMjZNOjZpUh4tO +hZZXh49KiZhdhpBMiZNTiYlGiphUjJFLgYxUh5BSjZBOhIpRgpNNiZBPhI9Lho5RgZVKgIJN +f4xKhI9Qg5FEgYRKfIhHgYtKf45MhopJg41KgI1OgItKiIlNgI5KgohLhpBKhIpLgIlFgotK +eYVFfIVMe4JHf4VPfIZEfodMdIJCgIFNgYhGf3xKd4JDfoFQf49KhIxThopIgI1SiphXkJVa +jpNSipBUjpRQiZZVh49ViotNiZNVjpFQi5ROi5RWlJdRi5RZi5ZTi5NXipVSio1ThIpKiYpS +h4lNhotUg49IfYVNfItFdoVKdoZDeYJskJNMf41MgohEbYQ8Y285XGY/cGxNg4FGd4Y8YGc+ +Z21Dc3I7YWtIenhPhIhCdoM+bXlFf4BMg5BHe4tFboY2ZnJHeoJMiJBTh5NJipBXiJZYkJVZ +k5tTi5hWkptSjZhOhpdQipJOiZlXi5pPkZxUjZ5TippZkZxXkZpZk5tZlqNhmaJhnaReoKhh +nqpblqFfnqR8v67s/t7+//r///////////////////////////////////////////////// +//////v///r7//j8//j9//n////s+u3g/ODf+dXt9+fu++ji7uD+/O/x8+zx/O3x+O7p+eX0 +/vD9/fL1//z/+/fr9Or9/fbt/+/3//L5//r/+/Xw9erz/e70/fLz/PD///r1/+/z//T5//X/ +++/v++z///359OlYSU1BQDw/REA8ST5HSUZFU0pLR0RFSTw0Pjc7PDU9Pjc6PTg6QDc9PTo6 +PDMvPjs2QDg1Qjk3Ozg1PTM2PDQ4QDc6QTgzPzY7PDszQDQ6PDo3QDQ6QEA3R0dET1dagYqe +rrSBn6eBmap+l6N1fZZLaXZtfI90kZt+nKZng5JoiZVyiJpwhpVng4xmeo1gf4VoeYlofYtn +eYpliIpxi5RujpN3kJhtjJRziZpyjZhug5driZJuiJRnfpFqgZBuhJFlhJVvi5hphpJzkZh1 +jp5sjJl1jJpuiZlxjJhqiJJsjJVzh5lyh5drhZNmgZJegYxviJxmiZZ0iJdkfYtuhZlngpRx +hZJtjZp4k554laOCo6qHpLCdvryhrL1/jqVsd5laboV1hZdwh51shI9/l6mAmqhrf5Rpi5Z0 +kJ51lKJ4kahpbZRTaGRwkYmHnK52i5huhZSAlp6JpaySo657j6KPlpXBqH7EnHG6o3KRjHxq +en1/kpqBlp6Am6qOpa2AmapXZ31mfYeDm6GWuriXrrqNrK2LoK6Rq7GOo62Ns7GBoKODpq9e +aH14oZ2QrbOHka1ndodmdIVidoNmgIt/p6yWurmVo7Z8mZh5jqFuh5VyjZ51jKB0jJ5ziJx0 +lqKCp6mGq7eLq7KIq7qApbR3l6h2kaFxlaR7nKZ7nKZ7mqx5mqR3lK5ga4dgiIl6oKx9nKx9 +p62GqrWDp693kaR5n6J/oa19oat9oKh9q6+LqbaGsLKCqrWErK2Do7N2l6d6oaqBoq18nqiD +o61+papvh55tlo6MrbWCo6x8o6iBoq2CqK6HrbSJsq+Nq7aOu7eewr6ez8KlvMt5h5thfoNp +ppaexMOiwMuJl6t7kKVwiIligIdfeItRcnxTgYRShJNRi49OjJRYg5FJh45UgI5KhZBZjp1U +h4xYi5RKhYtSgJROf4tPg5dMf45Nfo1EgpFOhpBNh5JUiY9YiY9Mf4xVgpJRgZROg49QhIxS +hJBRhpBSgpdQhpNNfpNRhZNMg41PhY5MiYlVh5JMh4dWhYpOi4lWhZBRgoFQgpFOgIVLgI5O +e4lDeodKe4NCeoBLe35JeYNGd4NFdodFeIRKe4ROe4VGfYVOgodPgYVViotVi5JTj5FbjpVK +i5NYh45QiI5ciI9ViY1UjJFRiI5Yi49NiZJQjJJVjI5Tj5BWiY5OiYlOhYxUgYxMhIxLgIhS +f41Gg4dNgIVOgIpQfYZLfYlHeYNIf4hQhY1IfIZMcYVDXXI9VVk+ZmZOe3ZGcYM7ZWY8aGtA +am44X2ZKfoBGdIhEaXQ+bXBGfIZHeIdGbYM6ZW9FbHhFgYBThpVPh5dQhZFQiYtThJJSi5NW +jplPjJtVjpRTiJhOjJdajpdUkZtZjptUjJxNhpNSipVXj5dWiZ9VkppdlZ9dm6NioadioKFj +l6denJ6Lvqr2/uH+//z////////3//T+//v///////////////3///////7///3///////// +///1//T1//L2//D1//Ls/en2+ezz//Pp+tvj8ePm8dnt+en2//D5//X5/ez+//v///X3/+78 +//n1/+v4//P9//D4//f2/u72//f7/vP1//f9//X///7///n8//3+//T7/e/y/O7///n6/+35 +/+3u8t7h49FZS0k7Q0A7RTtFSENDQz1DSUBBST09Qjk6RTk6PDg2Pzg5Qjw1PzY2PTgtOzk0 +PDg6Rz00PjE1QTg7OzczOzw3PDU0PTo6Pjo0PzY+Pjw7Ozk/Pz41RTtETVlIX2l8lp6QqauK +m6p+oKd/lqhwgJFPZ3Vde4d8m6d5lZ5vfZZkiJJyiZZvio9qgY9leItfd4theYphgYxlf4xj +fYlrh5Jvip1vi5p1kZtvipd1hpdsiJRwjJpriZhpgJhmhpBthpdph5RvjZZqipVyiJtwjZZx +i5hxjZ1ph45xjZtuiZ1niZBoipZriplqi5Zjfo1jgpNtjJdxiptqjZZpg5dhhYxuh5doipB2 +jZx0l5+Al6OFpamKpLCFsK+ivL+Qtrqgs8CXq7ydubqbsb9yhqJ5l6CAm6Vyh51qhZhujqBx +h6BziZptfJxFUVhjgYB2j5V+lqFykJZ5lJ1/oqCKqKmLo7CGmZq1pnzEpH2bh25teIJ0kJWB +oaaEoKuLq7GLo7ZofYxacoRyl5uRsLCdwMCcq7x/nJ+Kp66XqrOImqmOpbKAkqB+maJoeY9z +m5CUurqhvL+Mm659kZ5uhZtogYZvkpCXtredsMJ3k5aDlrJsjZV1kZxykqF0j6Vuk5tvkZ11 +o6SEpq2Dpq2DqquFrbl4nqt4l6Z1k6B5l6V4mqh3nax0nKd6la5ocItThIB+pK18oKyFqbKB +rrCBqLBwj594l6N+p6p/p7R8pLJ9pa+DqLGBoLGBrq+ArLWCpbF4mq6Cp6l9qLGGp7OBqrGF +prNujJ9vno6PqbOAoqt/oqp/oKyHqbKJrLSKrrKBqKiKp7WFqqyKtbKTyL6Una9gen9kiJKP +xrqtyM6duL6FrbGDlqBjgI9qiJBif41TeH1TfYlLhJFMholJgo5QiY9Pi4lTiZhPhZNUhIpI +iZFShpNViZFUhJFLgJBQh5FUh5FYi5FRhIdSgJNPhZJRh5BJgpFWh5BQhZJXgpJXjpRViotV +iJBLgI5NgotShpJMgI9RhI5Sg45TfY9OhYhVf4xTiI9UgY1PhJFRgZNFh4lTgpFJgIdPeYg+ +fIBRfodJc31Ke4JJdX9EcoVIcn5Acn9JdoBGdXtJfYVKf4JFfYlIg4VMhoxShYtOiZZWjZVN +gpBNh4xPiYxVg4pOf4lThotNh4lXho9MiYtYiZZSiY1Xh4tNjYxZiZFRhIlTio5Ogo9Qg4dS +g4hOf4hOf4xLf4lMfYZMfIhOgYFJiYxPgIlLgIlBZoE9V2hBYVtAcG9CbXVAZWg+ZmlAYnJA +aWNGe4ZCbnw8Z3RIdnlHfYpIbYE8a3o9ZnRDgYhYipdMiJFOhZVHhpJThJVNhpJXipZVkJpT +hpxSjpRRiZNgjJlbi5RWjp1UjptTiJhQhZlVipVWho5VjJZOjZxglpxgm6ZlnaNln65fnadk +maSLv6b6/+n///////////7////////////6//n///v///3///////z///////3///r9//7+ +//v+///+//f5//n+//j7//jo/efb+dXz/O38//br8ejy9evy/Ojx+O/y/e3u++r0++7x9fL7 +/+/8//b+//3///v+//z7/+3x/eTz/+33+efs9+rq/Ofs/uL2//H+//f///708ev4/vf+//n/ +//77++dYR1M1QDNEPEM/QTpBOzw2OzU6QD49PTwyQTc6Ojg1PTQ5PDkzPDhANzxAOTs0Pjc2 +QTc9PjdAOjc2OzU2ODk0PjU9OzsyPDVAPDgxPDc+Pj4zQ0FDSU9EVWRVaXuLqbKIna14laqH +nal7m6d0fpdVYXRWf4KBnqZ9l6Jyf5dih45th5dqg5VufZdffI5deYNde4tnf4lqgJFqgIpp +hJFvjZZwjaFzi5xxiZxui5lqkJp0jptthZ1ng5RjiJRyipdlhJhpgZdvjJVsh5dsjJlxiJ1r +iJhvhphzjJ1yiZ1viJ1uiptrhZZpgpZjfIxkg5Ftg5lwhZ5ng5VigJFqgpBqjJNuhZZzkJp1 +k6F6mKaPraqUpriFoqyNqLKIrK2RrLOUtrmdr7ycvrqXpLl1jZ9/mqtvh6Rug5RwjJt9laSG +oLB5lJ1jY5BPZVxkgpBngY9ogI1wh5OEn5+NqLGNq7FzjYe1nXawlXF3eWl1foeKr6uYsbaf +ubmDpa5iepBacIJXc3+In6eRtbWftr2Xt7qVp7+RrbGVrbmLp7aFp6h/l6BwkJV3jaZli4qT +uLaiwMOgu8CgsbqRo7OBjZ6AlZybubifub99iqKApKt4hqdvjZ13l6pzk510kZ91kaBzlKF8 +nql+paaDqK+GqLh/n7F0mKdvkKNukZ92mqZ4mqx0max6mqprfptUdGVxoKeBpK55pK+Cq7Z8 +pqxykKVqk5t/pLGBqq6CprN8oKqHrLWIs7aFrrOGq7iDpa14mKV4oqmCqbGApKt/pa97l6dy +iaNtno+NrLaHn6x/oayHq7OHrbSDo66Dp6qCpbCDpaqGprh+pqyKt7ifvsGAhpRbh4N8rqil +zcalx8mewMCNrrV0fpJsho9ofYpkg4tRcH1YhIdOgZNUipBMiZRUiI9LhZJNi5RLiY1PiIxE +gY9YiIdFhJBZh5RSi5NRhpBNh5VXipdVf5FVjZlZiJlWgpJTh5dLiJBSg5JJhZNMf5BJh5BV +iJVRiJVNgJZKhotNg5JKiJBUhpJVjotRgZBPgY9QhZBJgZBPgYpSjpVXhY5JgoxLfodEd4FD +cn5BcXVIcYBDeIFNdYJCeXxKcnxBd3pHa4NAc3dJdoBEd3tKeIJMg4dUiJFOiYxhjZxViZZS +gIpRfohKhIdSgYpQgIlQhY5Rh4xLiJFQiIpYjZBWh5JXj5RVgI9OhYxRhYtKgoZRf4tHeohN +eohFfn9KfoVLfIZPfYpKfYhShY9Ke4ZPgYZFcodBX248V2A9YmJAZmo5Xlk8ZGZAXmk/bW1F +aYE/YW0+Zm5Ddn9EdH01ZWlCY3lBcHtQgYtJgI1ThJJFgpBPgpZKhZJXjphRj5ZWjJZUipdS +i5VUhJFQiJNRiZJVjZdah5hVj5daiZ5Ph5dQgZBNh5BLg45aj5dfm6ZioKFhoaZipaZmo6F0 +s6Hu/sf9//n////////5//T///r///////////////////////r///z7//f9//3+//j///z/ +//j///X1//Tr/Ovr9OPj9+jp/9z2/vbl8+Xf9dr5//L+//r1/+zl9+f9/vv9//f9/e3+//b7 +//b5/+3s/Ov7//H7/+34+fH/+/v///v///////z////5/+/8//v4/+r29vn////5//D19eji +3tVSRUw9QDk9Ozs3QDk6PTk7QDg5QT5CQjs6PD09PDo7PjlDPjs0ODVCPjk1Ojk7PDo2QDU9 +Pzg2OzpCPzY0NzlAOjg/PT02QTsyOj4+PDk/QkM+SEZFS1RNXW5sjI+RqrKHoKp6nKGDoaN+ +mKN2gptWXnFUen+Kn6yElqF3hphmf41ziZxzhpRshpprgpZge4ZmdoJnfYd0hZhvh5FugJBm +iJN6jaBxjJt1iptviZp0i5huiZNziZZlgI9nipdth5Rrh5RpgJhyi5hzj5l1ip91jp17jZ90 +jpxxkJ13jJtvip10jJx2iZ91i5hnfY1lhI54i6Nyj51viJtrfZNmfZFtiJdyiZt2j597jKJz +kaOQq6uWr7+Koq6Lp6yNo6+Gp6yPra2OrbWbtLOouL2Gla5+m6h5kaRxhZ1ui5l0i5Zzi6Bz +j5x2hKFRXHFpeYhnfotxgpN3hJKEmpuBpKl8h6NzfnG+oH2VdWZ+g3xuh5V0iKBohodkjoxk +d4RecYFUaXxjfYKGrK2Vt7imwsWfvcWerryJqLCQsbJ/m6J5pZ+DkKl1kZd/k6xihIKWt7ij +w7apysOdv72husKnwMCkvcSnwcWpwMWBkqiEqaOHmLV0kZ58mKl6mKF5kKJ3k6JzkJ18mKCA +qKeLqbSErbKDpLZ1nat6lKVvjZx7lqdyl6Z5mat3nKx7k6VXZm92oaN9oa+BqLKBp699pa99 +mKpvj5qAo65/pKuGrrKDo7GFrLCIrreIqrWIrrOLrrl9mqd7nKWKpbKFqbSBp7B4laFuh6Zm +kY6CqbSDoaiFrLGNrrGLprSQqreJs7aOqb2KqrSJqrSMsrWGq7WZvLuUlbRmf357oKKXw7ut +0tO0y82ju8h5jJ9okJl7iZVvj5hngYpOdYJXhpJVipxVipNWipZVio1aiZNPhpBUh5RNfI5V +fJBKh49UiZZRiI9UgZBSgpBYi49Ph45ViZdQi49ZipZRiZFag5dShpJOhJZYiJZaiZVRjJlV +iZBOhJZSiJFRjZVWiphWiJFTiJFKgJVVi5FaiZBOfI1NgIdLhJNqn6xUgJJLf4lPeYlFdIJN +d4NDdoNLdodMeIpMe4FHdIFKcn1Lc35EeHxKeH5JeIFHd4NKeoRLgYVRi5FXjpRYi5lXjI5Q +f4tNgIZUfopJgYdUgY9Ph4tXiJJPh4hXiY5ViJFYi5NShohPg49SgYpThY1Sgo5VgIdLgY9I +eIpKdoZGdIBJfIRLeIJLfIdVgI1JgoROd41Hb31CW3E8Y2dJZm84WVlDYWs7WV1IaGY8Y21D +YG1AbW1Ja3c+ZHJCY29Hdn9FeoRLeo1NhYtQhI9Rh5BTg5JRipJVgIxSiZJXhpBQh5RUho9V +hpBWg49TipZXjZhdj6Jak5pckKRaj5xXh5dThIxSh49Zh49impxkl5tfmJFbhHFSXlpjbFbz +/cD+//z////////////////////////////////9//z8/+7///////////////3///////// +///9//f8//r8//n3//np/93n/Ojn8d38+vTy/+z1//j7/ffx/O7z/+/0//X4//T3/+v+//71 +++34++7u9ejw/u70/fPw/+38//X5//P3/+zu/erw//L29vH+/v318ej7/fb99e/7+fTs7+FT +Slk4RTs9OTk2Pjs5QDs6RDwySDo5Ozs3QTg1PTk7PTc2PzgzPDwyPDs9OzkyPDkzOTQwOzQ+ +Oj4tQjU2Pj00PTQ7OTs1QDozPkE1QjdBREY5S05DUV5VcX9/p6yPrrKBn6h+kqN6k6GBkqR3 +i5dcZHhIZ3KBnqR4lKNyh51lf4xlh5JsiJZggI5sgpJdc4VgdYRXeYVyiJdih5RzgI9pho10 +j5lri5pyjJhrhZlpg5VsiphzjJxqg5ZkhZNmhJRriJhniJhri5hwiplvi51yjJltjJtsi5Rz +iqBxjJlujZ1xiZpzjaVwi51kgJJjg4xujqFrhZtjgZZmgJNjfZBnjZRqjJd5j6Bzk6F8lqR1 +mJmauLiUsbmJobCMo66DpLCLqrGPqLKPsrOjwsCSoLZ8laN9m6pzj6FjhpVuipdugplpjZV0 +jp9XYolYc2xogZJzjJp6kaGCoKN6lqBme4+EiHOznnqIZV9qhHVnf4WDnq1sdpJdc4ZdbX5T +a4BTZ3lgfot/nJ6QsbWiv8aYtr6ZtrqLrbaImbR9jaN0iI+Dm6eZrsGInrFmdouHsqidvsGV +truauMGevrqkxcakwcGnx82nw8uSm7V4n5iKpbdzkqF2kqV9nKd1lal2l5t3mqV2jp54mqd9 +pquEprR6n613mq9rjqFxkaJvlqV1lqdwmaN2ma10mKteX4VllpF7oK57pbCDqLGDqbF9m6xy +kaB2nKuEqbGAqrmDqbR7qLKLsLmHrLaFsLaJrrh7nrF5m612o66LrLR8pKx4lKhrh5dlhY+F +praBnKR8qrSNpbSHtLOSrbSDqrSNs7CHqLSSqbWHrLqGqrSMtbKXrb9of4hvnJmAqrCbxr2u +1c+kvMF0laVujpFuiph0kZxsiJdghItTeYpXiJZOipBTiZNTh5JRiZZPhpFQg5RRiI5PgJdP +gI5Nf5BNh5JRiZdQhpFNiJNQjZZSh5BVh5dRiZRShZZLiJBYi5NSkpBbhptWk5JQhZJWi49Q +jZdSiJJIiZJRiI9KiZFYjJZPipBWiZBSh5NSipBMg5VRiZBJh49fiI1TgYlEfYFKdoZAeoBM +doJEe4FPfIpFeYNMcIFAc4FBcHxFc3tEcX5Ac39LdIBIfIFJfYBKiI9OiZJRipdWjZFRhpdO +fo1FfIpIeoZGe4ZKfo1GhYZRfoxJiItNipVQi4pVgJJHfoxRgJFLhJBSiIxPfohIfoZFeohK +fYpGe4dMf4ZMe4hPiI5XhY5GfYhMfIxLdIE/ZHY9Y2g5YGw8VVY7YF88UFw4WVtCXms4XWlA +anE5aHVAcHpBbn1FdoRHeY1Mgo9MiJBNgI9HfotRg41OhYxMgZBQho9PiZNPiIxPhpJPipVT +iZxSi5ZThZZOipNglJ5ck6JgkaVTiJVVh5xUh4xhi49lioFgbGdCSUlRTEhOVE1iYlX9/sH/ +//////////////////////////////////////////v////9///9//r////////////4//r6 +//b6//v8//3s/+/c9dXt9uX9///r9Onr9+X0//Xr/+r9//rq/ez8//Xx8+nu8eXx/PL7//n/ +//778fH5/vn///79//v5//L3//P+//73//T2/+7z/+v4/+7+//z//+7r/+L+//j5//BeUWE2 +Qjc+Qz02QDQ7RD86RTlER0Y+QT80Pzg1PzkvQjU7QTkvPzE8PzozPjUxPTgvQTcyPzY7PTcz +QDc4PDkwPzk6PjsyOzY4OD0rPTg8PkU/T1hLVWZql6CYrrWKp7CEl6JylKV6j5t7kJ93jJ1V +ZXJEWGZ2k5t4mKF/iZtadYdthZFnipdshJJbfY1ke45XcoFed4NripRuiZNsg5RmhYZsjpVx +jZlsip1zjp1ohZlwjJVsjqJuhJ9oiJdrhZVriJhof5Nqh5RvjJpuhJpvj5lohZFsiJdpiZdw +i5hpiZVvipdviZxvi55hfJBhgopqippohphpfZhhgo1jfI9kjJdpiJlzkZ14laZ6j6NshZV0 +npWOtrCZrL6NqbOOpK6JrrKXqraFp7CYtbiYr7x+lqV9l6Z4i6FlhZJpi5Zsip11jp15kKZu +epJGX2VmiYt6mp96jqN8maB6kJxjdIubk326n3eNZV5mfW1idH55pJ2SrbSJkLJzdpBmdoZz +hI6WsLmjusKYvLePsbeHrrKWtbuKqKuMsbKJorJ5lJmNtK+euryMq7pvf5KFsqiQsbeRtbWS +tLuNsraUubqYt7mhwMOfw8KhssFykJWMrLV7kaR1lKR0mKJ5l6J1laNym6Zzlah1lqR4nqx6 +oKp/nqt5pKt5nbFyk6VvjZ5zladvlaV1m693maVodJtTi3t8oq56o6p/pKx8qLSAo69ykqR2 +maN2qq+Iq7OCqLZ+prCMsbmGsbmIqrmGs7WBprR3mqd4nqeAq7SCo7B2kqJkf4tigYaBqLSC +obCDq6yQubWgu8mLsLaFrrWHrr2FrbeMsLiHpa5/q7KLsLGbucJ2i5Rzkpl7qaKUubuvys6i +vsN5kZ51mJ16kaB1jJVykZpvjZFsgpZaiYNTjJlXio9ThZZVjpZJipBUiJZIhIpWhIxIgYhL +i45OhZZZipBWi5VWh5dMgpRPipVbiJNOjJVakpVTj5RWiZZUkZFXjJZOkZNViJJJjJhVkZRZ +iZRRiJVKhYlQi5VKh45Qh4xWi4xLiItPh41RiI5JhI5KgY1LiIlPgY1DeoFJeoREeHtGc4A/ +fYBIdoFDeYBIeIhEd4FHbHw8cHJGa3c8c3dBb3s/cX1Id39Fg4JMiYtOjJBRio5WiI9IhY5K +gIZFfINJeoJVhIVNhYpPgY9LiI9PiZNTh4pSholNh4xTho1Oi4xRgY5LgodNgYlCd39EeIFD +d4FRfYdFfH1Lf4RLgYJMe4lOgIdGeIRCcHxAanI9Ymo8TVQ4XV07Xl88YGI8Y284ZnM+aXQ8 +cXNDd3tCeXlLfIdGf4VMfYNHgYNTf4pDfIhOe4VKfolRg5BRi45ThpNOho9MhY1ShpNPjZNT +i5NPhpFTipVTkZRblptalptkkJtgi41tfW5vXVVwUkRtU0hbTkJOTkVaVEpoZFLu/az+//// +//////////v///3///////////////b///v///v///7///r///////////3x//Ly/+z7//n5 +//T9//fo/+3j+dfw/+/u/Onm9eHv+ujl7+D4/v3///Hz/ev09+77//P///71/+3w/+rs/+j4 +//fy//D+//vz/+37//H2/vP6//D9//r////7//v///7y6uby+/P///3///Lq7eBYTVQ6QTc9 +Qzg3Qzo9Pj02QjZHQj81Qjc9Oz0wQC47PT42QjM3Rjo2PjQxPTgyPDc6QDU4QTc3RjU1Pjku +PTYyPjoyPjc0PTgyPjM1PDk6TEtHUGROXm6BpayasLOGpKeBlZ9ykJt7lKB1mKF4kqNWXnhO +WWpmjpODmqB/jp1jd4dnipBthpdlh5BlfYVkfI9Vdn5idIRkhI51iZduiZNngolkh5Fzj5h1 +kp1xjZxujJhxjptujJ5vh5lqhZlniZFniJlqgY5ujpluipZxiJhwi5lui5hxjJtsiZZyiZlu +jp53kJdtj5Z2jaJcfo1lhJFzkptqgZZkhpdlgZJjgZBpiZZyjZxxjZh2mqB5l6JxgpZeeIRy +nJGbubmiu7yUrLeOqrKQrbmPq7WWtL2furyBlqt5n6R9mqxyjKBziJNtkaBwj5pykZ50jZ9Z +ZIZdfGl6mJx+laB6mKCAmKRmeIWqnoO8onqKZVxneGhgdn50kpx/oqqGra2VuLieuryeucGY +u7yUt7yIsKuHqLCDqquTr7uGq6uPs7WRrreHpaWTtLWavb+OsLN4hZ1/q6GPrbGTs7eOrrCO +rLGLqrCQtLaVubicxL2cu8B5i6CGsqeMq7N1j6Ryl6J7oat1laV5naJ1naZ8mqV6oaR/o7F7 +oqp7qLB8qKh6mqxsjJlqlptvk6Bum6J1maZviJ9RdGR5oah1oqOBp6uAr7SGp694nql3mKZ8 +pLCHr7qBrLOApbB/sbGRrsGFq7GNtbd+p7d8nKp1pKmGrbSEoa5zlZ9kfJVbeoGMsLx+pqiH +r7WZxr2WuL+CprCDq7GHtLiPt7iLsbiIqbGHqLCCsaySvsKInKmAk6F5nZWJq7Goz8y6z898 +iZR4l5p4k5hxkJlzj5JtkJlyj4xjhIxaiotVh4pVjZJRlYpYhoxSgo9IhI5NiZNRiJRMf4xK +hpBUiIhFio1aiYpPi5JVhopLh5RVj5FShpNSi5BRjo1WjZRPiZJTio9TkJJPjJJPipZRj5Za +hZlJi4pWiJJVhotPhoxQjpBViJVLjZFLipFMio9Lho5KgYZUg4ZDgIJLfIlDeYVKeIBCdnxF +eHxDen5KeX5De3xIdXw/dH5Ebnc8amxEbXM4b3NHdHk+fIFPjIxVkJFSjJNUj5BWipNMgIdO +fYtBgIBOhIlIhYhKhYhRiY1RiZFXjJNPiolUhoxQh41QjJBRhotMhItMgYxFfoNMdYJHfXxJ +dYJEeoBMf4pKiItRgY1IhYRNfYxCeIVIaHk2X2g9UVk3U1A9UEs8XFs9ZF07Zmg9bGo9bm5B +cW9BcG1Fb3ZCdHtEeX9Fe4JHe4hFfIVMf4tIhIlKgoxOiolXjJZFh41ZiI5LipBUh5BNiZRW +i5hTio9gko5ql5JyhnZ3a1ePalCkclGvfmCsgV6Wc1Z2YVFYV0dhXUZpak/w/rH////9//H/ +///////////////////////////////+///+///9//z6//b5/+/0/+z8//j9//nv/+vx/+zx +/+7n+ujg+9Ty/fDp9uTg89j////7//Xs9uji9ub0/e7t/+v4//L1/+vy8ubw8uX7/fv///v8 +//n4//P7//D9//r7//L7//b7//X2//b9//f+//7///////fw//D1+ern6NtZTls7RTk5QDc5 +Pjg9P0E2RDo5Oj81QDc0OzU2PTU2Ozo2PTw3Ozg2Pzo6PDYxPjk1MzkyPzs+PTYuOzg3ODsv +OzM4ODotPDQ+O0I0Pz1CVlxGVm5feYuIqLCSqLWAn6WAk6F0ipp4jqB1lKR6laVhan5EU2pl +iY9/laZ8kqJse5FjgIttipdkh5NjeoligZBfcIhRcHxngpFvkZlziZpggItsgZJliJVtiZxr +iZVziplwipRyiplri5trhZpsipZnh5Vph5Zrippni5ptjJhyjZxsiZVvjJdxjpl2jJ5xip5y +jpl1kZ1thZVleo1giJB6k6NqiZJxiJhegpNkfZFihZZsiZhpi5R2kZxwip1ofpRccYBWd32A +q56mwLmluMGVsriXsbqRrrWNrrWXtb2Uorl0l6F6lat7mqV0jaFzjqN0jZx+lKN3mJ1seKFK +WFxzkJR8jZ59laWAl6NsfIerlIe6nniaampfb15fbX12lJl7mKJ4n6SFpqqKq7KOrrORsLmS +rbqNr7GHpLKPr7OXtMGHo7SJrrSPqrR/mqaVtrifur+Vr7l7j6Z4npOPrbqPqLCDoqx9n6KB +oq6CqKqMqLCOtbabvL+Hkah4oZWWr7h+k6Vxkp12laN1lKR2lqV2mqV1kqZ4oa59pal4na92 +pKl8qLF/p7NwlK9khpJqkKNtk6R0mKRyj6tTY25tmJ58oq96pLF/qK2DpLN7obBxlqZ8n6x/ +qbOBpbB+oK6FqLOHqraHsLSHr7aHp7R8orB5oq96qLGHqrB7k6hheIxhg36Rr7d+qLKDrLab +vsWVsruHprSFq7CRsr6PsbiNqrqHq6+FqLWCrqyPuLyftsSjwsyZsLeUvsav2dOtysV+kKR1 +j5J3kJ9wjZ1viIhrkpN0m6h2maZxi5ZVj5VTi5NVh5lRiZNTgZFFhYlWgoxLiIpMhZBFhY5M +gpJJhI9QhI9IiI9TjZZWhZJSjZRRhZFIhotOgY1TiJZRiZNOiZFLiZBViptRiZdShZZSgZlM +hpJJh5Fah5FOhpBRg5lPj5JUiJtOh5BThpVNh49LhY5Tg4tIg5FMfYpJe4BDd31Ecn5Ccn1D +dIdJdIZCd35BeIFHc4FAanU8aXI/anA8anJBcnpJdn5Fg4JUiJBTi5BShIpHiI9Sgo5GeIdM +eoJEfIVJf4dKgopJiolPiI5TipJUiItKhY1Lf41MiItSg41GgopOfIhIe4FDcoA/d35Id3pJ +eYREf35LhYlLgodHgIFIfohGd4lAZ3Q8YWs8VFg4Tl04RkczTFI8T1c0VWA/YGg4Y2lCaHA9 +bWxMdH4+c39Meok+dINJe4VHe4pGfYpJgIRIdIZRgoVUhotQg49SgYlLg5FUho1ThpBXiJBx +i4Z/eGmXaFK2hFzAi2nCmHDDoGzElG+wh2mkeGF7XlNcTUVOUURzZ0/4/br///////////// +//////z////////////////////////////////////+///+//7////////6//n0/e71//Pp +/+fm/t3m9eDr9Obq8uHr/+z6//b9//v9//Xp7ebz9/H1/+/3/+7+/vn///79/+3z/+72/+7+ +//v9//n+//j1//r7/+7r/er3//X6//L1/fDz8ur+/vr//fP29/Hr8eJdT142Qzs8REA9RjY9 +QDs5PTs6Q0AuPjQ7PzovQTc4QDoxQzE5QDs1OzE6Qjw0PjM3PT0wOjU7Pzo3PjI1RDc3PTYt +PzY5QDw1Qj02RENCXmJMbHl+oKeKp7GJpa2Foax7kKB1ip12j596lZ9+laJmcoVMV2tuj5F8 +k6F5maF0gpRgfY9ripdmhZVjfItceYdUdoxRbXxXeH9piZZsjphuhI5lg4xlgZBriJVtjJdp +h5Foh5BwjJpsi5ttiJZqiZRngpZlgZBtjJxvi5Zti5Zth5NphZZui5Vwi51tipdwjptzkJpy +kqJ2jJ5ie4ZnhZBujJpqhJZlg5NphpZkhZFkhZFriZVtiZFzlJ51kqBxh5lecoZYdH9ggYd7 +o56dsrOdtL6XtrybsbuGpq+UsrShvsF6k6R7m6h6m6h2iqdskpR6ladvkqJ5jpxtjJtWVntX +fGl4jZp2lpp+mqKBl6WtnIm7oHmne3NmY1hfan9ykpp9lp53jpx7lZx+mqiFp6mHrbGLr7aF +p6qEna6DqqWJr7R8nKd+o6Z4opyDoa+RsrWfv7+Wub6Om7hpkoyKrrWCpq2Dn6OAoauDnax+ +o6eCqa6Kr7GVubiWr7p2j5WOu7OMqbpvkJl2lKV9mqV7m6V8oKh7nax4oah8orB7n6Z9oal1 +pah+prB7n65xi5pnkZNwlaVylqJ0mKlea41Zhn15qK2ArLGCqKt7qLF/o7J0laJ0oKeCrrGB +qK+CpbB8rayKsruEr7GHr7aDsbJ8oLN3qKx9pKl7p697oq1bcolijIOHsbqDq7OIrKqVv8WP +rraDq7OGq7SLs7WQtsCKq7SDrq+Eq62HqrGHsLGSwbqZvbyhysakx8qn0cmyyMx5jpl8lpdz +kJhpiItliIVzk6SFsqqbwMKRobFfjZVWkphLh5dTh5JRiYlPiItMhJNUi41ViJFNiZBSiYtM +g4xUiZFLiZFakJ5QiIlYjpJRj5lUjZdLj5JVi5NPkJtYj55WjZpXjpxSl5hUjJZVipRRjZNS +jpBNipBXhpRPjJJYiY9SjpBVi5BNi5JRh5RNh5FNfolMhIlMiItEf4ZLeoE/eX5Hd31Gd35C +d4FEfYRJe39Dc389bno8bXg/a3Q8bm5HbXc/dnpKfYZMjZFSi5RPgYZRiZFKio1Pfo5Ee4dD +fopLfoJQf4dGhopTi45Oi5FOiIpJgotOhI5Ng4lMh4pQhotGfopEeYRDdIJGfX9GdoJEen5L +fIJLfodUhYpIgIZPgYJHeYZEZHQ3XFtDUVA1Vkg4SU84UU8/W2I4XWE9ZGk9Zm49aXQ8bHdE +dnpFcn5BeIBFd4FIeX1Kf4hMgIdGfIJJfYNMgYRThINOhItShYtThotoh4d4gneYd2ipgF3K +n3PKqHjVqn3OrXrSqXzNpnXHmm6yiWenemCBY1ZeVkZVVEltb03x/bP///r///v///////// +//////////////////////////7///v///////v////////9//n2/+79//v3/fDs+u3i/eLl +/9n0/vHs/efv9uj5//Hx/eru/fP6//X5/fL4//f69+72/fb6//j0//Pz//H0/vv///74+fH5 +/urr/+/s9+no/Oj7/vXv/+ry//Ht/+z39+31/u7t/ej9//vu8OZaTF8+Pzs8RztCRkI7QTk9 +QUE2RTw7P0ExOzM7QTkuQDk1OjkzPTY+Ozk4QDUxPjU6Pjs3QTY2RDkxPTUuOzc8PjsyPDs6 +OTszPT46TE9Fb3Vuj6CLqrKHo7GFqLCEmqp7kJp4jp9zjZl/k6NtjJtXZHtLWW1liJB5laJ8 +lJ9uh5dieYhkhpNhgJNofI1eeIRjeYhVbn5Vc4BniJJrjZpugZJmfIhhf4hhgY9viJ9riJdu +h5ppiZtviJdrjJh0jJhrhZZphZhniJlqiZttjJ1uh5ZtgpdujJxyjJ1tjZpwjZtsjZ14k6Jt +iJlhgItjhpNzjZtph5tnhJJoiJhheYxpiZlrhZRvjp13jpx6laF0jZpfcIxacHlYcHtlgY53 +opuhvcCgvr6nvsOQpbiMrq2dvb2CkrV1l596nax1kadvip14k51yiJxzkZpvi6Rqep5JV11p +iIZ0jpt5jplyiZiYnoy7o361kHxpWk9gfHd1kpx7nKN1kaRvkZ16mKV+o6mLrLKGqq2BpKZ+ +oqmDoaaLqq+Fpq+Kr7WStrqPq7aYt7eauLqdub2IobRwi5CIqrKIqKx9nqt+oqp8oayBoaZ9 +n6SBpq+Lr7WPr7qAlqmJsK2YvL58l61rkp14mqt3mZ17mqV6m6d8oKl3nah9pbJ7n61zm6d6 +oq57rLR2la1lipxvk6V0k6JynahpfJdMdGp1pax4pa2AprB8pa1+pLVynaB5oa9+q7GKqrSA +p6x/pq6FsriNsL2GrrGMsbp7n6t7nq98prCArrmAn7BicolejYWBqrCEqbWDsLGRsrqEoayE +r7WJrbeJrreMt72ArreJqLZ/qLGDpq58payPsraJr7SVvb6Ot7Wcx8advsWAmZ15i59pkI9m +i4hrmpSBn6yOv7aaxsWgv8JxjJhRi5xSkZxTjZhRj5hWjZdMipJMhI9Rh4hQgJJGgYxLhZJK +g4lYiZNPiJBNfo5RiY5QhphRgZNSi5BVj5RTj5VUkZhXkphVjphVjptRi5xSiJBUipBShIxK +i5NNh4pShJBRhJBJjY5agZNEgIpNhYxGg4lQfYdEgYZQfopEf4hLeH1Dc31HdXtEc38/eXxK +fYtGeYJIdXxDdX8/bng8bHc+aXQ6bnFCcXVJfIFPg4VPio1QhJRKiY5QhpJMgIZKfYpLf4xK +f4dGgI9NhIlRi45Ri49OipFRf41QhIpNgolOgohOgYhJhIdLfYRDfH5KfINAcXtIdn9HdoJO +fYNMiItRf4dJfYlJc4Q7VmM8SlM4Q0E2SkA9T1I9Tk89V1k8WmA6W2M9Zmo9aWxAantAbXRB +bndAcndFdH5CfINRfYdJe4dMeI1If4xUgYhPgYVfiIx0joWdjHG5lnDSq3vVtYHZtILatIba +sn/Ys4TUrnzOqHvMmnO/lWy2gmuogmCIaVViVUdaU0lsZEno+a/9//T///////////////// +//////////////////////v////////////////9//7w/+/8//X7//r5//X8//ro/ufd9tLi +9N/h8d3g8tzy/+34/fH8/e/1+e79//v7/vXx//b+//Dv/+z5/vH///72/evq/d77//b1//L5 ++Pf7/vr//v7///////////////vr7en+//rz++3z++/q8uFjTlw7PjdBREA9RjlIQ0M/QDI/ +PUA2QDs2Ojk9QD08PzQ6QDg1Pjk/Pjg3QDc0PDk6Pzk2Pjw5PDM5PTk1Pjc1OzY7PjcvQjpD +Q0A5S1RYeIeLq7OQpLOIo6+Mpq19l6d+kJxxj5x4jaB6laZ2i5pcZXpPXW5ohY18k6N/lKR1 +jp5meItjgoprhZZgfY1hdoJieoxVaX9VcH5riJBzippxhpptf5VjeYdmgItrhJBqhJNrh5hw +ip1wi5txjpZvi5dsh5xqhZlpipt2iZlvjJpvjJpujZxyjJxvi5hxiZprjZh5kZx1kqRqhJ1i +fI9phpdxjZ5yh55shZhuiJhmf5RmiZR0i5dqh5l3ipt2k6BziZVoepNVbntecX5edYJsiY+V +uLKhu8GZvr6Rp76Ir7CduLiWq7p6kJ97nqyAmqpzj59yiZ9wjqBzjZNyj6Fxi5xVYYVVaV5t +ipByi5dyipyBj5CxoYG8nnyCXWFfbmJrjZR6kaNzj595j6F8l6eAlKaDoaiHobKBpqqDmqqE +oaqQq7GGq7WMrbWSsrSNq7WUubWkxcmfvcSKn7dwh5OGqq+EpKx/nql9m6B/nat9pKp/n6l+ +pamFpqyMsbSUpr18npyatsWOprl2kZ92nad9na97mql8oa99oa18nKl+oK17oaZ8lKp3nKt/ +p7N9pLRxhZ5tjpRykKJ3laFrfp1OYmVrlpN+pa15oal+nq96pKt7mKtynKp/qreEp7SJpLR9 +qbCNrLmOtLeIq7mMrLmBobB7nrB7oKWCpbONprZvcpBlk46Eq7WEpreDqLCQp7SGq7CPqriM +triQsMSIsbOKrriMqrSGpbSBnaOAn7GEqKx9qLONrbOKr7aWvLycvMiJmJ9+kaJrf41hioWL +trqcwcGUtbqKtbGSvcaMkaBXh4hViZZTkZVahpZTipNZh49Ifo1Vg4pGeYdNfIdJdoJPgn9R +iYtQh45OgIlMgYJPipFOgIlVhpFRiI1djJZWj5JZkZVVj5JUhZVTiJNViZRMh41TfJFKgIxS +gYpSh5FSiJRPhpFWh5JOg5JPg4tQg5BXhoxMfolRe4dFgIBGeoZAd35Ecn9EeH5LeoFEdn9F +d4ZCc35IbYE/cnpCanY7anNBY3NHbG9EcntIgodOiI9TjJJWhY5SholPho9OgIdDdYNGf4FJ +eoRKgohai5FSiZNXg49PiI5Tg4tSiIpPh41Kgo1Qg5FJfYROeIJDdn5KcYZEcntOcn9He31S +hIlKgIpQfYdLZnpBVWA/UmA3RUE1Qj47SUs8T0xAUVo9VllBWmg6YmZBbHNFam1HbXtCbnhJ +bX4/c3tOdYRJeYFSeIVNeYZhgYZsinmjinPAn3DTrX/VvYnbvonauofjv4ffuYbduoHZr33c +sHzbrnvPq3jQnHPFm26ygmGod1+KYFRkUk5cVEVuYlL7/rD///////////////////////// +//////////////////v///////////3///////P///3////w/fD5//X3/fbk9OLs/tz9//j8 +//3y++319O/0//X2//34//H2//b2+Onu/ej5/fP///T+//r+//X9//f///7///////v///L9 +//3///fy/+/z//Ht8+Lm/Ob4+vP+//j///Xu9uvy699ZTmJCPT0xRz1JRD81PT9DQDo8QjpA +QTg2PDo6Pzs9PDw2Pjg8Pjo6QTs9PTUyPjg7PDo6QTg8PjkzQTk7PTs2Pzw4Pjc3REA6RkZD +WmNago2Xs7mLp7KLo7OFnqt9mKh3kqF3jKB7jJ2Ck6JxhJpPZ3VcbH5ojJl/mqB8lJ57j55m +eY5qepBiiZFlg5JddodceotWcYdWaHpdfohxh5dwh5psh5hshZBieoZke4xkf5RsipBqiZVw +i5txi5xtjJ5yi51ri5dziZtnh5ZzipxriJttjZlriJ1vi5pqkJhthphvkZ13kqFqhZpkhZdl +hpR0kqFxjZ5vjZ5xhp1ohpNmhpRnh5JxhZpxipl2kp13kJ91hp5ic4ddcXxacYJfeH95nJyS +treetb2Rr7eWr7mTs7educCAlKyAlqN8prJ6kKpthp13kqR6lJx3k6NxiaFyg59GTWZggnlw +jJVvh5hrhY+Yn5OwnnSVcGdZZlh0jZh7k5+DmKt+nJ+Al6Z9lqCDn6+CoamAmq1+nKKBpqyK +rKyGprWKq6+Xs7iUp7uJq7GbubuXtbqPrLt1j56Hpq6Hoq9+mqF7nKN+oa5+m617m6aBpKqB +p66KrbOTtrWJm6uTu7egtMCBmbR8m6d3kaF8pa18m6p/o7B9oa5+o6iEqrF+m61vkZ16q7CD +q7R6nqxvhp9uk5p1mad0japRVW5kkYd+qah/oLB6oKl8qLZ8n6p3oKh6naiAqbiIqrSFpLON +rbSJsLOMq7KIqriApbR8pqeDprJ9qKqDq7RveZhtlZuBq6yHp7eMsLGWprqHsrWLrrmUtbmI +sLuSsb2HpraJpqyDpbSAn6t6oauCpah9oKyFr6uDp6uMuryqwsuBlZ9/iZlefIxvl5eWwsOh +wsiUuLePsLWJsbeYr7tnd4Nej5pemJxhlKFYi5VWi5RPi41ahZhPg5RKgY5Je4dLfYdLfINN +folHhIhTe4lQiYxWgJRPh5VdiZVJjJBYi51XjY5ci5hUjJdhj5pShpFUgphKiI1OfJFKg4pO +hY5SiJRLhY9XiY5Njo1Rgo9KhopOh5FPg4pLgYpNeoVJfIRKcoRDc31GdoFDdYJKdIlEfIBK +eoZEdYBGcHw7bXNCZ3Y9aXBBaHJDbm1EdoFKhoZai5dWhJZUhI5Sg4xKg4xNfIlKdoZKgIRP +golQg4dUh41Pho5LfodLgIRUfYhMg4ZTfo1HgIlSgI0/dIBRdYBBcYBJdX5Hen1QgYZJg4VX +g4lJb349XmQ9XWJDTlg6Pz83PTpBT0Q2Uk5AUlU9WV08W2E+YmpDZ2lDbXRFbnlFdHxHc3xQ +doJTfX9riISLjHarlXvAonzIroTPun/cxI/dxJXfwYnlv5DcvojiwY7lvIbetILcsoHatXfZ +snfZo3fNnHPFkWq1f2aufV+HZldqV0tZUk1iXU3o/qr+//r///////////////////////// +//////////////////////z///z+//z+//3////5/vf7//L///r3//Tp/+vh/9ni8uHj7djm ++OLq/ebw+un2+efs++r+//7///fw8+fs/On5//X9//T9//D7//n+//v6//Po/Onz++r9/vv6 +//X3//Pz9+v9//7///////X8//T5//z///329utdWGFEQEA2QjhESEk/PzY9QkQ2QzY5QUAy +PjYzQD00RDk8PTw4QDU7Pjc1Ozs1PDc1Pzw8Pjw9QDc4PTY0Ozk8Pzc7QTc8Pz05TVJJXGps +naGbsLiHoKyGnq19n6eCmal6j555jaJ6kKR9lKZ5lJ9fZ39TaXptkJR7j555kJ56ip5pgZBh +fYtheotoe41edYNbcoVgdYhOZnJgfodtiZt0jJltiJpuhZZleIdje4hqiY1uiZVuh5dujJly +iphzj5hshJhriZdxhZdoh5VyjKBuipNxiptxjJlyiJtqh5RviZlsiph1kqBsiZxkgo9khpJz +lZ1xj59ujZtriJhrgphmg5FshphshJVwiJ5zj51zjqJ+m6CIlK1hcoNcbYBacHxmdYN2lJGX +tLifvMGQq7mOrrSUq7aRpbp1kZ6AoK96mK9yjJp5kZ99naZ9lKN3kat2k6Vjb5hPYlhthJBz +hpVuiJSBlZXRrIewi3RfX1J3jpR/lqGJpq5/mqR/l6x3l6SEnaqBoqt+mqVzlaGDoqqBoamH +o7GPsK2VsLiForCKqK6WsrSQrraRqbiAoqqGo6uCm6l8mqN7mad8oqWBoq5+nqR7m6p/n6eK +q7KLrbKUrbiPta2mv8ectryCl656mqGAorOBo6x7nrB+pa6Co66GrbKEqLB6lKd4nqV/pLGB +pbR4m65ngZZwmaZ2nK9aXYBYfXV3oad8nKx3o6yEpbB7nK19nKh3oauJq7GCqbCLr7iDr7WO +r7eHrLWLqa+BpbR6qbCApbF3oayArbZ8hqFqjpuGprSGsbaMq7CSqrSJq7SLsrSTtcWRub2L +rLmIr6yFpLCCnad7mqqBpaeCpa+CpauGqreGqKyItLemzciNmKBxh45hfohyq66Rv7ybusGL +r7aMrLWKqrORtsODjZlRipZelJVblJhajZZUlJhjjpBMjaBZiZZFg5VUfIpFeIVSfIBOfIdM +gI9Ld4pFhIhThJFNg41VhIxVipdYippRj5pijZpQjZpci5JRjZFYkZ9QiZBUgJFJgI1QhZFW +kJZNi5BMjJJLhY1GhY5WhZBQgI5NgYtPg5BLfoFGd4VMeINEdHxHdYFCeoVJdIRFe4NIcIE/ +bnxCa3c9bHZAY3E7aGlCY29CcHNFbHlCfXxTho1Qi49RfYZPioxPhpBPgIhHeYRIeIJHe4FQ +goVRhotQgYZPg4xUg4pQfohPhIZRgo5PhoNQf41GeoFNeoVDd39NeYNGen5MeoFLgYFUg4pL +eH9CYmtBWV86RFE0QDw3QzU8RDo6RjxBUEU8WFhAXmE+ZGg+bXVGbnZIcndXd3huiHOclH2w +pnnHrofMtInRrovNt3vYvITUwIvbxIvdv5Xiv4zcvIbivoLhv43guIjdtX/cs4DYrXfdtHfc +rnvInnLIl2i6hmWofF+ObVlsWktaVE1aX0fm+6n+//X///////z///////////////////// +//v///////////////////////3///v5/ffz/uz9//z3//Tm9+Lp/ufl/dnx/O38//Ly/O38 +//Xy++3z++zu++jx++ny/vD3/e31/uv0//Dx++7w+Obv9+rw/e3u9Or5/vL///35//H3+e/y +/PL///7z/+f4//Ln6+Pj9eX4/PDv/uzx8eVmVF89PUA7SkA+R0JBSj8+RDw9Pzo7Pj87Pjc6 +OTk/PTguQDM7PDkrOzVAQTcxQTc+PzkzOTZBPDYyPTY6PzQ2PTg4QTg3Qz4/VFpJZHJ1oaCV +rbaKprGFnamCnaiBm6Z1laN9jZ11jp15kaJ3j59jZ4BQaHhujpV+kZ54jp92jqB5hplgf41j +gZFkhZBieo1gdYRjeopYZntVdHxojZJ1i51qh5JwjJRmgotkfYxmgolnhpRqipVvi5psjJhu +hptxiZtwip9ui5pxiZhvjJpvh5RuhpVtiJdwiphijJpmiJdrjZlyjZ1pgJdifYZfh5Fsj5V5 +j55wjJpphpJihI1lfZJnh5Nqg5NrjJt0jaFxj5d4kp+VtbSEjK1bdYFacHtbcn1geH50l5mX +tbGNsLibubaStLegub96lKt6mad+nah5jKdylKBxjp5wkZx2kKB2k6VvhqFBUmtfeXJmg4py +hpVqiY+js5uIdWZrX1NtkI2Alp95lJ96l6B6lKN9laV8n6h/nKZ9m6R6maZ9laSIp66KrbKK +qa6Goq2Qr7WFqqaNrbGMq7OVr72BqauKqbWDoqqCnqx4m6CDorN/nKd9mqN6nap8oaeAp6mJ +rLWQs7GTsbekyMehw8SMpLl9o6l6oad9o6l+p6yAoqp8pKqFqbd+o6t7maVrkpyApa1+prd9 +pqxzkaZxj5x3oKdld45HYmBwnJ51lq99nad8oKh8o6t9oq19oaqBqrGGqLSDqrCFsLSKr7mJ +r7GGq7WHpq96pKyBpLR+pqyCqLh+m6pwl5+Kq7CKsLqKqK2LrrWKs7OMsbaMsriJtriFqLSH +qbB9n7B6nat+m6uApKqEqbSFq7CFo6yEq6yKsr6px8l4i51xfYpbhouDvq2StLyMtbiFqbKJ +r7GDorGOsa2Vsb1jfIBXj5daj5tbjJpeio9Xj5VVjJVWf49DiItRfI5FfINKeoNIf4hQfYhL +fIVKfoZFfoVQgYlNh4hNfo1ThoxRiZtGiZhUkpNgkptXjZVWjZVRhJdLio1Of4pKhYlRipRM +j5VViJVOiI1Xi5RRi4xSgo1GgYlOg4hGg4tIf4tEeIBHdINCcn5Ldn1DeX1KeoJFdoI/eHxF +cnlDb3dBanU8Z3M2ZWs7ZnU/aXBEdn9OgIRYh5NJg4tOiY5QiJRVhJBGf4VKeYJGeXxRfIdN +g4pRgYtOhYdMgYxKhYhIfohNgYZJfohMf41JeohMc39AcndEcHtFd31HdXpNfIBLfoNNe4I/ +YW0+UVg2Pz08PzwyQTc8OzwyPjdAQUI3S0JQYFBWcFhyfWeFh22glW+qm3S4pnnFsYXItoXP +uI7RtojXu4bSs4LRs3zQs33WtX3auILZs37at4Pat3nds37btXvdtIXasXfdrn7ar3jWsHzQ +n2/Ej2+3hWGlfGGPaFFuWUtTTUhXWErh96T///z///z///////////////////////r///// +///////7//r///////////////39//n9//7////////7//Pu/fHi/NPu+unr+uPh797z//Hy +/ent++vy/+nn8OX6/vz///////n9//P7/e76//T09eft++b+//3////v8+fm8+L7//j///n0 +/+36/vj///r///n7//z////19+/x695oV2RBQz46TEBQTUc/RkE7REI8RT0+SDw9Qjk1PDs8 +Pzo3QDU5QDo3Ojk/OUA1QTc5PTU1PjU7Pzk4QTk1PDo8PTk8QD06RUZIVGVRan2Mr7SPqrKG +prGGpbCEnqh/nqt+k597jp97jqB1k6N8k6NqbYNTZnZskZeCmah3lqd8kaJyi59qeZFefYpt +g5JnfpNac4VfeYhdcoNMbHZsh5RtiZZwipdyi5prhZRje4ljgY5nh5FnipJqipJziZZxjJlw +iZpujJ1zjp5tjJ10jJtvhplwiJdtiJRwhphojZtvi5pwjJt3kp9sjJxkhJVkiZd1lKR2jqJv +jJdrhptrhpZig5ZqiZVvipl1j6B0kaR2kKRxkZ6Jq6+Tr7ODkKpieYdfcn9Wb39mcoJsjoyF +o6aQt7ScsruTtLeLn7d6lqV+nKp4kqRui51tjJ91jp52jqZzkaN1jaBdcZJNWlNogopvipBw +h5VtgpGBh4tqY1dyi4hyi5pxhptsh5R4kKF1lJyAnqh7mqZ+maV7maiAn6eFprKJqbGJrKyJ +p7KLqLF/m6CLrrOYubqdt8GQsLeMqrWJpK6EoKZ+nKuDpayCo699nq+CmKl8nKSFoK2GpqmP +sLOXuLmbuLuVt8CSrrl+lKd8oKqEpbSDqa2Co7GDqquDqLGEqrKAoLFwk6J0naN6prGAqLOF +qLN3mqtznKdwiKBOVmVkkJB3nKl1lqR7obF7nql7n6mAqrOAqbSKq7KCsLeKsbeIq7SPrcGE +rbOFprSBp62EqrWEqrWDrLWApa14nZ6Ip7CHrLaHr7GHpbWDrLKMtLyMr66NrLmFpa2DpK6B +pKR9oKp8o6p/nap+p66Fpqp/qKyBp7CIvbuct8Fzjplrf4lliY2XwMCRsrmQr7mIq62EqLCK +rqyPsLmNvbZxgpJWiohcj5tYj5VZi55Vi5lYjptWjJpVi5FSho9Sgo5FgYFKcXxIeYBNfYBJ +eoFOdIRMfoFKf4xKfIdUgopNjpVYjpZWkJlikp5QkJVXjJZSkZhVjZZPiZNRhI9Wh5BPkZlT +h5pTjJhSiZRUjpJTh5NQiJFRgJVNg41GgIRRdIRJd4FHc4VAe4JOgYpJdn1Pe4dCeX9GdoBi +g4FPbXlKbG9CZm8+Y2g/Z3FGcXpLgIBUhY1VhZFRgohTiY5Vg5FOgYVLfohNf4NQfoROg4dO +hotOfIhRhYZUfYZKfIRQgodKio1chpBJeoZSeoI+dHpMcntDcX5IdHpLe4FPgYVRe4VJbnk+ +QVQ4Qjc4QDgyQjo7Pjk3PDk9PztBTUNlZk9/f2CPimqfmHSpmHKwnni4qXnKsIXMt4HRtozW +t4LTtYfXt3/St4bXtX7RtIHbsnfZtoDeuYPauH/jtoXZtHvftH3btX/br3vXrH7UqnfPpnPH +mm2zh2SqfF2bdll1XUtZU0xRWEjs/av///////////////3////////////////////6//z8 +//P///X///7///f////8//z+//T+//r+//f4//T9//bs/+ng9tXm9ePs9+Dp9eX8///5///5 +//P9//77//f9//v7//b0//P///7////9//X1/+/0/vL9//7///n1//P+/vb9//75//D7//f7 +//P6//Pv8unz/On6//P9//ju9+Z2T2s6RjpDRUZGTERKSkVBRD9CRz4+Rzw8Qjw4Pzs5Qzs5 +Pzc0Pzo1Pjo2Pjk2PDY5PTk6Pj4+Pjo6PDg8Ozg5Qzc9QkE7SUhBU2dYg4yQrbqNpq6Fo7GK +oK6BoayIpKmBlaZ0i512j6J0j518laVwf5RKYHZiiZOCnqiCmaR5kaJ6k59mf49ng5Ftipho +gZdgeo1ZeYhhcohMZHNnhJJsiZRwiZhqhZdxhZpif49ke41lhI1rgo9ph5JshZpohpNyi5p1 +kZ51j51xi5l4jZ9wippwiZduh5lwjZdohppqhpVwiptwjZ1vip1rg5pohpVxkaF0kKFziaFp +iJ9vg5xhhZBqhpFri5h0kaJujqJ3jJ1yj6J8mKWCqq2evbqHnbRfd4xdb31dc39jcYODo6KX +tbmZu8Kar7mWr75+l6eAoqt/m61ziKRzkZx1kadyjph1jKB4lKJukKJJWHBWbm9ofYluh5Nt +gJRuhI9uaHlkg4Fqh5Noh5Zvi5lwiph2lZ57laN9laV+naOAoamCoa2Fo6+IpbF5mKuBoK6A +pbF/maR/qqiYuLqUtMGNqq5/prCCnqp/nLF7nKeCpq+HqLSCo6x8oKmGp66KqrOMqbeLqq6V +s7iVsbyYuL6Us7yBnat6oKl/n6mAo62EqrGKqbKLrreHrLeEp653naxylad9p7WDq7eFrbZ/ +orF0kKBvh5xRYmxghIdzk5x3l6R4nqt8o7J4oamAp7N6oqqHsLWIqrOGrbqKsraLrraGrK2E +rbeAp62DrriFqrR6q7WIrLB6nqiGq7OIq7SJsrKJq7OErrWNrLuJsbqRqbWEqKyFq7N+o6eD +oah+qK+In7B5o6qEsLiBqqeFqLWKsK+esb53kp9jfo5kkZSawMOMqrSFq7B+p7SFrK2EqrGN +u76TvryLpaxSgoZckZpXkphZi5VRjpNTjJtTkppbkJZRiZFXjJhEgohLe4s+dn1RdYNDe31J +doFDcX5KeoVMf49KgZBRio9Wk5pakJdak59TlJxZiptTjpdRgppOhpBOhJBKf4xQiZFPi49T +i5ZRi5RZiJhNiJRWg5JQiIhRf49JgYVLfo1JeohId4NHfoNFd4NJfIZDeINKeYNFdH1Td31C +anREYmxBZm08Z3BBZ3M9cHJQfH5KgYVXjZNIf49ShYtLhJJWhIpGfIxSdoVKeoJOfYNMgYZS +hopOhpBQgoxLeX9JfoFRgodLgolOe4hIfoNMeYFDdIFJbntEdH1LeX9MgIBNhIVPeYY9RFM6 +PUI4Pzc1P0A7Ozo0Pz88RDo8RkFfY0x3e1qRh2eZkG+nl3KsmnW8pXu+rILLrIHStoHUtYvQ +tH7SsILPs3/YvILVtYXbsX3YtILes4PbtX3ktoPftX/cs33itoDeuYLYr3vPqXjPonPClWu4 +gWSufl+ad1mDZ1VgUkpWVErb+qP9//T///z///////////z///////////////////////v/ +//////////7///////////////////z6//X6//3k9+Hn/db8//v2+/Ln9uL5//X2//by//f8 +//f7//j5//H5//j4/evr/PT///7+//X9//v///7x/+z2/+76//X///71//P9//j7//X++/P0 +/vP2+/P8/+z6/e3u+Ojs8uRxVmc8Qz8/R0VJRUE9RD5DQkI7RkFBPkA6PDg7Pjs2PTdAOTg1 +PTg9Pj42OTc4O0A1PTk9PT43PDg4OzswQThAO0IyRENASk9EWGldfYeKsbSUrLqOo7CHoa5+ +maaAm6p+kaZ2jp53kaCAlKR8laZ5jaFJXHRph5J7mqJ9lqNykaB7kqVzh5hthpdnh5Vng5dh +fYthd4lbdIZTXnZbeYFphJZoiJVwiZlyhpZsgo5ieY5lgJFjgpFpiZdwiZpviJZtiZhyi59s +jJ5zi5xrjpZvh5xrhJd2h5hsh5dwgphghph1iZ5vjJ1xiZxmgpdohpNwiZ5uj51wh5xqiJ9s +h5dkh5Frg5JyipZujZxshZ5xhZJyi5xxjJuBm6OHqKmcs7qHoK9repdXbXpfc4FgfX5/paSg +u7+cucGWsbyFmbJ/ma2CnK96jKdujpd3j6Z0kaFxjp1yjpxyjKNrgaNLUWJifHlmhJFqgZNq +hZBtg5RlgJFpgZFogY1ugJJtjJR4k512jaJ9mJ97nqSApKqBoat/pqx/mqd7lZ+Doq18n6t6 +kKZ5lKCCp6uIrbGGpKp9oamBoqt/oKyDnayCpa2MqLWZurzO5djc8enO593I2NnL2dfV4dvd +8OTf8+Xh8uPg7OTOztmbq7uMrLiOr7aKprmMq7SPrbaIrrWAoax3nq95mqZ9qLSCqLODpLOB +qLVvgp5ZeY5XdGxwk6J3maZ7nKyGqbZ+obV2naJ4oKx+qK+KrbOIrLWJrLKCqrCMr7aHqK+C +prN8pq2EpLSBpKqEpLR/q6qTqbyMqrSPt7yLsLKPs7uMrLSCqbGCp7KNqraCoLGBpqqHqrGC +pK6BpbGCqK2DpLKEpqyDrLWOrrKVsLR+jpxjgYp0n6OZvMKPsLx9oq+Fp7N8pauFpbZ6n6uH +tLWSq7pofYZUj5dgkZ1ajpdRlplekJxfl6BamptXk55ZkppVi5NJgo5Oc4REc4VNc35Dc4JG +bn1GenxIfYtGh4ZUgpBRhotYjZFYkJtZkKBVkpZZjqBTi5RShZJWgJBQf4xRhZFMhI1Ui5RT +iJhSiJhXh45JiI9QiZJOho5MhotPgY1LeIpDdYdLdn5AdYBMdH5BeH5ReIZEeIFUe309dntF +a3g8ZHJBZ209ZG9Da2xEdHlKgolUjJNWhY5KfIZNh4tVg45GfotLeYVMe4FKfIdMgYhNgohP +g4pRgIpPfYZNgoFMg4FTgoNOgYpOgIdKfIVIdn9EcH1Gb3xJdX5PeYBOgoRXfYQ6SmM6QD83 +QTo5OjgwQjY5PD42QDk6RTtRVERtbFSFemCZjGSnk3KumXa1oHTFqoDLqX3MtH/NroHQroHZ +sH3Nq4HWtH/TrYLUsnvZuYTatIHfuoLguYfft4Hbsn/gr3/YsHrfrnzRqHfRonjDk2vAiGun +gWGgdFmEa1JvWk9aV07j/qz///////////////v///////////////////////////3///// +//////r////////6//L5//L2//Pz/u7q9OTz/+zk/t3n8+Ds+eH2++/1/+nz9+b7/vH5/+/4 +/fD0+e/69/H+//r///L5/vrt9+vx/Ov3/+////3////////7+en+/+/2//L4//D9//7///Xy +9PH1/fL///X5//L1+et+V2RAQkFHUEJEREJDRz06RDhERj42QDlHQDwvPDZIPz0yQTlBQTkx +Ozk+OjY1OjpAQTszPTo/QDk3QTw2QTU5Qzs3SEZBT1pJXGJagYaLqrCVrreHqKySp7CFoKeG +n6d/lqV+j6N7kKB6lKJ8mqZ7kp1TZXxWfH53l593m6F1mKZ5j6N+i5hmgY5riZdngZZkfohh +eoldd4NYZHtTdnZrhZhoi5pzjptyjJpuhphkgIxlgYdkgIxpho5rjJhvi5lzjZl1jqBzjp1y +iptxjJ1uhpZxjplsi59wi5xuhppni5Vyj5ttk5t4iJpri5VrhJlukJx7lJ5vjp5wipxqh5Vn +iZNpg5ptiJhvipd0iaFzkpx1jKRwh5RwjZiCmqOGqa2YtLabqLxqeZddb35bc39ghoSArqCh +v7+Wt7+Wrrp7mqSMq6uGo7B9kZ92mKF6kKh1k6R1jJ90lZ14k59dYY9QY1tpg4tqhpBrhpFq +hZFoh5Rtg5lohJBmf5Bqg5Jxkp93kZx7lqR8nqJ8o6t+maKBoauAmqR7lad9oKiCnax6kJ55 +k6d9mqCCnqp8l6F8mqiBo6WBnqOEoaeCpa2aubnQ69vb9OXY8uDf9Obp+ufj/OPU7ePR69/Y +8N/a9+Ls/evw/ers5+fe4t/m3uPW0tzBwMybsLuXsLeHp7F+pKx4maqAqayFp7aCq7OJqbZ0 +g6FZdHVTXmpqi5d6nJ9+qLGJrrOLr7p2mKdnh455oqiKsK+Nrr+HrLKLsb6JsbKLrrmHqrWF +qLiKq7ODqbOBrKyErq6Gq7OErbaOs7yKtbaWvrqIrLGQqreHprKFp7CHpKR9pa6EqamDpq6H +qKeFrbGDpq2DqrCKq66Pt72kwcFyipVqgoh3q6mbvsGMrbuEqrGCpauEpKqAo6Z5oqeGr7Gc +ubpqfIRWko9bkppVjpVajJ1bl5JdjJdalpJgj59XjphamJ9WhJhZiZFKfIZKd4RAcXZFc3ZC +c3ZJdXxIeH1SgYhLiY5UjpZalZ1ilJ5WmZxXkZ9XkJ1Vh5lRipJOgJVSiI1VipFHiY9Rh5NX +ipFZipBTioxYiY5KiYtRh5JTho1JfYpOf4pIeYVJeIRMfoFCd39Kdn1FfIBKdn5EdH9Fbnc+ +aWtAbWs8aWU+am8/dHJNfYZSi4xZj5dMfodVhYZTjIlJg4xFg4ZLeoFKeIJLeoJPgYdThopS +iItMfYJOg4dRg4ZShIhPgYdJgItPfIRHc4BMdn1GcnlLfX9FenxPe4RMgoFUZ300Qj88Pzkz +QjpAQDg7QTk7Qjc+RThCUEBjZU18dVKOhl6ljWuqmnGsnXTAqXXGqnjMsHvNrnzPrHzTsn/V +toLUuYPbsnvYsH7as3fcsoPbs3rhuH7fuoDitXzds3vbtXzcsXjVr3/SoXzHmGzElmuziWij +dF+MbVB8YFNiX0rV+qD///n///////v////////////////////////////8//b6//D+//L/ +//////v+//3+//z9//r3/+z1/u32/+/y//Dn/9fx/e/1/eru9+bt/+/1//P8//D1//ny//P8 +//b6//b9//L4//j///z////5/+3u+/Hy/Ozw++bw/+jy//X9//fx/PD1//T1/+v5//Xw/Pr/ +///0//P7//zw8d6CV2k8PDs+R0NDSj9ARDw3Pz85QTg6Ozw1Qjo1PDw+Ozg1OjU1OTwzPDQ1 +OTkyPDc6Pz4rPDU5OjszPjQ2Ojw0QTc9SlBBTE9MWm5SgYWCpK+MrbSNqbSOqbKBoKl9n6p8 +mal6j6N/lqF0kaJ6lKd3k6ZfaINObX10j5t4kaJ5kKR5lqJ7kKVff49ph5Vdhppkf5RXdo9j +eo1RaoBKaXRngJBkiphvi5tvh5VripdkhJRmfI1ceo5kgpFkh5Vviplsj510jJ1vi6Jwj59u +i6BrjZhwjaFsh51sj59uhZpripxzjptujKJqjJtig5pph5Zyjp1yjZ1si5twjp5th5lmg5dr +iJhriJhni5tuj51viJhzi55mhJNpi5ltj5p6lqGBoKaSsLWKoLdjdY1ab3tccH1jgId2lpiL +q7CPsLyFn657m6uMq7NuiaRti5V+k6p2mqZ9k6dripdwh55ykqNJVW9KZmJqfY9lgpJthZRq +h5lvhplngpRle4pkgJNwhpR1jp96k6Z5laJ6lqJ5mqZ7lqd1k6J3lKh6mqWAnKx2kaJ4k6J2 +lKR+nKl2lqR7lqd8oKh/oKt5l52EpK6+6NDf8+jS8uLT7uDm/enk9ejg+ejs/evs+unm+urq +/Ov0/+3///D//+7//+z7/e77/+z9//Dp5uTL2trN19LLzNW4vcqfsLqVsr2UrMKEqbSBnbJY +YmpbZYNbiH94mal+p6+HsbWIsLp/pLFyj6JmhZOEpqqJsbeFqrWEqbCFq7SCqa58p7WAqbCC +qrKHpbN6qbOBpq6BrbGIprGIsryHsLWHrrWLq7aCq7OMq7GBqrCBna+BoKyCp6mDprWBp6uE +qrGEo6yDqq6EsLaPvb+arrZziZBnh453uLGatb6EqbWFp7N+pKx/nat2nal+obGBs6yUt79p +eYJWhZJSjpJVj5hak5ZVk55SkZdWjZpWjZtVkJpdjaBWkplXiKBSipRIgpFGdH5Db3pKbXc/ +bnxIdIE6coBLgIlEg4VSkZFUjJphkplXjaFZj5pVjppUi5FJhpJKhI5Nh5NLiYxQh5BRhYtL +hJNKhotRi5BLiZFOg41JhZFLgY9NgJJIeopFe4ZKeYVAc4BCb31BdH5Hcn5AcH9CbXc6aXY8 +YWs8Zm43X2k3aG1Jd3xKg4NQhoxMh49MfoZGhoNPgJBGg4hKeopJeINLfodJhIZSgodKg4hK +fopJd4NLfoNKf4VPfYhHeoNHfIRLdIFAcXtEb3pEd31Dc3xGdn5Ke4BQdYU3RlI4PTwxPTY6 +PDgvPjQ4PDYvPTZBRUBZXkh0bVOEeVyXiGeekGqslnS5oni+qHvApnvMqH7JqHzOs37Ss4PQ +r4LTsH7VsYHYrnzTq3/YsH3Vsn3atnzds3/YrH3VpXzOom3TpXDJoGvJmHG0jGq3hmqgeF+Z +cFt2ZlFvXlDM85v9//X///7///7///j///////////////////////////n////////////+ +//v5//T+///7//b9//T+///4//zl+N/a9tTt/ebh9N/h8Nry8+br+ery+ejm/eL4/fH8/+zp +9uLy+uTx/fL7/e3h+en+//z///n///79//X7/e/0//Px/+zy/Ov5//Tl9ePh9OTu8uj3//D8 +//r///Tq492HVmk+Pj06RTw+PkA2Qjo6PTs2RjY8QD4zQDc4PDo6PDc0PTc0PTU1PDIsPjY4 +QDg5Ozs0PTY3Pjw3PzgzPTc6REE/TU9EU1xLYW1Zfot2oaOPrLONsraQprF8nqZ6m6p4lqB4 +jJx1kKB6lKV8m6SBmqdxc5RXcYJykpp9kqWBkqJxkKB3kJ1nfpJripdph5dih5BdgZFZeIxj +boJFXWhigo5hg45viZdtjJhwiZZoiJVsgZVaeoRmfYtkho5yiZlwj5p3jJ11jpp0kaF1jaFr +iJdwi5psiJhsjZptjJpvk59vkKBxiJ1phZdmi5Nnhph0lKF3jqRuiJdxhZligo9sippqjJlp +hZVlipZ1jp5vjqFzi6BmhJVshZJtiJZ0kp15kKGEnqaNrrKJlrBlcIxYaXtXaHdXc3hhf4F2 +pZZ9nKl+n6uDo6x+na13mKF2lah2kKJ3laVujZlvippzjZlwgKJJUWdXdWtng5Rrh5Rphppu +j5puh5hjgIxigI9oiI10lJ98lKN6kZ91k595kaBzkaBvjpt4lqB7mKJ+oq14nKZ6lKN3kaF+ +m6h3m6d5k556nKx+oKZ8naSdyLfZ9uTe+efb8+fm+uf4/+/6/+39/+78/+f9//L9/+v//+v9 +/+3///L///X///T9//b9//T+//L9/+z9/vPx/OPv/+n6/+f49+r6+ubu8efd6uHDwdCXe6VV +c3hSb2lxnKGCqLmIsbWKr7h+p7F8orJthJx0p6eJo7yGrreJr7SDqrSBp6qBqK6Bq7KEp7OH +rLJ/p7OCrK+JqreHp62NsryFr7WIrLV6qqyGp6yFqbCCo7V9pauFo7CDqq6DqLB/n65/obGB +oqyJo6uBq6uUu7qXsrR0h5Jkjo2NucONrr+EqK2BpK18oKd3oKd5mql6oKyHsrCRsblkdYFD +hYVThpBOiYhejphVjppWjJtZkpZdkZ5PjpFgj5tVkJ1ih51UkJhVipJMgY9UeolEbXw9Y3JA +anM5bHNCdYBFgYNSi5ZVj5dTjp1WkJlNjplWj5pYkZZVhpRHgYdVhI1Lg4lNg5BKh4pRiZNN +ioxNi5VLjI1ThpBQgoxLhpJQgY9GfYpKe4ZFeYJDdH9AdHtEc31CdHY/bn1Db3M9ZXI6ZW08 +X2pCZmY7aG1Cam4+e3lOhI1TjJJMfIw/g39Vg4tEhIZNf4lBf4dOfIFHf4JKe4dPhY1MhIVL +doVLh4BQgYRPgodMfIhEfYFIfIJGdYJJdX5Ac3dIdn1EentMeH9Lf4VDWHM2PUQ0PDczPTs4 +OjQzPTw1PzI3RD5RWkBnaUt9dFWOg16hiGilkGi0lnC1nHXDpX3FrHrOrnvOsHvStYDStoXQ +rX/Tq3vUt33Sq4LSp3fXsnjWtoPct4HZrn7Zq33TpXHRonHHn3PGlW23imWvg2OodlydelOG +Zll2ZUzb/rP///////////////////////j///////////7///////////z///v///z////9 +///7//T9//H///n2/vPv/eX2//Pr/+L7//Xz/ezz/e7v/+r1/+3+//7z//D6//X0//T+9/Xy +//L9//v///7////9/+/t/+7u/+nt//L///7///Pt9+r3+u/+//n///v6//X9+/T3//f+//f4 +//n//feTWGhDQkA7QDdBRkY7RTpHS0I6Rzg+RT8/PzZDPjo9PT86PjY5Qjk7Pjw6Pjk4Pzc7 +PDg4PDk7QD43QjczQzw8SEpBSVBEVmFNYHBab35fiJOTs7OXtLmTo698m6iInKV2lKJ6ipp1 +j519kp98m6V8mat7iqRbc4F3k5p4kaJ8kZ1+kp53jphtgJRriJZthplkgY1ifo1ce4dkcolL +V21af4dniZVtip1wiJpxi5dsiZdthZdleo1hfY5niJNripV0jJtzjqB2i6BwkZ1xiZ5zjZ5z +i51wjJl0jpxsiZxtjpp0jZ5xip5uiJtph5hnjJpxkJ52jZxyi59yjJ9riZpwhZl3iqNthJNo +g5RxkJd3jp1xjJpwgJdngo1uh5Vuh5Vxh5t4kpp/maSNsKuVprh3gKVlbIJXb31gb35dc35k +d4B2l5mBoqyDoq54mKF/mKp+lKd1kaB1kqFxip55kaZ1kp1pdplIVVhkfnplhY1rhJdukJR0 +jZ1ieotkfI1igo9zj5x2mZ92j5xpjp52i5tqip9tiJlyj6F3lp94lqR2kqd1kaB3lqN+nqR6 +mad1lZ2DmZyDn6GPq6/A5tHi9uff+ODe8uX3/+3//+///+7//+37/uj9/+/9/+b9/+z8/+r/ +/+7///D///P///L///L///X///H///f9/u/4//H8/+39+uT+/+/7/u3r+eDY5NbQ19STf5Bc +ZXVomZGNrrWIsbuRtrmFrLiGrbR0jahqmZiFsraOqrmErLeIsbmIrLaDq7SKq7OGq62Eq7GH +qLeJrLOJq7SEq7CVrruIp7KBqriIqrCGq7SBoayIp7CGp7KIq7CEqKmHqbGHqrGEp7SDpbGC +pq6Oq7GavsWesrZshZVrk5OSvL2NrrWHrLCMrK2DnKZ9nKl3naeApamEqqeMp7Rtd35EbndS +iIdVjpRhkphWkJ9iiZNUjppgiZVTk5hjkpldkKNfmZtgkp1XjZVSh5lNh49NgJBGcYdEbX09 +ZmVBa29CeX5QgIhRkJFcmZ9jlpxdjp5blJVflJpWjZVaipZVg5dRholOg5NKhJJRg5VRipNO +jZZSiI5KiI5Vi41ThY1ShY9NhYlNgYpNgIZRfYlFeYFMdoRDdX1LdoI9cXdHaHY9a29CY3A9 +ZGc9aG9BZm5GdXtKgYVQiIpYgYxHe4tMgIdPio5HfYtGeIJGdoNKeIBIfYJSgolOgIlMeYFI +fHtWgohKgYdWe4RJgH5Re4dJd39Hd4BJeIJMdYJJf4RSgIZRe3xLa3k+QUc3QjQ4Ojg1QTg6 +Pjk7Pjk5QjVGUj5haEp7dVaNflyYh2qfjWWukHCvl265oHq2mnLLpXjIrX3JqX7GrH3PqXnP +rnbUrn3OrX3Wrn3XrnrUtXzfsn7YroHWp3vPp3jOoHjKmm3IlG3AjWu5gWOpgF6gc1WOaVSE +cE3a+Kn9//f///7///////////r///////////////////////r///////z///3///z///7/ +//z9///9//j8//X6//bu//Lq/934//vq9+bl8N77/Pb19ezy/e79//Tx/+7+//3////7/+/1 ++ejq++n1//f1/+rq9ef4++71//n5/+7+//v////////7/fPr/Or7//n8//D+/+/x/ez5/+/m +8d2iXXA7PzpERkNAQztDQURBR0E8QD5JRT07QDk5QTo2Pzc8PTk2PDk8PTg2PTc7Pjs1PTk8 +PD86QzkwPzY8QkI2VlZES1hEU2RWYG5LbndpgI6Hqq2ZsLSAnKmHnaZ5mKN9jqF8jJ51j6B6 +k6B6k6iAn62DnKRcd4h6nqR8kqZ2jp17kJx3jJt1hJVnhJRziaBmgZpof45ie45he4xPYHpZ +d3drhpJth5NzipZuiZJvipx0iJlkf5FlgIhhgJBqhI1xipZ6jp9zj6B1kqFxjJ9yi55yjJ1z +jKJvjJxsiJpojJhsip9whpxugpZnhJNogZBzkptxiqBti5pwiJxxi5NlipRyj5xmgZZrh5l3 +k55zj590kJ1qgplmgI9siZhtjZlviJpzjptxkZ59laOBq6qbsLh5h61qeIpbc4Rdb4Bab35o +hYmCm6d/m6d5k6eTrbOEoLd7mqN6maV3kaZzjqF1gppvjKBdX4REX1Znf41kg5BmgJBnipJq +g5xkfoZje4tmjJZ0i6NsiJdxjJ1rh5VyiJtsh5Rtipd1kaFylKt0j59yjZVzkJ94mKJ3k595 +laKGop+OqKucxbfN8drg8+PZ8+fm+eP///L//+3//+/9/+b8/+fy/Nr3+tv9/+T//+////T/ +//f///T//vT///X///X///b///f8/fD1/+79//D+/+/8/+39/+by+9/l6drQ4dmxnr5cbXJs +io18rLKRt8CIs7qPrLyBqrV+nKtqf4mHs7SNr7qHq7SLrbmFq7CEq7SArauGq7eGq7GJpriC +pauEpbGErquLrraHp7ODp7GLqbiFq7GOqbyBpqaFqbKEo6iHprSDpq+BpLCCp6+Hp62Lp66L +srehur+Onq10iZF2mZqgusKTr7iPqLiFpqqBnaeEm6J7mqeFoqeOtraOm69aaH9MbXtBb3RW +iIlZjZNklJxSlJ9bkZpdlJ1bjZ5SkZZgkpxakpxalplfiZlZkplZiphLh49TfpBBeYdHZH03 +Y21DZG9EdHdPfo1akZxdjJhSjZdYkJVaipdYjpxTipNXjZVMiJdTi5RMj5dTjpZQiJJShJRO +hY9UipZTipNSiI5QhpFUhpNPg49RhI9DfXxKdIREdYJLdIFHd4JIbXs4a3VDaXI7Zm9CZG49 +X2c9aGtFbXVEd4BQhohOgotNgIdLfX9QiYxMg5VLgYZNfYVIen9MfoZPgIRVgoZLfIROdoBP +g4ZVfoRIfYJKfolJfIhNfIZFeXpKe4JKeoFOgYdSfoZUhIhQcX44QEM2PjY2PTY8PDs4Pjo2 +Pzg+PDtCSjthYU54dlGNgmaaimSfhGmjjmW5j3Ozlm7Bn3W8pHDJpHi9p3HHpXXGpnnPpnnN +p3rPrHrSqnrWsXjWsnfatH/Vq4DUp3nOnnHInWzMnW7GoXLGmmu6hG+mf1uge1iQblmGb1jZ +8Z79//v///7///////z///////////////3///v///////v///////////76//X9//f+//v/ +//n9//f5/fbu++7h/OPj/Nbz/u7s9uPq/Ofq/uLz++31/eL0+e7t8+Xu9evs++n1//D///7/ +//////////n9//v///////P5/+3t++79//D2//P///n///v////q7ef3/fj5//P6/+/u8uWo +XXQ7RjZBQD89RD1ARENCRj49Rz86QTs3Pzw5Pjo8PzU5QjY1QTo6QDs3OzY0OTQ7Pjo6PTk5 +RTwtPjk7RUU5TE1CTlU8VWFUZm9Qanxvj5uLq7SOoKuClqKAlqB/m6h5k6B4jp90j552kJx5 +maKGoa14m6ZacYZ5mqJ3l6F3jqB0jJtwipx1ipdjhY1rkJhthJhmf41ff45igoxVbIRPam9k +hpRqhI9lipdphpdpjZZxi5dphpZnfZFigY5mfItpio1ujaJxjJ11kZ1uj5t2jJ9ykJ50jKNu +h5htiZdujJ5xk6BsjZ1riJdmhpZoh5VxjJVqiZ5si5dtip5uh5lviKFvkJxniJhqi5NwkJly +jZxxkptshpZlfY9jh41sjpdwjp50iptuipZyjJ14maKHqayZu72dssR9jrJsfZBnfZdogIh+ +mqp7n6V/m62Nqq6OrbOAl6t1laR5lKJ4nKRziJ5rh5l0g6RQXXpQa2Rgf4pnfo9jgI1wiJhl +epNid4tfhJBvj55qjJprhphxjJ5yjZ1viZpxkqNxjppwk594lKJrippxkZ53kJx6l6KKoqCT +sbCcu8CkzcPV9uDZ8+PM5drs/+X///T//+j5+N7t4cHp2brp47/t7r/v9rz2/9f//+T//+3/ +//D//+3//+z///D///L///X8/e71/+v8/+3+//T2/+v3/unr/t/u8+LX7tO/scBTamdieIB0 +m6KLtbGJsraRsbqJqLqOqbhxe5p2p6iItLmFrbOHrrKDqLCJq7aBqK6Dq7KCqK+FrbaDpLGC +prCFq6+Hp7OEqLSGrrKOqrmCp6mLqrWHpayFpLeCrK+Pr7iDnqJ/oqyJp62BprGHqKiMuLa1 +y9K6z8y9082+28/I39O328+82c+1x8WbqrmFpqF7payGq6eTr7h4iZhNeX1XgYZEb3lKeXlI +g4VhjpRZkJZZjpRYiZldjJ1TkphXkZhZj5lRj5lVjp5Si5lYj5tOkZJRiJROiZNMfYs9bHc+ +X2c/bm1EeH1MjIlSiZRUi5BVjpVNj59Uk5hSkZ1Xj5VPkZZWjZFNjItRhZFQjpJPhZBJhI5P +iZFHiI5RiI1SjI9RiI9Oi49Rg5BKf4NNgIpFd39KfoVBeYJKcH5BeHhIbXs8ZXQ5Y2hBYWwz +YGc8Zms9dHZMgohViJBPgI5JeoFLi4lRhpJLgIlMfYNDfYNNgIpMgodUhIhGfn5JdX5FfYJS +goZMf4BTgYhKeIFPf4JIeH1GfX9Kd4FPeoBVgopRf4NIZXQ6Q0M0Pjg6QDk1QDg4Pzk1PjU2 +PDk6RTVVVkRsb0+GfWCMhGKejmyklmu3lnKxmGu4l3S3nXDBnHK/n3DFnm6/nW7GpW7Lo3HJ +oXXLqXfQqXnSpnbNq3bPpnjRq3bYqnrPpH3Rp3XGnHG7lG2xi2aohmKjd2CYelmSdF3W76j/ +//v////////////////////9//j9//n///////7///X////////////+//7+//X///n4//f3 +/+/t/ezz/+r2//rq/97x++ns9+Tp9uTt/u/9//7p+efx9Ov9/vz///n8/u7p/u78//b8//b6 +//b7//P5//33/+v1/+/y+fP+//z9//Hz//v///////////////3///z8//D7//v//++5Zng9 +RDdCQkVETEFDQEQ9Qzw2RDs7Rjw8STg5QDk7Pjg7QDo4Ozc5QD44Pzk1QTs6RDk3QzlBPzwu +Qz86SUk4TFBIVWhEZXVfcId2k6iUqrKMqrOLpKqAn61/maaEmaN6k550i6JzjJx6lKJ6lqiB +o6t0lqJfcot1nKF+l6J2kJ12jqB2j5xzi5xceZBojJhqiZtlf5BfgpJfgo9hdYhLYGNjhY5k +iJRqjJtviJttiptzjJtviZpqhZZlgo5ngJJkgItxjZd0kKB1jp5ukZ91lKJzjZ5wj51oi5pt +hZlsiZt1jqRqiZ1lhZdoh5xoiJt0jptykJ9oiJptkJxwiJxwj6B1k6Rrg51niJBqh5Z1j5xu +iZ5ti5NsfpRngYtrgY1nipRzh5lwhph3ipdui5p9l6R9oaeNsLGaub6asMKRqr58ia6BoKCF +oqd/ma6AnqZ/pK56laVzjaF1lal7naRxjqNoh5ltkZlnfp1MVG9WfHRmfZVdfoxphpNuiZxn +eY9mh5BxjKJsjpxzjaNwjJ93lKF1jqFwi6F0kZ5yj6d5lKBzh552k6B7lKCFp6eTtLqmy8Wk +xMel0M3X9eXY49zr9Oj5/+v9//D69NL488zx6sbq38Pf2rLa1K/Wzqrd2K/f3bHn77n0/9b4 +/eX4/+b+/+n///P///X7++3u/+r8/+r3/+/y/ebt9+Tu/ePx9OPe7tzArMVLYVltgopxiZh+ +pamGsbeQtLyfx8Xx/uzv2Oiut8KVtcOLsrKLrbWHqrGHrrmHqbKDqLSErbWIrLSEprGDpKmH +r7WHqbGKrraJp7SNqLSKq6+IqrGHra2LqbKJpbOLqrOKrK2Pqbmbt7yyz8nE4M3B3Mm10cCq +w6uitKydt6qhsaWInJCIkpGCmoiHwaGz1cStub2ct7l/jZxxgIlRfIFljI1UfJFOdng/dXNS +g4dTlZtYlZhVh5JVk5hZkZtYkZxbk5hSi5hfkZ5RkZlckqBShphWiZpShZhOgpVDf49EZn87 +a2c9am1MfIBPjJJWj5lVj5ZPjZNYj5dPjJZRiZVRjJtWjJNSk5lVjZlYjJhViJlUkJhWiZdN +iI5WiJhMh5BVgJNKhotPgZJIgIhIfIxCe4NJc4I/dX5HdIFGc31HcH0+aHhDZnc9ZHA2ZnE+ +anBBbXlGeoBJhIxRio9MfY1LioZThotKgIhWgoxKfodNfohFgoJVg41NhYhKdnxFeXlNgIVM +foNRf4ZFentMeYRKeH1GeHxMeYVPfoJShIVOeodAVmg1QUMyPzY2PTo5Pzg4QDc0Qjo9Pzw1 +RTZOVkRhakx8dV2Ig16jjGujjmyskXGrlm+6mXWymW++oXOznnK6mXLAonDDo3DHpnbGonjI +pnLKqHXUp3rTrnrRrX7Pp3zTs3/PpYPFonXKnHHBlG63imyyhWKpf2mgelingWTc6KP///z+ +//z+//n5/+7+//z///////////////////////////////v7//X///z////4//b9//f8//72 +//L8//Xw/+7p/+Du/ezp9ube7tz///Lj/Of9//Hx/fb9//n8//P9//b2++/t/ent++X0/efw +//X+//n3//X///r///7///f0/+v8//T5//Hy+enn/OX0/fD9//r5/+70//Dx++W7XnA7RThC +TEVESkBERUU/Rz9CRj87Qz08QTdBQjg6QD48QzU6Pjg2RDo6Ozs0Qj06Qjs4Oz86Qjc6RT88 +RkpEVWVgc4t1j6CApKmKqq6Eoa2Dnql9mKmBo6uClaV/oKOAl6p5jJ57kKR5jZ97l6R5n6d+ +lqdefZF8mqJ4laF8lad6jppwi511i5pse5ZujZl0jaBlhpZkgJRffo1jfo1FXWhjf4VkhIxw +jJZniJlwh5hri5p0iplqh5ZpfpNkhI5od49mg41zj5tvjJh3jJ52kKF5kpx0j6JsiZpsh59w +i6F1jKNuhJpki5VrhZVngpJ3kaBvkJ9xiJttjplti5p0lZaBk6RtiqByiZVnjI9ziJ1ijZZ1 +j51of5Nrf5RpgZJthpVyh5l4jpt4i6FwiZx4jp95lZqAm6eErKqWvrmpyMahsMRpiJJ6nqCH +oK2Al6SOp7ODpLB0lKlzkp5zkqhviJlwjZtsiJpziJ9sd5ZGV2hefHplgZFng5Bsi5hqgJpk +hJNvj5xvkJ9ziqV1l6J5kaZxhp9xiZpykaFzlp+NpauYrbuxv8ehuL+iwb+hxMO10tCkw8ao +zMbW9+Xw/en5//D5/+j///D09tnr4bji16zh0KzW0qzZyp7Zy6TZyKbZwqPeyJvXzKHW06fi +77bv/8v8/+7//+3x6+TR9872/+v7+ert+eXo99nu/Obx/urs+eXo7ePg5N3x9unm4+LIwtiN +rqyZwbzf/OX+//Dr9uS62NSqz8iyz9GmtsSIra+KsrCFrLOCqLOIq7SHqrCKq7GBoaGHr7CR +q7WNp7CNrKyPpaqQpq6XrLKzvL6/x8m+1c28072jxJmaroqSo4GVkYOUjG+RgnGNinGTiHiF +eWaNf3WDeGKCfHFue2psdXBXWltRZVNrr3uj1MCxusGGjJNdeH9dkpJZiZZShYxMd3xIe4NN +kpFcjp1NkJVdkZxVkJNijJ1YkZZiiJlQkZVciZlPjpRgi5ZXiZdRj5FRjJdNhJJOfo9JZ347 +Y2dAcG1Ce4FRkJBWi5NZjJpQipVSjZxPkJtVi5pPj5BZkJlWi5RSi5pSjpRUiZdUi49Qg5NO +iYpRiZVTipJQiZFRgY9NhY5Ph4tMfYVNgIdKfIRKeYFIcH1CbnxAb3k8Z3Q+YW47Zms/ZXA6 +bHdPd3xEfoRWipBQg4xNf4FJg4lYgolKgoRQf4tOfIdMeIRLf4RThYpRfIdLd3xQgIRMhYpO +fohJfINQeoJKdH9IeH5Ne4JOe4FTg4dOc31CS1k8SD03QT08Pzg3QDw6Pzg4Pz03Pjc5PjpF +TDtUXElyb0+DelqSgmOaiWumkm6skW2ymnaxm221km6xmW65mW69pnHBnm3Epm3DonXFo3bI +pXfLqHfPpHLKoHnNpXjRpHbPqHfLonbHoW7Hn3O/kW22h2eqfGGegVukfVvk/r7///////// +//////////////////////f///////7///T///3///r///////////X9//r////8//L5/+/3 +//Dl/eLj/trq+eXe6djh8dnv//Dx+eb0/fX2//H6//r1++bz/vL1//H///7///v4//T9//jx ++eX7//b+//z///v7//T///j7//b8//f8//H7//zz7+nv9e39/vv9//v09OO3Wm9CRUU2QUVC +QkQ6QT5CQkE9QUNDS0E+PkA5QDk7Pzk5Pzg7Ozo1QTQ7QTk1PTY7QT01QDw/QT86RUc/Sllc +fI14kZ5yhJhmg45yk597laWAl6R7lKeCnqaBna59naaJoax5kKJ2jZ51kqN+kqJ+mKR5lKZU +cIN9lqZ4k6F6kqB2j5p2iJhth5hyhJpchZBuh5plgJJkgpNffpRhgpBFW3NYdnphfYxqhZRq +g5Nqh5dsippxjJ9viJRvhJZoh5Nog5JkgItzipFripVyjJp3kJl3kJ5sjZx4kKJkiZp0jJxw +lJ5yip9mhpVugpNpjZJzjZxxkaFyiKByiaFripl0k513kqd0i6Vjg5FripRujJ5tjplwiZxo +iJVsgZRphZFzhZpriJhyjJtwippxip1wjJt1j593mqd9mqeAn66RsLWas8KFjrJwio6Epat+ +m6uAoKeDoa55nKN3lqV4j6xxiZpviZh5lJ5ujaV0i5pkdphIXGtge3tkfIRrgJdvjJdogJ9r +kJZvjaNzkZt4lah1j6FxjKJwjZl0kJuGqK+6287T5+PW8OXD1N2my8Ov08+72dqsw8+gxL7J +89zs/+n2/+n9/+zx7M7h0rDZzaLbzqPUyaneyqjZxqfeyaDax57gzKfj0Krn0aXl0ajp3avu +16/p3bHo9cfz9OS+wqbq/t72+ujv993t8t3v++P8/uPw/eDm/uP7//D8/+v7/u7u9OrHvM52 +hIuP1KHV/NvK4dq9287I4dfe9OPBxcWKq7GLsLWPqbGLrqmKp62Lp6WWoJyNmY6Pl4iQkoGS +hn6ak3axmn+2l32zi3SrmHiolHipj3mokXa3mXy6nXW8mYG3oIW8pXa+pYHBoH+7nHaslm6m +kX2li2+fhW6Sf2SRdGZ7Z05dT05JVElVXVdrk3mp0sW8zsmlprdokJNch5lNg49QfoZJgYNR +lZdajppelZJbkp9fi6Jem5lik55VjZlikZ1ak51hipVUmJtZjp9RjpRZi5FKg4tMfI47aX9D +Wms4Z2dLgINKh4hdjpdUj5tWkJdPkZJRjZdVi5VRi5pVjppVkJpViJhViJhTjZZYjpFSh5JZ +iJNPh5FUg41KiJFRgI5Ph4lQfYtKfIpNeIhKdoJIdoVDcHtHaXpBaW5CZXU9Zm05Ym09Z2xB +cnFKdX1HgohPg4tPfYVNe4VShY1PfopLfIlLe4dNfYlSf4pSgIZPe4dTeIJJe31TfYhHfoRT +eYdEeIhOeIJEdn5RcHxKentMenpNaXM7Q004PDs4Pjk9QTg1PTo5PDo3PTY8Ozk8Pjk+STxZ +XUtvb1GGd1iOeGSbh2injm6rmGutkW+zkHSujmyukm2zmG65l3LAn27BnXbEmnHFpXPHp3nI +rHnKp3vTrXvVrYHMpH3MpX3LonbIl3TEkm3BjG2wiGmpf2aceV6lhGbl+bD9//f///////// +///////////////////7//z+//f///v///z///////3///3///j9//L8//P///b5//P9//Ps +++7h+tfk8uHv9+H4//Tz//T5//T5//v1/+3x+PL3/fD9//j9//Lz/e76//n5//Tx9en9/vj3 ++fLs++7x/vL5//b1//P3//T+//3///X6//z5//n///74//b0//Du8uPHaHA+PD89Rjw/RkI+ +Qz09Rj07RDo+R0A7RTczRTo8OzoyPTI+PjUuPzRAQTkzOzY6QDcwQDo+RDo6TEtKV2ltjZxq +gJNjf5JYcIZTcXRli5F6kJ96kqOBlaaCpaqDnKeHqa6Clqh1lJ55jp11kaCAnqh6m6tjcox4 +m6N6kKJ6kZ90jZZ0jp9uiZhviJtkgo1riZ1ogphjgI9lgZFdf5FaZnxIb21lfYhkgI1mgpRn +iZZsjpdtkJpwj51vh5hoh5hlgpJlgJBnho1siJNsjZl4lqB4lJ13lKJzlKNhiJtxj552j6Ft +iJprh5dth5lphZtrjplykJ5yjaJzj59oi5Rxk5x2l6V3lKFlg5hph5VsjpVxiJlxkppuiplp +iZlqhpVvh5VsiZZohpRsiZFshZpti5pzh5pxjZt1kZl7maZ/paaQrbacsrxuf5ZrkZR+oahz +nKF6mKh2mKR2k6ltkaJ0i59niZpzjaFsjaF0kp5rg6FndJNIW2VafH1nf49mi5JzjaNrjZpv +jJt0lqFxk6B3kqJriZVrhJh0lY6/39XY8uTc9uPd9eO4zNiky8Ou2c/D4da40NaZwLy159Db ++eTs/+n2/Orj2sDNwJbUyZ3dyafby6Xq1a/u27Xp2K3iyqXo2Kny3rb04rju4sPo3rTw4Lnx +5rjz3r/g3rW2nZvD7Ln4+efz/eX1/eLz+uD5/+Hy++Xp89/u/+r+//D7//D8/+309++2r8SB +i6OKr5HK5NXK49bW9dzl/OS8v8CRpZ2anomomomsmIaxkom3mH67oIK5n36xl32plXCzkHe9 +oHTIq4jYsYrTrYPLmHjDpnzMrIjMrH/OsXnOsILOqoDRrn7RqYjTtofSspDSrYvEqIvDoXy3 +p3S1kXOljXeogmiael2Tb1ZwY01gTUhOVExXbF52nXmw2b+8ucJjkZ5bgpFFhIlTeIlJgIJP +ipVWk5lYk5tbjZNhlptWkZNakp5akpJSk51LjZRYjp1SjJlYiJdOjJpajZNOhZhKhJJAbX46 +Y2ZAbG9Pf4NRiI5WipFQiZBWi5dOi5BTjJRPkZdYjJpMjJBVi5NIi5BVhpRPkphVipVPi5dX +iZNNjZZTiZNOhpBPiI5NhIpCfoRAgIZIe4NDd39Edn5Ccn4/a3Y6ZW1CYW06ZWk+ZGk+bXJB +bnlBf39Qg4hLiYdQfohNioZRh41Mg4JTgItJgYROfIRLgohPgIdKdoRNfXxMe4ZLf4RKfH5M +f4FEfYBIdnhGdHxGc31Ie3xHVm41Pj48QT0yPzI6PTksPjU8PT0vPzdAPDkvQjZBQztKVUNp +Y057dVmRfl2RhF2diWiokmqljnCrkW+ri2WrjmetkGezlm+4lGu3lXO7m3XAonXEpXXIpHPK +pXvQqXvRrn7LpXTHqH3Oo3HJn3fJp3XDoHu3hm2pf2Skf2OpkGPm9bX9//b///////3///z/ +//////////3////////////8/vP+//j////////////////////////8//X6//T9//Pt/ejm ++tjm8uXz/+3q+eX1/+/4//X///738e33+P3///n4//b6/+z7/+bt8uX7/vP9//z///X+//z/ +//////////X8//3///f///j///Lz//H19+77//T49uXs+PD///TRZHdDQUJBTUtRVE9JSkZD +ST9DREI9QjlBPz09QTw+PD44Pzk8QDs7Pzc/Pj42PDw7Pz09QTg7RT1CUllmeZNxip1ufJZk +eZBidI5YYX1PYGNqhpF0k6F3j6B2kKSHprGMp7CHnat9kKZ8j59+kqaFpauLo61ibYx1lJp/ +kqJ1i6F3kKB0ipp1jZl3iZpkf49vhpZ0h5hogJZrgJJjgJFjcYhKYWple4lpgZBnhI9thJZm +ipdziJ5zj5pwiJxwjZdxiJhmg4tqf45piI1vi5dtkJl0jaBzlKJ1kKNqh5RwkaB4jqJwhppp +i5lxjJ1nhZl2kKF1iJxzjqBvjJ1thpx5lZl7k6Ryk55thp1pjJR1iZxwi5tzjpx3iJl1h5ln +iY92hJhriZZyhZVqiZZvh5dripdwiZxyiJNvjqJ4jZ19maKFpa+QsrKNl7FlfI13kZV3lKB8 +l6V3lKp3kaJ7k6V6j6RwjJ9wip9uiaJwjZp0i6VuiptjcpJKXGFngYZng4ttipZ2jqB0k5p1 +j6Jykp11j6Fqg5RjdYOOuKDZ9ePh+eXj+eni9Oq9zNOmzMqs1NLE5N293tmvv8+Tx7a96tXf ++uPp/OXw8Ofbu63OxKHg0qjr2bb47sL468ry4L3o0rLd06no263y7MXt4Lvq1qTlzKDn46f4 +58Tr2LHex6bfz6/j6L7v/eb1/N/4/Ovx+uL3/eby8Njx/+j//+z///f///P9/vHl3NmjnKG4 +4NDG49HH5Nm7xLGpqIe9nIbGpIHKpX7Tq4nWqIDSsoXXsYrOsJPOqIPIpITCnXTKnXnSp4LW +uJLju43iwqHct43ctpLfun7btZDat4LUr4XSsoPctYrZtYPdupHUun/avIbWsIjUsYTMsn/O +pITBmWa4jnOfhF2gfGWZd1eAYlRhUz1bTk5JWEtXalyAxJatyb+Jn6ZYiZFOfIlTg4dPjI5W +i5JSkZFcjJdXkphgjJVYkpdhk51WkJRckZlUi5BhiZNWjJNWiptPiY9Xh5JNh5NSfZBGan49 +YGBFcHNFgoRYj5JVipZZi5lTipJUjJZMj5RUipRck5pWjJhZiJJTjpNZjZlVjZhdjpJSjJFf +jZtTjpZSiZJSipJajJhSfotQeotPe4FKdX5Jd39FbnZBa3dBanZFanA/ZG89Y2pAZW1CaXRF +cnZJfH5OgIhLfIlUgopNgIlSgopNfYhRe4hIfoZYgIdNholbe4ZJd3lXf4dOgYlVeodNeIBI +dHtJeH5PeH5Ld35Re4BES2A2QTg8Ojw7PTk+Ozg/PT89QDc6PDc6QDg9QTg7QTNOU0VmY0l2 +blmJdlaQfl+Wg2KijGyriGmniGeni2SujGKzkme0kWi9j2u8m2/FoHXBn2/PpnfLsXjWrIHT +tH7VsobJqH3Nq3/GpXbJnXHJonK/mG29kXCtgmSufmKuhmHf6rD9//X///////////////3/ +//7///////////////////////////3///n////8//T9//X///r////1//bz/+ft/+zp/9rr +/+br9efc6NT5++ns/ev0/ff///f2//Ty/+v6/vn5/+3+//3///X9//v9//f9//v///b5/+39 +//3////7//P5//H0/+/8//T+//z18+3+//v/////////9PDJbG5CQUQ8TD9PSEg/RT9DRkU+ +Rzs7RTo6PTg+QTk3PDg+PT09OT81Ojo7QT09Pjc1PDo6Ozs0Qj8+TVVliYp+jaRqe5JkfZBj +e4xlcolGVWxdcXhqiJV+jqF2kaONoa2CoKeOo7OBlqV8lqd5kqGDn6iDmq1idIt7lJ1/l6N8 +jqF8kZ55jKF4jJ1wh5V0gZZnhpduiJxlhJVqgZFego1keIxJWWBne4lgfY1rgZJpg5Jui5Rt +i516jZlyjZx5jppshJtohpJjfo9mhY1zjp1wipt5jp9zlKF0jKFriZp1kqd0kaR0i59ohZpx +iJxphpxxkJlyj6F1kJtwjKJriJR2laN+laN6lKV0iaFqh5txiZVyjJlyip1zjKFzjJxviZtw +ippviJVyg5lvhptvhJhyh5Ruh5dviplziJdxjJ11kJ6En6eHqq6Ws7JyfJ9rfY1zk5h5l6V+ +nLF8mKt3kqZ5k6N5kZ1zj515j6l3k6F4kadwh5hnfo1XaYVVaGVkgYhmgJFxjKB6jp90jp50 +jp91jqFufpNVbW+KvqDG69fa8N/a9OXj9OfB2uGox8mt0dLD39nK5Nu+z9qSsbeezL7V+Nzl +9+vr/+bq3tzKvaDg0bPw5rz899H28Mrx2r7cyaLbvJPjx6Ho2Kjm1Kfky6brz6rrz6Xx2rHr +0a3p1K/x4bz33sDr4rfu/Nb7/+f2++Hw/OLw89T1/+n///T///X///P+//Ly9ujMzr7I5tfF +29O4wq6xn4TDq3/Sr43XsZLivJDivpXgrZHdq4LfuYrVuZHZuIvXrYjQq4bUq4TWt4rewpLr +yJfiyZnbvJHewIrcwZPXsorct4rYq4bfuIvZsYPitYvWu4rhu47duI7cso3UsYTZt4PMqXvM +pXe8mHqpf2Cae2STfGScdmOIYlNiWE5bTkVPU0tjZFZ5tIu40suBlqdghJlKhIdYfIxYj4pY +j5lYjYldkZdgj5dWh5ZZipVYjZhemppajZpZkJdckJNVjZlZkppYiZ5WjJRTh5hVfoo8ZXpC +ZmlId3lWhoxTipdbj5VTjJlTiZVTjZpdkphWj5tdjphUjpNckZhRjJpVjJRai5ZUipBejZVV +kZhbiZRZj5ZWhJFRgpBSf41GfIVPd4lGdIVHb4BFcXtHbHtBZXQ+YHA/X2xCYWg+Z2pEbnNL +fYFRiI5MipBMfYVLg4ZRf4hLf4ZOfo1Fdn5Rf4VNgIBRfIxMe3tTfIdTf4RTgYZNfIVKdH1I +dn9Gen5NfYVOcn0/RlM7Ozs7Qjo5Pjk5QD05Pjw7Ozc4Pzk5QDk9QD5ARDtTTkZgXUlzbVR+ +eFeUfl6YgmGgi2ujjGini2emiWWni2eqiGWuimG1kWi+mna9oXTFn3XMqnvKqHrRr37Tq3/R +rn/UrHzUs4PMoYDBmnG+lW/AkXC/kW+7imuyhmq0hmPl67D///P///////f///////////7/ +//////////////37/+////////////3///3///n////+//T7//P4/PHz++rq+ebd9NXl893l +9Nz2/Or1//D9//7t/eHm+en99/H4/vr///L2/+r9/+37//3///z5//Hy/+n6/fr///3///Xr +9Oj+/vz9//P1//L0/+749+306+v18+r1+ef0+efp8+LLa3M/Qz4/QT0+RjxDQ0A8Pzs8Qjg2 +QDw+PDk9PT04NzE6Ozo2Pjc5PTg4Pzk2Pzs5PDs2PjxCQkY7UlZmg450ip9vgJVlfYtkgZRj +f41icY1DSVdfeoFtj5h7lZ98l6SDl6SKpayKoqp+kKJylKGCoqyDpKxkdJF0lZt8l6N7lJ93 +k6J/jqR3jZ92ipxvhpVphZRujJdufppmfZFhe41bdopRVmxSbnFlfZFkfItwh5dng5Jxiplt +jJxzkaB5j5t2i55vgZFpeo9mf4xwipt3j591ipx6j6J0iJ9xi5p3l6V4j6lzhaFtjZx1iZtl +ipZ5kqFtjZ57kaNxj6N1iqFylqR+lql1lKhyjZ9thZZriJNzkaBsiZ5zh553kJ54jKFxiZxz +g5ZuiZZxiZZuhJtwhJVviJlzhpJ1jJxwhpNzjZt4kp18mKyHqKOVrr9sdZlmg4t2kZaLqa+N +qbZ3nbF4mKd6lKRykKFzlaV1kaF8lKtwh6FqgpVmgpRjZ4pQZWZle4NogpB0jJ11kJ54k6d8 +kqaIiaCTkKaot8CuwsHI39HO6dvU7+HU59/E1dG0y9C839TM7+PK4uKkusySt7uk1sDW8+Pw ++e7r9OjJvavd2Kzy6MD778X36Mbmya/WupTo2Kvy3Ln01b3mw57u2bf13rPy3LHuzKrhx5vp +2Kzv3rHz4rzu3rXo0afu+8z7/ujw9ODc4b71/+n///P//+7//+/5/+rj8OHG4NW708qzpZK4 +n4XOqonasonjv5ntwqHvyKHswpjqv5Pps4vis4Pdt43dwJ3er4/Rs4jkvZjdt4/iuorgu4ri +vY/euo7uw5LmxZTowJXduozjt5LatIbesojgu47dwpHgwYnhuofevpLguo/dsYfftpTTq4LN +oHyyjWq4jmmtiWOtiW2afmONbFxlX0NcUklDREJUWExhk2is0sCqrLdsg51Vf4tWgItViJRY +h5Jej5ZakZdYjptVkZdXk5lYkI9Yjphel5lcjppfkZlVjpVikplTkZNRiphNgpVNeY0+aHJD +bG5Df3hUhYtXkI5Vi5hRi5FWi5RRjZFZjZhZippRiY9ZjZNVjZhWiZZTiJFUjpZaipVViZRW +jJNVipFUiI5MgpJRfIpMfopPfYhDdoBLeIQ9c4BObn86aHVDZ3E4ZW5CZGw7ZG5Ba21KdXpL +gH1ShIpNgo1OgYpQiIpRgpBIfIpOfYVKgYdQg41NfYVOcXtIfnpPfIFQgIRPfohMeYdLeoFM +fINLeX5MbX46PUU3Pz89OzYzPjo8PTY7QTk6Pjk5QDo+PTw0PjVAQzhQUUBgX01uaE6AcleJ +dleSgF2YgmOhhWKhhGaifV+lfmChgGWniWKwjWi5mHbCmHLHpnTRrn/XroHVtojXtoTVs4fL +q37UqIPLonK+jm2xgWW2i2i6kGvCkG6xima7imHi8K3///////////////////////////// +//////////////////////n///n3/u34/+/w/Obz/+r9//X///j4/vDu9+zm9dTz/On3+/fh +8Nz6/O/m8+H9/vz///z////7//Xp/eXk/OP9+fbr9+ry/fX///79+/f8//z7//P9//z///// +//v7/fT5//P9/vf9//f9//f///3////////19ujMbXhEREA5Pj47QEMzPjo/PT80Pzs8PUA5 +Pz07PUA2OTw4PzozODk6PDs4PjwrPj06PDw3Pz42QkJCXWhzjqB1i51sgZVjfpdde5Bfd4lZ +d4tdYn4+V19ogY1zlJt5iaR2kZ6Go62KqbKBlKp6lqGFnKx9n6hpd5Rxl6R7lqd8kKF5jaJ2 +kZ90j6B2h51uh5dnf5Bsipdsip1jgJJjgJJhe5RVY31OYmtXd4Nje4tlh5VrhpJnhZFviZhr +i5p0jZtxiJx2jJtshJJpgYtxiZlxiZp1j6Nyjp16kKBxjZt3kqR3lKVxi6Bqipxsi51oiplw +i55xjqNtjpxxh6hnhZZwkaB6l6N3mKZ3lKJuhZ9ui5dviaByhJ9vi5p3k513laZ5kKNyjZp3 +iZ5uipZwhZpwiJpuf5lthZdyhpdxg5dogZR0i5p5kqF5mKOMrbaJlbZneY5riZJ7n6KCnLB8 +mK58l6h4mKhwjaNwkaZxk59xkqZ3n6t2hqdkgpJmf5hTZHheaINfe3tziJl0kp2XrbK/1NTX +5ePZ7OPd8OTg9ujg+OXX8OPP697H7OPW9eDe8eja7OLQ6uPU7+S4zdWbwcOWtsW55NHf+eng +8Om3trfKzKDq4bv45ML05cbmwK/Otobu37ny58H66snyzqz15bz678b56MHs0LXTqorcwZLX +vZri06Pq4Lnr27jq2K/u+8/09eTg4Mn2/+f7/+n2/+ns/Obr9efR6NW9zMCwoH7EoYHJo4DZ +uZrmxp/vzq710aX217j40K3wwZ/iu4nkuYrcq4fbwpTkxqHUr4HmyKXlv5reuZPaq4Leu4nu +z6fxzaLzzKXowJPnvJPgsYbct4zXvY7jwJXdvojlvordypbjwY/fuojju43kuo7cr4TMlnO5 +kWXCqXu8lm6pfGWhd1ucemWJYlRjVEpWTEQ9Sj5JSklSe1mUy6e81Mebn8FilZRWh5VQiJRa +kJlZkJpUhphSi5BTj5lakJhYl5tXkJVXlJ1aj5lYkppWjJdWj5ZSjJZRi5hNh5pJdoY7X21B +aW5De3xTiYxSjpRgjZlRjZdejpdQjplZi5NKipFVjpdOjptVjJZMiZJQiZhNhJJOhZJNh5JK +iZFShZBNiYxTiJBKgIdJe41KfohFdoA/cXxHcn89ank8Y3I6aHI9ZW07Y2w7YGpAbHNBdXlK +gIpSho1KfYdciIhSgpBMfYhJfoZMgohMfYJLeYVGen9KeX5JfoRTfoNIfoNJeolEcn9OdYRJ +dH1FYm04PUY5Ojo4QD05Ojk2Pjk1PDg2QDw5Pz1AQD40Ozs8QDtFT0JlX0tsYU55bFWKeFyN +fmGZgmiWfmKgg2akhmOmgmSTgGKcgmOpi2e3lnK5m3TGqXvNsX/RtIXWtYbZq4HTrIDLqX7L +pHbMqHq/mHTFl3DCi2y8km65jm+yhWm0jWXl4rD///b////////////9//z///v///7///r9 +//r///z///r///////////////////////////zt+ejv9eH4//Lv/+/p/934//L1++3s+Oj6 +//rz/e7p++Ps/+bt9eLw+u3+/vL7//L9//r///79/fPz//P9//Hy++r1/+34//T///z///n/ +//X8//v///Xx/ff9/+39//Px9+bp9ODs8uXYcX07Qj48REE4RD0/QDw7PzY+QTw5QTlAPzg4 +RDk9QT84QDg5PzY7Pj04QTY2QTk2QDo3Qzs6REM/XWpykZdwip1uf5ZlhZVof5FieoxifIte +doNMS15Pc3Rwi5l4l5t7j517m6KOqbCDmqiAlqeDoqeBnqptdpJ0kZt5j555jqF0i6F7jp93 +jJtzjphvhZhof5p0i5lwiZ9ogJRlgZhhg5Jmc4lEWmJbb3xcf4tsi5dqhZF0hpdqjpp7jqNw +kJx3jJx2kpp3jqGAlKCWoqeAjp92jp1ui51xi5hyj6NzkqJ1jZ5xi6JxiZpxhZxriZpwi5p1 +kp10kJ10lJ1pg5tuj5p8l6txj6B9kaJpjJt4kKByjpx6jKFxjp1+kKJ+nqmElqd6mKJ1jJ13 +ip90kZx0jaFuiZdthppxhpx4iptwiJ50h5R2iZ92k5qFmaaQsK58hq1he4dqi5OEpq6GoLR+ +maN7ma92j6B6lqp3k6R4lah7mqd1kKFzh5lhc4dpfn+lqrZ9e5WFlZ25w8jW7OLk9unp+OTr +/ejk+uri+ero+ezq/urr9+fa7ObL5d/I6N3f9+jm/Onm9OnM4N6nx86q0sy/4ti74NXB69qv +s8WttY7n4bT27sj46MXhxaDGq33j16f25rn68c773cPy37D568L758X02bflybfd2sbQ2sjT +uajSxZXn2K7v1rPr1q7n9NLf6tHe89nv++f0/+n6/+rh8N3Fz865rY7PspXTtpHeupnkyJrq +0aLx16fx4bj86LP73rD3xp7ntY7lr4TZtIHbq4DevpbhrY7auIviu5rbsYjUpHrew4/xzaLy +0aTswZ/wuZTivJPjuYrgv4TpxJPlwpPnvZTlxY7rx5zrxZfsxZnpxZTpwJjowpHaroLMoW/L +n3u/j261f12lg1umgWCadVaCXkZpUkJWS0JBOzdETERQX1htlHOh0a7A0smOp7dmiJZUkY5b +ipRQjZNbk51UlZhakJlRjphajJ1WjZdZkJVbj5hZi5pakZVUkJlZjZ1XjZlUho9Md4g7YmtD +am5He3pWhYpNipNTi5ZPjJRXjJZRjY9Yj5hUkJVZjJlKh45VipRWiIxVhJdUiJFRiJRXi5BU +ioxPhJFNhY1NgIZPgolOgY5HfIdIcoJEb3tBcHs+aG1CZW07YGg+Z2k/aXE/bHNGdHZGgIVX +iYtRgIdUiIhPhIxZiI9Jf4pRfoVQf4pSg4pPfIlHeXxHenxKgIdRfYlFeYJLdX1IcntLb3g/ +V2Y4P0A4Qzg1PjY9QDw4QzU8Qj46PzY7PjlAQTY+QD05QDRKUENoYkZwak9/cFSIeVibfmKZ +hWCghGOjgmangmGggl2aeF2chF+rjWWzlWy7om/CqnrLp3zMsoDUrYbOq4jWsoPMo37Qp3nE +nnPJnHHInXK+kGW5jWirhWmuhWWshGLf4KP+//b///////////3///////z///////////// +//////z///z////////////4//P///X///j///j8//j8//Dg8+Hj+dDt/+vt++Xn+d7u/Oz0 +/fz///v1/fT3/fb///r7//P7/fL6+/bz/vT1/e7r+ej6//f///z///j9/vj7//D4/+r9//f/ +//z///j59erq8enz+e/0/vn///v////de39FSUg2RjxBR0o9RTdHQ0BAQzo8PkFBPzs7Qj8/ +Qj49QjU1Qjw8Pjo6P0A8Oj07Pz44Pzg4SEVAUmRpj5p9j6R6jKFyiaJqgptuf5dke5lqe5Zc +aH9FTVdceoR2jplxj6GAkqGMqrWVoa97mKp+n6yDnq5yf5pykJ1/mad8jKJ3ipx+jJ5zj516 +i5txiZp3g5ZqhJZyipxsgp1mgI9ff5Jhe41NVW5PZGxdd4pmhY1og5VshZFvjZ16kp9/kp2E +lKF/lqCDlaGFoKbKzcmfpbeBlqV6j6F+mKl5kqWCla12kKR2i593i6Nyj6Fzip5zhptyjp51 +jptxjp9rgZd3lJt8m6l5mad1lah6kaN1kJ12jp90jqRyjJx5kaaGpK+InLCAm6mAlKh4j6V5 +ip92jaFyhZ5xiZx5iZ5wg5p0hpVthpZyjJh2jqB8kKGBn62Sqbd6fqVmeIR0m5+JrLOGnLJ6 +k6p2j6B2lKZ4naR5j6l7m6V8naluipZle32RqZDQv9y6ztLY6d/c7+Xs++3s//Hu+e/s++3x +/u/x/u31/+7o/Ovg++ff9OTc8ubW6+TT8ube++ro/e7j9OzP1+K419Oz1NCv0tSxztGowMmK +lIng37T17Mr16sjesKSQgF3Kypbx4a796sL74sD11aj54Ln95rP34r7q5Mff59TW29TX1cbV +wcXYvqnpz6ny1rXny7Hj6NL2//D6/+n+//Dw++fW29S+rojXtY7awZLevZXfypnrx6fozqTs +1aju2a/izpbgwZbbtInNrHXSp4LUq4jcr4bZqn/UvY/XtJTTto7SqYTVqIjcuI3nw5jqu4/r +wpbpv4/xw6Xrx5ntwJLtwZDy0avtzKDz1ajzxaDpzZj1zZzyyKHxzaDvypnruqDjvI/gs4zX +roLCl3exfGKnfGilelucbV+KalJtTU1YR0FFREVNS0VLUkpdXVNjkmun16+9ws2Om6Ngh5Vh +lJdciZtVi5RYj5hWi5FfkJ1Si5dbj5hLjZRhlZpVkZ1bjJpakZdYlJtai5dShpJFeIhBY3g7 +aGdHeXpMh4lWjJNWhJpLhY5Rho9ajJJUjJRViJdSiZ5Yip5UjpZWiZRWiZhZh5ZRio9RiJNO +iY5ShZNMgotKgJBKgolUfotKeYBLeYRHcHtJaH5BbnZAZHU+W2k+aGxEZ3A8aW9FdXxLf4dT +iI5OfIpWg4hSgo1NgIZTfIhOfoNTf4NLg4FQdYNHd3pSf4dLeYNLbnxEbnVHanRDbXBEWGs2 +QEE7PDw6Pzo4Pzw6OT47Ojk7Ozs/PT09Ozk+Pjw8QT5CRzpfXUhzZ1B/cVWQdWSQgF+igWmf +g2SoiGWjiGClfGWMclqXel+aimOyl3C0l3TCo3fHo3rIp3nOpIPMrXnTqoDPrYPGoIDQpnjS +pX7Oo3nMlnPDl3K3hm6vhWmqhmDk26D+//n///////////////////////////3///r8///8 +/+7////7//P///z///////////7///v9//z3/+z+///1//ji+9rl8uTo797x+eb8//j9//73 +/vH+//z///X59+74++/4/+3///b9//X9//T6/+74/vT+//v///37//Xz/fP+//7///v2/PD9 +//j///f19/T9//v///P8/ezs8+DWe4A+QTw/QUNFSUI+R0M/SD02Qz9BOUEvQDpCQz05QD1C +Qz42QTlARj42PztEQDo4QDs6Pz88RURBYGNykqR/l6R7kqJvjaFrgJlrhZpthpxqiJpogpdJ +UmZJYGdnhI11jpt9k6KAoKiWpraFm6l8lqWBnqd3hZ52lqB8k6Z5kJ91ipx0jJ53j5t6j55u +i5lziZpif4prhpVnhpdngpVdgI5kgZFaZntLXmZYcn9lg4xlg41pg5B+lp+QpaeUqa6rt7u9 +w8W2ssCsvrjO4dC5vMSnrrilqbaRoLOLoKuGm6mAnaV/kKt+l6F5k6d0j6R3jZ11lZ99kqRw +kp90iJ9si5V9lqR2mKKAmqR1l6R3jpt1jpxyjpl1jZx9laGQs7SQq7SOqrODn7F+mKl+l6B9 +kaF3h6Ryipt3jZ9xiZx2h6Bmh5Zvhpt0jZl1jaB3lZ2Foa2EnLBpepJjeoJ9mJ9/oqaEoqt7 +lah1k6F+nKZ7m6t7mqlvj6FleId/i5y/0cPi8erX7+Pl+ufb++jp/uzz/+z0//H2/+/z//Tn +/+nq++vo/ebk9+zW8+Pb9OXn+ens++3m9+rm++na8+Xd8OO91Nikxcimy8ip086nyc1/goTI +16bu47v25sblv66femytp37k16v97MD96sL2yKf257P87cv26crq4MLb6tba4tTJ08nIy769 +rqrQxpfdx6LX2bbn+eH5//D5/+z5/u3q6tu+s6rNspDbwY/ZuZXQtY3fyJ/nzbHlyqTkyZ3e +uprOqILSuIXixJbpxpbpyZ3nw5rpxZvluZHep3jRmHbHnXjZsITYtYXisYzjtYHkq5TfsITm +w5Psx5jvyJntzZ7uzaf52Knu1qr41ans0Kj30KTy0qby0aDzzqbtyp7szafrvI3fsInTp3vK +l23AjmW+jnSriWCkel+OZlF/ZlBlUEdYS0NDRkJES0hFT1NYXVVebV6Lv6K53MeiqLZfjZxa +k5VUipBfj5RYlJ1akZhYjplZjJtblJdckJtVkp1hlqBdkpxckppXlppajphTgpFLcIc7ZG1B +a3VFfYBSj41VkJNbiphSipRYkpVTjJJSjJZQjZFVjZdXkJRSjJtUi5VTjZVTh5JRj5VYi5VR +i49TiJJOf4tKhZBQfpBJgIlPdYNBdIBEa3s8anI/Y3A3ZWU9ZG08amo/bHI8bXZNen1SholP +gI5QgIhQh4VRfolOfIdFeYFJf4JRfoFLeINGcndMfYFId4JDbHFCbHFIaXFDZ2tHVWM3PDw6 +PTswPTZAPj0tQTY7Pz0zQjZCPzo4QTk9QDo9PDo8RzteX0htalCDdluNfVuahGKgiGeih2qi +h2msi2mmgmWhgmOYfmWhjGe0lnSxlnK9oXTEq3jIp33EpXTLo3jLpXjFpXrAm3XCq33PrH7K +o3zFnXS8lG20iWqximivgmfh2Jb+//L//+v///X///r///////7///////7///////3///j/ +//////z///////v///7///38//b1/+z+///u+Ozf8djq/9v0/+zw/Onp/OX6//f1/+/+//bz +++30/fL5//b///7x/+n1//vt/+j+/vv///////Hs//H9//v9//r///73/+75//X4//L9//z/ +///7/ff6//j9//7///////Lff4REREA6RjxFRkI+RD09RDs1QTs5Pz06RjhCQkI8PzU+Qj46 +PDo7Qj49Rzk9QEA+SkM6Q0E5RT49TlZciIl5lKN8kqF6iZ93iJlpg5plfpVmgJJnhZdlc4Q/ +SFVYc3ZsjJJ2i5p1laGTrbN9nal+nad9nah7hqF3naWEl6Rxi5p8ipt0kZ17kJdzi5tyh5hw +h5dmfo5sgpdvh5RnhZRlf5Rogo5jfIpLWmZMbHZkfIlrfYxwiYuOpaChtaq/08bg7dfo8+Lb +5dXJ2M3e7Nfn8eHn6+Db5dzD0Mi6xrzMxsjO0M3f3NzOydSuqcOJm7OInKuBoZ58lKd7lZ9z +i6B0kpuBnqd5l6OAmKZ4mKh+kqFzj5x6mJ97j6R6laOJrqqYs7uWrriJq7OKqrSCnbF8mKh+ +laVxkKB1jZx0jJ95j51si5l9ipx7j5p2jKFyjZp9k6KFpKuKlrFmfoRvhYt4pJiKqa6An7B/ +laaAnaqDm7GDoLGEnrGOrre3z8jO69bh++fe8uXq/Ofw/+33//L5/+76//Hu/+7k/+/I8d/T +8N/a+eLi+efm9ujd8OXe9Ojm+uvw/+/p9uvS7eHa9OLa6+TG3uC1ztekzMihyclzc4iju4Pp +3bH16cbu17u+16vBsbXL06D58sz87sfzyqrr4qX58L7357jt5MTk79Te6dbT28XMz8XFvLnE +tK3W1MHg7ND3/+r+/+z7/uzt+ubf39HDrI7VrYbbuI7cv5TPpYXXyKHo067m0KfpyKnauJbZ +p4TRtoP12Kn55sH+5cD23ar93K7116f2zJ/vvo7lwI7ku5PpuI/nuJHtxo3nso/lrI/ux5T0 +z6f1zpr13K7327X43q303LL937f627H50bHuyZ/y0qL10KTwzqLvyaTtxp7syZfou5Hapn3E +lW3GlnO2iGiegF6OcVSFa090W0dnTUJPSz5LSkNES0BJWU9aZllWbFmAt4i32sO6t8htlqJo +lZ5YjZpgkJlWkJlilJlVk5lai5RakpdYjppXl5tfipRekZtYkphfj55UkpdVgo8+c3tDaW5E +d3NOg4JTkYxSkJVZkZRVkpFTj5RYh5lWjpRXjZdSi5NYiZRUkJVViZNQkZdajo9UkZJVjJZQ +iJBRhYxHhohOgopHgYxNeYhEdXxFb30/bnY+anI4ZGlCY207ZmRCZGk6aWtFdHlEfoFQg4BN +fYZRgYVMf4JOeYBLeIBGeYBQf4BIdYFFdnlGeHpGcXhCZnA9b3BBamxAaGVDT104QT5AOjov +PTI5Pjo2PTc8Pjk4QDY/Pjg3RDc7QTk4Qjg9QzhRVkVwak9/clWKd1KRfVydhWChi2utkmqz +mXKwjW+chmOXh2eei2aqlWivnXO9m3O9qHDFqH7Oq33Rqn/MqX/Pr33SqHvSrIPJrXzSpHrN +oHS/mHC3jXGuiWmziGTm2Z3///////////////////////////////////f9//f9//b///// +//3///z6//T///b6/+3z//H5//H6//L7//Pt/+/l+drq8t7q8t7q+d7r9OPo9+v7/vL6//z9 +//fk9eX4+O79//37//D7//j//+vu+Oz9//39//X6//n///75//f9//T///v///////n///77 +//H0//X9/+vz/+319+TZgIg/RT47Rjw5RjlBRUFBQjlCSD87Qz89OzlBQT9APzs/Rj5AQzw9 +Pz0/QT02S05LTFU7SEc9QkE6S1BPeX5/oKd8mKd9k6N0hpxsg5Jsh5dmhZpvfZZif4tbWXU/ +WFhrfohyiJV5j6CQr7GJmq1+lKR5oat+k6d7mqiBlaN4jJxzjJx6kqB0i510jJx1h5hviZdp +e41mgpJviZZmfJJnf45nfpNjf4tRX3NNY29kfoVcbnt4jountqy8xb3L4NHh69nc5dbJ08jZ +49To+OHw+Obz+Ono897T4Nbd4tnp9uLv9ufx9+bn9uDZ4tnCz8LRydDFxM2zsMaJprGKmaiE +namFoql5m6Z+l6V+mqh6kKZ9kKR9l6F4lKR7laORsa6jwMKeuMOUsL2QrrSEpq+Ena18mqh9 +lKZ5kad/k51+kaN+k5uQm6mZo6yYo7OZoa+OoK+XqKmruL7GvMy6qL6YnrKTqLKsvsLJyM7G +ws25xM22wMO1wcLEy83P1MzX6t/Z8ubd8OXq/OHy/+7r++zT/OXF5t612dG919bH393J4dbK +59nM6NzN7t7b9+Hg9+vl/+nq/Orq/Ozi8+Xa9ebd8OfL7d/P7t/F4dy3ztR5e599lHrd2a/0 +68Hs1b+4p4+/rbq8v5Lp47D56cPz1Lrjx43y4LT44LXx57rw9+Dt5Nbk2cvO28PX5dLX7NXc +5NLe9eD6//L+/+34/u7x/efUua3Ns4jYuZXWtpTYuZHDh27JuI3n0Znsyqjxx5vsyZjosY3l +ypr+7r//+9n+9s788cD/6Lb+4bz62aj82ar62rj2z6j0y5/3yaLx16n5xZz0zJn60Kbz0KP2 +1az13bH84LD63rX137X63rD54K3847f92qr316n316zyzaX31KTt0prxy5vixJXjroXMpnzL +mHK7jGuyfmacfVmkYll1ZEl6X1BkTENcT0c+SDdLUEREVExVV1JYXld3rIex4MnDzdF8j6Jf +kp1Zjp9bk5ZWh5pVkJpWipZXjZZYjJRekp5XkJhVi5hYkpVll55bkZZfhpVMgIhEbHlDaGpJ +eoFQgoBOipNalJZXk55TiZRWipVPjJJSipNVjJVWj5tWipZViZdTh5ZSjJJUi5RSh5JSiJBK +f41QgYZWfohGf4lSe4hEeYhPdYVDcoBGaXk3ZHNBZWw6YWo+Z2VBaG0+anBEcXtGfoJNfoxK +fH5Qf4lMgYVMfodMeYJKd3xNfYlNdn9IcntOdH5HbnJBamtEZWo8X2E8U1o3Pz49Pj85PjY1 +Pj83QTQ3Qjw5Ozg7QzQ+PTkyQDg9Qjo8PzlTUkJlZkd6cFSFdlmPeV6Vf12pkGiwk2q2lGut +lW6agmafhmefimekkGurlmm4m3LEp3rLq3jRsoPUsIDOsYjXsYXSrYTFp3zKqHzIqHXSqHnG +nW/ClW21jGm/kGjl2pj9//D///////////////////7///////////////////////v///v/ +//////r////////////////7//X9//Dq++nr/Nr7//z0/e3l8t71//Tt8+bk9+jt8uvt+On6 +//f///7///X9//v7//v6//z////4//H2//L0/Ovt/uz2//L///3///n///v+//v2/+/z8/H2 +++zy/e35/Ozy8+fjgY49RkFCQz01RUFERT02QjxBQ0A2PEBERDs9QDxARTxCRjs/RTs5QD03 +QzxLaGdGTU1DRlA6QkA7TFBIbHyBmqR1k6d7kaR1jaJzg5dpg5RrgpZrf5VkgJVfeIdDTldW +cXBnhI5vi5qGpqqSorV7kaB7mqh8mKt9m6d4k6NwipVviJdui5ZwiJlpiZRziZxti5lugJJj +go9riZhqh5lkg5hggpNgfZFOX3FPY29Wb3NZbG+YsqWqwLbQ38bk897t9OPb4dnM4Mnp++T1 +/+r5/Ovw9ufd59za7Nj3/un4/+n7/+70/urr9eTT4Njg5trp+ef4++3q8+PU19ynuL6itLmb +sLiXrbSSp7mOp62WqrGls7a4v8mxucWVo7iIqqufvcOZuMSTub6VrL+PrLiJo7d/oamLo6+g +trfFzsvB0M+/xMLU3dLp9Nfo9uXp8+bU5NXm8eH2/en4/+vt8+Ta49bX5tDs9+T0/ezr9uHV +4dXQ48vp+ODq+ufx/ufp8ejP2dDU4tDf8NTn8urM5tnK4N7B3tbF39vU693d8+jn9urt/+vt +/ezp+urj9Oba7+bV8t7l/+3r++nj9uTe+unR6OSo2Mm249jF593R5uWfmLlpcWnFyZrw5cPz +3MDCtqbLz8+4p5bTx5P55MH01rvmu5Tq16j03bztza3w/d3//+7//O3+/u/18+bi4drU5Nfp +++T7//L4/+/r9uPv8eXHr5fYvpXdvJTVqovMn4DBgG66j3bizpf24b7027Tu2rLvwqPmzZb6 +67///9b/9s3+8b7/8sj/8sL/6cL+7b796rz34LP33q712qr40Kj40qfw06f50Kbyy6H52aj5 +3rD+57b24Lf637X53bH42qv437T44bT95LL74rL31qzz2a/00qTryZ7vx6jiuYrct4rLroHQ +rH++mnC3i2+igVuSZlttVEVsVktfTjhRTEVASUBKUk1GVEtJUUxgf2bN5s/E5NHR0NBmmppf +kJNWkJdXjpVVkJdajJRWkJlVj5ZRkpRakplTkJZYj5dTkJJckZhTkJVOiJdHd4tCan07bnNP +foFRiIxSi5ZZj5VYiZlVjJlSi5VYkZRVk5RWjJhVipJWiJJUiZZSjpRaiJRNiI9VjJVPipJQ +gpFIgopLfY1DeIVMe4ZDeoFFcXw9bXY6bHQ8ZWs8Y2k4YGpAZGo9aG5CbXJHgYBMgohHd4VJ +e4JNfYNOeoFIeX9ReoFHfoJNd3xBbm5PdHo9Zm5HYmk+aWlGYGs6T1c9PUE0PDw8PDYzPjU1 +PTc6PDk3Pjc6PTs4Pjc2PjM1QTg0QjZGSj5cWkt0aU6Bc1WQd1yWfl6jkWewmWy0lnWli22a +fmeYhWCkj2mmkWWqknCxkm+3n3XEpXXLroDOq37NtoPSroDQsXvOpX3HpHTGoXDGo3HGlm3A +lGy3jW65imzc1ZP9//H///////3+//b+//n///3///////////3////////////9//f7/+7+ +//n///z5/+36//H7/+38//D///jq+ubl+tTk8Nrn9N3p8eDx/O73/vbw//L1//L+//35//fx +++fw9+bp/OX0/e/7//Dz/+3y+ev9//v////////9//v+//z5//L5/e36//D+//33//b6//H6 +//P///r+//v0mqo8R0Q6RT01QDc6RDo6RDZART01QjQ7QD00RTVBPz8zRTM/QDs3RDY+SEVf +aWw9R1FPXGM8QUU+S1FWfIGAmaN2kqV1jqN3jaByg5tqh5FqgJRpg5Nlgo9lfotjcYJKSk9Z +eXlwi5ZukZqWrbF3kaJ8kqJ1kKF9ladsg5pzg5Jigo5xgpNlhZRniJNshZVnhI1yhpFbeYVo +ipRujZpkg5Rgg5FlhJNccYVPYm1SYmhthX+is6i6yrvX6dTl7t7f6tjS38/b69vo9N72/On1 +/Ofm7+Xg69je8drx/OX5/+31/ujr+ube5tnf9Nv3/ev1/+v9//D2/OjZ5dTP3MPj7djo9d/s ++Ofj7N/P2tHa6NL2++X5/+34/erv+eTT4NW8xsKour6ovL2txL6pxrytvLqmuLXV5M7s+uL4 +/+vj8OHo9t72/+f3/+Xv++Xf5tnd89rw+t/5/+n1/+nh8eDU3crh79Xz/eTz/unq9eDm79zw ++uD6/+3//+v///H8//Ht9+b4/+n9/+r///T9/+/4++zn7t7c7d3j9+Pd8ubN7uDN5+LA4dfG +5tnX993p/erb7uTR7t3i/OPi7ufN8N/R5+KwxdODnqqayL662NDM3daTg6agsIro4bv35MHb +u7C116bNvby7soDjyqfv17XsvqLjv4z02rXy3a31+9z6/+z+//H7/+3+/+76/+34/+36/+vi +8t7g+eTn/OHa1MfHqIHSrojZtpPZtJfPlHfGh2u/gWXYy4/z2a/w2Kj66MP64bDuuo346bb+ +8dH74aj86rL/78P/8b//6b3+26v526n54LH54Kz1yJ/tvZbyy5ryxJnyyZHy1qb73Kv54rL+ +4bX84bj24Kz87bX93sD55rb94Lbz36z847762LH53rDz36z01Kvx1ZzlwZHguoXSo33ImHXF +m3a+j3SmgFqJaFN8Z0d3YElqVUZiUUZLTT5BSkNccmJSa13E5srN4drV8tvm8dyxq7RWmZ5h +kJpalJ1ZkpZVkptckJZZi5lSjpZZkptVkpZalZ9WlpRZjZZVko5Tj5dSh5BEdI06amtEbXFD +fYJSiYxYlJZfkplWkZVTj5FSi5NbkJZZkZ1WipNVi45VjpRWj5ZWj5FUjZFUipNMg45PhY1R +iY9Vio9MgYpMf4pIfIVNdIA9cXZCaHk3Z2s+YWw8Y2dAX2c5ZWg/aXBBcHZLeX5LeoFJeIBU +gYFKfYJMgIBGe4FFc3xNeX5GbHZHcnM+Z2dBaWo/Z2dDX2dATVQ4PDo3PjU4OzgxPjY+Ozsv +PjU8PzcxRTA8PjgyQzY9PDY6PThARDlaW0t2Z1GEdVaUg1ufhGOehGSlkGytmXCgjGmchmae +jWOlkGmqkmyoj26yl3G4nXfDpHDMqXvJsHjPpX/EpXHQr3jLpHnPpnLHpHXOoXfBjmi0imW1 +i2S8km7r2Zn///////////n///////////////////n////+//f9//L5/+v////////9//79 +//j///n6//Tv+efz/+v19fPq/N7u/+H2/vHt/+bu+OTn/ev3//X9//b7/evr99/7/vfz+ez9 +/vX9/+7///3//+v0/fX9//7///f8//T///z///Py/+3+//v///X///z7//z17uj7/fn///// +//f5//HjoaZEQ0RCRz03RDpBQz43PT5ARkM6RTlEQD86RTlDRDs8Qzo+QTk7QzpBV1xbWWJC +TFdmjY9FSlFESU5KcXiCm6tzj598kp96lJ91iJlqh41of5NmgI9ogpdmgpNofoxPV2pJXV5k +gZF4iZiFpKt/k6Rxi515jpt3kJ9xi5hpgZNsf5FmgpRmg5ZohJNqh5VmgJBvgpVddYdnfo9r +iZZmgpRtiZRlfJNjdYdTXWVTXWaEmYi1xbXT4tDj8Nzy+OHq8+Tg69n0/OT4/+z//+z9/+/y +/OPn9uDz+uX5/+z6/+37/+zt9ebj6dzn9OP8/+3+/+7///D4/ezm7t/g8Nf3/Ov1/er6/O3o +6uHY5tbg6tn3/+X+//Hz+uni6dzV3dXW49XR1tfF1MbJ2MzM28zQ0sfa5s/0/uf5/+zz+evT +49fl797y/Oj7/+jq+ebn7t/n9N7s9+D0/+n7/+/1++no7eH4/OP+/uv///L4/un2/+r+/+3/ +//X///f///f7/+74/er9/+///+3///v///H8//Du9d/3/uf1/eTv9+nj8Nrb6NzQ5dTM4NrQ +59TV7eDO5trQ39bV69vf8uPX9ObR7uDT7OTQ6OLQ6d7e9uTX8eXAxdGgm4rc2Knw6MHoyr6u +sZjO2M3AtaHfyqft4bf74cbwz7r22b3//dL///T//+7///T7//P6//H1/+/0/+j4/fHQ09HP +8t2+1szKrJHYspHiuZPitprfuZfamH/JiG66fmfSs3/54Ln87bz/8sr+5sL1y7D66bn+68v5 +zp775bH/8Mb/+M7+5LT706T706j31qTy06v0zaHuvKDrypnwyKH106L61KH95Kv5677+67j5 +5rn947r/4bn+6Lj+6Lr947T64rj76Ln346v84bH62ar33LDv1KDsxZvqyJjhvH7No33Gnmuz +gGqZc1iRa1R2YUd6ZVBuXkJtXE1eTkFFTENSb1iw1cLd8t3Y59bk/eHy9OPFtsdjk5JakZdd +kphVipZTjpNZlppmippWlJReiplTkJtbi5VVlpVakZ5akp1YjplVjpRYf5E9cH5LbHZCdnpW +holWjpJbkZ9fkJdZi5NZjJBMhZJUj5ZVjJRVjJlYi5FSjZRYjZRViZJXi49TiIlYjYxPiJBV +h49Pg4hVfoVDd39JdoFAdnlFbHo9bHM9Z3A7Ymg9XXBAY2k9aXFBbHNKeXZJe4NMfIVNd39L +foRPf4NPeYBKcn5NeHpLbnhJa3A+YGxCZWc/YmREYWU7TlY8QD43QDk9PTwvPTdCQDs5PzhB +QTo5PDlARDY4QTc2QTo7PzlBRDlXV0ZuaU+FdlqUe12diGahi2mokGiummyjk26lkGymjW2j +j2qikGWplnKwoXC+p3rCpHfPsYHPqXnOpn3PqXfQsYDNrXvNpnjKnHHHoXW/j26xgmaziWGt +i2Xj0o37/+3///n///////////////////////////////////////////3///f////7//T3 +/+79//n///X///z9//bu/+nq/d3o8d/m8tvh6NTy/+zt9eD0//T+//3////9//v9//37/+n9 +//n///79//f5//Hy/+zq8eT6/vL6//P1/e////b9//b9//n///D4//T9++/4//b7//H1//L+ +//PlsbtHSEE5QjM/QDw6QTU/Qj42QjVCPkM1QTY6O0A6QzlBQUE7RzY7RT5ce3dNTVFEXGZ9 +naRRTVxBRk1Ha3N+nqZ9k6V7kp14k6V2i51jfpNpg5NjfY5og5Zkg49rgJFbdX9KTFhcdX5y +jJdsi55/kKFsiZx2jKF0l6R3jZ9nhJVhf45kf5JlfpJthZdogpBqgpNjf45qfI5he41pg5Zo +iJZpg5Nlf5BgeohNWmlkfXejt6vP28vt+uf6/+r3/+vm8d7j9N74/+j9//D//+/w/Obj7Njl ++OD//+7///H///D7/+z2/Ovs/ej9//D///D///H8/e3r9OHk89r8/+z8/+/9/+34/+vv9uf1 +/uX1/uj//+/+//T///Tx++zn9ODk7N3d5tnb6Nzb7Nnc6dzX5NTg7dvt/+H6//Dx+efu9ej3 ++Oz+/+/4/+n3/+/z/ur5/+v///H///L///H5/+/6/+////D///f///L2/ufx/OX+/+v///f/ +//T///H2/+b4/e3+/+////H///T///f5/+z3/un+/+39//P///D//+/5/+v3+Ory9+vs797l +8N/m9ePv/OXp+O/k9ubf8OPa8OHc7+TS593U8eHO6tzQ6d3N6NfJw83KxaXn2bvs3L3avryr +ua/S89n0/eP///H///H///f///H//+////f///f///r//+7///D//+/5/+73/ejq8+Xb6d/L +wLrYv6zpxKrtwaTryKbwxaLry6jaoZbAg23OuIP368P+88X/8tP+7ND54b779ML/57380KL7 +3qv/8sP/8cz+36v73az44L3yyaDw0qHtzJnrupLoxJL817H83Kz83az84rP96bb95Lf95r31 +5rH94rP15rD658X/57f948L65rj95rn23bL34bL816jx0KHqxZ7gtYHVrofRp3q/kHC6f2ad +dV2ZbFKLcVqKZk16YFCAYk9lVkVNTkFyw5no89XL6NXt/uHt/eHu/OTTzs5ekptZlJlZi5Na +lJxZk5xci5pVjphcjZlXkJBZjZVXlJdajpJRkpRajZpXkJZai5dMi5FOeYlDcnxAbXQ+eHlP +g4RWipNZjpNQipBajZFOiZNVio9ViZFYi5BQjYxSipRTkZNUj5RUi4tSh5JOh4xUhpFMiI1S +hI1LfoZLfIlFfYRHdIdBdXtCcn5CanI+aHI4X2c/YWY7ZWc7aXFDcHJEfH5OgoNJfIRKeHdQ +d3xHdYBHeIBDcnZIcXpBbG5HZ3M5YF1HaGlAX2dASFc1Pzo/PjoyQTM/Qjo4Ojc5PjgxPzQ9 +Qzg8Qzg8QTg4Pzk9PDE+PjdSVD5taUyLeVqWfl6chGKfhWSjkm6eiWmjjGqfjmqij2+olGis +kW2nlmy4k3a2n27EpXzOrHbMrH/DpHbPsHTJqX/MpnnGn3LInXPIlmvGkmvAi2yvhGmujGfh +0Yz9//f///f///j///////////////////////////////j////////////9//L9//n+//H3 +//f5/+74/+3w++zu/+3p99fw/ur9//nw++z///34++nq9ubt/ezy/vD9//T0//b1+ef5/fDx +9+bz/+39//3///////v9//37//X+//z//+/7/fPt+Obs++z5/+/0//T7/ezy/vL///f0//bg +ub9EREM7Rzs/Sj07Rj47QTA4PTw1PTU1QDU6QTszQTg/Qjo4RUBET1NoeHlBS09OgIZ8oKde +WmA/RkhFZmmBm6l2kaJ4kJ92jKF0jKJqhZFrhpJje41mhY9ifItgepBlfYtHUmRNamZhe4hh +go53laFwh5x1jJh3kaF0hpxohZVgf5Bgf49wgpVkh5NxhZVkgItuhZVkfoxgfJFkiI1qiJVf +gY5kfo5ZaHtOYV6YrJe5zb/Y59Tq++D2/+fz+efc5NPh69X0/OP4/+z0/Onr7+Di7try+uXy +/+3+/+v1/+r4/+ji8Nnw+eH9/+7///T///L8/ejq8uPo/N/7/+7//+v9//H0/ern6dvo/eD2 +/un///H///Dy+uby+uH3/+P4/Obr9OTo8t7q8eDn9uLo6uHl8Nn1/uv7/+r6/+r4/+b///P/ +//j9/+v9/u7z/+j+/+r///D///X8//D5/+v7/+n+/+///+////H6/uv4/un+/+z+/+7///b/ +/+z//+39/+v///L7/+z///H///L///f///L//+////P///f///L//+z///H8/+/6/+X//+// +//L///L///b9//D09+T0/OX//+/6/e7w+uTp/ebm9+bp++vq9ere8+jf8d/j7+Dk8trU2N62 +x7Pk+9j9/+n///P///b//+7+/+/9/+v///X///D///j///P///f///H///D//+n+/uf29+Hu ++d/4+9vr99zv+efz7OD438rpu7HKlHbQwor28ML898n/+8v+7MvzyqD74rH526X10qbz2az/ +7MD/7sD91aL32Kf25cHtyZjqxZzowpDpwpbqx4364LX93a/857P63bH+47D/57j958H76rr9 +57757bv85sD95bf95bn86Lf857j857X737H32J7sy6DZtIjYrIPNmnTKn3e9mWqsgmmVd1ub +aliJc06MbVaEZVKBbE6CXU1qmm/f69bQ7NDl+ODm/+Lu9eLh99vd09BkkpZVjpRZjJVUk5da +lJlYkpRcjZ5WlZJdj5dUi49djphVjY9aiZRQj49OiplSjpNTjZNSh49FeoJBaHY9a25Fe3tQ +iolXjJNVjY5UjpNLgopOiYxajZBUjo5Xj5ZPjZZejZBTjJRXjJVMi5BXjpNSiJJViY1Iho1P +h4JLhY1PfYhFeYlDd31Bcnw+anc5aG87ZWc9YWU6ZWZAYmU+aGpDdXdEfoJPfoVJeHlMe3xK +eHxFcndBcXhDcXdEZ2xDY2FAX15DY1s+XWg9R0o0QjgzPTQ0QTM4QTU1QDU0QTc0QDE8QTc2 +RDI7QTk1QDA4QDU0QjVDTDhxbUuJf1mZiGGhjGehjWani2edi2mekmyfkXKhkmmkj2amkmm1 +nW+8o3W8pm3GrXvGqnzBpnu/pnLFo2/AoGvBnXPCmXHKn3HFlmXHmGu5kWmthmWrhmDezYH/ +//////////////////////3////9//T6//X///7///j///j///n///z///////////////// +//P8//z7/+3r/+jg+9Lt+uTm+d3s/uT+//Lx/+r+//f7//f79+3q++Dw8uj1/vD5//P5//L8 +//X1/+/+//b4//b///7z//H3/+3x/+/9//z///////ft/eb57e39/fz///////v19ujYvbxL +REg8SDxHQkI3Qjk9QT43Qzw/Qzo5QDhAPTg9PTs3QDs+Qj5Te3pfZGtDT1t/laSGnq5kY3Q+ +RUU/WV99n6J5lpt5jp14jaF6jJtjiJJmgZZeg45qhZNmfo1shpVigY5raYBAT09bdn1jfo5u +kZh7ip1sipt1kaN3jaBtg5lkfpRkhJVnhZFui5lvhZdqhJRrgpJlfpFmdYlge4Rtgopjgoxq +eYxWYXF+iou2yrnl6dTh7Njs9N309+b2++rz9ej5/er8/+/9/+7//+34/en3/uf7/fH//+r8 +/+7///H2+evv8OL1+uj8/+z///b8/+ry++fm8N31/+P6/+n///b///X///H9/ur8/+z5/uv/ +/+/9//Dz/+v3/+T7/+/5/ur0/unz/Orx/evs9eTo99/6/ev//+///+34/ez0/+z///H///P/ +/+/9//H6/+v8/+7///D///T9/+7v++f5/N/9/+/+/+/+//T9/ur8/+39/+3//+///+////f/ +//X///j///f//+////b///P///n///P///v///T///j///f///n///L///b//+z///r///f/ +//T///L///P7/eX9/+////f///T///T9/+z0/+ru/+vy//Ls/+/y/+/u/O7s+vDq9uvh7eXf +8+Px/+r6/+n4//H5//D0/u/z//H4/+3y/+nz/u3w/+zz/+71/+79//D9/+z///P///D///L/ +/+r//+r7/+v6/un4/uT6+urxz9Tiw7Hw5rv//Mb/+M//887+38Lxv5TyxJf02JX35K3/9cL/ +57f81aDyyp/qwqbcuI7gsojewZDqxpnt0Jb84a/84rL93q/84rX/6Lb96Lv+7Lv26b3+6Lz9 +7sT/7L/957786LT87Lf63a/75L3556rz1KDqvY7lxo/nxZzVp4HRr3vLmm+1imqcfF6ee1yT +gWCZbmSJbliNa110iGfa9Nja5NPq/eT1/uTt/eTz/ebk997Ju8Vfi5lhkJRakpldkZdblJha +jZlak5pYhpBahI5UkJlajJJRk5ZZipROi4xcippWjZdakZpVj5VchY1Ec4JFaW8/cnVRfYRR +jpJZj5Ngj5lWjpNVjZNUkJlWjJhRjpJak5RWlJZcjpdSjJFcjphSiZVQiI1RipBUhY1Mh4pK +f4VLholQgINKfYZEc3o/bXtBbnI+ZnM/Zms5X2pBZGY8YmhGbnBEeXNMeoFJeH1McX1HdHdI +dnlEcnVMcoBBbXVAXmk6WFpGXFw8Vlg+RU49Pjk4PjYyRDk6Qzk2QTY4Pzg1QDc2Qj08Rjg+ +Pjs5PTo5Pzs6RDhCTD1ibEqFf1qXjWmpi22nkWunjmihlW2jjWmci2epkHCllG2yl3KtmnG4 +oXO/pnTBpHfGqHTCqHbDrXzGnW/OnnPFnHLHmnPOmHXKnG3Dk2a6i2Spf2OnhF3SyX36/+r/ +//////////////////////3///////3+//X9/+z////////+//z+//b////9//f///f7//T8 +//X6//H2//bm8tby+eb19enr7uL3/+ny/PHt+ujt/Ovp/ej+//z///H1/ejr/uP6/vH+//7/ ++/Pp+eP7//b5//f+//j9//L3/vj///39//fy//P///3///n7//D5//X9//f9//nuzdJGREU/ +Sjg/RjtISD07Qzk9Pjs7QD8/Qjw1QTdBQD81STw+REJfgYFOT1s+YGaDn69xlJ5mb4A6SUFE +Ulx0oJ5+lqV3iptzi59yiZhqhphpgJVggJFohpZlgJVogpRmgJVkeYtHS1dGZGNieYxrhpF5 +k6duiZ16k6JyjJxxhJhnhZNogJRlhpVviZpoh5dpg5Voh5RqfpNjf4tkfYxviJVphI9fb39e +bXSfsqfR4tTq9eL2+uz7/+37//Hz/e39/Ov///P///X///L//+/0/+f7/+7///H///P8//P/ +//X7//P+//D9//H///H///P7/+32/On0+ej3/e39/+7///T///T//+7//+////P///X///b/ +//X//+///+v//+33/+73/+vz/ujv/ufz+ez1/+T+//H//+////f6/uv0/en+//D///X//+37 +//H3/Oj+/+////D//+////D//+z///D+/+7+//D///T//+z///P///D///r///b///f///f/ +//X///b///L///f///f///f///X///f///b///v///P///b///P///b//+z///X///r///r/ +//X///D9/+////H///f///b///j9//P2/OX6/+3///X9/+z4//L3/+/3//L6//f1/+/y/er0 +/+36//H1//Ds//Dn/OLw/+3n/urn/O3r/+ru/+3v/+jx/evv/+v0/+/3/+/2/+v///P//+/+ +//T+//H//+n//+j+/+z5/+n8/ur/8t//9cb/8sz/7sf+5cL20qf5yaX20aD22qr+5bP+47f7 +05v0xJ/kpYDjrYfeuYnpxJbuz6Hzz6PzzaT+6bT/6bj/7b7+68L96sH96rz+7MT88cf95rn1 +7cL+6rz85bf+5rf65rP+57713Kf0zqXjv4rhu5DUwIrZr4rCn3PAk26vj3Ozjm6igmSRe2Wb +blyJe1qNe2XN5cXX5dvo+eT3/ub3/+Xy/+vz9+fj8tqFn6ZdjZNkjp5bmZ1ai5lVjZJajZdZ +kZhdkppQi5NZkptak5RYkpZUj5RWiZJbk5xYkJdRi5VSjJJTjJNLfIZDc4BAcHFAd31Lh5BR +jo9XkZNVkJhQhYtTi4tcj5dOhpBXjJhVjpJfj5tQjpdai5tNipZThpBNhpBQhItOg45MhIpV +h5FPgYpOeYZEd39HcH4/bHlAaXA9aW46Zm03YGQ7Y2c8a21HdHRNfIRIeH5FdXxHenhDdH5J +c3xGdnxGdHpAYm1AWls+WFpAV1k+Sk83QDkyPzc5PDoyPjQ4PDkzQDY6PjY2QDc9Qzo5PDc6 +QDg3OzQ6Pzk9QjpgYkZ+dlmWiGShiGifjWWkkWqfi2qci2iej2unkG6jjW6wmW+sk2+unW29 +n3jEpW/Gp3e8nnPFpHTDnG3KpnTAmGzOn3LPoHPMona/nG++kW2uiGipflrazoX+/+n///// +///////////+//b+//n////////////////9//T///7///r9//X4/+n7//Dv/er8//H4/+/7 +//D0/+31/+b7//z1/+jx/ub8//D1//z///n1/vb///75/ef9/fT1/+z5/fP9//n+//39//f9 +//7//+/y/+77//v////6//fy++719/H6/u/y/evw79/4/vD2/PHu/u709OffxcJMRkg8Rz5J +RkVBSzxDRkE4Qzo8QEAyPzdBQEI6RDs9Pj9CamtvfolASk9YgYx/nq1+lKl2gJI0Qkc9TFRe +gIR1kaB0i51riZlriJhnhJVpgZdjgJhsgZdkgJBrf5Vjg41kg5FianNATFhVdnxjfo5riZF0 +i51zkZxxiKFohpdmfpFmf5Nng5Jng5dnhZdqgpdohJFogpVif4phfYpif4tnfohZZm+Yr6fb +49rl9eD5/ej9/+3///T3//D4+u35/+v///T///L///D2/Or1+Ob9/+////T///T8//L4/+/z +++n7/+////r///X///f///T5/+/4//D///L///L///T//ev1++33/+v///b///L///r//+77 +//L3/+j8//X5/+33/e/2/ur2+Ovx+eb2/+n6//T///T9//Lz/e/4/u36/+z8//D7/+n6/+7/ +//T//+7///X///L///P///X///L///b///b///f///L///b///j///7///X///v///P///r/ +//X///f///f///f///T///f///r///n///r///j///X///D///v///T///v///f///r///X/ +//f///D///r///v///f///f///L//+7//+v///X///P9//L1/+fv/+zx/+z6//Pz//Dp/+vl +/+zj++fh+ubc8+Hy//Hz/+3x/+zw/+/y//Lv/+/1//L2/+72/+3y/+/y/+zw/+3w/unt/e/o +/+3z//Ps/+31/+74/+z6/+3//un//ur/8s7+5b75z6z50Kf5z6P20az32q7816z326f3zZ/t +xJ7nrYrpwJnnwqDqzZrz2qjz1qfyyZn33qz+4rn36sL87MX+77/+68P56cL+7cr85r376sX6 +6MX+57385rv+4rn55bn52rbxy5rpxZnnvZnav5LTpYDMn3G6mXWviXGkfWKYc16FalaMdlyF +cVu40rrd89ne9eL3/Oj6/uv4/+n1/evJ0cOTrKxcm59ilqRalJddk6JZi51bk6Jbi5RakJVZ +jJpWjZZYjJNVk5ZYi5RaipJUj5dTi5RXjpBWjpdTiJhZj5pMhpBQeI1BdH5Nc3xIe4FcjJJS +ipRWjZNUiZJaipJMhJdVhZFQi5dYj5NTiJlTjZddiZdQjJZaj5tOiZVRhpROiJJUg5FSiJBR +gY1Pg45LgYtLd4lDe4hBbH8/aXM7ZnM/Ymc8X3A/aWpAaXZIen9KfYlRfIVGcnxNdoBFdH5L +dIBKc3dHZno6XmE/Wl47WVZARFMyPDs1OzszPTY7PTg4OTo9Pzo4OTs/QTg4Qj47Pjg2PDo5 +OzxAPz08QTpTWEF5b1eOhV6dgWaZhGGei2yYgWyahmeajGShjGuljGevnHSplG6xnnK/pHrL +r3/HqHzGn3jDlnXBl27FoHDKn3bIpnbIm3fHlnS8jGm1iG2rf12wg2ffzYv+//r///////// +//////////////////////////////////////////////////////r///////36//Xy++rn +/Obg99Xs9+P0+/Dl8t3v/+vx/Oj1//n7//L6//f9//b///r///v///3///H0/+/2//Ty/+75 +//v//+/5/+/0/PP///z///3///////////37/ff///r///3////7//Lu1M5HQEU/STo9Q0BE +RTk8QDs+QTo0QjtAQjszODo/QjwtPjtphYtjanVLTVNwmaKMoq51kZ91j59JUGI8SUtPcHl5 +l6B1h5xyiZtyhZFmg5dof49mgJRth5pmgpNqgpZmgZJmfpBqe45FSVNRam9je4llhZF6kKN5 +kaVzj51viZxngJNmgpNqgJFniJZphZNliJpxgZhmhJRogY9le4tmgItWcXdmgnrL3sj2+ej2 +++X9/+z///H///T7/+r6/+38/+z9/+38//D//+/9/+79/+7///D///T///H///D2/e37/en9 +/+////f///b///X6/ez0/+b8/+////n///T///b8//L9/u3///L///T6//H///X5/+z0/un6 +/+3///X9//L8/+z5/+/6/+r5/+n8/+/9/+7///T7//D///L///H///X///H///H///D///P/ +//b///f///P///T9//L///b///T///r///v9//D9//j///b///n///f///T///X///T///n/ +//H///v///b///n///f///z///j///z///f///f///L///r///X///z///L///v///n///r/ +//f///n///j///n///j///P///j///f///v///T///X+/+78/+n9/+r5//D7//L4/+/4//Pu +/+/s++rr/ub3//H1/+v8/+/2//Dq+uvN8+PV+uft/+/7/+/3/+/7//D6//D3/+31/+/2/+/4 +//P3/+/5//D4//H0/uz5/+j9//H//u7/58j/377+4Lb/37L/67r/5Lz+2Kv81KP1x5f30Kfv +tJvty6f2y6nvy6T64bz63av91qz62Kr/5bz96bH88ML/7sL+6sD56bz76bz66MD56b785L31 +5LX95bn547b53rPy2KDwzZ7iqojMpnvLn3XJlHDClXe1kXC6jm+gf2SdeWOQelyUfGqhtIzr +9t7b8Nvy/uj7/ef7/uv2/+nr6Nquw7iOmqBeko5klJNimJ1hlZxhlJpjlpBakZlikppakJFX +jpZSkZNakZVXjJdajZhSjo9VjZJQj5BajpxRj5Vej51Mio1RgZBCen9Oc35BdXpRgolPh4xb +jpRWiZVWjpZTiZNFjJFWio5VjJNTi5JXkY9Vi5NVi5VViYxTjJBPho1Si4xKhpVVhYxOf4lW +gI9Mf4ZSf4ZGeYBQdYBBbHJBZXQ8ZGQ/YWs/ZmlBZnJFb3ZGcHJLenxGcXpJcnhKeXpLc39J +dHlGbHdHYGk8WldAWlc+S0c6QDU1PzM/PDgxQjM9QjotQjg+PzswQjdBQjs1QzJCQjk6Pzk8 +Pjg8PTlESj1pakyGe1uXgGaUg2CdiGWeiWSZg2Wdj2aojmqolm+ulGyqk3O1oHC+n3PEpXTM +pnrJo3PFnXXDmW/PpnnPp3XSqHvQoHPDl3jClGyzh2OtgWOqgV/g0YP9/+////r///////// +//////////////////////////v////+//f4/+39//L6/+/+//f7//H+//72/ef1/uvn9ufs ++97+//vq9uDm8dv9/+70/fP8//H1//bt/Ojw++3u/fDu/+z6//b1//L7//f58+jv/OT+/vr7 +//H+//n///7////7//f1/e/x+/H7+uz4+vD5//fx9+Tr7uPm9uX14+ZGQElCPUI8RUFBQ0E9 +PTpCQz9CPz4zPz88QDw8Oz1DSldnf4pZV2RDUmOEpayBnqh2j6Jzkp1nZHI/RE9CVl16l59z +jJ90gJxqhJNug5Nmf5FqgZlrgZRqfpZlhpVug51ogZNmfYxeWHE/VFJld4Fkfo9uk550jqJv +h5xtg51mf5NogZZlf5Jpg49kgJBohpZlgJVpfJNigI5vepNRb3dXXmaEpJnj7trx/un6/uf6 +/+v9/+78//H//+3//+/8/+z5/+v9/+z///T///D+//L///D7/+/9//L//+3///L+/+7///T+ +/+7///P8/+39/+/9/+7///b///f///j///D6/+v+/+7///X///v///P///j///T///X//+// +//H///P///T///H7//H7/+z///D///P///b///T9/+////L///n///39//D//+7///L///j/ +//v///f///X//+////X///X///3///X//+z///T///j///n///n///n///P///j///f///X/ +//b///r///b///v///z///r///n///v///r///n///j///v///7///n///r///v///7///z/ +//////z///3///n///n///j///3///j///z///n///z///b///z///T///r+//L8/+z0//Lp +/PDt++jf+un4//H9//f6//D9//jz9+/R2d7B89vp/+/6//D7/+/3/+7///T7//D8//T8//D+ +//j7/vPv+Ojw//L8/u3+/+7///L///D/++v/8Mv/+NH/9tL/9c3/7Mj+3rf32rT/4sH92bb1 +4K731rHy0KLy4LX/4L792Lj4zKH25bP/57r97cD/9L797Lz7673+777447X85bv54bX54br2 +3rH32qr31qnx2KvrvZnhvpLguovSpYnIj3C6k2zDm3+ykHSrgGmae2Kac2aHhWXk9N3d7d3r +/OX9/+rz++j0/OD7/+jq2dW1vrWCnp5fjZ1jlp5impldlZpYi5tWjZpWiJhWjZRaj5VZj5Zb +k5pVjZhajZZXjJdcj49TiplYhpRUjJhaiZdTipdah41Pg5FEen5GcHpEcXtIeYJHgYRZiJBP +ipNZjZNSjZRUhZFRh49TiI1RhpNUg4pTiJJRh5NSipZYiZBLg49RhYxUiotMgpBLgZFRgotM +goxMe4VFeYZEcH1CcH1BY3U4YGo8X2g4YmU/XmU7aGxEdXdIfIFJcYRCbXRNdXtJfX1KbntC +bnZBandAYW4+VVw7PEw3Ojg3Ojc6Ojs3Pzg0Pjk4PjY+Ojs/Qjk9QjozPzQ6Pzo3PzY+PD05 +QTQ9QzlbY0eCd1mKeV+ReWGNgVyWgGeRgmSgiGSmjmenim6nkGitlG+/n3a6oXjBqnrMqXzF +oXrCom/GoXPKnnTIoHDJl2/HnHHBk2+4jmy4jGSsgWanfWPQyHz9//T///3///z///3///z/ +//7///////////////////////3////////////////////////5//X3//D+//zw/+zq/93z ++Ofz+ufw++j7//H2//T0/+vs++j5+/b5/PH7+vX//fn9/vv7//f///7////9///5//f8//H/ +//31/erq+d73/fj///////z///////n///7///X7//X2//Dk3dNJQkE/PkJCQ0I6OztERDo5 +PTtCQEFARz89Pj44SDpYeXxwfo1bVWVEdnOXr7h6kqZ4iKF3jJ12doxBRkw8TVRdh4t6kKBx +iJlvg5hshplpg5hugZpshpdngJVrg5Zrg5RsgZNng49mc4o7SFJZbnFff4trhpl5kKJ3iZxl +iZhxgZplg5Ntf5RmhpVqhpRtg5loh5ZpfI9ge41reoVNVV9JUE6LtJbm+9z1/e79/+78//D8 +//L8//L8/+78/+76/+v7/+v//+7///b///H///X//+z///L///P///P///b///P9//H///P/ +//P///H///H///T///P///X///b7/+/5/+7//+////P///n9//f///f///X9//T///L///X/ +//D///L///X7//P6//P///H///n///f///b+/+n+//T///v///j8/+39/+n///T///b///b/ +//X//+7///P///f///P///P///T9//L9//b///j///f///j///n///j///v///n///L///z/ +//v///v///3///r///z///r///v///j///X///n///b///n///v///7///z///n///z///r/ +//z///z///v///r///v///b///v///n///7///r///v///n///v///b///r///L///f///H8 +/PLu/OX9//P1//D6//j///b///n4/PbY6OPh++j7//D5//T8//P8//L8//L9//T6//T4//Hx +/+76/+////X///H///H//+7///T///L//u7//+D//eX/+s7/8sj/3Lj/7cD/78X+9NH55LL8 +4LTwzqT64Lf/58L/4Lv92Kv94rX+6Lr66bn/6L/+7Lv35sH+4rn32rP64bDy2aX337Dz2abv +267t3qfy0LDqx5XcwY3duYvSqX/No3/FmG65i3Cth2ilg2edfF+Sc2jM5cvr+Ofh9N/6/u/5 +/ejw+u33/un5/+vb3c6VsKhyl5pdkZphlJ1knZxsmJ1fmKBcjp9Vk55dkZtXl5hhlJpilJxZ +jJNej51ck5lei5tVj5VjmJ5bkpRaiqBZkJRYhpdTipdQf45Id4VCdX1JeoBPg4tSipFUjJJX +k5hUjJdTi5RShYxPjY9Vi49OhpVOhY1Oho1XjZNMhoxPgo1PipVSjpdYkI5NhI5Nh45TjJdS +gotMhIxIfIZJcnw+bXpBZ3Q6ZW1AYmk8X2ZBZWZFbW1Fc3NKdnpHcHlEbnRKdXs/cHtHcn1F +cXlFZHc6WWFARlM3PTk4PzszPjY8Pjg0PDY7OjszPjU/Pj83Pjc/PDg1QTU+QDg8Pzo9PTo6 +QjdUWz95b1WEdFWJfFuVgWGQgmOVh2aWfmSnj2qkjWymk3Csm226oXO9pXXEp3fDpHfOp3fC +o3G4hG2+oWnSqXvFn2/KmHjBmG63g2qrfluzhWevh2PNyH79//H///////////////////// +//////////78//j9//P///////////v9//j////8//Pv/ur5/+z+///2/+/q/+rk/9Lq9eDk +9Njs++L3/+zu9+b1/PH7//r///7///v///31/+/9//n9//L19evu/+35/+zu+/P+//7/9/n/ +//z///z9//P4//r///fw/e309PH+//r///7///z/+fHo5NZOQktBSEBCP0M2RTc+Rj88QzdC +QUM2QzZBQ0I6SU1qepJhf41KS1dThImas71+mKt4lqV0kaZzh5pKRlk8SU9Ha3R+laR2jKB0 +jZ5vgpZtg5NqipVyipppgpZsipZlg5Fwg5Zng5RxgJJUWG5MW2ZefohthJRylaNyjZ5yjZ1s +ip9qf5RpgZNph5huippuiZRpgpZofI9meIxaanRCR0xCSUJkk3ff9NX3/+7+/+77//H//+z/ +//P//+////L///b///b///X///b///r///b///f///T///j///P///b///T///j///X///v/ +//j///b///n///f///v///j///r///f///H///D///f9//T///H//+v//+7///b///b///v/ +//P///P8/+76/+7///P///f///b+//T+/+z///j///X//+/8/+r+//T///b///X///b///T/ +//b///n///j//+7///X///f///P///n///b///X///P///v///j///z///j///j///r///3/ +//j///7///z///z///j///v///f///b///b///f///v///n///z///j///3///z///r///3/ +//f///r///3///r///n///7///r///3///7///3///n///////n///z///n///r///T///j/ +//b+//f6/+79//f///b9//T+//nz+/L0//H///f///f///L7//X7//b7//f8//T4//X8/+78 +/+7+//j8//D+//P2/+7///H//+////X///H//t///Nj/8r7/7LX/9cv/9tD/+sj937v62qv1 +1LL73q336bj+5Ln72ar626782rL22Kv46Lj96sH24K/93Lb31K772bX40Kn117Ty06vx26Hw +1KHryKDox47dtZLOroHMsH7KqonKpIDFoYC+knqne2SZdGG61Lvq+ODb8+L4/uv2/+v6/+b1 +/+v//+n49+fCy7ynr7FumZ1bkZhfjJVfmJdilZ9gjJthj5hajZpbkZpkkp5YlJphkZhblpdg +kZhRjJVWjJZVi5dbj5hbk5NZkptakZlUh5dRipFRhIlLeohJd4NGd4hKfYlNg4pMho1Ui5ZX +j45ShZBShYlMhoxPipVPjI1SjZdRiJJYjJNUjpBXiZZRjJNWiphPiYxRio5QhZJQiZFPho1W +iI5PfYhLeohGc39BbXs6ZXA7YWw9Ymg8YWtBZGZCZ3JHc3JHd3xGb35McntJc4JIdX9Oc4FI +a4A9XWpBTls1Qjo9OT4zPDM9QTo3PDc7QTozQjY9Pjg6Pjc6Pjg4Pzo7PjY+QTo7QDQ9RDtN +UEBuZ0+GdlqFeleRf2KSgGGYhGGUiGOmk2qgkGiul3KwnXO7nHW5oXHGpXjBnnXEonfDpXbH +pHXCnHDPrHHMqXvQpHjOpXi/m3S1iGisf2OogWDHyXn+/+7///T///////7///v///////// +//////////////3///////v///////f6//n9//D///j///rw+/Dt+uXx/ezq/9z1/u/x/Ojm +8eH0/+z6//z///nt/evx/uz3//Dz/+79/+/w/+z9//v9//f8/fT6+fX+/vv///z///////z/ +//////z///v6//D0/fP+//35/+3u/+33/vX0//Dy7ORSRERBQj9EPztHQEA6PTk/QkA2QjhE +PkQ7SDhIWWZpfoxpfYVBRkxVdIOMqrR5jqF9jKN6j6F8laNpXXI/RE9EV2RdlI6CkqN1iZpu +iJZogJVshpVngo1thZZjhYxxfpBhhJFvgZRXcHlTaX5zhZZod4tkgZNrhZJ2i5trhJhphZdn +hY9mgpFlf5Rxip1oh5xugJdogY1nc4NHUVhIQ0U/RUJMalnR7cj4/+f9/+7//+3///b///H/ +//b+//H///f///X///j///X///T///b///f///X///P///f///f///T///f///b///X///X/ +//P///f///T///j///b///X///n///T///X///b///H///X///b///L///T///b///T///b/ +//H///X9//L///X//+3///f///X///D///r//+z9/+////D///X///X///X///T///j///r/ +//r///P///f///f///z///T///j///b///f///v///X///j///n///z///P///v///X///z/ +//b///z///v///z///r///////b///H///f///////////3///z///z///////f///b///n/ +//z///f///v///v///r///v///j///3///f///3///b///z///H///7///f///r///T///v/ +//j///f///T///T///f4//P6//T///j///n+//X9//L5//P2//T+//T///X+//f7//T///n/ +//P///X///L+//L6//L//+////f///L//uv/+dH/6bv/7Ln//cP//c3/+dH+57362K363bb5 +3rz+3bX/3q381qb31Kz33Kvz2az93Kz12bL62LX72bL637L626f62afy1KH43K3w0p3s0qLs +yaHlw5Lar4PPoXTGonzJrHvYq4PLqH/Bk3qlhmamp5Dq+uDX7dnk++j6/+r8/+f1/+j//+j5 +/uj18+DF2s+aqKVmk6BhkZxXiZdZl5BUi5NWlJVek51Uk5Vhl6FakZlgj5VYkp5ikJ9VlJNd +iphVkZZZkZVXkJRaipdXjpNbjJdckJdajJlPipZRgItHeYBFd31IeYNJgYFOhY9Vio9WjpdX +i5hUiJNahZVQi5NZio9TjJJai5ZSipNTh5NMho1ThZdPhIpTf41Kh4tTiJBRiJFSgJBJhoVP +f41HeoRMdoRFb4FDanhBZG86Xmo9Y2Y+ZmY9ZWtDbXFNd3dKbnlBbXNGdntEdX1FdnxFcXpF +Y3FAU1g/QkIzPjY8PjY1QDY6PTs0Pzg4PTg7QDg/Pzw6OzQ3Qjg4Ozg8QjM+Pzc6QTdFTDpr +a06CcleKfFuRgF6TfmWXhWCZi2qdiWmmiGmslGawknawlG+8mnG7oXTLoHvBo3PLpXnGqXLQ +p3vDknDLnXDRqHnHl3W1kmu2h2alhWCvgWLVyHr9/+z///3///////3///////////////// +//////////////T7//T///r///3///n///z///T9/vn+/+7///n2//fh+9bw+efp9uTt6uPv +/+by/+z6/vH8//ny/+Tz++/4/vT8//X8//T9//f+//j///7///////P///z+//z///37//v9 +//r///r3//b///7s8uP8/vz///////Xn9+Dq5ddIRkNGQj9BRztCQUI5STlBRT88QTlISEQ/ +R0Zhe4xrg5Nlb3xGSFFZfYeIqK93lKV1k6V5kqF1jp10cYRBTE9CTVhJaXJxj51zjZtviJhn +gZNvg49mgI1qgpZqhI9lf5FbdX9TanJme453ip5yiZljfY1kgY5ofY5qi5Jpf5Nng5Rqf5lv +g5Nqg5JoiJRshZdviJdle41VZm5FRExAQkFJR0VLZljQ5Mby/ub+//D+//H///H///T///b/ +//L///P///L///T///X///X///r///H///T///X///P///T///L///T///T///n///f///j/ +//L///z///n///n///X///r///f///r///b///D///j///f///T///f///v///j///X///T/ +//T//+////b///P///T///n///P///X///H///f//+////X///f///f///P///P///j///X/ +//j///f///r///j///P///z///z///r///j///b///r///n///r///P///n///r///b///j/ +//j///z///j///r///n///j///H///X///n///3///b///v///z///n///3///3///v///b/ +//7///r///z///r///n///X///n///X///z///n///n///X///r///T///3///j///r///X/ +//z///3///v///r///f///f///r///n+//b6/+7///b9//P///b///j8//X8//H+//j+//H+ +//D+//P///X///L///D9//H3/+b//+f/+9f/9M7/8MT/99H/+dT/9cr+7cfzyp/y2LH15Lf8 +5rn73af82rL02an31rPs0ar32a3x2aLu16/y3an65LDz1a/1z6312qjv0KntzZzq0qDmxJvn +xJPgupnXr5LMpIPTso/JqoXEnnytl4PTxrvm+d3c69vs/On+//D5/+n9//D9/+3//+z0/uPc +7t/D18qkqLhrkp1kl51ikZtZl5hbjpdRlpZhkZpYj5Rdk5pbi5VajplckZtZkppgjJxRjZda +lJZWi5lYiJFUkZtekZRclZpdjphTjJZejJNJh4xSd4ZKc4FHeX9CfIRQj4lUjZNZkZVajJhZ +kppdi5dRj5VZiZFNio1XiZRSi5NWho5RhZBQh5FUho5Wh45LhZBVh5JPio1Tgo1Lgo1SfYdM +f4hQeohBcIBGbHU/Z3c/Xm06YGQ/YGQ/Z2VEaXFDbHRJcHlFbndKdHNMdX1Od3xEcXZGZ3A/ +W2U9Q0s1Ozw8QjoyQzo6Pzs4QDw3RDs6QTY6QDg4QTc5Ozs5QTY5Pjw4QDk8PztBTzlrZ02D +eFOMemCIflySf2WRfWKcgmSdi2ejjWirk2uukXC1j2q9mHK8n3HEm3fGo2zKqHXMsnXUrIDJ +o3rMnGzKqXfEoXHAl3CuhGOuhV6sfGHKxnP7/er///////j///////////////////////// +///9/+7///T///////z///////////r///z7//f+//z3/vbg8tvk/dfu++Xv+ubw/eX7//b4 +9eTt/e36/+75//L///3///f6/+79//nq89/+/vXt/un0//P+//v59/H1/Ov7//b2//X1/fX0 +/+v+/vX0++n9//f///r8//b///r///Pt59xRRkI9RTs+Qz87SjlFSUM6SDhFRUI5Rz1IXWRr +jZdthZhfX2Y/TFFflJWMoqt3jJ52i6FsjZd1kaF3gpJAS1FETFZNYm5khY59jJxrhZJug5Bm +fpBqe45lfIhpfoxbZHNVWG1liY6GlqByhZBvf5JefY1ke5BjgIplf45ng41pf5BigoxrgpJq +gpJshZZsgpRrhpRpdohTVmJCSENCRUdBR0JHXVS53rfy/ef7/+39//H///P///P///D///f/ +//P///f///H///b///X///H///P///P///T///L///T///L///P///b///b///T///X///r/ +//n///n///X///b///j///T///X///j9/+7///b///X///j//+////n///H///j///T///j/ +//b///X///T///X///X///f///f///L///f//+z///X///j///P///j///X///X///j///b/ +//X///r///X///L///f///j///b///j///f///f///3///n///X///f///z///f///f///b/ +//3///j///v///b///X///H///f///f///j///v///b///v///z///v///r///v///b///j/ +//j///////z///b///T///j///z///n///r///f///T//+7///v///r///n///X///r///T/ +//X///T///j///L///f+//f+//b///T8//L///P+//P+//L///X///L///b//+z///P//+n/ +//H///P///f+/+3+//X6/+b+/uf//dn/9dL/78L/+9D/9c3/9Mz/6sT5x6Hl16jy3rT02rDz +2q7x2KH027Du2KzwzqntxqDry5zm0KTxz63tyqfv0LDt16j11qvt06PxzKbnxpzmyJ/kyJ7j +xZ/fxKDhupfTsY3QtJLQ0LPg9tnt++Lf8Nfk++n+/+71/+n6/+n9/+vy/+j9/+r1+uLX5ta8 +38ezu8SHmqpYm5VhkZ9al5lejZxSjZZgk51YlpRYkJ9dk5JSl5dak5dfkZlblZpWlJhWkpZV +jZRZjJVbkZRbjZpaj5FYk5haj5hUipdYjJVMgI1Qe4VEe4JLeX1FhYVYjJBNjJBYjJZMipZZ +io9RhopUg4tSiI1Xj49OjpNVjZNXipJSjY1ThZFOiYtRiYxRh4tWh4tNhItNgotNg41Pg4lI +dYdHcXpBb3hDaXE+Y2w+YmU7X2M7YGRAZ21Ea3BDdXlQc3hEcG9JdXhFcXlGaXY/aGhHXmc5 +RE88PDo1PTI4Qzo3PTU8PDozPzY8PTs3Pj47PTc7Qjg4QDY7Qjg4PTc8PzY/Sj9raUp5cVmK +dWCLfV6SiGGUhGKdhWKUgmWei2OrjmmwmG63l3O5kGnFoXbGqHDHn3bHq3PMrXHOqnrPonbJ +pHHKmnK/lmvDl221h2qthmaqgGXHxHb6/+n///L///z///r///////////3///n///n///D/ +//D///////////33/+78//H5//P9//f3//fy+u3q++Lz/+/k/tf6//Lr+uXj9tz8/+/2//Tt ++ezw/vH8//f8//j4/fH1/u37//v///f9//z///z///////H8//r///37/fP+/vz////7//b/ +//7////3+/Tz/+v8//D1++zq+ubx7NpPS0k9Q0M/SUBDST9EQzw/QUFERUJEQkRNaHBifI54 +jZtOVGBHXGlumqSCnqV6j6J+kaJvi6J7lqZ6jp5PUF48SVREUGFhgY57jJxwgZhngZJtf5Jl +fYldaXZRYGpQZnNggomFn6l6lqBzg5VkgZFpgJBqfZBkgpBphJdlfJNlgJNpf5BogZFrhJFs +h5puhJZohZRmfpBLV2M9R0Q7SUJARURBUUuqyKrs++P9/+/8/+3///L///L///P///P///b/ +//X///X///X///T///L///X8//P///T///X///X///j///X///b///f///T///r///T///v/ +//j///n///j///n///f///b///f///b///b///j///f///r///j///b///r///3///P///T/ +//T///P///j///X///b///j///b///n//+3///T///P///n///T///j///f///z///j///7/ +//r///z///X///7///n///n///n///v///j///X///f///T///f///3///r///7///j///n/ +//n///z///f///f///T///v///z///////f///n///j///z///n///7///b///7///3///z/ +//7///3///b///r///j///z///z///j///j///X///P///n///n///f///T///f///n///7/ +//j///n///X//+////H///b///f///X///X///n///j///L///7///n///v///f///f///T/ +//f///f//+///+3//+/9/vD9/Nv/9Nf/89P/99j/99X/9NP/9s398dj378/7+9/7+OD5+d36 +/uH4/t/9/uj199z189/s7c7s4c/x6MDv2sTs1bDs27Xq2LTm06vryKbm0Krs0qblx6LjyKXf +ya7i5Ljn+tv1/OXr++fl++Xl+ef2/uP9/+75/+b9/+/7/+nq8N7m/N/7/+vs8uXE0cbS7drO +zc6OpqxvmaRhkpphkJ5elpxXjptbkJhclZ5gk51flZhbk5hijqBbkZ9bkpdakpdbk5VXkJZa +jJRVjpNhj5RVjpJajJVKi5NYjJVPjJZThJBHf4tJeoxFeYNOeIBLfoZdiJVSi5BYjJhWiZVV +iJBWhY9TipJVipVSi5hXipZViZJXiotVi49QjJFShpRTjI5PhotQg4pRhI5OholNfolFeoFP +c4dBc3xKa34+bG5DZnA8ZWJBYWo/Y2Y/bHBEanNMd3tHbnlHdHBLcX9GZnRIbHA/am9DTVs3 +Pj05Pzs4QD88PTw6PTg2PDk8QTw3QDY9QDg4QDc+QD42PjhAPz0yRDtIST1fZEZ/clWEdlqS +fGKQfmSVg2aSg2iPfGObgmWliGmymG24nHW/lHDBpnbKpXPKpnjNqH/EoXTKp3nHn3HJo3O/ +knDCkGq/k220h2mjdmWhelzIx3f9//////////////////////3////////////////////+ +//36//H4/+v+//3////////7//T6//H////8//vs/+Xm/Nfo8eLr99/3+/Dz9en7//n///X3 +//b///v6//H9//z9/+v3//X5//L6/fX1/+3///f+//z///////n9//j6//f5//L7//r9//j+ +//Tz9u7+//P+//n///////Dr3tZYSEU8RT5IQz5CRj9IRUA7Qj9HQz8+S0pifopoi5p1gItC +SFJKZ3WFoayDna59mqx7kqR3lKd7mKiInq1VWW1HSVU8T15Sbnp0kJd2hptqgpBlcIRWWWxS +W2tOaHRedYl+nql9l6l2iqBvg5RlfI9rgJNsiJpsgpVnhZlrf5BmfZBle41lgI1ohZBshJZz +hpxuh5ZqfZRXYXJDR0w8Q0BARj9ATkakyafw+OP5/+7///D9//P///H///X///P///L///P/ +//L///D///T///L///L7/+3///T///D///T///H///X///H///b///f///T///j///v///b/ +//n///X///n///f///j///f///3///j///r///n///b///f///b///n///f///f///T///T/ +//f///b///j///L///j///L///r//+3///r///T///v///j///j///b///3///n///z///r/ +//v///X///j///j///n///z///n///r///v///n///P///r///z///f///z///n///7///f/ +//z///n///j///f///n///z///r///n///b///n///3///n///r///r///3///v///n///3/ +//z///v///z///v///v///n///n///n///3///r///////////z///j///v///z///7///7/ +//z///7///r///r///3///r///7///X///v///r///b///r///j///X///v///P///z///X/ +//j//+////r//+////T///H//+v///H//+j///L///L///L//+////P9//H///L9//H///b9 +/+/+//L2/+r8/+/6/ury/+7x/uXz/ur2/+Ts/en5+unz/Ony/OHz/OD1/ePw+OXx/uf0/+jq ++eLl9+bp/Obx++vs/uj3/+3//+/8/+75/+z+/+j7/+Dy/eT2/+Lz+fDd5dK94cjh/ODU1dmT +sbZ8laVjkJlhmJpekp1iipdXkZxel5hhl6Bfj5dZkJdfjJlUlZlkkZpPio9UiJVYkZddjJdV +jpVWi5RTiZdbjJlVi5RbjplSi5ZPhJZKf41KgIlMf4VKeIVLgYlNgotUho1Uj5JVjJFTi5JO +i45NiI5PgYpWjZVPipJShZBNi5NThotPh41ShZFNiIxYhY5PiIlRgIxOfIRKeYdJfINKdIVD +cH1FbnxBZ3U8Z3A/Y208X2o/V2Q+YWU8a2xIc3ZEcXdHa29Hb3JGZXNEZmpDZ3M8WmE+PkYy +PDQ/PzszPTQ8Pjk0PzhBPzk2PThCPjo6PTk9Pjg4QTk4PTk3Pjk9QzljYEh6c1OGemCKfmCV +g2KPf2aOemCVgWeehmSsj2irjW23lXK1k2vAoXjNp3bGonzUrH3Ko3vHpXDNqHzLonjAmHPD +kW+6j2y1iWqof16wgWO7qm75/9j///r///////z////////////9/+7+//X///////n///// +///////////5//T4/+/////8//3z+eT4//Tt/+f5/+n///v3//Tx8+r6/+/s9Oby/un9//nu +/en+//T5//L+//X1//f///7///////f6//b///v///f1//L4//j///39//////Pz+/P8/vz/ +//v///////f///3///Lz7+RPSEhBQz44PTdAPkA7QzpCQkQ8Rz9HWGBmi5VviJ1maHRFTlhQ +dn5/paqJo7KIorCCnKZ5nKeGp7GHpa5hZ3g+TVI/SVRMZW9oi49zfYpXXmlRX29KaHFbdYVt +jZt9l6V8nqJ8lqdxi5xugJRmeYhog45yjZd1j6JmhJBmgpVmgYxjfIdogYtmf49thJNki5dw +hZRtgpdebX1FSEs+RkE+RD87RkKJtI/m+N75/+37/+z///H///H///X///D///X///L///H/ +//L///H///T///L8/+/6//D///L//+////H8//H///H///T///X///f///j///j///T///f/ +//j///z///b///v///r///f///P///j///b///f///j///r///b///T///j///X///T///D/ +//D///D///T///L///L///r///P///n///X///n///j///n///b///n///f///z///r///n/ +//P///P///b///f///r///T///3///n///n///L///f///X///n///r///r///r///z///j/ +//T///r///f///T///n///z///X///r///X///j///b///z///j///j///n///n///3///z/ +//z///j///////r///////z///7///b///7///z///3///X///3///f///7///3///////7/ +//v///r///n///b///r///z///n///r///3///f///r///T///v///P///j///T///v///H/ +//j///j///z///P///H//+7///D//+///+3///H//+///+7//+/+//P+//L///P///L///L/ +//T///L///j///D///v9/+z+//L6/+79/+/4/uj5/Ovt+uTs+ePd7d3b6tjg79nZ8OHW7tzf +9dvq/er0//D3/+z+/+j9/+n//+v8/+j3/+Lv/eXz/+Tk89bK3M20zb/g9+Pd+uXd59iar7qP +nLF4mJlclp9glZpXkp9dlptfk5VZk5hXkppZkJdWkJJckZRZlZJilptYkZNakJlWjpBTjZVa +jpJXj5dWkJFSi5JYiYxTho5Wio1QiZBUio1MhYxNf4hIgohViI1QjJNVjJBXkZNRj5VQjZBS +iZNSh41RiIxSipNMipBTiJBPiI5OhpNUiJBRhY5Mgo1QgItKgohNgIlIfYdNeYRPeYpJcYBF +b4BEb3g+a3k+am04YmpAX2ZAYGk8aXFBb29JdXVEdHhCaXY8aHNDY2s/bG4/WWc6Q0Y9QDs5 +RDk6Pzo2Pjc0PDY2Pjk1PTg2Ojc4PDs1PjY5Pzg8PjY2PzlCPjtcYkl8dFOEdlmLgFaSf2aL +emKKe1qVgV6ciWWqkmqrjmmzoXC+nHjBmG3GonfDo3fKq3fMrHjOonrGn27DnHW+mHG1hGWz +jmS3i2ewhGakeF66sXH9/+j///////z///r///////////////////7///X////3/+79//v/ +///////////////5//P7//H0//Hs9uLt/ujn/9rx/efs/OXh7938//v9/vr4//r5//Hz/vL+ +/vn1++js/d/w/vP8//T19en5/u36/+ry//L2//H+//f///7///3///////////37//z+//z1 +/e74//X5//L3//H59uVYSEtARD5ERT08Qz8+QkA+R0E/SUJMcHdwk55vhZlRUl8/X19igIp4 +qqaQq7WFpq+FoLB1lqOCr7SIsbFzd49AUFZDS1VBWmFbanJOX2pOYG1JaXVsjJiFpq6SrLSP +oat8oax9j510iZZmhpVofY9mgo94kJ18maFziJ5jhZFsgI9ifotlfYxjfo9pg5NsiJdziJ1t +iJlnb4dARU9BRERBSD9CR0aEqoHg89r3/uz+/+36/+///+////L///L///T///n///L///P/ +//L///T///H///P//+////X///D///r///P///H//+////r///T///z///n///b///P///n/ +//r///3///z///n9/u7///b///b///T///H///z///X///v///b///j///P///r///P///r/ +//b///7///b///j///L///H///n///v///z///n///r///f///////v///X///v///v///b/ +//j///z///z///n///r///v///z///z///T///f///j///n///7///j///z///z///////b/ +//r///b///T///f///j///j///z///X///z///////3///z///z///z///z///3///j///3/ +//r///7///////3///v///3///v///v///z///////v///n///z///v///////v///////z/ +//r///b///7///n///3///3///v///n///z///T///v///3///z///n///b///T///b///3/ +//n///f///v///X///b///T///7///P///n///X///n///L///T///P///3///L///z///j/ +//z///T///j///X///T///b///H///T///D///b+//D9/+z//+/9/+n7/+v6/+7+/+r8/+70 +/+zx/+f9/+75/+X9/+v//+z//+rNx6uJm4KOqY+sw7C1wby9787h+ubo+eTW4uGetbyGrbF3 +np9mm6Bhn6JbmadalJ5XkJhfkppUlZpgiZlWkZpfk6FUjJFhkpdVjpJflJVbkZJaj5dWjpNV +jZVZhI5SipBUj5RQiJNYhpBUiY5OiYxSiIdNfo1MgYZSio5OiJBTjJJai5ZPipBaipFQgotV +h5FNgIpXho9NiZBWi5NXjphZio5OhY5WiJBaiY9Sgo5LgItMe4ROeIVOeYBMeIZKe4JQdIhC +cXtCbXc8bHRBZG1AYGs9YmhDZWtEa21BcHJJcXlIcXhKbm5EaW1Ga25AYWU8Rk87PT44Pjg4 +Pzw5PjkwQTZAQTs0Pjw5QTszQDY9QjszQDc8QD45Qjg+RTxZXEV4cFWFfFuPf16MfGKDbl2J +gFubhWuijGmmjmaokW+zn2zGp3nFnnbHpXXFoXXGpnPAmHK0jGq7jGi/lme/i2+shF+viWer +jGWyimacel28qmj9/+r///////////////////////////////////////////////////P4 +/+31/+vr9uP2/+r5/+36//D///31/vPk+dXo8eXf7dPp8t71/+z4//Lt//Tu++/4/+v7//f9 +//r9//z///////37//z6//H+//r7//X6//f///37//P3/+3r/+ft/+rz//H5//n0+/D9//n/ +//v///X5//nx8OFSRkZCSUA8Qzg6Qjs7Pjw8QkFEUVVff4x0jJ9nf4xHTVNDYGpXe4Nhg5GD +pquMrbKForCFnamNqrJ9mqp1iJJMVGk8UFZHUGVKYW1Uan1YdoZ3k6V/mqJ/mKeOqbGBn6+K +qq19lad1h5hlgIxjeoxnfItvlp98nqd4jKZnf5dphJRmeo5jeoxkfY5kgJFwh5pviZdzhJdf +dH1KSlU3Rj1EQUM6RkJylnXO58r0/O34/+3///T///L+//P+//T///b///j///T///L9/+// +//P///P///L8/+/7//H///P///P///v8//H///T///P///r///n///j//+////v///n///v/ +//v///z///X//+////j///f///r///X///r///r///n///b///j///j///v///r///P///v/ +//f///z///z///j//+////z///z///7///f///f///j///3///7///z///r///z///L///n/ +//////r///f///f///j///z///////P///T///j///n///3///f///3///v///v///f///T/ +//3///f///n///f///r///7///3///z///3///j///////j///////7///z///v///////v/ +//v///n///7///f///3///z///////z///7///z///////z///7///v///3///r///////r/ +//7///n///7///r///////f///////b///////v///////z///7///j///f///n///n///3/ +//n///b///n///z///r///b///3///n///7///r///j///H///j///T///r///f+//Hz/+n/ +//D9//L8/+////X///P///T+/+/9//D//+7//+///+z9//D7/+32//D5//H5/+n4/+/1/+z5 +/+71/+71/uj5/+L3/+v3/+bc3d3Dy7zA0ca3x7avybzd9+Dd+ufh99/Y7NypqLKJq7KBnqt1 +l6FnlJpikqJel5tgmJxVlZ5ZlJZXkptkjZJbk5dci5JUj5dejJpXkpxhlZhSjZpalphOjphh +jJRVi5dUj5FZjZdMipBTjJJSi41Uf4tKgYJQfX5KhIBThYlSjotYipFMi4ZWiZBXjJZXjI9Q +iYpSiIlTjI5WjpBNh41Qh41NgY1ShYlNgo9PgIxJfotIeoRFfIBKdoJLfIdMeIFHdIBIcHw8 +bnpDbXVAaHE7YnE8ZWY5Y21AamtBbHBGc3JHdHxGbHI9Zm5BZmNAZGg9RlQ3Pzo4Pzo1Pzg8 +QTY2PTg2Pzk7Ojw2PTg5QTk3OTQ+QDs+RTxBOzo2RDhfWkd0blOAcFeEe12RfmGDdV6QgGKi +imeokG+kj2uoj26xnWq7oHPHp3jFqnXNrn3KpXbHonfHm3PEm3G3km+6kmvBim2+jmqofWCe +dl2mfGG1pmH9/93+/+r4//L8//H///////////////r////9//39//b///////////X///// +//j///n////////+//r3//Tr/d/f+tbr/OP1/e/r9OP3//L1+/D8/vz////7///5/+/5//L/ +//7t/evz//n5//f19eft/O7///f1/ert+uf6//L8//n///z////9//L9//3///T+//j9//H6 +//Hr7+br599US09BRkQ3Qz9DPUA9PzxBRT9Ld3tsip9xhplebnU/SlRQX25PaXpYdYNwlqGC +oqqEpKyAoKh9mJ14n6RreIJSWmRKX2hccYJzjZaImrKAnKWLpa5yjJlui5p1jJV4jJ99l6J9 +lqpwi5tqfJFlgYxff4twj5iAnqt+laZ6jp5khJZof4xjeIple4tlhI5tgpBsh5VxhptjeotM +TV43RkFEQkM7Qz5WYlalz6jr9uD8/+v///P///T///T///D///P///f///f///f///H///b/ +//T///b///f//+7///b///b///n///L///b///X///v///f8//X///P///n///j///////r/ +//b///r///b///r///r///r///X///r///v///3///X///r///3///3///v///D///3///r/ +//7///n///f///H///j///z///7///f///D///v///r///r///z///3///n///j///z///3/ +//n///b///3///v///3///3///X///z///3///v///z///j///z///v///7///b///r///b/ +//n///3///r///v///r///3///j///v///3///////3///////z///z///3///z///////// +//3///7///v///z///f///////////7///j///7///7///7///////7///3///////////z/ +//r///////j///////v///////j///////j///v///v///////7///7///n///n///3///v/ +//n///z///z///z///f///n///b///7///n///n///v///v///n///j///T///n///T+//H0 +/Ob2//H///j///H///f///L///P///H///X///H///T9/+z1/+/5/+78/+r7/+z4/+v0/+nz +/+Tz/ubo/d3x9+Td8OLU5dnE2Mi51MCqyrnL59zX+N3e9ePd9ObY6typq7J2l52AoqmDn6d1 +mKVjkptek5xZlplfkZ5kl5tbj5hdkppWj5peiZVVkZpbi5dUipNdjphRkJRikpdUipVWjJRP +jJRgi5dVkJVWh5FShZJShYtPg4VNhItTfoZGfoBTfYlGhohYkJROjJJdjpBajpJVgpFSh45b +ho1Si4pZi5JTipFUhI5KholVhoxIgolSfolNg4pNfYVIfoZPfYdKeodJe4VGf4RKeYNBdn5F +bXtAa3VAZ3c/ZGtDYm1BZW5GaHJBa3FJc3tDbnZCZGxAZF9BY2FASVc4QD04Ozg4QTs9Ozs8 +PTY3QDczQzY5RDY+QDs6OjU+PDo6Qzc9Pj07RDleYEV4cVGBdVuHfVyKdF+FdluPf2CXgGSf +gmanjWWwlHG0nWrBmnPFoHPLq3rClnLFo2/RqHTDnHK+j2+5jWa3kGm9lG63iWaxg2arf1uY +cVywmF/6+87///v///////////////////////////3////////6/vb6/+n///v///v///// +//////33//Tv/eb6+u74//rk+tfw+eXt+ujx/Oj////5//j1//Tt/evx9O319+v4/fLt/+z9 +//r1/e/+//f7//z//ff5+vP9//3///v9//////v///X5//T///v////0+e34//H9//L0/vT/ +//72+ehcTVo1QTc+QUA6Pzc9Q0A0Qz1ggY1ulJhrhZ1PVmBASVFOXmtPZHVQZnVadHxkfIVk +f4hifoRibXpUY25RX2dRaHpkeIt+nqeDn6yNq7J/laBhe4dmc4BRZnRjf4h2kZ6Hn6x+maR3 +hplmfoxoe45igo9mgY59oaeAn6h4i59sgJFkf5BjeotlfJFhfIZmf4tmgpNrgZZleYtOTl06 +SEA/QkA3RUFATkmOrZDc89Py/+j//+3///T///D///L///D///b///P///T///H///L///f/ +//P///b5//D///L///X///f8//D///L///b///f///j///b///X///r///j///X///r///r/ +//f///n///z///z///v///7///v///z///r///f///n///v///r///z///T///z///v///// +//n///f///P///r///3///z///f///n///n///z///7///z///////z///n///7///7///n/ +//n///////n///////r///b///n///7///n///z///z///////3///7///n///////n///j/ +//j///r///z///////z///v///z///n///////////z///////////7///X///7///z///// +//n///z///3///////3///////z///7///z///////7///j///3///r///////7///z///z/ +//////v///////v///j///z///////7///7///////n///n///v///n///n///7///f///3/ +//////7///z///3///n///z///v///r///v///f///v///n///z///X///f///j///T///v/ +/+////b//+////T///H///P//+///+////H//+v+/+/2/+b4/u7s/uPw9OTh7tPR38q+4LW5 +0rGjrpW40MXX5N3G2NDDz8inyr+33cnT6eHX9ODT9OLN5NrJ5NistrqQqLOBpaR9o6Z4lZ9m +kJhZmJlhkJ1ai5RVipxclJVckJhRkpJbkpdUjJNYkpJWjZdUipRWkZdci5NakpdblJhWjphW +jJBTkZZVipRZipNVhpFMgopQf4dOgItOgIVNhYtQgYhOiZBUi5FTjI1cj5JOiI9WhY5MhYhT +fYdKgoZRhZFJg4hKgopPhYpMf4lHfohMfYhDgIlKe4lKeYJJeYVLc4FJeINLe4JGdoRJcn5E +bHs+bHk/aXI6Ymo+ZGg/am5EaHNDbHFOc3tDcndNZmw4Y1xCTFMvPzs6PzszPzU8Pzo4PTU5 +QTs3Pjk6Qzg4PjY7Pjg8Qjw6QTU5QDg+PztcWUNybFJ9cVSFeVuEcFmFdFuMd1qReluhgV+m +jmymj2O0jmy5omzKp3nDoXLInXC3lXHFmHC9kW+9i2m5h2q8jWq5hmezgGWremCofl+db12r +k2j6/sP///////7///r///r///7///z///z////9//r9//j///////r////////////7//f5 +/fD8//D////7//nk9t/j/Nbt/O7v+Orf6tn0/+/0/+/t/eb0/u36//X8//f///3////////4 +//b9//3///n8//f///7///////38//r///n9//v////3/+r3+eXw+fH+//36/ez7//bt++ns +6+BYUVY7Q0I/QTk+Qj83RkFHXWhkh5BlhpFsgopHTFRAR0xEW2JNZ21OYGxOYG9SY3BQYWpM +X21NYW5ZaHhXcoZyjJl6kqOFnaV6nKh8lZ98mJ9nboJQYXNRYm5RanJskZWFpqt6lKF1g5pt +gJNnf5Fkfoxqe5B0mZ2Gm6pxkp9+jaBpgZVrf5ZkfJJjfY5kgJFtiJFugJlkf4xTWGlAREA+ +QkJERD5AS0ddeGS32bjj8dj5/+r///L///H///D///L///j///H///X5/+7///P///T///b8 +/+/5//D///L///T9//D5/+////D///X9//H9//H9//L///T///f///j///r///3///r///v/ +//b///7///////3///3///7///z///3///f///r///b///n///P///X///n///3///v///f/ +//n//+7///z///3///v///j///f///7///v///j///z///////3///j///3///////j///r/ +//r///////r///z///T///3///z///z///3///7///z///7///v///b///z///3///f///z/ +//f///3///v///////7///////z///////z///////n///////v///////z///////z///z/ +//////7///n///////7///7///v///3///////7///////3///z///////7///////v///// +//3///////7///7///3///z///7///3///////7///7///z///////7///7///7///3///3/ +//z///j///n///r///f///7///f///n///n///z///j///v///j///v///f///r///j///r/ +//j///f///P///n///X///L8/erB4cuz17zM6si9zcC6xbm7yb/L2srN2tPc3dvZ3dvm7uHe +8uDl8t7J29C+1b2vxsG20cfS6t3b7N/c8d3T8N7P6dvE4NKemq53kZSAjJmDp6aEnrF5k59e +jJ5ZlJ1fk6JhlJ5ij59ek5taj5JWiY5akZVaipZWjZNakZdYk5ZVj5pfkZdXk55bjZZVipFa +ipNQjJJZiZlYh5NTh4hVg4lPfotKgYdUgopTiIlYipFSjoteipNRjI5WiJJUiIlWhZNQhI9S +h41QiZBYhY1WiJBSgYpOhItIfYpLgYZQgYhLgoZLeYVDd4JOdIRJeYRNdoNDdoBKcX9CcX1F +bn0/bXdEb3Y+a3BFa24/a2tMcHlHc3lQeYFEa3VCXmc/SVg3QTk3Ozw2PTY8PTQ0PTU3Pzs6 +PT88QTVBPjw5Ozk9Qjw5PTQ+QTtARDpdWkRsa0uEdVuEfVqMdGF+cFyKfFqLf2Gnk2CciWaw +kGO0lW3EpHXKqnHJrnnGoXm8m3LBl3TFoHHGpHnEoXTAkXC7jmu7imiygmOjfVujemKyj2L+ +/83///////////////////////////////////////////z///v////2//Py+en1/uv///// +///3/fLo9eDp/ebm/93t++Dt+Ovp8t78//n3//L7//f///z///Ht/uf4/ev6//f+//z///X0 +/fDs+ej1/e33+uz6/vT+//j9//f///T1/fL5//T///31//X///7////////////9//z/9+5f +UF5ESD02Qz9DPj82RENnhItjhJJugZdpfItDSks/SEZEV19SW2hEU19LVmBKXF9TWWtNX21T +ZnZahIx6kKCAl6Z1hJxxmZx1i5tegIVqd4NPYmxSXWVPXGxSY3Bgf4eEn6GAlKFziJpohpVm +hZFlg49ngI1tjJqJnqhviZt4kJ9rf5FrhpNffIxufo1ge4prgZJigItwgZJRW2xEREQ/QD89 +RUJERENQX1d/nYfG5MPv/OH0/ev7/+////P///P///T8/evx/uz4/+////L6/+z2/+j1/+b2 +/vD8/+/y/+jt++X5/+39/+34//L6/ez6/+z+//X///n///f///j///r///r///v///r///r/ +//////z///3///v///z///z///r///j///j///n///v///n///v///z///v///r///z///3/ +//T///r///r///7///z///j///3///////X///3///7///////f///7///z///7///r///r/ +//v///n///z///f///z///z///////v///3///z///////v///r///////7///v///v///z/ +//z///////7///////////////////3///r///////z///z///////7///z///v///v///7/ +//////3///7///7///////v///3///z///7///////3///////////3///3///////z///// +//7///////j///////3///z///7///n///////7///n///v///7///z///3///7///z///r/ +//b///r///v///v///T///n///f///j///b///v///v///T///j///3///7///j///r///j/ +//f///f///b///D//+39/+r9/uz5+Ofq/ujv/vDq/+34/+z0/unz//Du/+3z/+zy/+ft+u3d +7Nm70c2wzb7D1M/R5tjT9ODY6OXP8d/O6OLG5Na30c2Ol5h5mJZ9iZhrko+Ao6F7m6p2lqRe +jp9akJNempZkkZZYlplhjJRYi5dgj5FXkJdYlZ1Vk5pVkI1Xi5RXkpJXjZRZj5VajphYk5dj +jJxXjZZZh5RKhI9ShYtLfIlQeYVLeYRQgYhNiIxUiY5ZiJVXi41aio5chYtQho5RhJFPhItS +jI9VhotSh4pOiZBPfYpKfolMeoVLeoVLeYhGeX9IeoVMfYNReYNDdX5NdoFHdntLdIFGdn9H +cn8/bXJDanNAZWdCaGo8bXBGc3dMdXtKb31EYm01S1Q6Qjo3Qzs4QzY4QDc0OzU+PT45Pzk8 +Pzg1QTg8Pjk3QTk+Ozs3QDpCSz1YXkdxZ1B/c1eIdV18bVeGbVmBb1aTfl6eiGGojWq0lWzF +o23FpXzCnnDNp3fMq3/KpnnAo2zJpXDBlm26l2u9kXG8kWi3k2+3imWtfGWefVWmg2D3/br/ +//n///z///////////////////////v////+/+z+//b///////j///T///////3////9//P/ +//r///ny++3b79Hu+OTu9eDs9eLu/+z+//z////7//H+//z9//T///71/+v9//z///3+//39 +//X+//v///////n5/+z9//T9//j9//Xx/efz/fP+//T4++3+//n///z///////f09+pjUGJD +PkY7QTs+Qjw+W1ptiJdwipVlfYprfY48R0lESEM8T1BYWGBEWGRRVWVKW2hRYXFSXm5OZ3Ze +gYt8maCIoax5iJx3j5txf45baHtRYm9RVmpRW2xUX3BQaHBhgIiGnKt9kaByhZhrf5Jpg5Nn +fYtshpNtg5Z2j6B6jaBkdYxhfIdriJJrf5RgfI1kfIhlfotpg4xkf41bYXRBRkdCRUM8QzxC +Q0lNWFhriXO52rrg7d/k9971++f+/+////H///L5/e3t+ubx/er5/+v6/+32/eny/enu++X7 +/+3w+OT0/Or0/+r///X///L///T//+7///L///T///n///v///v///f///j///v///j///z/ +//r///r///r///z///3///3///n///////3///r///3///j///7///n///z///f///3///f/ +//////z///////z///////f///////3///v///3///7///b///z///r///3///v///7///z/ +//7///z///P///r///////v///7///r///3///v///////z///////3///v///z///////7/ +//7///3///7///3///v///z///3///z///////////////3///////3///z///3///7///3/ +//////n///////z///3///r///3///////////////7///////v///7///v///7///n///7/ +//////////3///v///r///z///////z///7///7///3///n///3///z///3///b///z///j/ +//z///b///j///j///v///v///n///z///f///n///X///j///j///7///f///f///b///f/ +//T///f///b///L///X9/+/4/+z6//X5/+zy/uvt/+7t/u/r/ejt/+vj+ubq/ebg8dzD1ce4 +08bI4dTP5NjX793R8d3U6ODP8NvT793K5dK4zcx4aIVMU1RUaFxljIlthIFqgIZrkJBxjJxW +k5phkp1ak5pilJpbj5hTipNUkpdWjZpXjpZViZFRjpVciZdWjZdflZlWio5YjZBSiZNWipRR +jpRWkJVVjo9XiJFSh4xUgYtMgIVNfoZXiI1MhIhVh4hYjI9ajpRfjpVbjpNViZNTho5SgIpP +gIhOgYhUgIhOfYdPfoRPe4hKfIBPe4VKfoBSeodDdnxLdYVFdn5PfYJKd4JKcoFLd4NIcXlC +b3pEbXRCZm4/ZGlBanBGcmxJdHpIcXpDbndAS1w6Pzo+QTs5Qjg9QTo1QjlAPDs3PjRBQDk3 +PjdDQj07QTZCQDs3RjZHQTpWWkdwbE9/alSAblR3a1WAc1GLelmUgWWdg1+ljmitimbBom7C +nnXBnnPDoW/KonnMpXHHmHK1lGK3jnOyh2CyiWivh2SwgmiuhluqgWejfl+ljGP5+7////// +//////////////////////////////3///f///7///v///////////////j9//38//P9/+7/ +//bx/+3w/+L///rw9+zn9d35//T0//L3//b1//f5//H+//v8//Hv/e76//r///r///7///// +//X6//L///3////7+/L7/vT9//v///////////ny8ur+//n2//H8/vL4//Pu8uRgUWpLQkY7 +QURCQ0VLfoZyg5Zqgplnf4tmfYxCRks/RUI9TEhKTVdFVVtPVmJOXWJSa3lWb4NxhpNcfZF0 +hZmAmqN4hJxicoZdaXpQYnRTW3FTWWlOW2VOY3FNYW5Tb3yClqN3jqNyg5hrgpRpgZFkg5Bt +gZNrg495iZeBnKNvdZFRbnZpgpJqh5hmfpJoeo9kfpNngZNlf5BkdIBGS1k/R0RERUZGSkxV +WltbamiOtZzT5cza6Nfk9tvz/Of6/+7///T///P//e/z++r7/e77/+7///D8//H4/fD8/+// +//P7/+z5/+v///L///r///n///z///T///r///v///r///7///n///n///7///z///////// +//3///n///z///////z///n///////7///////3///3///z///////////////z///f///// +//////////////3///7///////3///v///////////n///z///////z///r///////////3/ +//7///L///////7///3///7///7///7///////////3///////z///n///////z///////// +//////////////////////////7///////////z///////////////3///////////////3/ +//////////7///7///7///3///////////7///////////////////////7///7///3///v/ +//7///3///////v///7///r///v///z///////////3///7///////7///7///7///7///7/ +//3///z///X///v///7///n///z///j///f///n///b///n///X///j///r///r///j///n/ +//7///b///f///j+//P7/+zy/+39//H3/+7u/u3q/unk8OPV7trF4M621cu+2czM5NrR7OHU +9t7a8ubJ6tjS6+HF4tzJ6NrF6t3F4tirtLdTXV9CWlhLTFA9SkxNXlpae3VoeYldf4Bjj5da +lppglJ5fm5lki5RWjpddiplYk5VekJFdkJRVi5dXj5JajppWi5dQipNTiI5RjI9ViJBVjJBV +io5Qho9PjJJWhI9Vf4hTf4lSf41RfpBOg4hSh49RhYpciZJTio9WhZVRh4tWhYxMf4NRgIxP +hIVNf41LfItMfIhPgIdLe4hQe4RMfYZJeoNHdH5OdoRNeYJMdYVLd35EcnpNdn9Ec31Lbnw/ +aXJIZ3c/aXVEanc+am5IcHlDdXhTcIA3WW0/QEEwQDw8QDs9QD08Pjw7Pjo4PzhBQDw9RDo9 +Pzs9Qj08Pzk+RTw/QjxUU0NrZ0Z1a1h/bVWBaV6EdVaQfl+NcVqcgWCljma0lHO9mnLAoH21 +mHW6mXTBnW/BoHC9lG++lW29kWq5jm68h2u0h2axfmWlgV6kfGSbeFuui2L7/b3///////// +//////////////////////////////////////3///f///////v///j8//n3/+33/+3p9ubd +79Tj/NLs8uTf79jp9eDy/+/z/e3x/+/6//np+ebr/eLx++32/uz+//T0/+z6//fz//X3//j7 +//b3//X1//X9//7////3/+7w/uXz/+38//v/+/n9//z///v///r4/fLs8eNrUGo9QzxCRUEy +R0RlhZBoiJ1pf5JhfIpsgJRDUldEQ0c+RUdHUVxATlhGUVpGWmFSYXJLaHd6ipljg5NviZNx +jJRviplleIhSZW9KXGZMW2hIV2xPWmRPX2dSYmtVcH2HpKuCkqN4i5lnhJBrh5FhgIxufJNl +gIlyjZx1kaNsepRUZnZddoRrhY9rgpZofpBmfo5qhZRrgY5wgpBQVWVBRUFBR0BAT0hTW1tV +Zl+Eo4vF3cXl8trs9+jy9+ns/OH9/+/9/+////X4/+r8/u79/+3///T///H3/Oz9/+v///n/ +//b3/un//+////j///z///n///r///j///v///n///3///r///7///7///j///3///z///3/ +//3///3///z///r///r///3///7///////7///n///////v///7///3///z///b///7///7/ +//7///////z///7///v///7///////z///3///j///z///7///z///j///7///////////7/ +//j///v///////z///////z///z///z///3///z///7///3///f///7///r///3///3///3/ +//r///////////7///////////z///////////////3///3///3///////////n///////r/ +//////7///////3///3///n///////////////////////z///////////////r///////z/ +//3///n///7///n///////n///7///r///r///z///7///r///7///z///7///z///////X/ +//////f///3///r///j///r///r///v///7///3///b///n///v///b///v///f///b///f/ +//j///D///P///L+//Hy/+z6/+3z//Dz/ejb7tvX6tzZ7uDU59rT6N3S79rV7eDU7eDO6dzF +6NXF59nI49jI4N/D6dnJ5tfE29CMi6JjcoBJcnhPV2xASkhCSlFDR0dKUlZZeHdmiYhdlZFe +iJtajZFWkJVYh5FZkJRdjphRjpFejZVQio5bjJZcjJVVjJdYk5FQi4tajpNVipRSiZRWkZRa +iJNOiJFYiJFRiIxRhYtGg4hSfYZKeoZRhY1OhYxWiJFXiJFSho1QhpVShYlTf4ZPfIRTe4NN +f4BQhIlLfYdLfYNKfYtMe4ZIeoZGeIBFdn1Ld4RMe4NFd31EeIBIdn1HdINJc35JcH1IbHk/ +b3tCaXBCbHREZ3BBbnJFcXVFb3ZOa3o2QEk9QDsxQDY5PDoyPjk9P0A5QDs7Qjg7Qjs9Qjo9 +Qj06Pjk0QTY/QTtXVkNvZ014aVSBcViAbVh8dFaOfl2ahGOcg2Cnh2i0lmzBn3LCp3fAmnKt +jGS8kG23jmW5knC2kmvBkmq3k2y7jmquiGerhGCkfV+VclqUclihhF76/br///////z///n/ +//n///j///////z///////////v///////////////////r///n///j7//P///j////y//Ho ++9zp89/l9eHr6+Tq//H+//b7//n9//n1//b6//j///7///n2//H2//v1/e/q/On9//b1+ej1 +/fLt/e31//H5//7////9//f+//bv/eX4+/L///3///j0//L8//Px++x3WGxDP0ZEQT8/VF1k +hJRtiJpnf5VjfI9ogpFaVGBCQEQ6SEhHTVU/U1lHUmFCVmBPXXJHZ3RkeIlfeYdmb4NVb35u +f45UZnVSYGpMWmdNWGlRXGtJXm5RX2xOY3JTe4SBkKJ2jqB1hphuhJZvhZhrg5NrgZNkgYxu +hJJyi5t8i55YaHtTZHhXeoFvgZ1jeItogZZngJFshJhxiJdjbIJER0pBSUFHUk9TXVtUW192 +lX641b3l9d/w/Or6+ujq8+X6/+39//D///f//e/4/+37/+z///n///T7//L+//H///T///j/ +//P///L///j///v///3///f///n///z///3///3///3///z///3///7///3///3///v///f/ +//3///v///3///v///3///v///////7///////7///////////////3///T///////////// +//z///v///3///////3///z///////////n///////////3///r///////z///3///3///f/ +//j///z///z///////3///////z///7///3///////3///v///7///////3///z///7///7/ +//3///////3///z///////////////////////z///////////z///7///////////////// +//////7///////////z///////7///////7///////7///////////////3///7///////// +//////7///////////////7///n///3///j///////v///3///r///////n///z///n///// +//z///3///n///7///j///7///z///z///z///j///7///7///f///r///v///n///n///L/ +//n///H///X+//b8/+n9/u7l+uvr++bh/Ozk+OXW7+HY7d7O6dzP5dnK5tvK59zI6tnG4drJ +49zD5tzI49vJ6NvK6di3vcR3mKF3lZ5xiZxqh5dchZBUeIJLaXJFSlNIbV5zjJ5nhIhejpVb +kpJaj5hYjphfkZdZj5dbkZhYkZZVlZNdk5Zak5VVi5pTi5RYjZVXjZFRiZRSiI9UipJOho9P +g4xSh4tHgY5SgI1JgIlRg4tJg4pYg4tNh4tQipRTiZJWhI9OhY5Uh4xNf4dNgIZMfYhRfodO +fYNKg4VOf4REfYJQfYdNgYZNfohOeoVOfIZLe4NMe4JJeYJMeYRFc4dHcnpFcYJHcH1AcHhD +bnJAa3ZDa3RDcnxJdHlEdoVLdYE7T1U9QD05Pzo3QEA1Pjg5PT42Qjc/Qj81QDc7QDw1QTc+ +Qj06Qzs8QThQV0JpZ1B5a1l/b1h8cleAblWIe1qWf2OkimarlW+9nXC3lnC+mHe8nXS3lGy8 +lWzIonS/mXK5mW6+n3HBmXLAlnG0imupeWOjgmGacFiRcVadf13y+7L9//r///////////// +//////////////////////n///3///////////v///n///7+//n3//L+//T7//Hs/+jh/9r7 +//b2//Hw9uj////2/+vu8+nz+ufw/e38/+7y//H+//D5//f9//v///3////9//3///////// +//////v///f+//v///3///77//H+/+/z++3y7OTw+ef1/Ozz9OSDXXBDRjw/Pz1CbmplgpZm +fZJhe45hfZVnf49jYWs7Pz85RUVESlJAUldKVGNJVV5KVWtLXGdUaXhaanhVXXNRXGxXZXJK +XmlOXWhDWGFNWGVMW2dQX2tXWm1RZnJmi5B9lKV0ippug5NngZJrhJJng5Nrg5Nkg5BrgZBr +ipp+k6VkdIhNXG1QY29sg5Jmgo5sf4xjgoxsgZJvjpV4fIxCR1A/Q0NJXlBRWWBVVl9ea2Wf +tp3a7ND0/uf9/+r6/On5/en6/+v+//H///H5/ev6/+r///L//+/4/+37/+n///L///X///D/ +/+n///b///T///f///D///X///n///f///j///n///r///n///n///r///v///z///r///3/ +//r///3///v///v///z///////T///n///n///7///v///////z///n///z///////////z/ +//////////z///P//+n///H///n///X///v///v///v///b///n///r///j///n///X///7/ +//n///r///z///z///v///v///n///3///3///r///v///7///////r///7///z///////7/ +//v///3///////r///z///3///z///z///z///3///3///7///z///3///r///////////// +//v///////7///z///3///v///3///z///z///z///3///v///////r///////r///z///n/ +//z///v///7///////7///v///v///n///v///n///3///3///7///f///r///v///v///b/ +//v///P///3///j///z///j///n///L///z///f///7///7///j///v///f///j///n///b/ +//H//+////H9/+7+/vHp1NC+5svb+OTq++Lh+OPd8+TT7t3S6t7O6NrU5t/N7tnS7trS7tzU +7d/O493T69nM39mKnKl0iphxkJlxiZpyiZlslJxxj5pljJlkfI5BTlVYdW5iiJJjiYpZkJJi +j5NVjZNhjZhZkJNckJ1Uj5NVjZNdkJNbj5ZWjYpXipFXjZFRjZFWhZFSg4tSh5FSjpBWhpFO +h5BQg4pRhYdNf4tRg4lNgYpUhIhSiolZiY1RiJBXhYtRi49ShIdJf4pUgItHdYJTeoJJfIJU +f4ZKfYdMfIZKeYZMfIBMdYJKeYBLeoNGfYJJe4NHdYNNeH9SfYVNcoJHeH1Jb3pDaXZCZ3JB +a25Da3REa3RCa3JGc31GcnpAZGQ5SFI5PTs6QTg0PjY5PDg3PzQ6PjU0PzU7Pz0zQjc/Qjc8 +RTVAQzRMUTpkZE52bFV3Z1SDcFCEbFGFcVaRf12egGCujmi4nG+7lmzAnHe0kGy2iGO3k2nB +nnLAnnG8m2vAmXDBmm2+kWergWKmf2Kjd1iZc1mWclijgV7z+rX///b////////6//v///// +//////////z///b///r///z////////4//T///////77//L8//H+//Ty+ebm+ePn/9jz9+rj +7dnm9dnx//X8//X7//f///Ls9+fy/un2//P9//L8//j3/fP1//X4/+31//f9/+v1/vH9//X5 +/e/4/vj///3+///9//X4//j/+/T+/vP8//b9//3////39+mTW29BRDw+RUNRdoBmfItphZBn +g5FohJFog5JlbntBSEM4RUo/SU1BU1xKWmVKVmdMWWxKXGhMVmlKYG1SYnJKXmlQVWlHXGVP +XGVHXGBNV2dNXWJTXmlTZ29WanhvlpuAlKN0i5tvhppnhpZuiJdngJBmgJJtf41khJNxkpp7 +l6d5i5tUYXNHWWdUaHptiJNqhZFng5BogpFvjZRveIpGU1hBSUVJYFlXYGRQW1ZaYF1+moHI +3sjj9uHy/ur1/e36/+v8/+3//+76/+/1/+j5/+z7//L3/+rx+ub1/+X///H7/+39//D+//P/ +//j//+////P5/+7///f///L///X9//b///v///z///z///z///7///7///r///r///////3/ +//v///z///z///v///v///n///r///r///////////3///n///j///v///////3///z///f/ +//7//+z98s764rH/6rr/9sL//dL//+z///X///j///X///n///z///r///n///L///////r/ +//3///z///z///v///////z///////////7///j///z///3///7///////////////////3/ +//r///////3///3///7///////////////////////3///7///3///7///7///v///7///z/ +//7///3///////////7///////7///////z///3///z///7///7///////7///7///7///// +//////////7///////7///v///r///////v///3///f///z///f///v///f///r///P///r/ +//X///n///n///z///T///X///D///f///X///n///n///////f///r///j///T///b//+7/ +//T///P+/+v7/+j+/eXd5My91cOz387S8+Pj9ubl/eHo+efd9ebk8+Lh9uDj8eLd89rc+uHc +8eHd7eOxrb16jaBti5h0jppuiJp0jZd2laJujZt1kqJtjpxuhZljeotkhI1rjpRbkpVZkJZa +kpJbiY9RhodXipRYjpJXjZZRkpdii5lRiYxXh5JTio5TjJhaipBajpVYipJRjJBXjZNUjZRX +hoxPhY1Ug4xRiIdMgYtRiIZPgY5QhYxWi49Rh49XjZBXhYpNfYZQfIVEfIRVfYVFgIFUeohI +f4VSeYNBe4RQeYFGdYFKdoBQfINKeYBNd4FHf35LeYRQeYFJen9GdXxNcXpEbHxDbHZCanVD +bW9CaXZFcXNGcH1BdXhBZnA/WGA/P0I7PzM9PTw4QDc4Qj48PjM7Qjs7PDo9Qzs9Pjg+Qj9C +PD5HTj1nYklzalJ7aFaFdlWKdFiOfVmgiGerk2iqi2iymGm+nXe4nHHAoHWyiWvCoW++nnLA +lnDClmzHmHK7jXC+lnKtg2ivgmChclqbeFuPcVikgl74/b3///////////////////n///j/ +//////j///v///z///f////4/+3///////3v+en8//L///////z///n0/+zb8dPc6Nbz/uP3 +/PP8//X3//Dt/PL7//T+//3///H7/+31/uX4/fr6+err7+T7/vX9//7///f6//P9//b+//z/ +//f+//f///37//f///n///7///3////1++34/vHt9Oe0YXNBPjw+UVNgfIhnfZJkgZNpgY5n +hZBmfZNqeYxDP0c7RUNHSk9GUFtIVmZNXm5JVmtGXGlNWGBMWGZRW2dHWmVLUWlFVmJLVF9J +WF9SWGNOXmlRX2tOY25VaXZqj5Z1j6J0iZlxhphmhZBpg5FmgI1ofIhmgYhvh5BtipeAmqJ8 +nKhobotKW3BFW2tohYZviZtvh5ltiJRvkJxtcIZGUFdBSElmdnJfZGtQXVdYYF5ngWm+1Ljf +8dzf7eDo+N71/ur1/+n2/enr9OHr+OX4/+3y9ujh7djj6tfu/eXx/efo9uPn9+D2/+j///Hz +/en1/uTz/eb8/+z///L///b//+7///b///f///3///f///3///7///3///v///3///7///z/ +//r///z///n///r///z///r///z///v///v///7///v///n///z///z///7///r///b///X0 +68b/8dH/57j/6rn/57L74rL88Lz/9sn//Mv//9v//+n///H///f///T///D///n///v///3/ +//n///v///r///3///f///7///r///z///n///////////z///////////3///////7///v/ +//r///v///////7///////7///////3///////7///////7///7///7///////////z///3/ +//r///3///z///7///v///////////7///z///7///////7///7///z///7///v///////z/ +//////z///////z///////n///z///3///r///n///z///3///v///3///n///n///7///r/ +//3///n///j///j///T///H///j///T///f///b///n///b///z///L///r///b///j///P/ +//f9/+j///P+/vH07dng7dm1wbWzxcO32sHN8NTh9t3g997c9eXb9drV7+Da9trZ+eXf7N7C +zdCAnqWDkZ9zkJZ0h5pxipByjJp2k6F0kqJxjpx5kaByjJqAlqF3laJgkpdekJZVkZdXkZpX +iI5fjZpSi5ZZkpdYjZJUi5RdjpRTjpNVjJNUkY1XjpNWjZJYjpRSjYpZjZZPiJFWipFUhYlQ +h5BKfIVSgIRKgYBRgINOfolSg4pQgYtQi5BVho9ShotNgopRfYZTeoVPfoJHeoFMeIdIe4VQ +fYdHfYNNeodDfIFPfYdBc4BNdoBDdoFQcoFJe35LfIRJeH5KdXtFc3lEcntDcn1Cb3REcXU/ +a29Db3dEcnlFcnxCamlDaG45RFM4Pzo2PTo4PTc7Qz40PjRAPzs6Qy5CQTw4QDA5Qjw7QDVH +TD1iX0dycVd9bFSHe1iPemCShmKjimiij2amjGepkGyyjG+zkWy9mXK6kWu6lmq7nG/Dlmu/ +mHK9lnG9kWyyhGeofF6sg2Gog16jgV2Yc1WWfVju9Kn+//r///7///////r///////7///n/ +//////////r///////z///b2/u75+ej+/+33/O/q/eX0/ej2//Hv/urq+trw9+Xo+ePp+dzv +/uj+//z7//H///n5//b5//T+//z///////f///3////2/+30/+z6//v////7//L8//T8/+31 +/fT9//j///3///n9/PX6//P///7///////n9/vnEZX5ERUBRcnBmhpVmhJRkgZVnf5FoepRn +fYxqeotEQ0hAQ0RDSUtDUFxKVV9EXm1SZGxEXGdPWWdBWGhRW2tFVGZSWWhFUmNNUVxFVGBN +VWJLXWtQYWxWZHBUcYGAlaF1jZR7jJ1whphvhppqhpRrgJBlfpBmgo5uhZZ1iZd6laeBnqx6 +hp5QX3NOWGhSZHFwjJlyiZtvh5l3jppzd5JTW2JDU1mVo595fYZdYmVSYVxiaGCNrJXQ3s3b +59Td59fk89vu++n4/fL4++ns893x+ef7/ur1+ejj69/x++T6/+v09ujk8Nzs+uP8/+z///X/ +//P5/+33/er///P///f///f///P///r///r///n///v///////r///v///r///3///r///z/ +//3///3///////r///7///v///7///////////////T///z///////z///r///799Ozz3q// +/tj/99X/8tD/5sf327L64rX24rXtyJ3u15766Lj18b3+/tL//97//+b///L///r///f///r/ +//z///v///z///j///n///7///n///j///n///////7///////r///////n///////z///3/ +//v///////r///////3///////////n///3///7///r///z///////7///////z///z///7/ +//////////z///7///////3///3///7///z///3///////r///7///////r///7///////v/ +//////7///////f///////z///////n///n///7///z///z///z///3///z///7///b///7/ +//r///7///H///z///v///v///j//+////H///v///7///X///r///T///j///T///n//+3/ +//L///H///b9/+f8/ujcysadtp+62b+20b3A0sG928TI3NG73crF28K51MGar5xzjIeCmqB6 +maF8lpp9j5x6kJp6iZp2maN0lqN2lqSBlqVxhJGApKVykJVmi5VZkplglptblJdZh5xSjZNb +iJdUjZRaj5NRipdYjI1YjJBYjpFUipRZjpRZjJdakZpUi5RZjZVUkJpYiI9NiItShZBLg45P +gY1MgYpSfY5Hf4dNf4hLg4dPgYhWhI1TipJXiZZNgYtXf4hFd4NEcn1JeXxKdXtLeoJKfYdO +e4dJe4hQfYZMe4NPdYNJd4BMdoJCdH9Xd4VHcHtOeH9BcnpLcXpEcHVHcX9GcXVGb3pEa3BE +bnZHbndHdn1CbnFGaXZBVGY4QD88Pjo4Pjs6PDg7QDc6QThBPj04QzZAQTk7RDZCQDw8SDhf +XEhwZE55bFJ+d1mNe2KMel+bgGWihmeoimauk2q0jWuvhGaqjmG6kGjDpXO2kG3CqHDEom+y +iWiyimerhmOykWC3hm6bc1eQbFeLbU6ngl/0+rT///////////////////////////////// +///9/vj8//P///v///////////////////3///36//vp8ubf99vr/+D8//vy+ufy8uz1//b0 +//D0++f1//P1+fPy/ev1/+78//Lz//L1+eXx/vT//fv5/Pb///79//n5//Lx+vL9//f///77 +//P2/e39//v/9/f///f0/+75//X///n9/+vLYnU7RT5deIduiZJugJZlhZJngZZmhpNngJdp +g5lOSFg8QT9ERkk/UV9KUWFJXW1OW2lLWWhRVmhEVGRLVWdGVWFTW2dKV2BKTF5CVF5OVmdH +V2NWXWxPa3RogZeBnaV5i6RyhZZyi5log5JqhJhngZZpgZVrhJJrhJBskZR7lKGBnaV+l6Vn +bIBMXG5MWGtffohpjpp0ipxylpl8e5ZOXmpFUVqftqKXmKNnbW5gZWJXZV17mYS/1rnV38/V +5tXk6tnl9Nv2/+v3/evn9970/Ob///L9/+zx+ufr+OH5/+z5/+z49+ru9eP6/+7///T///X9 +/+/7/+3+//H///j///b///b///f///n///X///n///3///z///v///z///7///7///////3/ +//7///7///v///z///z///3///////////7///n///z///////r///////r+8vTpy6D88rb/ +/cz//+H/9Nf958P95srw2K/sxZHw0Zn22qvw1qDx1qD55K388Lz//Mn//+T//+v///P///n/ +//j///v///T///n///n///n///j///n///n///n///v///r///////z///z///7///7///f/ +//v///3///////z///////z///7///v///v///z///z///3///7///7///////////3///3/ +//v///z///z///////////3///7///3///7///7///////z///////z///////7///////n/ +//////z///v///z///r///z///3///z///3///z///////v///7///r///z///n///r///z/ +//////r///v///X///7///j///j///T///7///f///z///f///3///T///n///H///b///X/ +//L+//P+//D//+/x59a7nZOWt5iuzbirzbenx66lv6yNsZdpi3FTWUxMUFNki4uBlqNzmZ+C +jqB3k5x/kqR2l6F3kqJxmKF6kqN7mqJgipl+mqRTd3hWkJlbkphXj5lXjZhXkJpcjplYjJlg +kJdUipVSjZ1WkJhbj5lRj5VYkp5OiJJejJpTj5FdkJJTjZZVhpVVi41Wi5JViZRRiY9Xh41P +hodRholTiIlSh41Rho9Ng4xVhIlUgo1RioxNhI5ThYRGeIRMdYJBe4JOeoZFfoFTe4hCdIJP +eIBDe35SeYJJfIVQeX9LeYJGe4BPd4JEeX9FdIFBc31Ed3tGcX9GcntFc3hJcHc9dHhEbHZC +b3hIbnZKdG9Kb3tCYW46QUI8Pz09Pzg4Pz09PjU5QD47QjU+QUE/QDw6QkA5Qjw/SDleWURn +aEx1b1N5blWKd1uPfF2UfmWTfl+hiWawm3G3knC4lW21mHG8mHK8k263k2q3jmm3jGiyhWWr +hmKsg2OsgmWlgmOWclaQcFGVb1Oaelvw/bf///b///f///////////////////////z///// +//j////9//n///z///z////9//T9//L6//D5/+/6/u7v/+vf/Nrj8tfn99/u+Ojx/uj4//z/ +//n7/e3w/en1/u75//z///P9//7///////v///77//H6//j9//3///////v+//r7//j5//X3 +//P0/+3n8t/7//b///j+/ff7/uzz+ejKcXU/S0dheYBlhJBkf5ZogpVmh5VxhJJjgJJng5NY +VWE9Qjs5R0U8U1VDVFpKVGJKVWhLVWdBWGZKUmVJU19KUWJEUFxLVmpFU1lJWWNFV2NPWGtO +X2pUa3Zmj5WCmqRyiJpqiplrgZZpg5Fqfo5rfpJogZBqhpNuiZdtiJp2kp9/mqWCm6hpdY1M +XnFQWm1LZ3N2iZpxjJt8kJ15kJtYYXFDYmWtxreosLd1fINnamhcYlVqemqlv6fV6s/j8Nzm +7djd7NTz/OL4/+vz9eXi9dv7/+z///H5/e7z+uft/OD9//L///L5/fD0/Or///b///L///b/ +/+v///L///v///n///3///j///n///P///j///r///j///j///3///n///7///z///7///3/ +//7///////v///////////z///7///////n///3///////7///v///j//fXnx7P02Kj947D/ +47j/88X/787/8M730Kf10aH62Jv62qb72aH206T515733q7/5LD98LP/9ML//9j//+b///T/ +//T///P///T///P///f///D///j///L///r///f///b//+////f///X///L///n///X///f/ +//j///v///n///b///X///n///r///r///////z///3///z///r///n///7///z///7///j/ +//7///r///////r///7///f///////n///////f///z///j///r///v///////7///////n/ +//n///v///z///v///3///7///v///z///3///n///7///z///z///r///r///r///3///// +//7///v///j///n///r///n///b///v///L///3///v///j///b///P///P///f///X///b/ +//b///L///b5/9/dkqZvblCCg2+LoX2NfXJzX1lOTU5DRkFIUktad2+CoJ6GnaWAl6R2k6R8 +mZ96kqF9l6J8lKZ1l6CBmq92f5pslJtyfYlPjJZgkZpYjpBdkZ1WkJdejpxWjppfk5tVjJZb +kJJUjZdai5ZYio1WiotTiI9ZjI5SkZdPjZFZjpdTkpVZiJBWipFXipNSio1eiJZOhI1VgIpR +gopPf4pNgYpSf45Kf4dPhYpMhYhRg4pRiI1PgYlLfotNdYZFfIhOc35FeX9Ld4JGeH5OfIRG +eIBNeYBHeoJMdYFJe35MeX5RenhKc4JEdH5JdH5JdXpIc3xDcX1Nc39Gc3xHcX5EbnZKa3pF +cnZHbXBPcYFCYGs9RVE5PDc4Pjc9QT06QTU7RDk0PjU/Pj46QTY6Pjw8QzhBRj5WVEJqYU5u +bk+FdFeIfVqXhWWVgWCkiWSefWKsjmKzlm+4lW7AnnrFnHTDonm+n3DEpnPBnHPBoHDBk3G2 +iWatfmCielegb1mbe1iUZFeaeFLl86j+//P///////f///X///z////////////7//L+//j/ +///////////////9//76/+3+//j+//v1/Or0/+3s+uTi9tfz++b4//D4/PD5//D2/+f3/+/t +/+j6//z///////f8//X6//n7++bq++n7//X8//r7++n7//b///v///X///D6//r///n///j+ +//n7+/T///v9//f6//D9//j///bidYRAS0lsipNmgI5siJVliJR0jJ5qiJJnhpFmg5NoaXQ3 +Qj86QUBDUVVJTl5JUmFKU2FJVGRFUl5FWWVPVl9FT2BHUVxJVl1NWGNKXmFNXGpIXGRRWm5M +b3RylaKBnaaBlKdxi5pqhZhshY9rgZFhf4xnfo5lfpFxiZdxiZV1k5p9maGBnKJjdYVTZXRM +XGdLXGNlgYVzi5hwipl8l6BaYnROamW50bm5vbqCkZCHhoFjaVtha2GGoIrP3sXn9dvx9+bm +6Nrc8dXz/eX8/e7p8OP0/uT7/+/8//H//e/y++P7/+7///P///D3/Or+/+3///P//+7///H/ +/+v///T///b///r///b///j///P///j///j///f///f///f///z///n///3///////3///n/ +//r///v///n///v///////7///////f///3///z///3///r///j///nz2NDjxJvy06b+57z/ +4rT847j52q/82a/93Kz73qT82qT526H83af94qz+26v+36/+57L/7bj/873/+cn//ND//+D/ +/+H//+r//+r//+///+n//+/9/+X//+T//+j//+z///H///T///X//+////L///D///P///X/ +//r///j///j///b///X///P///j///n///v///T///b///j///n///v///r///7///j///z/ +//n///////v///r///3///b///z///f///3///f///z///f///7///3///z///T///X///P/ +//P///r///j///r///3///r///v///L///H///j///7///z///7///r///7///7///z///b/ +//n///H///n///f///j///j///v///f///n///f///b///T///b//+z///T//+j///P///D/ +/+7//+///d61b2dyWE9tW0huWExpW0h2WlBMT0BGQUFIa16JqaOHpq2Boad9oaF8mKJ6mZ9/ +nqSDrKiJpq92pad9j59xlJiEmJ9mkptYjZhai5hVjpVakpJfkJFYkpZajpBYjY1Si5NcjpVX +kI9Zio5Yi5JSkI9ciZRRg41ZjpZVio1hjpVWjpNWiJdVkJNTjZVaiI1ZipVRjI9QhY5QgYdQ +gYZShYhMfYhRiYhRhpBSf4tNgIlWgYhRgIVPfoVMeIBPe4BQd3xHd3pQeoZDeIBQd4JEeX9P +d4JDd35PdX9Ad4BTdnpFdHlQdHtFen9Id39KdX1JeH9LdoNMc3tKeH1Gd3xHbXtAcndHcHlC +bmxLbnlEaW5AUFw7Pjs5PTo5Pz46Qy86Pjw5QzY+Rj03PjI9Pzw8QDU/SD1WVD9lYElzak59 +blCJd1mIe1eYe1+Yg2Kgf1+ZgVqsj2O6nXHGqXLLqn3GqXbDnnqvimTGqnHHnna6mHOsg2Kq +hGahdVmngVabeF+WcFWbgVDo8q////////////////////////j///z///7///////////f/ +///9//f9//P///n///n///31/+77/+r///34//Ds/9z6/e7z9+3l6Nb5//L7//P1//n///76 +/+/z9+fw/Oz8/+bv/e37//T9//7///Hy//X8//f9//v///z///v7//T+//n7//H+//n9//7/ +//X8//j///7///f3+e7o793Od3o/VEpcfohcfYtnf5VlhZZpiphmgpVqhZVtg5tyhZFARkpA +REU/UlhIU2BJXGZKXWpJWGpOVmZLW2NKU2RDWWFIUmZEU19SWmlFW2ZKWmxOWGpSYG9Mb3R3 +nZ99laSBlKd2jqF2i5lpiJRsh5NqhZVkgJJrhI1oipt3ipp0jZh3l56Eo6pkc4dSZHNNWWdI +VGZNaW9yiplzjKCFm6lpcolVdXDD4MrEycaKnZqYrJ5/eXpmamFpfm+szKvd7dbo+uLq9uTk +8dzz/+f6/+jt8eLh9t/3/+z4/+zy/O3t+eT5/+3///j9//L6/er9/+////T///T9//H8//D/ +//f///f///X///T///v//+////n///j///j///n///v///z///n///v///n///r///z///n/ +//v///f///////z///7///////j///n///3///////3///b///7/9O/gwbLhvo/y06b65bb8 +7b3+58D/6bT/57X54LP516v326D+5LT/5rn75LX/5rb/7r7/8rz/77r/9cn/9r/988j99cT9 ++cf08bvv7rbw/ND9/9b//+X//+z//+7//+z///v///b///v///v///////v///////3///// +//3///7///////3///////7///////3///3///v///3///v///7///z///////v///z///3/ +//7///r///r///////3///7///7///////7///////z///////3///////z///3///r///v/ +//b///z///b///b///f///r///j///n///j///////7///7///v///////////7///f///v/ +//j///b///X///T///X///z///T///z///j///z///P///b///T//+/9+tzy/+P9/+7//+j/ +/+v799y2jXSpcl+aa0ylc1iifVijemGKX1BIVF9SfG6RqrCFpKyFoap5nqWCna6KsbGjwsOM +pLF9nah7naGDnaCCnapljpVgj5xdkp5akZ1YlZpaj5hWjpJWj5VWkJdWi5VZj5RSjY9ak5dZ +kpFhkplTjZJfjppRjJJajpRVjY1ajZhSi5BUjZZSiI5SjJRajZRVi49Rh5BMi5BLgohNg4xQ +foZOf4NOgY5SiY1ShpJRhpFPhpBUgYtJgYdMeIJCdHxOdoRBc31Ld4Q/en5QdoJHeoBMdIJE +eINOfYVFd35JeX9Kf4JIe3xJdoFLeoROe4RFeYBPeX1Fdn1Ldn1Hcn1JdIRFdn9FdYFDb29G +dYBFZXE/VmE3QT82QDs7REQ7Qzc4PT47Qzg5QD86QTk5Qj48RDY/RDtTTz5gXU9qYk5yak6B +c1OPfF+af2abiGWmgWWtiming2K0lGnCpnjNrIDKpH2/qHfCkHCwiWi5j2q3imutiGWwiGeg +d1uYeFqifV6aeFmZgFXl+a7///7///n///3///////////////////z///////3///////z/ +//z///////v///39//b5/+7+//X7//fr+uXb+9Pn+9jk9dr1/+75//T9//f1/eTz/+76+ej0 +/e/+//34/+////z3//j9//bx+ev+/vz////5//T9//r///7///f5//b+//7///v0/+/z//X+ +//z7//Dx7+jr9ur9//zuh5VET1BefoJpepBphZVxi5pmhpVqg5FkhpRvh5NshppKTlAzPj47 +R09BWGFKV2ZEWGZOV2FDWFxNWGdFUmJKVmBFVGNKWWVMYGVOV2tMWWpOXGlKY2xke412m6aH +n6x4mqZ+kp53hplqi5ZrgpJqfpFlgJJug5NrjZd5jp1zi516l6aKrLB2epNPYm9MWHFKVWZP +V2pfgIF4i5p4lJ5+gpNbh3bF3s/Gzs6Qmp6wuqmglaJ0cGxvcmOUspLR4sfV49Db69Ph9drv +++Tq9+Hg7dzk8d3u/Obs/ePl8t/m9dr7/+zy/+vx/Obu/uP8/+/2/+79/+3v/eb4/+79/+z/ +/+/8/+7///D///T///D///D///H///H///X///P9//X///D//+////j///b///P///f///j/ +//r///f///////r///////D///3///T///////z///z///7///b34uTYs6Phu5PozZz13K34 +4bL96Lv+5br72q7716f646v/6b795bn/7bf/8cD/9ML/8sX/8b3/7r7/8rv/9L3/9cT/8Mn/ +5rv22a3046r7+s///+D//+z///P///n///b///n///7///7///7///n///3///7///////// +//3///z///3///r///////r///7///////////3///3///7///z///z///v///////r///3/ +//7///////////////////////7///////3///////7///////z///v///7///z///z///n/ +//v///n///b///z///v///v///n///v///X///n///v///3///f///7///b///n///v///7/ +//H///v///P///j///X///n///j///v///v///n///T///j///D9/OX5/uX79uHi+dTx69zk +0rm6lXK2nGi+mGq/qHC9n3i3mXCmempPZ11khoGCr6icr7SOs7GbsbWVsLWUsbeFsq+Hp7F3 +mqtzmZ2BnKVxkJ1blpVhk5pYlJxXjJxUlJtXjppVjI9ZjpVXipJXiJROjJZajpRVkI9Zi5FW +kY1Vi5NTj4xWi5RUh5BViZNSjZZPiJFUi4tSjZRVkJdXkJJUh5FMh41RiZBUh5BUf4pRg4ZL +fIlJfoNPhIRRg4hKgodWg4hJfIFRfoNDd4JPeoNFd3xNc3xBc35Ne39JdX5IfH5Mc35Men9J +coBHd39Ec4NLe35IeH9GeoRQeYJMfH1LdH5EbntEdHlIcYBNcIFLcoRKdXxKdH5HcGpJcHxC +ZWpCUGA2Pzk1Pzg6PzY6PzQ9PTM7QzlBQDs0QDU7Qzs4PjdBPzlGUTxnXUdsZkx5a1N/b1SR +fFqai2mZfWqmjGStjmyxkmi5kWq+n3DFqXrCl3K9onK8lnG4k2q8ona7m3KshWSthWGphF+n +gl6aeFuLZ1uNcU7U5aD+//P///7///3///j///T///////////r///////L///z///////z/ +//////37//T9//b6/+39//v6//bw/+3q+97t9ef7/vLo8OL3//L8//z///v9//r+//z///H1 +/+zy+eTw/Ov6//n///z///77//P9//z////7//P7//z///nz//H5//D8//P5//H9/fT4//D+ +//v///7////u9urdjptFUkxif4tphZRyjp1vhJdtf5JsgZBjhpNwiZ1ohpVOVVw6SD4/RkxJ +UldEWVpOXF5EVVtHVVpHWmFPV2JDWmJPWmRJWWRVXm5FWGRSYG9TbHFic4R1lJd+mqGDpqh/ +oKl8lKN2jJ1yhplvipdwh5hngZVqhpFng5N2kJ58k6J5l6GLqa6Cl6FYZHRPYmxPXG1HWWFS +anVljpF+lqN0gY5vkH/G4s/N1cuOoZ62ybTAxMCQiYR0bWZ4hXOmxqXD2cPG18LP48Xj7tXR +2sjM2MLN4svk8NrU4tDR4MnS49Ho99rg69bZ69He8Nrx+eDr9+Xj7dnh8Nvs+tvv/+L3/+X0 +/+r1/eT3/+j5/+b//+r///D//+7//+7//+n+/+3//+v//+z4/+f9/+j//+j9/+j8/+n8/+r/ +//T///T///j///j///L///j///T///T///n///j///j///v///H03tvcwZfduJHhw5Hw1aT0 +26b826r12qr92aX75qn+5bH97LP967b/8bb/9sD/88b/8rr/9cT/9r7/9MP/9bv/9cD/88H/ +7cH/8LT/77v/7bv/+MX//9r//+j///X///P///f///j///3///z///////r///////v///3/ +//////////z///z///z///z///n///3///7///z///////////////7///////3///////// +//3///7///z///7///z///////7///////3///////r///7///z///////3///////7///n/ +//7///z///////n///z///7///j///v///z///3///P///7///j///z///v///r///T///7/ +//T///P+/+r8/+r///H///X///j///b///j///D///n///D///T+/uvp587b2sTLxay+pXzD +om/DoW+6lmu8omy1oG29mXOtiHFbWmBggnyVtbugubexysehvLias72Jq62Lp66Cpa54j6h7 +kZt1lpVajpFclZllkZxcj5dekZlfl5JbjpNakZNajpdakZFXjpVVipFTj5VYjpJXjY9jkZJN +jphci45Ui45UioxNhYdViYlWkJNYjYtSiJZVi5BXjY9UiZNYiJNRiZBUiZJPhZFTg5BLfYZK +fopKfoVNfYZLfoZRgX1OfoJQfoRNfYhJeIBJeoZHc3ZGeYFLen5Gd4FMeHtHeYJKdXtHeYFG +eYJIeIJReXxHeoBNe4BOe3pOeX9Gd31KdntIc3pHdHxNeoBLdX5FdHxLcYBCa2xDb3dAY2c8 +R0s4QTU4PTU8QDg1Pzw+Qzc7QTs6QDk4PzU4QTY9Qzs6RDRPSD1fX0JyZUp2bEuGblqKfVKc +gWOahF6uk2WukWivimisk2PBmXC9lG3HnnW7jmuzjGbAmm+1jGitjGebdFyefFioiV+ufF2M +aVSGaUied1Hl6q////z///b///////b///////////////////////7///////r///z+//r+ +/+////r///z///T2/+7p+N/W7tPb8cb7//rx+ujj8Nj7+fLy++n9//r09+nz/u/+//D1+/L8 +/u////z///v0/+v6//z5//n9//Hz/eX4/PL2/+z6//b5//b7//3///v///77//Pz//T8/+/9 +//b///f///zrp7ZATUpifYhlgZh7jaBnhJVlh5Vtf5RnhZNwgplpiZRlYnE/Qzw6Rk07TVBP +Vl9FVWNJTWJFUWJJUGNOU2JPVmRIWGNSWWlOXGdQX2pTX3BjeoNngpCGnamQrrmAoauJprF/ +m6Z0kaB3iJZxiJVrhJRhgJNrh5VqgZN2jp57laKKoK2MrLOLobBdZ3pRW29FYWxOVGdHXWhm +gIlzlqF3gpRzmIjQ4NTJ082Pnai+4cfZ5tqzsLJ4c3N0dmiGnoa30LnL0MTF07/K4MXa5dLZ +3tPE1cXZ58/h6tni5tbZ59HZ4c7n9tnu8N3b7tnn79Po+d3r8+Xt9uHt9eHp99/1/+L9/+/7 +/+79//D1+eT5/+b+/+n9/+z5/+f6/+b9/+f//+n///P//+7//+3//+j///T///L///j///D/ +//P///D///b//+7///T//+3///P///P///H///X///j///L///P449rewqnavZLexJLp05vy +1aPx2Kn40aT22qT94K7/5a7+7bX+7rj/9cD/88D/8ML/8r7/88H/9cX/+cL/88T/8sf/9b7/ +9sX/8Lz/98f/9sn/9s3+68b+/9D///H///P///H///3///n///v///j///////r///7///z/ +//7///3///z///3///n///////3///////r///////7///////3///////////////////// +//7///////3///z///7///z///7///z///7///f///////z///7///z///7///7///7///7/ +//3///////////////z///7///z///7///v///////////////f///r///v///r///T///n/ +//L//+7//+r///T///X///X///b///n//+////T///H///P9/uP9/ufy4cq5rIq+pXTIonm9 +onW/pHi9l2m+onK9lmunjm9cYVZbgXqPr66Ztbeew8Kgur6ZtLqLp6t6maV+lKB8oKt9oa1n +kJpml5pblpZhkpdalplhlqFZjpNYjZ9VjZVXipNPjZJVkJlVkJVYjJRQj5BYi5RRjY9YiY5V +io1Pholai5NOhYlOiY9Si45WjpFYj5RNjJNajphXipZWiZZSiY5RiJNRiItYhIpNgohQf4tK +foVQfotLfodOfIhEf35TgYtJeIFNfohMe4NGcoBLeX5FdYBMen9BdX9Od35JeYJLfYZIeIFK +doFNeIBJc3xIcHpFeHxLdH9HeH5MeYBDeHtQcn1Edn1Md4JBd4FNeoBAb2tQZnNBTVk+QkA4 +PDc2PTY4RDo5Pzc4QDo8QzlAPjo4Ojo/PTY/Qzk+QzVJST1iWEdtZE90a09+bFKHdFWWfmCc +gWOliWaujmatjWqtj127nHLKpm7AmXqpfGutj1zAo3O+nXO3kG6rhGaof2Oad1ubeVuLYlOJ +ak2beVfa5Zn9//T///n///////////////z////////5//b9//H8//b9/+3///b7//X+//L/ +//////z///v////7//vt/+vq/9ro/OPk6t7j8tj2/+70/fXx/O/0//X+/vv////7//f7//H9 +//v9//f+//35/fLu/fH7/vz///////////39//j5//z///////v///j+/vn///////39//7y +/e39/+7crbRKTE5efopykaRvh5pmh5plfpRsf5NqhZpyiphwi59wgIg9Q0k+SEc+TFBGUldC +TlJKTlxIV15NW2dFWGNMV2dFXGNPW25LWmVRYnJRa3Vle4xrg5mDqbGSq7aEoqyGoK99naWB +kZpzip10h5dpgZJshZFrh5FsgJN3kJ99mqqKo62ApamJoq1caH1SX29GX3FOXG5AUmNXdXht +iplzdYx4oY3K4dPG0cyOmqLA1sPg6tfW0s+Xj4p2dWlzfm+rxqbW6tHg59nJ1sPd6s3f6Nnc +39DQ587o9djv9ujv9N7h5Nre8NT1/uf1/Oby8ePr+dr9/+/+/+z//+/2/Ofy++X+/+j//+7/ +//X9/ur//+n5/+f//+3//+7///H///L///f///z///3///3///3///z///z///v///r///z/ +//X///7///X///f///r///j///j///X///b///r///z///f///f69ePo0cPavZfZv47fw5Hl +z5rs1Z/43KL44bD94rT/4bT/7rb/8MP/8ML/7sP/77f/8sb/77//9b7/9sT/9sL/+cn/98T/ +9Mb/+cT/+8T//cX/9cr97L3+6rr8/cD//+P///H///b///r///3///z///3///z///7///// +//7///r///v///z///////////3///n///////////////7///////////////z///////7/ +//////z///////v///////////////r///////7///z///////7///////////////////7/ +//7///z///7///3///v///v///7///v///7///v///7///f///7///r///j///j///n///T/ +//D//+3///P///H///b///L///T//+j///f+/+/5/+v7/ub4/d/NtJ6+nHXFpnLDn2vBpW3I +mXS8mGi9nXG/oGS2kXZzYV1Tg3mYt62XtsCVtrWNs7d/iZmEnqh6l6SCpaKNpLBvkpthjZZW +lJdakaBgkpNdlpthlJlVk5pikZRZkpRckJVQkpFajZZWjZdgj5BUjJJZiJRYi5FZk5ZRjJRS +iJFQhotLgItSg4lUh5FViZFRiJJUjJNSkJRajpZRipBUio1UipJYiJBRhYxSgYpRgIdPgohP +gIVPeoRPhYtNf4lKfodPfIZGgYpLdn1FeoJJen5JfIJMd39Lf4BNgIhLgIFQeoNGd3pVeIRF +dXxKcIBFdXpQfIVHen1Jc35Jc3tMdH5IcXxKcH1JcX1LdH5HdHlGZ2lGVFs5PkQ9QDw5Pjs4 +QDY6QDw5RDlAPT05QDRDPj04PzJAPj85QDs+RD5ETD1lWEprZkxtYkqAd1OReF6OdV+afmGv +kmiwiXKxiWaihWOzlmu/lG+5k2qxg2GtiGO0lGyxjmmvg2ewhWGtgmajfFufelmQcVSSbVSU +dlXb4Z3+//T///////////////////////3///3///b///////////////////////38//L2 +/fHt/+f6/+/5//T3//Pt++Xq8uXm89/s/eX+//zm/eTz+u31//X9//fx//T9//7///v+++3y +//D+//j1//r////9//H3//Py/+30//v////7/+/1/e7z/fH8//31/fL0++z7/+30//H///b1 +/+3mxNBGS0ZhgYhviZlxiJ5mhZdpiJpqhJd0ip1shZl0j6J3kJ1MS1o8Rj4/Skg9R0tCSEpI +R1E+U1lJWmdNWmJQWGVNWGpKYnFTYG5SZHJUcX9piY9tiZttiJmIpq1/oLCGoa2Co6eGmKB2 +j6B6iJhphJhwhJRyhZhkhJBsjJSCnqWDoqp9nKp7lqJdcYdSYmxPaHFMWm5GUmVNXG5mhI9s +eYiYxa7Q4tfK1dGWr6nG28jk8tzh7N7GvbiAf3xwc2aDl4DL37zg89ns7d7Q4M/p893r8+Tb +4NTe9djz/Or0++rw9ePX6NDq+eH+//D9/fDq8eH1/+T9//P///P5//H2/eb1/OT6/+f//+r4 +/uz///H///X///T///z///X///f///T///z///v///3///v///z///z///////////7///z/ +//v///X///z///7///7///////3///3///3///3///n///z///v//+/++Onp2M/cwqrTuI3b +wZLqzZ/tzJr226X53a/33av757L65q/967j/88L/8cL/9bn/88b/9cb/9sL/9cP/9MP/9L3/ +/Mr//s3/+NH/+8n/+cb/7sX/5Lj52Kzt6LH6/sv///L///b///z///b///7///f///3///r/ +//3///v///7///7///////z///7///v///////7///z///////7///z///3///3///////z/ +//////7///7///////7///////////v///////////7///////////n///////v///7///7/ +//////////7///3///n///////v///z///z///////7///v///7///z///v///r///j//+j/ +//L//+z///X///L///b///f9/+j//+v9/uX1/d3s7tLbrJm/o3TKp3TMp2vGrHe8l228nnS8 +nGW8nXbBlm63k3CFZ2dUe3iXsLGSsraarLuKoq19pKF8oKqAoqmDrLN+jZpak5pej5hZkJpZ +kZhdkphbkphYkJVXjphWjZJXjJRZjZNWiZJfipdTkJhfjpZWkZNalJpWkJpXjJVYj5BYiJBW +h49Tgo5MgopZiIdMgIlSh4lPhJJWhopTh5VVi5ZRkpRbkJhUiJNZg5FRg41Ph41MgYdUf5JF +goVQg4tOgotOfpBEeYFLfYRMd4FJfIBHfoNJeYVHd35Pe4RLfIdPeoZOd4JCc35Kc31HeoBK +d4BJdnxHfYRPd4hHeX9MdoJGdn1IcX1EdnhLcntJc3tKbHc9XF4/QEo0Qjc9Pjw2QTk6QDw2 +Qjs9QDs6QTk/QDk+P0E9RDw9QTpCQjs+QjxER0FbV0liWE9uZ0t+c1SUfl6SfWGcgV6qkGi2 +knCuiG+ig2GshGG5lGi9lne4k3G+kW6uiWmxhmSwimC1hmqlgF2pfV+deF6KalSNa1WYelje +3Zj///r///7///3///////z///////////z///////f///v///v8///+//T///////r9///y +/+v4//Hy/+nk+ujf+tH6/+31/+r1+u3///b+//z///Py//Dy/+76/+/5/+7j9+P9/fz5+/H4 +/vb9//r///r0//j///b///7///f9//T9//b///7///////////////z//////+7x++jx8uXZ +zcxOTkpcg4lqhJpuh51sgZdqh5hwhZhziZh0iJxtjp+AkqV6c4ZAQkQ8QUNBS0w/SEtBSExA +SE5KV1xKWmRSXGpJXGtVY3JKYm1SXG5PaG9qgo9eiY1/kKGFqquPprR+oax+lqeBn6eBjqB2 +jJhziphshpZsiZRzhZFsiJR7mqCDmqd7nZlue41XanpNYnBPbXZTZ3lKWGVIV2hXd3hndoKq +zLbT4dTBzMeWq6m94MTt+OHw9OPk3t2vn6GFhnx0fWyProvG38Lc7tXe6dbj79bw/uXu8OPW +39Hk89r0/ePr9eHg7NXi8dfx/+T7/+3s897u9uLx/+P2/+jq/eDs9+Do99j6++X+//P///b/ +//f///j///n///v///3///r///z///X///n///j///////r///7///3///3///7///3///// +//f///z///v///////v///z///n///////X///z///z///////T///n///X//uv55t3cvLDX +upLavInlxY/l0Jbu05ry1p/23qj+563/8rf/7bb/87T/9MH/9Lz/9Mf/8r7/9sX/98T//M// +/8v//cn/+tL/+8H/+cX/+cf/7cH/5bb417Lt4qb5/8v//+T///D///L///L///D///b///v/ +//n///r///T///r///j///z///r///7///////////7///3///v///3///////7///////// +//3///////////////3///3///////3///z///z///////3///////v///////v///v///n/ +//z///3///3///////z///////z///////////z///////j///r///z///r///n///D//+7/ +/+7//+7///X//+7+//X6/936/ujl5czf7MvQw5fTr3fLsHnRrH3Op3nGoHG6mG/BmWy4l2++ +om+1mW28lnCQamZdgnCKwLSVrriOsLOKkp+DrKt+jpyHr7CKo61pk5lgkZdcjZlijZlhlJVa +kZhik5ZSko9Xkpthk5pcjJJYj5NNi5JUj5JXjpJWio9VjZRbjJZWj5FVi5FQipBXipRRjI1T +hpNNgoxRgpFKhoVRiIpSiJFUjpRTiJRWjJRTjZRdi5RejJRQho5SiZBTiItVhI9OipBTg4xR +gohMeYFLe35KfIdQfYdKfH5QfoRKfHxPeX5Dc35Ren5Ge4JNeoZJeINQd4BGeHtJd3xGc35N +eHtNe4BId3lLdHxEcn1IcX9FcXlIcnhIdHtLcntDcnVCTFU9QEA2PDc9PDs4PTE9Pzs4QS4+ +Qjs9QDY/QT89RDg6QDs8Rzg8RT1CRjpASTZdV0ZYVEZwYkx4cFGKdlecf1ungmSki1y1kG2t +hGangl2qjF26mG+5lXHJo3fCoHSwfWWxjWazkGurf2eieV2bblWYb1iYaVWFaE2belnh04// +//////v///z///z////////9//b9//j///////z///////32/+7///r+//L+//T1/un+//T9 +//vu9enm9d/m/Njo++H1/+rt+ens++Pw/ff6/vb///359+33/fj6//f9//H5//n///79//n5 +//T+//z///39//X+//X///77//n+//z///n4//n+//P69/P2//D8//f///76//j///vn3thM +T1BUc4JuiJRqiZVxhplriZ9vi5lyi6B6ipprkKSCmKJ8jp9PUlg+Pj0+R0ZBRlE+R0RERUs7 +TU1OUWNNW2pUWGpKZnVKYG9NYW5QZHNabn5hio2Opq6Dn6WIq7N+oKt9nauBmKR7kaR2jJp1 +h5luipVqg5RshJRwjJWAlaOKoKpteYdZdH9YaXxKX2lUanxfc4dNXW9DTl9PY2xfdXy207zJ +39PM082ToKC80rvf79bq9+vs8uLHzceemZiCgHR9jHejvaW6yrXK3cbR5NPf7N3Z5tDW5c7U +59Hg79ri8Njb5Njf6tTl8trW68nZ7M3j9Njm7Nrk7NPs9d74/+T8/+z///L///T8//X///L/ +//X///r///v///3///f///z///f///n///r///z///n///////////z///n///7///////f/ +//z///7///7///v///////7///7///v///////3///////b///v///v///P///H+9unlz7nS +t5LYtYbbuI3fvo7jxYXuzZjx2Jv95Kr+6rD/67z/6rn/7Lr/76//8bj/+cf//cX//c7//c7/ ++cn/9sf/9sj/+cX/+8n/+cr/9cP/88r93rX2zanr06Tw87jx9b/6/sz//+f///T///P///r/ +//n///j///b///v///v///r///v///////////r///////z///////z///7///7///r///// +//3///3///z///z///z///7///z///7///n///z///7///j///z///7///7///////v///z/ +//r///z///////7///v///j///////7///////7///z///r///v///b///H///D//+3///D/ +//H//+3//+j+/+j49d/j4srNwqPFsIjTsITRvX7buITRp3POqXjGomrJmXG8nGq/m2i3lm3A +lXCumW6baGdZcWWMtbGTpa+Rs7FzmJOFnaR1p6OXub6AnKVlkpldj5Jbj5pbl5Zjk5pajZJb +kpdRkZJbj5VakpNfkJBQi45Yj5JWkJFikZtVjJBbjZVXi4taipZSi5JOh5BMiY1UhItPipFW +h4pOf4hFgYlNhYdSjJBZi5RYjpRVjpRQjY5Sh49ThY5Oh5BXh49Uio1ShY9PhYlRgolMgIdS +eIdJfYJPeIRJfIBPdYhKfIBJe4VJeXxLe4JJd4BKd35KdoJMdH5MdYJKeoFOeoFJeX9LeoRG +dX5FdntJdX5IeHxKeIBIdoBKc3xGdntMbntCXWVDQUk0PjdAPzkvOzY8PTo1QDg/RTk7QTw9 +RD09Qjk3QTg7Pzc8Qjg7QTs7QDZDRztTTUBdU0ZrZEp8Z06LgVidgGOjhWiqkGOtjHGsj2aq +hGWqhVqwhm63m2LAq3W9knGyiWi8k2azi2u5imOxhmenfF2kg1yhgGKbd1+aeVvh2JH///j/ +//////////////f8/+39//z///////////v////+///+//r////7//P///n///////nu+ezt ++uLw/+/q/Nrt9+Pk9d/k8t38//L9//X2++fh59Tz/fT///7///r///z9/+30//P8//7///Pt +/Of5//v///H1+/P0/u31/vL9//Xz/+76//v7//f7//n7//r1/e3w/Oz+//v///Du6N9QTUdb +dn1sg5Nkhphugpdsi5ptiZZpjZ15jKV0k519mKV1j5xugI4/REM5REQ/REc9S0k/RUg6SUtH +VlxIWmZRXXBPZG1canRWcHxTaXVQYXJok5J/mKiGn6iHqa+LoaiDnqqCm6Z5kaBwjpt2iZxt +i5ZuhZdlhY5uhZV3lKB/lJtodoJVaXNRY21JXGpOa3hieIRNY3RIWWVJVmVafHe62cLR4tTO +2tWWnqSvybPf8Nfq+eDy+ubj69fFx7+Rjoh+fnWEnYSouaK1xa/G07/J07vG1r7J2MDM2MLQ +2sXQ4MjM4MbT4sXK073GyrbO1rna6M7r+OD2/en5/uT6/+v//+7///L9/+79//D///T//+z/ +//j///r///n///3///X///L///L///f///j///z///3///v///n///r///////3///T///3/ +//z///r///z///v///////////j///v///v///z///b///////3///7///T///3///D88uHi +zb/Vs5vOsYDOrnzRt33mzIz23aL74ar847H/5bT/7bL/7bP/7rv/9MH//Mn/+sr/+8L//Mf/ ++cn/+cn/+sT/+sX/+8n/+8r/97//9b3/9cT+5rb10qbxwJvTqXvRwY7V5J/1/9f+/+H///D/ +//T///L///j///b///n///3///r///3///v///z///r///3///j///3///j///////7///3/ +//z///7///3///7///n///v///3///7///3///r///v///3///////r///z///v///v///7/ +//n///v///n///z///7///7///j///3///7///j///f///b///X///L//+n///H//+v///L/ +/+7+/+j7/eLZ4cXOtJnGsX3Uu4Hcv3zXtH3UsnzPqHTMpHS+o3K+l2S2km3ApnC7nW6+k2+x +lG+dbmZWaXCAqpiOrbGQoKl0np+AmJ2EmqCLnahljZFblJJklJ1YkJZYkpNZkZNglpZNj5Ja +kZNdl5ZcjZdZk5Ngk5pZjpBXi5BOjJFgk5dQjY9gjZZSiZFYiZBLiYxTio9TipNXjY1LiIxO +e4VJeHtNfoRKhoJZho5KiY9WiZBSipJWjZRQh45WiZBRio5UiZRNiYxXh45RioxSg45JfYNL +f4NMe4RJfINEeoFLfYVMeIFEeX9KdoJHeYFIdX9Md4JJfYdKdn9Hb3dMdX5Hdn1Nd35Ie39L +doBEd3xMdoNDeHpPdX1Gc3xMdX5DY21BRE81QDc1Pjc5PzcxOjc4Pjo+PzdAQz44RTg/PTk2 +QTZBQTc9QDw6Qzw/Qjw8Qz5BRj1JUj5jWkZqZkyAb1aGeVSXglujh1+ujGqhjGmyimugimDC +km26k2u/kWy4gmTAmWi+lG63i2m4h2m0h2O2iWapf2OcdVmfc1iTbVeVd1Tb0Yj9/+3+/+// +//////////////z///////////z///H///j9//T////////+//v+//H///f9//nv9+b5//Lx +//Dk+Nfv/Ofq8OHh6df////59+/2/vT+//7///Hv+uj7/fD6//D+//7///////////////fx +//H8//b9//7////////////////9//Xx/PD+//z///////////////////359uxZTk9Yd4Bv +g5dyipxyi55xiJpyh590jJt3j59+lKV2lKl4j6Z5malmXm09QUJEQ0c+Sk1JRks6RVBPT1lJ +WGpKWm1QXnRXZ3Zbb3xQaHJUXnVoi42LpqyIpa2MqbWKo7GIn6h7laJ8jp17j6B2i5dzippy +gpRrf5BpgpN2i556lqBtdpFVX21KZXJSXG5XaXpicYRVZnlPUmc/TlpcfXa81MbI29LE2Myg +oa6gva7Y6tft+eXv9ebh7tzm6di+sbGJgoB6gXaZrJC5yLXX4sra5NHN1svGyrjEz7q8yLTJ +zbrQ0sPU38fz8uLl59jv9d33/er6/+v8/+79//D///P7/+////P///H+/+7//+////H///P/ +//b///j///j///T///b///j///X///v///b///j///b///n///////7///////D///3///z/ +//7///r///z///7///////v///////7///z///X///7///j///z///f///z///n///j//PL4 +4NjgvLDCn4XBnnbbvIPozpPu1ZT52qX85LD866z/6Lv/8bz/8r//+MT/+cz/9sX/98r/9b// ++cr/+cT/+Mz//Mv//df/+8P/+8n/+Mb/9cP/7r3/57P+3q70yqbhoIq1gXChn3HBypLX8rD4 +/9f//+n///L///L///b///v///z///7///3///v///7///3///3///z///7///j///z///// +//////////////////////////z///v///3///z///7///v///z///n///7///n///7///n/ +//7///j///7///f///3///z///7///3///n///3///X///L///P//+v//+7///b//+n//+z+ +/uLs79nQwae+k3nVvILXtYHgvHzZtH3XrXvSqHXTpHO9n3bAlGe7kGy9mG2tkmq1kWq4imyk +gGhla3Vkf36Rrbx5h5aClqSJqKGMpa9wipFVh49ci5Rdj5xdjZZhj5pXiJVYiY5akZBblZpe +k5VhjplTjI9fiJJakJhVjJVVjZdVjZRVjpFbhJdZjI1Xh45Th45UiJFUipFUiJBPgIhSf4xF +dYNGcXxGc3xReIJSgYNUiI5XiZFahoxSg41ShpFRgI9Rg49XiZBHho9Uh4hOg4hTe4ZPfoNN +fYpPfIdNeYJNfIVIeoNOfIJKeYBNeIFPeYRLcoJFd39NdH9EdHtMdn1HdHxMcX5GcXtScYFL +dX1PeIJJd39LdHZNcYFIZ3ZGSVVCQEE3QDc5Pzs8PTg4Pzk3PDdBPDs4PjlDPTw5QDE+Pzs4 +QDhDQTw6QDlCPT43PzlFQD9MTT9nV0hsX0qEa1OOeVmcg2SngWijhF+jhWKohmewkGTAmm3C +lHjEn3fEl268knG8mXC/lG/Ai3Gwfmeygl+lfmaYb1qMZ1iCZUeOdFjXzYL///v///7///// +//////////////z////9/+/+//P+//b+//b7/+7+//v///L///v6//ny++n9//L2/vDq+Obg +9s31/Ovk8eHr9d71//Xt++r0//37//f4//P+//3///r///Tz/+r+//v///n++/b9/vv///// +//////nt/u34//P7//X9//z////////4+ez6//P///L6/vf///738OTe3tVSTU5QbntwhZhk +iZZ0hJxshpZvh5dzi5d6kqR0jqJ/kqtzlKKGorKMpqhiW3U4QD45P0U9Rkc4R05EUVFHVWRK +WWxRXm9NY3BRZW9SY3JLY3Buk5h6ipd6oaOUrLKQrLyNoLF6kaSFk6J6kp5+jKFsi5d8h5ht +iJd3i5hzj5aGlqNRbXlTYW1OXnBTWWpTaX5nfoxZZndKWGdDSlpLbGW0y8K/3dDO1tO0t7qn +xLPX8Nvt9eHu++rp8uPc6ODU1Muuo6WIh3p9iHiJoYSiw6akt5iFl4OEjHydoJPi59Hw++bj +7N/0+ub4++jk7db2++b7/+r9/+77/+f//+/7/+////H///L///b///L///b///P///P///r/ +//b///b//+////f///j///3///7///j///X///H///L///T///b///b///D///r///z///b/ +//f///P///X///r///f///7///v///n///j///3///r///r///v///z///r///////L//+n+ +++bt3NjNrZfFrH7YvYvjzY7316H75Kr85rX96rL/8Lz/873/88b/9Lr/9cf/+sT/9cH/+cP/ ++MP/+sf/+Mb/9sH/98r/+sP/+sP/88D/8Lv/9sP/77z/7bj93rb506Ttv57hqY3RkXvClXrI +047m77r7/9b//+D///n///b///z///r///////X///////3///////3///n///7///z///r/ +//7///7///7///////3///b///7///z///7///n///7///j///z///7///3///b///v///X/ +//v///r///j///3///f///////v///r///X///T//+v+/+78/+b//+7//+j//+v9/uvq58rW +xaPKr37iwIjewXrguY7avH3brHTSq3HRp33MqGnFl263j2W8jWi2kGa5mne7kGu7kGSmhmyH +eohzkZaYpa1wf4x9oZ6Ps7uJoq5kj5dViIxWh4xbjZVdkJhelJJak5ZbkIpWj5VikJZMkZlf +jI5XjJFWipBWkZlakI5ZjZZZj5JYjpVYjZJVho9Oio1ai5dVi5BZg4tOiYpZh49Sf4RMd4VH +cHxHbnZJeHdEcXlMgIVQg4lWholXg4pOhYpQg4pLgItRholNf4lNf4dPfodMe4dHe4lRfopM +fYRTfYpNe4NLeYJLfoJNeINJdntKeYZFeHxGcn5Fd31Len5Jen1KcX1Fc3pPdn5Nd39Pd4BM +cHlJdntLcntGanNDSFRBQ0I6Qj06Pzo4Pjk9OTs2PTdAPz44RD1EQT03RDZAQzo3RjpEQTs6 +PzhFQDY9PDhDQDk4QThORkJdVERuZUqBdleRfFyTfmOegWGegWCohmGtiWm0jGbAmmy/lnOx +i2a+mHG3jGy/lXOvhGSyh2enh2OxiWikgGOXbWCDaVCJZVSHdU7e0If///j///////////// +//////////////////////X///////////3///3////+//n+//n6//Xx/+n4/+/6//vm89rn +9drr8ODs8t3q+uby9+z3//Xt/+z7/PDu/+39//z1//L+//z5//H4//L9//z///////f8//X5 +//X+//7///z////8//H///v7//T89/X+/fD3/uv3/+/5//L5//Tx7+VTUFBacnhohpJyhp9q +jZd1jKBuiptyi59wj59/kqWCpKl+nKp+o6aEoqxsdIdOVlxCSD47R0g4Rk1BUlpHVl9GUmVM +XGpSWmpRWWtPW3BQWG1ykZRziZ1+m6aNq7GTrriKpKqEmah8laeGl6J3j56CkJ9ujpx6jJt4 +jZ6Bl6SCjJ1RYnNQW2xRX2tOXmhLZHBhcoZQZXJSW25BUVtQaWOwzL7D2c7R49W4wsKtwrTV +69Ds+ujx+urv9+3u9uHr7ufZ1cyyo6aSh4GAhHmHiHmGh3+Wjn+vsZ7a4M/r+N/v/Ofv++P9 +/+7y++Ln8N36/uz7//D9/+39//D///D///H///L//+////X7//T///T///j///n//+////L/ +//P//+////H///f///v///n+//X9/+j+/+3///T///v///b///v///X///7///n///r///n/ +//X///T///P///D///H///f///b///T///X///j///f///r///n///r///z///L//+v9/uf4 +8uLVvqLGoIXOtn/rzpbz36n84bL54qn96rj/8r3/9sP/9sb/78P/+sL/8sj/9Lr/9sf/9L// +9cb/+Lr/+MT/8rr/+cf/+sf/9sX/9br/98P/9MH/8Ln/8Lv/77z/4an83Kn205/2x6ruvpLp +wZziupPZzJL2+8v//+r///P///T///z///n///T///X///r///n///v///j///n///3///// +//7///r///v///z///7///n///j///T///7///j///3///r///7///////n///j///n///7/ +//X///v///z///z///j///v///L///H+/+3+/+n+/+j+/+r///P//+b9/+L28tPMu6C/p3vb +wobiwYLkvIDctHjctoPUo3bOpnHOpXHGoG3FmWa4kmK2jWCsjWS4j228lGy9kWyviWibpaqJ +paZ9hpdtgoZ/sa6drbdrjJxhiJBQiZFejIxRkJNWiI9RiY9ZjZVTh5NYhIpViZRVipZWi45b +ipNXhZJYkpRaio9QipBhjZdSj5Beio5QjY5Tgo5ViItXiodVh4tRgYhUio9UhY9Ofo1LcHxB +bHpJcHREcYBDfIFKgoVOgopPgYhUiJBNg4xLeohPgoZPe4dOfYZQd4VKe39NdohNgH1QfIdK +f4NRe4JHeHxKfH5HdH9LdH1Hdn9Idn1CeX5Kdn5Gcn1KcX5LdnpGdoFKd31MdX5DeHhJb3pG +c3NEbXI9TFVBPUA2Ozc9Ozo0PTZEPzg1PjRBQjk0Pzc9OTs7Qjc/QTg3QTZAPjs9PTlAPzo/ +QDlCOz4/Qj9BQTlHSj9gVEduZ0p/dVWNfFuXfGKfhWSjgmKmiF+xj2i4kmq6lW7FmHXBlHO1 +kme9imq4lWu5hG6simavfmeWelmccV+OaVGLY1GQZVGJa0/TyXb9//D///n///////z///z/ +///////////////////////////////2/+79//b8//f0//P7/ez6/vH///zv//Lc9dDi7+Hl +89rj8t35//n9//37/e3///z////5+enq9eT0/+z7//L6//j7//P///j///T9//z///X///z+ +//n///7///n9//r0//X+//f///3///////////vz/e70/fH///NcUl5KdHFxg5dsipp0i6Ju +jpt3k6J5kaJ9j6VzmqWCm6t7pKl/oauDnKZqfotYZ3JFQEs+S0s9S01FUFxEU2FIVGVLWGxK +YGxRY3BPY3BKXmxtj5d0ip1+mqKDn6aLrK6IoKyBnqmCmaeCmp9+kqN0j591ip56j5mInKGG +pquChZ9UZHFRXWtKXG1KWmlQZHVaboBUZ3pNWm5JUl9Ocm2uz7/D2dDQ3NW6uLqqyr3g7dvr +/OP1++js+uf2/ubw/Ob4+eTZ3NG9v7avt620vrO1wbLL2MHf5tXZ6tLp8t7l8t33/uf7/e3y +8+bp9+D8/ezz/uf6/+b//+3///L///L///D///P///P///T///D///T///L///b///P///L/ +/+j//+37/+P//+r9/+X///H///z///f///////7///r///////f///z///////3///3///n/ +//r///3///j///r///r///r///H///z///z///n///j///j///n///j///n//+3///b8++vb +vKzGsoTbwI3qzZvw0qD12qr94a7/8bz/8L//9ML/+8r/9Mb/9cb/98P/98L/9Mb/+8D/+Mz/ ++M3/+Mn/+r//98j/+8X/+8T/+cf/+MX/+MH/8L//8MP/8rn/7bv/7Lf/7bz/8LX/8br/7Lr/ +5bT42LDvypnq1qT5/NL//+T///L///X//+z///L///f///n///f///b///f///3///3///r/ +//z///f///r///v///n///b///////z///7///b///3///T///z///n///////j///n///j/ +//D///X///r///z///b///H//+////P///P//+n//+v+/+b7/uH28djWu6i/sXbasn/dxInr +v4DfvH/dtH3au4fXp3fLo3POo2i+nWi4lmi0j2CuiWe4j2m1lmu7mW27mmmsj2yWtquNqa5n +hYZslI+Io6qJn6ZkiY9VjI9ekZdYiY5alJdVhotVi5ZOhopYipZTj45YjpJal5dXj5ZZipRW +iI9Wi5JWjpBYipJYkI9YlJRTiY9VipJQjYtZh4tVhYZTh4hXiYtSi4tQhIxGg49QeIdDdnxK +cHpHdH1Pb31HfoVTgIRKfIBSgoZSgYhLfYVNeoFRfYZKeYJMeIFOeYNOe31Kdn1GenxReYJM +fIRPgIBOe4NMd35Md35Hd3hMdH1Kc3tLdXxFdHlFeX5Jcn1KcnhGd3pNd3xMcXlIZ3BHamlC +T1c+QT83QzxDQTw1Pjw5OTo3QTg9Pzs5QDk6Ozo5RDhAQjxEQTw7QDw1QDU9Qjg+Qjk9Pzo9 +Rzw/Pzk+RTZISz5lXEhsZkuAcFKEeluWgl+igWObgFmif2GrjGKyim60mGa+kW/AkmzBmXK+ +m3CzjGSzjWu2immngF6jeluYdFeTclmWblmQa1aJblbXy3j+//H///////////////////// +//////z///////7///n///////v///r///j///r2/+39//b///r5//Xm9d/j8s/s+Obk6tzc +5tTt/uHt++jz/u3+//f///n///z///T4//D7//P+//v9//n9//rx/+z7//z///v///r5//Hx +/+r4+/H8//P5//L7//j///v+//X+//n///z///7///ns6txiVGNQcGlwi5poi5d5jpxyjZt3 +jKBzkaF4k6l0jp54lJx2mJ2HmqeKpbNmfolXYGw8REc8TUg/S09DVVlNVl1CVlxIVF1IW2JL +ZG9RanhPW3Blf4lqgpJ9mZ6Cj6KOrbOKoK57maF+mKl+lZ99k6R4kZ93jp55j5uClqGPrLB6 +hJRTZHNKW2dLWmZPWGVQYXFacn5TantMWm1FUmBRd26vyb/T49HG1c+cq7CmxrTl89zv/OX1 +++nr/+L6/Ofn+uPz/ebx+ujs8t/d5NnA0cnV58/Z4tXl8tva6dTb6tTl9dv6/+r7//T2/+73 +++/7/ery++f1/u3///L///D///j//+////T///b///T//+v///H//+7//+73/ejs9tvr69Lz +9dv///D///j///n///n///z///n///r///v///v///3///X///3///v///7///r///7///z/ +//3///j///z///z///z///X///7///3///n///r///v///v///n///3//+3///T38N/ZwJXW +v43hw5Hy1aH63q385a3867f/8L3/8r//9Mj/+sj/98v/9cH/98P/+8f/9sT/98D/+L///Mb/ ++8f/+sj/+sL//Mr/+MT/+sD/+sv/+8j/9r3/9Mf/98L/98b/+Lr/+8f//Mr/+cX/+cf/8bv/ ++r7/9Mn/7cH+5b354q32+sL//97//+b//+3///b///f///n///f///j///T///r///z///7/ +//j///n///j///3///j///////T///f///X///3///b///3///n///X///X//+/9/+j//+n/ +/+3///T///j//+n///T///L///D+//D7/dzv8tft9c3e1bm5pYDMqn3Xt3/qyo3fw4nivX3b +tXbdtnbXsnvRr3nQo3TFn22+nWjElly5iWavjl2yjWq9lm68nHO9m2unjGSao5+BkqFrgoN6 +rKKOsap1jZRbh4xWkI1aiJNVj49bjJBUh4lYipJSiYxSj45dko1VkJNUio9gkpddjJNZkJFX +jZNWkJZXipZTjpFQh4xRiItVi45VhYdUh4pUiYlMiopRgIVNiIdYhYlSiIxUgolEeIBObnlG +c31Ldn1Kdn1MeoJSgYVRgIlPfYRNfIRGcnxEcnVEaXJCa21KbnJEcXZKdHRKd31NeX1PfYFK +e4BMeH9KdX1Hc3hIdXpNcHpOcXdJc39IdHVHdH1Ib3hEb3hObnNIb25GaGs/XFhGUFBMT0c+ +QUE6QjY8Pj05QDk8PDg4Pjg4Pjo9PTs8PTk/QT49QD1CQzs9QztAPz48QTo6QDg7PDlCQzo9 +Pzk9RTZFST1dVEJnX0x6bVCHblOVflKniGGOclmbemGoj2OqgGyojGO/kW63jm7ImXO2kGus +i2SogWawh2GuhmGogWWddV2jfVubdlqPblKBZVbNxG/+//f///r///7///////v///3///z6 +//X4//D+//L///n7//j9//X4/+z+//T6//Py/+X2/uvq++L3++jg9N/l+9bx/+/u/Ono9OT/ +//////v4/+zx//L6//H7//P9//j1+er4/fTz+ent/ufr8+Xw/+38//b///j///r///7///n/ +//7///n7//n+//z5//T///j7/fX7//b2/+35/+//+/hwXG5LZW9wk5h2k6Vzi5ZrkJ1zkZp3 +j594iJx1jZx6lqd/n6qHnq5zlZtiboNLW2M/SElESkw/TUxDUltFWGBPW2hEWWJMVWJIYW1Z +ZXdFY29hcH9PanhzmZiGra2ctbmHoayEm6Z/m6WElKB8laB3jJt5ipl1kZeDm6iWrbJ0f5JX +ZW9PY2dJXGNPV2ZNYnFbcYdUa3pMXG1MV2NUcW2p0cO+1svG1tOirrK81MPg8dfq++jw/eby ++ury/Obw+uP2++jv/efu9OLP4snR1MbS68/b6Nfl9dzs7t/K3sro99v9/+v4/+vu9+L1+uP2 +/ef3/+b8/+7///D//+////T///L///b///P//+///+n8/+/7/eP9/en+/eb9/+r//+v///T/ +//b///z///v///7///z///////r///////3///////T///z///7///v///////v///7///// +//z///7///////////b///z///f///v///f///////f///7///r///P//uznzrbfw5Lx16P1 +5bD847L85bT96bj/9MD/8cP/9cL/9cT/98n/9sf/9Lr/98j/+sP/9sL/9cH/9cv/9MH/+8r/ +/cP/+cr//cT//cv//8n//Mf//cX//8f/+cb/+8b/+sX/+8r//L7//cb//s//+cT/+MP//cb/ +/9H//8///c7/+8f/8cH95rzx4rPl57Lx/9H//+n//+3///D///D///v///f///3///f///n/ +//r///r///n///z///b///b///H///D///H///r///f///P///T///X///j//+3+/+v8/+b+ +/+n9/+X5/+P//+v//+P8/ufn6sHY4LvIzKK7onq3imbFoG3et3/ltYDgv3zcvYfgvH3htnzZ +rHXVsHbbqHXIn2jBm2u/mWu2kme1j2C0kWy2jWi9mXHAmXC5lWmqgWONp6GAiI52kpSMr6uB +mqdgjo1UiYpXj4tZjopYiIxTiJBTjI9ThIpRjZBbi4xTjo9YiotRjItVjIlTkI1YiJJUh45W +hY9MiIZWjotZiotaio9PjIxUho5QhYxTio5QgolUfodMh45Vf4ZKfolRe35Od4JJcn8+cXlK +c3tFentLeYNKfH9PeYRKeX9MbXtHaGtGYGVDZWVCZmlBZWNJYWdEamZFbHJAbXNHc3dGcn1I +eIFTdX1Idn1Md3hGb3RKbnBJcndFdXdLcHlCaGxLa2pDaWFLW1xBU0xfaFFpbFdVSUw3QzpA +Qjw3PjY9Pzc8QjE5Qzk3QDU8QDk2PzdBRjw9Pj05Qzk6QDw9RTk4QTM8PzQ+Qjc5Qzs/QDtE +QjpDSD1bVkZkX0p9aU+EdFKXfF6Zg12ZeFmihV+jfmmsjl+9k3S9mGy6kWvLq3TEmnSqh2S1 +kma7i2myhmOqhGOhd2CYe1mVcl6EY1WOdFjczIL+//j///////////////////////////j/ +//////b///f///P6//b6/+z+//n2/+P9//X9//H+//j09u7o+tvs++Pn9+Dk9+Hh89rp/N7o +9eb0/+7x9+jp8+L7/P3////7//Xt/er3/vX///j+//7////7//f0++zw/+z1//L9/vP9//z/ +///1++z5//T1/+/6/+/9//b///7///f2/+7r/+eQWndIZmJ0lJ51j6F5jqV0k6F9kKN7kKJ2 +kJ50kKJ3kqWFpayDoqxkdYdVaHVPXGg8SUpDSVE7TExDUFtLV1xMXmdOWWZIWGFUYm1NY3RT +a3lyf5BYZnNbgIWHrKyPrrqSpLF+naeFnaeAnaSClqR6k552j5t3kpuDnqaPp6trfItWZXNL +XmRNVWNHWGBQY3BUbXtbanxMZG9GWWJbe3KoxLi1zci0y8Cet7fG3sXj89/s+uXv++3y/+fw +//Hz/ury++bz+eXP3s7O3sTV4tbc5djS2svm9Nnr+OLd5NnU5c7e9Nfh9Nrk7trw+Obz/On4 +/+v5/+/4/+v6/+f8/+z//+78/+n8/+z7/uf0/ur6/+f//+3///D///T///T///n///v///3/ +//j///////3///r///z///r///z///z///z///n///3///v///r///v///z///z///////z/ +//////z///3///f///3///////z///v///r///////z///7//+zx58/m0J/w2Kj05ar87r39 +77v977n87LX/8cf/8sb/9MP/+cT/+Mr/9s3/+8///Mz/+sr/+cX/+8f/+8b/98//+8X/+8X/ +/sn/+sb//cX//dL//9D/+8f//8n//s///sr//s7//sf//9H//sz//M3//Mn//cv//Mz//sT/ +/8j//9D//tH//sn//dL/78T716jYt5KquIe12qPG5afh/8z5/+r///L//+////X///D///n/ +//X///v///n//+////b///b///D///H///j///X///H///T///X//+3+//T3/N3x9dTg5sze +8czn8tLn7cTQxKKvnniogWelgluvkWbFomTcvIDduXzkwoPiwn3ruIjZt3vbvH3at37Ts3bU +qHHLqm/En2i9kWO3k2a2jGCri2Wukly1kmO4n2+8nG29l2eYgGZqgHdbfoOLqqiOpqd0iZZR +hItahYxUh4hVhIhPiYpXiolQi5FTio5PhY1RiIdai49Ri4pViY5RiIdViItQiopWjI5Oh4Nb +iopVjY1eiYxOiYdYiotOiY1Tio1ThYZZh4lOholUg4dSgIJPgoNMgopLdn5FdXtGc3pCdX1K +c3pId3xPdXxFdHpNb3Q/YWY/Wl9BWltEXWA7XldCYl0+ZFhAY188YVtCZWNCb2xLeHhIdXxF +c3hGc3ZPdXdMcnhLcXVLcHRGaGxKa2tBY2VEXFlLVU9naFGHgGKBh2F3cl9fVldCRD44QTg7 +RDs4QzZDQj40RDc7Ozg4RDlCRD80Qjc+QT43QDlARjw7Qjk9RT09Rj49QzY9Qzw/QD5CRjtH +TT9TV0VsYkZzZk58cVeOfVeiflubhl2vjm6sjmC/nm28nnG8lHO0k2vHpni+lnOxh22mhmi1 +i2uqiGa6jWqqf2ebcVmZbleXbFeZd1rQxnf7/+n///////7///////3///H///v////9//L/ +//z8//f+//L9//P////////+//j+//b7//X6/u7y+unt/+jk/dXx+e3n7+Lh6dX5+e7w/vr5 +//j///7z//ny8+Xm9Ov9/v7///z////////5/fH6//z///////3///b9//7///f7//f///71 +//Hz+e7p8d3u+On1/ebv+uvx/en2//Hs8eekZ29DYWBnjZlzjZ10jZ11kJ59kqF4j6J6iZx0 +i552kKKCnaqNqbFnbYdYYHFBVWRGSk45RkZET0w/TldOU11HVWNSXGVKWGlSYWZOY29ZdoJ9 +hJJWa3lZc4FtjJmWs7ePqrCDoa59oqeCn6d7l6N+kZx0jZp8kqCHp7GOn6pod4VYZGpLVGVE +Ul9GWWtRX25Ta3pedYRPZHlJV2FRcG2lvrmrwrqks6yfva/R383e8Nny/OTn+ujr+ebs+uby +/efq+eLe5Nq2w7zO38re7t3h8tvg59vd79jr+eHl6uLV4dTK3cza69Tj9d79/+z3/ebu+uPs +++bt+eL0/ub9/+v///P///P///H5/+r//+v///H///X///X///n///j///r///n///v///z/ +//3///r///j///z///b///v///7///z///b///3///z///f///n///z///z///////3///j/ +//z///v///n///v///3///b///v///j///n///r///X07s7n1aTt2Kfx4a766bj867j/7Lv+ +8bv+8b3/9Mb/9MP/9cj//cj/+M//+cn//cz/+Mb/+c3/+s7/98f/98X//cz//M7//Mf//Mj/ +/NH//cn//9T//s///cr/+s3/+8b//s7/+8v//dT//9P/+cr//c7/+Mb/+9D/+s3/+9D//9L/ +/9H//tD//tH//9D/+sr/8sL52LDSwKW8tZGvr46io4Gz16Xg99L5/+P//+b///f//+////X/ +/+////b///T///b//+////T///b///D+/+j9/+f///D//+///+r+/uL499vl5MDn383Tzq28 +nYevimm1hGm6hFzEjmfTnmzVtHjetHzZtXXhuYbiwn3is37cuoPar3/Ss3TUrH7MpG3Jnm7P +oWm/m2i9kmizlma1j2WsiGK1j2a4nmzCnG+9oG20jmSUfWlTXldgj4abqK+Bmpxhg4ZVh4dQ +ho1Vho5OiI1Wg4pUiIhZiY5SiItXh4dXhYdTg5FRi4dYgoxVf4ZTh4xTiYhQiIpKiIdSg4tP +h41WiohNhIpVgYlOhYhYg41Rg4hVgItLfoNQgIhKhIZSf4tHfYNRfYJFcoFJcH1FdHpKdYFF +cnpNc3VFanBAY2dAWmFBV1s/VVxFV1g+Vlw6W1g/W1tCWWQ8XF0+W18+aGFCa3BIb3RJbG9D +bG9Ga3FEbGlKa29EZGhLZmM9XFhLUVNlcVGCf2eBg2SIgmiAgGV3cmVlYllERUU3QD04Pzo4 +Pzw2PDM3QTk6QTg9QTo9QTk5Qzc8QjY0QDU8PTs3Pzc7QTc4QDVDPjw1PjhDQjo3QTRGQz5Q +T0RqWkxybU+Fb1aYgVuojmahg2Sqimeuk2W2kGu7kmyyiGith2DCoHG7l3K6mHO8jXSlfWek +fV2uh2WsjWiog2KkgWCgemKfflzQynn9//b////////////////////////////////+/vP+ +//f///z///////////j///b///z///n4//Hw+urv+/Ha8NLg79jq9OXl9t36//T4/u/+//j7 +//X2/+z6//f///Hs/+j5+uzt9u30/vL9//3//+/w//P9//v7//f+//X///j9//P9//j///z/ +//v3//T5//P9//X6//T+//z///n///7kb4RDX2Bui5h3jKF0kKR5lJ56laN6kJ55iaB4j556 +jKN+oqiCqqxobYtLYnBDSmBBSE0/SVE6R00+SldFU2BFVWRPV2pKWmdOYGxPZnFgho92iplf +cINkh4iFpKyOsbaMn7J/naaJnql+m6h/kqJ8jZ56jZx9maWNrLODjp9ncYFTX2pMVmZMVWRJ +WGpJYW9adIFfc4VTZXRJWGdRXWObwayzxL+bq6ukv6zP5c3p9OHz++j5/Ozx++Xy9uji8Nze +5tjD0ce3wbfW587p897p+OTx+uPg69rr9+Po7Nve6tfe6NXX4c3n9tr1+uj0/ujz+enz/eLx +9+Hu+OD9/+v9/+v///H///P///H///T///L///v///j///z///n///v///n///v///v///v/ +//r///n///3///////z///////////j///z///r///3///j///v///3///////n///7///v/ +//////P///z///v///r///f///j///j///n459Xr2K7w2aP126f647D967b98bj/8b//9sX/ +9ML/9MX/98r/+ND//87/+tD/+tD//cz/+s3/+cP/+c3//cX/+87/+83//dH//c7//cn/+tX/ +/Mz//9H//sz//M///tT/98z//8j/+tL//cv//9T//tb//tb/+8z//sn//9P/+tD//tP//8// +/tP//9L//c///Mn/9cL96bnWvqWtqYqoqYSqonqkrIS4yaPh78jx+9/2/+H//vH//+b//+// +/+////T///L///T+//L9++f189Tn7tDz+tr7/+X//+z8++Hw6MzctaTAnoOzh3ytjmjBlGvN +snLbt4DVrnThtX7auX3dtoDduHzot37hvHrjtYDZsXHdrH3WrnTZsH3SqXXXpHvLp23KmXDA +nWu8kG6yjGquiVysi2C0i2a6k2i/pHK8nGuyjmqTf2ZcYV1ompGbqa9gf4hZgItPhoVWg41N +gYBRiZBJhodTgo9PgolSiI1Ph4tXh49Vh4xYjYpRgoZDgYdOgIlWiYtQgpFQgYtWgYhRgIJK +fIdOgoZPgolLhIdLgYJTfYZJgoVQgYhNf4FSgIhPfoJRdolFe35OdYVJcnlFbX1AbXJFc3dK +anI7YWVCXFw9W108X145amg+b3FBc3lDeHxIdntDeH5BcHQ+aG5DZnFDbW5Ja3FHb2pJa3A+ +aGtJanFBZGZIWmVDXlZea1VwgF6NiGiJhmmHg22BgGiBhWVsbl1sbl1JRko3Pzo5PDgxQDU4 +PzYyQDo9Pjc6Pzk4PzZAQTk9QDpBPj47PTQ7Qzo7QzZARUA5QzI9Qj5AQTRBQENBQzlPTUVr +X0d1ZlGAbVmSd1ehgmWnh2iph2enime8lG67mHK5iG+xjWTEmnLClW/BlGy+kHCvgmemfGGv +h2end2WieWGhemWacWCUdlzMxHv+//z9//T9//j///z///r///////j///////////////// +//////////jz/uv6/+n///z///Tv+u7w/+jk8+ff8M7m89/o9tz0/en2//Tx/fD0/vL+//z/ +///3/e/9/vn6//L+//7///////n5//r///z////3/+/6//X6//Lz/vL5//T1//f7/+/+//r9 +//v9//z///////X7//b9//jz8ObGc3NKWmRsh5V1jqV4jp5+lqN9oKiBlqF/mKN1maF9m6mI +qbCKpK1sdYxIXnFHT1tCS1VASU5ASUxDSlJBUFZET1lEVF9PVmpGXGlSWG9je4Ryh5WFoqiK +p62PrbObqbqFnKiIo6+An6mInaeAnaZ8kqV6kZ+Go6WFmKVyd4Zaa3lKX2xNVWRLWWRNWWdJ +XnBVbnlbc4BMandMW2tAXV+eu62xy8SprbGMr6jQ5drn9uHt9+fw++nt8+Xs9+Pk6tLK1MvZ +5tTD0sXY7dTv+ujv+OT6/+j4/+nx+uXh6djS5Mz0/ejv99/g7Njn9Nzw9d/o8Nru997x+9/6 +/+j8/+b+/+z///P///r///P///X///X///n///v///n///r///v///3///3///z///r///v/ +//3///7///3///7///7///////f///z///////z///z///7///r///z///j///////z///z/ +//b///3///r///r///T///r+/vLx3MTk2Kby3aX44a/757X977z/68D/9Mb/88b/9Mf/9cf/ +8cH/9Mn/9MT/+M3/+tP/+8z/+c3/9sb//sv//Mz//c3//dX//87//9D//8r//9D//9L//tP/ +/8v//9L//9D//tb//sn//9P//ND//M7//s7//9X//9L//tf//9H//tb//M3//c7//83//Mz/ +/s7//c3/+87/+cn96rXr4bHTxZy+uJ6yqpKinYaTi3aTj3fBq4S/lIPCv5jb1rzd27Ht7M/7 +/tj7+ubs4c7byLDe3L3i1MLZyLPCmI22moHLrpjFk3fDrXjPtHvbtXrWrHTbs3zkw4Xqw4ro +xovgvIjdtXfjtoPauXzjvIrcuH3drIHZtITcsH3XsH/Xp3zUr37IoW7EoXTFoGzCom65kGS5 +j3Gyi2WuiWSti2m7lmi5mHC8nHG2knSsjWmdgW9Qb2FwhY12jI9fgYdVhYZagIxUhYRYipFV +f4JQhohNgoZNh4tPgYRWholTgYtFg4lShJBRiIpVgIdQhIpRfo1RiYpMgo1MgIZKfIFQgodR +gIlWgYtRgolYgoNKgYVVgYREfINTfoVKgItRfYNLe35KfH9FdH5Kd4FFc3pEbG9Ha3BFY2tD +X2VAXVxCamU9d3lJf4FBe4NOe39NfYlJgItNg4ZNgYlGd4JCcnxHa3RIaWxFbXBHaWhDZWdL +YmFOZ1tnflqKkGmOjnOTi3CRhWqChmmLg2qBgWSIhWl1fmF5eGRcX088QD03PTc8Pz89Qj06 +QDo9QTo+Qzw+QDs9REA6RD9APzw/RDg4QDxFQTo7Qjk+Rjk8Pzk/RTw7RD1ERT1NTkNlX0Z0 +Y1B/cVWWfGKWel6limOrk2+tima1l220jmq0jmq7km/FonbGonTBk3XBmnG0kW6vg2SofWSp +i2KmfWWbdmCTc2GbfFu4tWr9//L///////z///r///3///////77//X+//v///b////9//n/ +//n6//T////////3/O/t/Ob8//T7//fk8+Xj+9Tz/On4+/Dn7d37//b89+/1/vT4//X09eT1 +/vb6/fb+//j5+/Lr9un0+fP0++31/u75//P+//3////////////7//j///v////3//f7//f/ +//X3++v+//z////////////3jY1EVVpqjZNxjJ51j557l6p3jqJ5k6Z6l6J9k6h6lqOLqbWP +o6lodYdSXmlCRlFBSE87R0lBRkpCSExJSlZATVNPUV1IWWFTXGpQWXBqe4dmhpGDpamUsbmS +qbaSqLqHpK2VpLSBn6eElat/mKF/k6N+laaEmqhrdYlkb39TZ3NQWGxLWWdKV2dKVW1IX25V +YnhYaXpZZHpQWGZDWGGivKy4zMeprbB+kZS4yb7Q5dnk8+Tl9OHj7Nzd8NvZ4tnQ387p7dvR +2c3f79fr8+Hv/er1/+j4/+74/ej1+eXW4dPd6M/6/Ojv+Oji7Nft+OT4/Of6/+z//+////T9 +//T///L///n///r///X///r///T///n///j///3///f///j///v///z///j///r///r///r/ +//z///z///z///v///z///X///r///z///r///v///7///v///////3///n///3///b///j/ +//v///7///f//+/36tjs1rLo1KL226z146z75LX96bb/7bz/7cD/8rv/87//9cr/9cn/88b/ +9cL/98v/977/+cz//M7//c//+cb/+cn//cr//tD/+sn//sr//8///tT//dD//NX/+87//Mv/ +/s7//dH//Mr//dX//83//ND//dL//8v//9X//9X//dP//dD//tj/+tb//8X//9f//Mz/+8v/ ++8n/98n/8Lv32q3SvZGadnCCfmiLgGuCfmeEeGeKj2Po3J/02arvy5jnyIzjvYDatobZr37U +uI7Zt3zduYvXs4HTrH/Wuojbv4TarXvbuX3luoXlwYbqw5DpxorrwIrhuH/mxY3qwYXrw5Ph +tIDdtn7duYHhvIDdsXjZr3zYrnvOsH3Vr3bKrHXNlW7DoGfImXDEnG29kHa7k2e2kG61imKp +iWWximKujmXJmHO4lm6/mW61km2yi2udiGuAjJBzkpZec3hSgIRWe4JRfX9SfohSfopNf4NS +eohJf4JSgotKgYRVfYdPg4ROgYtMh4FZiIhNf4hQf4ZMf4tUe4pSgoNTf4VPgIVUeoZPfoVP +fIFJfIBPgIlOf4JNeYBFeXxOen1OgHtQeIFFeXpKeX9CeH1LcoFCbHFAZ3RAZGlIYWU9bV9F +f3xKhYBXeX5Lfn9ShIlOfodSgYdOgIlPe4JLcXtDa3BEZG1FZGRHYWFJW1pPaFZuiF+NlWyX +lGqck3SVlHaRkXGOi3KQjmiQh2uFhWZ7emd9gmSFf2l6fWNzamM7Qzw7OTwzPzo5QT02QTk8 +Pzo8Qjw9RTs7PDg9QTs9QjdAQDw8OTdAQT04Qjo9Qz87Qzs/Qjo+RD1EQkBFSj1iWklrY0qF +cVeOfVideWSgimO0lG2tkWu0j2q5imm+jW+9lWq/lm6+lG28kXG3im6+mXO3jW+jfmmcdVyh +eF6Ub16MbVqHbVCvpmz6/+D////////////////9//n///////////v///r///v////////+ +//v+//L9//f6//H3//P5/+3z/Ozm9t3d9M7q9OPm7+Hf6tb1//H3/fL3/vL5//T9//X1+ez6 +/+76/u77//n5//v////5+/H6//D1+/P3//D2+vP+//X1//P+/vb0/e/58ert/fP///j///v9 +//f+//z////9/+/u9uXdn5xFV1pqiJZyiZ11i550ipp4jaN3laGCkad7k6V/lKaIqrF9fphc +anhSZHJHRlFBR08/SlBESk09R01DSEtDVFVGTllGU2RTWGRJXGlvgZNndIeAl6ONrbSUrbaP +q7WRrreQprWJpayBlqiBlKh/mKR/k6SCmqd2h5pdan1ZZnZNX2xLU2pQV2ZLV2pTWW5MYHJU +YnNNX2xKUF1DTlR6m42rwrujtq5/hI6gt6nM3s/e7+Dq7+DY59bW39XDzMTV4MvZ4dXV2tXY +6tTw+ub1+uny+ubw+ejl6+Hf6Nzj69bf6dbn9tn9/+z//+33/+37/+3///P///f///L///T/ +//P///n///r///r///T///n///f///j///r///3///r///r///j///z///n///z///n///z/ +//r///r///////r///P///7///r///z///n///j///n///////n///7///n///3///D///j/ +/vD26Nfv1K3x1aby2q3536/747T85bH/77T/8L7/9ML/9MT/9cf/8sH/88f/9ML/88b/8MH/ +88j/9cT/9sn/+sr/+cr/983/+sj//M3/+s7//9D//c3//dD//tH//9D//M3//tT//dH/+s// +/NH/+s3/+s3//c3//Nj//9L//9D//9r//9P//M7//tH//tj/9tD//9T/+tD//c//+Mr/9cf/ +8Lv+5rL02qzMt5mgoXCxrH+5nniahmaPgmKWg2Xc1Z/746z86qz83qX31aHx0pLyypvuyZLv +zZr0zJHpwpPsxIrlworqvofov4/rwYntxYfovX/qxovtwIvjwofotn7jvn/nwoPpu4HftHvg +uoXasnbZsX3Wsn3csH3QrHLYp3XPp27No3PEnWbEnm7CnGm/mHC1l2O1imiuhl2nhGKniFuu +jGy1lmu7lHC2kW+zj2yphWqmh2eLh3F9kJ6BnaJtdYBNeXxQdohKgX5OdYBPfH1YgIdPen5X +dodJfHtUe4JLfHxNeoJGgIJTfYNRfohUe4FOeIJReYBSeoFFdH9QfYRPgIdNe4BKd35KeIBN +gYBNfIRRen9LfH1PcnpFdHtSd31IdHhKdoNFeXlTcH5KaW5LanJFYmFMbGhVl3OEro6grpyS +oI6arIufrIaElnhpf2xhc2dRbWRZbGBWcGFadl1khlx4l2eOm3CaoXekoXadnHmennuZmXee +lXmXlnOYj3SRlnuWiHKPiWiMhGqAiG2Cgml9fmyDeWh1dWhJS0k/Pj09QD08Qz07Qjk8QDo2 +PThAPTg/PTxAQTs+Pzs/QDs+QD49Qjk/QDw9RDU/P0A/QzdDQz1ARDlJTERcVEVtYVSEb1CM +eVugg1uxk2epi2u1kWu9pHHHoXDAm3G6k23EmXC/lWvNn3PCmWy2hGqvg2argmKed2GUcVeM +cVqTaliKaVeklWD7/tn9//T///z///////z///////////////z///z///n///n///j///T+ +//T9//H5//T3/fD0/+j8//fv/+/n/9j2/ezr7+Xe7df////4/e3x/vT7//T+//T6//L7//H3 +/+7+//v///P1//D+//v////////////////3//fx//H///3///3///z2//X39ezx9en+/fL9 +//z///f2//P8//Dy4tZPWFRki4p6k515jqN5jaSAn6iCnaqDoKyAoqaPsLeClqJlaoFRZnFR +ZXJFWmZETlRASkk9SUpBR0tBRUc+S0pATk5JUV1MWGVSbnd3lZhhb35edoGHrKiXsLWPrLWL +pq6Dn6eGnauEnaSHnqd9nKR/mKF+k52AmaRwiZVaanxJYW9MXG5IWmdNW2hKYGdNaHNRZnNP +XWxKUF1GTlRYdG2swre2xbmHlJyOqprH2cbX5tDS3NDF2sS9y8GzxLzN3MnN2MjQ5c7d8tnt +9eLm9eDg7dvP4M/r+dv7/+j8/+33/+b9/+v//+3///H9/+z///L///X//+7///P///P///H/ +//X///b///X///j///n///b///b///j///3///v///3///n///j///X///r///r///3///3/ +//z///j///z///P///z///n///r///f///j///f///v///T///z///b//+7478vu3bft16Hy +26ry4aT23bH34Kz95rX77bP/87//9sL/9MT/9Ln/78H/9b7/98T/9sb/8cr/7sD/88H/77/8 +77f/+ML/987/9sT/9sT/+cH/+MT/9b7/+cn/+c3/+83//c///s7//M///cf//M3//Mz//9H/ +/dD//dH//cf/+cv//c7//83//sz/+87//M3/+cL/+8b/+Mj//Mf/+8n/9sT/8cH86rD86a37 +7rnnxZnZzJno46+6knpkW05iWVJcVEdnbFihmm3s26f85qv82qb51pnw0pbyzZTmyovqvovq +yIzrwYrowojptoTjw4HitYXmwX/qyo/it3zfvYbmwn/mvYXmuobjuIPisX3aun3bt3vau33b +r3bOqHfSq3fMp3PPpXfMoHDPoXC/mmy9mGS9kmS6mGaxi2apg1mkgV6hfV2qj2OujGK0jGe3 +lme1jmiqkmingmihgmCdg2RbXmNmhod9mJuImqlWeHdSdXtLenxQfXtNfINRfHtLe39SfH9K +fIFPdX1Le3lNdXtJfXxRfYVKenxQeoJFf35UeohFentQeXpFeHxTdntIe3tSfn5LdHlKc3dR +enVOe3tSeX1IeHtMcHJGdnNNdXlMd3tKcnVKcW1cmXmHqYqZs4ubooiaqIG2t5a4xJq9tpyr +soyytI2yr4esroytroOrrIemrIKzq4iqrYSor4asp4aop4Omo4KkoH6enXmgonupoXyfnnqe +m3ial3aRlnGPjGyGh2iMlXCLjXWFhG18imiAg2p+h2ZzZGM4QDtBQjk3QzZDRD47QzhBRTlA +Qj08Pzc3RTg8RjpDQzs6RTlAQTw9RTtCRDo7QTxGQTtDSDtCST1HSUFPUUFoZUt4b0+QfFmr +jl6xj3GghGC8nm7Em22/oXbImXK6jnDGom/PpXfHnXDCl3i1jm61jWq4h2urhGeogWWcfV2Q +bFeIb1anj2P8/sn////////////////////////3//b///j////8//P7//H///f///j////6 +//n8//T///z////8//bp/eXl9tbg7Nbe6dfl8Njy/+rw/vD0//Tx/+31/vT///v///X0/+v3 +//T8//n9//n///n9//n5//f7//T+//v5//P+//P9//f8//3////1++7x+O3+//7////0//P+ +//b9//j9//Xq39NNU1Viiot4jaJ0i5d2j6B9m6d6lqaBo6iKqbKQpq+Ck6BgdYRTaXpNX21S +VGU/S1FFR089SUlASU1ASUM+SEtJS1BBU1hKVWNTbnlxgJdic4Zlg5ORrbWKpa6VrLiEp62I +nKh7laKBlaJ7lqGBl6Z8kqF/kaN4kaOHo6hsfoxabXtMZm9QX25NW2lMV2pPXG1TZGxNWW9G +TFpGTlJLZGeiw7C+x8KZl6F6kYmsvLK1zL/Q4tHK0sm/0cHH08HJ3MTZ3M/I2MzU38/Q38rY +4tLb69bj8Nr8/+z//+z//+/0/On//+z9/+/+/+76/+r///D///P+/+3///T///P///X///P/ +//b///D///z///b///3///b///z///b///v///n///3///n///z///r///v///j///b///3/ +//j///f///H///r///r///n///T///n///f///P///L//uf459Tt2K/u1aLr2qj13rDy4K72 +4K725LH847P95rv/57X77Lb/8sD/8L3/88P/7bz/8L//8L7/8cL/8cL/8sb/7Lb/6rj/8sD/ +8cH/87//9cH/8sP/9sf/77n/+Mf/+s7/+tD/+M//9cX/+83/9tD//Mj//Mz//c///cr//cz/ +/Mr//tD/+sr/+8r//c//+sn//sb/9Mr/+8T/8sv/9MD/87v/9sH/78H+7Lj76bD76an74LPj +ypDy+83x3st9XVlbTklSTExaUUdeVk+HlXHY25n536z63KLw0pPyypTmx4zqxI/jvoTkt4Xd +t4DkwYniunzdtX7gwIPkvIriwYHjs4DeuoHktX7iwYLfuH/gu4LcsG/VtHzUq3fWrXvNp3fI +p3bQpnHPqnbKoG/Hn3DHnm/Cl2e9jWqui2GxhWqliVuge2CZgVquiGmsimO2j2urkGm1kWqs +jGSuhF+nh2Klh2aIh3B4kp14kJx6l5yBoKZhb3tPdH9Ke3xQd4BNeYNLcX9PeHxKen1Rc4BJ +bnRSb35CdHhOc3xFeHxPdX9MeXZPdX1KcnFKc3pJcXlIc31IcXVKdHNNeHlNeXxPcXZNcnhK +dnpMcnNKb3NLb3BNb29QcnNNg3h9p46lt5ivsZmdo4uqrouvvZG8u5yvsY27tZGyuI+7sIuy +s421so2xs4+ssIKzsouurImspoSqqX2srIako4CkpIKlp4GjonyloXqfmnyjoXyfmn2Zl3uV +jnSIjm2PjXGOjnCPlXKVn3+PinWCiGuDh2t9hmt3aWNFQUI7Rjc3QjU7PTk7Rzw/QTs4QzRA +Qjk1QTg/Pjk5PjY9Pzk8QDc8PzhBRDw/QT1APz1ERD5ASTxDTDpZWkhsZEt9cVKRe1qdg16n +imuhhWO4nG/Iq3a/nHHLoHW7jXG8mXHFnHO8mXXCmHC1iWa7imuqhGWsf2afg16WcFiLaVWB +alGZh1v2/Ln7//L///H///r///r///T///X7//T///////v///////z///r////5+/T5/+b+ +//j8//f6/+r0/u3o+OPh/dPu+ev3/+3s7uP3//H8//nz/+b7//v0/e/5/vPx/+n3/u7y+On6 +//z9//X///j8//v7//v+//b+//v7//X///j9//n9//j6//v////7//v///P9//P+//X3//r/ +////////7+RQSklkgot2j6J6j6F1kKF/m6Z8naqCmKR3kp2Ioat9kqFkeYhSZXBOX2xHUWFA +SU1CSlE/SkpCSEw8SEVCSkc4SVBFSFNJUFtSbHNreIRddX97np6ZrLOLn6yKqaqInbCBl6N8 +kqKFmJ97lKKClqJ+kZ98kZx+k56Cl6SHqqyDlaNedYFWbHdQaWxHYHFMW21SXW1MXGVGT1s/ +UFJPW2SXuqTAzsWksq98h4qZsKK0wri+0cDE0MO7yru8xLrI3cPR3MzQ2M7P3Mvb69Tw9+Xq ++eDp++X4/+f///D1/+jw++f6/+zz+un3/+f///H///P8/+n9/+v///H///H///b///r///j/ +//L///X///j///X///X///f///r///n///f///f///f///n///n///n///b///f///z///r/ +//n///H///j///j///f///b///D///D6+uDt273p2KTu1KLx16fs1Z3u1Z/v2qfx26rz26f8 +4rH94qj84bH/5rX95rL/7Lj/67f/7Lv967T/67n/7br/8MX/6az/7rn86rT/6L3/9Lf/8sf/ +8b3/8r//8sL/9sT/9sL/98f/+M3/+Mn//Mn/98L/9sb/+cX/9sn//Mf//Mn//Mv/+M3/+8f/ ++8j/+Mz//Mn//c3/+8r/9MX/8r//+Mb/9MH/7bz/8b7/9Lj/7br+56j74a/63qnuzaXY0ZH8 +/uLdva9mUVBHRkBJSEVPTUhYU0OKmm3I0Y302aft0ZbtxI/qwojnvITiu4PdsoXfsIDduInh +wIjeuoHfsn7Zsn7Zu4Dfu4DdsIHeu4XiuIHcuH/ju4Pfs3nXtH7UtHTOrYHTpW7RrHjMnmnE +oW7Jnma/mm3EpGe9kWq/i2SuiWG4hWCifWCdfFmbgGGngl2uiWWrlmS1i2uukGuthmylhWGc +hWGif2GOd2Z9kpOEk6FwjZh0jph6l52Km6ZKeGxMdHRSdndRdH5Ob3dNc3tMc3dJbnZJdn9K +dHRIdXxMeHNEc3pKdHtFdnpNeXxLdXVKcXlFd3dMbXpDcXdMcHdQenNQc3pHb2tSbnVHcm9O +cndGc3BXfXh8m4SgvqCuv6Otr5OmrYm5vJvHxJ3DwZq7s5S1spC2spC0uZW4spG7tY61sIu5 +r5GssoiyrYyqrY20qYatq4CtqoeqqoSrqYSlpHWrqoyjoXymnYGjnHmenX+bmHmXjnaKiHSN +lnKSknaTj3mPkHaIl3ORk3iHhG+FhmyAhGl9dWJMRUM6QTQ8PjoxRDdDREE8QzhCQz01QTdE +Qj07QTlFQz43PzdIQjs+PzxBQTpAQDo/QT5DQj5ESD9HR0BQTkFsX0l9ck2VdlmXhV2wiWin +hmaulWq5mHCxim7CnnS5j2vGnHjFm2vAk3S7jGa8kXi2iGivhWqmemCbc12WcVuRcFl4YVKY +e1nv/L3///z///////////3///////3///////////b///r////9//r1++j1/ur///n////3 +/urx++Tq9uTe79Xe88vs9uHw9+bh6dj2//Lv/fH+//Pz/PT+/O/y/O79//35//P9//Dp9efv +++Xw++v0/vL6//P7//T+//L1//f9//f///v////3//D0/vP59+/4+e7s9eb9//r///3///v7 +//Hz6+NOTk1ggIV5kaJ5jZ52lqeClKF9oqyJpKx/n6aIpad4jJ1mbIFKX2tTW2xBTl1ESFQ/ +TUpBSlE+SUc6Rko3SEY9Sk5DTVFEU11GZXBlcYZpfox/oKOOrrSIna2Fn6eFna2GnKh/lKKG +maJ6kZx9lZ99kaB7kKB/lqF8l6GGnqqNqq2Zr7l4maFye4VZaXBSZXZRbG1VZXZKZGpMYmlF +Vlp+moumtrSera6QnZmbqaSsu7OsvrS+y7q/zbzD1L/S4MvN3cjY4tHT4Mzt+uD9/+vu8uTt +/OD3/ezv++b4++bt++H5+enk+N36/+f9/+////P///P///L///P///L///n///r///P///L/ +//f///X///b///b///f///7///f///f///X///z///j///f///b///v///T///v///T///r/ +/+v///z///L///T/+ufx5Mrr1LDnzp7ox5fozJry1afy2azx1KLt1KPy1qbt3KTw1aP21KX5 +3Kj+3Kb+5LX857D85Kr/57D/5K//6bP/7Lb/7Lz/9cT/8r3/8Lv/87r/8cX/8Lv/9ML/8b// +78L/87n/7sL/8sP/8rv/78D/77z/87//9sT/9sf/98T/+sz/+sr/9sn/+sb/+83/98r/+cv/ +9cX//83//sz//ND/+sj/8L//9b//873/7br/8bX/68H/5K7+4K774bD62qfiuonYwozr78a1 +golVSkNITEFISD9MVERyclWhtYLSyofszpbsyZDkuoTnvoXhvoPfs3/Urn/brX3Ysn7btYDd +sn/asHjbsnrauX3dtYPatnzgtX3ctX7drIDUrnjSqHbQqnzQqHXFpGzLonjOn2rHpG/DmWi9 +l2m+lGq+jWS0i2SxiF2ngFmgg1ugfFGZe1ebhVqnhWCsimWqimmnjWaoiWeZgmSYfmWZiWSJ +Z2RwlYd+iaFtkp58i6J2kKB6ip96naJecndKc3dKc3xIbnNJcXZOcHtKcXRKb3hKbnNFdHxJ +dH1Hc3VKdHREcHZLbHJIdXlOa3VDa3RKcnFFcXFJbHhCc2tOcHVLdG1Lb3RIdXBSint0r4Ob +w6KzxKy6vKawuJnDyJ3GxZ7Ev5vFuaG3uZW8u5CztY6ztZC7u466vZS7tI+wrYu1sJGwqoO1 +tYyoroexqIatqYGysIinpoCsqISnpoGsqX+np3qkoYCloH+eoXujln2Sj3aamnmQlX2XkXyT +kHKRjnSPl3GRkHSUlHyOiXWEhnWDgGx2cWNMQ0RCQT07PDQ9Qj06QTY/QUE7PzJAQDs7PDk+ +Qj09QDU7QzdGPzs6QjtBPjw+QDZCPT06QTVFRT5FSDtORUJoXkZ1ak+KdFmcf1mkg2Sph2O2 +mGyxhWqti2isjG+/m2rCn3XEmXPAlXK/iGmwiWivfWiriWSid2OedluVcVuQb1t5YlKLclbt ++6////j///3///f///b///////////v6//v5++f7/ufz/Of9//T///3////////5/u/v/eT9 +//b8//rr/ujh/NP19+jr8+Lo9tz6//X6+fLy/O/5/+/w++z9//X8//L6//P+//3///7////7 +//P9//7///n///7///v///79//X2/fH0/Ob+//7////5//T0//P///7///f0+ej1++zu9Obs +6t1PUExegIeAmaWDnK56laSCnqyJpq+Boa2AkqFnfpF6hY5TaHpPYmpIXGtVUFw4Sk9ITUw9 +TU5MRlE6S0tDR0o9TE9DUFNGUV5SbnZoe4tvhZOJp7KXsrWKn65+oKaCmqSBn6d/kKd/laCF +mKCEm6d+j6F/k6J8j6GAlqSDmaSJo66SsbWar7ybubmOqbZohZRheohgcX5acX1eaXVNaHNZ +Y3JmfHqNlZaKp5m6zrnG0cO9z73Q3s+/yrzO3MnQ29DS4M/b6dXU5NLr9t7u9uTf69jr++Hl +793r9d32+Of9/eX1/+v5/+f//+3//+///+7///L///j///H//+///+////T///b///L///H/ +//b///P///P///b///j///n///X///X///X///f///b///v///X///n///r///j///z//+f/ +/+z05srq0q3ix5nnwZPlwpTrwZHuzJr206n13qr637fw26H12Knw1p7y0qXvz5r10Jv53qP6 +3a762ar72qT81ab84Kf/6bj/6rX/8MH/88b/7cD/7Ln/7Lv/8cP/8b//77z/8Lr97bz+8L/9 +8cH97rr/67j/8rr/7r7/8bf/9MD/+8L/98P/9sL/+cn/9sX/9L//9cD/98r/9r//9sb/98X/ ++cn/9sL/+sb/98f+88T+88H/9bz/6Lr+67v96Lj636b415r+2qD106jSnniomXW4sYyObHRP +TURWa0xMS0Jkglbb8sL77NLk2KDvyZTiwYnet4zXsIHRqnvUsXnUrHvSqnbQqnnZrHvWsnvc +s37btH/bsYTatnnZq4DPsH7Rq33TrnrPrXbOoWrOqHTLpHLJqHLCnG3EnG7BnnC6nWO9kmq0 +l2C1kGutgl6mfmGegFacfmGde1Wdg2Ckh2CtkmWtimafgWelhWKNc2GCbVhrWVxmX1dkiIOE +mKF8m6J8kKR6kaB4kZR6i519lJ6Fk6FJaW5LcHtLbnlOcHVCbHBKcHBFdm5FbHJFc21QbHlG +cHJMcHdGcG9IbnVKbHBMdHdKcXdObnRNbnFLeHBNg3dZkXZ5rIiqx6i6ya2zu6Wyu5fHxZnN +1qjW06/MyaTIwKa3v5TAuZa6vZK+vJextoy9vZe7u5q9s4+vtpC1r4+1s4m3r4uur4y4ro2t +p4WyrIuvrYCtp4GpsISvpoClpn6spoKrqYGko3yenX6XlnaVo3aeo3qUn3uZnXqQlXmTkH2I +jW6OlXSUj3eVlXyLiXKJh298fWR5cGRNRUk9Pzs+Pzk9Qjo/RDlCQj49QDw8Pzg+RDs/QTs5 +QjhBQDw/PTk+Qjs6PzlHQEA6QzhLQkBBRD1LQ0JCST5oV0d3b0yOd1mgg2OphWahhGOzkGyu +hW62lWi5k2++mG3An3q8kWq+lXO+m3S9jm6vhWewh2Sbe1+ge1qcdV6Ob1OHaVyQdFDi9Kr9 +//H///r///////////////////////////3////////////////9//L9//X5//D9//Tx++rw +/Ojo/Ofd+NPq9+Dm8uHm8t/0+eb2/fHq9+v0/vT9//3///P4//f7/+3y/Or0+uvy++33+Ovr +++vw+enw/O/29+/y/fH+/vv///////3z//Dy/fH1/vv///X9//r7//f+//7///////f///Nd +UVddf3+Doax8nKqGnqt8oq6DnK2DpK6Ejp9edYZmc4BNYW9KY2xNVmdFT1pBSlM/SEw2SU9C +SUY6SU08SUk7SExCTVNBV11TeH1sipZwiZeCqK6Sp7SEpKqKn658mqiDlKZ5maGGlKV/maaB +laR2kKN8kqR7l6KBm6h8mqeBoqmIqq+Rrracu76evL6UsbqDnqpthpJkeYhfaXxWUmhQU2BV +YGaAooqlvLTW4s/J0sTG3MTY3c24zLjT28nL2crW4NDa5tLX4tLJ1MfO38vf6djs9t7r++Pr +8eLy/Of2/ur4++j5/ej9/+r+/+r///P///P///L///T//+////H//+7///P8/un///P///L/ +//b///L///j///X///r///j///X///X///n///b///b///T///T///T//+3z3tLnxrHlxZ7k +wZbiwJDnwYnozJHsxpfu0ZT21qn32qj74K714rHz1bDry5vqxZzpxJbnwZDswZbyypf30qH0 +0qL10J7316L52qn84qr/67b/7rn/9cn/78T96LX/7L3988L/77z66r3667n45bX957X67LL9 +8LX98bL/7rT87rf/7rr97rb/8rP/7Lf/77r/7rj/9b//9Mb/877/98T/8r//9sf/9cf/9sf/ +8r3/+cL+8L797b786bT96Lb55LP747D33Kr02aP33aPz3Kfx0abQpH+mhmeOf2SPi3pbXUdY +UlBPV0VVX0meuobZuZ7kxZXit4XSrILOrHfQqXjHrnPOqXvNpnDVrXvQqXfPqnvTrXvPqXnT +rXfOr3TRsHvPp3rMqHjHpnfOn3C8m3LBnmbEoW/Cn2nKnGi5mmvAk2a6k2y7lmq3jmixiGmo +hF6lgFubgFqVelubgFmegGGgg1megWaSeluNcmeAaFVoWVVST1JNUk1MeWxri4tykJd8k5l5 +lKJ9mqJ6l6F3j5twjJZ7kqJ6kqRcfHxFfnRRh39FhHdOfnpJh3ZZinZKh3lRj35TjoRak4BX +on1jooNcpoNtrYSDtouGvJGbw5mlwqGiqJijqJqospO7vJ3G1KLQ06XR1KfTzqzKwqLLyKHD +xpvFxJ6/wp++upi2vpPBu5e0tYy+u5fAu5C4tZS3uo67tpeysY6zsIm6t4+1t4qvto2trIey +sYqtq4aqq4SwroqlpIKpq4Gmon6bl36UnnWdpH2ipX6mpIOUnH6ck3qLjnaRknqMkneJj3OS +lXeTl3iMlnCHiW9/h253fWZrZV5DREI3PTwxPjc4PTg4RDc/QD40QTc5QDo6Qjo8QDo4Qzc3 +RDM4Qjw5Qzg9Q0A8QjdDQj88QzRBQkE+RThCSEJbU0R0a1KOeFuUfluwi2atkGm6lnGtjnGv +imm4m2rRonPIoHbGoHO+mG67jW+yiGyshmqkeGGhel2ee1+bdl2Ual2DZFKKdVbh/Kz///T/ +//b////////////////////+/+7+//j////////////7/fT7/+39//P5//Hw/OXz/ujx+urq +/eTe+NTi6dri99Xs9Or1//L4//X8//n///b7//D0/uz6//Pz/+76//H9//7////7//z8//T/ +//7////////9/+/8/+31/e/9/vH9//z////1//b9//r7//j8//f5+/L6++nu++zz8udXTlhb +hYl7lJt3jp96lqKIoK1/oqGCn6l3j5xsdYtPX3JPaHNMWmtLUmJJTlc8S1A/SUw8SUtBTE08 +S0g4Skw+VVZEVFtOYWxpfIp0jpmIp66Oq7GMrLKDoa6Dnah/kaF7l5yBkaJ6j5h/jZ58j5d3 +jZl1jZZ8kJyBlZ6FmaOIoKeIo62OqrCYtreju7+UsLaImqVqgothZnlRTl1HV1dOXl2Cqo2v +yLezw7rZ59DQ08nBzL/b59LAwL3E0MLG0cHH1b7U4MvV5NHf6dfd6tbs/OX1/+rv9+Xs9+Tu ++Ob7/OX1/uj//+v8/+7//+39/+79/+7///L8/+////D//+n///H//+n9/+////T///n///H/ +//f///P///r///f///P///b///T///f///X///T//+n34tjgxazjwpLgyI/kyZPmx4rnxpHq +z5vw0Zj62qT026r52qf626n42Kfz16f216Po0ZnqxJTmxpLnv4zbr37pvobtwovwwIjxx5rz +1Jj305342KT+46z+6LT+7rn/8MD/6bH75rH87rf/6bj65LD35Kz+6q3/6LL+47X85rH96K/8 +67b/6K7/6bP85rP/6Lj/7LD/6a//7Lr/77b/8bf/87n/9MT/87v/9cL97r//7br/7LH/7Lr/ +7bj+7rX646365LP75bH73rD13qnv1aTv0pnt0Jfv1KPu1aPeuI6kf2CBall+eFx+YFNdXE5S +VUZ0h1Ofk3vQtYrWrYTQonvJrHXLoHHDoWzLqHbLpHXJpXLNqHTNrYDHoXTFpXjHpXDLonvE +m23Hp3TMo3THmWnInHG/oWzCn23DmGnEn27CnWavl2bAlWywjmmvk2axkmGskGmki12piWid +gFmjflySglqcgGGPf1uNdGBzZlZpU1BZVk5afmB4pZeDpJl2jZd4kpd6jZx5mJl7k5yEm6F2 +l6aBl517naZ9mqN3maF7mqOCmp+xxqzI0bHK0bTC0q/FzrS4vZu6vaC6vJaxspWqs5LJwqm0 +sJSelXyFinCzrpahpoanrIWrsIa1u5DQ1KXa2rLS1KzT0qDS1KPMxJvR0J7UyqLKxqHHxZzD +xaDIw6G9vZrEv5a5tJDDuo69vZK9vJSzuZGztIy1tpW1rYe7s4y3sIm2tIuxsYawrIevtIe1 +r42prISkpYGcnHudoXqaonqYoXmeqoassIWmqIydoIKRknmNj3SVmnqXmX6QmXyUnXiVnX2S +mHWKi3WUknV+gmt6c2FpcFtJQkQ4Pzc7Pjw1QTM9RDg3RTc9QDg9Qjk/Pzc8QTc7Pzw9QT89 +QTs+Qzo+QDc/RT1BRTs+QzpDSDxNRDxBSkNWTz5tZk+IeFSUeV2lhmKrhGauiGaojWqnimey +jmXClXLJnHLBl3HDkm/DlHK4j2uxiGWmfmSfgWCcdFeTdleXcVeGalWLb1TT7KL///f///// +//////f///////r///v///////X///T+//H+//H///f///z+//z8//L5/vL2/+z3/vLk+ODg +9c76//Dy9eff8drt9Ojt/On5//35/e/z9+zs++v9+fTx/ur+//7u/vX1+ev9/vz///fx++vu +9OD9/vT8//z///v7//j6//X+//n///z19+72/vj///X9//7///////////Tu9OBdUmFYgX+N +n6x6oal7kqVzjp59lKl/m6V9kZ5fbHZQbnRVZ3VQYWpKWWRDS1NBS046SUg9TEtASUg8SkxC +SkpDUlhGT1tKYWxibXt1mpyKnqeAnKeMpK+AmKF+iZlviZh7iJh5lp6On6R2iJFxc35XZnFb +WmtjZW9rfH10hZN+lJyFoqmMpquYr7iat76NpLF8jJlrdoVNVWNOVlhMYWtvj3vBzsa9zMC8 +x8G918DI2MqxvbDEzcCzw7G7xb7DxrfA0MLS4crT4tTb49fi9Nvl9tzo9eLs+OTv+uTz+ufz +/eT8/+r9/+/8/+34/+n4/+z8/e38/+v///P///b//+////P//+/9//L///r///j///T///T/ +//P///n///j///L///X///r///T///P07dnixaTfwpHjv4/fwInmxZDkxZLowYznxI7z1KLu +1qf42aj20J720qTuwZfz1Zj10p/22KXr0qPkypfsxp7mv5PiuoLouYfpvobvz5buzZr00qD0 +zpn41Kb436T85Lf667T957f45K3636355a385LX84q7636j56rP857f85LH83a7+4ab66rD/ +4az84av/6K795bH957H97LT97bj+7Ln+8Lj/7Ln/7rT/7rz87rb/7Lr757H85rn656/+6rn6 +5K723q3x26fv4LHz1qjtz5/t0J7s05Pt0Zvq0Jnny5rWt4+whmuHbFhnZUp3dFyLjmWws5mN +emmPkGTJrnzIoHO+m22/mnG+m2rInnHBpG/MpXTIonLJonXAo3LLqHnLqnbLpnjJqHLDoW7H +pm/JqHLGpHPAm227mnC+m2+/nG26mXO/lmy1jmiwjmqti2ekiGaphmmnhmKnh2uXhVyif2CT +gFmUeGmKbVhrV1tZS0tKS01NTkhGVVFkgYp6kZiCmJt6lZ91kJl8kpd+maB8l5qAnqSFp595 +mKRwlaB7nqiGoqN4lZ+CmaGNtJnEzKrBzq3N07a+1K7Kzp/FxqbHxqPDv6PMzqrN17TZ2LrN +1aXT0KnBvJi+yZzJxqG3r5nBx5vS0qfQ0KjX1KjQzaLLyqXLyp/GzaTMwqDEw53AwJzHwZzD +wZm/vpu4v5PDvpy3uZC2sJC5tIuytYe1sIqwtpK7t4uztpK2r4u1rouytZS0r422rIalqIOf +o36fq4Ksro2lroucpIGVn3ufpYOfqYCfoYeNlnmZnHuaoHqfpH6bmnyPm3qUmXORlXePjneM +jXGLlm+Ef3JzdGR1dmVOTko9PDw1QTc8PjU0QDY7QTg4RDVDQDs1RTlBRTw9RDw+Pjw+QTk8 +RDg3QzZCQDw9Qj5GRjhGQD5GR0JGR0BSTEBqZE6Dc1WPe1mngmOkgGKsi2m5km2rf2ilhl69 +kGq5km7FnXa7mW6/knKsi22zgGejf2CXcFqLcVGYdFuLZlmHaFeSdVfZ5qH///n///j///z/ +//////////////////////////////////7///n9///9//L///n5/+z9//f///j1//fg+M/q ++uno993i7dz////7//Hx/Of3//j2//T///r8//H//+/3+/X0+/T0//H8//X+//z////s/efk +3sb6/e3z/u////3///v7//b9//35+/H9//X9//v9//j///n3+en8//T/9+tcUmRijYx7pKyK +qLB4lKV+mad4kqN9l6R6iJpbZnRSYnFLXGlGX2lFUV5DSlM8Sk1ARlI7R0c/SEw/SktDSlBB +WF5LV2RZhoaAkqJmeIyFkp6BkZ+AkZ56iJZsh5B3jpWEmZuKoaaFlZx1jJR6io1ydn1cUVlH +SE1JSU5MTFReVWFpenqGlZaPr6ybsLR9maNxi5ZmcH1MTllCVVNSXWKJrZjAzcS60bnT08mz +xbW7v7amuaqot6ixvbDD0L3Fy7nB08LQ4sTV4s/a58/l8tvm89vu9+Py/OXv9eLx+uH0+eTy +/+P4/ef3/+T7/uj1/+f+/+7+/+j///X///b///X///P///P///H///X///j///H///T///X/ +//P///T///T//+///+v+8+Dfy6jdu5TiwY7myJfrx5DmwIbryYvtyJXjvIPqxI/mzpjxzJ3x +zaP00KPzz53yxpTy1Jrv0KHu16fs1JzmxZHeupHmxI7mwobryZTxzZjyy5X0yI/ty5Hww5by +05j32ab02Kj55LP54af83q7156774K7336f536z55LD74Kr65az/5a3/47P94a/93K7446v/ +5ar/56384qz95rP96bH86a/+7bb76bL96bP96bf67LH87rj67rD86bz45a/767X456/226js +2KLx1KXrzJTtzJvpz5zn0Zzp0ZfjyZbevprWt4rJoHuefV6EbVZlY0tpa1N4dVx0Zl5nXlGT +lWPGnne4k2W/m3TAmWvCnnO+oGvLqnLLq3bKp3HHqHLLqnzKrHHLqXfJqXjEoXPAp26/pXHF +oHDBm2vKpXbKpXHDoXq9oWu8mW+3l2mxjGqsj2GtiWWrjGefgmOoh16jhGacfWGWfGGPcFZt +WlNdTklKS01JQ0VGVEhTiXhyfoFKaF55kpp6l5+Blp18jpl6kZZ5lI6Cjp9yjJJ7kpl+mpuA +n6R2mZp9nKR8mZ+InKeCm46rq4y2uJW7vpjCyJzGyZfY2LPd4rTe4Lrl4L3d47rh4rfg4bHV +yqu2q4yzuJC2sZSpp4O7y5vT1K7U06HZzKzLxKLSyqbKypzQx6DLxpnPx6bAxZjFwZvFxZjD +vpm7uZOwvJe9s5G7tYy3sou1tY29upK1tpSytI64toizs4+6q4qqp4anpH+dpH2krIarspGw +qY+WpIKeoX+Wpn2joYCdo3qXm4ecnX+dqIGdpIaZnoGVmX2QlnaTl3ySlHuJi3eOjHKHiXCL +km+DgWxxdWN1dWNgVFU9QThCQDo2PjVEQT02QDk9QDs2PzdBQTk3QjVCRD44QTRDPjw6Pzo+ +QzU9QjlCQjtCQzpAQztGR0BCR0BOSkRkXUh6bVGWhFqoiWSvjGe7nWu5lW+whV6ufWGxkGLE +m3LGlWvAkXXBmWu3hHGqfVufeWSRc1mPc1SRcluPcVKPbFZ8bFPQ55j9//L///n///b///// +//7///j///j+//X+//X///////z///v///////r///z6//T7//j4/+/8/+7m8t/c8srh693q +89rn9OP5+eby/vD4++ft/Ov6/vDt+e/+/v70/+7+//z///n+//7////2/+z09/Dt/OXk3Mzp +++////77//X5//f///v9/fXz++78//b09+j29+j3/fD///v9//Xy9OdeWmxegIN3k59/lqp9 +maiAm6eBn7B5fJBXYnRSYW9LXm5RWmpKWGRMV1xARVFESVFDTE5BSVI/TU1DSFI8SUxMYGZI +XWRtlJqAm6d7iKB3iZZ2iJVwh5N7hpR2jJN+kZmCipKAkJiBjZV6fIVpWmtjVlZiWU1MTkZD +R0NIQ0ZDREVOSkxNTVdoanOAk5GKnKh1h5Jqb4JFTlBKUVhRaWOSsJq4xLq3xLy4vrqsuK2t +tq2ns6Wps6enuKm/w7i/y77C0cTU4Mfa4s/h6dfj69bu997j7tno8+Dv9+Hz9eLu+eD2+eT1 +/+f//+7///H///D8/+n///L///f///f///T//+7///L///D///f///j///f///b///T///b/ +//f///H//eft4NLdwJzYupbkwIvuzJntzJXryZ3pw5DkwY/jvoXlvJLeuoHqxpnoxY7twZHo +y5Puz5vuypTr0J3r0ZnqzqLryZzfw5LhwZPdwpDbuIXhwozsz5jt1qPy0aHy0Jvrx5vy1J/5 +1p/21KL13af22qT2263836764qz847H13bH636n847b85q374a774K/84K774av83Kf546// +5rL75rH84a385LT96Lj847X137P04bD247X247H03q725LD03Kzz3qny16ry2Kfw1aLnzp3m +zZfkyZjmyZPgx5XjzJnew5PZuIzRs4PMrH+7lHKTb1t3ZFZjX1RiZE1eXFFjYE1ubVe0oXK+ +oXm6l2+8m3PFpmzJpXfOrXTLpnPRroDLqXnQqnzLq4HSp3fNpn3Ko2/FpW7CoGvHo3TCn3XI +pnbDoXXDoHS9o3C9mXKvlWu2km6ulWGtj2+skGeriWmjg2GmgWWcfGKReGeCbVldTU5KSE5N +S0hFYlhTgGVsgIRxk5l7j6BYWVxrlo+AlJmAmp6Ci41zkJF/i5h6i5d6kJ14mZt5j595kpmE +lKZ5kqF9i5t2iZmLqqHV3bTg5Lvq4r7d37bb3LTZ4Lnb2LDW06zZ2K/Y16rQ1qnZ1a3KyKmw +qIuntImzsZWepX7Ox5rTzJ3SxKbQ1KLVxqbVzaXLwpzNwpTNxaLDupTCv5nBu5K9uJPAvZS7 +tpm/tpG9uJHEt4q6vpW7upS9uJC4s5K1s425sYisqYqdon6lqISrtoyxspKjq5CtrI6erI2l +pYKep4OcmHuQoXeanX2jqIWpsY6joYmXnXyWnXuRmXyVlYCPk3mQkHmFjG+Hg2+DhWuLjW58 +e29zbl9vbGVeUVM8REE8PTc8Qzs9PDY+RD47QDc8QTw8QTM/QD5BQzc8Qj0+RDhBRTxBQTg6 +PThBPztCRjlBPzpDRThJQj9ISj1fVUVwYk6aeFypi1+5k2y2kGrEmnW9iXG5ima1iWe6jGbD +mHHDmXO4h2u1jmuxiWmsfGSabFeEa1STa1qLbliFbFeCblTL1I/9//b///////////////// +//n///z9//n8/vH9//L///r8//b+/+////v///b9/fL8/+3///72+url9ePj98/s9uXo893h +8Nz7//Dz/+74//H///j9//b5++vz/+76//b+//v///n9//z5//P8//X7//jy/fDx9ebu/e7t ++uLy/Ov+//z///n4//v////7/+/9//r///////bz+en+9/D09OR7YHhVcnV3lJh/lKWLo612 +jJt3iZBodn5SXGZMVGBUX2dRX2xOTVdHS1hET1VBUFJHU1k9UVZLUFlCTVNJWmRbb3lggYhr +iJt7iJqEmaaCjJ12hpR5jZV8hZF6ipB8ipV+i4h9eHpva2KId2KXkmilkXWekXOlhm2ci2WL +eldrZ0lPR0hHRUhLRUhKRk1iYmJ5g4lseoNOX2ROT05mfHWInI+krKels6eos6eiraCktKei +rKartamru67AzbjU4c7R4Mva4dLY5c/n79rj79jr797e69fr8tz1/Or//+n6/+b6/+f//+z/ +//P///H///H//+////T///T///X///H///L///T///b///X///b///P///P///D///D//+n3 +4NfSuJbbtYTjx4/rzpzpzpzz15/x0qDtx5bvvpXcs4DfuIjiuX7lvozkxIbsxo3pw4rry5Lt +yJXpxIzlx5XlyI3mx5Lfw47ctI3PrnjftojiwIrhuoXiwozqyJDrzpX01Jrv15f42qP02KP6 +2q763Kf72ab02qL72KP426X536f53qn13KT34K374q/446r526n53qb32qf23ab74ar24KX5 +3qb026fz2qnw2KL02Kzp157r0Kjqzpzt2azx16Tt1KDs0KDr1pvt0p3q1Z/ny5fjwJfcwozg +wobfw5DixZbhvpTavo3ZvYnbwpHXvY7Xt4qoe2N7bVdwfVaGil6KhGiQhG2unXTJpHvIp3nP +rXrKonbPrHPSsH7VsYDUrn3Urn7PqYHKsH3Mq4DKo3POroHNq3/FqnTIrYTFp3XKqHrFqH3E +onPBnW2+m3K3lG2zkXGwj2ezknOnjmuliG6hhl6dhHKdhmqMiGt/eXB3fGx0hW1Sb1dcgINz +jI97mZ58j5lnh397lJp6ipNWXllebnx6kpqDoKGDjZlyiouAmJyBk56IkJh/lZuJlZp1kZuB +jpV3j5V9k5WNoaHB17Hg2bbd2bDc27Db2rDc2bDR1qbY2LXW3LDW1Kja16rb06nHxKWsnISk +rIenoYaorYPK0Z/V06Dc1avSzqnb0qbSxqTJxJ3Lw5/OwKDBxJvMxJm9wpm/wJy9upfEvJW5 +t5PEvpu9u4vCv5Gzt4q8s5GqpYeinoals4OrrI6xuZCusJOqtJGsrYqrsYmssIufpoCip4Og +oHygrYGssYyvuJWopYmbooOdp4SZoYWQmXqRj3mOkneMh3OJimyOjGyKj2qRi3iFjm+JgHFg +aVNrbFZdVUxCRD46Pzg8Rj4/QDdCRDo7PTs6RDY6Qz49QDtERDo7PDQ9RTc/QThAQzZCQjw+ +RThGRzpBRzxGRD5ESD5MSUBbVUJzY06WgFapiWOoiGS9lG63lW+2i3C7nG7AlWvDmXLAmW7B +l3C3j2m0iWilfWKrhmKphF2Wb1aLa1KQc1WIbFSGakzVzYj///n///////////////////// +//////////////////P///////////z///bw9+Pz++bp9+Ly/ubo+uLo+db9//3q8Obi7tn0 +/+vy/vf6/vzz+O32/vH5//L9//n4//Hu+er1++nz8+fx9+T3/fr///z///7///3///7///3/ +//z///////f///71+O3+//X+//b8++v0/fb///n9//7/+fmYXHNWam1qgpZ1jJl2iJp0kJVz +iZdldoNWWG9DWWRTVW1GUGBASUw8SU1ESE48S09CTFQ9T1lHU11HU2ZRbHd1jpuAmqV3h5Fz +h5d2iJ17iJJzhZF0hox6hIl3gImIkpiPiIeVimynimynlWysknakkXKmjnygiW+iiW2gjGuh +iWuQhF+DdlNeV0ZGRERLRkhaV15hbm1aZGlEU1RmdW+LjISboJSpsKGntqSZppqXpZqns6Sz +vK67zbrN2M3N3MnZ5NDb4M/P2cXa59Tx9d/p9uDp8Nvv+uT//+7///L///H8/+3///T///b/ +//b//+3///H///P///T///f//+////P///T///H///T///P///T//+z//eju38/euqjWtojk +uo7jxJPyz5jt1p3316Ht2Kfy1KPs0Jftxpbet4LhuYXiwI3gwInpx5Lry5XqxpPlxI/ivYzb +tIPPonvBmXfKm3jfwYvnz5bs0Jjsz5Pt0Z7xzpr11aX02aX20qbx05v11af226j526z526j1 +16r52ab43Kn83a353qz337D52aTz1aft1Krwz6Hx1qXy1an32qH02qj11qf02qXy2KXvz57v +06bt16Pu1qLx153zz5rq1J7t0KLu0p3x1J/t0aTpyp7o0Zrqz57jxJfbwJDevpLZuYXXu43U +wIvexZrexZPfxpbnz5fs057n05/Tr5aZe2WMhmWennuorH6uqZC+rYLOrIjSsYfOroTQsorX +sofUrn/RtIDRsYjPs4jXtI7PqH/IrYbHqHbKqH3GpHzHq3/EpnXDqnfKpXXCqHnGpnjAon++ +oHCzmHW2mXesj3C1j2umkG2rlHKjlm2dmnGflXmjmXyZm32fnoiToZCdtKGqsrF9n52Hm6Z8 +mJqJmad1lZl8kJp+mqGDiZlliIRiZ3JqiYl6j517n6WEn615mZd9laCCnKCGnaB8mad/n6J6 +m558l6OKn6jE1abX2LHc2bDa3bDd1KzZ2K3d1a/R0KjX0qzNy6La0KfR0aTHu56kmn6qrYij +p4OiqojCzJ/a0qPTzaLNxqLLwJ7IxJ3Mw5++wqHEwZnKxaHEv5y6upK9uZS7vJC8upW9upm3 +t5WxroyhooWkq4Kor4yutZOxs4+tuJWutpO0sZqosIuwsY2vtoyztZOnqYefpoGjr4aqsI+x +uZK1uJmproq0s5Kaln6LkXeKjnWLinGMjHKGjHKKiG+NknOTlXiSk3ePkHiMjHh8c2pnZ1Jj +a1dfUlE2QThAPjg1QDtJQT49Qj88Qjs7QTpAQD1CQTs8QTlAQTs+Pzo+QTc/RTs+QTpCQT5B +RT1FRT5DQjxHS0FKSz1XT0VyaEiPel2ig2Grh2+5kmyzjHK6jmesjmvBlXHDoHi/k2+7lHGv +e2mliGesgGSdfFyke1+MbViSaleHa1SFalKGb1POyYL+/+7///P///3///n///z////+//n+ +//T6//b9//T///////77//T4/e36//H6//T////8//ny++fn+ubo/drm8uPn+try+er//+zt +7+n3/fH4/fH9//z///P4/+77//L5//r+//7////////1//X///7///3///z7//X///z///31 +/+30/+39//v///T+//v///////37//H9//r7//Lt8uCdZHRafXNmgo9mcoVleIdje4RabX1k +dYVQW25TXG1LUGBLUFY/SEZCR0w/SUlITFZAUlFJVVxBUVZMUGNNYm55i5ZtgYx2jJV5ipd9 +jZ2EkZt7jpqDk5aCkJWInp2RjoalmHC4nXaxmXCzl3Oxmm6zmXWmlXCulXGlkWymk22nkWui +imybh2OWgWJ8bk1OTUVDTUleZ2Jib2lSWF5fbWWGjXmbm4ueppSco5CaqJOntaKtva26y7PH +1cDJ28XX38rg79Xg6NTU38jv+Nr3/+f7/enu+t75/ur9/+3///D2/+b//+3///L///L//+3/ +/+///+7//+////D//+v///b///H///T//+7//+///+7//ez16tLgxajZr47asIDjt4LpxYjq +yZb02qH226/02qPx1aTqxpbtxZHrxY/qwZbnxYjguYbguX/jvYXkuobTqXzIm3eyiGyuiGfF +n2XduXrnzYzs05zy3af04LL34bH13aL21aX12J321qj02Kb32KP32Kj72qb22aD62aL315/8 +2J343K702KL21KX12aT22aPw1p7y1aLp1Jjs15vrzpf005bw2qH136ny2qf23KHu1qPt0Znt +2J7x3KD23qjy1KLy2KLu16Pr1aHp0JfmypPlyZLiyJbgyJTdxJHcvo7WvIzQs4TRuYjXxJTi +yZLly5npzpvy2qfm0aDKqYutmnW1u5XGyKXKwKK/q4/CroHLrYHVtoDVtofVtojRrn7Ou4HT +tYTRsoTLsYPQrX7Hqn3JrX7Hq33KrXzKsIDMrHzKrIPDpHu/o37IqH++pHbFoXm5oXa4nXWy +lWuzl3qum2m1oH2voXKroH+mpXittYrKyaPT4LbN0rfIzrG4vay2xrTAz8OSpad8lqKCoKV9 +qaqQqah/n6B+k6h7lp90i5hrjJFyh49leH9yaHpWY2ZpgId2lpeDjpl1k5mEn52Bo52CpKSB +laODpaKzz63Z2K/a27Hd1q/Z2KvU1Kza3q7Xz67Z16nZ0avV06fX2au+vJqbmH2iqIKipXyb +rYDFy53Tz5/TyaXIyZ3LyJ/Qxp3EvpzMyJ3GyJzHx5m9v5a9wZTAwZa4uJKvq4+lpoKjroOq +t4ittIqst4+7tpKptpS7upOsuZK6tpSesYyvs46lrIuyso2nsI2vtYunqoqquJOqsI6stYqt +rpOoqYSpr4iil4GFgGyCjmaMh26LimyOi2uQlHKXmXiRmnSVlW2NiXGDiWl0amdmb1Vna1hU +TEg7QUI5PzU7Qzo/PzU+Pzs8QDQ7RDY8Qjg9SDhBQjo4QzRFQjo4QzU+Pzg4RDQ8Qzg9RzZG +RT9DRTpGST9AQztUUD5zbU6MeFmYf1ysjGS2lmu3kXClfWSfeFq3iWi8nXHDmG+3lXWvhmuh +fFyriGCnfF6egVuTc1uJbVCKa1F5Z0qGbFTRyn3//+////////////////////////3///// +///////////x/uz6/+r8//L7/+v///33/+z8/+v8//Hr/OXf89Hn9djn8eDe68/////7//Py ++uz4//r+9+vu8+v5//L4/uj1/PL7//f+//7+//f59e72/Pj4//P+//z///vy+ev3/PX+//z/ +//f4//b9+/r5//j+//T7/vX+//f9//P7+e/09OezZXdYdnpteotbeIJngJBkd4VlcYdjdYJQ +X2xJW2lMUVxBUFFDRE4/SkNCSFA8SEdJTFdDUVhNU2FEZWpPb391iZNtdYtxi5B/ip+AjpSC +kZyHlp2Ik5aPkpOdjYKzl3OwmHKzmHe6n3i+o3q8nXezmHW3mHm0kHOxj3Gvk3Kzlnark3as +j3OdiG6cf2mBc1paUk5PVltlZ2tdZGVXWlyDhneZn4eWoJSdpIyfpJqbq5u0wa/CzbvP3MbS +483c5NLu+t/v9+Di7d35/+X9/+/6/ej2++X+/+v8/+37/Ob5/+n8/+b5/ez2/+n+//D//+z/ +//T///T///H///T///H///L///D//+z//+r7993jzsHYs5TcuYnnwZHrvI3owInqyZXxzZr2 +16fv17Dy1qbw0J3tyqPpxI/hso3arIDYsoDWrH/RpHa/kXOrgGWrh2fDm2PYtXXgxIjxzZny +1pv23af13Kn84bL55q385bX45q/93rL52ar51aLx0J/52KD61qL3zZbzxpr0yZbrxpXvypnx +ypzxzZfv0pv02KD11qH026Pv26T326fw2J/116b526L43Kj63ar63Kb23KTz16fy1J301Zru +1aDy26jv1qLp0qHo0JjtzqLjxZPixZTdwI7ZvpDYuZDXvInTupPPr4rNtITWv4vfyJfnypPs +1J3t1abgyaS5mn2xrHvT0a/Qz63MuKHIs43Sro3JsIjTuYzTuYnTuY3NtIPPsI/IrYXOtYjL +sYDLsXrHrYHJroLJqX7KsoDKr4PHsInHrIXKr3/FsILMs4rHq4fBpoK7qH26pX22pn2toHys +oXe7qIG0qIO8sYi8xZ7a473m8s77/t/5++Tv8dvZ4srS2sfF1MnE08KztrmPoKSEl52BoaeC +mqWMoKx5naWBkaF7kZ16kaJxjZeCk6Vyj5hPS1VET01QTV5UU1xhZnR1kYuDm6N9jZyEpKmS +ra6oxqbRz6za3LPd26/b2Krc3LHb2bDR0LDT0arb0afc1K3U1azFt5Wdm3qsp4KWmHugqX7J +zpnZyqXPz6bRy6TIyJ3SyZ7GwZnIw53CwZi+upi1tJarqIWrsI+vvJG4u5m6xJ62vaKwu5W3 +tpWutoy1vJW3uJm+vpqvtpKvt5GttpSztpOysoyxt5OvspixuJaptJGssIuqr4+mroqfsIum +q46mrYivs4yMinGMi3KRlHOZmHuPmXiboHyWn3uXknmOjHGGf21+hGlpYmFgaVNoaFVTS0hA +PkA/RDxDRz9BRDw9PztBQTw6Pzo/QDs9Pzw/QjlAQj1AQzk/Pz08QTpAPD4+QTpBQj9AQj9J +RUE/QzxJQj1STkBqXE9/cVCggGCcgGGwiWWvimi3jGurhmK+kG26kHLAmGy/kHW4kG2dfGGm +fmSifGGZdV2PblaQbFiOclOBZVV4YlDJwXf///n///3///////////3///////////////r/ +//z7//P///7///////v7//T3/ez6/+33/u3z/+jp/OPg9NHp89/l7t3j8Nry/+r+//Lz+Oft ++ur1//L3/+v9//j///7///////H9//P7//n///r///75//T4//T7//T///v7//X2+O/9/fT5 +/+/q7+b9/fD6//j///7///z///bz/fP///nKbnRRXmJZa3BZe4JxiZJXeYFof4Zbc3ZVZHFN +Y2lLVWRATEw+RUs/SkM9SUpHTFI+YF1EWWRScXlNYHBPdnxwhJFwi5l6j5h6i5GEj5d9kZGA +fn+FfG+diGmyk262mm+7mWu6oG7Bn3O4o3S/nW+3nHW7l3K4nHa6mnGwnHCxl3KvmnqvmHKs +kHCijGubhml/cVVaYVZbYVpXZGRTWFh6iXOhmImYpYufn46Xo5CcpZO5z7LZ48zV4czZ5dHi +8NX3++Ho8+Dq9dz3/+X8/+zx++T1/ubt9+Lj7tfr+d36/+b6/OX5/+f//+z//+3//+////L/ +//H///b///L///H//+j//+f3/dzu483StY7Vs4XbvYfox5PoxZbsw5bjuoXpw4blxJXuzJfs +0Z3typjpypLmw47ewIjWsYPHnHmse2icemOkgl66mmfVrXTdvYboxY3uz5Xy0pj01qH64qn/ +6az436j56K//6rP64q7+5bL84LLz16nvzp/wx5nuzZPwxZjrxJbnvozmvInjuojmwInkv4zv +zJf03Kj23q352qnz26b24KT646344a7w2aT33qv02Kn53an32Jzv1qPu1Znv06bt0pvv05rp +1Znq1qTizJPiyp/exJDbwZHWu4rOsoXMr4THsH3Fqn/Bp4HErHvQtX/WwZTeypnczJ7ez6PU +wJK/pomytZO/sJDDsovMtI7CrYbNt4zIsX/MtonKtZHPuY7NtonPtozHs4nHsILKu4nHtYnK +s4XJs4nKtY7Uw5HdxKPbxaHdy6Di0qPeyZ7XzqbVwp7WwZ/Hsom2ooWonnasoX6hmYC/t5LE +wpPc3rrr88X3+t/5/uH5/+v//+n9/+n5/d/j7djc5NPT3b7X2829y8SLpah9opx7l6Z8l5qB +maqClqJ2jJ99lJl0jJp7ipFsl5J6jpZej45Zc3NMbWdNW1NATFNWYVdrjol/lJmClaCCmZyU +vZXY3KfX16zN1Kjb06vQ4afU0avU1anY0Kja16/X1azV0qW3sZOQmXSfqYefoH2Ypn/GyZPK +yZbLyKDEw5y+wpC1sI+urYqrr4ipsI+yupS1wZq0waKwvpq2wJ6vvZ66v5iut5iwvZa2wZe7 +vp+4wJu5waC8x6CztJumsYeyvZWytY2tu5Gvt4+zuZequZKps4yor4qor4attImfsY6mtpWk +rIqrqomkoISan3iaoXyXoHqXn3+VnnuWl3mKjG2JhGl5fGCAgGddaFVibFNobFJLSEo4PTU/ +Rzo7Qzg7QTk1QjY7Qzg6Qzo7QTE6Qjk8PztCRD1BQzk6RDc7Rzo5RDo5QTo6RDdCQ0A9SDhF +SDxBSjxTUERkYEZ9cVKcgFqpiGapi2O0kG23lm26jmy+oHO5jnCzkWi+lHS4jnGddF+aelyg +eV6ScVqXdVeNcFKEblB/Zk9xYlG5vmj8//H///////3///////z///X///33/+z8/vT9//D/ +//b///X///3///P///////nz/uzu/eLu+uns+ufw/9n7//3p893p9973//Lz/vH9//z///r/ +/vb7//b///Pw/9/+//z9//X+//X1/ezw+e74+vX///7///3///n1/+z7//j///j///T6//H0 ++/b9//v//fT5/vL7//jz//X///r7/enXdoFDSD5LSklCSUZJUVZNZWJRaXJwg4tcd4FRXXBH +VVpEWVs9R09CSEpEUFVHTVJMVF5KYnh5iZpdXHRXdn12jJx/i5d3jpiBg4V9c2ugeWOkh2iz +jWeukGu9lWy6nXDDmmy9lnTJqHvIqHzDoXTBoHfCp3u9pH27oXi6pXq+pHnAoHyxnHi5mHSu +lXKtkXWiiG6TeWdxYWJVW1ZITUxvdVyclH2Yl3+ipI7Fyqq1tK/R1sPK2sHU38nZ4c3r9Nru ++eHj79rr9dvu+t/f8Njm89js9drl8Nrn69Hx99z//+P//+3///H///L//+n///P///T///P/ +//L///b//+3//+b5+NfXyajQrXzXtoThvZPYuYDevonkuovnvo7ou4fasoLfsoDZun3fuX7Z +u4DWsnzAoG67iWrBnH3QsJ7Ep4PXqHrgv4jsyIzuy5Ty05v21qv20qT42an74a/85bb/5br9 +57L+7r797bb767r45Kz526nx0p3nwZbnx5DmvIreuoDdtHzesYHluYriuorpwZnsypf42aP3 +4K373bH43bP34qr54av34LH747X63a723qT016Xy16H005322qvz1KfnyJDpz6DjzZXryJbn +zJbkzJXjyY3bu43Ns4HGqYG5onaxmnitlm2rlnWomXW0pX69rX/Fs4HHvY3HvZDUxarl1rv1 +39Hqzr7ewrDcvKbbvazbvqbbw5vkyK7syrjy1cPx1cb52s3t1MLx177s0rvu1br27c7+8tr6 +6dD/+Nr//+H//+7//+///+r//+7//+j//vH//ub+++Py7NHs6c/j3cDZyLjQ07ng48zu9t75 +/+P//+j//+P+/+v1/+T//+7//+/+/+38/OXp8djr7NLR38/U3su6ubmVrrCSpayMmaF/n6WJ +kqF6o5t+jJlxkpp8kJd6h5l1lp2Bj551l5x4h5hmipN+iZZcWmpLWE5YjnV/k5h7pKCXvJXR +1K7Y2K7U0qvW0arV1KrY3LDb1q3Uz6fU3rHVzabVz6u2rI2VkXqdqYGhpH2hqIGutn6ron2t +pYCyrIq0s5LAup+3u5G5t5m6u5O+xKC9xKq4v6G3uJWquJStuIy0vZSvupe3xZrDx6y6v5+6 +v6KwvpiwupSysp2ssoyvtYqzu5mtvJKtsparspGnro6qs4mssZSssZCrsJGmsZGqtY+vtZOr +qIyutI6goYWXmX+UnHqTmnSVmnSQlHSMiG59gGR2cWJrcFhnalZze2B3c2ZFSkhAQzw2PjRD +Rz41QTY/QD44Qzk/Qjs4QThBPjo7Qjk+Qzo8Pjw8Qjo8Qzs5QjVAQz49PTw+Qjw+Pz0+RTlG +Q0BJS0BnWUp8ak2dgl2hiWG+lWy0hXC3i2q1jXG2jWyzl3O1i260iG62iGmtf2SyhmSpfGSW +eF2QbFmLbFWGaVJ6XVNyYEyss2H3/+n///////////////3////5/+7///v///////7///// +///9//D///v///3///j///79//z+//fs+Onc9M/i99zu++Hs9eXv+ujs9uX1/fL4//P8//X9 +/vz///f5/vH6//j7//L+//H+//b///3///n2//Pz/+/7//v1//X49vH1+efz+fD7//z///// +//v+//z9//T///b8//P///32/+ncio9FRkFDRkhDREJAQkNDREVESU5PTVhXZ25KTFlLTVJJ +XWFFRUxBRU5MT1Y/TVRLUltFV2VyiY1odHtbZ29jdXZxa29mX1+IdGCUe2Kph2Ksi2WxkmW4 +jm2/nGy3lW2zkW7CnnTHqHHNqHrEpXbLqHzDonm/nHHBpXi/oHnAqXvBp33ApHm+o3q6ona7 +mnSym3Ovl2+dgWhxYVhMTUtjaVuTinqhmH+kqpPO2MHAxrjM0r/Q18Xj6dHO2sje69HZ58/b +5NDa6NLU3dDW5cvu9d71/uf6+OPa08a4rY7Q16X4/tv///H///D//+v//+7///H///b///L/ +//X//+z89tve0qbUtITduXjbrX3Jom7Kl2bCkl/HlGnTqXjbsn3bq3nUpXTUqXnRoXq6lm+6 +k3HRvZPawKfUr47Wr4XetYnsw47pyJfz2JX32ab52KL62qX74rL947f/4rX967r95bb44678 +5rb647H236/u1qb10Kfrz5fpxJffu4nhuojctoPbsYDat4Xit4rkvYvpu5Psy5fy1qX53qn0 +3qb55bP35a334a304LH14K3z3a303K/wz6Dw1Jv12aTt0Zvt0KLlypTnxZPo0pLqxpjozpfo +y5nauofMqYe6oHizl3iwpHq9ro2+q429p4a1nHy5qYTLvJDUyqfe2bLt7M7+/+X///L///L/ +//H//+v//+///+7//+7//+j//+z//+////P///H///H//+3//+v//t7//+v//+H//+L//+b/ +/+r//+r///L///P//+n//+r///L///b///H//+/+/ub08tX289To8cvu4M7i9sv5/+T//+H/ +/+7//+f//+z//+b///L//+j//+79/uXz9uXq8Nfj69XX38/N3MfQz8Syvriis72Tr6+HoaWB +maGCm6eDmJ56k5qElZl4fZJ3lZGEjpuEkJpvhZR4iJdviJhpantJU1pZaGNwlY2NtJbY0qbX +0qzXz6LV06vb2a7Y1KnY06nZ1Kfa1bDNy6LFxp2pq4iVlnenpnyimoCjrHu/vpC+u5S3uJC3 +vZO+vJm5wJ26vZ62w6G/vpzCx6W4vp+zu5+vuZ2wvJS3tJW1upa7wZu8xKLGzqi4vqC4vp+z +u5q6uZqyupSur46qsoyuuJCvuZKuu5arro2rr5KnrYeor4qtr42ms5Ctso+ut5Cxs5GtrJCm +roqrro+bon+an3+SmXiYkXyIi3CKf2p6e2B2dGFua19tbltycV5vaGFDRUVBPz09RDdEPjw8 +Qjo/Qz48QDtFQTlGPz4/QjdAQjtCQztAQDo8QjlAQjo/Qj5DQ0BERj9CRTs9QEFBSDtJQ0JE +Tz1qWk14aUqhfWCegmK3l2+0lXC1gXCvkmm7k3O9jHG1i26zh2q1jmuxjGuvhmarf2Gab1iR +a1KBZ1ODZVB2ZE9wY02jqV/5/en///3///v///j///v///////////////v///f///X///// +//n+//3y++j3/u7///r7/+7+//f0//Lq+Nrn7Nvl79za5tPq/u/+//z5//L9//X5//f//+71 +/fHz/er3//b5/+z2/u7y/ujz+Oj1/vj////9//H///v///7////////+//T9//3///v7/+/1 +/u/9//7///////f///z////tlaBITkVHSUA6Rz07RjY2Rz5BP0A6QUFJQ0U+Qj9EQUE3SkBE +RT09Rj5CPUM9Rz5HQEc/RkNORk9MTEdPSEleW0h6alKHeFOafFidfViqgmCtjGW5jWq2j221 +jmi6lWvClm7AnXLJqnnJsX7OqnvMrX/RqHvBp3fHpXzJqX3IrHzKrX3GqXzBonjDpXy6q3i/ +onu2o3azl3CiiF9yY1JkZlCcknWln4C2vZ3U4MLEw7bH0bfO17/R3MPHz7XFzLW+y7Pa6cvq +8dri5M/c5svx+dr8/+np4s+0jXikiVyzkWC5t4j3+9r//+///+n//+////T///H///L//Obo +x6DUrXHat3HZuXPYtXXUo2vHll/IiVu2hFW7hVawfVq8kWHMp3TEmGi7jmzAr3fUu5rMs4jb +uIfetYTmvIrkwInnw5LqyJXvy5Xt0pj12KX84KP94q/+57X84rX84LD63aX616bv1aLu0prt +x5rsy5XpyZfnxZTewYzar4bbtorfv4vjuIzcs4LatIfctIXowJHkxJHqyJLt0aXz2ajz16Hy +0prqzZjs0Jbpy5fjzJTnx5rlzJDpx5TjxpPkwJPdxJDlyI/pypboyJXkzJzjx5vcwZbYtoPF +pYK4nnK3qXvBvonSz6vS167X4rvl6MTu6873+9P5/d7//+P//un//+///+7///P///H///X/ +//D///P///H///X//+3///P///L///v///P///H///D///D//+////H//+///+z//+b//+r/ +/+///+////D///H//+7///X///b///T//+j//+7//ur+/eDz99ru89zp79P5/+b//+b//+r/ +/+b///P//+n///L//+z///H//+j8/uL0+9/y+eDd5tDh7tDc6c/S2cHD0cGjnZd5dIN8jYeC +nZaDnaSLpKCIlqFylJhudIZqioOCjJp2iZRrg49uj5Z4jpFtjJB4iI1gbG6DtZnP0rPa1ajO +zKXRzaPGwqLIwZfEwZe9v5fIzKLOxaTKyqXMyJnMy6HLxqDGxZvSw5u9wpDBwJq8vZe8vZq8 +xJK+xKC2uZi+yKTBwJ69wJ+3vpO0u5m6xJq2wpu8waK4xJ2wuJO1v5W9xae5uqOsuZevupmq +tY6ut5Kmroyws46qtI2ksIymrIerroyjqoGuqIilsYu0s5Ctt5CwspCzupSutZKqrY2osYix +s5CcoYKWnnuRlXaOjGuCh2aAeF9zdGB5c1tsbltwallmY1ZZVk5EQUM+QjQ+RDs6RDI7PDk4 +QjQ7QTo7QTQ8Pjo+Qjg5PzY+Pzs8RTk+QTo5RTY+PzxBRDk7QDg+RDlBQzs+RDhHQzhGSz1b +VUN7dEyehF6qkWefgWCuhWe2jGinhV+zi2q1kGm0iWa7j2i2iGatgGSjgGGif1qUcVeFalCA +aU5zYEp7Y0xuY0ehtV36//H///z///r///////////n///j///////v///f///n///////// +///3//L6/+7v+en2/+Xy+uzd79jW8szn9t34+urs9+P///T49/Dx++nx++zr+eb9/vr0+uj0 ++uzu9Ojs9/D9//7////9//////////H9//zz//H4//Hu/fD9//v///75//P8//L///7////5 ++fTz//D+//39//n38+nanJ5KXmJMZF1CTUk9QkA+QUA7QEJCQUBCRUM4QUA/Qzs+QD44QT87 +Pz46Pj8+QUM7REFCQkVCR0JWT01kYEN6Z1KCbFSYelqRdVqigGWqhFyzj2u3j2i2k3C5lWrA +lm6+lW7GqXzOq37RtILPqH7Mq3vNq4DHqX/FonnPr4DOq37QrYHLrH3GqHzEp3/EqX7ErH6+ +o4Cznni3kHSafF1yWVKFhWisnoi2uKjZ3cLLyb7GzbXP1r7M0rnAw7TByrbIz8Dk9tbr9eDo +7Nbi7NTz+uH5+ePVxLWphmajiVm1lVm6n2/N0Zz//+X//+n//+////P///L7897auJPVtW3h +u3PetWzNqG3TombVnmzLkWe+imCxdFeufVKxeVamdlCrh2Lcy5PZwavUrY3ZuYXiv43rx4/p +x5Xgu4/iv4zkxJDuypLtzJfx0Zvyz6H31aD13a/64a3406j22aj21azwxp3mxJDjwZHivo3d +v4fYuYvbtY3duYjYvY3dsIvauYrftIvWtIbctoXiuY3lvozkx5XtyZTt0Z7216Hy1KTz1Z7o +zpzqzJnpx5fnzJPqz5nlyZzfvYziu4zfvofixZblyJbqzZnmyZXhxpnWvI3QsY6/pHy7one7 +rn/h37fs8s36/OL7/eXt6NDi6Mjq8dX//9///+z///L///P//+3///n///H///X///P///b/ +//P///f///T///X///j///r///L///n///X///j///L///f//+////j///j///f///T///T/ +//X//+v//+7///H///L///T///D///H//+z///L//un9/OT289T1+uLx+OD5/+f7/+X//+n/ +/+z//+3//+n///L//+n///H9/d/5/ufy/ubz69bU4czN1cHE4MnZ18rAy7m6sJaFfWd5bGl0 +dGd5fHF5fnmAf3+Aj5BzdYNje3N/i5JzkZeBo6FyiZN1g5FnjoaEmp2SrJO1tpTBvZLGyZnQ +yqnRy6bN3K3U17PZ3LnT2b7N1LHK1KnMzafS0qnGyqfJy6TLz6fFy6K+xJvJxaPEx6fHx6bF +zaS/xKK4wKm3vZixwpm8upqvu5TCxKK7xqm4vqS3vpevuJe9xpzBwKO3uKGyt5WvtJOqsIis +t42hpYuqro2nq4yqrY6jr4irsoytsIyvt5CttJOrsoqxuZatuZW2vJu1t5auspmorIqqrpCo +rouXmHqTj3aKiXR/e2l5d2JzdGN7el5zbmNvdFxkX1hZVExEPUE4QTw9Qj44Qzo8PDs9Q0A9 +Ojs4Pjs4Qjk8Pzo7QDw8Pzk6Pz8+Qjk6QjtCQjk7RTk/QDY7Pjs8RThCREBBRz1EQkJaWEGA +cFOaeViwmW2ujmmuiWyif1+me16oh2SyjWmuimq9knK3hW2qgGmqfmWgdV2UcGCTcVqRc1eM +Z1J6ZlRvYE2WsF38/+7///r///////z///b///j////6/+/9/vP9//L///////3///r+//X+ +//r////8//zr9OPh7t/i+N7l+tby/OXq9OPq89/z9+js9ej5//b+//v9//Xz/vD9//35/+v/ +//3///////v5//b9//Ty+en9//r9//j///3///f5//X7//n///3///jv9ej9//f///3///// +//n6//H7/vD0/evqtblOY2VaZW5bgX5Zb2o9Sz1HRUE9QTpBQEQ2QzRAQUI2PjU7Qz08Oz02 +Pzc7Pz06QTNBRD1JSkFTT0ZsXEt3YkaCbU2OdVeUd1ifgFysgl6sh2C4kWi2kmnClmm6m2nK +o3LGp3vSq3/KqnzNpnnNrXzTrXvOrH/MrYDPr4LNtHzOsYPKr3fMqnzKrn/Ip33EqX3HqYG9 +one1oXKtkGaMa1Zzb1qgknevtZvR3r3HwLW4w6zR18G9w6jAy67Z4cTK1cLq8dXu9eDi59Hk +7M/2/OTy7+HHtJ+hgFyjgFipkli9l2m3pnPi57f//+b//+////H/9+HatY7XtWvfvGvcvHPX +uH3eu4HnxJLjs4rXp3nFlnayfF6aak+icUyfbU6si1TUrYfiv4Lpx5Lm05ft0Zvr1J3wzZ3m +wZjqwpDixI3jvITnwonpuozqw47uxpHszprwyZHyzZ7xzprsyJfpw5DdvY3atITYr4PMqHvL +q3vNq37ProPWtIfZvY3gvY7bu4nes4rfvIbpxJPsyZfs0KDv2J752aH13ab32qXtzJ/rypnq +ypXv0Jvp0Jjmw5XewZHcv4ngwI7gwIXqy5Plx5HjxpLgv5DZu4jNqoXAoH+5pXjJwIzv8sP+ +/+T//+r//+r///L+/ebw6dDh8cn5/uH+/+v///f//+////T///b///b///X///D///n///b/ +//L///f///f///X///f///T///P///T///T///b///X///f///P///L///X///r///L///P/ +/+z///D//+///+7///D//+z//+3//+7///T//+/+/uj1+dv1+d/1/uH4+d3z/9r//+v///L/ +/+////b///L///P+/+n8/+f1/979/+v1/d/s79nX2sLT3cTD2MLM28HK2bq7vZ+yo4qOkWmj +lWaIflp5b19pallZTVVSVU5YWVlja2V2i4KGm5h6mJ6DmZOlvKDFwKjEx6HJz63Gy6jQ1q3J +zajSz6fL1rHS2bHO1rfN2LHM0bDO1KfS067Fz6LN0abO1KrLzabJz6XLx6bGxqHDyKDEzqi6 +wqbAwZ7Awp+2wp62vJa2xJe8wZ+/v56yu52wvZKvt5O0vZWvvZuvsJSosYmnrYysrYmos4+p +p4ulsoqus4uts4mssYqnsIqwspCttpGvtZGttJGyt5Gpt42zupi7wZi0uJajqoagooKhr4ea +moKMjHGHiG58dmRvcF17g15/fGZycWJ0dGFnZFlaUEs6QDtAQDw7Qjg8Qj02PzRBQDs4QTZB +Pz03Pzc+Qjo0Pzk+PTg6Qjo9Qjk4Pzg+Pjo9Pj0+PTpCQD48PjlCRT1HQzpHRkJVVkOBblOR +fFmrjWatjmiviWWzimame1eqhFuykmG1i2/Alm67j3Ctg2iqeGOTcFuacleLbFKKbFl+aVJ0 +WU1uYEuCmVf1+9f+//b///////////////////////////P///X///r///f///P6//T4/+36 +/+z+//X////6//X1//Pm/dbs9eno99zp+eT///////vx++zv9+7y/u/t8+Xy/vD5//H0//D8 +//fz//D49/b9/v3///////X+//j0//L9//3///////n9//j///z///////X6//L4//P+//f9 +//T///7///3qwsVMbGxigYxdfYdziplldXw/VVRATEU2RT5EQzw1Qz9BRTwxPjc9QTs1Pz1B +PjwzPjs8RkBESUFRUUVhVUttXkx/aE+JcFGSdVmZel2mfmOsimS4kWuwlWq8lGzAomrCm27D +o3TPrnzNq3rMqXrNqH3Qqn3Ts4LQtIDWtoTTtojMrobGpXfKr4LOsnvKq3/Ao3rBq37Hp4O6 +n3i7mXijf2F4ZVSRhm+upIystJWuq5W7xaTO0bu1taPD0bbe4MvT3cLv9t/p7t7b5dDc7NP3 +/uPs6ti7ppCZd1udeVWfhlawk1m0mGO+tXzy+Mj9/+X//engxKTTrGrevGjv1Y/u577n0Kvc +v4vhuI3YrYLPmXjCnHXDj27GmW+3gVvEnF/bu4LnyJTw0pbx2aTu3qn33rPv2K3v1qvux53n +vIbftYjfunzmwIzlwofkvYTkvYPlwonnyovrxZDlxo7ivZLVs4PVr4TEoXS2jXOnf2O1imrF +nHPOrH7VtIzavo/gvZLjwpLiyJHmyZzqzpvr0KLp1p3z2KP33Kjw0abozZjpxZnozZDryprl +ypjjxpndw43gv5Ddv4rgv5Lhwo3ixZLiwY7dwY7Ts4jFqXi4oHqzm3vWzZv5+9f//+r//+n/ +/+z///D///D//+38/eTp78/n+dD6/+j//+///+7///H///j///H///b///H///T///P///j/ +//X///X///T///j///r///T///X///X///f///r///j///X///b///P///T///f///L///b/ +//b///v///D///H//+r//+///+7///H//+f//+79/eTy9t/3/uPy89zq9tj+/+r///D//+z/ +//P///D///H9/+j9/+r9/+f+/uj8/uf5/ePo58vd7dDl5tPK2sLO27rEvLasjHOJnXS1vYun +r4qZkXaEfWRiU0ZMUUxLUUNNTUpSXFNgYV5eb2BtiXG1vZbBxpvIyKDKyKTF0KbK0arJy6bC +xKbIyprCxqC7xJu/xaLDx53Bw5rKzqjCxqPDyqPLzKa+yZ3GxqjDzau+yKW6w6DFz62xuZm+ +w6G4v6G5vJ23up27wZ61vJ6us5Cms4uoso2ntpGtsY+vupKyuZmrr5Ktr4ioroyltIqkqoik +tIass46mtIurr5OtrIqrromqsYyqr4urr4ivvI+3uZWuwJe7uZ6pspKkrIicpYKcqn+enoOM +iXJ6fmR5eGJxeV6DgWR8emR7gmt6eWRoY1ZMRUk+Pjk5Ozs4Pjk3QTU4PTs6Qjk7Pjg4QDgz +PTY1QzU7QT4yQDNDPz4xPjk+Pjo1RThEPj82PjpHRUA3PjZHQD5BRTxJQkJVUkR9a0+PeFei +hGCmf2SphmS0jmytg2eyh2W0jWqzhW2xjGewiGylgGqkf1uZbWGCaU2HaFeFaUx4a1BwXlBt +YFF8mE/7/+r///////////v///////v///f///////n///////3///f///////n3/+zy+O/z +/Ob0/evy/Ork9OTd9M7w+uz4+/Hj59fv/ezy9+32/e739/n//v3///////X9//7///n1//D5 +//H0/fT///r+//L8//3///H9//j//fj9//j4/+z0/+b6//D09/D1/O36/+78//n2/+z9//f7 +//T8++7fzcdPXF5efIV7iJ5vhZZugo5le4xhbIFca3dJUmZISVA7QkM7RURBRD47RTs8QT48 +QTQ9QTtERztFS0RQVEVqWEp1YUaHaE+MclOgfF6hhVyrh2OukmK1kWu+nWzDnHDAlmLCo3LQ +qnjFpnTLp3jNrn3TrYLMsH3SrnzTs3vMr3vTtojQs4TKq3nRsH7Sq4HOsX3Lq3rCq3XGpne5 +oHK3kW2RcluPeluYmW+mmIG3uaG9taLKyrCxs6DD0bLZ4sjP3sfp9tfb5cvP2sDW5cvs+djP +zbygi3OQdk6Ydk6delClglOvk1W4lWXAu33d6Kvt47rPp2rSrV/t3JX//+D//eT55tDtw7Dw +xKrux7Du2sHs373Qvp3Tqn3etoLixZDtzZ7x1J/33a754rL34bb45bXz3K7x0ajxypvrvJXm +wIbtwpXlwYfnwInluIjsxJPqxZLlwovctoLauYTVs3rDoHLPpn/n0LPx5M/RqY/TsIDcupDm +xJzpyZ7syaflx5rsyqPszaT21Kbv0aTw0aDu16rw2JrozJLmu4vpw4/ryZfr1JzsypnkwpXm +xIjpxZPkxo/jxpTjxInhxpDlvovWtIXHq4WwmW6yk3XQt5H27M///d7///P//+////P//+z/ +//f///L///L///H+/ej19dH0/OP//9///+////P///j///L///X///H///L///L///P///j/ +//L///H///j///b///X///P//+////L///n//+////L///P///f//+////j///X///L///b/ +//H///L///H///P///L///T///D//+L//+r//un9/+P7/uL7/uDz9Nr4/+H//+n///H//+z/ +//H//+v//+v9/ub//+r9/uv4+d7v9tnr+c3s+9vr8tXo5c/V4MXR2b/Ry7rKzLHMwqq+s5m+ +spK7u47DqI6ukHyddHJiXEdfX0xcW0aemXrAvpjFyqTFyZ3Nza/CzaXF0azJ0JrDzazLy6vG +0KnJy6rEx6XLwqS9w5vExJvFwp3BwqPFxJ3KyqXAy57JyafPyqS/xaHKyZ3IyKa6u5Wtwpaw +uZGitY2vroyisYqprYivtJC4tpq1uJqyvJWyuJG4u5GzuJOvsYyttJOvuI+1u5WwrY2jp4Wk +s4iqq4enrYWqtIeqtI2ut4aqsIqlrYept4+vtpSztpKsvJWsso+rq4GhqH+aonSeon6Ghnd9 +gWSAe2d9gmuEgmt9e2GDiGd/eGRmX1hFQ0E3QT5BQTk/Pjw5QTg+QTk7Rj06RTo6QTc4Qzs8 +RDo7Qzs5Qjs9RDk/Pjo/QjlCQTg4QDo8RzY+Qzs/RThARD1ERTpFR0BMUD17bkyHdlaWdV6b +hVy6jW6yh220i26wg2q+mmm3imqviGW1jG2sgmSne2KbdVmUbFiPblGLblWHa09yWlNoV0t+ +lFP5/+D///f///////////////////r///H///f9///7/+////b///j2/+7+//L///7///z7 ++fr9//fn+Ozb99Du+9/n8Nzf69X////////3//j8//Xz//D6//D4//X+/+zw//H+//79//r9 +//Pt9un5/vP1//H7/+zy/+/4//j7+ff5/vP6//3///////j///f6/vT///34//L///n0//L7 ++fPm08tZdHd7lp58j6Jqho9kfI1geoRieo1keYxgbH1dboNVaXpPXXBCZmxDSEw9Qzo6QDY2 +RDo+Pz9FSUFOS0NjVURrYUZ9Z02EbE+Yd1aggFeshGCpiF63km6+lWzCm2q9k2zIoXHKpXbO +q3bSr4LWtX7UtYHSr33Ss4HVu4TWt4DUtYbas4fQtYTTsYTNs37JrnzJrnnLqHfDp3m+one7 +nG+sg2R/bVedj2ivp4vAzp/RwLfGxqe3t6OwvaLS2sLK1brq9dnT08S+0LDe6Mbs7dPBraGM +dFuRbkqNcEuXcE2adVKgg1e2lGaviV20k2m/kWe9jVnAlVve3ZD//+T//+r//+z9/eX8/eHz +7M3Xt53VrYPfsofhvI3pw5XuzZjy2Kby2q784a7z6K/34bDv3bP02K3rzp3sxpztyp7syJPs +y5/ltYTlyJHovo7bv4ngv4jZsoDNo3rMoG7ZpHPxy5zn1Kju8c7t5tDbuZjgwo3qzJ7x1aLx +3q3x2bPr1qH216n12q/53LP03a7x163oy5fmwZDivInnwJHnyJfrzJ7dyJXmwpLkw5blyo7n +wJLjx5HfvYzcvo3cuYvOsIC6oW+yl3LLtIvn2L/3+dn//+b//+3//+3///H///X//+////X/ +/+3///T//+j///H5+uHw+dj7/+b//+f//+////L///L///D///T///H//+////L///L//+z/ +//H///L///T///H///T///j///P///j///b///r///j///f///b///j///X///b///f///j/ +//f///j///b///f///b///H//+7///H///L//+3//+z9/ujy/+f+/+v9/+n///X//+////f/ +/+n///H//+b///H+/+36/+z4/ODt/eLu89jw8Nrk99nq8tfl5c3R2rnSz77KxaLGyazEx6jI +w6nK0azIz63SxKy3n4qqkG2jpXq9wpm9w6K2u5S0wZm+wZq3w6K+vZm6vJ29w5m6xJvNzKTG +z57J0KfRzqzJzqTM1arN0aDS0K7K06LLzarDy6bMyqLJzaTDxZ/CwaPCwZ6rroqxsJeor4mz +uZixupm5uZyxuJazupO7wJm0u5WyuJuytJC2uZSrs46rsImys5WuuJa1uZOvtpWor4yfrIet +rI2pq4SrsIutsImrro2orYqrrImqtIiytY2utI+3vJqxtpWrqYecnnqgoHyYnXaZkYF/f2eA +fmh7hGaAf2Z+fWh6eWR8e2hlXlo/QTs+PjkxPzZCPjw4QjU/Pz88RTc+Pzk7QTdCQzg3QTU+ +QT08PzZAQTtAPjlBPz48PDtBPjY+QDxARjtAQThDQjxIRjpHSEFKST11ZkqMclOXeWCmg2G4 +j2+4kWuvgGmwlmfAknWthmSrgmqzkmm0gGaaeFyZc1eMb1eNZ1WJZVBxXFBpX01mWUh8glT4 +/s////P///v///j7//j+//b///////////v///7///////////39/+/8//bz/Or2/+v2/+ny +/Ovk9drg9Nbo8t/n7t/u8uT///X09ev0/fLz/+/49+fw/On4//P5/+3+//v9//f5//f+//v/ +//v2//X5/fHt8+Lr8ej1/fL9//v9//j///7//+7///P9//X///r///b5/+/+//b1/ev1/On9 +8+1Za3V7jZV0gZZvfZFjd4ZnfI5dfIlme45aeIhseY5dfIxld4dbdoRSWGE4QT8+Qzw2QzxC +SDxDR0FKSUJaVEVzW0Z7ZUeHbk+Wc1mbflqogV6riF+yiWi7k2q7kWrFn2/Lo3TKq3fQrnvX +tITYs3/Utn7RqoDPtYbbt4nUu4TXu4nXsYnUsX/RrYPYsX7Lr3zRsoDOsHzNqny7pne/nXK2 +jmmRalyOfGKwqoiyt5rQy7W9waK+uKerqpzByLC9wq7f7c7Pyru4vaXT37vn5cuykYaHaE6V +cUeVb02RbEmcdVKbeE/BoGmyiV67l2bAklzPn1/GnFzQunf//9n//+n//+f89+Lm0r3btpXY +soPkt4bjvozlwo3qxozv0J301qPw3Kz44bbx3bLs16vt3Kft16vszaDkx5Lsy5rnzZTrz5vl +vozhvorWtIXTqH/IpHDLk2/KlG7isoLtxov94KXv0Kno2LLXzLfivpPnyJru0aP12Kj13K71 +27Hx4av44LT45LX657P23qzy16DtyJzkwojkxIzmv4fjwJPbw4/cvIrhwIjmyJDnyIzmwZHj +vYvfuZDYtYHRqYK5l3W4nHfe2KT3983//9///+H//+3//+v//+j//+z///P///H///L///T/ +//L///D//+79/Ovx89T6/t///+L//+n//+////H//+////b///L//+////P///L///L///D/ +//P///P///X//+z///H///P///f///L//+7///P///L///f///X///X///H///j///P///b/ +//X///v///T///b///L///T///H//+///+n//+r9/+v6/+D///P8/t/6/+v//+7//+7//+f/ +/+n9/9/7/+n9/uf3/ejr7tnr/uD9/uXz/ej058za49Ll8NLh3czMyKvG1rjPz6fJ0a/GxafD +y6nIy6PLz6jKyaTFvJnIw5jFw5vBxaHGu5y9upm+u5i6xJfDwZm/v5zBwJrAxZ7LyKrK0KjM +0azY1LLM0qvO06zRz6rK0qbNzKTEzai/yKO+wpjBwJy5tJKrsJG5uZmvs4+zvpqzupi4vpm2 +vKG1uJawuo+wtpC5vZizvpa1tZyzro20uZKrsYyttI+utZC1uZS3uJSrt5imrI2msY2pr42q +r5SttIuuso6jrIuss42ss4yxsY2ttoyzt5OtuJettI2qq4OfoIOgoYKVnH+bn3yOiXF+f2R4 +emZ3fGOCeml2dWCDgGZoWlpCQD05PzY9PTU6QjY4QzpAPTw7Pz06OjpAPTo9Pzc+Pzo7RTo9 +Pjk5PzQ/QTw1QTpBOz46PjlFPj48RjdGQ0E8RjxKQT9EQUBMTUB4aU2Ndlqafl+qiWG1k228 +k3K7i221jmy7j3W/kGqoe2ywiWixh2mpfGGNbFWKaFiNbFSDaVh/Y0xrWU5iWUN3hFj3/8j/ +//j///n///////////////7///////////////////j////////////////9/vzw+ufs9+Xs ++uDu/d3w/Ozw/+b5//T1+/T6/+7t9+nx9un1/vr///j///z///////P0//X7/+7z/er+//v7 +++3x/PH+//3///////3///z///X+//v9//L6+Or///3//+78/vL+//b6/e/9//r///zy39ZM +Ympqf4Ntg5Frf41eeYdodYtne4dle4tid4xjfYhlf4tlf5NrfYplcH46RT89QT41Pzo/Q0FA +QzxHQz1STEZqVEhyXUl+ak6MclSXelihg1mqhGCsg2S4h2O+mmzCnW/Hn2/IpnjIq3fSs4DO +un/btoTVtXzZs4jPuIHUsIPMsIDWs4fPsofRtYDTtX/Xs4TKqnzMsYTOsILMsHzDoHa8onC1 +jGGKZlKAeF21q4mws4m2rpWzsJGgoIOqroqpq5PAy6XHxLK5vZ3Cu5+ej3KVa1aYdU6dd06U +bkqWbkuObk6bdU7Br2jJoXu2j2DAllzMkmDEk1nZynv//df268veyKXcsYrbs4Hfu4Douovq +wovpuYnlvInnxZHqypPuzqPtz5vv2K3p0p7rzJ/ky5npzZzlw5DgwJTasofLsX/QsX3MrnzF +lXWxiWWofGCqd1jSm2/it4b0z6D+5Lj/7L/337bnv5PcwJLlx5rszqLt0qP02arz3q/436/y +4rH/4rX65rT857b23K3wz5/oxZzlxI/iwY3du43ZtIbYuorgu4rjwYrlw43nwovlv43dvIPZ +r4LMpHrFnXDj1Kj888z//+P//+P//+z//+r///H//+D//+7//+j//+7//+7//+3///H//+// +//H//+f+/en199z19tH6/OH//+b//+f//+3///D///P//+n///b///X///D///L//+3//+// +//P//+z//+r//+n///T//+///+z//+r//+7///L///j///P///P///X///r///T///T///T/ +//n///b///T//+////j//+7///D//+///+/9/+n//+j//+v9/uvz8dj///L//+7///L//+/+ +/+v+/+v9/eL099/w9dfq8dDx9tzu/tr0/ePy+Nnz89jc3bzT2L7U6cXg3MHVzrbN1LTHy6nP +0KzK0Z/Q1azS0KfG0aPTzrHJ06nF0q7N06fSz63NyKjGz6fOzKvLzqrEyqXDzK3KzarI1KPO +z6jDyqPCxaG/wJi8wJ+8uJO1t5ausoWnqomwsoW6uJOzuY6+u5qpu5C5w53Avpitu5a2vZiu +s5OtuJazvpu0v5uqsIutt5CxuJG2vJetuJSstJCztpOouJW2tZOttoupqISiqoKnq4apr4mu +sImir46qrYqmroartI6vs5Oqs5GqspKstJKospKrqoebmICUnXmYmnibnnyQhnV7gGh/fGaA +fGN3b1lxb1l7fVloW1hCPTU9Qz49PTc8Qzs8RDc5QT0+Rjc5QTxCQDs7Qjc8Qzs2RDU2QTk6 +QTdDOTo2QjNAPzs6QDlDRDtAPDlDPztAQj5GRjtHRz9MSD51ZU2MclWbeGCnhWGxkGq0k2+5 +knG5kHLIpXTAnHy5inSnfmamf2GngWaWdFuMa1CLbE5+Yk98W05yW1RnXkh/eFP1/cv///// +///////////////9//f///f///r7//P+//77//P1/Of2/+ju/Or9/+/4//T4//H9//rw/u3c +9M3k8uDl8Nnj8d7y9+Hz/u/8//n//+7t+d/s/Obx/+H0/+/8//P5//P+//z///P1/u7+//v/ +//////f+//n6//P///H7//b9/fL4//b///X7//b///z///////j///j+//j9//Ly6t5baGth +fIJle4plg45phY5ieYtkeIlkfo1lf5BjeYhsgYxlf49rfZBlfoxQUF5EQj48QDs/QzhGRj9F +Qz9JSj9cUUN2WUd4X0yIcEqWfFahfVidgVynfluviWC1j2u5mGy/m3DDn2nKrHTLr3vVs4DR +tYDZtYbOtYDTsYbUsXvYtoLTr33XtoHUtYTXuIHUtoHPs4HQsX7Ss4TNsH7Lp33Gom3AnG+2 +iWmIYVWBiF2zp4u1sY+mmoOck3eglm6dgmKjimSfkGaiiluhi1OsiFioh0+pf1Obd0iedEqa +bEaSaUySa0WgiU68mGmshFO5jlbKmVnFkVTIqW7auIzhu4zft4fcrYHbsoDjwYzjvovotIPn +uoLosYThvIPkvY3fxYnrxpbnzpnny5fjzJnpxJHiwYzdu4nWtoXNsHvEpXrBm3PBkna4jHuw +g2m9i2jLlXDetIfyyZb95rn/8s/958H32aPrvJPlxYztyqDw0aH51ab226r737v446/64bX9 +4qz/5LL94Knxz6ruzZzhxpXctITUq37Urn7YtITbsobdvorkwJXgvIncuofbsoLRqHfClmrI +pXLz6cP9/dv6+NHp7735/sz8/9f//+v//+T//+H//+r//+3///D//+r//+n//+v///H//+n/ +/+b//uj+/+b3+tbr8M3u/Nr4/d78/+b//+n///L///H///L///X///b//+////X///L///3/ +//T///f//+////P//+3//+7///L///P///T///P///P///H///b///T///j//+////f///f/ +//X///P///r///b///z//+////P//+v//+///+z9/+n8/tzz9N/1/+L//+///+7//+n//+T+ +/+X1/979/ubt+t3t9+Xu/+D5/uL6/uTw69fT5Lzg7dPk7Mvg3tXQ3sHf5cvc2r3X0bfNyqLM +0a7O0ajS0KrQ0abLzKnK2LDK0KnMz63Kz6bKzafFx6a7xqG/wp66wZbBwZ27v5XBvpq8u5W+ +wJq9vJrExKrAxZ/MyKPExqDHxZvAxKLIxqHByZu+wp6+vKS1u5CzvZi8vJmyuJmvto+uuI+v +tZCttpG1uZGutJO4t5KutY+yvJSttY+stJGst422tY+lr36utI+ipYOhrIujqoCqso2rrYqu +royysJCqsYKor4yusY6lrYintIyrsJOpqYiio4WbnXuXlXabnX+bnnWYk31/gGOBfmR/dlx3 +bV9rc1OGfGBmXVVHQDw4QjdDPzs4QjJFPzw7Pz0+Qzk9Qzk6QDlAPTxAQjc9Pzg7Pjk8QDY+ +QDk+QzU9Pj4/Pjg/PTs+QjpDQD4+RTZCQj9ESzlMT0hlX0Kbf1mnfWOagV62jmm9j3S4jGuv +jG24lGfCm3S5iXirgGiofWKgd16Ra1eJa0yRbFyHbVaIalR/Xk1yYEuBe1P7/8n///D///b/ +//f///////////////////j///////7////9//v9//T///n5/fLu9+b5/en6+/fp++Xl99Dx +/+jv9ePf6Nf///////v07d7s9ez+/vv///////////H3//L7//L7//j+//7///n+//31/9z9 +//X5//L+//j///z///r///H3/e/t7+T8//b9//H7//H4//D///7///T///zx7+NbaGpriZN6 +f5JeeotvfIpif4xkeolhfIheeYxigIpjfY1ihIlqhJhmhZFkZXU/Pzo8Pzw4RTlDQ0A/QTtC +R0JKSjxpV0dzXkqEbU+SdFGbd1alfFmhf1yvimG1ime5lWq9mmrBo2/GoG3DonLPrHnQsYHM +sIHRt4HZtoHMrnfYtn/dtIDUsYDPtHbStH/QsIDTsYHPr33Orn7LsHfOp3zEqnbKqn2/l260 +i2KBX0+DhWOxpoenmX+Ve2eKb1CXd1GlhVKmhU+silavkFm1k1/Wyobaq4+ifE2edFKTb0mR +ak2PaUqbclGpiFS1h1vXvoffqYvDkFnZqnbqvIzhvo3dtIfWq3/Yq33cr3/ht4nft4Lis4Pf +s4XYr4Hct4Hft4bcv47fvYjcu5HaxovawI7Ts3zSqYDRpXrguJbn1Kn069Dhzby7kXvAiWLM +n3Xku5PtzaT63LH/88f/4cD31J3zyZvltoLsxozyzZr21aL52qv54a/+57/657355rD537P4 +363z1aTrxZrgxJPWvIrWuIXWsYfVq4basYTcuJHkv4zhsYHVrnjVo3LNpHHJl2+9nnLh2a7U +vZrXrYner4PnsoPksYXowY/z6LX9/+L//+n//+j//+z//+///+v//+v///L//+z//+n//+r/ +/+v//+30+N/e5cTb7cT2/938/+D9/+X+/+f//+7//+z///T///D///T///T///r///L///r/ +//T///f///T///r///T///n///T///P///H///D///H//+3///L///P///D///P///L///n/ +//H///j///T///b///X///f//+z///r//+/+/u7z+tn4/OT1/971/+P//+7///D+/uT3++D0 +/N7j7NDm9tzp69Lm9tfs7dzi9try9+P38dnl0sLW7MPt7djo8c3o79bT3sLT2LzK16TTzqrD +z6DMya3AwqHBwZy5wZm5uJm9vZu6vJrEvZzKw53LyaTKxqbOw6fNxqzIxqrJyK3MzanOz6rM +z6bQzajR1aXQz6vJy6TOyKXKzqbNza3IzaHIxaXEvpq9wJq7vZi4t5q4uZqvuJyzs4+vsZC0 +vY+0u5Sxtpezt5Oxupivto+tsI2vso6yt5K0tpOnsIyrs5CnrIStqoOlrYSysYmgr4izr42k +roepsIyksIOrqYajrourr4ilqYmfpIOdoYKYn3uXm32fnnqbl32SnXyFhW9/f2mDeWdudGB1 +cV93gmNoWFc/QD88PzY9QT48PjQ9QDs7QzM7Qz47QjM9PT88Qjg7RDw6Qzo3Pz1CPT06QztA +PT47Qjo8PjkyPzdCPTo+Rjs/Qz5GRz1FQz5JSURuZUqbiVytimyqh2W3jm+6iG7Dn3C9l2+/ +mne+m3G/k3bCj3OkhGaugWigemSRcVaNbFiOc1KNcFN8Zk93YVJ0cUny+Ln+//n///z///// +//////////z///r///f///j///r///v///r///////////X///f5//X+//Lx/+7h/NL0/unn +8OHt+N3y/Ofv/uz6//r9//L5/fD1//D9//P2/+r5+uz+//79/+/2/uX1/+75//D7//j4/+33 +/e70+ez1/Or6+u3//+7+//z///////v///X///3///n+//b+//T0++n99ulSXFxyjZNng5Jp +gY1UcX5wf4ZdeodseYNhd4VmcoZje41mgY5rhJJsgI5lbX1BQj49QDw3RDZDRUJGSjpERTtK +TD1kTkNzXUZ+Y0aIb0+YclWaeVOihVqohl+wjWK0jGS+k2jCn2zFpG3FpHfHrXjMrnnQr3XU +rnrXtH/Qr3/Ps4DXtH7atoHWtoHWsn7Psn3Tq37PtnzQsn3JrHPKq3fGrHXIo3LCn2y8nWme +dVpxX0yPiWuiiHSAYE6YdkiukE/FoV+4kli8l1m+oGG8pGS2oG+mhWKZdk6bck6SbkaVaEuN +bEGbckekgU2ykFvt7rX86dDRqIHsxpLqxpbqwJrlvpzlvp7SporTqHPUqXnZsYDbrXrWrHnX +pnfSqHTZr4HTrH3QqHzLqHzIqnfSrYPiyZj46MX9+9b//ej6+9bm28rAmnzOnHDOn2/So3Xh +xo/45Lr747z758P306j81qTtxJvjrXvqxoz01Zr426X93q385rX857j95rz75rH44azw2Kvl +zJrauIvGqXW+lXTAp3bTrYPUsHzasoLdsoHhtorasHrZrobbrXjRpXbYvITTt6PNl3Teq3fn +s4bqvo3wv47vwon006fx1qXx68D+/9z//+r//+7//+j//+z//+3///D//+n///D//+r//+z/ +/+j+/ebs58/d4sLb6sfq9c71/N37/9/+/+b//+n//+////L///L///D///T///X///X//+7/ +//L///b///T///n///H///L///H///P///D///b//+3///f//+z///T//+b///D//+v///H/ +/+3///P///X//+r///X///D///H//+79/ub6/d3y+tf2/+H6/+P//+r//+r9/+b6/+X89dnp +79Dp5MrHxbK+4LDl+dft9dnn9tbq9Nbl+tns+dj299vn7c3o48bM37vOzrHIzKbNzaPKzqHP +zK3DxqPJw53IyZ7Kx6XCzKnR0KvH0qjQ0ajS1qjKzKXHz6vR0KnM0qjM06nN1KnP06HL0aLN +06rM163bz63Dz6fM06nE06PKyqrL0qPDyq24spqjrYSuuI+tsZSvu5KwtZyqs5CxuZO2uJet +tJCrt425sI60to+ys42us4qyr4uys5CktI+hrIuos4apsY6lrIicpH2ip4KeqX+uto+kqYml +qoilroKmq4ifrYKsq4mgpn6doYSTnneboX6ZmHaWmXiPkXKPlHGShHF9eFpzc1pvdFR2dlt7 +fGFnVFVDRDs7QTU9RDs8OzI7Pzc4PzI5PzQ0QjI+QkAzPjQ8PTYyPDE+Qjo0QThCRTwzQjdC +Pzs3Pzg/PzQ7QzI+QjM/Qjg/QztJSDxJRUByZ0ehily1iXCuk2zBnHPFonm+lna4jnG6mHG8 +i3a8jGq2jXG4iG2rf2aigGKddWaMa06Ia1V/Zkx+aVRzXk5yeFH7/8n///////////z9/+// +//7///z+//7+/vD///f///v7//T///79//P9//f4/vnt++L3/+rv++Tp/+Tj9s/x9ufk8d7k +6dn1/vTs9OTr8uT0/er7//f//+7+/fH5//T///bt++T4//H+//v///////////v8//b///3/ +//////z///r9//n///z5/fb+//j///X4//X6//P5/e/6/uz7//Pr3tRWVE9cbnZkfI5teoxj +gItndopebodpeolfe4hrgo9phpBthJVkfoxpfJJmdoFHSUw7RTs/R0M+Qz9TSUFFRD9OSUBf +UURnW0t9ZEmHa02TclacelShf1aohVyrhF22jmfCmHHDoW/HoW/Kp3XHpnjIp3XKsHfUsYHT +uoDasYnSsHzcu4nctn/bsoPYuIXauInZt4HVsH7TvITXt4PQsYbNrnzMqHjAoXTCn3O1jGiK +YlJ3aVWUgF6DY02cfUfEr2fv3ajbs3W8nF2yiV6kiFavhV2qiFSvfk+ZdUmabUuQakiSb0ud +cEyoglCrkF/w8Lf+89jdwZnqw5LuzZnw0J7uyqfmwKPZuY7Pm3DVpXfdq3vbsH/SoHTTo3vP +n2zOp3nHqHnTsInlz6L16cn9+9r//+z//+r//+z//ure0MLGnX7SpW3gt4DguYTmsoDovobz +1qX52rX10rT1y6n50aTrt4/kuILwzZjz06T8363+4K//5rf75bn45bjz1ajx06Lkx5rUs4e9 +k3qogWK0jGrConTVrYLar4XgtIrftoritovhvIjesYXQo3bPsHzSo4jXp3zsuorvwY/1y5/0 +yJvtx5f22an516/swpbm0aD67cH//93//+P//+f//+3///P///D//+z///L///H//+7//+j/ +//f//uj8+OLy9tLy8NPn8MXu99f8/+P8/+n//+D//+X//+z///X///z///P//+////b///H/ +//n///b///L///T///X///P///v///X///X///P///P///T///f///T///X///D///L//+r/ +//b//+7///T//+3///T///D///P//+r//+b+/uj3/uP1/+b7/+T///D+/un8/+b8/eTy+tvz +9eHg4Mzi8tDj4MLO1sHN373h7c7i8Mfk99j1/uD3/eDp8tLq6Mze38HMzqfOzKDKzJ7OyqfM +zqfHyKrO0arM0a6+yabK0abP0qnO06vN1K7H067T07DU06nN1q3Q2rDZ17HO063Q1KjJz6XP +06vM0Z/NzqrK0abK1KvQ1qvNy6y/u5+9t56rsIu1sZGwtpW3v5i1tJeutYuut5Wws5Gts4+v +tZKztpOzs5Cyv5ivuZavtpS1q4+jroWstIqqtIqztZOeq4iorIapr4ylr4qnromnq4Wkq4Wj +rYqoqYifqX6jqoqiq4Ono4KcoH6gnoCUl3qOkXWRlnGZmHaWj3mAe2R6eWJ3eF5+e2N6eV5l +WVVCQD1CRz5DPjw7RDk3Pzc7Pjo8QTY3RThDP0A9RTxGQj44QDo8PT4+QD1DQD83RjpAQD45 +RzpAQjs8QT1IRUJARj1KQ0BISkJQTEJ+cEqojWevi3evkGnEpXm7mHnOrXvRpIjDmXi9m3vA +nHm+kHS1immtgGepgmeacmGOcVSLaFaHcFOBZFJsZFB2dFb4/8T///z///v///////////// +//////////v///////////7///z9//b9//j///b7//b////9+vLv+ujl+9Lp8OTn9tzs9ufy +/O/8/+39//z////p/eX9//H0//H1/OTw/u7+//v///f8//H6/e70++r6/vz///n///39//v/ +//77//T9//rz/ej08+nz//D///z///v9//z5//j///////n9//pdS0lAQklPWl9ieIFkfY1l +fY1ceohnc35ieYdke4ZlgIprf4xqf41ofopmfIlITFQ3RjpBQTw6QjxHSkI+RzpDRzxKUD9i +VUhvYUaEaUuOcU+adVmff1ephl6ojWGujGa4lGq+n3LDn3HCo3LAo3HOp3fMrnzRroXOsX/Z +uoTTs4LRr4LWtHnWtX/Ns33YuYDXuILbuYfTsXvWuIDOsn/UsIPNrHzNonbAom25k26lgF6B +XE5kUkqCX0GUdEqoj1mwkWCoiVmqgVCmhU6yj1awjVqwi1irglCddUuYckyTbUeWdFGadEqj +eFGkjFnu77b799vx3Lrnx5vuypviwpHnt47bsIvPpIHCj2zLo3PPqnrTqX3Sp37Ssn7lxpb3 +6MP//t3//+r//+f//+///+j//+3//+j8+OPXs6jIpXvbrXbjtX7mxYTuzJv0zZTxyJPxxpbz +y6X42LD41a3xwZfer4Ltw4X615773qn23qn86Lv957P53a3z16jrzprewI/RrH7Hon++kHXE +m2zNq3vXsojfvYnqwprpy5/wyp/pxpfru4jVqX7Bi2XTonjpuoT0x5b81Z393rL01afwxJTu +1KD01KnlxJPkupHtxpb0xpHtyJjz4a7//df//+z//+///+n//+z//+///+r//+z///b///D/ +//T///D//+3//+n799/s6cXn9cr0/+T7/+L//+r//+j//+v//+z//+v//+7///f///b///f/ +//T///T///H///T///P///v///n///P///H///X///X///X///X///T///P///P//+////f/ +//P///L//+7///P///D///b//+z///H//+r8+OXn9tTy+Nv8/+z+/+j6/+H7/uXy+9vz/OPs ++eHz8dXl9dbt8dnj5M3Ty63J3bzN2LXJ377l/M3o9dbu9NTe17vJzq3NyaTNzarKyaTJyKfG +v6HHxKTCxJ+/xqLBx5/JyKfK0KjK0ajOzqzE0arOz6XL06bL0KjM0afJ0KvN1KXTzqzEy6DK +0abL06vF06LMz6y2vpa3upW9yJa5r5intIa1tpO1u5OzuJiqvI2ws4ymtIytuJGvt5Orto+1 +uJWss4+qtImos46xtZKst4uqsIurtom0uZSvtJCkp4GkqH2kpISmpoWdqYGrq4SepX6jq4Oc +pXunpX2hrYWgo4SYn36dnHyXmnmanHmUmHeQmniRkHKPkHOIf2h4elxzeF52dmF7eWVoYFdE +P0E8Pjk8QDk7Qzk7QTY7QDs2Qzg8RD09QDg5Pzk7QDU+QT08QDc+RDw+RTY7QTw6QTg7RjZA +QDc9RTk+RDg/RDpISD9FSTxRT0V0akesk2ezl3aulW3MtYTTtInUsInWrYfFoYHEm3q8nHm9 +kXW0im6pgmale2eUdFqJbVOJbFaQcVeCZ1hqXkpta1Dx/LD///v///7///j///39//v9/+39 +//D+//P8//L3//D+//T///7///bs/un1/+j6//Lz/+nt+ujf8tXV68vj8dfg79/a4Mzs+ef4 +/u76//L19ert9eLp+Obu9+n6/vL8//z7//Hv/+zw++33/vD9//Pz++z3/vLq++bz++zz+Of5 +/vj///v///7///////3///r///j///z///f3/vP///bq5ttcTEhCRUJERkVJVl5VdHZheIhg +e4djg5Fqe4xccH9dd4Vkg5BrgJJhgIRtfIxKSlE6REA3Qjg9QUJCRD5IR0M/SDpDSTtaT0Vs +Wkd8X02IbE6UdlaVe1Wifl2simKvjWSzkGK9lWy+o2+9o3LEoHXCp3LRr3zMqXbZtIbQtH3W +sH3YtIDgtX/Tsn/ZtIDStILUtIXUtoTQr4PTuILPs37Srn3Jq3vMpHW7oXCyimqTcFZ3WUlX +TUV0W0SGbUeaeUengVKzh02sjFajiVejj2Klj2KaiGSchWGpjmGldkyQbk+VcUyac0ykfk+o +jlzu77n7+N7r4b7iw5jpwY/huIzctYzTq4bHm33DlG/Mn3jMrHnct4r05Lj+/dz//+z///H/ +/+z///D///P//+////L//+75+N/Qs6XTqXfUr37duYHpwZHtxYz0y5j01J/51qDy2qj92a77 +4bjzyKDouYnmt4Tu1Jf53ar93rH54az847r83qz12qru06PgvpXVsobjyKbbxLHJpInRsoPi +voDhvpXnx5Pyz57vzpbwxpnpxI/ju4vFkGnaqHHrwIr1ypn41p/+4bP64azzxprkwIrqxqDc +s5HfuIXrwJXzzJn1xpvv1Jj75bL8+Mb//+T//+j//+j//+v//+v//+j//+////b///L///H/ +/+////L//+////T//+f9/d/2+9r6993x+9T7/+f//+b//+z//+7//+7//+j//+////X///f/ +//L///f///T///T///T///T///b///X///b///3///T///b///L///f///L///7///j///X/ +//P///f///H///L///X//+///+///+v9/uv5+OHq8Nzy/+b//+j9/+j+/uj3/OPy/Nvx/t/i +48XN4sHi89Dl7tjq9NDk48/W2cTUz73Czqzh7NXp4b7V3cTQz6DP1K/N07HOy6jIxqS+vaTD +v6W7u5G9w5a6vpfCw6C9yqXGzqrNzqjD0qjOzKrN1arO0KvKz6zJ0KHIyaDT06bKzKjR0KjJ +2azO0a28vZq6u5LGyZ++xKO0tJiotIysu52uuoy4u5qsro+vrpGfsoWrtJGutY2uuoqptpKs +t5O0uJGuuZSttYuwroeqsomps42otJO1tY6lqYqjp4Kcp4CjpXedrIWlpYGfp32VoHuXpH6l +poSdp4Kep4KcpoKWoICboHidoYGVmHmVkXeOkHSKjW+Hg2t3d2R0d2B4dmF7gWhsYVxGREE9 +Qz49Qzw3QjhAPzY8Pzo6PjxCQkQ7QDpCPTw9QTVBQT47Qjs8PT88QTk/Pjs4RzdBQTw/RjxB +PT06QjtGQj9FR0BLS0JKTUOCbUyckGaqj3aunW7JsIjIpITPtn/PrZHHooTBlXW2kna7kW25 +i3CshG6mg2qbdluDY1aIclOPdF2BZFRqWVRrb0rw+bj6/+n///////3///////////////// +//z///////7+//n5/+/8//n9//X///v///zw+uju9Ofm9uPo+932+e3v9OTq8eT///////Xy +/+/+//b///z///39//r///r5//Hy8e31/vX///f///7///////////////////////////Hx +/+rz//H7//X0++33//H7/vX///X///f7//f9//Xm59pdS04/QjtERkY7RTxDRUxHU1NUcXxp +gYple4xcd4NneoxfbodjeYNpe4ZthI1jX2o+QEA+Qj88Qz87Rj5MSDpCPDtCSDpPS0BsV0d0 +XE2GaUyLdVCYclibflushV6ri168k2i3mGy/lWrAmW3EnHDFpHXIqnDVsHzWs3vSsX3TsHjd +tILVuoHZtIHZtYDdtYbYs3/YsoLZsoTVsX/OsH7PtnrQr4DLpnLAmW+fdFtsUkphUD9SSkVY +Sz55XEiYdEqje1Gjf0+NgFuLeFysoXjWyafUyrHGqJahi26pl2+sdleZdEudelCpfVSuklzs +8Lv5997k3sDgw5vbsofcsYfcq4Xaq4PXpoPfupP01bL/+dT//+n//+r//+3//+7///P///H/ +//T///D///D//+r58d7QtJvWq3zcr3zku43iw4zxxpPyy5n0zp3226P94q793rD42aryy6Pq +t4rksYHnwYT02aX84an75LX74bH83q3w3KrwyZnpwpLfvYjz58H799rn07/XrovauIzlxI/t +xJ/qzJ3w0afty5fwyJbetonjroHjsX7svob3zp752qX+4Kf74a/11ZvpvpfZtYLZr43QoXnl +u4fz1ar2zaTxyJj64q332ary1p/2/NH//ef//+P//+b//+D///L//+r///H//+v///T///L/ +//f///f///T///L///L//+z+/+f7/d/299j1/9z//+n//+3//+///+r///D//+7//+7//+// +//T///T///P///j///P///H///L///n///j///T///f///f///z///j///X///T///H///j/ +//n///f///P///H//+///+n//+v//+z+/uz7+uTt++H+/+X+/+v9/+H7/OP0+9319+Xq9dDl +59bZz7u5vafP5cPp9dfq9Nrq9dTg08LD0qjr6dHJwpzM1rDO16rQ1K/Oz6vDxaDExZm8wJ22 +t5Sys4q6uZe3wJjCvp26v6HExKjIyqrQz6nEzqnM1K7IzafNzajK0qTN2abM0qrS2anOz6i6 +vpW1t5C7w5rMx6PCxJi0tJGut4+xtpevvpauspOvt4+osImtr4yus5Gxs4myto6st5KytJCo +spKttI+vr5CqsoyksI+ttI2msYiytpGko4akp4Kdq4GrqIigqYGhqYalqoCjpIGcpH+kpoOh +qIKbon2ZpICXnX2dpnqion2QlnqVjnOPimyMk26UiG17d2V2eWR8eF97el9sY1tHSkNBPj47 +PzY9PzgwRDNDRDw5RTo9QDw3QjVAPzs4QDk/Pjs3QjY7QTs3QTg+RTg9Qjk8QTw4RjtERT5D +QkJBRzVJR0JRS0VNVEPOxpSMg36onmvWrpa4pobFqHnLqoq9oHzFp3+/nHq1i3G2mHG7kXeo +gWSheWSeel2ZcWCHalaJZ1l3ZlB7ZEyAdlrx/rv///////////////3///j///////////n9 +//T///P7/u/z/e76/+7///b0/+7z/+r6/+/8/vvn++bg/9fv/+L4/O/s9uD3/+rz//T1/eX2 +/+74/+35//T8//L///3///j///7///////Xs/ef5//T7//X+//fz//L9//j///T///v///// +//Pz9un9//v///f9//z7//H/9+7+//v//fLs7N9ZTENBQkJAQUBAPz1EQkVESUhHRE5TYGFi +bnlkgohpeoljgI5kgI5keIRpe4JudntFQ0k8RDs+O0VAQztGQT1CQjtCPzxARTxiTUV0V0h2 +YUmNaE2VdVWefFulgF2niV28kmyxkmivjWXDn2rBmGzBmnDEqXLQs37VqHrUrXvVrnzVsH/c +tIXXtX/fuIXbtIDZtIPWtX3TuYLUtIDTsIXQqX3NqHfQpnXGoHOXalhjS0RcRkBQSz9RRkFY +SkR9ZkaIakuFc1Kom3jBup/T0LT0+tb5/OX0893hwr+olXy3jm+lelWqfFCnglG4mGH39cj/ +/+n89eLw4MHwz7juyarz0bL01rv/9dX//+r//+7//+////H///H///P///D//+////L//+7/ +//X//+j69uHLsZDWq4Las33ivYvwypDyxZrzy5z315782KT21Z3716r516XyyaHouZPjsoHi +t37szJfz2KLz05700pz00pr1yZzqwZPkvY3dt4b05rn/+t779ODpxrTlv5bmyJr2zJ7v0ar2 +1KrzzaXqwZLeqX/kuX72yZT40Jj916v316f51qXz0pjyyJjnvovaqnnLmGvLonbmtYX1z5n6 +2KT0y57y0Z7z0KbuxJfy5bT//+X//ej//+T//+X//+z//+v//+7///L///D///f//+////T/ +//P///b///T///f///H///f//+///+38/OL4+N34/+L7/+b//+r//+r//+r///L//+n//+j/ +/+r///L///T///H///D///b///H///f///T///j///D///n///b///f///T///T///P///f/ +//H///X//+////T9/uX8/+j//+X//+n+/vH189j1/uL9/+D6/eHz/Nf1/OD18tbq9dj089bo +687c4M7S1b/S1LjK27Xd7dLk8tTu6dHN5MDe0r3Iz6PRzqjN2KbP0q3MxqrLwp/Cw529tJOz +t5a2uJO5uZm/vJu9vp3Bw57FyKPIxKHGzKTKyaXLz6bNzKbNzqHSzbDMzq/OyarDvpu2uZ6/ +x5nJw6DDv5rDwKGzsY+utZK2t5i1spOuuI2vtpG8t5KvuY68upOyspCqsY+sspCysYyztI6s +s5OsrIeqsYmrtZOuuZOvr5e0tJKvoY6Tm36foH6cooCoq4WjqIemp4KbpX+iqIemqYmkp4Sg +moCWm3uXnnmcnXuZnHmPjXKJh2yEiGuSjG6Ni3KBfGaDfWZ3cWF3d2JkZFFTSUw4PzJAPDo8 +PS87RTw7PzdDPD9BQTg3QDk+Pjk6QDw8RDg8QTg/Ozo4QzY+QDk7QDk9Pzw/QzpBPT09Qj1I +Qz9JRD1NSUVVZESnpICIfW62wnSjkKRzZ2aChGLftZq2lH+2lXyxjHK9l3m2k224mHise26o +fGGhfGOdeGGUcFiacFuBaVVvXlFzaVH1/bT///j///n+//b+//X///////r5//D9//j///// +//v///3///b///H///////////v///38//Ds9uXg9c/p9eDk7Nnh6tPr8OLs+ejy+urs7+Xt +8uDt/Oj7/u76//T+//n3/+v3/+vz/e7+//3///f///77//X7/vP0//L9//X1//H3/vH///j/ +//7///f4//H+//r+//3//////fTq+ebz8OBVTUpCQz86Qzk/Qz07QjlCRUE2QjtHRUpIT1Rf +YnBee4Nvg5RpgI5ldollbn1UZHNFSk8/RD09Qj06Pzk6QTxCRDpAQDlARjpQS0FmV0J2XkeC +aE2NcVWbdVWYeFilglqujmS8kmSvjWLDona+mmnHpHLEpXTMpXPKrHbYrXfQqnXWs33ZsH/Y +tX/UroPWs3zVtYLSs33Xt4PWvYLVs4DNqXzPq3jHqXTHoHCgaVNsTUJfTT9XSTtMRz9MR0Bl +W0uCck6fl3nW17LY1sPR17vx+t38/Oj9/+by8NnLvqu4pYC2jWGngVKnhVDFt3X5+9T//+r/ +/+z//+v//+n//+r//+39/Ob//+n///H//+///+////L///H///H//+////T///P//+///+rx +6tfSwaTWsYThuIbjwYztw5Pryo71xpX21KH815/22Zz726v206X0053qwpXfrYfYo3XivoLn +x5jv0qHvxprovozoxY7nvYrdu4jbuYTt4a7+/NP//OD36dDryaLlw5ns0prx06b016Hzz6Hm +wZbdqYHhvIHuypP22Jj837P95rD/37L516HvwJPkt3/bq3jMnnDIlWzbvX/0zZf53KT20pvu +xJPowKDgu5Tt2aP//9j//+b//+L//+f//+T//+n//+v//+n///D///j///T///z///X///r/ +//H///X//+////j///H///f///j//+3//+/7/t35/Nz8/97+/+z//+z//+3//+v///H//+7/ +/+n//+v//+z//+///+z///f///P///T///T///f///v///j///X///P///T///b///f//+// +//b///P///X+//H+/+j//+f//+79/uj0/d/p+NT9/+D6/uLt/t/5/+P6+t/t9dnq8tfp89Tq +8dLt8tfl6MzU1sfJ3rnU28Hc5Mff1cbR2LTM0a/O1KfS16/T1ajOyqTMw6bEyKS8u6O5upmr +tI+ztIm2v5S5vZq2vZvDwprIx5zQ1KjD06nNzqjK06PS1KzL0qrMyKLCv5jCvpS8xZbFxZ/G +wp7Iw5+/w5uvtJC3t5azt5O6vJasrYavs42yvY2ytpKvt42yt5Gus42ttZK0vY+ur5Wrsoyp +tIWqsIersI2utpCusouotI+vpoWlpX6bnHaXpH+lrIOep3+kqISdo36bpICepH6lpoOZonia +l32Wm3iXk3uSlnaRkHOCiW6LhWeKiWiOlW6EhG18dmNucVp8dmRoZlNWUUlCPjw4Pzg2Pzg4 +PDc2Qjk4QTo0PDY+Ozk6PzY6Pjg3Pzg5OTs2RTQ+PTs3QTY+OTg3QjhAQzk3RjhDRDhBRjlN +Rj1ESj9gbkmFf2SimXSeoIN5c39WVVhxhVTlzrfGzaPv0cfOopHBn3muhHGngmejdmGae1il +f2egg2KbdmSPbVeKaFh1Z0h/bVH8/rn///D///L////////////9//T///////P///////X/ +//v///f///z6//by/+7y++bq9OHe79fh9tjo/tzy/O/n89fq8eD////5//b0/vL///7///// +///9/+vz/vP7//3///n9//f///Hy/ej4//X+//v7//T+//H8//r4//T+//3/////////+//5 +//D+//n///b///T///3///////b19udcSUo6ST9HQkEwQT4/Rj42PD89Pzk2QENARURGSElJ +S1BQXGhdcHtmeYZhboJ0iphgcIFCREc/QD07Ozs7PTs9Pzk6PTc/QTxKSDxdUkZpWUmAY02F +ak2SclSefFijfliqimOximC4kG65nHG8l3HCn3TEpnLMq3nOq3nUqHvQq3nWtYPUsn3YsYTU +sIDUsn/Qq33UsX7QsHvYtHzTs4TUsYDPsXzTqn7Pqna5h2Z9WEZlTkNfTUFVS0RSREBZVkWf +mWi2s5nZ5bzm5dHR1Lnw99X+/+b//+v7/uX59OHp48fVu6S8n2vLrnPq7r3//+7///L///P/ +//T///b///P///L+/u7///L///T///H///T///j///b///b///b///P//+////Hz79vUtpzZ +uYPkvozoypj0yZn126P72KH51Kn71qL21af616Hx1pn1zZnpyJfit5DPnHfYsn3nxZPhwpPb +sYTcsILft4jjvInetoTZr4Xt36r//OD//9r9++Pz38rsxaLqypny1Kfy05/syabeuI7ToX7p +vYT005z63aT/3rL/5Kr+5LD52KnqwZXgs4DXrHrLmnPDmG/ctH7ty5b41KL416Twy5zit4/b +u4/x5LT//+L//+b//+n//ez//+H//+z//+f//+z///L//+z//+v///L///T///r///r///X/ +//7///f///v///j///v///b///r///f///D+/+z7++H5/dzz+df0/t38/+P//+3//+v///H/ +//L///T//+n//+z//+3///X///T///T///X///T///b///L///f///T///T///T///f///P/ +//X//+z///X///P///L8/uL6/ur29tzm89b9/+L1/ef49dzs99Hq99bx+t7t8dXp+drc583h +7crRyq28zKzQ3rzNxKu/za7W0LPL1avSzavOzqnS2qzU0anY17DLyZ/KzanHxp68u52stIut +r4ymrYutuJW0uJy+x6HJy6nM0KvL1qjR0anJ06jM06jJyKbKwqa1uZG7xpm+waLJxaTBx5bE +w6K+vJmqrZOqtYywspGpqoirso+vtJKtt5OvuJiyuZWzuJSwsImxu5C1t5ivtpOrqomusYup +so+rrYursI6ssYyttY2rqY2inn+Zo4Gknn+ep3ufo4KfpYCdoX+Zpn+npYOepn+ZnYKZlHaa +mHaYm3WPl3iRkHeKjGuIim2Ih2eTj3GMhGx3dmRvclh2eF5ual9fUkw9QTs0PTg7Pzk2QDY/ +QT02PjlBPz4yQDhBPDw3PjZDPjw3PTxEPDszQTdBPT46PD5BQjw8PUBAQz0/QjxCRjxHRj9G +TEJteVGFgGm4q4yBenpkZGGIgWGTqmy2qbrm8rr///H//+vixNTLr6mljYCdgmKVdWSih2SV +d2eYe2GJb2eDblqFb1eFeVvy/bv///////////7///z///b///////////////////3///j/ +///8//3+//D6//L///v///32/fDy//De8dLg8Nvm9d3e7d/n/Ob7//H6/vLy++Lr/ev1//H6 +/PXx9+Xw/ur9//X4/fP///7////5+/Lx/+rt/Ofu++r2/+72/vH///35//H9//z1/e7+//X+ +//L///r///j+//X2/+f9/vj28OBaS09ERkM6RDw2QDk9PTc7RTw6QjhCPjtARjw9QkBBQjk/ +RkU+SUZMV1hYYmZcdXtweoNVXF9FPj0zQTc/QDgzPTdDQjo3QD1HRD5MSkJnVkN0X0yAa0uQ +claXe1qhflelhlqogVmtj2G8kGyxkGrCnG/DpXDOqXvRsHzTrXjZsYHUrnrbsX3QsXvUtYjX +tH7TrX/OqXPSp3fSqHvSsIHOq4DQtn7RsH3OsH7Oqni1gVqHW0lsUURoTUdjTT1fU0Weq3XI +va/H1bPj5MvW2sTj8M78/+j8/+f8/+n2/OL5+dz159Xg0L7q7Mn9/+P///D//+z//+///+// +//L///P///X9/+X///T///L///P///T///n///X///P//+///+v7/+fr5czNspbfuovrypby +x5Py06Py16L33LD74an92rH83J/505/3z5n11JfqwpPcuIXOonfZu4Tpv5PfvYbhuYrXrH3a +qn3at4LeuIbZrnvy2q3//t///+P//9/9+eDr1K7sw5fnw47y0qHrzaTevI3crH7owY/10pP9 +2qX636T+5a395rL72avyzJ7qu5LVrXjKn3TBlGncsILsyZv30p30zZfyzprpv4TYr4Lr47D/ +/+L//+H//+b//+X//un//+r//+X//+n//+r//+///+z///D///L///n///v///f///j///z/ +//v///j///3///b///v///b///b///b///f///P//+3//+n7+9vq79Du/9j8/+b//+j///D/ +//D//+3//+r///L///H//+7//+v///T///b///b///f///T///L///n///j///X///j///P/ +//r///L///z//+79/vD3/uDz9tzs8tbv/uD4/eDx8tbj+NPg6sTf7s7n8cjU48bZ58fg9djk +7cbX3cfY07ydroXF0anJzKnO1KvK0KnVz6fF0a/U0anV1KXOzqTLyaXIx6S6w566s5SxtJKn +sYyqtpG0wJC2vJfCy6DJ0qXE0qTOzabEyKDFw6PBwJS8vpi9vI/FxpzLzZm/wZ3DwprGxKHG +v5mvrZWnqIOqq4WmqoSttY6otY6ysYyvs5CzvJivtJKutJCxvpW2tpOyuJKusZCtsomysJCq +r4iwspGnrImrs5CusJKhpoqdo3+jqICeqYKjqIueooWdpYOZon+boX6YoX2Zn3eYn3qYmn2V +nHOXmXaPlHOOim2Mj26Uj3WKjW+PjHB5e2R8eGBwdlZ7cWJeWlFDPz81OzQ/QTo2PjZAPDs3 +PDQ9Ozk6Ozc4RTU9QTw8Qzc5Pjo3QDo9Qjc9PTs/Qjo7Pzs5QjU/QD48QjtHQ0RKRzxPUUV+ +g12MkWqwqZV+dXhlbFq/tZiuwY789d3//+b///T/+uza1Mqknbd1doBgYGCGgVW/lppzZV5m +Xk9gXUxbUktYV0lgZk/x/Kz+//v///////3///f///r9//b8/+z///n///b///z///Tv/+7z +/OX9//b///v///v8//D2/+3r+OHh99Hv9eDj7t/i59P///X///79//nw/PH1+vP8/vX9//P5 +//D6//X6//T+//7///f+//z///////////P0//P+//T///3///Dp9u/4+uz2+PH+//L7/+/6 ++e7y/Oz7/vn///////v7//NfT047QEA6RTlCPD07RDg7QTs7Pzg6PDs7PDhBPzo7QTs6Pjs9 +RDxCQD08QT86SURFSUxJRUlDPT46PjY5RDw/PDM2QTc+Pjc9QDlJQz5WT0JsV0d2YkqJbU+U +clWmfVubf1Wqgluvi2G0jWa5k2i7lGy/pXXKqHjKrnbVs3zSrnrWrHvRrn3bsYLTsIDZsoHW +sH7ZtYTWrX3Xt4PUrnnUrHzRsHzUrX7TrHzRsH/Mqn7AmWiwfFmkfliYelFzWkyHkmPLwaTA +yLHf5MfR1b3W48Py/d7+/ef1++Pu8d70++P8/+T0/eL+/uj//+v//+r//+v///H///L///T/ +//P///P//+j///T///P///f///T///X///H///T//+38/ubm28fRuY3ZvYrkyZbwz5r10qH5 +16H42qX95av83a/84bP63af41KXzzqPqx5XWrIXOo3PhwYjkxpPnxJPes4PZroTZr3zesYbU +rHvSqnzz5rL//+r//+r//On//Nb27drnx6zjxZPlxZPmy5XguJTXqnzowYvzzZj726v937X4 +46z846v43azx1J/qx5bgtoPDnXS/j2rasn3zzZ3z0qL0zpjswZHpvI3cr4Paw4v6/Nb//+b/ +/+b//+///+r//+f//+b//+r//+///+v//+v//+j//+3///L///j///b///b///7///b///z/ +//j///b///X///r///X///j///f///f///T///T///P//+/9/eLy+ND09dTq8NPv+Nf2/+X/ +/+j//+7///T///L///H//+r///L///D///L///P///z///b///X///L///v///j///b///L/ +//n//+n//+3//+n+/+v6/+j9/efh7Mjr687Z7dHk89Tl89rs8Njh5snm7tPc6crQzrfN2MHS +2rzIz7fT2L7c0bbGy6rFy63LzqXM0KvO163U2LnU1bDSyqbO0KvEyKbJxZ++vpi6tJGvs420 +tpSttI+wv5K8vJy7w5q+xpnLx6PExpfBwZ+4wJa8v5m+xJXKxJ7Bxpq/xZnFxZ7My6nCv6Cu +tI6oroOvqYqkqoutr4uosoa0s42vt42xt5WstZGutJOmrZCstI2usY2tsIipsYKwsZGntYuw +tJKqr4Wrs46utI+io4ufpoSeoH+eqoOkqISgq4aWnHyYnnqgo36doH2jo4Ogn32ZmHyVmHSZ +m3qUlnqMinSLjGuPiHJ8fGCKi2Z9fmeGe2Rpc1qDeWBaXFNMQUQ3Pzs/QT07Pzs7QTY7QDc4 +PTQ4Ozg3Pjs9Pzk6Pzc9Pzw0PTg2OTU7Qzg9Rjs5QkE6QzU+Ozw6QzdDSURKRjplekixmo6G +jGelmoV4cHF5gluvpaLR5qX//+z//+7k4t3ay9TAxblxdJJlbGhVV1ePk1+osppbWHRTU0pQ +U0tERURHTUZMUkfq/Kb6//T///7///////////////v///////v//+7///j7//X9//T+//j7 +//X4/+v3/+zy/+vu/eTs++bh+8/p9N/m9Nvw+ejn+OHt6tLt/uz7//T7/ev2/vD9//71/+v5 +//P8//r5/+/7//Hz/uj9//L7//b///z///n///v1/+/3/u39//3///P///j///7///3///v/ +//r7/e35/+////Tv6tlaT1A+SDpCQj02RDU9QD43PDlBPzw3QDdBQTw5Qjk7QTo2PzhAQjw9 +PTw9RDw9QT41Pj42QTxBQEA9Qj43Qzc8PTc9ODo6QDQ/QTc7PzVTS0FdTkN1WEqAbkuRcleN +eFKefFyehFWrhmOog162jWS3lWbEoG/Jo2/HpHPNqnfQrnnUp3LOpW7SrnXKrnfUsH3Ys3zR +sXnXsYHSs3/RrHvNqnXOrnjQsnzTrXzKqnHSs4DPt33TrIHJrHPAnXKVc1Z+b1WrrojEvqHS +28HQzbnK1LTh79Py9N3i7NXj69Pt9d76/+f//+r//+3///H//+///+7//+3///T///L///T/ +//L//+///+////P//+v///P///D///T//+z19ePXwabVu4rhwYrpzJT12KH43KX62qn43aT8 +3Kr94aT94av736n716LuzZnnu4zctIfYuHvp05ru0Z7qypTgwJPasoHUsIPSqojHo3bgyYb9 ++9j//+7///D9/+b6+t7x88zw3crgxJrbtIzWrnrfsIPmwYftxJLu1J752qb84LD95a313Kv1 +1qbu15/pyJHeuIvPqHnRqnbxzYj526b615/00KDrw5Pis37Xq33OsoDz+cn//+b//+3//+r/ +/+z//+v//un//+j//+n//+f//+3//+n//+3//+f//+z///n///r///j///f///v///r///b/ +//r///n///v///j///j///3///f///b///j///b///f//+z///L///L+/+r3+djz9tH5/tn4 ++eLy/dn6/+P//+P//+3//+z///D///H///L///j///L///r///b///T///b///D///X///b/ +//D//+z//+3///H+/u7r8tzr6NXn9NTo79C6sZi+17jd7M/q89bi68zl6dbZ4MnOz6vFzbDI +yqrF1b3O073TzbDAxafGx57FzqPN0afS1KvN1KLO06jOz6rPx6bByZ+8tZSrtYm1sJClsYmy +rI2vtoe4vpnAwZ++xKTIzKHGyajCx5jFyKTJxJ7Gx5zEwZnBwZq8vZ65vZnIxJm2upOzr5Cr +uYuouIq2tY6yso2nq4amroSztY2tuI2utIuvs5Cvs420tYyys5Glsouwr4mlt4+ztZSttI+o +rY2utZCquZClpYeanX2dqIOcpXylrICYon2YnX2ZpHybooCbpH2hnnqYn3iQlXOamnSVm3qU +lXuOknCBgGmBfmB/g2GAg2OHgWlzdFpoaldxel5pYFZVUUk4QjpBODg6QzhAPjw/RTg8QDg4 +PTQ/Qjs6QTU5PDc5QDQ8PzY4QDc2PTU6RDw4PDU+PzM8Qjc/QzdDTDtMTD54h02XioaIjWfY +0pl7coRveVqVp3/x/8f//+3/8+7l4tKtpcJ8f4ZbY2l3cGpVXFSRjHtSVFhUU1RMUEdLSEND +R0JKTENQW0fr+KH+//j///f///L///n///b///v9//r+//T///j///////P///X9//L9//j/ +//H6/vLy/Ob1++zi9eHg99Dr+uPn79/g7tT///H2/uXz+O/x//H9//D///77/+/4/vD///T9 +//P///j4//v///H///3///D+//T///75//D9/vz9//f///v///3u8ur9//f9/+7v/Of4/vP/ +//D4//L7/ejy6+NVTU9EREFAQTVDPUI4Pjc8PD02Qjk6RTo6PDg1PDlDQTs5PTo1PjY9Pzg8 +Pjc9Qzw9PTpBQzw9QDo3Qjc5QTZBPjY5PzFCOzk3QjhBPT1BQzhdS0RpVkN+YVKGZkeNbE+S +cU+jgF+ngV2nhVutiGK3lGrCmHG+nXHLpHbLqHPRq3fTrXvWrn/br3zUr33Vsnvas33YtH/Q +q3nUrn/Sr33TqX/Mr3nWrnrKrnzZrn7Kp3bVqXzRsnzSqnvCo3KtgWJ9ZE6GfGW0qovJx6vY +07zEy7bU38bp8Nrn59Dr79bw++D3/OL//+v///L//+7//+///+n///D///H///T//+7///b/ +/+r///X//+z///P//+///+3//ent3NPPs5fYuorhv47tz5Tx1KP12aX516T73KH12KD73K37 +4qz84qr016XtxJzgsYHUonvQrXbozpTr0aLwyJrr0Jnpwo/at4nOpn/Krnvp5av9/+X//+r/ +/+7//+f9+OH5+Nj06szhyq/bs4zeuH7twovvzpP31pn32KP72qH62qX61aTvzZ3ry5rox5fo +xI7btofMpnrYs33y1Jf826j81af305/0xpHltIXQnnbGnXLev4P28MP//+n//+v///D//+r/ +/+z//+r//+z//+j//+z//+r//ev//+n//+v//+v///f///b///X///v///j///X///3///f/ +//r///r///3///r///v///f///v///L///T///P///n///T///X//+z///L//+f//+r+/+T7 +/+D3+t3299X4/+L//+3//+z//+7//+3///D///P///b///b///b///T///T///P///T///D/ +//P//+3///H+/vH58ODf68vl89jq9dvm18KXiH2TupfO17/X5cnX4dLT2MHQ3sPJx6rBxrHE +xau8v6jBvqPDwKHFxKDCzKHMzqrSyKjZ1KrI1afQzKPMz6bDxaXEwJa3rY2npoaoroulqYeu +rY61tZazwJe8vp3KyaTDwp/DvZrCvZPCvZPIxaHDyKDCwJvExJm/xp7Ev5qwt5OzrIuisJCv +tY+tsZGzto6rs42trYmjrZC0tpStso2lrYWntI+vr4mqtI6ms4+vs46xtY2qs5Wtr4yppo6o +r4uuso6kooWYnn6irH6doX6ep36jooCdoXyapnufpH2cnXmYnXuXlHaXmHmZmnWcmniPj3OM +h2uFfmV/f16JgmCGiGeSinBycGBtbVpze1luZlxXVUpAPD45Pjc5QjY7PjY7PDg4Pzk8Pjw8 +PjQ/QDhBQzg+QDg8PTo5PDQ7RDhBQTw/QDo5Ozo9QDU7QDk/QTZUWEBhXkqKcl2NfFnHspRu +Y3RdVVDD0YLP1MH//+jv2uvw7NeNiK5wdHtlZV3PzJ9qbnd0Z2xTUE9MVFFJRUhGRkJISUNL +TEVobUnt/KP///////n///////3///3///3////5/+v+//n7/+7+//L////////7//j////z +/e/4/en1/PDo9OPf/NX7//D2/fDu9OPq9+Ln9eHt/un7//L+//v1/fL6/e77//H4/e/8//L7 +/+7y/ez+//7///////P5//X7//r7/+3z/PD+/vv7//v7/+r9//r///v+//j///77//T///z/ +/////+3q6t1dT1Q2Qj4/RDc0QTw/QjY2Qjg5QDY6QTc7Qjk/PTk2QDM4Ozk6QDg5Nzk1QzI6 +Ojk3QDxCPzk6QjY5PTk8PzY2PjU3QTk8PTY8QD85PTZCQTxJS0FZUEZpWUx5ZkyEaEqLb1CV +dVKaelmjf1aohFqviWKujme6lmzBpXDIpnPGqHDQrXXOq3Hbtn7VsXrauYTYsnzbsoHatnjV +rnnRrnnSr3/TsX/QrHnTrXvNsn/TsXXMrnjTsH3RrH3Nr3rHqHSxhmN6Y1GEfl61pofRz6vV +0bvM18Do9cz5/+D7+uTs+eH4/OT8/+n///H//+///+3//+39/+v//+v//+7//+///+n9/uz/ +/+z///H8/+f3+97v49DNsJXStIjbwofq0JLs0ZT326P42qr23q743av63ar346363qj13ary +0J3fuozToXfBkGvas3jlxpXrzp7oz53kw5PmvY3dtIHUrYPk2J34+tT//+r///H//+7//+j6 +++Lw7dLn2sjUupbovIvrxo711Kb42qH74Kv53qv33anw1qPvz6PqwZHftYPXtHzZsYHQpnvE +onDmx4f22qb84bH62an20JvlxJXbuIvIonbFpXPov4vz1J39+Mj//+j//+3///L///b///H/ +//X//+b///L//+7//+z//uT//+b//+///+3///X///L///v///f///v///j///f///n///X/ +//v///n///j///r///r///r///3///P///7///f///7///T///z///j///7///f///f///3/ +//X///f///H//+///+n///H//+7///D//+7//+z//+z///T//+7///P//+z///z///L///X/ +//T///P9/uj5/Nz8/OTb8Nbc6cbp8t/h58i4iHl7a11ycmyRl46twKmvuJi6x66817fM2L3D +y6nCxqfFzKXBwp66wJHQ0arOz6vR16vL1KfJy6bN0qfNzqTLx57GvZquuZanqoadsYyqs4uu +q4mtrpOvuZbDw5m8xJvCv5i9xpi9vp2+xJrHy5e3wJHBvZO9upm9wJG2upOjr5GkpYOoq4yp +t4mvtJSnu5SwuZewuZSrsYejqYGcrIqlrYmirYylrYevr4qqtIqtso6uso6usYujrYmpsYan +s4qrp4qcoHymo4KaoICcnHmbnnOXm3qWmHWWk3uXlXOVmnuSj3GOkXGYmnqOkHePi22DhmV/ +gWV8hGCIimmQinCCh259emd3bVp5cl5fWFVaWUw3RD1BPzg2RThBPjkyQTZDOz8wQjQ9QTY3 +QTc/Qz0zPDQ9Qjg2Pzk7STY8QTs5Pzk4QDk4Pjo7Qjo9QTw/QTdcYEWYgFuujWK6i2i2j2et +imS2pYrd7bH//+////DPw92qoKdtaXiit2XLw9V0eIhnb2lUXE5LT1FHQkRIUUBDR0NFSUVS +UknY8ZX9/+n///n///z///n///////////f///r///////7///X///j///j///////n0//L3 +/uz2//Dp+eDl8tDe7tno9d3m8Nz6//j7/eru9unz/vT0/ev1//H+//ru/OT6/vz///f4//v/ +//////////r///r99+n0/vX///7///X7+ez6/u76//P7+e35//b+/+/6//L///r///f6//T/ +//v28t5fTV5BQkFAQD5ERTw7Qjk9RTlAQz09QDI/PTg2QTk9Pzk5QTY+PzwwPzo7PTU4QjY9 +QDY4RTw6Qjo7Qz08Ozg+Pzw8QDg6Pzc7Pzg+Qj47QTxDRkJZSkJdUUd1W0t/Z0yHcVCQdVKY +dFedeViofV+rjWS0jW2zk2rCoXPFpnHRqHrNq3bTqnjZs3/bsoPYt3/ZtIDUsn7atIDatn3b +tHncsX3Rrn3WsHnOtIHVtIDWsXzXtIDWsYXUsnzVtH7TrX2+mWyfcld3Z1OvrIXc3rLt8dbl +4tPb6Mn+/+b8/eb1+ODu9+D8/+T//+v//+7//+z//+X//+f//+j//+v//+v//+z9/+r//+n/ +/+r49t7ayrfGspHOsIHRtIHnw4/vz5j31KP426T53bP42qf837T44K784Kr146n93K3qxJfZ +qYHBkGnQqXLevIzhvorkxYzgwZDhu4rXtYTUsn/n3Kz7+9P+/+L//+j//+7//+T//ubu7dLg +yrnfuZXnxIzwzY372Z/63aX84LP73aL54LLz2KrvzpzqxJTjuIrZqn7NqHbPpXvJo3LixYX2 +2aD95K/+47D42KvuypXmvozbsYfHpHXjv4jz3qr/5rb897///+f///D///b///P///P//+z/ +/+3///L///P///P//+n///H//+r///P///L///T///j///r///j///z///3///z///v///D/ +//r///n///v///j///3///j///r///P///v///T///z///n///j///v///v///n///j///z/ +//T///n///j///T///L//+///+r///D//+z///L//+z//+7+/+z8/+////H///j///H//+// +/+7//+7+/9/+/ezg6cLi6NDi8NHt8Nbd5MWsiGloa1RmZlhke2CRlIKcrpCms5i2wqW6w6u8 +xprKzqjCy5y9vZW/0KHLy63O0afN0avK0qvS16bOzKbNzqfDwp+6wJm2tZCorIqmsIatroie +rIertZG/xZzIxp6/vpfCwKG6xJ7DxJvHxpvIwpy5vJfCw53Exp28tZirtI2zs5Grr4ynrYmt +s42ptpO1tpSwtpSvs4+rs4yusomoqoqjroefp4SlsoiqsYyutYyxsY2usYqkpYqlsIS0sIyq +rYein4SepH+dpYifo3ucnn2ZmnqVl3abm3iamXaQk3aXkHCYkXSSlXWTjnWLim+Dg2uLiWWM +jWmRkWyIhGuAgGmAfGd0dWBpbldeXVNXXExKP0M1QTQ9PjozQDg/Pjw7RTpHRjo7RD09QjY8 +Qjk8RDc7Pzo4QjY+Qjw6Qzs8Pjc7RTc9QTo4Pzg/QzxBPzpkYT+ihV+1jmi8lHK/lGjBm3a0 +jXPHxI76/9D//fHb0s25qMZrbm692I3U19OEeJloZWJea1VbTl0/S0RKRkNBRkBLS0ZJT0Td +9p/6/+r+//b///////////////7///T///v///7////8//v2/+z///Py/e/0++n0/Oj8//Ly ++u/t/uXk+Nnq+eDu+eXn9t/6/+n4//T9//73/+/9//z3//Hy++v3//L6//H9//35/+/1/+v8 +//Dz/u79//v///Ls/e7+/+79//T9//L6//H7/e32+fD///P5//L+//L6/u7x/Ov1/e/1/u/7 ++e1aTl1ESD1CRzxBRT47RDY+Pjs1PzY+QTk0QjVAPzo2RTk9PTg6Qjg7PTk4QTg3QDg3QTo6 +OjY6RTo4PTI5QTo6PDY0QTo6QjU7RTM/QDc2RjdBRT5NRztXSUNnVkJ2XEt8ZUmOb1KQdlCb +eFqdgVWshmKtjmK3jGi4l2vCmW7FpXDJpHLMpG7VrnXXsoHZsXratn7QrnrUq3TYsnrWsX3X +sXrSrXfSrHfQs3rWsIHRsn7atX/RsnzUrnbQtnzUrX/EqHO6lWyPcVKakG27w5/u79Dv89rd +6Mv5/t///+n5+uXx79/r8dn8/+X//+z9/ej3+d/5/uT9/+b//+b//+r//+j8/uX//+bw8dHO +u6+7oH3KrHzQrnrhvYbnzY/216Xy2aH/36nz3ar93az616f72qT74Kz23KPuw6PTpn/DjWbP +pmnbqnzbq4DVq3vSp3nSpXzHp3rXvoPw5L36+OD6/d38/dv9/+L//+T//+T69NHew67euIvq +xYzxz5X63Kf85aj74q/946724q/216zrxpbnvoXes4XarX/Po3PFnG/Eo3LdvH/23KD736j9 +4qr02qn1zJvlw4vduIbStIDsypby2qn74rT04rX//t///+X///P///T///H///D///H///P/ +/+7//+z//+3//+3//+r///P//+7//+////P///L///X///P///v///r///3///j///3///r/ +//v///z///v///n///r///j///r///v///f///r///b///z///r///3///f///3///v///z/ +//z///////f///f///T///r///H//+3//+////X///D//+3//+v//+z//+3///L//+///+7+ +/uz7/+L6/uPx7M/l9dfh9dzn7NPl6tDf4cmxj3ZucVdqaldpaVlwYVVsalJ8lXW4vpHExJnK +zqXJyaG8wp/DxqDKyqfOzqbNzarNzKbNz6bN0arIz6PPyqW+v5m+upipqYyhqIWcqX6mrIuy +uo25wJ2+u5nBuZe5xJbHwZzDxZK9wJbBvpPBwZzExKDJxqK7uJKdsZCss461tYyttIqqr4uq +sIWtt4ynsY2zs42os5CtsJGirIOmp4emsYWnpYSop4Crr4qqsoi4sY+oqH+ssIqss4uvrI+b +qIGjpYKcn3Wdn3uZnHiXlXeXl3eak3yTknWSkXaSkXeYmHeSjnGOjm6KkG6PjG2XlXWUknON +jmqIh2uEgmWGf2dtcVxmYFdYYk1nXlA9REBCRDs0QzpARDw9PDk4Rjg3PDc5QTc4QTo7QDw+ +Pjk5Qzw9Pjo2QzhART07QDo/QTQ9RTs/QDc+RD4+RDZpYEqkgFi8kGu0iGW9kW/DlGq7lnS+ +nXLKuoju47ze38+ahrRudm54dWiMkH2Ac4xZXFu9yIReSndVWEc+S0BFSEVJSERLUUTo+6z/ +///////////9//79//j///T///////////v////////9//r1+u36/+n7//H+//b8//rv9ufl +9uDc9cj1++/p8d7m69j1//H5++/1++zx/O7z/ezs/Ojz/fD2+Ov1/e7v/e/1/+z09+fr+tvw +//j///j//vv+//3////////////7/+77//X39/L3/+n+//T///3///v///r9//n9//Tt699e +UWFCRD82Qz07Pj09Pj41QTs+QTo4Pzk+QD48Qzc8PTstPzQ9Pz00Rjo2OzsvPzE1QD83PDY/ +PD81Ozc5Pzo9QzgyQzM7Qzc6QDo7PTg3PzI+PThHQD5LRUBYT0BpVkRyWEl+aUyObk6NdFCd +eFmegVitiF6ohmGzi2KzkGvBnHDHoG7LoHHJqHPSrnzSq33Sq3nVrHzVrnnNpnjUsnXUrHXS +snjTsXjUsXvWsX/Ws4HRrH7TtoXVtYfTsoHRrnzMrnrJpna5k2qUclianHLK1qbl6tDc28zZ +68v5/N3y++Lt8tzm8dn2/OH5/+X4/OXs9t72++L//+b//+r9/+X//er09dvn5c/FtJW2mHjA +oHjMroDXsYTfwpHu1KHy3KX52an63qn21qTz2qX82bP63a772K300aLcr42temS+k2jOpHLN +onvLmnTClmy/j2fEnnHhx6fs8Mv79dr799v399ny9Nj3+tnu79Hh1rjauZ3iuIjtzZX32aP3 +36v84q365rf+6K744rn226vpzZThu4nXrnbOnXLAkWTAlnK5kG3buIbz2J752KL13ab42KTs +zJPnwo7VtYjUr4Xo0J3wyqDt16r47MP//+T//+r//+f//+3//+n//+///+7//+///+z//+r/ +/+X//+3//+r//+7///H///X///L///L//+3//+3//+////n///v///7///n///////j///// +//j///z///3///3///z///b///T///f///T///r///f///b///v///v///n///7///r///7/ +//z///v///T///3///f///j///T///f///f///f///j///T///b///H///H///D///b//+3/ +/+n9/ubw7N/h89Dj8tTp99vp8tXk6s3j6svNxrGnjW2ZhGuCcFR0aVaIl2yxu5jDxpfGx6XN +yJvBu5+9upi7w5vGyqbK06THzqfLzZ/LyJ7C05vEyq3BwZzDu6C2s5enrIqnqYWksoqyuIuz +wJS+vpa1vZXCxZu5xZ3Cw5y4v5vCwZu/v5rCw5i9w6WzrpSlr5CqroiurYanroWrrY+nrYmo +rIuqupCqtpaor4yvsYykrYimroStsY+lqISlrYeqpoKuso6usY2pqYqlqoKssIqvr4uhqIyk +ooCao3+WnnyPmnWWmHmUm3qenn6SmHWVknWSmXuUknaWk3STj3SSkXONjniOk2+UkHWDgWeG +gml/fGeBfGdvdWZcW1dkbFVbW1I/QT9APDk9QzwzQjs9RTs5QTc4QDY6Qjc0PzY6PTo7RTo8 +PT00QzY8Qj4+QzlAQDs5RTg9Pzk5QjY+QDw+RTh5akiohVy9lm3AjHK7kGjAlm7EmnG/j3PB +mHS2kHSum4SHgIRrc21raVqNk1l5ZI1PV1F0gGBKU15MTEtGSlFBS0BHSEVGT0TY9Zz///b/ +///+//v+//r///////////n///b8//X8//L8/+/7//H////////////8//n1/+v3/O7l9+ff +9dDg7tf5/+/r8+Tz//z3/e7z8+ft+u7w9+j6/vn///7///P9//v///7///z///3+//n7//X4 +//L+//P6//L0/+Xw//D+//H9//z////3//L9//T9//j///f///3///T1//D+//X29+xsWWZB +RUI9Qzk9QTtCPTk7QTs7PTE9PTk1PjU+Ojw1PjE4PDI6QTg6PTk3Pjg5OzU6PTc/PTU8PzY4 +PzU4QTg4QjU3Qzo6QzY6QTk/QTczQDpCQDZCQkBFQjdJTD1eUDxjVER5ZUt8aEmKblGOdU+e +clKcgVemglurjF66kWa8mWTHpXDKomnJoG7InW3IpG7Qq3PQqHvUrnTPpHPQq3fTqnnYr3bS +q3fZsHnTsH/Usn3brn/XsHvZtYLSt37QtX/QrnnMp3XPpnG2j2+Wd1uXkGnD1Z/j4sTGy7PZ +5MDm887i5tXh6s/m7tTp79zy+tr2+uD7/+H5/+P5/t339+Hw+Nfg3ca9q464n3O0oXHGrHjX +r4DdtIXnx5Tuz5T03Kf62qX726Hz15z226L315z71qXv0qHuv53JoHPUpHHEj267i2a2h2G5 +imS5iGjPuJPe1bbj1b/t6NX08tP6+Nrt7dLe4L7WxJzivo/gs4frv4zzyJz32qT94bX54an+ +5rb96bD85br53Kbvz5zmvYXasoDNnG7AkGu6kW29k2rZt4Pz2KD50JftyJHrzpjmx43XsYbN +rXzWr4Pry5nvz53sz5r48cz//+b//+7///H//+z//+z//+n//+///+////P//+j//+r///X/ +/+r//ur//+T//+7///X///r///H///L///H///D///D///f///j///n///3///v///z///j/ +//z///7///7///b///j///P///7///j///7///n///n///r///j///3///n///7///n///// +//X///7///b///j///b///n///b///f///T///j///T///T///P///X//+////T+//D4/uP7 +/uX38N/b6cXl99vo69De7NDh7szh6M/h6M7RzrXLz6nCtZS5wo29yp3EzqbPyaTEx5nGxp66 +w5m+v5/Jx6PN1KvN0afPy6fLyabR0anJyqvGwp22wJizuZKtsI6noomkqIqdpYSlt4qvvJC1 +vI/Cwpm8wpLFxJ69wZq+vp28vZbBwpjDwpzIw5+wr46trIegqoStq4qjrYOiroGtrIytr4at +r4umrIyrsI6wtIyqqoiqsIWrsY2qsJGqqYiqq4aqr4mvsZKmqoSpq4eosIyxtIqjooCcpYOZ +oHmfl4CWoXeenn6bnnublneSmHOTkniTkneQj3GTkHWMj3KSlnOQk3GVj3GNi2qCf2OAfmN9 +gWCGg2N2c2ZcXVNlbFRjWlJDQjpDQz4xQTZBRT06QTpEQTs2QzVDPTk8RDRDQj4/Qjs3PTc4 +RTs5Qjk7QDo/QDs9PDU5Qzg+PDk3RThCRjiIcUuwiV6+l2++j2e/lnXFn27HnXLGlWnBk3K5 +imy9jHStfWaCbmiEa1qipG5eU3lQVU12dV9KTktPS0pBQz5MREZQU0iHfFzb8Lr9//P///// +//r////////////8//79//D6//X///////v////6//T2/Or0/Or6//D0/u32/+rt/+zi9tTu +9eTn7d/c59Pv/+Tz/fD///j///bt/+71+/Hy/ej1+uv7//D5//L5/ev+//v///7///v///T/ +//r///////v///z8//b7/+77//f7/+/+//b8/+/4/+7w/en+//b9//b7//L19+pzV247RDw6 +RD45QThCPkE2QTk+PTgyPDM9QD0zPTY5Pjo3PTU3PTk8QTk5Ozc1PjU5Pzo6Ojk/Qjo5PTUz +PTg4OzY0QzU6PDU5PTU1PTg6QTs3PTZFQDtCQTg8RD9MST9eT0VmVkB0W0h0ZUuHaUuNck2g +eFaWfValhVyojWG3jWq4lWzDm2rDmmjEnGi7nGnIqHDMp3LMqXLQqHnMrnzNrHPOrXbPrnfW +r3vUsH7croHTtHvdtn/XsnrYs4XOrnvYtYTTtoLUroLHqHnAkmqZc2Whl3PJyprJw63NzLLN +0rnQ2brb2snn8dPj59Tv9tr1+OD69+Tq9N34+N3x8djf38S7qo+wnXKzlm/AmnPPr4jUrn7c +tornxIvrxp/v0pj31qnz2aLw0KHz0aD11qP0zp/uyJ3esITQn3PMoHjTpHXLiXCxg1/TuJjl +48Px69Hs69bu8M719N7n5MHWz6rbv5voxJrtyJfxzJnxzZb11Jj12J763qf43qz75aj64bH4 +26jz2aLty5TmxI7dtoHUpXvHoW/EmW2/kWfaqH3t2aX42a/tyJjlvH7asoXPrn3GpnvMqnjq +yZTy0JvuzZvy6Lb//+T//+j///T///H///H///L///b///D//+3///P//+3//+3///L//+// +/+z//+v///L///v///T//+7///L///f///D///f///z///z///3///z///z///z///v///v/ +//v///z///r///f///n///z///3///z///n///z///n///z///b///3///r///7///f///// +//n///7///b///////n///7///j///j///X///X///P///T///j///P///P+//T5+dzr/93z +99zo7szl78nj69Dc7M3i6M3d6szM2L7I6b/Lxq/F0qrNyKzJzJ/N1K7Eza3NyKbGvaC5xZq+ +wZvDxqjEzqTJz6rL0qrSzazJ1qrN0arMzqrNyaO+t5Wvr46hrYedroqip4Wqro+3u4m6vpO9 +v5e4v5K2w5K+vZi9vpq+wpvDxZ7Jw5/Dv520so6qrYWor4ulrY+nsYerr46krY2ttpCysI2m +sYiosIepsIqxs46qr4azt5CpqIasrYqnspG0rY6jrIirrIWgsIOusYqnrIimpIKdpIKdpH+b +n4OdnXqcn36VmXuUmnqXlnmUk32QlHucmHqLkniPknSQmHOTkXGPhnONi2qGhGeAhV6IimuF +hGZ2cmthX05mbl5aVlE0QT09Qjk3Pzo/Qjc4Qzw1PDc3QThCPkI6RThEPj45Qjk/PTs1RjY+ +Pzs5QTg9QDc5RTc9Pz0+QTtBQztNUECRdVK0kWi7jWq9jm7ClnPGl3XFl3PClXK7jHK+jWq/ +kmy8k3C5jGyZcl2fpWfMp7VoWHFWW0pISkVFTERKQ0JATUFLUUdmdFfO/K7///v///r///r/ +//r///v///n///////j///////7///r///v////9//33/+/y/+33/+zy+vDe89bm/NT1//L4 +++bo8OD///D4/O3t+efv/uv5/vH///7///f1/+31//X2/uz+//j///b5/enz/Or6//T///v7 +//T///f7//L7/+/7//X///7///P///3///////37//P8/vP///f//+/4+e6DXnNASTtAPEM9 +QT06QzpEQzszPTk7PDc7Qzw4QDU1Qjc0QDc9PTw1QDU6PDg9RTg6QTY0PzQ9PzoyOTZBPDwz +PzM8OzwzPjI9Pzk0PjBBPj46PThEQUBFRTw/Qj5GRD5SS0FkTkJvV0V1Xkp/aUmHbU6ScFOZ +dFSfe1qrhl6tiWSzlGi+kmy9lGW/jmu1jGHHoG7MpXPMpXHRqnPOo2/KpnHXrXnLqXbXsn3X +sX3ftn7Zr3zdu4DduoLWsn3Wtn3Wtn7SrYDWr37TsIDJp3vEmG2beF+jmnLHtpXPzajW0rja +3bvf4cvn7Mvw8d/l69bu8Nvv9dnv8tvp7tTp7djGuKiwl3Szk3S7lXTIqHvWuYPftYzcvYrq +x5Xpx5Tzzprvzpny06bxzZbxy5ruyZfzzpzsw5XksILmuoPguYzgtYjnuYXiv4zjx5rd17Hn +6MTj3MHe4Lfh0rfNqIrhvovtzJf02Z351aH51KP42qj43Kj+3qj636r93LL14a/11KXvy5vw +w5XfuIncsoTSpnzLpXC/m3PCmHHixo333KP34LTyzp/qv47es4PHpHi/mHDPp3Hkwo7pxI/n +wpHr3qX9/tz//+j//+v//+7///T//+7///X//+7///D//+///+///+7///D//+///+7//+3/ +//T///j///b///T//+////b///D///D///T///X///3///v///r///3///n///////z///z/ +//3///z///z///f///z///n///3///7///7///z///j///3///7///n///7///7///7///z/ +//j///v///r///z///v///T///j///L///j///P///j//+3///T///T///P9/eLz/tz6993s +69Pk7s/h4szc28jc7s/h5s3c38bKyLHV5cXRxqvGzqXL0rXNyqfIx57OyqbBwpi/vZvCxJbF +zKXBx6DHy63O1KfPz6vMz6LNz67MzKXJzabGw5m6tZSpoICXnX+ZpH2lroa7u5u2w5O+vJO3 +upS7uZG9vJXBvprExp24wZzFxqDAvJuwr4+kp4aqrYmkrY2rro6gp4essY6qso2xr4uqsI6y +soylqoioq4Csr4qlroqqroixs4qsrI+lroWtpIelqIOkq4KrtIywsIyqpIiZnH2en36joX+d +pH+eooObmXiYmnebm3qSkHeUlHiQkHWSlXKYlXSSlnSSjG+Lim2GhmyGg2OIgWWJimeBeml8 +eVtvZ1xfZ0tfUE0/RDk8PTc7QTY+Qzo7QDk6PDVDQDs+Pzo8QzQ8OTpBQDo8QDo7QTY6QTo8 +QDs/RDs/QTk/QT8+Rj08PTleVTyifFW/j2bCj3PFkG7Il3K9kG2/hm22hmTAjWi+lG7BknC/ +lm67jnCugGeKbliclndgWWlYX05OR0tFSENCRT1CQ0FETERkYVW66pn///j///z///////v/ +//f///////r///////////////j///r2/fH1++f///j4++7w++nt8eHg993f9s3h7dXm8Nfk +8tvt+Ovs9+v0+e30++749uzm/uf9//X4/uf7//r0/ejx/PDz9un///3////////9//H9/+/y +9+rz/u79//z///P4//jz9+3+//n6//H5//f///n9//f7//X+//vy7+N5WW5ERUI2Rj1FSEA2 +PzxCQz41Pj1AQDg0QDpDQT01Qzs6QTQ6Pzo6Ozc6PTg6Pjk4Ozc5QjhAPDw0Qjc6PTwwODM9 +Ozo2QzU5QTk0PTc2OjY8Pjs/QjpHQzk9PzhBRD1KRT9WUENfT0FoV0d3ZEZ8YUyFaUmLcFOR +dFWWfluef1uri2GviWqzkGO/jWS8j2LDmmrGoWnEoHDEpHLGpHPKp3XLp3LMqXTNq3TOrnbX +s33ZuoDUtnvYtH/buIDeuYfVuoDcs4HYtIbTtIDUsYbSsIDBmG+igWS6r4XLyqbO1Lnb28Hh +38Pi583w+dfs8tju79vo8tXx8dzm8NPKxrGnlXaxlHS0mnXFpnvStX/avIrivI7mw4/oyZjp +yZzzyZ7yzZnyz5fw0p3t0KLz0qPy1qDzy57pvYvtzpzoypjqwZXgt4bmuYrevIXds5DZrYXg +ronduInjsI7oxIn41aX01qf23Kz64LH33rH93qj846/74a752qz626/02qTyz6LnxJXet4fY +q4HPqHbGoXa9lnDTqHjx36795Lb14azt16PhvozWsYPIpXm+lnTSrn7s05vvyp3dvYzu2bH5 +/OH//+z//+3//+z///P///X///P///P///L//+r///D//+z///H//+7//+////P///j///f/ +//v///b///b///L///H///D///D///X///X///z///f///////r///z///7///7///z///// +//7///7///3///j///3///n///j///3///3///7///7///r///j///f///7///7///7///7/ +//n///z///n///3///f///v//+////j///X///r///L///f///X///X//+v+/uzt8dns79rv +8Nnd7tPi3bbc08LR6cvY4cbY2sG5yKrY5L/j2cPKzaXMyqm+zZ3LzavFxJnDwp26uZDEwZq/ +x57Ny6jD0J/MyKXGyKTIzKjNy6fEw63AxZm9tp2roouTk32Vnn+froSuu428xJjCwJ+7vZq3 +uZa5wJS+w5m8vJWywZi+yJ+9w522tpinsIqlqYylrIaoqYekrIWvtZCntZGqt5OksY+orYmd +qIKpqoKlrYenq4WmsI2mroyqtYi0sZKrroqmo4KiqYimsIyqr4GlooCYo32dn3+fpH+kpYGb +oH+YmXyZnXuWkH2Nk3WalnqWnXqUlnSMkm6UkHaHimqSlnWNj3OKiGyHiW2Cf2VwcmJ8fGB7 +dmBnaFRTUUs6SD44RDY5Qjw7PjY+Pzw0QDdAQD84QTlARD02Qzk+Qjo1RjxAQD01RDdCQj0z +QDtBQzw3QjtCQj07RDt7bkOkhmK6km2/l3TBkmq9kGy+kG2/im22hGOwfWS4jmjAmG7AlXS9 +jmu4i26leGCBXVFnV0hRTk1CQz1MU0ZHS0RJS0lKUEBkeVDY7bP+//T///////////////7/ +//z///v///v6//T3//D7//X////9//v7//L8//n6/+/////6//D1//jq/9zx+e3k8Nrv+eP6 +//X+//v6//v///7///rw+uz6/vb5+efr/Or6/vL+//7///31+er9//j+//f+//z///f+//T8 +//b+//P3/fbz/+719+70+efz++zz/er6/vT///b4/+/t9eLp8uOQYW9EQ0I2QTlAQkM7QTo6 +QTs8RD05QDo7Qz07Ozo8PTg7Pjk1Ojw2RDk7Pz0/Pzs1Pzw8Ozo6QTo6Pzw6QDdAPDg2Ozk+ +PkE6PDo7ODovPjc+O0A/QzlFPzo4QjY7Pzg8QjlLRz5WSj1fTUNnVUh4Wk16ZEqDZk6La06R +dVmee1udgl+rh2O2jWW6j2m8kWm+m2rAl27DmmzImm7FoG7LonHJoWvNpnbKp3DPp3PUq3nY +sIDVtH3eu4fat4fctojbuYXdtIvZs4bZtoTVsILUsIbVsH/EmnSokHjKwpzX2Ljd3MDg4MTp +69Di4dHr7trp7dDn8Njg6M3KyruokoCtkm+ukm3Io33Gr37ZsYXZw4rsx5PkyZfuzaTqxprz +zpr4zJ7zz6Hwz5vyzpr0zpj40aLxwqT1xpfz0qLtyp7vxJjyzZrvzJ/yyZ7zzpj21KT31KT3 +zp/yzJ731Kr325343az95rH+6bX+5rD/5Lb/5LX/6LL53rH3263yzp3kxJPht4jYrX3UpnvC +mHK9knDRuXr24bL65Lv54LPz0qLivY/Ronu2k3GviW7HpnPt1p7t0p3pwpfn3a3//+T//+r/ +/+z//+r//+z///D///H///D///P///X///L//+///u7///L///b///X///j///X///r///r/ +//7///7///b//+v///T//+r///D///b///v///v///7///z///7///r///3///7///7///// +//r///7///z///7///3///r///r///z///z///////7///7///j///3///////3///7///7/ +//f///7///////7///j///f///f///7///T///3///j///f///b///X9/uvv6tbq89vr997o +69Xk8NTX48i7qprV58nW2MDJvaa1ya7D2rnO0KrN0KfCxZu8yZ/Ex6C9vJy6u469wZnJzaDH +x6jMzqzGyqPNyqvHz6TNxqvExJ7AwqGvtpSsqZWanXybj3yXp4CqtpS5v5e/wpm/wJrDwJnD +wJq5w5e/v5i/vpa3vZrBwJSusY2rso6mqoumrIykqIimrIqns4y1uJWqr4mrsImgsIynqY2k +rIKpsoqntYywr5Gns4ioq46rroqvuJOqqIqusIuuso6yq4inpYeVnX6ZonyipH2booGdooGe +on+doH6UmXmYknSVmHWalnyPkHGXknOSlXGSj3eLjW6YlHaLjnSNhW57fGV9cWF3fGJ+fWNm +XlZOSko5Qz84QDs4Pjo+RjpDQj40RDs8Qz04Pjo9Qjo6RDw9QTo5Pj85Qjk6P0A4Pzk/QkI9 +RDZASUA8QDdBSkOReUywi2W9i2q9jHG+j2W3i266im67i2m0iWO4hGS5iGm+iWnAkG7Dk3K5 +hmutgGeYcGBvXE1RSklMSkZGTkdFSUlHSEFJSkdWYknT66P9//H///////////////////// +//n///7////////////4+/fz+en6/+/9//P4//D2/+78//rr/ufh/dXz+unl8dzn8+D1//f6 +//D8//b+/+/z//L89u/t+uj+/vv////////5++Xt9eT1/u/+//bz/+3///n///v///Xz+/D+ +//v///////////////v///78//b5//H8//H9//z///////+uX3I+STs+RTw4REBCRjw5RD47 +QT42Qjw3RDc4QDtCQDw1OzQ7QTwyPzQ4PjszQDU7Pjs2QDQ6PUExQjQ9PT03PzQ6QD08Ozg3 +PDo7Ojk3QDc7PjU/QTg8Pzo4Pzc6PTg+QjhCQj5ITEBVTEFbUENiV0ZwWEp0ZEmHaVGIbU+T +dlmZflmmgV2qi2OzjGi0kGm9k2a3kGvCnG7Bl2jDnWvDl2zHqXbLpXPMpnDWq37PqXnZsn7S +tHzZtH3ZtYTcuYTbt4TXuIPfvoLev4bXs4fSrH7XuIbUr3vJoHuynXPDwJba1a/b3MPh5MXm +6Mvu8tjk7dTl7s7R07ytnoamiWuvk2u1lnLDpnTOrnrZuYrkw4znwY7oxY/wy53v0J331pny +06T10qL31aTy1KT02aP11aH21Kn32an+3a313qr53a783K/+46/83LP54q373bP23qz616/6 +3Kn947H74q355q766bj/7Ln867P75bP857b86LHz1qXsyqHjv5HhuojVq33Lo3S5mXC+mXDh +xpD55bD96Lj65bDv2KXkw5bEpXy0iGmxj2fFmnPo0Jry1aPs2J327Mb//+T///P//+v//+// +/+z///f//+////b///f///n///v///j///L//+7//+z//+z///T///j///j///n///X///7/ +//j///b///L//+///+7///H///b///v///v///////r///////n///7///f///z///z///z/ +//v///j///r///r///7///b///X///7///7///z///z///v///n///7///r///7///n///// +//7///3///n///r///P///f///j///v///j///b///j//+///+7+/ujt8tzf7df9/ujx9+Lj +8tHj5NHd48zEyq/J1LbG3b3EyazOzbrD17TSyKvCvprJxaTFxZjCvp24vpa+v5rAxp/LxabM +z6fLzKLNzqbHyKHNwqPKyJ/CxZu6wJS0so6kpYSUoX6bmnmZpoS0to+9wZu5vpq7u5TIvJS+ +wZvAxJu6v5TCxZi1uZS2r5KiqIuus4+kqIahrYqrto2pqomwtYqltIaqr4ypq4usrYyoro2q +rIyksI+mrIqlr42nsIyor4uutIilqImksoizrY+mqISqrYqcoHyeoH6bn3qaoIGepH+epISb +m32Vn3ybmXWUm3SbmH6PknWVkXaOk3GaknaSlnWblHeNjW6Kg2qAfGN0dF50fGCDgmpsalpQ +UUtBRT09Pz02Qzg8PzY4RDo4Qzw9Rzk1Qjo/QTtCRD80PTk7Qzo+Rzs+Qj84RTtAPz04QDdD +Rj9AST9oYEimhle3kWi7k2y9j22/lGy4iGm2iWe7i26xhm6yhGm+iGK+imqoiWusjWq1gmq0 +hme1f2hzWVdOUUlaVUtESkZFSUlFS0JEUUhVXEmy1Yz+//T////9//L+//X////7//L9//T9 +//L///r///z7/+////z///////v8//Xw/+70/ent9+Tk8OHf89Xu9eb0/e/r7eX3/ev6/vv1 ++ez6//v5//f7//T///L7//Ts/+Xy/uj6//b///7///H59fLy/u/5//X1//X+//X///77//Xy +++7q++Tt9+r6//H+//D3+e3x/vD6++r0/u79//Ln9NnGaXg9RDo8QDo2QDo9PDo6QjY5QDs0 +QTc7PjgzPTc6Qzk9QTg7QT0+Pzo4QDU2Pjg2PjozQTo2QTc2QDY6Pjg6QDU3PzY3PzJAPDo3 +PDQ9PT0yQTZDPT06RDRBQTs3PTI9Pj88QTVCREJFRjdMREBXTT5iUUZtV0l1X0d+ZUuGbUeQ +cVOTeFaiflmjg16pgl6vjGO3kGfAmmm4lGi/lW7EoHHIn27Cpm3Qq3TKrXLPqHjNrnLctX/P +tXvUtHfQrXfasoDfu3/juoLcvYrevIPdvIjiv4rfuYjVsYfTroG3mXfBvovVy6nZzrja38HR +1rbKzrPHzKytpJSlimSviWi4mmvCnnzOqXXXs4bevYfkxZztwJbqxZ3rxpjty5Hxzpzs0Jbz +2Z7x16H41aLu1KP32qL63J7636T55Lf85qn85bH846/+5a/54bL/5q335a766Lb42a353q36 +56/967n25q/75rn75rH95rb55LX63ary16Xuz53nxJDdvITXqn+/oHa7k27PrYLy3bH57Lz8 +67X34rDx1J7gu43EnnSti2m0i2nFqnXn0KPsz5zr0Jvz68T//+b///T///H///j///D//+// +/+3///T//+////L///f///n///b//+z//e3//+P//+z//+v///r///T///f///T///j///n/ +//b///X///b//+3//+3///n///f///r///r///v///7///z///n///X///r///P///j///z/ +//z///f///b///j///r///P///7///X///3///v///////v///7///////r///7///v///z/ +//f///v///7///z///j///L///b///P///X///P///f//+////f+/uf37tf0/uDz/ePq89vv +8NPg6svd3cGow5nS3MPAzq7KyqXAybHC1LbMuqbByKTJx6G+wZi+vaG8v5q+yJ7KxaC+zKHH +wZjKzpnQyK69wZfJwJ65vJTCwJyusIWfpYmXnHuipIWcoX+nso+1v5W7u5bAwZi+v569xp7C +xZvEwJi8vJq2s42vrYmirYqqrIuxrY+oq4ekr42trYmnsIqrrIimqYSoqoilrYiwr4yosomz +sIqprIyqsIuqro6wtJSttY6doYCgqoWqqoakqomqq4mdoIKaonuhpHycnnuWn3qbnHaZmnqS +mXiSmHaVlHuXkXick3qTkXSYm3mYl3Wak3mNjW2NhWyDgWN6eWR7eVyDf2N3e2NwaGRJS0g2 +PTo7PDg4QTg9Qjs4RjQ8Pjg2QjI4PTc3RjE8Qjk4QzY7Qzo4Rzs1QjM3QDY5QTc8PTk3PzxE +TD+VfU+vjGW7km3CjG66jm6/j2XDlG/JmmzGm3q4im3Cjmy/jW66j3C7iW++i221iGe4h2S+ +i2mab116aVJfV09UUUlGRT5DS0JJTEZLUki645f///P///D///z///////////////39//r+ +//X7//P+//f///7///T7//P///D+//H7/+/y+uzo/+Pi+tfk9tzh7dro8N/s/+nq+uz6/+7q +/uP0/ej4/vP8/+z1/+39+fD///7//+vy+ub7//X5//X///P++er6/vz////5/ez4/fD9/vn/ +//7/+f/5/vP5//b9//v//e3///79/+z0/OTx++rCbXhASURBQzs7RkA7QDk6RDs9Pjk5Pzk6 +Pzg3Pjc9QDszOjg9Pjs6QTY+Ozs3QDg5PzszQTFAQT43OjU7Ozo3PTk6QDk3Pjg2Pjk2PTM7 +Ozg6OzRAPDc9QTk3PjpBPDw9PTU0PDY6Pjk8QzZIRztOST9YTURfUURrVkpvX0qFZ0uEa0uU +bVKMdVKifl+bgFyphl+qi164j2u5j2a+lGi+lmvCj2bAlGbHn2vPq3jPqnrRrnnOq3vOq3nU +rn3TrXjYsXzZtH7ZuofevoDkxYzhwoviv4vcwovjxJXZvYvdtonHon+9poHJyJTXzbHPza/S +0bLBx6Koj3ipjmezk2q+pnHGpXnOsHrWuoPmv43ozZrszJrpyJjuxpjoypnvy5Hr0KDw15nz +06f52Kf22qj32ar516j63qL+4LT65af/4r7/4rD/6Lr94bL95rP73rL65Kv73bH74q785bP6 +5rP44rD15rT24Lb24LD02Kv426bx0aXwxpvlvpPVr4jCoXu9m3PhxI/74bv857z96LXz27Hw +zpnjvozSp3m2jmiyj2jOp3nkx5TszpvjxZLv37H//+n///X///X///f///L///D///H//+r/ +//P///H///L///P///b///P///X//+7///L///D//+3///L///f///n///b///f///X///j/ +//H///r///H///H///L///v///r///z///r///r///f///z///P///7///z///7///v///j/ +//z///////z///n///3///z///z///j///////3///z///3///z///7///3///////////// +//r///v///j///3///P///b///L///f///D///n///X///L+/vHx8dLs/Nzv/t/1+t3y9tbk +7s7h6NDNtaGq0qrS1rXLzKXFzJvNxqnEyqXCwaLKyJ7Dwpy1vpDDwpm+uZXJyabBzZ7Ev5rC +v5nFvqC/w6HGwZrHw6G8v5q6s4ytrY+jpoifnnqboHmnsomvt4+vvZKuuZLDw6HDvpvEwJi8 +wJPFxKa7u5G8rpaqqX+tspKrr4isroyvtIuys5SyrYuvqYmprIyjq4iwtYqvtIytspCutZas +qYytroevr4ysr42sq46np4ahrYitr5CorYavsomSl3qjon2an3igoH2YmX2do3+Wm3mhl3yY +k3WalHqYl3qSkXGWjnWUm3GUk3yWjneLinKHhmmFfmJ4emGGgmWDfWV+dmJ4bWFMREc/Qz4+ +OjY/Pz86QztAQUA5RDZAQj88QDY+RD09QTY4Qjw+PTc7Qz0/Qzs5RTs/QTs9QTxDRTxkYT6t +iFu3kWvAlHHAkWvCl3G+kGzGmnXImWrLmnjDknC+jme/jHK9imy7jGy9jWq+iWi5hWa6iWiz +eWaDY1JVUE9UT0hFSUdESEFMTUZLUEas0Ib///////////////////7///z///7///X+//r9 +//X7//b///7+//j7/+78//X1/+72++/6++nx/+rf+NDl79/q797t997y/PPz//H6//L9//7/ +//n99/L1++/8/vb///79//Pz/eXz+fH2/Pn9//v///39//z5//P7//T///f8//f///X///39 +9ev0//D7/+73/+7+//77//T6//D9//v///bVcHs6RD4/QUM6QDs7PT86PjxAPD41QDg8Pj44 +QDdBOz83PDk7PTs2PTg5PDc9Ojs3Ojs0Pj06PDs8Oz09Pzs3PD08Ojc1Pjs6PDw3Pjg4PTs1 +PjhBPTs2Pzk6PTo1PDI+PD42Pjc9PTs2RDc7Oj06QTtMQTxSSEBXS0ZgVUdxWEt4XkqDaU6L +cVSWdVeac1mXe1yphlqohGCvkWW1jGavi2S4jmm8lWm+nnLFoXLLo3LDom/LnnLOpXDOn27L +r3vYsYTPsnras4TVt4PZuoTcv4flw4zjwJDgvY7jw4jiv5LZtYvOq37Lp4u8rpGtsJGnqIym +kG+nhmazk2e7m3O9pHTDpXvQrnzduorfxYzty6Do0pzxy53kwZLsxZHlzJj10J3w05n22qfw +1KH1z6PwyZzyypnz0p/42qn02KX13LH93bD23av326363aj62Kf23av21qH13qr+67b76bzz +2aPw26zz2qr01rHu06L0zKfrzJrov5rUrn/BnnXMonjy1ab44bH66bL13bDu0anpxprYtIrL +p4C7mG+2lnHcvYvsy57myJravpTXr4b4/tv///b///j///P///L///f///P///b//+3//+// +/+////L//+////X///r///D///T///H///P///H///T///r///n///P///f///X///3///j/ +//f///n//+////T///f///3///n///3///z///v///n///////z///3///////n///n///z/ +//7///3///n///z///7///////////j///7///////7///7///////////////7///////7/ +//7///n///v///X///n///v///n///j///f///L///L9/ero6tjc7MXy/uPv/ePv793j7s/d +6NTT3sDEn46txKXEz7bDzqHCxaLFxaPDxKrKzJ/GxqG6t5m8v5q3vpnAvZ+9yJnCv6HAwZjF +vJ61v5bExZ7Cw53BvJ2zuparqYGcpYWgpIidpYOir4mtupK0tJi3u5W6uJm2vZi6v5u6upy9 +vpq5vJKtrYyqroilsI6ut5Wkp4yuq4insY2oqY2jrYyoqoWnsYqqsYywq4uoroOvq4ulrYOu +rpGjroWtspOqrYanqYemsIqtsJOosY+jqIubln+co4KWoYKcooOWmH6WnICannyZnnybmHyR +jXaPk3SUj3aZlHiTjHOMkHCSjnOLkHCIi3OBfmyIhmh9gmaHfmt6emV/bGE/REFDQkA5Pz4/ +RkE3Pz9BQDw7RDk3QTo9PTk7Qzg6QTw8Qjk8RD87REA/RT04Qjs+QD08Qz8/STySgFK9lW6/ +mHO/nXDFmHnElWvHnnvFmm7Ln3zHl3HElnXHkWbDk3HDi3K4jGzCim25hGe5gme8hmiyhmSo +d2GKYFJzW0hqU0pFSURIS0ZGT0mnwnr+//b///////////7///////////////f///////r/ +//v///z///f6/vP///z6//D3//Pv+ujg9Nzm/9rz/+3u/unr9OTy/+zz9+fo+ez8//D1//j/ +//v///7//+/z9+7w9+b9//z////////7//P9//X9/+75/fL9//L+//n5++3z8erl8ePr8Oj1 +/uz0+Or8/vD29+z9/+z5//D+//T//+7Yen5FQ0A/Qz0/Oz8+PTw5PTk2Ozo3OTc6Pjw2Pzs1 +QTk7Pjg2Pzo8OzwzQDg9PTkwPjQ3Pj01PTQ7O0AvOzU+PDw3PjU8PjswPjc4Ozw3Ojk9Ozg/ +PTlBOz0/Pjk2PTs6PjY8PTs6OzU6QTk7PjZBQDs9RDxKSEBTSD5eUEJmVERzVUh6XkuDaE+H +bFCObFeZdlOie1+if1irh2CxhmKzhmW0jWW5kG+/l23Cm27DoG7HonHDnGzMpm/LrXPNqXjP +qnrWrnvYrnzauILUs33buITfwofkvYrbv4rcwI7cxInfvpDUv43QrISwlnWvj3WehGmpi2ax +kGfBmW/BoHHDpHfKpnjTsnzevYzqx5DwzJftzqPwzJftx5jtwpTuyJPvzJb00KLx1KLy1qTy +1qPz0aDyz571zqrx2KT21qv316Xz26/226n73a753Kf10qnz1aLy1aTz2qz147D55LLu2Kf0 +1aP01aX10qfvy5/tyJrow5bdsIjJoXzMsXju1p346Lf857r44q/11ajmx5bes4zEnXzAknSy +j27exorq0J7lwZbWuIfBrofx8cX//+v//+79/+j///H///P///T///b///L//+3//+7///D/ +/+7///P//+////v///D///X//+z///L///H///f///T///T///T///f///T///v///n///X/ +//X//+7///X///f///r///v///////r///7///n///z///f///f///7///r///r///r///X/ +//v///r///v///n///////////////z///7///j///////r///3///n///7///n///v///X/ +//3///n///j///b///v///P///b///L///b+//H6/eHk6c3n9NPl9s/1/d33/eDz8dLa3cbj +58XS27qysIy6uJy/waG5xJvGwqbDy5zQzKXDwZPBvJu5wqDDu5q7w5jDw5u7wZjHwpy5vY27 +u5C9v5XBxJu9u568uZewroyip32amoWbmnyiroaut4u8vpS6vJW2tZG+uJazu5a7upW1vI+2 +uperqYatpYebnoKlp4icqIWoqoemqX2jrI6mqIOgq4emrYWtromsr4SsqYmqrIelq4SsrYWt +qoWnq4mlrIWqqIioroajrJCrsIWmq4Sln4WUnnuenXyQl3SbmXmXn32gnnuPlnWblHOUlXqa +knKOk3aQkXaOkXSUk3SNhm+MjW2IhGyAhGiIiGV5emCAe2h1dWV+cF1FQkE8Pjk7RDs4Pzs9 +PT85PjZBRT86PjdAREI+PjdBQj4/PjU/Qj1BQjs/QD1AQzs7Qz09PztcY0Cpi17Cl3LEn3PF +nm3KnnW8j2zLmXbLnXTHnnXLoXTIm3fLmnHHlnTGjWy6jGXGjm28hmy9jWnDiG20gGSsfGCa +b1eKaE+Ma1NuWEtXU0ZJUkeluXP+//b///////z///z///////z///////j///r///v+//L2 +//H4/+z6//L////////6/fzy/enq/eTh+NPt+efj8t3i7tn1/ejx+ev69evp+ez2++rl9eD2 +/Of+//j7//n7//b///T19+77/u78//L09eH9/vr///34/+/2/e75//L9//v///////////// +//n///74/+r1/u7///f+/fH8+evddYJFQkZAQkE+Qzo7RTc6Qzs/QD0/Rzw1PDs9Qj09PzU5 +OzlBQzg2QTk7Pjg2Pjg2PTk6OzM9PDYzPDc6OT42OTc6Pj03OTQ/OjwwPjQ2OTs5QDZAQDs0 +RTQ/Ozk6PDk8PTo+QDo8PTo7Pzk/QTw+Pzk6QTxDQD1KRz5WSUBbTkZhTUNuUUh2W0h/ZU+D +Z0qLaVGSdVGcd1mYe1ireWGlhV2zhmWwjWS8j2q9lm7FmHW9mmq7l27IoXHNp3jOonnJpnTR +qHjUr3XVtH7buYXbuoTcwo3hwojfxJDaxIvhxpLYwI3Op4m+onHJr3qsim+jhWarkWS6lGu7 +oG/LpnbGpXfQqnjSsYTfuofixJPtyJvtxZ7mxJHtyZLlzZrsz5zuzZfuzJrvzZvz1qHw1aPy +0Z3u0qnsyJjy1KXt1J3z0arz2KT126z32Kfy0Kby0p3yzqPtzpTwzaXx0qHv0Z7t06Hx1aD1 +0aXzzqbuw5rkv5XXr4bGm33Jq3fv2pr55LH03rH02KTuy5zgwJPXq4i9kHi2iWvDsnDq1Zns +0qjju5e+koKvq4Lx/N3/+u7zxMHy8Mn//OT//+3///j///X///n///P///P///H///T///L/ +//P///D///X///H///H//+7//+7///L///D///b///P///T///T///n///f///n///X///L/ +/+3///T///j///n///v///v///3///r///7///z///v///j///z///f///v///n///P///n/ +//////3///b///n///v///v///7///r///v///n///v///f///////v///z///f///z///n/ +//7///L///f///X///L///D///f///L+/+f3/t3v79ns9NPn59Dl9M3x/OXz8t/m5s3PxrDJ +xa7CyKy9yqW5v4rFw5a/x6jKxprFxqXEwZ+7wp7Bupy/wpe8w529uZS/vJe2vYvBupO4vJW+ +vZG6wZTDu5u0tYqur5KkooWnnX+PlnqZpXykromvuJG7wZu8w5zBwaK+w5W0uZS5t5S6tJWp +rYunroiusYqnrYerqIqmqYSqsYypqoirroqiqoGtrIqqsYeorI6lrICmr46nqoWsr4ivq4yp +rISgpoampoOjqIWjqIanqIWjqYGcnoGZmXibnHycnnqYmXWfoXqgnnabm3yPl3icm3uOk3aZ +k3aPlHKZj3eNknKXk3KNkXWQkXKHjGyEfGp3fGZ8cV1xblpxblZGQ0I9QTg9QDg8RDw9PTs3 +Qjk9PTY5Qz86PjxAQTo3QTU/Pj86OzU6QkE+QDo9QT9DQDlGV0KWh0u+mmvHo3bKqXjGnHHE +mHDJlm7FlmvJm3nInnPOnnPGm27HlXO/iGfDjnLFi2vAjGm/hmW7imW8hGmyf12ogF2gdluW +cleQblSEaVRwW0VhWUWcr2b9/+j///////3///////3///z///////X///v///////r///z/ +//////j3//Dw/+j9//T////v/+zj+dPl8N/q/eHp9uPu/+/3/vP///nx/ev2/u////7///fx +/+P+//z7/+3z//P6/fL6//X///D6//v//+/1/+/+//D8//f8//L7//H+//Pu/+////7///v/ +//7//vn///f6+/D2/+r5/+bYgH5KSEE8SDg8Qjo8QjQ6QDs5Qzg6PTo7PzQ8Pjc2Qjg4PDg7 +Pjs7QTo3Pz46PzA2QTo3PzY2RDw6Pjk6QTU6PTMxQTY7PjczOzU7PjcvPjA5PTY1RDM1Qzk6 +QTI6OTs4RTk/Qjs3QDc9Pjk2PTY+Pzs9Qzo9PDlIPztCQjlPQkBJR0BXTEJeTkFmU0Z0Vkt7 +XUd7Xk6BZU+QbVOVcVWcdFyae1aogF2niFu0iWa0kWe8jGqyj2XCkm7Anm7Am3PGom7Mp3nP +rHvQr3zVsHvbvIHaxIfiwIziwo/fw5HeuobNsILGrHvQsoC6lXO0oW24oGjCpWzDp2rJpnHM +sHLYsXrRsHzhwYjhw4rlxZDiwYrqxYzmxJDtw5HnypDsxJXpyJXmypXlxpfkxZLowpnlwpLp +yJvpyJrvzJrqy5zsy5nsxpvqxZ7rxJ7ou5fqvZnhvIrfuo/htonivJTivY3lvZTktInmspHf +rYTUpYXKlXe6k3TEtnXhzJHtzprrxZ/ivpParo7Mn4G1nHC6wm3i2Iru1aXlu6LVnZSzfYKN +jneEqJJ0o4t9mYG5pLLu59zr79P9/9L//9j//9b//+n//+n///D//+r//+z+/er+/+X//+3/ +//L///L///P///P///D//+7///D///P///L///z///v///v///j///f///f///r///P///L/ +//D///f///b///v///7///n///n///7///z///f///v///3///7///r///f///j///////z/ +//3///r///z///n///7///z///////v///////3///////7///3///7///z///n///7///n/ +//v///f///z///b///v///b+/vD1/+b9/u3v8dfh8M7Z7sjm8tTt/Nf8/+Xy/uDu+djc4rrK +1azDyaPEw5vFxqnFx6XFyJ/IyqHEwpzAwZ68vpbAs5K3v5G8wJW+vZPCv5O2wJjDv5u+xZbE +wpu9v5y9v5qvsJOsqoqcnn6coICUo32oqoe5uo+5uZK6uJa8v5i8wJW6vZq4vJeyt46lp4ak +roinr4issIqirYOqpYSksYirr4mlrYmttI+irIiqro6jp36qqYmkroWlrIykrIWpsZCqrYep +rYqmp4OgpXyjqYOjqH+hp4Oeo32Slnqbm3qZnnmWnXOZoXqYnHuWmHSUlXaRkXOQkXOOknaW +lXqOkXeRk3aNknGVk3KMk3OOiG95iWWCg192d2BwcFlpaE5IS0NAQD04QDY9Qzo8Rjo+Pz06 +Rjo+Rjo+QTs+QTg4QDU8PTg9Qzo+Qzo/QkE9RTpOZEKYgka7mGrKnXHPp3/MpHXLpHjIn3PP +pn3OnnHNpXTLpXTCl2rKmHHLlnHJknHEj2fFm2vAkmfBiGe6hWS1gWG1hF2rf1ybdVuYcFiN +bFaGZk97ZlFoV0ylrl36/+////n///r///v///////////////j///////j///////r7//T6 +//H9//j7//b3/+3w/+fy/+rp/9zs9ebj8d3o+9z///j7//Pz/+76//3/////9/T7/uv1/u79 +//n///7///////37/+z6//r///j8//T///79//X7/fT8//3////////7//L1//H9//f///7/ +//////n///j+//Ty/eegWHpCRT8+RD87QDpAQjo8Qzg/ODg9PjpAPjo7PDk6Nzk+Nzc5Pjg6 +PDg5PDY7Njk+PDc3PT06QDs6PT49Pjg2Pjs5PDs1Nzs3OTo2Ozo0OjQ0PzI7PTk1QDU9Ojoz +Pjg3OzcyPTM5PDo2Ozk9Nzs5QDs5PD40Pjg9PTs8PDk7PDs9PT1GQD5MPj5OPkJQQEFTQ0lc +Q0ZaR0VjS0psTU9yVU18XVSCZE+KZ1aOZledcWCeeWCrfGWthGG3hWezh2PFlHC+m3DPpHTP +rHfVr4bXtIbYtYnWtYTZuoHcvIrcwYvevI/YvIffv43XvYXZuoLYvIXcvoLZvoHevX/evInh +yInhw4/jyIzqw43kx43oxpLlw4ruw5LhwYvqwo7hwozjvZDcuIzitIfWuYriwInevY/WuYvc +t4reuojZuYPfuoPcuIDbtoLfuoDivYLmxY3pwJbfsovXqofUqX3Rpn3DoHPIoni+oXDEpXjL +rXLauYnduobetpLcsYnNnIXAqXjLrXzRmoeucHuAZ2GSiHKEh3OZtZKHuY6EraSFrrF8laV+ +kKGAmp6HtaqVu7mLubB0c3qOfZHLscfNwc3QzMLU48vl6NL2/Of9/+v5/+f3/+X7/+///+7/ +//H//+///+///+z///T///b///T///P///X///n///z///3///n///P///T///X///T///v/ +//H///r///X///7///v///////3///////v///z///7///j///////3///r///j///7///n/ +//////z///////z///////7///////v///3///////////////////////3///////3///n/ +//3///j///z///r//vT99+bi583f9dTp+Nvr9dT0/OXu/d7o58TN6cbl9+Dr8tjt89nc6szh +68fR0qHDyKe7wZu+uZ25vp25uJW1t5S2tpC1vJS7t5K/vZHBu5m3t5LCvpm+wZfExZvBwJPC +w5m3tZOur5CjpoChooKUmH2bn32dq4Our46uupfAuZmyuZC3upmzupC1tZG5rJCjoYelqIio +s4yrsI2ssYenqoWproimsIerq42rsY2gqIuksISnr4mosYatq4umqIOnq4uprImurYyprIav +ro6iqIassIulqYWio4iip4Kam3yPj3WTnXmbnH2YnnyVnHmVl3qVkniXknSOjnWSi3GOknCR +jHSNjW+VjnKSj3CTjnCOjXKQh3d9fWZ+bWNvb1pwZ1ZaXEw/QT86Pzo+QTo9RDs8Pzk/QTw+ +Qjw7PTw8RDg8Qz04RDxBPz04PjtFXj2Hg0i2lVrHkm7JmXXUoH3To33QonzMnHTLk3jKnm3O +oHjPom7RpHrSn3XNm3bKnnPQnHXMlG7MlnDQmXXHlG/BiW7Dh2m3fGareF6odVuVbFWcalR+ +XlWFaE2EaU+Jc1X0+8H///z///////////////////////r///////////////3///////// +///////z/+/0/+/s/+rs/9zz/u7t9Ojj/tj+//X8//n6//T7/+/6//X///X9//n///7///// +//n9//3///P///7////////9//L7//f///7////7/fL5//X///7+//j///7///////////// +///9////9vf/vu9mSlxEQkE8Rzk+Pj42Qjk/RDs1PjJBPTg2QDc/QDc1PTs/Pzk2QTk5Nzk4 +QDs4PTU6PTU1OzU4Pzo7Pzg8Pzo7Ozc8QDg0Ozs3Ojo6QzMxPTY+NzY1QDo7QDQ1QTQ5PTgu +QTg8PjkwPTQ5PjU2QTQ7PTk2RDhAV0I5Sjs6Ojg7QDc7Pjg9SjdBSzlCSDxHRz9FRz1HQ0BG +QT5IRkFTSUJORkdXSENcTUhpUktwVlF1Xk+BaVSLbVOPclmYeVujfF2mh2Gvjme3lG3DnXLC +p3PJq3nPrH/RtIjZuoPcwIvbw5LjxZTjxpPjypPiy5flxorgyI7pzZHozZPoy4/szZTtypvm +yJPozY/oypLrxJrfwYTjyIvrxZDqwJXlworkvI3duojhuYnatoLfsYbSsIXbsYPVsYTVrX7c +tYbesIXeqoLXq3/Xp4DUoX7RnnvIjnTFlHO/jnW8knbAjHW9kHC5jnS9lnXGm3nKnHjLlH3J +lHzLi3+zfW+lfG+Pdmh1gWVmjVlqonN5kJhnfY5fcX1ib2hziIGAm5SEoq6OqbWOrreJrrKE +qqyHq7GOqbWSr7uQq7iQrbiGoq6DiKB9qITB473f6dHs6drq79v0/+f0/+b5/+P//+z9/+z0 +/+b//uv//+n//+v//+///+////D///H///3///f///3///f///T///n///b///b///X///f/ +//P///f///r///7///////3///j///////v///v///f///3///////////////3///3///z/ +//////r///3///z///////7///////7///////7///////////////7///7///n///7///n/ +//z///X//fn85+be5MzV8s/q893t/970/+v69uLu/eHw8tfz4t3c3cTo1dbU48fc3cLb4snd +5cvW0LrEr5myvYrAwZa7xpO3wJe5vY+8v5S9v6DCwJK2vpfAuZm1u5DCv5bAv5i+w5TAt5a4 +sIyyrYymnYqbnX2SnX6ZqX2krIqptoyxu5mwt5GuuJWst4qttI2wsYyyqJCfo4Wkq4imp4mg +pIelqomkrYmmrIulroyoq4qoqoekqoWlrIqqroqlroelroaqq4inq4Wip4mlqIKlqYSnqIWl +pIWcpn+ho4ShpoKjoIObmnuOjHqTnHGZlniZm3uXl3iWk3WUjnSLjm+GiGeLi2mKiWqIiWiM +jm2OjGyNj2uNjm2QjXODgGh9cGFpbVZzbVdha09xZlI9RT5BQz84QjpBRT45QT5FPzs4QDpC +RTs+RTk6RDg7Rjo/TDhVbz+ejUy6mmbBm3DNpnPPnXfOnXTPm3TNnnPNm3DIlWvJl3TJl27K +m3bOnW3On3PPnnDVmXzRl3XJlHXJlmzEknXCjG/AiWjAiWa8h2ivgWCtfVyldlmXaleJZU2M +ak2MelSGu1jy/7z////////////////////////////////////9//n///////////////// +///////8//P1//T5/+n+//v5/+/x9+v1/+/6//Lz/fn///7///P9//f+//H7//D9//b7//L/ +//799+/h8d7pictoRFhUS0Y6QDxDQj81RDY8Rj1BRTw2Qzo7RDk9QjQ2PUA/Qzo6PDk7RDg6 +Ozs6PTs1PjI/OzcuPzU6Ojk1NzY/Pjs1Pjc/OD02QTRBQT82QTQ6PkAzPzI6Qzw+Ozc8PUA3 +Pzs2PzY6PTo2PTc8Qzc1PjM5QTQ6QDY2QDo3RDs6WUZKV2RRSF9NRk9FXUxbm3mXxrSryMWk +xL6fu7uLrrSPtLCLr66btrOWna2Eo5qKlp6TsZ+Vuaiss7Sag6ZnhHqClIxud3heYmFGUVBL +SEtESURFRUI+RUA+SD9CRUNIRj9NSUJVSkNbUEpnV0xwXlV1YUl3ZVV5ak5+YFWDaU59Zld5 +ZFJ4Y1J9ZE93Y1F4Xk9vW01yV1JqV0xrVFBiT0ldUk5bR0ZWS0lVSUpOSUdOUkdKU05VbFJs +fnlrh4xwhJNugI9vh4txgJB1iJBxiZh1hJV2jZNxi5h0jpx3i5t0ipxyjJpxj5t2jZtzjZt2 +i5V0lpx8laJ0iqB2kpx+nqaClal9m6KDlqR/k559jpx2lZ57maZ9lqh6laV7lal4lJ2Hqa2I +oaZ9h551fZFscIVgZnZYWWlUTV5RZVmGxITF6cXr8uPFpsR+ZHtshmauu6uknp7C77bx/ub4 +/+n9/+r9/+n8/+r+/+3///L///T///j///j///H//+7///H///L///f///r///r///////n/ +//3///r///f///n///r///L///j///T///n///r///j///L///n///T///z///j///X///j/ +//P///r///r///7///n///////////////////////j///////z///////j+//X9/+3w7tvf +3MXQ1rzO0bjB2bbS3MXS89rl8tne8dHl5dbd49PK77nv9ubt99rs6NPNu6GxtZKjrIKvvoy5 +r5KzsYuzs463tY61tIqvuJC3tJmvuJK3upivuJW1sZSus4K0uJGvsIiwtIyqsoetsY+pso+s +uZGto4ibnYWRkXySlniiqYOqqoKlrIapsoKsr42nromqrIevtJCgpYuglYGbpH+iq4qjsYer +r4efqoqnq4akqoWptImorYqqroOhq4ioroSorIejqYifpoahqoWnqYujqYGlo4Kdo32cnoOW +p32loYebo32frIScpYSel3yNiHOKi3GOlnSZknqZmHaRlHWZmHiUl3aan3eZoHebpIGho3qc +nHqcl3uRiXiIfWl9gGF/cmB0dF94blxtc1lxbFpsZ1ZcSlNNRUZERkI/RjxAQD9ARD8/Pz4/ +RDdAQjs/RDxAS0BbdEGmg0+/k2DKnHLOnXXFmHHKlm+vi2TJj2/CkWzMmW7Jl3HMlXDUnXLO +oHPPnnbNnG7Tm3TMoG/PlXnHk3LOknPLk2rKi2y4i2a7jWu1g2e3f2SwdWGqd1qhb1uJZ1SU +a0+UbVSVilTq/6z///v///////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////3/ +//79//fy/+nr/+Dv/+f2/+/w/+vx9+zx/vn7++vz++39//f9//f8//P5/+j8//b7//D7//38 +/+v+//uUUGRNPUhIQT8+Qz5CQD86QTk+PzM/QTc3QDg7SDc7PDo0PzQ1PD08PTUyPzg9PjY2 +QDc6Pzg0OzQ9PTMxOjJBPzsuQjg/Pjk0QDk+QjQrPTY8Qjw4PTk2PTg3PDg6Pjk7QTs5PDQ7 +Njo6Pjs9PjowRDM8Qjw3QDc2PjY2RTg6PDk6RkVDQ0Y+RUFAR0JglnuGrKmmzsKz1MqpyMav +0se42NPD3dbE3dXAzcqOs6+ZmqlrkYuGl6Wwxbe4w792e4tufn9oa3Zog3ltbHFOUVdESkpC +RkNDQT0/RUBBRkJBRT9CRD9CQUFFRT9FQkFMTUFUSERYR0ZPS0paVEhXTUdaUkhVU0pXUEZa +S0tVT0hRTUpKSUJSSElKSj1MSUlGTkRRTklJW0hmf2Rbbm5kdXRmfoJvhYpqgItte4ZufoVv +f41ugoxqfotrfo5sfopwg5JqfI9ri41wi5V2jpp2ip14jZ11hZpwipRzhJ1yiJF3i59xjZV5 +k6Fzj514h551kZx6kKJ3lZ17kaF2k56Ak6l3kJ57lqh/n6V8lad4k6B0j5l4jJxldI5gdH1Z +aHlPVGZOTVRMR0lGRUhCSUZ4nG3A07fb69a1n7ZeWVtlbl99mnTF08Dd8Mjz/eb7/+/6/+vx +9+P3/+n///L///H//+7///P///b//+z///D///D///X///X///f///f///j///f//+////P/ +//n///L///b///X///v///P///f///n///3///f///L///D///T///v///b///z///T///r/ +//f///j///j///j///z///////3///////z///j///7///T///v///P8/ezu8d7a4czP2MTJ +1sXF0cHF4sPb5czf7dHd6c3Z6tPf7NDa08LE8sLr8d7y+dni5M7GuqK5vpO1vZWztoqus5Oz +tIq5vpm8tIuvu5Wxt4qnrJStsYyuto+3tY2rq4yvqoivs5ayto+1uYivrH+vtJCrsImxsI+q +p42Xkn6JkG+Zpnqfq4Kmq4assYitqo2psYitsIqvsYqoqoyjpICVo32hrYijq4mgq4iipYWi +q4ikqYigrYqprX+mrY6qqomjpoamqYmjqYWtqIeiq4WipYCjoHuiqYWnq4edpYKbp36mpoqc +pX2goISdpIKco4GSkXuLhm+JjGyXm3mZmnaam3uboXiamXqZmnmZmXqapXuflniWknKQiXCO +k26Mg210dmOEe2Rybl10bWBvcFh1a1psdFdyXlZCQjxIQ0M8RDhCOUI8Qzo9RD87PjU7PT4/ +PzhCREBnZ0ajglS5jWPEkm/NmnbRn3LOnXbIknCsjWbEjGvIkmnQoGzKoG7Qnm7LnnHLmG7R +pG7LlXbKmnfTmHbJnnPSj3HFjGnPlmvAi2m6gGSzhWCxfmGtfGGrdl6mdlmRbFWKak+Qa1OW +b1THyHX///f///v///////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////v///38 +//jt/+3t/9/5//T4/+7y9+b0//T5/+72/un5//n///fz/ujz/un19eHv/ebr79vHYWRETEBN +REE0QjhCRDs6QTlKREE7QzY7Qj02PzhBQzwzQzNDQz0yOjNAPD05QDg2RDI9QTI9Pzk7QjQ5 +Pjc9Pzk4QjI5OzY7PjM7PDY6PjA5PTZDPzdAQj1CPTg2OTg+Qjo2QDpCPDozQTc7PjkuPzhB +QzwyPTtDQDk8PDpCQDg9Pzw9QDU9QUA9PztCRkN3rJGuz8XB2s621M+90tCv0sq/3c3J4dHL +39LL3NHC3tHE4dDA18y92Mm/29C50Mqww8KPj59wjYaKp6GUs7ehwrqv0MrA2szE28yxycCv +zMSvxsKsxb6errGWv7OxyMK50MfA1ce90cO408e/2snH1M3F4Mvd7djR6NXU5tS30cu21cfD +1s2zysixy8aXoLJ1h5dnhpBziI91iJhvhJFviI94k5eCkZ5tgoxYV3JJVVtRUltGV1lqgHxv +i49qgo1wiIx1hpl2k5qBlJuGnaGEn6l9k6aFmaCKpKaOqaqOrrd8kJ1uiJB9n56FpKh2lZh9 +nJiEo6aKp6h8k6Voc4tZanJtiIKRs6+JrLGYt7OgurudtLxxgZpgcYJSZnBLRlA9RzpERkZL +ZEGcsJKfraZhVWBGSUpHUEhibFtOTExNVkiBonHT4Mbz++X3+Obr+9n5/+b///T9/+P///T9 +/vH1/eH//+////f///D///T///P///b///X///3///T///v///D///T///T//+////X///j/ +//b///T///f///X///X///f///f///z///n///f///X///n///X///f///j///v///b///X/ +//n///b///r///b///j///P///L///D+/+z4/+bv7NrU5M7S48jQ3cPL177M4LrQ28bH2MHM +3LrV38LO28PQwr3S4MzWwraz267Q89Hc58S+tJmqp4iytpKzsYmpsZCwr4i0uZC4uZO5vZOu +uYutsI23tZCut4atr4yqq4CnrIOtso24uJa8tZC1tJi1tJOttpK1r5GssYWdm3mFkG6bnX2d +qH6tqYOjrYitp4ekpoWqr4GqrIymon6om32NlXubqH+orYWpr4Wts5Cuq4emsoOutJOksYqu +upCssoqrrX+mqYKfqYanqYCmqYalqoGipIOjp4Gnp4Cko3yio3qhqoOeonWaon+fnHmYnn6e +mXqLiW6NiW2Gj3GZmnWZmnenmneVmXacmnyWm3OZlnuWk3ONhHKAgGGCdGKBeV+FemSCeWJz +blpzdFl0a1hyaFVua1ZzbFZOSEU9QjhDQjY9PjlDRTw7PzdBPzg7PThAQD0+Sz2WdUuvflay +h1zAj2nFjW2+jWbBiWu+i2PBiGe/i2TAjGekg1nEiGXAkGnLmXfOlXLMl23Ml3DLm3PIm3PR +oXrRo3jLnXbIlnDKiXCxfF+3fF+1fV2xgGCve1uzfFyWbVeLZlOPbEmfblafqGb//+T///z/ +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////v///r///v///n///37//H///71 +//by/+Tz/Or6/+/3/+3y/Obi7d/4+uz7//X8//j9/+v9//33/+vw8uvu799fSVA+Rj01RT9A +RTg/RkJEQTkvQjxBQTo1QzdDPjgvQDdAQDg2PDo9Mzc2PTY7Pzc2QTkyQDc6QDQyQDA6OjY0 +QTA7PTgzOzExPDk5PjY1PDwuPjQ7QDc2QDg7PjY1QjY8PTg6PTs6Pjg7PTw0PzQzQTc6PTg2 +Pjo8PTU1QDo6QDU4Qjc5Pzk7Qzo7PjU3QztXjHqpz7610Me639C+086y1snA2NK628zC2M+8 +2cy2z8mpwb2dureTp6Z5doVcUmNOTVVITVBqkoaHp6mOsqygxLiv0cnA18+50sqzzMSwzMiw +18a5zcaQqLGTsrCaxLywysS628/O4dbM5dTQ49a31cvQ5NbP5NXM4dW+2su8283B3NHH0suU +oLF2iJJuhZVxh49wiZN4iZVwiZV3hJt2kpeAnKN6kJx2j5t6lJt3iZhTaG9GSVtGT01eYnBl +e4JydYZjdIB2fYhyjJB7iJZtgIxziJBvhJJye4xea3xZZ3RTX2tRXGhYX3BSX29OV2FOWGdP +WWFSWmRRWGJQXGdMVWJRWGRacnNreY5jb3pda3pPYGxVaW9UXWVIRVQ9STtOWVhKSU1aXltY +UFdIQ1BCQkM/Rz9CSUFJUE5KS01KZkWx0rDP5cDz/ujt+OPr/eH7/+v//+3///P7+/H1/N79 +//L///f///L//+v///H///P///H///X///P///n///b///b///H///X///T///L///j//+// +//j///L///L///b///z///j///f///f///j///f///X///n///T///3///T///f///X///v/ +//j///n///P///v///H///L8/+fv+9/r89/g69Hb6dLZ4MvH0L3M28LY2M/Ez7XHzb6507S5 +2rW+paivxbTK1sSoxK68xaq73r21oY6XkIOdpoWqqYuopoOkrIavsIK3uJGsto60r5SrsIWv +s4+vtYW2sZKtsIetrIuruIqsrIykroerq5KtsouxtIqssYirrY2prYmciXuBkm2YpX6cpIWm +poqjsIqnq4WiqYmiqYCrp4CgrIecnYSeoICWonyprIeosYurroehsIaorIuiq4uurI2eq4iq +r4adoYWgrIKmrYGrp4KeqYaqp4akp4SqqoOfoX+pqoWpp4CWn3ydon2doHyhpH+inoCYkniL +h2uGhmWPkXSSnXeel3ygnnealXGajXeRjXSRkG6Lfm19eWSBgGR6fV2EgGSDe2F6b19wcVd3 +bVlscVdpZ1Brb1FoWVFGQ0E6Qzk3RDc7Pzk+Qjo7QzY7PzU8QzU3RDV9bUilflm2hWO6hmDA +hWm8jmjBiW68jmS+h2a4iGLHjWy4i2aog12/i2bLlmnHmm7MoHjImnrNo3XRnHjNm3TMmXLN +k3PMk27DkHO+hW20fl6wclumdlavf1qxel+nclmTaFSGaUiTbVSPbVLM1YD///D///////// +//////////////////////////////////////////////////3///////////////////// +///////////////////////////////////////////////////7//f2/u78//T///j3//Pf +99f1/u77//fu9ev7//b///79/+35//D1+ezz/fL19/H///7///3j0tJSRkk6QUNFQj41RT9E +Rjo6RT8/QD86Ojo7RTc1Qjw9QDM6Qjk6QDc9PzczQTRCPj41PzQ/RDpCPTw6PTY8PjQ9OjY8 +Qjg4PDw2RDk/Pzo0RjM4Pzc9QTg8QD05QDs2PTw1QTY+Pjs1PkE2Py80QDo6QDo6PjY8PTYx +QDY6PjkwPTg9QTs0Qjk+QTwvPzk6REFDX12Pqqeqz8O61Mu1zse5zsqw0Mi0xsamv72gra+F +lZp3eIZkaW5VTlpQTEtARkdDSEJBSEhlhHyDoaOJp6yZurmlxby1ysawycOvzsaq0sPI4dTL +4tO/082Vu7uQr7SPrbKWtLifw7+/2NPA1c+/2cvE4s7H29LK5dXF39S50s+dp7d2g45tgY9v +i4t0iJV4jJN7lKB1h5h0gY52i5KCi5hyiYyHlp16k5p9lJ19mZ13hJVJYG5FSlBDTU5WTl1H +SlNRTFdKT1lYW15TWWZOWWhQWmRNVGFRVF5DTltOT1hHT1VIT1VETU1JR1NFSU4/QkRCREtB +Qj9BQkw+QkBFS1RFS01JUVlMT1hQU11OTFRLSVZGS0tHRVRARkM+Q0NAQUM9RUJDREhBRUhD +REVCR0FGSkNER0RJTEhITkp5pWPIy8XN7sPu++Du+ePx/eD8/+3///P8/+32/Oj7/+r///L/ +//b///H///L//+7///D//+/9/+3///T///T///H///T//+////X///X///X///L//+////b/ +//r///X///f///r///f///v///D///n///j///r///X///j///P///j///X///X///n///n/ +//X///D///v///T+/uz7/+by+OXq9dfo8tbf5dLS38/C17vV7tDc2si3x7W5uKeyyrWwxqei +goautqS6qat5c2J6hHeZnZCFjXGFk3CjsompqISrrIaqsYa1uY+5wJK7uIuxtpGrt4urs42x +tZetsIizuI+vtJGuupGrtYyvsZOor4yvvpqnt4myuZOttYiwr42Oh26KlWySoH2iqoKjrYem +qoaeqoqiqIWjroSor4ecpoaboIGPnoKgqYmhrIeoqoycpYKiqoagq3+iq4Sfo4GkqYWlqoWm +poClpX2kpH+fpoSir4Sip4KfpX2fp4Whq32eoombqYCdn3+eon2dpXmioX2gpXybkXmIimaE +gG6Pj2+bn3yVnnmdmHiSkWyWj3OPjWeUiXOEfmOJh2aDgGKKg2mCf2F9cV9yb1VtcllybFhp +aFRxdFR6clpgTFBBRj46QTdBQzk5QTZCRDs6Qjk9QTs6QThUWUGZd1KzhGGvjWXKjGq+iWTD +ime0gWC9iGK3gGO4gWK2iGm9imeggFrEj2fIlHHKm3LOnXjOnG/RoXPEmXPMmWvOmnTKm2zH +lnS/hWq8hme5fVyxf2Sue1iyfV+veVuecV6TZlKCY1GRcVCHclrr/rf///////////////// +//////////v///////////////////////////////////////////////////////////// +//////////////////////v///////////////////7////////////+///2//Lm+uHz/+f+ +//v6//Hv++jy/eb4/vH3//b1/+/w/un9//3//+/z/uPl6tnWX3xERUhFRzg/QTtAPzs/RT87 +RTo6Qz48RDY4Pzc6QTg6Pzs9NzgySDg9PzsrQTc8QTgrPjg7OzYsSDc9QDQvOTY7QjU1S0RB +PzkzPDk1QjQ6PTo1QDU7QD43QjY6PTsxPzU1QDkqPTc7OjY3PzQ7QDc2QDU5Pjk0QjY3Pzc3 +PTU4OjQ9Qjo1PjI8QjU5PTg2PzpCSUlgh3ueuK+ovr2fs7iZra6Tq6iOoqCJmJl1fIVqXHBV +TlZPSk9AREFBRkE+Rjo/RjxAQz5OUVlseX17i5SFnaGex7Wrw72mxb+q1MPD3tLF4NXK49bQ +5dfG5Na+2dOv1Mit0cKjx8GrysOsycKuzcOtxMSqxsK1sciTj6x6gpBwi415jpd8hpV2b41l +YXpiYG9SWWlZVGZWVWNTUl9TUV9PTFxXUWFXVFpWT2VaVWxdUmlLT1pBREtERkZERklDQktB +RUFCR0xDQkZHSUs/Q0VFP0tAQUFIR0c0PkJGPUY7PkU+QkQ7PT5BQkg5QUBCRUA8RDxBQUA8 +QD47QD9BQEQ/Q0FAQkBCR0Y/QUVBRkk+QkRBQEQ/QUE+Qj88Qzk9RD85PzxAQEA+QTtCQD47 +QTo/REBASTtNTkxLaEWzz6WptZnb79Lo8d7p/eD1/+P9/+j9/u/2/+n9//H///T///L7/+z8 +/+n9//L8/+3//+////H///T///L///P///L///T///X///T///T///n///P///D///L///f/ +//j///T///v///f///r///X///n///v///f///r///f///P///X///j///f///f///P///H/ +/+////H//+v8/uj2/OLw9+Tn69bc287F0rzL3cTR38rL3bvT0cC2sauLgHyhuaypvqSglX2a +mZCEbWl0cmNyd2F+gHOChm6Knneqr4OorYWqp4WlroirtoyrsZC4to+vr5OutoyssZGssYKi +rH2stIewtY6ntoSrtIqmtIakpYOdqIimtIyjsY+mq5Cdon2GgmiQpXagq3yiqICkq4WhrIGe +pYacon+jr5CppIeYnIOXmHuVoIObr4alsImlsYiorYSjqYiiq4aiq4eoooCep4CmrIWjpoGi +pYSioX6dpn6aoHeipoWjpoSnqoWorYajon+aonucnn6apXqnoX6ZnXibm3eSiHKHgWiIh2WE +kG+cmniemXiXknWOimuRjG2Th26KhWqFiGmKiWeLgGmCeWWFfWFub1V1dFpnbVZwbFppaVJv +aVRyaFZZSVE3QDdDQTs4RDc/QDw9QTk6RTo8QTlDRjlrZUCce1a2h1+4hGS9fWC2gWa4gV++ +hWS1f1+0e1+yfVmveF+0glqig126i2fIlG7NoXLUn3nOpHrQonnHmm/MlW/IoG/Jl3LChW6v +gGKzfWK1hWG2fFy3gl6zfFuqd1qdbleMZlKEZE2MbEuTslf//9X///7///////////////// +//////////////////////////////////////////////////////3///////////////// +//////////////////////////////f///7///////////r9//79//v+///1//Hv/9/r+uzt +++Dv9+f8//fz//L8//Ty//r5/eru/e39//z/////htJMTkdISEU2Rz9AREE+QjQ8QUI/PjY9 +Q0E2RTU+Pz06QTg7PT88Ojc+QDk+Pjc1PzQ8Pzs3QDk9Pzw8QDU1PDU2Ozg0OT09QD08Pzg6 +PDc1ODZBPz42Njs+PTk2QDtCQT81Pjk9PTcxPTc/PjoyPjhCOzg3Pjk+QDUzPDs5OTk6Pjw5 +PTc6PToyPTQ7Pzw+QDY+Ojo6QkBVWl9wfXyLnZaTqaaPip17b39kU2dXSFpNRU1HQEhKREY+ +P0M8Pzw8P0BAQTo/QUE8RD1BREdOS01VgGmoxLSmx7+qxr+wxsOZqraRsLSgsr2jwr2zy8it +wsWitLqXq7ORpq+Nl6aPraCQp6uQqa2Om6hvaYRXVWZRSVxTS1tSQ1xSS1VNRVRMQ05GQ05E +Q0pJQExDO0hHQUxAQkZIQklDRENFQ0k+Q0ZDQkhAQEZJREg9PUU/PUY6Pj1BQ0Y9QENAPkA5 +QEJBREA+QkE9QUE9Q0U9QEA7PUNAPT0+Pz48QEA7REA8QEA6QUI7REU8QD9DPD87PEA/P0U5 +PjtBQUI7Rz0/PkI7PztBPUE+Qz5CR0M6QkFCQT09Qz5BQUM6Q0A8QD5CPT08QkI6RD04Qj4+ +Qz5BQUZLcUis1afF2rzQ5sLe9dXw/Obz/+Py8+Pb5tDx/+r5/+f///D7/evw+uT2/+T8//H/ +/+39/+36/+b///H///H///H///D///L///P///T///f///f///L//+3//+3///f///r///j/ +//P///r///j///z///z///r///j///n///H///n///L///j///X///H///P///b//+////P8 +/+n7/+z0+urq9tvc59jS2cjHyrXF1L7KzsS4vKjHz8erq6R9ZmxwlW6QdX6IeoRwaWhmbWRv +eVx3dmZyhV2AenV7l2iWqIGlrIWeroWvroatt4atsoissIqusI6psoyqsI2tq4Wopomlq4Ct +rY+rrIiuuJmtt5Cpr5KkqIaapoamroucqZChoIOLh2+Mn3KaqISjqY2iqo6kq4KnqIGmqIGi +pISdoICdm36QmHmYpoOgrISppoWer4esr4mnsYKmq4idsYyqqo6mp4Sor4imq4morIygpYWj +poOhq4SkqYukp4ajpXyeooKkoXubnH6gpXaipH+koX2dm3+ZmHuZlHiSiG6MiWeKhW2MlXCS +lXmVkneOh3GNiWmWlXKOiGqRgWuBe2V9c2N6el93eGB0cVh6cF9za1hmb1l2aVltblVubVhe +T1FDRD87QT06PzdJRz8+RDtDQkA5QjhCQT9EWDqOcUuoeleze16wf1u7emW0hWC/g2a1fmGy +el+rd1eiblineli5imOlfWC+kmHOmXDNm3bQpXTQmnrJmnbKl3a/lHLHknXFimu6iGa0e1+1 +fWCte12yfGGqdWCrc2WXdFSUZ1OAZ06FbEyEeU3r+a7///n///////////////////////// +//////////////////////z///////////7///n///////7///////////////////////// +//////////////////////////////////////7///////////z8//bz//Hz/+L7//X0++n0 +/+j1/+ns9urj7N/7/vb7/evz/er3/+/p68+2XGNNQkZIRkE1RT09RT81Pzs6RDw6OTI9Pzw6 +QDY5QDk7QDk2RDw7PTkzPDs2OjgxOjM7Ojs0PTE+PT80PzI6PTkyPTE9QD8xOTM7PTsyOjI1 +Nzo3OzU7Pzo7OzczNzo8PDU1ODc6OjozPDk5PTs0PjUwOTg3OTIzOzU3OzY0PTc6OjUzNzY9 +PTkwOjk/PDw1PTo9PDs2QTxKREZISE1ZU1hWTl1STFFJRktDQkVEPkc+Q0A8QkA5Pzw+Qz45 +QDlBPEE5Pjo/PT48PzpAPj5DVkugyaaz0MW0y7+ztb2BhpN2i5B5l5SKo6Z2lpp3iJp3fYZv +dIRkXGpUUmZac2iAoZx4lpaEoJlqW3dORU9IQk1ARENEQkdAPkA+P0NAPEBCPUE+Qj1APEBA +P0A/QEA+QUE8QTw+PD46PDw/QT4+PTxAOUA+Pz1LR0E3Qj05Pjo8PTk5QDs/ODw4Pjc6QDw5 +PTxAPD8wPjlEQD02QDw+OT42QDo+Pjo5RD09PDw7PT47Ozo7PEA9PT42Pj89ODo1OTc/Qjk3 +REE9Qjo2OkA6QTg4P0A7QT48QT08RkA9Pzs9PT42RTk8O0A6PTo8OTk7QD0+Oz06RztBREc9 +RT2GtXe91LvG08bF38Hh89ji7tzj6t/S5M3s+9r7/+n///b9/+v3/+r6/+n//+7///H4/u3y +/+T3/+n8/+r+/+///+j//+7//+3///f///L///b//+3///b9/+b//+3//+7///z//+3///z/ +//n///r///r///H///f///j///b///b///b///D///L///H///P8//L+/+3///D+//D7/+Pu ++OH4+ufh8NLc4tbK2sLAwrPJ3r7Y0b+42bvGwa+coZRiZFVukG6FaWdXWVNUaVRqbltucmN3 +eWV6fmpxcmKImXelroCiqICisYWxsJKss4mrs4ulq4utsY2nrYCspo2ksIKmp5Cmo36krI2n +roirsYirsY2ls46ir3yWpX6Uo3uWnn6Vkn16kWacoYKmrYqjpo+lrIOkqYuprYacpYmppYOZ +nYGgnXiSlX2ho4aeqoarqImhq4qqqYmkqYeqqoSfqYiop4Smp4mhpIGjpH+ep4Gmp4meqYKk +sYWeqISkqoScqX+io32fpoCdnXqZnXelpX2VmXmcnnqanXWZkXiKhmuJhW6IhW2Oi2qXknWX +hm2Kjm2Tj22PhW+Ke2WCdWJ/cV97eV16cFx1b112dV5rZ1htZlhpa1BwaFdub1RxYllIQUM7 +PkA4Pzg7PztCQzxHQ0E9Qz09Qzs/RDhxYkScclGodVetdVateVyte1q6gGG1flyzdlundFOg +alWLZU2idVSthF2jfly9kmXHk2zFlWnInXLOonLLnXjGk3LDkG/ElGzGj3G3g2OydGKqdl2v +e2Gxf1+qd1uocViRak6SbUyDZE2FaEuavV////D///////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////7///////////////////////r///////L///z4//Tr/eHo+932/uv0/On/ +/////////fHt/Onx/vLz++Hk8tnehKBMR0xESEA7RT8/Ozw7Qz8+SEE/RjhDQz05Qjs+Pj01 +QDdAQD41Qjc6Ozo2RDlAPD01PDM5Pzs3QDM6Qzk2OTc5Ozk7OTY6RDs8QTsyQDo4Pjc6Pzk6 +Pz46PDk3Nzk7Pzk1PjY6QTozNzQ2PjkyPTU9OTUyQTg5QDszQzY2QTosPjQ7Pjw2QTJCPzk3 +PDM7Pzs1PDc9QTs8QDo+Pjw9Ozo8QTg+Qjw3Qj1CPzs5Pzk6Qjg8Pj07QzhAQjw5RDc8Pjo0 +QTg7PzsyQTg9Qzp6qXfV3tHE2c67zsBmXXBKRkQ7QUJHREM8RkRLSUg9RUNAPz49QURAP0A+ +Qzw8ST5ccWBZYGRSVltFR0tFPjs8Pjw7QTs8PD47Pz08QD07PTc+QDs7QTpBRkQ6PDU9QkI+ +RDo3QkM7PjQ8PT4+QDk7PDw7PzY1Qjk+Qjg7RTtBQTs4RDg6Qjs8QDo8QTo4Pjc/QDw7Qzw6 +QDg5Pzk+Qzo7Qjs4PzlBPzw3PjtARTs9QztARUM6Rjw/RDw+Pz5BQz04Qj07RDc3QTk6Qjo+ +SkM3PTo8RD03Rzo9ST44Qjs9Qj44RTg9RDo5Qzo+QDw6QD4+Qjg8QUQ+Pzs9RkRLWz6hw6W3 +y7KYpqCTkZaOrJLL7rrd59bo8tjo/dn6/+74/+/u99/k9Nvp99v3/+j//+/9/+v6/+zt+ODq ++d/3/+P9/+38//D///H///H///b///P///n//+7///L///f///j///X///f///X///T///H/ +//f///f///P///X///n///P//+///+7//+3//+3///D//+r+//D2/efv++Py+uPy/ePj+tzi +6tnU3cXJ3cDH0rzK4cLK38a+xK/Gz72TgHmJhoR4gG53fGxxfF9ybVdqaFZnbV1veFxwf2pv +ZmB5mW+froShooiproSnroSzuJmps42usIqlsYyvt4qlrImorpCtp4qqs4unp4mjqn+gp4Kc +oYOan4SKoXiSmn2cmX2Umn2cm311hWmPnH+Vp3ymrommrIeuqoumq4qnp42fqIOioYGTmYCS +l4eSpX2cpX6cqoSosomjs4qrsoSpr4emp4ajsYelsYqvrIOmqYWprYamrYGlrYKeqoGdqoOm +oH2bpn6iooKbo4OgoX6To3yanHeZn3minnqVn3egj3aHjm6Oi2iHh2iWi2+Skm2Sh3SQiHOC +hmiNh2mHhWZ/fGd8d15+dV12b1p4cFx6eV9yaFdmaE5qalFqb1V4eV9qaVtZTkhBRz48QjY8 +SUI/RUBARj1CRT1DQ0E/RTdoYkKYcFKhdVGqdFajdlSpe1esglizdVyufFixdl2UaVVsUUaD +bEeoeVWuhFuehVnEkGvGknDGlW7Llm/JmnPMkHXMlnXCjXHFiWi5h2izfmKneGGse1uwfF2q +eFilcFqRbFGSbFSZb1GEY1GCd071/7r///r///////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//7///////////////////////////z///////z///j///f1//bu+tz9//b7//z6/+/y/+z0 +//L9//7x9+vr5+baVpxfRVJJSElBQT5FQT82RT89QkI+RT1EQUU5PDhAR0A0QDQ9SEQ5PDU6 +Pzs6PzQ8Pj88QDc2Oj4+QDk7PDw2Ozc1Pjo6OjsyOzc6Pzg3Ozc6Ozg6Ozg6Qjc4Qjk4ODc7 +PzcyQDU8OTc1OjY8PjoyOzY8PDcuPjk7OjwtOjVAPjgzSTk+SUE0R0RDSEc7SUM6Rjw6P0A2 +PTg6OTkzPjg8QT81PDk8Ojs1PTY9PDo1QTc7Pzg2PDU6PDU2QD04Pjs8Qj48QDw8Pjs6QDk7 +QDs3PTk3R0ZSUF1kS2xWQ1NGQ0g9Ozw4Pjo7QEA/Pjs6Pz07PjtBPz85Pz46PD47Pjc7PT42 +Qz1DOkRCRUQ/Q0I8PDs6PTw6Pz06Pjs7PTw6PT09Qz06Ozo9PTk4Ozk8PzsyPzg4PTU9Qj44 +QDg3Ozo4Qjk3QD03PTc4PjgxPTg8PT49QT47PDg2Pjc7OzcxQTc+OEA4QTg+PT44QTo/QDo3 +Pjc5PzcyPjo6Ozg3Pzs5QTs3Ozs3QDY3QTo6Oz82PDo8Pj06QTk4PD8/QTs7Pj04RDg/QD01 +PTk9QUM6RDk9QUIzQzxAQj42PT1CPj45QDtDP0I5Qj5BQj5ATURIWkphYWJcVV5UUVdegWGL +o4ex17DIy8PE77ni6drXx9O+y7rBr8C266zk793m597h/tj0/+z9/e7w793Z3dHY/9D4/+/+ +//D///j///P///P///b//+7///L///D///P//+////D///L///b+//H+/+r///H///L///P9 +/+/6/+r8/+v//+3//+b+/+z7/+n+//D0/+j3/uTy8+bm79nd5dba5tLT2sfJ08bG2MTM5MDa +7sfb4M/Ts8mowZi1mrKMiIGHl3yPj3yFiXyDfWt3ZGJoYmNac1RueWd5ZmZxgGh5m22XpoiZ +qHyiqYqlp4ulq4enpImnq4urqomlpouiqYGsp4KjqIqjqoOqqYmen4SanICVl4CPl3yOl3yO +kn6Pm3aTkYCNfXGEiXCLnnONoHyfo4GYnYGirIecnYmipICYpISipYaZkoGZlX2TpH+ZqIak +q4ilpIehrIKjq4WjpoSipoCgoIedo32hqoOjpoKjo4WhqIKnqoagpHuioX6epoCcpoSjp4Sk +oIWcnXygn3yapH6jnH+bm4KdmHeciXiOiHSRjGqShXKMhm2Mg2yCgWiKfmaDf2OMfGiEeGZ9 +fGN+c2N7cGZzc1t4d152alxvaFVnZk9nZ1JlbVNualloV1ZfS1JPP0RGQD49Qzw8QD0/Qjs4 +QDg+QztEWD9dbkCXdE+pflaxelmqc1mkcFekd1SyeFqxdleoY1uHWVOATU5wWkaPeE6qgFG3 +hGK6jWCqgF7DimfKk2zJmXPHlnTFknbDi2vBhWu5fmSwfGKygV+wfl6vfWOsdlyoc2CZZVWW +ZlOSaU+LaVaIzVPz/8j///////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////3////9//v+//z///z7//r9//78//Xv/+vp/977//f4//Dz+O7u9+Pp7eHk +i9SpVINlRl1LRkhKSUk+RjpBRUA2PjZIREA+Rj5FRUE8QD1DQ0Q9Ozs6RDk+Pzs3OTk9Pzk7 +RDg2O0A8Pzs2Pzs6PTcxOzs6OjkyPzU6OzkuOjpAOT02PDU/QTszQDVBPj41PzFAO0A6ODY/ +PD81QDE9Ozo5PTM5QDo8PTo7PzU7Rzs1Sj02RUc3REQ6SEU8Sks+UFE+Vk9AVE43PTwxOjc/ +PDo2OzY6Pjk5Pjo8QDw1QTVGPjgyPDlBPjswPTpAO0A0Pjw8Pzo8PDxAPTw3Pj03Ojk8OTs8 +PTo5P0BCREJFPEdBQkJBO0A7Ozw4Pjc2Pjo+PTc2Pzs4QTg7PT05PTg+PDw4Nzg9PDw5PzU9 +Q0Q8PTc8QDs9Pjg8Pj89PTo6Pjs4PjY5PDs6PT04Ojs4Ozs7PjlDRDo3PDc4PDo4RzY8Qzk3 +Pjc4ODo3PDc5Ozk8Pjc7Pzw7QTw8QTo7PTo3PTw2QT03Pzw9PT87Ozo/Pzw5Qzo6Qjs3PkA7 +Rjw2Oj00QTU3RDk4QTVARUA8Qz47QD07Rj1BQT01Pjs4QDg6Pjo9Ozo3Pjc9Pjo6Qz46Qzg3 +QT02Ojc6Q0A5PDc6QT05Qjo2O0E/Pzs6RTo3QTw9RjtHSU1CUEpJZk5UXFRhjF986nXT3s3h +vdrIwsW+vrO7p7ix3a/P+8Tq4+PW7tHU+cjz+ebr+d/o99/i/tTw/+T6/+n9//H//+////L/ +//T+//L+//H//+7//+////L//+z//+3//uz///P9/+j///P//+v+/vD+/+3///P//+j8/+/5 +/+f///X+/+n5/+f7/+b3/+f5/Ojy7uDk5dPU187G5sTV4NDP1snJ3bzL37rQ5MnbwtrHr8Ck +u5eoiqOLjnSIinaHjnWOkXSHhXWGcHF0WmJgbFFgZ1xwb11nlVqFoGyUpnuTpH+eoX+eoIOf +n4Sbn36cpIihoYKiooKhpoKlqIWmsYqrqoyprIqrqoqzqpCkoIOdnYWalH2cl4OVinaPf3iB +gWmBlm2HpXSVoX2io4CdoYehoYCbnoCanXqaonudlYGZlXmVinySonmapn+mqoqrp42rpoKd +qYGlqIGfoYGloYCbmoSZn4KVn3+inoKYnIGhoH+UoH2goX6bo3ujoH6dnn6enH2dnIGbmnmg +mn2ZmXudlnyalnebi3WUjWuOhGuHhGmMe2uEgWWJhWeIhGiFgmeHgmOHd2SBc2V9c2F1c1p2 +cV96aF9uY1pnZlRoZVBkZldqa0xoWldmSlNXRkhKREhGQUNCRT89RDtDPz47RTtDSkA8Wjpp +cEWad0iog1awcVuqcVemdVipc1iod1arcVqdXlZ/UVFwTUpmVkl2ZUaXcEqhfVSth1y+iWHC +i2WqhV3IlG7KlXLKjXbAhGu5fmy0e2GwdGWnfVyzel6vdF6mcWCcblycbViTZE+VZlGJgk2c +9lXz/73///v///v///////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////9//r9//bt/O3r/9vz/err+eHx+urOWKJxQGBORUFL +SElCQUJFQ0Q7REBBQEBAPkVBQzw9QTo7RTg9PjtCOjg2QTo6Oz80PjhCNz8xPzg9Pjo2QDU5 +Oj02QDQ8PDowPC87PjovOzc6PT00PDM6RTcwRTc9QDw3PTk9Ozg6QDk1OjpBPjkrOjU3OTY6 +PTc0PDgzRDQ2Vzk7T0c2REg9QUQ4SEE/SEg9TkdETVI6U1dDWmFDYWBMY2k5YU48UUgxPjU5 +OzozPDI7PDo3Pzc7Ozc8PTg2PzY6Pjc1PDg7Pjo7Pzg8PTg4PDo4PDc8ODg3Pzg+PDYzOjY8 +PD1DO0FCPUA0PDZBPUA0OzRBPD04OjtBPDozPDJBPT01Pzg5OjUxOzY8Pzs3Pjs5RT04OT05 +Pzk6Ojk5PjU4OzQ7ODk9PDYxOjk+PDoyOjk4ODQ3Pjk3Pjc5OTo3PDQ5Pzs1PzQ/PT42OzM7 +OTo2OjQ/OD04OzUzPTw1ODY6QTw8OjczPTw6ODw5Oz0+Ozs4PDs7Ojw4Ojg8PDozOTY+PDo3 +Pjs7Pjc2ODs6Pzw8PkA2PTk8PEA5QD89QEA6PDc6QT0yPTg7QDw4PjpAQTk0Pzw5PT04PTsy +Qzg8PEA3Pjg9Ozw0QTQ5QTo1QjY9Pj47YjtCZUNSfV1WxVSK2ILEsbqsp6mgjZuVYJl0m3WG +9HzV8snk8t7l7tTj5dvU78Xk4uPi5Nnc8dXd6tLa/NX3/+f+/+z9/+/8/+z///L8/+3///L7 +/+35/e70/uP8+u33/+X///P6/+r9/uz7/+r9/+r9/+r5/+b7/Ob6/+z0/+L3/+r+/u/7+Onx +/OT0++Xt8+Dm6tve39jU4c7O7cXc6dPY0tPI08DL1b7PzsTK0sTIpsCgrKSkmpqli5OLh3x+ +iWd/jHWFiG6Fg3J+e25+X21gVVVZcE9gjFh+lG6TmHubnHybmoCbmoCZnH+bmoGXmn2XlXmT +kHuYl32SjHqXin+MjXONkH+MlXKOknmMnXWUn3yOnn2dk4OKiXeMgnWBgm53kmWKlXOPmX6X +nIGUoX2Wnn2apYKcnn+ioX6bmICfkoGNlXmPmXaToHmbpoCZpH+gooOZnXudoYmcpX6jo4Kb +oX+dnoWeoHuio36aoH2ipoKfoIKcnICXmH6cnXqbmnyWm3eclH2ZmHiXk3yXj3WViXWSjG6O +inCPh26KgWqOf2uAfWaEfmaCgGiNfmaBemaLeWmAemWEeWJ7d2KCeGJ8a2N6ZVxoY1lhZU1o +ZU9mcFBxZlVsU1FhR1JTQ0VTQEhBP0BHQD8+Qj5CQDs+Rz5ASz9EY0BpdT2hdUesek6ue1Wu +e1e0fGC4flu2cmGnZFmOU1ZtSkpYREpiSUVtUEh0VkOCZkeZbkykek+xfFuzgV29imq/i2mq +fmLBgWm9emexdWCsdWOufmCxfGGucmCoblyfbFWXa1SRa1KZbFaRa1KO3lbn/5r///r///// +//////////////////////////////////////////////////////////////z///////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////3///H////3//Xz/+X6//P+//r3//FMSFVRSUlER0dFRD5F +REE7RzxCSEA/Rj8/QEQ3QT06RTs1RTtCQj8+RDo7RTw2RDY5QDw2RTQ6PT43Rzs5Pj45Pzc9 +Qz86Qjo6PDs5Pzw6Pzo6Pjg7Pj46RTs7QDg8RDw7QDs1PTU5QDszRDU9QDw2QDk+RTs1Y0ZE +XFc2TlI8Pkg/TUg+UVE7VlI7TFM5UU1CTFI9VllJWWRIYmlKZnBPaW5RaHRIbHBCaWI9WUk2 +SD86Pzs7Pjk3QDg6QDYzQDk3QTwvPjc8PTwyPzk0Pjg3QTJAPj43PDc+QDo1RDU8Pz42PjQ8 +Qj81PTc7P0A9Pjc6PTo3PTg4Pjg7PTs3PDg6PT04Qjg4Ojw7PTw7PDs3QDs4QDo7PD84PDo9 +PTk0QjU7PD42Pjo/QD02PDc+QDsuOzg+PDoxOzg/QDoyPzo9RD0yOjs+QTg3ODo4QTk2PzQ1 +PDs3PTg7VTk/UUE3QDk8QDs5QDg5PTg4Pjo8PTk4Pj09QDw2Qjw4PzU6PzwyPTc7PkM2PjY5 +PEE1Qjk9QEE1PTo7Qj47QDw8P0RBPT85RDs7QT07QDtAOkA7R0A/RkA8Qz09Q0I8QD48QT46 +Qj03QT04Rzs6Qzs8Qj5BZDxZXFtzpGi8zLeroalwW3FmX2hiUmNYXlqe1Ifb4NawsqLf8dbk ++Njv+uXd5Nybh5m65LHV39XX7s3i8drt+uL9/ez7/+j///D3/+/1/+r1/+v6/+/5/+r8/ezw +9+X9/+/8//D7/+j+//D9/+n4/Ozu+uTw/ef6/urh6Nrt/dzv/+bz++vq+d/u+eLq+ePv/Onq ++eDi59zZ59fa5dbZ583U3s3N2sXL0sLBxr+foZixq7B0gYp+jHeJkXyKjnWEiXKFjnOAi3aE +iXSAf253a2NbUlZdeVR6jGyJlHabm3ycpXygn4WWnnqWnoOSm3iYmn2SoXaanX2Vm3SQkXmT +l32WloWPnHeZnYeXmHqXloOUmH2TnXyOjH+Lj3N7fWp9gW13jGuMmXaNmnyYpIKbqYijqoWf +q4KdoIOgpHyeooSPk3uNkHSNlneUm4GbnHygqYWjqYalqomirIWopoacqoSdpX+cpIean4SW +pXucooKYo32aon6cmYKZoX+anoGcnn2WmXmVmHmTl3iaj3KYkXGWi3aOkG6WiHGLhWeKhmyH +gGSSiG6OhGCKg2iHgmWCf2uJeWKBeGN9eWJ5cmN2bV9uZ1hrXVVlbFJxb1t0cFRrbVdoYFRa +Sk9PSEhIRkZKQ0ZERENEQkQ7Qz5JPz43RT9HRT9MYEOYc0yhdVC3f1i0h1vAhl3DgWPAgVmv +b16PXFNtTFBXS0ddSUhMS0JRSEBhVkSMaEaccEybaVOkcFOueVq4g2G8imXGkG/CimideWKt +emCqdGKtgVavfmKvfV+jcF6WalWUalaWbVCfc1WdbFqWvGD//9////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////v///////3///n8//j4//D0/+zn/974//Hz/uzk7+JWWUdES0ZASTtAQURDSDc/ +TEA+Qj46QkU/RzpESUI7Rz88RDg2Pj09RDs9PD47RDk5Ozs5QDk1OTc4Qjc6Qjo7Pjw2RDVB +Pzw1PzU6QDw2QDk6QD00PDM7QD42RTY9Oz4zPTo4Pzc0Oz42PDo7PDs1Pzs7W1RJaG9IVGND +PEM6RkFCVVNEXWpMV2NCTlVAS05EUldGU1tFVV9NU2ZNWWRRXXJLZG9YbXtSbnhRZ3hSb3ZT +cnw+Z1k8TkszPjc2QD09Qz41QjY2Pjw0QDk8QDs2RDo8Pjo4Ozk2QTo2PzU5PTk8Pjk3Pzk8 +QTw1Pzc6PTozPzk9Pj4wPjQ6PTgvPzc+QjsxPDY+QTgwPzc8QTgwPzk5QTk3Pzo4QjQzPjo0 +Qjk5QTk6QTk4QDozQTg8RDYzPzw8PTU6Pzo5OzgzQTs0PTc8PTkzOjQ6Pj02OjI8PD43QDQ4 +QT47Qjw+P0g0PTs6RkE4PjczPzc6PDg1QTg7PjkxQDg5RDw3QTg8Qzo4RDg8Sjk5TTk+TD09 +RDw3Rzw8Rz87Rj48RT87SUI+SEA7VUQ6VEJBRUM8PD47QjdRRk47R0E+REI3P0A2Qzs8QkA5 +Pjk4QTszQTg5Pj4+SD9GSkZdaFlxY3JXTllTTk1ITklef1Ghvp6/vL+kvJ7F38Xd6NXk79fN +1dCNeJmDpnzJy8qOmorV8cvm8t32/+f0/Or7/+j6/+j7/+ru+N/z/+nz/+nx++be4tb0/uf0 +/uX4/un6/+z4/Oru/N3u8N7w/+T6/urx8+bW6snj9t3r/OXq997Z6djq+tzn9uHo8dvg5czY +6czj9NbT3MXY5tDQ4M3N0cqcpqV8kpaPp6R6foBogn99kXiKnXWSlH2NkXWNj3iBiWuChm17 +fmpqU11GW0d1hWuDi3GRlX2UlYGRmIGPk4GSlHeUk32RlHmKkHGKkHOFjG2MhWiEjG2JgHKA +hG2EinSBkW6Ok3uLmXSbn4OKk3WMjnuBf29/fm18gGaKknWNl32ZnX2VpX+WqHuZoIWdpIKb +pIWepIGTnHiRjHSNj3KQmnuUmn6dp4Ojq4Olp4Kbm4Ccn4KVoH2jmnyTp32ioH6don6in4iX +oXujoH6bmXWXmXyXoX+amXidmXOSlHaUlXSPiXGaj3SOkHGQjHCOi22KhGyDgmeJfGWEhGaI +fmd8f2N+eGSBeGF7eWOCdl55eGCAb2FtdV1vYVdZYE9sdFV6d2B7aFxeZU5iVE9NRUdDRkJF +RUA+Qz1APzs+RDlAQj8+RDtHRD88QTtIUD+BZkqkd1eidlexf1m4g2G7gWC8f2Cwd1mjbll5 +UURMUkWGaElzVEhVRj1LSkR1XkKVbkyrelGkdFGye1q1fGK/hWbAi2vCi2y9h2eadVuwc1es +fFizfl6kbl2VaVWUblSZb1WbcFaYblOfdlWQb1TQ5Jb///3///z///7///////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////3///////////////z/ +//r///////3////////////////x//bv/936///0++j1//BcYVxQX0paVVFJVktPU1FMVkxO +UkxNVk1NS0xJTUpITElEUElKTUhDTEhAUkNEVUk+TkA/TDxAS0I9SkJCRD07Sj9GR0JBRjxF +QUFDQjtCRT83Rj1BRkQ2Rz8+RD82QTk/REM6Pz48Qz83RTs8Pz07QT5PYm1RXWlKUF5DQUQ2 +RUVJVGNNYXBKX2lEVl4/SlFFTVZAUF1JU11HV11NWWVCX2VVYXRRaHZabX1Tb3liboJZbnpb +b4FVc4FUb3xFX1tBSUs4PD48PEA7QD45Pzo7Pzs5Ozg9RDs4Ozg6PD48Pzw7ODs9Qzk9Pz47 +PT89PT07PD02RTc7PT8zPz1APz83PDk7PjoyPzhAQT4xQDtDOzs6RD48PDw8QD1CQD07PTs7 +PzpAPT8+QT8+OT48Pj08QkE5QTs8PTw2Pzg8PTo+QD08OzQ+PTw9PTg7QkAzPTo7QT06PjU9 +QEA8QT06Q0BDRTk7Qj8+QTo8SkM9RD45Rz4/Pz9ARkJBSURDU0dFXUxBTUo/S0ZKWktQXlVS +Z1ZTYFFld2JXZmBMWVJPX058inmEjoNXWVg7PTpEPkJAPkBEREJAPkJDREA3QD49Pj48Pj83 +QDk/QDw/QDxBQkNCSUFJRk9PUk1RT1JERkVMT05SUVdqb2tdUmBobV+iuKywv6m3xbqQj4xc +VFx+k3elprKcuJvP4szm+Nnm79/J28Tg99bd6tnX4tTR38P5/+36/+fu8+Hf7M/m9eLz/ub7 +/+r4++3c3c7f9tfk6tTz/Obu+Nvy/ejl79rf7Nfi8t/j6t7F2Lfr9+Hk7dnt9ebl79zc8Nbm +7tXZ3NLW6dTc4tHAvMB6j5l8lph7h4lle31qe4lziHaOkn2IknmLjXp+iHOGhHN+iWuAfGxZ +SkZQa1J+hGiFjHaOknuSjn2TmXKXkoGOkX+PkW6NlHiOk3mNkXWIi3WMjnKHh2h+j3aGjXGM +lXOMlH6PnnyUl3+Tmn2OhXSCfmyAh21zfWt+f3KFk3WTlX6VnHmcoH6Vn4KjooWepYmeo4Ch +on+Wm32TjnGLjXaOk3ebnoCao3+ak36Nl3qSlISXk4CXm32Tmn2dmX6goXykp4abn4GcmIaV +l36fmH+UlHOXmYCYlnyUk3yUk3aRjnaNj3OOj3mXlXaTkniRjHOPiG6NhGuHhW2NhmyOe2eF +emmKgGOBf2aFe2V/dWODc194el97bF5fYVNlZlVycVx9aFxhX1NoWE9SREtMP0NAQT1BPT4/ +QT5BRz89QjtAQzxDP0A/SD1EQj5pWEGNZkuYcE+reFu5gV66gV/BgGG5fFy0eFufZFNyT0pM +Q0FZT0VgSUNSR0JLRD9VTUWEYEqhdlu3fVu4fl+3el2xfV+8gmW4fGK8gGeXcVeseFyyd16s +cl6ebVmMY1CNa06Xa1OddVWbbFqccluVbl3j9rj///n///////////////////////3///r/ +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////7////7//X2//Ds/+H4//b1/+39//Hj99zW6tnT087s5vDOzMLDwsbLv8O2 +wa+1vq2rrqqUo5mgq6OPjY+KiIV8gXt0dXdub3Fvc25sb2tsbmZiZV5WYlpRXVNUWFVUXE5V +VllLWExRWFFGW09JVlNLV0tRVE5LUExKVUxGVU1JVUpKUEpEVUxQVVVRXFZQV1VFVk1JVE9M +W1dQY15TX11IXlxETFI6U09NVF9EUldHVV1BW2NQWGJJYWlPYW5OaXZSbHxZcHtacXxYcH1Z +coFgc4FZdX9ZcYBXen1OaXQ5S1M6QD82RTo7Pjs3RDs9Pzs1QTo4QTc1Qjs2Pjs6QD80PjQ6 +Qj8zPTM4PzwzPDY0Pz08RDY2QD05PTg1Ozo5QDguOTw6PTwzQzY4Ozs0RDtARkEyQzc6Pzs6 +QTk5Qz40Pzg4QD41Pj87ST86R0M4Qj06QUA/TTxBRkE7ST84Rj45QD8/QD85RTw8RDg2Qz89 +SEM7ST9CTEQ9R0JKYExNVU9EVVFJUU9IVEtVXFZlc2Z3hHVaZ2RdYV1NaFlSXFVOXVNYaVhx +fXRUWFpjc2WQkodpd21jYW1HTFJDQkc3P0E4PDc3Qzs5RUA3QDo7PTs2Qjs7Rj01PTg+Rz82 +QT4+PkJKX0ZIUlQ7RzpGTEZATUtCREs9R0RFREo/RkREQ0RLXkl9f4RNUk5QUFNLTktATk1i +dl5oYXN0kHDP5cji79u6vcB/inPD1sXE1Le9yrLT6sD3/+fw/+Ty+eXt/Ofj797u/+H2/+nq +99/IzsTj99vk7Njh8djn9dnu9ODk7d/c6tPf9Nfe5drH37jm9dne7Nno9N3i5tjG4MDc7tjT +3czN5MbR6tO8trpyjZR0iI9lgodse4Jeen5vgH5+j3iKjHd9ineHjXF7im2Ch2x8eWxTTUVU +blZ3fmR/h26JkHSMkXeMkHCNk3eLj3qOkX6JjHGGjnyDjXiFiHGNkXqHknqQkX2JlXGZloOR +nH2TmoaYm32Um4CIhWZ9fWt0dGh6fmt6hmyEjHSPmXiPn3uRnICZnH6XmX6Zn36ao32ZnnmV +m4GQjXZ/iXKMkHeSmXqPm36OlHqblXeOm3qVlXaVmXqcmHSZo4iloYqTn4GcmHGYk32ZlXad +noKYmnaNlXeUkXeRlHiJkXGOjHCJjXKQiGqJjm2NhWqIh2iRjm+HhmaKg2uFhmiJfmZ9fWOI +emV9eV+DemN9eWR7dGF4dGJ5aVphYFNjbUxrbldsZFRaXk1WTEZBRT9DP0E/RDw8REE6QTtC +Qj86RTpCQkJDRkBCPj04SDt4X0yIYUiWZU6Wb0+ye16uely+eFuwfVuuc1mZZ1Gne1CveV+e +cFORWUhfR0VHRj9LRkBzW0KUYFChcFOzfWG4e1+1fWCvely3fV+weluUblWsd12ye2GrdVqO +YlJ7WUyLZU+NbVGecVeLZ1CNalWBbVfh+rr///v///z///z///////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////9//T/ +//////////z///j9//vy//Dt/+D3//Dt/+zu+un////////l79Pi8+Xy8+Pt+ePo8eDt++n+ +//3/+/Po9Ofp5ub+4tzU3NLK0MnPysnXvcLJ0bi0tbCur6q5squZo6aTh4J/enp3eHB1ZWlY +ZVdfXlhPWExaWldSUE5UVVNQVUpTU1BPVE5PUk9PTk5MTkxQT0xNTktNUE5LUUlMTktHTUhN +U0tMUkVPVEZRUkxKU0pQXEtJT0pJRUg9R0JPW04+SEJBRkFLUExKSEdDSUVNTUtKWE9gaVVY +WVNHT0lSVlRPUlJcYllNUU1LTFRZZVdhaF1aV1tmYFpVVlxZZVhcXFljbGZvb3J4jnt+koJY +XlpRUlA+QUI8QUI8PTk6Pj46PDE4Pj06QDo9PkA6QDU3Pzc7Pjw5OzxDTkE9REE+QT9XaU5R +S1JBSEFLTUhETElDSEVBR0JERUJISUhFR0JedFd4gHhyk29vgHJZY19NUU+MoXuEloqmwZXT +4Mbk8dTb7NTF67/n9dLj99Xg69jc8c/8/eXx997o7N7Z6c/x+eLx/OLz/OP2/+Xn9N3j9Nfp +69Lv++Dx/N7f39vY48bk+Nrq8tne6Nrc6tPi69XY6szg69LV4c3W5M7T3MjM28PT4snJ0cPM +0L+8ybOUmaKYsJCFiqJrfHuHinaEiHCFh299gG9/g3B+g3CBf291eWZiW1ZLV0trd12EjG2P +kXqVm36Wmn2YlnaQkHqMlHeQkXSLkXWNj3eJjnGKjW+Kj3aKiXGFim6JiHGFiW2MiXmPk3SV +mHuPl36XlICHj2qEgW90eGR9hnCMlm6PlYKWn3+Zm4WZoYOXnH2Tn3+Znn+anIKOj3qKj3mN +lHqWoYCapYWZqYecoIKeo3+cpIKXo3ycoISWon2bmoKWloCco4OSmn2eoYCVo3qaoIGVnHui +oYCZoHyhoYGem36am4KYmnyeoX2XnHiTnnqZlnyMh3CMiW2MjWaQi26SiG+LiG2IhWSEhGeM +gWuIhWd/emZ7d1yJdGd0bVh1b112el56aGVoZk9la1RtZ1hxfVt/bWRqX1ZLRUFBQjxDRT5C +QztARj1IR0BDRT9CQzg/SDpuZEqZc1SmcleoeVO4fVi2d2LBgmC2g2TCflytdF+zd1ahclet +fFu0i2S/hGi6i2vIl3XMmXjOo3jVoH3TonPJkHDJmGzNlXHIjm2/gWqyfmO5fGK2f1qveVi0 +eFq4eF+ncl+icFaIY0yJZ1CVbFKQmGn1/Oj///////j///3///////////////////////z/ +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////4/OD///////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////z///////////////////////// +//z////////6///r/eTu/+Lu/Orv/efs9uDr+OXq8+Xr9OL6/vX5//X9//79//r69erq+eTw +7ebk6OT39unt8eDn9Ovx+e7t7OHe4db26uTZ3djb29TN1cTEwMC7uLjDur2vsrKzurq70L7Q +tLyQiYSDfXtzfHB1dXRxeHR6anBZYVdXXVZZVVFTWlhWVFBVVVVSVlBRVE9UUFFLUU5QU09M +U0tMUkxMUUxOTlFMT0tPTUhRU09KUk5RUElJT0xVWlFTWVBZVlFKTEpUS01JUktZV1BGSkpT +VUxNW1dfYVtgal5TXFNOV1ZQU09NVVJQX1huc3FaXl9mdGlhXWJUWFZFV1JKUVBBTExAQ0Q4 +R0I7PT5AP0A6PTg9O0A4Pzc5Qj84OzY8QTw7QDU5Pj07PTo7Oz4+RDtFREQ9QT49SD9NWExc +alhIR0c6PzxCQUI5RD1BREQ7RUBCQ0Bnf1pfWWZFTEdJRUlCS0NKS0eEjXVXWlikvZDe6tDc +5NKpsLSUrIfL08bN18K7wrzg7sP3/uf0++Lf5dzp79Th8dzx/uL1/+fq/uXM2cff99Xe7NLt ++N3l9dvl7trc5M7f79Ti79XY5dfM4L/j8Nzi7NTd79XS28jW5sfb48zM3cXR4cjI2cbC07+Q +oKF4ioqTpqBvfH5pfXl/i3uEi2+FiG+CjXGDh3R6hnCAgmt4f2pXT1ZMVkR1e2WBh2iQknWQ +mHyYnH6Vln6XlHmPl3uRi3eUknuPkXeQj3WOl3qPlHeTlHyVl32WnIKToIOWn3yYoH6Vmn2S +nn2RknyEh258e2pxfmV+hnGJknCUlX6QmnaWl4SXmnmXoYGaoXycooiVm3uQj3yMj3KPlHqU +mX2ZoHWan4SVoIGaoYGXn4CeoX+ZooKZp4Wcn4KZm3qcoYGWnn2Xn3uTnX2XmoOPo36epoST +oHugnIGSnXuhoHmWoH+dnHuZlXuVmXyWknmOkGuPinKKi22IgW+OhWeFgmmAgmeCgGiHfmaC +e2SGd118fmd/cGFublx3dVxydltsY11bZEljZllkeV13cGNraVlmXFc/QTRBQDxCPDpBQUQ9 +QTs7RTpEPzc7RDhESkR7ZEybcVWndFSydFiwc1iue2G3gGGyd1+veWCseFiyclSMZlCmdla2 +g2HIjGK8j2nSm3XJm2/SpXjNn3bRnnbKlXXLmHHKkHPClHC9gWm0gGW1gGa6iGO6gGSzgGGw +eF2icVKabliJZUqQZU+ObU6pv4f9/vH///7///////////v///v///////////////////// +//////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////+n///////////////////// +//////////////////////////////////////////////////////n///////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//v///////////////f///j////7//ni9ePi79vx9Ovs9+L0/u31++r1/+7s+eTr9OTp9ubx +/e/v/+j4/vH9/+70/O7u+uj+/vzs+eje6+Hn7uHm6t/j8dv0+vTm8tvT38/L2MbMzsLEz8G4 +vrLC0b20tKunrqWnrqKcoJaSj4+Eh32EhX14fHRrc29pbmBmY1pTYlJYWVlPW1BTWFNNVktR +UVNDVU9SUVJMVkpPUlBKU09MU0tRVUtQVEpSVUxKVE1NUU1LVExSUlFUVU5TWlFSW1BUWE9U +UkxNV05RVVFGTUtHR0hBSEVHSEo+T0h1hG5SXFhQWVRJUExGREhDRz5BREM7RD4+P0I8QzY4 +Qjs6Qj41PTc1PTg1Qjc4PTk8QDs4PTo1QDszPjg4Pzs4QjU7QDc7QzhKSkQ+R0JFRUZDSkZA +QEQ3RThDRkUyQzxBRDs2RztJR0Jle1lfVVxESEhERz9AR0RJWkl3dHZRWVG7zKXh7tOwx7ty +eXqlvJOyv628x7W3yLbr99Dx/uTw+eDo793n997h8dvs/eDw+ubn9drG1sPq89ri89nk7tfe +9dLm9d3W5tLa69TZ79LP2c/M3Lfj89fX6sjf79fU4dHS4c3Y7M/J2MTT48zL28Kdr695jo+C +mZd8jYlseX9oen6GjnaIlXmMk3WCiXSChnJ9iGx+hWZ4e2tST0xLWkt2e2B8hm+FjmeOkXOL +lnWPknaKkXWMkneLmHiPlHmKkHSLj3SLkneIj2yLmHuNk3eMlX2PnnqSmX6MlXWOlXuNlXmI +jHyDgmt3fG16eWZ8hGyLkHqMmnWToIWSmX2dl4CRmnqUm32TnH6TmoKQlnuJjnmKlnaRmXiW +pn6YoIKdo4GUoIOaoX6ZoYOZpIaUnoCVonyXnoCapX+SoHueq3+ZnH+XoXyWmnyWmoKTk3uU +lneWmHyTm3SWm32NlnSemoOOnXGTlXyRjHKPjG2BgWSHf22Ch2eDhHCFgWmDhXWDeFt/fGV+ +fWN/e2hybWBzclt1cmV4eFlpYFFjbU1eakxja1BtcVpwbVxUTUhCRz83QzhARTc2QDU/PUBA +RDs/PUAySThIVkB6aEuibVSfd1apcVelc1SwfFm2fmKvb1queFmrdFSfZ1B3XEiiclaugFu3 +gmnDiGvCmG/MmGzMm3DNoHXHnXzLmHXFk2/JkW3AjGq9g2mufVe4fWGrf162e2ivhV6uemKd +b1KaalSGYUeDXU6CZFOxzZn9/uz///3///////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////7/+X///////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////9//3+//n///// +//////v4//rx/+b///n0//H4/+318uv+/fv//vr+//3z9eXt/u75/ebp+uvz/+r9//z3/+3x +/Ovx+Ory/u7s/+76/fT///r4//D6//Tu99/t8uX4/fLt6eT48/L//ff/9f7s7ejq7drj7ODj +4Nrc5N3u8OPf4NPT39Lf59vf29PNzMy+v77CvcG6tLS0tK60t66sp6alnJuinpiYk520l5eF +fYNycHBuZmhbWmFgXWJcWVhZWVdQWlRVVVdQV01XU1RRVlRVVlNMUlFWVFJSVkxSVFFVVlFP +VU9TVlFMU1BRU01RWE9VXFNUXFVZVVNWT1RHREhDRUU8Rz1AQz87PztCREE6Rj4+RUA5RT5E +QUU3PTw9Pzw1Pzo7QTw5PThAQj42PDs8Pz85Pjw7QD09Pz1DQz5ART9LWExGSEs+Q0A9QT9A +QUM/RD5DSEVDUUJESEU/RzxHSEc/SUNFREg+R0JDSUxyhmNUV1t9kWze6dDM3cxtbnRte12y +trOQon+uvarO0rrt/d3u+9/x+93u+d/j7+Hr+Nzl9dzq+N/Bzc/Y5sPi8d/d5tPi7tnk89Dq +9N3U59HZ59Pg7dTK0srY68Xb6Nje6cvl7dbT0b3W5cXR4c3BxbzI3MPU6MWWlaVvjJJ3iopn +en5oeoBoe4B7h3iHi3eDjXWDhXOAhHV8g3F9gnJ3dGhLTUdZXk14fmWLjW6NkXuSl3uMlnuN +j3qLkHSPjXmHjnGFim+Fi3CBiGWAhWiAiGmChHCAhmp/iG6AjGyGjnaHkm+SkHuMkXqIjHSC +hW16eGp7gXWAiWuIk32Pl3aWoYmcn4ecpIaZoISUoYeZoHmTmH+NkXmHkHSRk3qVmn+fpH+d +on+dpYeaooCfn4Ggo4KbnIaXnXuWmYCUnnmXoH6dpnueo4CeoYCWkX2fmnqVmH2Zm3mSk3ya +m3yTmnqUnoKXkn+VlXWQj3OPi22LiHCKhW2Hg2yEgmaIfm2GgWSMh22BfmOFgmd/h2h+eWR8 +cVh1a2F7dV57emRvYk5iYlBobE5kXldqa1VoY1ddW05KREVDQD9EQzw9Rj5APTs9QEBBOjw8 +Rj0/REFhck2QdFaccVWrd1yqfmCsc1Wdc02tc1yvdlGufVudc1Z8VUhiUz6SdlGpf1e4hWW+ +i2jIjW3ElHDKmG/OlXO8lnHDlnLEj27CjWzKkWrBgWWzemCqeV6veV6vgWC1eF2lc1afcFGQ +aE2KYVF/Y02KZ1fK4qH+//H///3///////////////z///////////////////z///////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////8/+T///////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////8 +//v0//Lz/+n8//n5//Dx/+v////z/+fx/uzs9eXr7+Pp7eTr/Ojw+/D++/Hu9fP+//z5//X/ +//P1+PD1+vP8//v79/P4/+z6/vL///n5+fD5/vb9//79//f///v9/fL9//r///X///3///L2 +9+zm8uDo7t7s7uHk8eTw+evu9vP///7x6eP27PDk4NvP18fP08ra29bNysXHzsK/v7iytamx +qafOu7u9urm4raaWj5iKgYOBfH52eHFoZ2liYVxiYVteW1dcW1lYWFNXWlJYWFRXWFBVWFRU +WVFSVlFRVU5WT01WUlFUXk9ZW09LVE9ZVlFQVE1UVFNPW01RVE9FSEhNQ0M6STxKSUM7QjpB +Pz43QT1BQz83Pz1BPz1APz04QTc6QTg5RDlCPkA/QDpCQT1APjtGR0JFSkVOVkNRWU1ESEdA +QENCQUBCP0E+PzxBQUE9RTpEQ0I/RTpERURGSEJOXFJOU0e8zaLY5M6UmaRXXViwvpRzcICb +tIm6vqrd58n3/eHu+eDn9N3q9NnJ2srl9tbc6NPh7dvBxLvt99re8dnW5NHe7dfe7NTs99rm +79jK28Xf69DT2tHY5tDS4NLb6M3d7dXLz8TW4s3U48vD1brL4cTP2MuFj5V1h45vhYNte39m +dnxqeIJwg3uCiXR+hnOAf298gWyCgml9hm1ybF9JTEZda1F5fm2EiW+Mj3yOjnONjnKOj3GL +jHCMhm+MjG+LiHKKjHKFhW2ChWaChW6Afml+f3B8h2aDim2Jj3aRkn6UlHuIj3iEj3B/g2x3 +eml7fmmChGyKkneQmXuXl36VmnyYmn6XnniZpoSdoXmVoICJkG+Lkm6LmHWRl3qVmXycpYWb +o4WfooafpnycoH2bnn+cnH2Vlnqam4GYnXucnYCaoX+bon6Xmnmbmn6WlXibm4CSnH2Qk3aU +mHSZmHiSknaQjmuIi2iOi2aLiWeEiGmKgGKBemF/f2WLgW6FgWaFe2qCfGSBfGp3cld9cWJ9 +fV6EfmZ5cmFoZE9dYU1uZlpla1VrY1RkcVRaVktFPEk+Pjo+PTs6Qzg8Pjc+PTxBRTtAPz89 +PTl9ZUyWclOmeVard1eydVigblCjcVWod1Suc1ylcU6eY1N7VT5qUEqDaEipel+zfly5gGXB +kGjMjm7LkmrJk3POk3LKlXXJkXLEj2u9i2q9hGazeGCweFeufV2zeVuodlqxdFuSZFCRa1OQ +Z02IZFB8a1Pe7rj9//f///////v///3///////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////t+9n///////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////35/+79//j///75 +//zv/+T3//Hy/+36/vL5/+3s9Ob29u30/PT///7///f5+fD+//77//r///75//f5/+76//z/ +///////5//D3//z////1/fL6//r4//v1/fTq+d7r/+n1/+f1//H1/+3+//z9//b7//r////2 ++e30+uv8/fL39urp8uP5/vP1+fD2//b///Xw+Ojw9e3x8enx+Ovl6+Ld4dTX2dTd2Nff9dTZ +2cy+x73NxcDExr7ey9DBuLy5rq+jn6Cfm5yTkpiUh42FgIF8dXdxbW1raWFoY2BaY1paX1Za +W1ZTXFhUW1FTX1VNXFRRVVNRWVFTV05PWVJQU0xWVlJQXU5QVlJVV0pLW01OWEpPWlJPVU1R +SlVLREg+Rz8/ST08RT05RT86RDw5Pzw6Pzk7Qjw2Sjs/RUA7Qz5FSEM/SkE/RT08RkI+Qj82 +QT06Qjs6Rj4+SD07SDw+Qzs8QkA9Qz5CRkE5SUVvg1nC17G5yLdOX16OjnWgqKBUY1CntqTI +2bLh9dXq+9/j+Nvr99zL1M3L3L3g7NPa6s/P2NHW6sH0997c7Nfb6M7T4tDh8NXi9tnc69LP +4cTe8c7U6NTJ4cHF2MPZ5tDO4MbD0sjG4sLH4MS1zbXF28esxLt9jJhwiItrhZBifYBhe31g +d3h4inp/iG6Ch3N6hm9+h3Z2gmZ9gGpgZFdIT0dreFp0gm2GiXGIjnOLkXaNlXeJkHqIjXaG +j3GEjG2AjW2EkG6Cimp/iG9+hm1/hm17iWuFjHiIkXGSlnaNl3WQl3+AiG16hG95gmB1fmh5 +fmiGjnKQlYCSnX6Tn3+Xn32Vn4GSoICVnX6TmX6Om3yGi26Dj3GKmHeTnnibpn6VpH+cp4id +r4Khq4eVoYCcoIKTpH6VoIaPn3eWnnyRloGbn4qWn3qWnnqSmnyTn32VmnuSm3qZln+Rk3OM +lXiPk3OWjXCOjW6LjWmLi26IhGiCgGWChmWFiW6CfWKGh2d+fl5/fGx3dmB6dmJ6eFyCfmd8 +e1xwbFdeY05jaFFma1RqaVdxb1ZkZFVNQkY7Rzk7QDw5PzdFRDw7RTI1RT4/STtCTUVFTTuT +bVimdVSjdla1kHSmb1GndlSndFKpdVqmdliudE+CWEtzWUZmR0NzZEeZeVuogFu6fGK7kWa+ +jmi/kGfNk27InXHIlnTFlGvGinC2hmG0e2Gne1+wdlmre1iyelure1ibb1iKa0yTbE6VbVWD +YkuBjGb5/+f///7///////////////////////////////////////////////////////// +//////////////////////////////////////////v///////////////////////////// +///////////////////////////////9/+j///////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////v///z////////////////4//D7 +//X+//38//r3//Hy/Obq++n7+/Hz/vv7/+r3/ezy+eXt/eT3/e/w/+zs+OLx/PP6//Lt/uj9 +//r9//r///v5//b9/+7+//f///n5/PD07+36/u////7///f///Xz/+r7//P+//b///7///n/ +//7///////v///f6+fL7/fT4//f7//T6//P//ev6//H3+O71++7y+vL///7////z7ufk6+Ds +7Of47ufi5Nnd6Nzk6Nza3tTV1s7Kx8PRycXCwL/Ct7rOscKzp6azo6ynkpmOh4mPhY96cHV8 +bG9rZ2JkZV5fYVhbYFRdXFVUW1JXXFNVWVRVVVNVVlRWVlRXWVNQVU5XVFBXU05TVVFSU0pQ +VlBWV1BWXlZVWE5MUE9NRkZARkBGQT8+QT8/RD89RjtDSUU7QT4+RD88SD5EREQ9RztCQz9E +QTw+Rj87Rzw+QT08RDs8RDo8RkM/REE/RUKWpX+80bKCj5BdXVW0v6RtbX5jgFqstqjH2MHf +79jl7NfZ68zv+du2vrLP4cnf79Dj7Nq7xbjo9dbj9tvc6Nbc6tHM2czd8dPS4tLV48nP5MTZ +6crY3dDO3Me/zbrV5dHK3sPAzMSqzJ7D08C4yLLD08WZtKl6jpdvhI9rgYRleIFhdHlrdn1z +hnV/hW96hWV/gG94f2p7gHB4fmZhWVxNXkZze2R+gGaIh2+Gh3GOkHeLi3OJkHWLjXWHjHGF +iG2BiXCBh26AhW+Ei3GFjW2CimyMknuNmnmOlXqQnnyTlX2OkHuGhnV6fmV8fGl5gGZ6gmyF +kXSOk3uTmHaVnoKQnHmTnnyZo3ybnYOUnICOlXKGjHSJj3eOlXeOnXuZp4SkpoKZoX+Ymn+Y +nX2Vn3yRnHqZnnyUon6cnIOaoX6bnn2Tn3icoH6Rm3uZmXiRmXmYnXyOknSSlnGTl3mTkm+T +k3CQim6Kk3ONjW2JgmiKhWeAhGyJhWGGhmaKiWyLfXCFhWeCdmODc2KCfFyBdWJzcFh+bGJk +YUxnYVJpbFFwal1ndlZ5cV9hXEVJQD8/RDs7QDxBQT87PzhARDlEQDxCTEVKSj1Qak6jelao +elKneFije1uqdFSpb1itdlSndFaueFuTalBzUkZlRz9eTz5qXU6ZbUyVclexfl2viWPIk2TE +kW/JkGvLmXDKmHHMjXDCiWTBhGe5fWWvgV65fV2zfmG1fmGtc1ugdFSRZk6Va1CValKAX0iQ +s3D7/ej///v///r///3///////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////v/9n///////z///////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////7//34/+37//32/+z9 +//n9//v7//X//+35/vft++no7uDl7+H1+uv7/vv1++fy++n8/fn3/erz/fD4//L48OXs9+f4 +/vDz++b1/vP//PX///f9+ev8//n///T///r6/+/9//v///////f9/vL///H+//n///n1/+z6 +//n+//X///7///////////b5+PPz/O79+ezy/ez7/fH//vr////2/+z0+en9//j///////Xy +9ub4/vX5/fH6//X08ubz+fD/+/jr+OXe79rn7tvk7dbc4dXj59XT1c/SzsrLxcfDw8jNwsOu +paicnJablZOLhoaKgH90bWtvZ2lfYltfXlxYXVZYX1VXW1ZWWlNYW1BTWVZVWFFVXFFSVlJS +V1NTW1BYWVRSV01RUFFOU05TVU5LW0xWXlBTVUtVUE5ISEZISUNBTENIS0Y+Sj9ERz8+RD9A +Q0A6QTw8RTs8QTo4REA6QkM9P0FCTkakt5KKoZBZW1uLpneXqKBOTVVsil280bW80Lva8Mja +59nW68zj6N/J2LbW5Mzi79bP3tPC2L/b8NXT59DR4s7T5szO18/E5sLO1MzH3bm+zMHB27LY +58vM2ciquqjS1sfF2MGyuLSOrou4z7e3w7K3xrh8iZtph4dvg4pqfoZmfH1geHpmdX5xgG9/ +hW9+gGh7g3B7gGd8g3F6fmxYU1dSYEpvfGCBiG6FkXGNjHSQkHeRkXqMknKOlH2Lj2+JinKE +iXKJi26Ki26IjnKJkHSHjXWLlnaLmHuSmH2ToH+Tm3yIj3h9hWh1eWh6eGd0gGp+hGyBj3iP +knWPnoGUmH2SnYObpX2YoYKWon2boYaRkXaLinOHkHSOkXOVoH+Wo32YnnmOmX2Vm4GRmnaT +nXyWm3Wbon+XpYSbpYOUnn2XoIOUnnSWnHyUoHiOoHyXlICVk3mQinSOlXWXk32OknqUinGR +jGuTjnSIiWiHhmmCg2KHhWeMiGeFgm6Af2R+gGmCfmF4dGiAfmF7eWd0b19laVdrbFVfXlRm +a05zblxyb15xaFtjY1BVS0U9Rj5DPUE7RDk9PzY7PzlDRkA2QC1MV0lQVkVobFCgdlane1qr +e1qnb1ureVSyfmGxflu6dV+oZlWBZk9QSj5iTUpxSEdtWz6FZ0udblChdlqxg2PBjGXGiWfI +inDVl3W/lnfLknC9iWezgmOvfl2sd2KsgGC1gmGod1mjcVmicVSPa1OOaVGTZ1OCZkytypn+ +/er///v///////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////7/+X///////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////2//Xp/9z0/+vw +/uv6//Lk7t7r7Ofh9uP0++3///z5+e/6/+z6/+31/e/2//L7//H3/+fu++j+//z///n9+e7+ ++/j5/+/4//b+//j///7///P5/fD///Tz9+n1/PH3//X///7///n///72/un5/vT1/+79//f6 +//H6/e/9//f9//n///7///v//////+v9//X+//3///////v///7///3///r1/+79//j///7/ +//j///X6//D3/u75//D///P5//L//f33/e729+b1//Hz+ejy/OX3/+3v8ubl69nV28/Z29Db +3dfX4NTT1crEycHJw73HzsGzq62ptKjEwrCKiY1+gHVwenBrb2JgZGFXYFNVXldaWFBXWVdX +V1FTXlVbXExTVldVUkpQVk9TVk1VW1FTVU5RWE5SVU1SVU5UWVNQV01VXExIU0dPSUhER0FI +REU/Rz88Qj9CR0E/ST4+RkJDUUWBlnpaXWBCSUlZbVZcZWNBRUdvh16pvauPqo7L4L7I1sPZ +687b4s/L2sDE3cLS5svN5MrW4s7N5MrQ4cq6zr3R5MfP3szH1r/F1827w7OvtbOywqHQ2snA +x7aru6nP2MfK4MOxqrNseXysxqWetqizybWBj6BniYxqh4hmeYJjeH1mdHtjdnhvf3mEjneC +hnB7iGyAg296f2t5fWpMTkxfZ1NyfWF+gnGEi22HiXKGjHOOk3WHi3CPj3KIjW6GinGFiWyM +inKEimeGiG6HjHCIkHmJkXOMkXSFl3OSnXyRm3mRkHl4e2h1e2hwdmB9fml/iWeHi3aLl3GT +nHqPlXKXnIaXnXWTn36SnXqWnX+LjnWBiW6Gk3GLkXSSnX2Xm3KRk3eNknOQlHuOk3GQnHiT +l3yWoHeeo4CaoICalX6PnHyamH6SmXmUln2UnX2amYOKk3WaknWQknGOjHCMkHKPi2yNjGqM +iWqJh2yDg2qGhWuEh2iDfmiBgWCCfGWCfWJ8fWF8eF14dlx9dlpwbV1waVlaYU9iZFZvdVZx +cllpbk9ybVpdWkBDRkU+RDc+Qj4/QTc6Pjs+Qz1DQkE/TT1AQjlFRkB4a0qgdViqe1SvgFqz +eli6fV63dVe8gmS0dVqec1d9W0tHQj5QTztrTUVyVz1zX0yOZkuabU+xelysimDHimy+hmrI +jW7AimnBimK3gGC5fF6yfF6oc1W1gF2reVarcmCbdlWjcFaOakuYYlKKY0mFZ06+46P9//b/ +//7///////////////////////////////////////////////////////////////////// +//////////////////////z///////////////////////////////////////////////// +///////////////////8/+r///////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////z///z///v////////////6//r1/+v9//v1/e/4 +//CQAQAAAQAAAJABAAABAAAA +--------------A9E4A76F8F8B49A8F9408311-- + +--------------D866708591E89309695535AC-- + + + +--------------746A59DD382995F41B0947E-- + +From - Thu Feb 8 18:49:08 1996 +Return-Path: izzy@scr.atm.com +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id RAA04054 for ; Thu, 8 Feb 1996 17:35:41 -0800 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id RAA06978 for ; Thu, 8 Feb 1996 17:35:51 -0800 +Received: from scr.atm.com (root@[206.100.186.2]) by ns.netscape.com (8.6.10/8.6.9) with ESMTP id RAA08762 for ; Thu, 8 Feb 1996 17:35:03 -0800 +Received: from mailman.scr.atm.com (mailman.scr.atm.com [206.100.186.54]) by scr.atm.com (8.6.12/8.6.9) with ESMTP id RAA23678; Thu, 8 Feb 1996 17:35:10 -0800 +X-UIDL: 823829838.001 +From: izzy@scr.atm.com (Dr. Mark K. Joseph) +To: jwz@netscape.com +Date: Thu, 8 Feb 1996 17:33:10 -0800 +MIME-Version: 1.0 +Message-ID: <19960209013311.izzy@scr.atm.com> +Subject: Example of CID linking in a multipart/related MIME message +X-Mailer: Emissary V1.20, by Attachmate Corp. +Content-Type: multipart/related; + boundary="=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7"; + type="text/html"; + start-info="X-twg-cidlinking-V1.2" +Content-Transfer-Encoding: 7bit +Status: U +X-Mozilla-Status: 0001 +Content-Length: 46628 + + +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7 +Content-Type: text/html; charset="ISO-8859-1" +Content-Transfer-Encoding: quoted-printable + + + +Example of CID linking in a multipart/related MIME message + + +

+ +B= +uy, Try, Update to = +Emissary 1.1,
+Or Update to SSL Secu= +rity Instantly, Free!
+3D"=3D"Emissary
+3D"WOLLONGONG
+
+
+

+ +


+

+ +Wollongong has been a leader in software-based networking solutions fo= +r 15 years. Now, The Attachmate Cor= +poration has acquired Wollongong, and with the new EMISSARY line of products, Attachma= +te is "The Intranet Company." The Wollongong Group, Inc., now the Attachmate Internet Products Grou= +p, is headquartered in Palo Alto, California, with additional operati= +ons in McLean, Virginia, Santa Cruz, California, and Bracknell, U.K.

+ +


+

+ +All comments or questions regarding this Web site should be addressed = +to johnn@twg.com.
+Images and contents of this site are Copyright 1996 by The= + Wollongong Group, Inc., The Attachmate Corporation, or the respective do= +cument owners. and may not be copied or reused without permission except = +for purposes of reviewing or promoting the Wollongong Web Site or product= + line.

+This Site is Enhanced for best viewing with Emissary!



+ +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7 +Content-Type: image/gif +Content-Transfer-Encoding: base64 +Content-ID: <2.19960209013310.izzy@scr.atm.com> +Content-Disposition: inline; filename="attach3.gif" + +R0lGODlh+gBLAPf0AP////f/7+fe1r3v3ozOzrXGvb2thJylnJSclIyMjGPGxgD//0q1vUqUlDGl +tRiUpQiElAAA/2NrpTlrrRhjlAhzhABzhP//Zvn5Y/PzYvPzYe/vX+rqXurqXejoXd7eWdraV9bW +VtTUVdLSVM/PU87OU83NUsXFT8TETsLCTeecSri4Sre3Sa6uRa2tRaenQ6GhQa2ESp2dP5mZPpiY +PJKSO46OOYqKN4WFNYODNJRjIXNzc2ZmZmNjY0pKSiFjewBjczlSYwBKY4CAM3p6MXl5MHR0Lm5u +LGZmKHNaMV9fJl1dJVdXIlFRIVJCKUhIHUJCGjk5OSkpKTw8GDMzFTExFDAwEy8vEyQkDhAQCA0N +BQoKBAcHAwAAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz/wBmAABmMwBmZgBm +mQBmzABm/wCZAACZMwCZZgCZmQCZzACZ/wDMAADMMwDMZgDMmQDMzADM/wD/AAD/MwD/ZgD/mQD/ +zAD//zMAADMAMzMAZjMAmTMAzDMA/zMzADMzMzMzZjMzmTMzzDMz/zNmADNmMzNmZjNmmTNmzDNm +/zOZADOZMzOZZjOZmTOZzDOZ/zPMADPMMzPMZjPMmTPMzDPM/zP/ADP/MzP/ZjP/mTP/zDP//2YA +AGYAM2YAZmYAmWYAzGYA/2YzAGYzM2YzZmYzmWYzzGYz/2ZmAGZmM2ZmZmZmmWZmzGZm/2aZAGaZ +M2aZZmaZmWaZzGaZ/2bMAGbMM2bMZmbMmWbMzGbM/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kA +ZpkAmZkAzJkA/5kzAJkzM5kzZpkzmZkzzJkz/5lmAJlmM5lmZplmmZlmzJlm/5mZAJmZM5mZZpmZ +mZmZzJmZ/5nMAJnMM5nMZpnMmZnMzJnM/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwA +zMwA/8wzAMwzM8wzZswzmcwzzMwz/8xmAMxmM8xmZsxmmcxmzMxm/yH5BAEAAPQALAAAAAD6AEsA +QAj/ALsIHEiwoMALCBMqXMiwocOHECNKnEixosWLGDNq3IiwIIAuAEIa7ELRQJcCPFKqXMmypcuW +CxawjElTpsqaMG2ujDlTJw+eO33+tAk0JdCiL4vizNnTqFCnQaEyffkyixMVFgl+BClwK8GSWVJG +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 +dzR7Z/CIgF4WEAA7 + +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7 +Content-Type: image/gif +Content-Transfer-Encoding: base64 +Content-ID: <3.19960209013310.izzy@scr.atm.com> +Content-Disposition: inline; filename="liluse.gif" + +R0lGODdhCwFLAOcAAP78/P379vf4+Pv56vjq6+vv7eHr4vrm3PztzvHc1fzZx9bPzcvEyf/luP/i +rf7XvP/dtP/VtP/erf/ar//aq//Vrv/XqvjYqv/ap//cpf/Wp//Sp//Wo//So/rSo/LOsP/MpfzK +pv/OoszJsdXVrP/Zn//Vnf/Sn//Sl//Onv7MnPbJmf7GnP7Nlv/Ll//Lk/3Flf/HkvbFk+7Elv7F +jf7GifbDjezDjK7JrcS6qc+3qvm9lOu8k/29i/W9jP28hfW9hPu2iPS2hO29jOa8jOm3iu68he21 +hOW1hOethM+xkdy1id2tg9ash8ifm7y5qLOxqJSupayfobqqmbKslrimipanj7SXi6mah46WiXWh +jf/Df/u3e+m1fPmteOqreuWtfeWtduSmdfy1b/mpaeWnbd6tfduqetOue92lddakddykbdWjbtml +Zsyja+mcaNeddMiaddudbNWda9mZZ9WcZNSXYsqaacyVYsWUY9iJYciNY/WjVuqRUtSVWMmUWdWM +VciLV9mGScaGSrekbp+ifa2UdrqXZbeNZKaIaJSKcbuUWa6UVrqHVquIVruFS6yESZeGWv//ANyG +PLeGOXKMbFyKagD/AMt6R454ard6R6tzT6h6SJh5V4lyVJZoV5l3SpZqSIdpR89wMs9oF9xjDMlj +ALh4Oal3OahsOLFyLqZpKpd2N5hrOIZnOplmK4llLKtYLoxVLqdpGqtnB5NkEKtUBJlYAI5TCodJ +AKQmAIs2AW95alNyaHlpSW9sUFFqTHJXRlBWSzxkSjo7RHhmOmtkOnRjLFdiOHhYOmhXN3pYK29P +L2hKKFhWOU5MMVdIKnVhFXFSEnpHAGlIAFFHCChWJi5NA2U1JlA5Knk4AGg3AG4rAVc2AEk5AFUt +BUcrAHURAGcAAE0aAFYAAE0AAEUAAC0tJzMwAgwvATEaADwAADMAACwAACUAAAYaABoAAAAAAAAA +AAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz/wBmAABmMywAAAAACwFLAEAI/wDjCRxI +sKDBgwgTKlzIsKHDhxAjSnT4KVm1Y9J8FZsGa5koSIfQLEFC5IaNGS1CeMjAoQIGCRgqbGiBooWL +FylSuGhxwoWKDSJEtFChYgcMGjF2xPiBtEYLGD5BmEhhokXOFDZPdEghwsMJDRs0JJREtqxZSRPT +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 + +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7 +Content-Type: image/gif +Content-Transfer-Encoding: base64 +Content-ID: <5.19960209013310.izzy@scr.atm.com> +Content-Disposition: inline; filename="wollogo2.gif" + +R0lGODlhFQLSAPfXAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz/wBmAABmMwBm +ZgBmmQBmzABm/wCZAACZMwCZZgCZmQCZzACZ/wDMAADMMwDMZgDMmQDMzADM/wD/AAD/MwD/ZgD/ +mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMzADMzMzMzZjMzmTMzzDMz/zNmADNmMzNmZjNmmTNm +zDNm/zOZADOZMzOZZjOZmTOZzDOZ/zPMADPMMzPMZjPMmTPMzDPM/zP/ADP/MzP/ZjP/mTP/zDP/ +/2YAAGYAM2YAZmYAmWYAzGYA/2YzAGYzM2YzZmYzmWYzzGYz/2ZmAGZmM2ZmZmZmmWZmzGZm/2aZ +AGaZM2aZZmaZmWaZzGaZ/2bMAGbMM2bMZmbMmWbMzGbM/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkA +M5kAZpkAmZkAzJkA/5kzAJkzM5kzZpkzmZkzzJkz/5lmAJlmM5lmZplmmZlmzJlm/5mZAJmZM5mZ +ZpmZmZmZzJmZ/5nMAJnMM5nMZpnMmZnMzJnM/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswA +mcwAzMwA/8wzAMwzM8wzZswzmcwzzMwz/8xmAMxmM8xmZsxmmcxmzMxm/8yZAMyZM8yZZsyZmcyZ +zMyZ/8zMAMzMM8zMZszMmczMzMzM/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A +//8zAP8zM/8zZv8zmf8zzP8z//9mAP9mM/9mZv9mmf9mzP9m//+ZAP+ZM/+ZZv+Zmf+ZzP+Z///M +AP/MM//MZv/Mmf/MzP/M////AP//M///Zv//mf//zP///wAAAA0NDRoaGigoKDU1NUNDQ1BQUF1d +XWtra3h4eIaGhpOTk6Ghoa6urru7u8nJydbW1uTk5PHx8f///4Q/FlVHIMlAiuI2BoQ/FlVHIDRA +itcfhSx7JD+0PwA+dih7JPYAABUAAIcAAAZ7OAAAKEd7XP8ADvY8RyH5BAEAANcALAAAAAAVAtIA +AAj/AK8JHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXMmypcuX +MGPKnEmzps2bOHPq3Mmzp8+fQIMKHUq0qNGjSJMqXcq0qdOnUKNKnUq1qtWrWLNq3cq1q9eHrQQR +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 + +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7 +Content-Type: image/gif +Content-Transfer-Encoding: base64 +Content-ID: <0.19960209013310.izzy@scr.atm.com> +Content-Disposition: inline; filename="BULLDOG.GIF" +Content-Description: The Sender's Signature + +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 +Ow== + +--=_09tW13g.bO1996u.N01d000A.r02Y.33:0018d7-- + +From - +Return-Path: +Received: from thumper.bellcore.com by greenbush.bellcore.com (4.1/4.7) + id for nsb; Fri, 25 Sep 92 21:30:21 EDT +Received: from att.att.com (att-out.att.com) by thumper.bellcore.com (4.1/4.7) + id for nsb@greenbush; Fri, 25 Sep 92 21:30:19 EDT +From: develop!nextmime@ebony@sblab.att.com +Received: from ebony by develop (5.59/25-eef) + id AA28800; Fri, 25 Sep 92 14:08:15 PDT +Received: by ebony (NeXT-1.0 (From Sendmail 5.52)/NeXT-2.0) + id AA00975; Fri, 25 Sep 92 14:13:02 PDT +Date: Fri, 25 Sep 92 14:13:02 PDT +Original-From: develop!nextmime@ebony (NeXT MIME Prototype) +Message-Id: <9209252113.AA00975@ ebony > +Received: by NeXT Mailer (1.63) +To: @develop:sblab!att!thumper.bellcore.com!nsb +Subject: More richtext questions/comments +Cc: robb@develop +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary=tmrob +Content-Length: 2579 + + +--tmrob +content-type: text/richtext + + + + + + + + Nathaniel, + + + +I think the biggest problem with point size in the mail I sent you earlier was my own + +misinterpretation of the rtf "fs" command. It was not documented in my (sparse) + +RTF documentation but I guessed from context that it was point size. I've done more + +experimenting since then and concluded that it is consistently twice point size. So + +instead of a mixture of 12 to 24 point my previous message to you was 24 to 48 point. + +I didn't see it here because I either read it with metamail and no font software, or looped + +it back and read it on the NeXT where everything reversed itself. + + + +It should be fixed here: + + This is 12 point. + + + + This is 14 point. + + + + This is 16 point. + + + + + + This is back to 12 point. + + + +I do have some followup questions. Can I close a "bigger" environment with a "smaller" + +and vice-versa? I was doing that but for safety's sake I now use, e.g. "/smaller" when + +growing and the current point size is less than 10, but "bigger" when growing and the + +current point size is 10 or greater. Is this necessary? + + + +I also have a question about external-body messages. If I have a multipart message it + +would be nice to make the first external-body segment ftp, with parameters that would + +cause it to essentially mget all the files, so later segments could be local-file. To do that + +I really want the first ftp call to mget all the files, create a subdirectory on the user's host, + +and put the files into the subdirectory. One way to do that would be to make the NAME + +on the ftp access type the basename of the directory containing the message and make + +the MODE "directory" or "recursive" or some such. But it needs to be something well + +defined for all the MIME readers. Any thoughts on this? + + + +Finally, I'm pursuing the problem where WIN/3b munched my Content-type line. + +I t's Wollongong rather tha attmail, but I haven't heard back yet from Wollongong. + +A "content-length" caption was added in as the content-type line was mangled, + +so I suspect WIN/3b sendmail has its own private interpretation of content-type. + +Until then I've shortened my boundary down to 5 lower case characters so this + +message shouldn't cause the trouble the last one did. + + + +Thanks for your help, + +Marty + +robb@sblab.att.com + + + + +--tmrob-- + +From - Thu Apr 25 10:19:58 1996 +Return-Path: raph@callisto.hip.berkeley.edu +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id EAA18301; Thu, 25 Apr 1996 04:30:51 -0700 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id EAA01168; Thu, 25 Apr 1996 04:29:58 -0700 +Received: from RSA.COM (RSA.COM [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id EAA17575; Thu, 25 Apr 1996 04:29:05 -0700 (PDT) +Received: from callisto.HIP.Berkeley.EDU by RSA.COM with SMTP + id AA26475; Thu, 25 Apr 96 04:25:34 PDT +Received: (from raph@localhost) by callisto.hip.berkeley.edu (8.6.12/8.6.12) id DAA00979 for smime-dev@rsa.com; Thu, 25 Apr 1996 03:26:57 -0700 +Date: Thu, 25 Apr 1996 03:26:57 -0700 +From: Raph Levien +Message-Id: <199604251026.DAA00979@callisto.hip.berkeley.edu> +To: smime-dev@RSA.COM +Subject: Multipart/signed message format +Mime-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; + micalg=rsa-md5; boundary="7oU2Ma36WUas7M" +X-Mozilla-Status: 0005 +Content-Length: 1784 + +--7oU2Ma36WUas7M + +Dear S/MIME developers, + + I believe that this is a valid S/MIME multipart/signed message. The +implementation is still quite experimental, so as yet I have no way of +verifying that it is, in fact valid. The code is quite similar to my +PGP/MIME and MOSS multipart/signed implementations, so there's reason +to believe it works, but, then again, a lot can go wrong. + + If anyone can verify this message or tell me where I went wrong, it +would be much appreciated. + + By the way, there's a minor nit to pick in the S/MIME message +format document. After clearly (and correctly) calling out the fact +that MIME parameters including slashes need to be quoted, the example +of the multipart/signed at the end of the document is lacking quotes. + + Also, when the spec is finalized, it would be nice if the examples +had valid PKCS data :-) + +Raph (who really needs to get some sleep after staying up past 4am) + +--7oU2Ma36WUas7M +Content-Type: application/x-pkcs7-signature +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHAqCAMIACAQExDjAMBggqhkiG9w0CBQUAMAsGCSqGSIb3DQEH +AaCAMIIBQjCB7AIRAN8ws2vZH70kgc/aYPAb7EswDQYJKoZIhvcNAQECBQAwJTEj +MCEGCSqGSIb3DQEJARYUcmFwaEBjcy5iZXJrZWxleS5lZHUwHhcNOTYwNDI1MDQ1 +OTMxWhcNOTcwNDI1MDQ1OTMxWjAlMSMwIQYJKoZIhvcNAQkBFhRyYXBoQGNzLmJl +cmtlbGV5LmVkdTBaMAoGBFUIAQECAgIIA0wAMEkCQgC//PdZ46JmErS4tgZaI0rq +sHFosshkiNyqT5pVmcS8Aym2JBTtpZOL2oiZDWswBL21Hitxu3Mb2Wa3XNLFhT4y +xwIDAQABMA0GCSqGSIb3DQEBAgUAA0IAfkFzTSTLNoGvOF36wiQpsQ7oRmG8y/U/ +bjjoyVVtAHYikVTYQ3nPN/v8E84psDJu5mkSt9h2fa6c36nHMlEDAoMAADGAMIGf +AgEBMDowJTEjMCEGCSqGSIb3DQEJARYUcmFwaEBjcy5iZXJrZWxleS5lZHUCEQDf +MLNr2R+9JIHP2mDwG+xLMAwGCCqGSIb3DQIFBQAwDQYJKoZIhvcNAQEBBQAEQSUh +EF1KhpoFv1g5O/pOCaEploY8j6UmuR76CJf/6IS+2FPjH1o4Fkxqxzs2/MOp24Dr +leU63btqDC77W9cZ1lsCAAAAAAAAAAA= + +--7oU2Ma36WUas7M-- + +From - Fri Nov 8 18:21:51 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.01) with SMTP id AAA16354; + Fri, 8 Nov 1996 11:45:02 -0700 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id LAA02061; Fri, 8 Nov 1996 11:43:46 -0800 +Received: from krusty.strataware.com (krusty.strataware.com [199.246.138.42]) by xwing.netscape.com (8.7.6/8.7.3) with ESMTP id LAA26164; Fri, 8 Nov 1996 11:44:58 -0800 (PST) +Received: (from rosenqui@localhost) by krusty.strataware.com (8.7.1/8.7.1) id OAA29470; Fri, 8 Nov 1996 14:45:18 -0500 +Date: Fri, 8 Nov 1996 14:45:18 -0500 +Message-Id: <199611081945.OAA29470@krusty.strataware.com> +From: Eric Rosenquist +To: Lisa Repka , Jamie Zawinski +Cc: S/MIME Test Account , + Eric Rosenquist +Mime-Version: 1.0 +Subject: My encryption certificate for S/MIME testing +Content-Type: multipart/mixed; boundary="-ABC" +X-Mozilla-Status: 0005 +Content-Length: 3409 + +This is a MIME encoded message. Decode it with "munpack" +or any other MIME reading software. Mpack/munpack is available +via anonymous FTP in ftp.andrew.cmu.edu:pub/mpack/ +---ABC +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: 7bit + +Netscape: here's my encryption certificate for S/MIME testing +purposes. Beware that this is an Entrust certificate rather than +Verisign. Among other things, this means that I have a separate +key pair for signing and encryption, so you'll have to use this +one to encrypt for me and use the certif included with signed +messages (rather than this one) to verify signatures. + +Eric +--------------------------------------------------------------------- +Eric Rosenquist, Strata Software Limited http://www.strataware.com/ +mailto:rosenqui@strataware.com Tel: 613-591-1922 Fax: 613-591-3485 +Quote: I discovered a meal between breakfast and brunch! + -- Homer Simpson +--------------------------------------------------------------------- +---ABC +Content-Type: application/x-pkcs7-mime; name="eric.p7c" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="eric.p7c" +Content-MD5: THv54kLXRGIbbpoHJeNKGA== + +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 +eNmVDny/dh6w1pNIAhVyHzEA + +---ABC-- +From - Thu Nov 21 13:20:54 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.01) with SMTP id AAA27656; + Thu, 21 Nov 1996 13:20:43 -0700 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id NAA20931; Thu, 21 Nov 1996 13:19:19 -0800 +Received: from RSA.COM (chirality.rsa.com [192.80.211.33]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id NAA00850; Thu, 21 Nov 1996 13:20:34 -0800 (PST) +Received: by RSA.COM + id AA02049; Thu, 21 Nov 96 12:11:51 PST +Date: Thu, 21 Nov 1996 16:10:23 -0500 +Message-Id: <199611212110.QAA14653@krusty.strataware.com> +From: Eric Rosenquist +To: S/MIME Developers +Cc: Eric Rosenquist , + Michel Ranger , + Ron Vandergeest +Mime-Version: 1.0 +Subject: My encryption certificate for S/MIME testing +Content-Type: multipart/mixed; boundary="961121152248_14052" +Sender: owner-smime-dev@RSA.COM +Precedence: bulk +X-Mozilla-Status: 0005 +Content-Length: 5854 + +This is a MIME encoded message. Decode it with "munpack" +or any other MIME reading software. Mpack/munpack is available +via anonymous FTP in ftp.andrew.cmu.edu:pub/mpack/ +--961121152248_14052 +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: 7bit + +Hi everyone. I'm a consultant working with Nortel on their S/MIME products. +I've already completed basic interop testing against Deming's Secure +Messenger and at Blake's suggestion I am about to post a signed message to +this list for others to use in interop testing. If you have questions about +Entrust in general, please visit their web site . If +you have questions about the forthcoming S/MIME toolkit for Entrust please +email Michel Ranger or Ron Vandergeest +. E-mail any technical interop-related questions +directly to me . + +One big thing you should be aware of with Entrust is that it uses separate +key pairs for signing and encryption, so you must be careful to distinguish +between my verification certificate and my signature certificate. You +should import *this* certificate into your local database if you want to be +able to encrypt for me. For now, signed S/MIME messages created with the +Entrust toolkit will include both certificates for the originator as well +as the originator's CA certificate. Eventually this will be under the +programmatic control of whatever app is using the toolkit, so it's +important that you look at the certificate you're importing to make sure +it's the one you want. You can tell which one you've got by looking at the +keyUsage V3 cert extension (object identifier 2.5.29.15). The encryption +certificate has the keyEncipherment bit set (bit number 2 or 0x20) and the +verification certificate has the digitalSignature bit set (bit number 0 or +0x80). + +One other thing that some of you may not have encountered before is that my +CA is not Verisign. Included in the P7C (as well as my signed S/MIME +messages) is my CA's certificate - a self-signed certificate. You can +distinguish this form of certificate (a self-signed CA) from a self-signed +user certificate by looking for the keyCertSign (bit 5) or cRLSign (bit 6) +bits in the keyUsage extension. Failing that, you can look for the +basicConstraints extension to see if the 'cA' BOOLEAN field is present and +TRUE. + +Without further ado, here is my encryption certificate and my CA's +signature verification certificate. I'm away all of next week, so if you +have questions or discover any problems please e-mail me ASAP. If you +don't get a reply by the end of Friday I'll try to get back to you as soon +as possible after Dec. 2nd. + +Eric +--------------------------------------------------------------------- +Eric Rosenquist, Strata Software Limited http://www.strataware.com/ +mailto:rosenqui@strataware.com Tel: 613-591-1922 Fax: 613-591-3485 +Quote: I discovered a meal between breakfast and brunch! + -- Homer Simpson +--------------------------------------------------------------------- +--961121152248_14052 +Content-Type: application/x-pkcs7-mime; name="eric.p7c" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="eric.p7c" +Content-MD5: uqh4Ulmz/0OvRmRYshEwJQ== + +MIIHVgYJKoZIhvcNAQcCoIIHRzCCB0MCAQExADALBgkqhkiG9w0BBwGgggcrMIIDgDCCAumg +AwIBAgIEMpBhhzANBgkqhkiG9w0BAQQFADBEMQswCQYDVQQGEwJDQTE1MDMGA1UEChMsRW50 +cnVzdCBTL01JTUUgSW50ZXJvcCBEZW1vbnN0cmF0aW9uIE9ubHkgQ0EwHhcNOTYxMTIwMTU1 +MjM1WhcNOTgxMTIwMTU1MjM1WjCBljELMAkGA1UEBhMCQ0ExNTAzBgNVBAoTLEVudHJ1c3Qg +Uy9NSU1FIEludGVyb3AgRGVtb25zdHJhdGlvbiBPbmx5IENBMVAwEAYDVQQFEwk4NDg1MjMx +ODIwFgYDVQQDEw9FcmljIFJvc2VucXVpc3QwJAYJKoZIhvcNAQkBFhdyb3NlbnF1aUBzdHJh +dGF3YXJlLmNvbTBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQDGWzna0zhZqRFNLsKp3n1QARcM +IgTPKNCOhp3P1GULQQy/xyyof8Nhz4k6iO1rgo89SCVYAvq2iMk6jQUmNO3jAgEDo4IBcDCC +AWwwYAYDVR0ZBFkwVzBVMFMxCzAJBgNVBAYTAkNBMTUwMwYDVQQKEyxFbnRydXN0IFMvTUlN +RSBJbnRlcm9wIERlbW9uc3RyYXRpb24gT25seSBDQTENMAsGA1UEAxMEQ1JMMTAUBgNVHQEE +DTALgAk4NDgzMjI5MzcwGAYDVR0CBBEwDwQJODQ4MzIyOTUxAwIFIDANBgNVHQoEBjAEAwIG +QDAUBgNVHSMEDTALgAk4NDgzMjI5MzcwEgYDVR0OBAsECTg0ODMyMjk1MTALBgNVHQ8EBAMC +BSAwCQYDVR0TBAIwADBmBgNVHR8EXzBdMFugWaBXpFUwUzELMAkGA1UEBhMCQ0ExNTAzBgNV +BAoTLEVudHJ1c3QgUy9NSU1FIEludGVyb3AgRGVtb25zdHJhdGlvbiBPbmx5IENBMQ0wCwYD +VQQDEwRDUkwxMB8GCSqGSIb2fQdBAAQSMBAbCkpBU1BFUiAwLjEDAgbAMA0GCSqGSIb3DQEB +BAUAA4GBAIk5IGnAWKAIIrM6Iv1ySEz12l6QeOXJB7/DxNGoMXrPWrJMYDF8DNdWSls60ukK +hUN/5zkQQYDOSbTCsRTh6+aZM+i+tNQEW2T/6QqbCF5XzdDcM/5Tpf09PgMkjWUoOc12fcF8 +FUn8QHGsjMFuge86UprBchakJQBLo2rQT58bMIIDozCCAwygAwIBAgIEMpBheTANBgkqhkiG +9w0BAQQFADBEMQswCQYDVQQGEwJDQTE1MDMGA1UEChMsRW50cnVzdCBTL01JTUUgSW50ZXJv +cCBEZW1vbnN0cmF0aW9uIE9ubHkgQ0EwHhcNOTYxMTE4MTMxNTM2WhcNMTYxMTE4MTMxNTM2 +WjBEMQswCQYDVQQGEwJDQTE1MDMGA1UEChMsRW50cnVzdCBTL01JTUUgSW50ZXJvcCBEZW1v +bnN0cmF0aW9uIE9ubHkgQ0EwgZ0wDQYJKoZIhvcNAQEBBQADgYsAMIGHAoGBAKDpfkhv4sFk ++otmMcegaghJFlAOYIj9giN4qid7wfHZhPuE0pUTC1xIB4ytNaEu5j+jh8lUgcd31a7QcCmI +Yh8VzR8bCoGjaVBwOsWDshKFTx8iWeJcQ1fhSIofHWS5VbQudjxeJBzuU8pRXwAr3YXzOR6A +dBbaYZy6PGUYXLgTAgEDo4IBojCCAZ4wYAYDVR0ZBFkwVzBVMFMxCzAJBgNVBAYTAkNBMTUw +MwYDVQQKEyxFbnRydXN0IFMvTUlNRSBJbnRlcm9wIERlbW9uc3RyYXRpb24gT25seSBDQTEN +MAsGA1UEAxMEQ1JMMTAUBgNVHQEEDTALgAk4NDgzMjI5MzcwKwYDVR0CBCQwIgQJODQ4MzIy +OTM3AwICBDARgQ8yMDE2MTExODEzMTUzNlowDQYDVR0KBAYwBAMCB4AwFAYDVR0jBA0wC4AJ +ODQ4MzIyOTM3MBIGA1UdDgQLBAk4NDgzMjI5MzcwCwYDVR0PBAQDAgEGMBoGA1UdEAQTMBGB +DzIwMTYxMTE4MTMxNTM2WjAMBgNVHRMEBTADAQH/MGYGA1UdHwRfMF0wW6BZoFekVTBTMQsw +CQYDVQQGEwJDQTE1MDMGA1UEChMsRW50cnVzdCBTL01JTUUgSW50ZXJvcCBEZW1vbnN0cmF0 +aW9uIE9ubHkgQ0ExDTALBgNVBAMTBENSTDEwHwYJKoZIhvZ9B0EABBIwEBsKSkFTUEVSIDAu +MQMCBsAwDQYJKoZIhvcNAQEEBQADgYEAWZAeWY0jxvT5nRfzPZDULNebM+GdSNLC+YyPYqeE +bD7iR09O0Jh0tP2NyISUcWlRullDIYE8by4T6NhZy0MDrvA3alWxaeGgyEWnqa+kuFOgZTjQ +jc3k4hF1UrhdqK+KfIwz8lhWiDCmSL9IrUFosNwL23rW/pQBm3TZcVCO+nAxAA== + +--961121152248_14052-- +From - Wed Dec 11 18:06:10 1996 +Return-Path: +Received: from urchin.mcom.com ([205.217.237.40]) by dredd.mcom.com + (Netscape Mail Server v2.02) with ESMTP id AAA17435 + for ; Wed, 11 Dec 1996 18:05:59 -0800 +Received: from gruntle (gruntle.mcom.com [205.217.227.10]) by urchin.mcom.com (8.7.5/8.7.3) with SMTP id SAA20049 for ; Wed, 11 Dec 1996 18:05:55 -0800 (PST) +Sender: jwz@netscape.com (Jamie Zawinski) +Message-ID: <32AF6884.41C6@netscape.com> +Date: Wed, 11 Dec 1996 18:05:56 -0800 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0 (X11; U; IRIX 6.2 IP22) +MIME-Version: 1.0 +To: jwz@urchin.mcom.com +Subject: signed frog +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="------------167E2781446B" +X-Mozilla-Status: 0001 +Content-Length: 15749 + +This is a multi-part message in MIME format. + +--------------167E2781446B +Content-Type: image/jpeg; name="bad-frog.jpg" +Content-Transfer-Encoding: base64 +Content-Disposition: inline; filename="bad-frog.jpg" + +/9j/4AAQSkZJRgABAgEASABIAAD/7QEXQWRvYmVfUGhvdG9zaG9wMi41OgBIAAAASAAAOEJJ +TQPpAAAAAAB4AAgAAABIAEgAAAAAAtsCQP/n/+4C/wJSHwMFKAP8AAEAAAEsASwAAAAAC+cJ +YAEsAC0FoF7sACYCAQEBABgAAScPAAEAAQAAAAAAAAAAAAAAAAABAGQAAAAAAAAAAAAAAAAA +AAAAAAAAAAACAAAAAAQCBAUAAAAAOEJJTQPtAAAAAAAQAEgAAAABAAEASAAAAAEAAThCSU0D +8wAAAAAABwAAAAAAAAAAOEJJTQP0AAAAAAASADUAAAABAC0AAAAAAAAAAAAAOEJJTQP3AAAA +AAAcAAD/////////////////////////////A+gAAP/uAA5BZG9iZQBkgAAAAAD/2wBDAB0T +FRUWExsbGx0rHiAiKzYuKysoOlNSQjNCTVBlZmBiYmBrboCCdXJ1dmh9iouLjpWlpaWikqWl +paWlpaWlpaX/wAALCAD+ANUBAREA/8QA0gAAAQUBAQEBAQEAAAAAAAAAAwABAgQFBgcICQoL +EAABBAEDAgQCBQYGCAcDDWEBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSYjM0wXKCQwcl +kghT0fBjczUW4aLxsoMmRJNUZEXCo3Q2FxjSVeJl8rOEw9N14/NGJ5SkhbSVxNTk9KW1xdXl +9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9yg4SFhoeIiYqLjI2Oj4CRkpOUlZaXmJmam5ydnp ++QoaKjpKWmp6ipqqusra6vr/3QAEABv/2gAIAQEAAD8At52dk1ZV9bLNoaAWiB+7PgsujrXU +32ta6/Q/wW/5Ftvycj7MXNf7tvMDlYjurdZHNp/vG/5Ffx8/Pfhmx1nuA52j/IhZPU+oiut1 +dupmfa3/ACKfTeo59zni2wmOPaP8ifMzupNtIqsIb/Rb/kVfE6n1R2S1lthLe42t/wAiu3Z+ +U3KYz1IaRxA/yKhb1PrDbHRadsmPa3/ItA52YcTcHfpNvgOfuWY7qfWwJ9Q/3jf8ivYPUc6z +HcbLJeJ/NH+RRs6lnfYHPZZ+kDhrtHH3Kg3rnU51v/2rf8is/trLEfpv9q3/ACLTozzZTvNg +P3Kld1bI3EMt4PgP8iu4mbY9pFj/AHT4BDyepOZc1rbIB7QEevNDmzvn7lkdS6zm1X7abobH +7rT/ADJ/2tn+jY71tQBHtbz9yq/tzqn+P/2rf8ikOtdT/wAf/tW/5Fc/amd+yfX9X9J6+zdt +HG2fBf/Ql1P/AFRyPg3/AHkLPNLa3tW1TY30gCUDIFRaptNYxntHdpVfF2isbv3UbGfS0kyi +vsqOsqs22kXSo5lrX5FJbrAKldbWGtHccqbcqrYASFB+RSWnUKGPk1AOEjUEKFTwMR+7iVl2 +RuMcIZBUg94EBxCNiCbDPgi5z3MyCGuI0CquscTJJJS9V4GjihuJOpV4yMS0O50iFTA1Ulf/ +AOMH/oq/44v/0Z9VEdTd5tH5FQyNXtRpO0CUxk8pawmJJx2zzPZC1UZPiVAqdE+oJ8VHK/j7 +PigmUydv0m/EK86f2baf4YWeQmhJGxdHn5KXUNcp/kAPwVYpkx4V1/8AI7PNwCqBSV//AIwf ++ir/AI4v/9InVf8AVL7h+AVGwS4+RRBG1KRCbzSaD9nE+JlCIQy9s8pNAfwVOpp9UDzUc0tZ +e8fD8irlzYlR3s8U7XtJELRfH7Lf/TCziQkSFGRKNjRu+5SyWl+Q+PFVn1uDkoUm1PInaY8Y +Vm8FuJHi9U2qeivf8YP/AEVf8cX/0ydWj7cT4Ob/ALyFTt0e74qY1rUHMIEpm+8QE87cd58H +KuPUsdpwmqxi+2HKzZgOr1YUNjXMtbuHdB6s39O53iq213pSq6PQNPmtW0R0p5/0QLKa6SUN +zyHJw+XBWsWPU+Y/nUcq015dnxQ32g6pqzvsa0GJIC6Ci9tDm0N93iVHqOL9raRjt9wMkdis +LaWuLToQYKkVfj+4P/RV/wAcX//Ufqx/uhb5Fv8AvIVbI+nPjCnT9BGsYPTVCm0NuIRiZxr/ +AIgqGPawQEXcBaCrhsG0Sqdxab648UsqgWWPPmhPpApjyWU9ha4hGxwSQPNar2mzpT2jkvH5 +VmnGtpI3sLd3E6SgOx7JJ2kDzCG5rmmCIVzp8G3XxH86F1DXLt+KAZ4KTSWuBHZXmZdosZYB +JGhCs1dTyt59INAcSRKoOcX2Oc7UuJJUlen+4P8A0Vf8cX//1V1aft+QfDb/ALyFWvP0D4hT +odOiuPH6OFix+tEBXKQDVcw8ECUO7EZSWlrj80cY4eAS4hQyWmqsQ8qLabA2u48FwAV0tBBd +OsoFnu0OiqWYTDLg4oNNb2v0EgFbPTGB9QY7jeT+Kq9Uyqbbr2Oa4uaS1o8I0WY52RRtmWhw +3AHggopbXk1b4hw0KfEbDxHMj8ihdWDlPB/eQMloD4CD3VursrdrW14zSGgGOVSA1U40V6P7 +hf8ARV/xxf/WfqeudljuA3/eQqWUf0VJ8iFDDefVhW8nKFYjxCoY5NmUCrr2x64/gLLZY82M +BcTr3KvZpeGMDCQSY0VanJaHEPlwjk6wVpvtH7MxgdHEggHwk6qLnPdYWN4AkFEoxy5u5/0h +qQD2+CJnDCf+h/i3kQHAfzqljuqrd6V4LLG8Hs7wVzA0oDg7bqSlbS12UzIIa14+lM7XR3B7 +H4rP6tL8qt5bG5rZ8NEF7SwucBDZ2n4qWGJcT/DCa7XKtP8ACKZ1Yc2UKvDutY6xrSWN5dCe +kTaxvxW/TiUXYjHPbMjQFZnUcIYrw5mtbuPEeSqAaK9H9wv+ir/jq//Xjnn+6+Y3xDf94Cp5 +OuHXHAdCDhGMgeaJ1MwWKvh2xe1aZdutsH7zFjNMWN+K0ctxbXW4cgqpU1hZtIAMy53cAd1a +vzW3WhjGgMbtDfGBpCtC2mu6XnVzQAI7KxRmVAEGsvnsAUQBl2jKrQD4tESFQzcC51Rthx2+ +LY0VjCl2G5oO0teT8FNleSzQPa/gjVAzqm30F2wNsEka8xoQhkOuxK5r2sDQR/C8Sg0MNZjx +cPyJVUl11jj3JKjaxwO1vdbtNX2LA2tG57WEw3u5YuDiX35W5zS0TL3ERyugftrrMAANGk9g +Fk9SeLsCuxvZ0keEysxvCvf8YX/RT/xxf//Qh1AO/beQYMEM/wB5CrXj9Qs7w/8AnVTEfF7F +Z6qAWsPmqFGlzD5rXb/KGeYIWO7S0+RV7Mk4w+SrgbvNxAOijUzbfBgrXbcyp7Q4taYBBLQf +xVhmXRtH6Yt+PdM/JaBplaH4FV8jPu9GwCHNI2zxz5JYV76MS2wDUFpn5wpDqm/6dbTPki15 +mG9jgf0YdM9whYx9DMsoLm7SN7HDjUfkIQ7a/Tu28tB9p8Qp17GsmQDA5Qw5riZ/BXMK4jHs +sOrmmOeynlW2XU13Yzh6lc9+fLzWdmdRsynNrIDGke6VFjy7AezbHtEeZBVNphX5/uH/ANFX +/HF//9HRy6q3ZD3Hkx+QLIsaPs+U3XSeFl1NPqtgd1a6nPps+Kz6jD2/FbLCPVpPmsq8bb3j +wcfyq7frhz5BVjDB6be/J80UNGwSII7+KLna+if4Pf4qrucUWhsu1I011VnLn0Gt4k+PgrXS +mCxj2HUHx8lds6VjWtAALfNvHwQLOk0tEB7m9h5/5FlYhczNaRrtJ5Wjlx69UaAidOyrvs9o +HaFXNReS4O2mFGjO+ylzQNwdyJ0UDmTLKQWB3Mqdz202tLQJrA0PcFSos0uv2bGlpAHiSIVa +Fe/4wv8Aoq/44v/Su5jXfbLTOmn5As8D9Je3xB/Ih7aWwe6HmvrsYB2lB+zUurBB18kao+5g +5hw/IqPUBtzLf6U/ejG7djbY7IU/pde+qOR7dDwiZLdzKIEy0qzi0GNj6w49hwR/lUndLe6w +mstDT5nQoGfhux/TBEk91c6NAteJ0ErXG6NBPhCcguMO58CsGihjc63Hs2guPtc0fRPKLn1t +qtrAkgA8oGTUftXpkyTEfNLqrK8RjK6T7yPf8FikEGArH2azGsrNkDc3cADx8VLqL2bw0TuG +pPZPS5jcR7SCXlzYPaPBM0K/H9xP+in/AI4v/9MudkO/altLQSfbx/RCTsO+svse2A4EGFhl +7/FTyBNQVUPe3glaGNqB8Wqv1H+WPPjH5EfFdUGe5Ey/QtqaayA9vHmgth1U9wNR4K1LBVRu +HII/Ir+O0tDS1rdPDUFaFerWzpHh2VDrlZ20uBMSQhdFH628eTluBnimDTM8A9lmdepAqbcw +Q4GCR+CrZ1jLTjuboDWZjx7qXV8WuksymENeNssPf4LEyb3XxuaNwJJd3KrbnDhGoJe8l5J4 +k/NTy2l+S8DmRH3JmgtEEnn8UQK7/wAYn/RT/wAcX//Uu5prx899sQ57PpfAKDc8GlxcQNYn ++dV7q+n5hDmtIcBqWaF3yUH9NZY2GPnSYPIVW3o2S2sva3cB2nVLGqc2uSPA/io5eJbfkFzA +Igd1Onpl7m7dAfil+xMz+D96i3Dsrfc1wJcxpJjjRW8ag34kt5r1n4rTxGD0xq0/BXGhpGhV +DrTqziH3CWkHlU+juP2olsGd3K3Q4CCTKY2Nka6qv1EC3DsHgJ+5YTXlwqPMNd+VVcq91ri5 +xJJ7lVWtdY8NaCXHSB3Wg3pBZSX3Eh3Zo/nVOhoDwP4QSvM5Fh80+hE6z+VSar//ABi/9FP/ +ABxf/9XUz2V2S17Q4Agj4wsbKxmC6oMGxrpkDurnpN9JpaNr9oEt0OgT9Ifk5FRfaQ4NMNJG +p+asZufVjFjD7nOPA8OJWfdVkVtY1w9rmbgfnP3pODmursAkER9yKci2sbg0HyQ6+sWueR6Q +AAkmU2FkG77VW/lzHuB84VnojttT/MBWnU45e47IdOpbohnGqcQZefi4qt1WiuvD9rADuGvf +70LpA/WHeMFbBrsMagBRNdnd0lVeok14thDpJEcwsmjUV+Yd+VUba3B7h5kK/wBHdXVe5rxD +3AbHH8i0cx36F3wWHjibB/TCFaZuf/SKk1Tar/8Axi/9FP8Axxf/1rvULw3JeyeI/IqmVq6h +3miVWggCdQrRdVgYIe+QB2HJlc/Y51r33WGS8zHz0XRi6vKx3BjHQ1uhIVSquu2mCTuBlo8J +Ubx6TYeR5eap21AUucDrzCrY1mzIbB5BB+YWl0l0UuB4OhKvVsduMzrx5ozKy2In5qn1iDiE +dw4cqv0XTLPz/It0kQEN5J44Cz+sgjFHJlw1Kzq2OFtII1gflWo/pmP67rCNwdJgrO6piOdm +1CuAbAA3sJCJlOeKC14hwEHz81l4jSbGn+F/Mq7/AOMd4yVNqm1aH/GL/wBFP/HF/9ep121z +Or3gHT2/7yEZtpfiVuPZwRsevbkNstOyk6AnuUTrtjbKqgD7N+pHbRUMapr8qvad4gloPlwu +jxnucwbhAVIbTZYaRLN3I4Q85lZxv0k7p9pWZbke1zSTG2NFWxWusugAmAT7fJafTHFjCQNw +B114Wk25zHAOYWfCEVmRWRP4/wCVB6q9zsF5EGCFn9Hn7U7x1/ItoP8AHRPHCpdZb+pzGjXe +KoMcX5OOTztYPxW8SPx4VHqtc44tETU4OEc+ah1Gt+Rjl1Y3GAQPEFYuIC17RwQ46Kk4+93x +Km0qbStD/jF/6Kf+OL//0KfX2n9rZB/of7yE+Jri7TwHLZe6xlm0V76zxpITZrayxrS0DcDI +AWA9xqv/AEZLCwmCUb7ZnWQx9hDXaGNJV/EyRRQ0nh2n3IXU+o13UtYzU7plY7nku4V/o7Gn +LDXd2ka/zK30yvcXMmNpOp+K0hXBLd4ntPJH+wndUQSYGv5fNC6g3bhXRI8+fvVDo5jLJmNO +/wAFuBwPePDRPx2gHxVLqsfYngjgjTsVl4muRjg6aN5+K6CRPOvYBByxOPcI5aZ+5Qwv0mHS +efbH3LNzavSzBrO4OcsN3JUmlEBWh/xh/wDRT/xxf//R08rp9d+Q95Oro/Iq2R09tOJcGmfa +SodFN19Lh6pAZAHB5Vu3D1Ly8uJ8VCvpVDiXOJkqVnTaK63Fo1AJVPpmJTl1ltonZqIKtX9O +w8et9rWAFomVzdlRDiSNSjYbzTlVP0EELT6OYyH6jUu5+K09AQJk9p4+9SbwedRMHVVuota7 +Dtnw5HBWd0kA5BHl4+S2Y09xkgeHKkzQESCFX6oycG7QxE6fFZGFJyMfQTpp81vTpIBPaExa +S2PiACfFVOkEtptqdyywqr1NwOYI7VrnyVJqI0LSj+4P/RR/x1f/0t17oeULIl1Fo8WO/Isv +6vPhtwHl/OtcmRqpAkDQpnS5pHksrpLy1zxxyPxV7Idva1rtWnUjyVW/FZkVlphpHEeKxLWO +psIOhafyLR6O4uyXH96VrOP7095KYvg6/LcEO8E49upgtOnYGFl9HMZR8x/MtrdtPgPLgn4p +d9ST+RQyffj2tGvtI18wsTpxJyKPKFuhxkjtzKUtBERP+fZZ+J+j6rksg6if51DPAfmvA7sA +HzXPOEGPBO1FatP/AIwv9/8A/HV//9PbuMWFDmQR4iFndIY1hfHPB+9abSpEpg8LIxDsvsHg +5ys5FmwVuIkSQfmjMcRHeYWZ1mhrbG2N038wNZTdF1v+X8y2nfRmNO0cIJeB/R08eO6hcSan +tEO9pmfBZfTXRb4AD8IWq29riRoODyjAnwjyGqZ4DmuHlqJ1Cxemj9aYBpH+yt0GP9lNoTM6 +juP8qzXS3rQj2Bze3fRNa6epvHIAasDY574aJJKsDAy9s+kY8tVANI0Oh81o6/sP/oo/44v/ +1Ny5oLnFDqa3cs7px25ttZ7OcFpNLd0SneBtUKtvdZQe1mXcZ9oeVaynj7Jua31Ggg7m9v8A +Puq4vIBmCIBiU3UnCzCdqNCDoeFX6M6Lx2kLaBaGgTyoEkyRpMzHP4eSHa5xYYkggyCDwVkd +PcG2OJG4R/MtUPA5ae0/MKXqgggyBqNFMOcGmYJGkHggrJ6eQMgE6jSQCtauxp4InmPya+an +OkHx1WZedvWKzzLRp4JnbX9QtEzJA0KV/SmenupHuGsTol0rK2Wimzg8HuCrfUcGu9hsYP0n +Yjv8VS2H9kbY1+0xH9Rf/9XXyS4Pd8kCov3Kg99lWZca2h7y/QExyEz8vMrDXOxw0uMDXv8A +eruPljIrImHjRzR4+XkqmVnWUW+3hhkg91Xy7Gusyn1n2mHArR6Mx32Q74/SEkN8uPxWVc40 +ZLqiJ2n2z3HZEtyW2Y7x3LDOkTr+Kh0p0PBJ+a2N5LiDxM+U+CYnWSJ2xM8lDs3Bsj6QiYdy +qHTd3qkt5hX/AKEy3RoJgIjHCJntqOYHmptIAMGdCJjw/IsbEaDLe+g0Md1pUnZ9F+7xk8eA +UnWndAEeBlUXvb+1JIMNboAljbvt1pPId3WhvI+iJPIAWBbc+vMc4DaQ8mPmuibksNAsPdUd +/wCob+/2yfwX/9bYyfpuQ6291h9QfYcy2xoLCwafLurmBm1ZOPYzJ2idD/CHl5rJBZVYHNc9 +g1jxHgpX5JcyLGgujR47ypYvvqsB4LSt/BracOkg67eFR61il1DbGD+L5+BWJ6hLSJMwrfTi +ATJjTk/FaItBdxqZPeY8QfLspb54O4iZ2nXnmEjI9zmkToCBzPwlZ+IdrbIPaNOVfqeIaNwc +BxI7jn70YaRILj4cCD4lM95bIe/a7UEz2+5ZuA6HbvCCrYLGvB7n87XUcSPNPZe2oFzjxr2g +oWFU6x5vfy46ApsUTl2/0ytBjy0na0AzrJWH1YtGY8gyTromdnPdWGhobpB81bn+4c/8WP8A +jq//19fKP6Q/JMw+1UMwD7YB2eyCq7+kljN1bt7edp5HwVd2Mx7SwSS2de4VK0WVsNbhoSD8 +PgrPThpDuC0yr+Bk+k00WGHM4M8hWszNrppkjduO0Arn8ttJ99ehJ1AKliE+jYf4BU6MpxkG +SJH+fxVht3AP0xI3T98g+KM07m6BzHEkAtPfzVXCcSXumDHKvN7biCBBAM/fCJIho2wHHRuu +vl8EG5+2t4DtpIcIGp+c8Kp0/wCifAgDlEyMj0wZ+UKg+6w3BzwYkHat+mxrq2ODfa7jyVPE +e31LTxDnalRzuoekNrB7iskve5xc4y49yna1xGgWtB/YP+//AOZf/9DVyz+mI+H5EwOip5v8 +ppPkQrtX0Qh5NOM87nMG/wARoVR6lhv+yH0m72zLp+kFR6e3QDx3D8FWM+nM+5nhymsN1lbb +DZvE7QO6P1Btf2XGeysMkGYCWI1rq37ZjY7lUA9zT5Itdpa4HdI8FYbkCCdw4EyJ1HiidPPs +cf4M6DzV4v2BzwQRPn7h3EJP2DRvOhB/dny/nVfPeBjAcSePAoWK4MoeSJjbp4o+LiBzvVvE +u5a08BV+qMHrB06ka/JWcW3bjsB0gCSVX9R1VDnNEkugCFRHqPtDngnWTKvGxl1LnmpjIOjj +oIVSzJL3hpMsGg2iAtjb/ceI9vrePbav/9HUydcl3y/IpRpCpZoAsqPgVcZ9EIdx4U6yQ0Kl +kVMblV7BG8mY8Vk5DHteZZtI04iQqQ3AK0/KdkY3pvIaW6j+EVZ6e0FjY/ddKq5OG5slkubE ++YVMAt+Ckd0GDoVoYIPovP8AAKn9oaZn87ifhqpttYQJ1Gny00Qs14tc33EgEkkqxhDY5xiO +DB7Kw6ztHms3PaX26cAH5Ku60O2sDi1g0JlaFLn1YrnbJIPA1VK31LHRa7YD4BAcXloYXSG8 +DwUq6w6zWdT3W/6X9x9n8P8AmX//0tW/+Uu+X5E4c2Ykfeq2W3cW+RlHc9rNCQD5lCfbVuEu +CO19JaDvbHxVa4Msur2ODtrgTCbJGLa0sse2RwTyFj5OMxujbGvHkVTcwt05C1el4tm4NPeT +8iFEbLDtDxIMQeVXzMQh24iJQK8YuWniYj/QsEHVrgNFRtpZW8teH7vhCGGO3e1jo81fxcXa +7e4Fx7K5ViWhljtpG5VbXXzFePY48AuCquwM+8lz6yB4H/IrIxLXVsqZjQ4SC88HzVx/TXvx +w06EGfiqNvSsxxhtYaP6SH+xcwawPvRsbo+QLWufDQCD8Vt+gPs2z+FP4L//092xkvJmJhBG +FT6nqcOnkIuys8wfik6ulxl0KJoxjoQ3X4KAxsBp+iyUVv2Ss+3Y0+UKD2YDnbnemT8lHZ03 +XSv7go7elkf2L8ERuTg1iGvYAPDshus6YXSTWSe+ic5PTRy5ij9s6WPzmD5KX7T6e0QLWx5K +B6l00yS4H5Jv2p05o0MD+im/a2D2a4jyakOs4ZO1ocT4AKZ6nTBIref6qE/rFDNDW4HsCIlE +HUJaT6FgETx2UKOqDI3elU5wbyifaru1DvvCC3qm6/0RXD5iCQFO/MuordY+mGt51Ch+0x+z +vtOw7fU2x5Qv/9TQzBR9qeX2uB00DojRAd9jAP6VxP8ASKpbh6dgJeXR7TJ5RsIUfZwcmd5P +cnVWCOmeA/FCyRgGoisAP7RKp27HY2xrItke7yVqoYVVLBfX741McqXr9LE/oh/eqjnW4z3t +NDNpHOmhQ7bG5LqgysVuGhjgq+MnArGx1XuGh9oTO6hgD+wfgFmi8V5DrKmjbOjXa6IzCcnI +FuwN2ido7wjnqjBxSo29SZbU5jqJBGmqDiZl2MCBDgezlPGtLL7sgCTPHxVh3VLO1Y+9VM3L +fktAcwCOCFGvOy2N2CwlsRB8EWq+3CoY6nT1Ppbh4Jx1bOP5wPyVa62++31XGXeI0Uxl5F36 +K2wuZ3B7rW9Jn7M2bTs9WY8ts/lX/9XRzOnm7JfYHgTGkeSGOkjvZ+ChkdOFVLnh87edE2Dj +15dMOcW7Dp5qx+ysfvY78Ev2Xi/4x33hVOo4tGKxrmP3TpBPdHoxMbKorfY8gxETEKR6V0/v +Yf74Jv2R0z/GH++CzczHx8XLayl+4aO1MrQb0/AsabHyHHUjcpfsvpR7/wC2S/Z/SGDUjw1c +svGNLOpNYNa2uc2fEStU4nR2yHBonxJTCjosRDfvQsmrpAx37SGugkEHWVT6Q6h73+v9Ejjz +WkP2QD9FpTz0lxnYyfgqHV/sHoNdSAHh0aeCL0p+OzFi5s66SPJWftnTvBv96pDMwo0iPgsr +qzqnZNT62xuGvnqtP1f7k8Cfo/gv/9bZvZuscfVc3jQNPgqd+PL9cuweQrdwq9+NUanb814b +Gs1uRMWjGFZFWUTpyGFM7HqnXMd/w25R+z4//Ex3/DbkG7GwiG785w92k1uR/QxYbGW6ex2F +CONhyf10/Otyb7Nhx/LT/wANuQ24uB9oB+3Hdpp6TlYvx8QkTllpgcVlDrxsMP8A5aSfA1uS +txsMzuzQBu49IoOPi9ND3RnbvL0nKzlY+EdvqZkaCIrPCB9l6fP8u/5Cco2YvTtvuzux/sTk +XExsBtcNzd/n6ZCRx+nTpmf8hlOzGwoO3N/5DKDdi9OIbuz41EfonK0KML0gPtfz2FD+z9Pn +XM1/0sorKMEH+VEjw2FNm0YDrqi7K2Q0bRsJkSrXp4n2Hb63s9Sd2087eIX/2Q== +--------------167E2781446B +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIINTQYJKoZIhvcNAQcCoIINPjCCDToCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC +DDwwggm7MIIJJKADAgECAhApD8YX9G6ah0T5a1eI8maEMA0GCSqGSIb3DQEBBAUAMGIxETAP +BgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVy +aVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjAeFw05NjExMDYwMDAw +MDBaFw05NzExMDYyMzU5NTlaMIIBDDERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZl +cmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVh +bCBTdWJzY3JpYmVyMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BT +IEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk2MSYwJAYDVQQLEx1EaWdpdGFsIElEIENs +YXNzIDEgLSBOZXRzY2FwZTEXMBUGA1UEAxMOSmFtaWUgWmF3aW5za2kxHzAdBgkqhkiG9w0B +CQEWEGp3ekBuZXRzY2FwZS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAvf/Pd1H5zPhu +ZO6Dt702B4B/dOoosaVlYyknsHZfDHEufMwGbywmyrvhSgEWdL4TwOa1J3tvfzV1G9oKlRzM +pQIDAQABo4IHCDCCBwQwCQYDVR0TBAIwADCCAh8GA1UdAwSCAhYwggISMIICDjCCAgoGC2CG +SAGG+EUBBwEBMIIB+RaCAadUaGlzIGNlcnRpZmljYXRlIGluY29ycG9yYXRlcyBieSByZWZl +cmVuY2UsIGFuZCBpdHMgdXNlIGlzIHN0cmljdGx5IHN1YmplY3QgdG8sIHRoZSBWZXJpU2ln +biBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCAoQ1BTKSwgYXZhaWxhYmxlIGF0 +OiBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vQ1BTOyBieSBFLW1haWwgYXQgQ1BTLXJlcXVl +c3RzQHZlcmlzaWduLmNvbTsgb3IgYnkgbWFpbCBhdCBWZXJpU2lnbiwgSW5jLiwgMjU5MyBD +b2FzdCBBdmUuLCBNb3VudGFpbiBWaWV3LCBDQSA5NDA0MyBVU0EgVGVsLiArMSAoNDE1KSA5 +NjEtODgzMCBDb3B5cmlnaHQgKGMpIDE5OTYgVmVyaVNpZ24sIEluYy4gIEFsbCBSaWdodHMg +UmVzZXJ2ZWQuIENFUlRBSU4gV0FSUkFOVElFUyBESVNDTEFJTUVEIGFuZCBMSUFCSUxJVFkg +TElNSVRFRC6gDgYMYIZIAYb4RQEHAQEBoQ4GDGCGSAGG+EUBBwEBAjAsMCoWKGh0dHBzOi8v +d3d3LnZlcmlzaWduLmNvbS9yZXBvc2l0b3J5L0NQUyAwEQYJYIZIAYb4QgEBBAQDAgeAMDYG +CWCGSAGG+EIBCAQpFidodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9DUFMw +ggSHBglghkgBhvhCAQ0EggR4FoIEdENBVVRJT046IFRoZSBDb21tb24gTmFtZSBpbiB0aGlz +IENsYXNzIDEgRGlnaXRhbCAKSUQgaXMgbm90IGF1dGhlbnRpY2F0ZWQgYnkgVmVyaVNpZ24u +IEl0IG1heSBiZSB0aGUKaG9sZGVyJ3MgcmVhbCBuYW1lIG9yIGFuIGFsaWFzLiBWZXJpU2ln +biBkb2VzIGF1dGgtCmVudGljYXRlIHRoZSBlLW1haWwgYWRkcmVzcyBvZiB0aGUgaG9sZGVy +LgoKVGhpcyBjZXJ0aWZpY2F0ZSBpbmNvcnBvcmF0ZXMgYnkgcmVmZXJlbmNlLCBhbmQgCml0 +cyB1c2UgaXMgc3RyaWN0bHkgc3ViamVjdCB0bywgdGhlIFZlcmlTaWduIApDZXJ0aWZpY2F0 +aW9uIFByYWN0aWNlIFN0YXRlbWVudCAoQ1BTKSwgYXZhaWxhYmxlCmluIHRoZSBWZXJpU2ln +biByZXBvc2l0b3J5IGF0OiAKaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tOyBieSBFLW1haWwg +YXQKQ1BTLXJlcXVlc3RzQHZlcmlzaWduLmNvbTsgb3IgYnkgbWFpbCBhdCBWZXJpU2lnbiwK +SW5jLiwgMjU5MyBDb2FzdCBBdmUuLCBNb3VudGFpbiBWaWV3LCBDQSA5NDA0MyBVU0EKCkNv +cHlyaWdodCAoYykxOTk2IFZlcmlTaWduLCBJbmMuICBBbGwgUmlnaHRzIApSZXNlcnZlZC4g +Q0VSVEFJTiBXQVJSQU5USUVTIERJU0NMQUlNRUQgQU5EIApMSUFCSUxJVFkgTElNSVRFRC4K +CldBUk5JTkc6IFRIRSBVU0UgT0YgVEhJUyBDRVJUSUZJQ0FURSBJUyBTVFJJQ1RMWQpTVUJK +RUNUIFRPIFRIRSBWRVJJU0lHTiBDRVJUSUZJQ0FUSU9OIFBSQUNUSUNFClNUQVRFTUVOVC4g +IFRIRSBJU1NVSU5HIEFVVEhPUklUWSBESVNDTEFJTVMgQ0VSVEFJTgpJTVBMSUVEIEFORCBF +WFBSRVNTIFdBUlJBTlRJRVMsIElOQ0xVRElORyBXQVJSQU5USUVTCk9GIE1FUkNIQU5UQUJJ +TElUWSBPUiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIKUFVSUE9TRSwgQU5EIFdJTEwgTk9U +IEJFIExJQUJMRSBGT1IgQ09OU0VRVUVOVElBTCwKUFVOSVRJVkUsIEFORCBDRVJUQUlOIE9U +SEVSIERBTUFHRVMuIFNFRSBUSEUgQ1BTCkZPUiBERVRBSUxTLgoKQ29udGVudHMgb2YgdGhl +IFZlcmlTaWduIHJlZ2lzdGVyZWQKbm9udmVyaWZpZWRTdWJqZWN0QXR0cmlidXRlcyBleHRl +bnNpb24gdmFsdWUgc2hhbGwgCm5vdCBiZSBjb25zaWRlcmVkIGFzIGFjY3VyYXRlIGluZm9y +bWF0aW9uIHZhbGlkYXRlZCAKYnkgdGhlIElBLjANBgkqhkiG9w0BAQQFAAOBgQCvsCGM0+zA +TKtgRn8N1dKRfa1Y7JouUdVU4ynJWeEZ1iEvtzbhaaadgmV5ZPLoUZzjCMEpnYDzwK+bh/nv +IecbQOC9ie5Gr8DURh/9ZqYP0/L+QGDshYcBB7kyG9XZ5ihnAc4eZBJCqtrTYWwW9lGHFKRX +dEh4GQBfJRThfNOYgTCCAnkwggHioAMCAQICEDURpVKQb+fQKaRAGdQR/D4wDQYJKoZIhvcN +AQECBQAwXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL +Ey5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 +MDYyNzAwMDAwMFoXDTk3MDYyNzIzNTk1OVowYjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNV +BAoTDlZlcmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5k +aXZpZHVhbCBTdWJzY3JpYmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2FKbPTdAF +DdjKI9BvqrQpkmOOLPhvltcunXZLEbE2jVfJw/0cxrr+Hgi6M8qV6r7jW80GqLd5HUQq7XPy +sVKDaBBwZJHXPmv5912dFEObbpdFmIFH0S3L3bty10w/cariQPJUObwW7s987LrbP2wqsxax +hhKdrpM01bjV0Pc+qQIDAQABozMwMTAPBgNVHRMECDAGAQH/AgEBMAsGA1UdDwQEAwIBBjAR +BglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcNAQECBQADgYEAKeXHoBmnbxRCgk0jM9e9mDpp +dxpsipIna/J8DOHEUuD4nONAr4+xOg73SBl026n7Bk55A2wvAMGo7+kKTZ+rHaFDDcmq4O+r +zFri2RIOeGAncj1IcGptAQhvXoIhFMG4Jlzg1KlHZHqy7D3jex78zcSU7kKOu8f5tAX1jC3+ +sToxgdowgdcCAQEwdjBiMREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24s +IEluYy4xNDAyBgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNj +cmliZXICECkPxhf0bpqHRPlrV4jyZoQwCQYFKw4DAhoFADANBgkqhkiG9w0BAQEFAARAuhJc +9hmJOgvfpjpNc54XgAqiP6hhFJVL/Qih0b3/TLDX0dy7q0niVJ7LourWVn+oMtnL+8CamqOE +61cwKedkFg== +--------------167E2781446B-- + +From - Fri Dec 13 15:01:21 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA19742 + for ; Fri, 13 Dec 1996 14:59:31 -0800 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23726 for ; Fri, 13 Dec 1996 14:58:13 -0800 +Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id OAA00270 for ; Fri, 13 Dec 1996 14:59:27 -0800 (PST) +Received: by peapod.deming.com from localhost + (router,SLmail V2.0); Fri, 13 Dec 1996 15:01:48 Pacific Standard Time +Received: by peapod.deming.com from seth + (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:01:02 Pacific Standard Time +Message-Id: <3.0.32.19961213150855.009172e0@mail.craswell.com> +X-Sender: blaker@mail.craswell.com +X-Mailer: Windows Eudora Pro Version 3.0 (32) +Date: Fri, 13 Dec 1996 15:09:42 -0800 +To: Jamie Zawinski +From: "Blake Ramsdell" +Subject: Re: can you send me an encrypted message? +MIME-Version: 1.0 +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" +X-Mozilla-Status: 0011 +Content-Length: 1431 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAt +IEluZGl2aWR1YWwgU3Vic2NyaWJlcgIQKQ/GF/RumodE+WtXiPJmhDANBgkqhkiG9w0BAQEF +AARAb0tthyav05ce7KBWdlfN1M0R6wLQ2FWPVQynuWo/yHUoo3hiII7j15FXNgnxF7QkY5/p +mZXg0P2eJ1iYQy1vZDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5W +ZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1 +YWwgU3Vic2NyaWJlcgIQDOtpec1+JM3EpqAMVqgtjzANBgkqhkiG9w0BAQEFAARAuqnsnz1O +qEdx7NEMJDEdjccjdEuCM8x2euTYlU/GWNY+s2iKVahbT3/R8E8hp3YfrHd2sjvgy6teTOPO +ZI2SxwAAMIAGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIlhWqtbsElaWggASCAjBooYYTWSBz +7A4l0Aho7mK85zpMyAR0xTKqHXT0zL9XpHbKPAcETaBTh1n7e8aJeQ93ONGAs6tVVlA6bpUN +F3Q5O+ZuNXOMT83HIKRYEO1l8a+CH7XtUiQWtu/aBt12GQDX475WhPULKEJs7kLS2DwToRX/ +ctwEPNwc6zfsOZoVTQ5HOwisvDZ2QGwa08Psj38SaQ0Y+ryk5FeiAtKQUZ0uuJWI/rRu64yj +KmVs1DDId18coftA2rv/u2/zABEX8u5ckEkwS7fO7UHv6XMCQ3kqgqIZZE1zIGohfUdtOYYo +M4eki3QDyovHPxEjBbnmpUw2xDN7/DdxYEZ4CteWurQ+VoP0PUM2qwi6EgM6MpVKg8KzOWdb +aV51a1oQKtpJJFZqZtFf9SQ4OW6NKXHsJ2AF8W4OQ+ySWQN43wMk8dGJYlPrREqn5RufPg3k +QM+s4VwTrS2TrU+ELZCYnJFfH+N7tE8ILrFMAteVxtqjat7OJRyDxy0cnBP+oG81Sr0zvbdC +jUPUDFlrPgFjDrswX1UpkEE2OgKWmfc134AbysJFOuCIze2XqKB96rJvxS76ygzVvrU/4sI1 +6VDlZUEuUPaBUOimFxRk/rqPJDI1M8rNKykw9qsoWQMRnvrODfzo7iVWQ0TQHiwfoBhs6Dvm +UgrMwopFnzRdSHvT1acSqVfMYWm5nXImvtCuFAavkjDutE9+Y/LLFLBUpAVeu3rwW3wV0Tcv +9I6Afej0ntfbH9vlRwQIl7MeXMqoBV0AAAAAAAAAAAAA +From - Fri Dec 13 15:01:22 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA19910 + for ; Fri, 13 Dec 1996 15:00:10 -0800 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23769 for ; Fri, 13 Dec 1996 14:58:51 -0800 +Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id PAA00313 for ; Fri, 13 Dec 1996 15:00:03 -0800 (PST) +Received: by peapod.deming.com from localhost + (router,SLmail V2.0); Fri, 13 Dec 1996 15:02:27 Pacific Standard Time +Received: by peapod.deming.com from seth + (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:02:23 Pacific Standard Time +Message-Id: <3.0.32.19961213151017.0091ed80@mail.craswell.com> +X-Sender: blaker@mail.craswell.com +X-Mailer: Windows Eudora Pro Version 3.0 (32) +Date: Fri, 13 Dec 1996 15:10:21 -0800 +To: jwz@netscape.com +From: "Blake Ramsdell" +Subject: Encrypted message +MIME-Version: 1.0 +Content-Type: multipart/signed; boundary= + "---=_=_ 659214770-385040-15143392 _=_=---"; micalg=rsa-sha1; protocol= + "application/x-pkcs7-signature" +X-Mozilla-Status: 0001 +Content-Length: 4392 + + +-----=_=_ 659214770-385040-15143392 _=_=--- +Mime-Version: 1.0 +Content-Type: text/plain; charset="us-ascii" + +I sent you an encrypted message that was triple-DES. Let me know if you +had any problems with it... + +Blake +-----=_=_ 659214770-385040-15143392 _=_=--- +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggUM +MIIEdaADAgECAhAM62l5zX4kzcSmoAxWqC2PMA0GCSqGSIb3DQEBBAUAMGIxETAPBgNVBAcT +CEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24g +Q2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjAeFw05NjExMTMwMDAwMDBaFw05 +NjEyMTMyMzU5NTlaMIIBMzERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWdu +LCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJz +Y3JpYmVyMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BTIEluY29y +cC4gYnkgUmVmLixMSUFCLkxURChjKTk2MT4wPAYDVQQLEzVEaWdpdGFsIElEIENsYXNzIDEg +LSBTTUlNRSBEZW1pbmcgU29mdHdhcmUsIEluYy4gQmV0YTEjMCEGA1UEAxMaQmxha2UgNTEy +IFRlc3RpbmcgUmFtc2RlbGwxIjAgBgkqhkiG9w0BCQEWE2JsYWtlckBjcmFzd2VsbC5jb20w +XDANBgkqhkiG9w0BAQEFAANLADBIAkEA0q21Atm4nAvUY0I8lrFOjX9BbnR3gFfZu8+jiW87 +snqVeDFARsmmwqyQ1VoHgkSN/atjDHKkT+E/4OK1/up9YQIDAQABo4ICMjCCAi4wCQYDVR0T +BAIwADCCAh8GA1UdAwSCAhYwggISMIICDjCCAgoGC2CGSAGG+EUBBwEBMIIB+RaCAadUaGlz +IGNlcnRpZmljYXRlIGluY29ycG9yYXRlcyBieSByZWZlcmVuY2UsIGFuZCBpdHMgdXNlIGlz +IHN0cmljdGx5IHN1YmplY3QgdG8sIHRoZSBWZXJpU2lnbiBDZXJ0aWZpY2F0aW9uIFByYWN0 +aWNlIFN0YXRlbWVudCAoQ1BTKSwgYXZhaWxhYmxlIGF0OiBodHRwczovL3d3dy52ZXJpc2ln +bi5jb20vQ1BTOyBieSBFLW1haWwgYXQgQ1BTLXJlcXVlc3RzQHZlcmlzaWduLmNvbTsgb3Ig +YnkgbWFpbCBhdCBWZXJpU2lnbiwgSW5jLiwgMjU5MyBDb2FzdCBBdmUuLCBNb3VudGFpbiBW +aWV3LCBDQSA5NDA0MyBVU0EgVGVsLiArMSAoNDE1KSA5NjEtODgzMCBDb3B5cmlnaHQgKGMp +IDE5OTYgVmVyaVNpZ24sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuIENFUlRBSU4gV0FS +UkFOVElFUyBESVNDTEFJTUVEIGFuZCBMSUFCSUxJVFkgTElNSVRFRC6gDgYMYIZIAYb4RQEH +AQEBoQ4GDGCGSAGG+EUBBwEBAjAsMCoWKGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9yZXBv +c2l0b3J5L0NQUyAwDQYJKoZIhvcNAQEEBQADgYEAF6Z54NUzRdcCLfac7WDTx88kisX4TpG+ +UXPcTMhNm55pDb88mPMBNhsOTA9SP7OJjCVBvqNcWSopPaz6H2Bd1vowiDi3Lnm3Dw0ntXvp +WPO1PkUd6/TGpu4ayfpNVAYSxDcjdt4+LSSwLWLsWarAanulHHcoO9ZGm71nm70DubkwggJ5 +MIIB4qADAgECAhA1EaVSkG/n0CmkQBnUEfw+MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYT +AlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMg +UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjA2MjcwMDAwMDBaFw05NzA2 +MjcyMzU5NTlaMGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j +LjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJl +cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAthSmz03QBQ3YyiPQb6q0KZJjjiz4b5bX +Lp12SxGxNo1XycP9HMa6/h4IujPKleq+41vNBqi3eR1EKu1z8rFSg2gQcGSR1z5r+fddnRRD +m26XRZiBR9Ety927ctdMP3Gq4kDyVDm8Fu7PfOy62z9sKrMWsYYSna6TNNW41dD3PqkCAwEA +AaMzMDEwDwYDVR0TBAgwBgEB/wIBATALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgIE +MA0GCSqGSIb3DQEBAgUAA4GBACnlx6AZp28UQoJNIzPXvZg6aXcabIqSJ2vyfAzhxFLg+Jzj +QK+PsToO90gZdNup+wZOeQNsLwDBqO/pCk2fqx2hQw3JquDvq8xa4tkSDnhgJ3I9SHBqbQEI +b16CIRTBuCZc4NSpR2R6suw943se/M3ElO5CjrvH+bQF9Ywt/rE6AAChgDCCAScwgZEwDQYJ +KoZIhvcNAQECBQAwYjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWduLCBJ +bmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJzY3Jp +YmVyFw05NjA3MDExNzMwNDBaFw05NzA3MDEwMDAwMDBaMA0GCSqGSIb3DQEBAgUAA4GBABi7 +kOj1/AOwIqgRLVs2LZepWTUgyNG0eWFKPg9ic5MN9HcUJyUmylxHOl2LswFuR768wE17uXNf +Vlj0+HEQ8Jox+9YvUHA8rFsH/8BNKhk4liN7UE9COVRoe4yCQ9O55QcN0eF5fHR/ZK/OSbFo +p6gx+WCqSKPaPJJ2OZ+/qozqMIIBJDCBjjANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFBy +aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkXDTk2MDgxMzAwMzA1OFoXDTk3MDgxMjAw +MDAwMFowDQYJKoZIhvcNAQECBQADgYEA1dzv/pevULboNwwiRcIOq1XaRQOMyWw/SSFUNu+j +5rSRjjvmzWTpm0bi/8ct5T5HR9auJmz6Q/pj6x0waXEjshWQh3/VagIcgDsXcdObIDcw4Gpf +igcOHr577KpFlr3kGVC4ik5oTvzmNscK5So8npwbEXx9NHMXFmh7vMr7jREAADGAMIIBNgIB +ATB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIG +A1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcgIQDOtp +ec1+JM3EpqAMVqgtjzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc +BgkqhkiG9w0BCQUxDxcNOTYxMjEzMjMxMDIxWjAjBgkqhkiG9w0BCQQxFgQU2mTOfNT5sj4A +zx1+sUPxnuPu0BAwDQYJKoZIhvcNAQEBBQAEQE7o3gGllV4G6J4nrUpT8U9Ci5KPPC+WJ9Ot +UI4zv6C6+7KF4yf7Dbv5PL+EQHY02oDQXvrU4nNkhSefw4gcON4AAAAAAAAAAA== +-----=_=_ 659214770-385040-15143392 _=_=----- + +From - Mon Apr 22 18:36:56 1996 +Return-Path: arjun@connectsoft.com +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id SAA23836; Mon, 22 Apr 1996 18:27:07 -0700 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id SAA01845; Mon, 22 Apr 1996 18:25:57 -0700 +Received: from RSA.COM (RSA.COM [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id SAA27395; Mon, 22 Apr 1996 18:25:05 -0700 (PDT) +Received: from connectsoft.com by RSA.COM with SMTP + id AA11175; Mon, 22 Apr 96 18:17:09 PDT +Received: from [199.237.157.163] (arjun.connectsoft.com [199.237.157.163]) by connectsoft.com (8.6.12/8.6.12) with SMTP id SAA12999 for ; Mon, 22 Apr 1996 18:19:19 -0700 +Message-Id: <199604230119.SAA12999@connectsoft.com> +To: "smime-dev@rsa.com" +Subject: Ready for interoperability testing. +Date: Mon, 22 Apr 96 18:20:32 -0500 +X-UIDL: 830222885.000 +From: Arjun J Taneja +X-Mailer: E-Mail Connection v3.0.B1d +Mime-Version: 1.0 +Content-Type: application/x-pkcs7-mime +Content-Transfer-Encoding: base64 +Status: U +X-Mozilla-Status: 0001 +Content-Length: 3495 + + +MIAGCSqGSIb3DQEHAqCAMIACAQExDjAMBggqhkiG9w0CAgUAMIAGCSqGSIb3DQEH +AaCAJIAEggL1TUlNRS1WZXJzaW9uOiAxLjANCkNvbnRlbnQtVHlwZTogbXVsdGlw +YXJ0L21peGVkOyBib3VuZGFyeT0iPV84MzAyMTE2MjM6MTA1NDQ4Njk0Ig0KDQot +LT1fODMwMjExNjIzOjEwNTQ0ODY5NA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWlu +OyBjaGFyc2V0PXVzLWFzY2lpDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiBx +dW90ZWQtcHJpbnRhYmxlDQoNCi0tIFsgRnJvbTogQXJqdW4gSiBUYW5lamEgKiBF +TUMuVmVyICMzLjAuUkMxZCBdIC0tPTBEPTBBPTBEPTBBRnJpZW5kcyw9MEQ9DQo9 +MEE9MEQ9MEFUaGlzIG1lc3NhZ2UgaXMgYSBzaWduZWQgbWVzc2FnZSBpbiBhY2Nv +cmRhbmNlIHdpdGggU1RFUCAzIG9mIHRoPQ0KZT0wRD0wQWludGVyb3BlcmFiaWxp +dHkgdGVzdCBndWlkZWxpbmVzIGJ1dCBmb3IgdGhlIGZhY3QgdGhhdCBpdCBkb2Vz +IG5vdD0NCiBoYXZlIGE9MEQ9MEFkZXRhY2hlZCBkaWdpdGFsIHNpZ25hdHVyZS4g +SG93ZXZlciwgSSBob3BlIHRoaXMgd2lsbCBpbml0aWE9DQp0ZSB0aGUgcHJvY2Vz +cz0wRD0wQW9mIG91ciBpbnRlcm9wZXJhYmlsaXR5IHRlc3QuID0wRD0wQT0wRD0w +QVRoYW5rcyw9MEQ9MEE9DQpBcmp1bi49MEQ9MEE9MEQ9MEFBcmp1biBUYW5lamE9 +MEQ9MEFDb25uZWN0U29mdCBJbmMuLEJlbGxldnVlPTBEPTBBZS1tYWlsPQ0KIGFk +ZHJlc3M6IGFyanVuQGNvbm5lY3Rzb2Z0LmNvbT0wRD0wQVRlbGVwaG9uZSBOby4g +OiAoMjA2KSA4ODktOTE1MC4NCi0tPV84MzAyMTE2MjM6MTA1NDQ4Njk0LS0NCgAA +AAAAAKCAMIICHzCCAYgCEQCEto07ePXf6KTBZ5qzNS8FMA0GCSqGSIb3DQEBBAUA +MIGdMREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4x +IDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNlIExldmVsMSAwHgYDVQQLExdQdWJs +aWMgUG9saWN5IEF1dGhvcml0eTErMCkGCSqGSIb3DQEJARYcY2xhc3MxLWluY2lk +ZW50QHZlcmlzaWduLmNvbTAeFw05NjA0MjIwNzQ3NThaFw05NjA1MjIwNzQ3NTha +MCYxJDAiBgkqhkiG9w0BCQEWFWFyanVuQGNvbm5lY3Rzb2Z0LmNvbTB8MA0GCSqG +SIb3DQEBAQUAA2sAMGgCYQDUZFRq4Ll6Cu0ZfINkX4YzLz3w5a/yg8m7KQj2qcw+ +hmkMGK4GANp5yGiiFUIDdGIds+uzbKcehc0C61M7rI7L25Sz/Yd4Ij7527uE/YEj +97TCvf7CAJAS3hQQoEWsq8kCAwEAATANBgkqhkiG9w0BAQQFAAOBgQCyX2wUxSSd +0Rmtt1x+VzLJkewdXImjD1eE54nwuqhAR04vOaztxXCHw2GkBafe6R+W27ndlvRO +jb/Upmgv5Y4f2PycLY3uzPg5+kJgpjc5RZ6znVJ1KKXR9gzGCe2wPuZ3V3KP8W6v +9s5g4tgoG/vS2PGl5oRfWfj46ynKK2o5vjCCAlkwggHCAgUCcgAAATANBgkqhkiG +9w0BAQIFADBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4x +IDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNlIExldmVsMB4XDTk1MTIwNzAwMDAw +MFoXDTk5MTIzMTIzNTk1OVowgZ0xETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQK +Ew5WZXJpU2lnbiwgSW5jLjEgMB4GA1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2 +ZWwxIDAeBgNVBAsTF1B1YmxpYyBQb2xpY3kgQXV0aG9yaXR5MSswKQYJKoZIhvcN +AQkBFhxjbGFzczEtaW5jaWRlbnRAdmVyaXNpZ24uY29tMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDgeHrgXvkvVB1tR47OHIdk+rxL1rAi4LR4RKd59okkrOpF +dYzwbAUWA7jBphpSD7xSsBUxiOjp5YYhRDL5zExACvdiIEDJxPqwUvmkmNXYALKa +GYWvJWsxALtk0Bpf82y0uxSmUrsdHirSGpaFleH3D2AiEsYMChQ7kpBW1vs5LQID +AQABMA0GCSqGSIb3DQEBAgUAA4GBAKROBq7wk4Ynx1DXItt4EwC6/c6RcnU2RtpE +6/uxsgtYFtaPoSUqtl/3kjovWUFEDRe+DBu6Ae3Vm3x3kklF9b9Dq9+IUIurDTqt +x30bYTcuDdfNu3V8cz9/CFNeUAHb+RAremus3s/msgDvuyo9NyzkSWUlPjsqolRP +s1S9/yC4AAChgDCCAQwwdzANBgkqhkiG9w0BAQIFADBIMQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xIDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJh +bmNlIExldmVsFw05NTEyMDcwMTA1MTBaFw05NjA0MDEwMTA0MjhaMA0GCSqGSIb3 +DQEBAgUAA4GBADABPXKyt8lQYnZLOILguT9MgQF2mCnvRpBonj38PIVscBRP/51V +oJeBwdi0OGjqpCwjnfxQvkVl6BT/SCw9PXi2nN94lINJRTl8tJ/+BeU1PH/uTiuv ++D1ouEPRA7nBD66j9xG/jy8rIKWm6MNzJL/wI0/rVrk3mMI69Y5NC9iTAAAxgDCC +ATgCAQEwgbMwgZ0xETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2ln +biwgSW5jLjEgMB4GA1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNV +BAsTF1B1YmxpYyBQb2xpY3kgQXV0aG9yaXR5MSswKQYJKoZIhvcNAQkBFhxjbGFz +czEtaW5jaWRlbnRAdmVyaXNpZ24uY29tAhEAhLaNO3j13+ikwWeaszUvBTAMBggq +hkiG9w0CAgUAMA0GCSqGSIb3DQEBAQUABGBRBSdjzGVvqmxsR9sgeJnH7p4hJS+l +j89asKncnFHeDJston9tQt05f/3zJNpQWQJfoXVzCnwlogobiaWNVvxBNKkca/cq +7adpi+h6d6T0ZD9xfIhKvRPoCRinvcjOepQAAAAAAAAAAA== + +From - Thu Dec 19 13:29:25 1996 +Return-Path: +Received: from c3po.mcom.com ([205.217.237.46]) by dredd.mcom.com + (Netscape Mail Server v2.02) with ESMTP id AAA14894 + for ; Thu, 19 Dec 1996 09:38:52 -0800 +Received: from ghoti.mcom.com (ghoti.mcom.com [207.1.147.41]) by c3po.mcom.com (8.7.5/8.7.3) with SMTP id JAA03928 for ; Thu, 19 Dec 1996 09:38:52 -0800 (PST) +Received: from ghoti (localhost [127.0.0.1]) by ghoti.mcom.com (940816.SGI.8.6.9/8.6.9) with SMTP id JAA01356 for ; Thu, 19 Dec 1996 09:38:50 -0800 +Sender: repka@netscape.com +Message-ID: <32B97DAA.167E@netscape.com> +Date: Thu, 19 Dec 1996 09:38:50 -0800 +From: Lisa Repka +Organization: Netscape Communications Corporation +X-Mailer: Mozilla 3.0 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: very cool +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" +X-Mozilla-Status: 0001 +Content-Length: 661 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgc8wgcwCAQAwdjBiMREwDwYDVQQHEwhJbnRlcm5ldDEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAyBgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0Eg +LSBJbmRpdmlkdWFsIFN1YnNjcmliZXICECkPxhf0bpqHRPlrV4jyZoQwDQYJKoZIhvcNAQEB +BQAEQF+IarhYH6F+1SG5osDdiuiaHaiW+hN1qidO1jkmzrPcW+EWBrqz8N04vexYeRd3NTYM +n1izmFc/P8+c4NxIr+gwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAhM6vSiWNR/i6CABEgn +8VTx1medvABZJ6pdJYupUc7qlYZwIY3NjElAIwlbPwpWj4lt4TXQa+Ir8djF8xmHBOLxSSIn +EQK1tgT3CAMTeDvxvlvZWhEEQHaLZbk7XHfjoMoTCviNdkmfWC/3O5vfJmFzpBYrY+9lOvFX +K5QmWq8m680kJCbu8pSxXhxQGUoBV8U6ejvSc+gEMN+GS+LzvW5K04/CtO8cM1tSRcyOmWtt +oandbdLW+XWD907ylAoiHEXoKDeMCHVNjwQIrTKsMQRLJq0ECOk1Trs4Jm6bAAAAAAAAAAAA +AA== +From - Fri Mar 7 02:51:22 1997 +Return-Path: +Received: from gruntle ([205.217.227.10]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA4040 + for ; Fri, 7 Mar 1997 02:50:37 -0800 +Sender: jwz@netscape.com (Jamie Zawinski) +Message-ID: <331FF2FF.FF6@netscape.com> +Date: Fri, 07 Mar 1997 02:50:39 -0800 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.01 (X11; U; IRIX 6.2 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: forwarded encrypted message +Content-Type: message/rfc822; name="smime18-encrypted.msg" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; filename="smime18-encrypted.msg" +X-Mozilla-Status: 0001 +Content-Length: 2812 + +>From - Fri Dec 13 15:01:21 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA19742 + for ; Fri, 13 Dec 1996 14:59:31 -0800 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23726 for ; Fri, 13 Dec 1996 14:58:13 -0800 +Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id OAA00270 for ; Fri, 13 Dec 1996 14:59:27 -0800 (PST) +Received: by peapod.deming.com from localhost + (router,SLmail V2.0); Fri, 13 Dec 1996 15:01:48 Pacific Standard Time +Received: by peapod.deming.com from seth + (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:01:02 Pacific Standard Time +Message-Id: <3.0.32.19961213150855.009172e0@mail.craswell.com> +X-Sender: blaker@mail.craswell.com +X-Mailer: Windows Eudora Pro Version 3.0 (32) +Date: Fri, 13 Dec 1996 15:09:42 -0800 +To: Jamie Zawinski +From: "Blake Ramsdell" +Subject: Re: can you send me an encrypted message? +MIME-Version: 1.0 +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAt +IEluZGl2aWR1YWwgU3Vic2NyaWJlcgIQKQ/GF/RumodE+WtXiPJmhDANBgkqhkiG9w0BAQEF +AARAb0tthyav05ce7KBWdlfN1M0R6wLQ2FWPVQynuWo/yHUoo3hiII7j15FXNgnxF7QkY5/p +mZXg0P2eJ1iYQy1vZDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5W +ZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1 +YWwgU3Vic2NyaWJlcgIQDOtpec1+JM3EpqAMVqgtjzANBgkqhkiG9w0BAQEFAARAuqnsnz1O +qEdx7NEMJDEdjccjdEuCM8x2euTYlU/GWNY+s2iKVahbT3/R8E8hp3YfrHd2sjvgy6teTOPO +ZI2SxwAAMIAGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIlhWqtbsElaWggASCAjBooYYTWSBz +7A4l0Aho7mK85zpMyAR0xTKqHXT0zL9XpHbKPAcETaBTh1n7e8aJeQ93ONGAs6tVVlA6bpUN +F3Q5O+ZuNXOMT83HIKRYEO1l8a+CH7XtUiQWtu/aBt12GQDX475WhPULKEJs7kLS2DwToRX/ +ctwEPNwc6zfsOZoVTQ5HOwisvDZ2QGwa08Psj38SaQ0Y+ryk5FeiAtKQUZ0uuJWI/rRu64yj +KmVs1DDId18coftA2rv/u2/zABEX8u5ckEkwS7fO7UHv6XMCQ3kqgqIZZE1zIGohfUdtOYYo +M4eki3QDyovHPxEjBbnmpUw2xDN7/DdxYEZ4CteWurQ+VoP0PUM2qwi6EgM6MpVKg8KzOWdb +aV51a1oQKtpJJFZqZtFf9SQ4OW6NKXHsJ2AF8W4OQ+ySWQN43wMk8dGJYlPrREqn5RufPg3k +QM+s4VwTrS2TrU+ELZCYnJFfH+N7tE8ILrFMAteVxtqjat7OJRyDxy0cnBP+oG81Sr0zvbdC +jUPUDFlrPgFjDrswX1UpkEE2OgKWmfc134AbysJFOuCIze2XqKB96rJvxS76ygzVvrU/4sI1 +6VDlZUEuUPaBUOimFxRk/rqPJDI1M8rNKykw9qsoWQMRnvrODfzo7iVWQ0TQHiwfoBhs6Dvm +UgrMwopFnzRdSHvT1acSqVfMYWm5nXImvtCuFAavkjDutE9+Y/LLFLBUpAVeu3rwW3wV0Tcv +9I6Afej0ntfbH9vlRwQIl7MeXMqoBV0AAAAAAAAAAAAA + +From - Fri Mar 7 02:51:23 1997 +Return-Path: +Received: from gruntle ([205.217.227.10]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA4104 + for ; Fri, 7 Mar 1997 02:51:05 -0800 +Sender: jwz@netscape.com (Jamie Zawinski) +Message-ID: <331FF31B.ABD@netscape.com> +Date: Fri, 07 Mar 1997 02:51:07 -0800 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.01 (X11; U; IRIX 6.2 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: forwarded encrypted message (mult/mixed) +Content-Type: multipart/mixed; boundary="------------31DF237C2F1C" +X-Mozilla-Status: 0001 +Content-Length: 3188 + +This is a multi-part message in MIME format. + +--------------31DF237C2F1C +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +blah blah blah + +--------------31DF237C2F1C +Content-Type: message/rfc822; name="smime18-encrypted.msg" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; filename="smime18-encrypted.msg" + +>From - Fri Dec 13 15:01:21 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA19742 + for ; Fri, 13 Dec 1996 14:59:31 -0800 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23726 for ; Fri, 13 Dec 1996 14:58:13 -0800 +Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id OAA00270 for ; Fri, 13 Dec 1996 14:59:27 -0800 (PST) +Received: by peapod.deming.com from localhost + (router,SLmail V2.0); Fri, 13 Dec 1996 15:01:48 Pacific Standard Time +Received: by peapod.deming.com from seth + (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:01:02 Pacific Standard Time +Message-Id: <3.0.32.19961213150855.009172e0@mail.craswell.com> +X-Sender: blaker@mail.craswell.com +X-Mailer: Windows Eudora Pro Version 3.0 (32) +Date: Fri, 13 Dec 1996 15:09:42 -0800 +To: Jamie Zawinski +From: "Blake Ramsdell" +Subject: Re: can you send me an encrypted message? +MIME-Version: 1.0 +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcw +FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAt +IEluZGl2aWR1YWwgU3Vic2NyaWJlcgIQKQ/GF/RumodE+WtXiPJmhDANBgkqhkiG9w0BAQEF +AARAb0tthyav05ce7KBWdlfN1M0R6wLQ2FWPVQynuWo/yHUoo3hiII7j15FXNgnxF7QkY5/p +mZXg0P2eJ1iYQy1vZDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5W +ZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1 +YWwgU3Vic2NyaWJlcgIQDOtpec1+JM3EpqAMVqgtjzANBgkqhkiG9w0BAQEFAARAuqnsnz1O +qEdx7NEMJDEdjccjdEuCM8x2euTYlU/GWNY+s2iKVahbT3/R8E8hp3YfrHd2sjvgy6teTOPO +ZI2SxwAAMIAGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIlhWqtbsElaWggASCAjBooYYTWSBz +7A4l0Aho7mK85zpMyAR0xTKqHXT0zL9XpHbKPAcETaBTh1n7e8aJeQ93ONGAs6tVVlA6bpUN +F3Q5O+ZuNXOMT83HIKRYEO1l8a+CH7XtUiQWtu/aBt12GQDX475WhPULKEJs7kLS2DwToRX/ +ctwEPNwc6zfsOZoVTQ5HOwisvDZ2QGwa08Psj38SaQ0Y+ryk5FeiAtKQUZ0uuJWI/rRu64yj +KmVs1DDId18coftA2rv/u2/zABEX8u5ckEkwS7fO7UHv6XMCQ3kqgqIZZE1zIGohfUdtOYYo +M4eki3QDyovHPxEjBbnmpUw2xDN7/DdxYEZ4CteWurQ+VoP0PUM2qwi6EgM6MpVKg8KzOWdb +aV51a1oQKtpJJFZqZtFf9SQ4OW6NKXHsJ2AF8W4OQ+ySWQN43wMk8dGJYlPrREqn5RufPg3k +QM+s4VwTrS2TrU+ELZCYnJFfH+N7tE8ILrFMAteVxtqjat7OJRyDxy0cnBP+oG81Sr0zvbdC +jUPUDFlrPgFjDrswX1UpkEE2OgKWmfc134AbysJFOuCIze2XqKB96rJvxS76ygzVvrU/4sI1 +6VDlZUEuUPaBUOimFxRk/rqPJDI1M8rNKykw9qsoWQMRnvrODfzo7iVWQ0TQHiwfoBhs6Dvm +UgrMwopFnzRdSHvT1acSqVfMYWm5nXImvtCuFAavkjDutE9+Y/LLFLBUpAVeu3rwW3wV0Tcv +9I6Afej0ntfbH9vlRwQIl7MeXMqoBV0AAAAAAAAAAAAA + +--------------31DF237C2F1C-- + +From - Mon Mar 17 17:19:30 1997 +Return-Path: +Received: from ghoti ([207.1.147.41]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA8103 + for ; Mon, 17 Mar 1997 17:17:40 -0800 +Sender: dhugo@netscape.com (Dan Hugo) +Message-ID: <332DED2F.F5365D61@netscape.com> +Date: Mon, 17 Mar 1997 17:17:35 -0800 +From: Dan Hugo +X-Mailer: Mozilla 3.01 (X11; I; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: jwz@netscape.com +Subject: This is signed +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="------------ms088B4AC60B9FCF022C11E60D" +X-Mozilla-Status: 0001 +Content-Length: 6011 + +This is a cryptographically signed message in MIME format. + +--------------ms088B4AC60B9FCF022C11E60D +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +I signed this. It is signed by me. +-dh +--------------ms088B4AC60B9FCF022C11E60D +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIQCAYJKoZIhvcNAQcCoIIP+TCCD/UCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC +DrQwggn+MIIJZ6ADAgECAhBEnTH5Krg91zfWumiMpAYPMA0GCSqGSIb3DQEBBAUAMGIxETAP +BgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVy +aVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjAeFw05NzAxMjUwMDAw +MDBaFw05ODAxMjUyMzU5NTlaMIIBCzERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZl +cmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVh +bCBTdWJzY3JpYmVyMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BT +IEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk2MSYwJAYDVQQLEx1EaWdpdGFsIElEIENs +YXNzIDEgLSBOZXRzY2FwZTEUMBIGA1UEAxMLRGFuaWVsIEh1Z28xITAfBgkqhkiG9w0BCQEW +EmRodWdvQG5ldHNjYXBlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8k7aIi84 +a6+2Hy9re4TTL31jxpQgxnHi7Hf7ynIhcSaHo67XWuocRHsOq4A4JpklPACe1QquvVU9QSXy ++mVCW3oRFcaeXwIde5ImxbvO9H1Z8zCuii9r4Cq7zL9sTZDnIYhlSfqdkuLzoFlbZTauZil5 +MJmO3FJpD05C/tu/kH0CAwEAAaOCBwgwggcEMAkGA1UdEwQCMAAwggIfBgNVHQMEggIWMIIC +EjCCAg4wggIKBgtghkgBhvhFAQcBATCCAfkWggGnVGhpcyBjZXJ0aWZpY2F0ZSBpbmNvcnBv +cmF0ZXMgYnkgcmVmZXJlbmNlLCBhbmQgaXRzIHVzZSBpcyBzdHJpY3RseSBzdWJqZWN0IHRv +LCB0aGUgVmVyaVNpZ24gQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgKENQUyks +IGF2YWlsYWJsZSBhdDogaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL0NQUzsgYnkgRS1tYWls +IGF0IENQUy1yZXF1ZXN0c0B2ZXJpc2lnbi5jb207IG9yIGJ5IG1haWwgYXQgVmVyaVNpZ24s +IEluYy4sIDI1OTMgQ29hc3QgQXZlLiwgTW91bnRhaW4gVmlldywgQ0EgOTQwNDMgVVNBIFRl +bC4gKzEgKDQxNSkgOTYxLTg4MzAgQ29weXJpZ2h0IChjKSAxOTk2IFZlcmlTaWduLCBJbmMu +ICBBbGwgUmlnaHRzIFJlc2VydmVkLiBDRVJUQUlOIFdBUlJBTlRJRVMgRElTQ0xBSU1FRCBh +bmQgTElBQklMSVRZIExJTUlURUQuoA4GDGCGSAGG+EUBBwEBAaEOBgxghkgBhvhFAQcBAQIw +LDAqFihodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9DUFMgMBEGCWCGSAGG ++EIBAQQEAwIHgDA2BglghkgBhvhCAQgEKRYnaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3Jl +cG9zaXRvcnkvQ1BTMIIEhwYJYIZIAYb4QgENBIIEeBaCBHRDQVVUSU9OOiBUaGUgQ29tbW9u +IE5hbWUgaW4gdGhpcyBDbGFzcyAxIERpZ2l0YWwgCklEIGlzIG5vdCBhdXRoZW50aWNhdGVk +IGJ5IFZlcmlTaWduLiBJdCBtYXkgYmUgdGhlCmhvbGRlcidzIHJlYWwgbmFtZSBvciBhbiBh +bGlhcy4gVmVyaVNpZ24gZG9lcyBhdXRoLQplbnRpY2F0ZSB0aGUgZS1tYWlsIGFkZHJlc3Mg +b2YgdGhlIGhvbGRlci4KClRoaXMgY2VydGlmaWNhdGUgaW5jb3Jwb3JhdGVzIGJ5IHJlZmVy +ZW5jZSwgYW5kIAppdHMgdXNlIGlzIHN0cmljdGx5IHN1YmplY3QgdG8sIHRoZSBWZXJpU2ln +biAKQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgKENQUyksIGF2YWlsYWJsZQpp +biB0aGUgVmVyaVNpZ24gcmVwb3NpdG9yeSBhdDogCmh0dHBzOi8vd3d3LnZlcmlzaWduLmNv +bTsgYnkgRS1tYWlsIGF0CkNQUy1yZXF1ZXN0c0B2ZXJpc2lnbi5jb207IG9yIGJ5IG1haWwg +YXQgVmVyaVNpZ24sCkluYy4sIDI1OTMgQ29hc3QgQXZlLiwgTW91bnRhaW4gVmlldywgQ0Eg +OTQwNDMgVVNBCgpDb3B5cmlnaHQgKGMpMTk5NiBWZXJpU2lnbiwgSW5jLiAgQWxsIFJpZ2h0 +cyAKUmVzZXJ2ZWQuIENFUlRBSU4gV0FSUkFOVElFUyBESVNDTEFJTUVEIEFORCAKTElBQklM +SVRZIExJTUlURUQuCgpXQVJOSU5HOiBUSEUgVVNFIE9GIFRISVMgQ0VSVElGSUNBVEUgSVMg +U1RSSUNUTFkKU1VCSkVDVCBUTyBUSEUgVkVSSVNJR04gQ0VSVElGSUNBVElPTiBQUkFDVElD +RQpTVEFURU1FTlQuICBUSEUgSVNTVUlORyBBVVRIT1JJVFkgRElTQ0xBSU1TIENFUlRBSU4K +SU1QTElFRCBBTkQgRVhQUkVTUyBXQVJSQU5USUVTLCBJTkNMVURJTkcgV0FSUkFOVElFUwpP +RiBNRVJDSEFOVEFCSUxJVFkgT1IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSClBVUlBPU0Us +IEFORCBXSUxMIE5PVCBCRSBMSUFCTEUgRk9SIENPTlNFUVVFTlRJQUwsClBVTklUSVZFLCBB +TkQgQ0VSVEFJTiBPVEhFUiBEQU1BR0VTLiBTRUUgVEhFIENQUwpGT1IgREVUQUlMUy4KCkNv +bnRlbnRzIG9mIHRoZSBWZXJpU2lnbiByZWdpc3RlcmVkCm5vbnZlcmlmaWVkU3ViamVjdEF0 +dHJpYnV0ZXMgZXh0ZW5zaW9uIHZhbHVlIHNoYWxsIApub3QgYmUgY29uc2lkZXJlZCBhcyBh +Y2N1cmF0ZSBpbmZvcm1hdGlvbiB2YWxpZGF0ZWQgCmJ5IHRoZSBJQS4wDQYJKoZIhvcNAQEE +BQADgYEAafEe3g7HCyRq7u5/2gW1vL0IA7zbvuVcbTwpRc5LPldwYew29BW2qdy9IRTMHdMK +374ei4ortgDuhLVZUh9y5ov3s9tyqW41SlCVdjbJZcJE+2770LQ9SWhAVKuc35tN8uGgsIzH +D3B+bLcknQRZaoiWOo7SB7f3fZ2Na211nvIwggJ5MIIB4qADAgECAhA1EaVSkG/n0CmkQBnU +Efw+MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg +SW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw05NjA2MjcwMDAwMDBaFw05NzA2MjcyMzU5NTlaMGIxETAPBgNVBAcTCElu +dGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xh +c3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAthSmz03QBQ3YyiPQb6q0KZJjjiz4b5bXLp12SxGxNo1XycP9HMa6/h4IujPKleq+ +41vNBqi3eR1EKu1z8rFSg2gQcGSR1z5r+fddnRRDm26XRZiBR9Ety927ctdMP3Gq4kDyVDm8 +Fu7PfOy62z9sKrMWsYYSna6TNNW41dD3PqkCAwEAAaMzMDEwDwYDVR0TBAgwBgEB/wIBATAL +BgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBAgUAA4GBACnlx6AZ +p28UQoJNIzPXvZg6aXcabIqSJ2vyfAzhxFLg+JzjQK+PsToO90gZdNup+wZOeQNsLwDBqO/p +Ck2fqx2hQw3JquDvq8xa4tkSDnhgJ3I9SHBqbQEIb16CIRTBuCZc4NSpR2R6suw943se/M3E +lO5CjrvH+bQF9Ywt/rE6MIICMTCCAZoCBQKkAAABMA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJs +aWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NjAxMjkwMDAwMDBaFw05 +OTEyMzEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3 +MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO ++jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A0 +1480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEA +ATANBgkqhkiG9w0BAQIFAAOBgQBSc7qaVdzcP4J9sJCYYiqCTHYAbiU91cIJcFcBDA93Hxih ++xxgDqB1O0khQf6nXC1MQknT/yjYjOqd/skH4neCUyPeVfPORJP6+ky9yjbzW2aynsjyDF5e +1KG0IQkzyjtZ/JLCOPyt2ZYk4C36oyn1M2h4TrS8n2k14qiYlHM7xDGCARwwggEYAgEBMHYw +YjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTQwMgYDVQQL +EytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJzY3JpYmVyAhBEnTH5Krg9 +1zfWumiMpAYPMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYDqCaQ0zitIwVu7QLC3skxR +fl/Jn7sKSzC4SqeVMjm/JzeLLO8Edh0aZ73KJ9z/fdLXbyOKQ9kLUWzcdDv74K6S3RhPxCS5 +VcdCcp0/93l8Y3g/culxQqsxSK7tZKnPGYKHB6br6gC8VkFST+QjjhLTKGaS01WfhCzChTxY +xIre5A== +--------------ms088B4AC60B9FCF022C11E60D-- + +From - Mon Mar 24 00:03:37 1997 +Return-Path: +Received: from r2d2.mcom.com ([205.217.237.47]) by dredd.mcom.com + (Netscape Mail Server v2.02) with ESMTP id AAA14844; + Sun, 23 Mar 1997 23:12:07 -0800 +Received: from ghoti.mcom.com (ghoti.mcom.com [207.1.147.41]) by r2d2.mcom.com (8.7.5/8.7.3) with SMTP id XAA00404; Sun, 23 Mar 1997 23:12:06 -0800 (PST) +Received: from ghoti (localhost [127.0.0.1]) by ghoti.mcom.com (950413.SGI.8.6.12/8.6.9) with SMTP id XAA13656; Sun, 23 Mar 1997 23:12:06 -0800 +Sender: repka@netscape.com +Message-ID: <3336293C.1A98A9A9@netscape.com> +Date: Sun, 23 Mar 1997 23:11:56 -0800 +From: Lisa Repka +Organization: Netscape Communications Corporation +X-Mailer: Mozilla 3.01 (X11; I; IRIX 6.2 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski , Dan Hugo +Subject: testing out some new stuff +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" +X-Mozilla-Status: 0005 +Content-Length: 10236 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxggKvMIHMAgEAMHYwYjERMA8GA1UEBxMISW50ZXJuZXQx +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENB +IC0gSW5kaXZpZHVhbCBTdWJzY3JpYmVyAhBJCr3PVq/yL4EWb0iQtudmMA0GCSqGSIb3DQEB +AQUABECABA21ckYboqGsrycHuLFd2lAykH5zc0qn2lrVq+7z8ot6rrgBgo4ZXVXcqgJbeBIA +ndACq/1yn+cm1zTNJsDMMIHMAgEAMHYwYjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoT +DlZlcmlTaWduLCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZp +ZHVhbCBTdWJzY3JpYmVyAhApD8YX9G6ah0T5a1eI8maEMA0GCSqGSIb3DQEBAQUABECZVZtV +60EG17f8dx18Ko3HVPUDYtUatvbgUwVvppkznNYk6Dq6xhTXPcbB9QG+QLI4PzlG4UWoHa4L +8JPNbE0uMIIBDQIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2ln +biwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vi +c2NyaWJlcgIQRJ0x+Sq4Pdc31rpojKQGDzANBgkqhkiG9w0BAQEFAASBgM6NLcwNenBhPom8 +Jqc2Hg587jtyWmQWU0BG6JvTXWsWvTh+iMgpW18q/xp8bloIU2CHr+eaD0wwMb8jniznJAPt +UoiJ8AzQ+6N44sUtMaPct/9pb3xymN9f+S/HHPO39Hp9WeaLsibbBoFQJcjJX6ChFuTxDTiU +08p2hJYIm1etMIAGCSqGSIb3DQEHATAZBggqhkiG9w0DAjANAgGgBAjLe3IQq8c3gKCABIGw +XRuUTIR75iyUJzG6HY6754iofKee7cidFqsuY/qKl47opuUaat7QaJtYck+sQb3TFucwBbdu +vn1Nf/NG6akGKZQd52ndUBsrpK3Vf+taqbwXHaP54iHRinpSAcGbOO/s8z3C01qDlKNBsI3o +hRHvOliAmyGRonWvyxi1Iv61BJ7jwe5pwb3iHoveiPOc74jJFcOC7jauckqQsbGl7YebNv1v +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 +GgAAAAAAAAAAAAA= +From - Tue Apr 15 10:42:13 1997 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.02) with SMTP id AAA10068 + for ; Tue, 15 Apr 1997 05:06:21 -0700 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id FAA02788 for ; Tue, 15 Apr 1997 05:04:58 -0700 +Received: from alpha.iipo.ayce.com (iipo.ayce.com [204.176.152.40]) by xwing.netscape.com (8.7.6/8.7.3) with ESMTP id FAA14103 for ; Tue, 15 Apr 1997 05:06:19 -0700 (PDT) +Received: from dan.IIPO.AYCE.COM ([192.168.169.131]) by alpha.iipo.ayce.com + (Netscape Mail Server v1.1) with ESMTP id AAA192 + for ; Tue, 15 Apr 1997 08:14:19 -0400 +Message-ID: <33536F24.BBDEA09D@ayce.com> +Date: Tue, 15 Apr 1997 08:05:56 -0400 +From: danw@ayce.com (Dan Werbel) +Reply-To: danw@ayce.com +Organization: ayce +X-Mailer: Mozilla 4.0b3 [en] (Win95; I) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: Re: Obtaining other people's certificates +X-Priority: 3 (Normal) +References: <33522A52.3AC8BA5A@ayce.com> <3352D2BC.94342FC7@netscape.com> +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="------------ms1FB3ACBABA2E8DEE155566A8" +X-Mozilla-Status: 0015 +Content-Length: 2813 + +This is a cryptographically signed message in MIME format. + +--------------ms1FB3ACBABA2E8DEE155566A8 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +Jamie - + +I tried to sign and encrypt this message, but when I did I received the +following error: + +The certificate issuer for this server is not recognized by Netscape. +The security certificate may or may not be valid. Netscape refuses to +connect to this server. + +I also got this error when I tried only to encrypt the message. However +with digital signing it seems to work ok. From the error message, I +don't know whether the server in error is my mail server, certificate +server, or a server on your end. Our mail server is Netscape mail +server v1.1 and Certificate Server 1.0. + +Thanks for the help, +Dan +--------------ms1FB3ACBABA2E8DEE155566A8 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIFJQYJKoZIhvcNAQcCoIIFFjCCBRICAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC +BDswggHUMIIBPaADAgECAgEGMA0GCSqGSIb3DQEBBAUAMEoxCzAJBgNVBAYTAlVTMQ8wDQYD +VQQKEwZDYXNpbm8xDTALBgNVBAsTBElJUE8xGzAZBgNVBAMTEmNlcnQuaWlwby5heWNlLmNv +bTAeFw05NzA0MTExODMxMjdaFw05OTA0MTExODMxMjdaMCIxCzAJBgNVBAYTAlVTMRMwEQYD +VQQDEwpEYW4gV2VyYmVsMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAORuX/pu2WBZsRVEAo8a +gDsFIDMuMSSfHjumCcBIweDYJPIxfOA3df6LHiWm7mHo05xJQMYrikpV0cdTt2w8aKMCAwEA +AaM2MDQwEQYJYIZIAYb4QgEBBAQDAgCgMB8GA1UdIwQYMBaAFO+SFAaztmWl3qWbjuSr0z+7 +3YQzMA0GCSqGSIb3DQEBBAUAA4GBAJY7LQc/x7QaPVllkWjLCgn48g/ofjPmpYhVau84uNoc +2uxjxkk7nt7KVHD+JR5q22hZGE3FjDOVX1hf1Brv1ND/TrSNWNqksTPnLhJrksB4jr1nyWdk +cDdiwAwg/JV6hxDSotWEyQQxuXZcc2/8Uql0MayeQoCfnBddsRJJBCsaMIICXzCCAcigAwIB +AgIBATANBgkqhkiG9w0BAQQFADBKMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQ2FzaW5vMQ0w +CwYDVQQLEwRJSVBPMRswGQYDVQQDExJjZXJ0LmlpcG8uYXljZS5jb20wHhcNOTcwNDExMTc1 +ODE0WhcNOTkwNDExMTc1ODE0WjBKMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQ2FzaW5vMQ0w +CwYDVQQLEwRJSVBPMRswGQYDVQQDExJjZXJ0LmlpcG8uYXljZS5jb20wgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAN5RErUTfKDv1dNb5N6aFM8udyzuG1FfJ1pTGdN1ifsbhBsdDrX4 +h4t/ttLoL5oxs0giyWewmfnCBYJaszX/B8LYdbN7uZ/NYbVTQEj/+tP6cfUVt9BUm6kj+hep +YOXjNYHpyVHhORPXIDpLcIdi9ocSu8Y0bZpc3KChX3JEAehhAgMBAAGjVTBTMBEGCWCGSAGG ++EIBAQQEAwIABDAdBgNVHQ4EFgQU75IUBrO2ZaXepZuO5KvTP7vdhDMwHwYDVR0jBBgwFoAU +75IUBrO2ZaXepZuO5KvTP7vdhDMwDQYJKoZIhvcNAQEEBQADgYEAmyjzwo6RbPwY4nNrDU+a +bv0/Qai2GJuapSuiG5cnGG7xF1Lm1aiwmU6NVuoW8QyrQSvh80zNdSQIwjnxqws6NDrAg1VG +fwpkz2hCBZmpvfie2GedLO/19gO9Myahwr7BsjjAeCJhX+s9iJIWMcLB1auoc8EAq69RsqI1 +ftgNKqYxgbMwgbACAQEwTzBKMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQ2FzaW5vMQ0wCwYD +VQQLEwRJSVBPMRswGQYDVQQDExJjZXJ0LmlpcG8uYXljZS5jb20CAQYwCQYFKw4DAhoFADAN +BgkqhkiG9w0BAQEFAARANKYYXgGR1/JsdTBBpDKE2QSSCiOKnZI1oGAXbyhUlpzXcjevB9J6 +gI03JZ6QJOTp0t2YNPnNtxaIp0YVe2TC/g== +--------------ms1FB3ACBABA2E8DEE155566A8-- + +From - Wed Apr 16 16:57:13 1997 +Message-ID: <33556759.E69CC032@netscape.com> +Date: Wed, 16 Apr 1997 16:57:13 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.02 (X11; U; IRIX 6.2 IP22) +MIME-Version: 1.0 +To: Jamie Zawinski +Subject: encrypted +Content-Type: application/x-pkcs7-mime; name="smime.p7m" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7m" +Content-Description: S/MIME Encrypted Message +X-Mozilla-Status: 0001 +Content-Length: 523 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgc8wgcwCAQAwdjBiMREwDwYDVQQHEwhJbnRlcm5ldDEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAyBgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0Eg +LSBJbmRpdmlkdWFsIFN1YnNjcmliZXICECkPxhf0bpqHRPlrV4jyZoQwDQYJKoZIhvcNAQEB +BQAEQDGfrTzHvgPxsduymPX79aaqV2xKfsutMaqQW+LErXBDwkimBbTq49Id8vycP6SEp6vF +l5J5qda2KFCYUYXgQd0wgAYJKoZIhvcNAQcBMBoGCCqGSIb3DQMCMA4CAgCgBAjJN/R93qHp +TaCABEhb2+WRZ2GsIJzegOQzvmq+gwTH2LyDUgonylLXvlWLDYSTMseqErwpgYqxgfo5uapd +Wn6AtC5HgA5ZAbKAZhRA4Xm8fsZOdc8EEJYfdDGBEbAnDJ7VYP23fyQECB/zPDnCSWqoAAAA +AAAAAAAAAA== +From - Sun Apr 28 13:05:40 1996 +Return-Path: BlakeR@deming.com +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id BAA29432; Sat, 27 Apr 1996 01:15:23 -0700 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id BAA19974; Sat, 27 Apr 1996 01:14:30 -0700 +Received: from RSA.COM (RSA.COM [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id BAA24941; Sat, 27 Apr 1996 01:13:37 -0700 (PDT) +Received: from pain.deming.com by RSA.COM with SMTP + id AA10376; Sat, 27 Apr 96 01:08:51 PDT +Received: by pain.deming.com with Microsoft Exchange (IMC 4.0.838.14) + id <01BB33D6.1DC9C140@pain.deming.com>; Sat, 27 Apr 1996 01:08:59 -0700 +Message-Id: +From: Blake Ramsdell +To: "'smime-dev@rsa.com'" +Subject: Deming Software -- ready to go! +Date: Sat, 27 Apr 1996 01:08:58 -0700 +X-Mailer: Microsoft Exchange Server Internet Mail Connector Version 4.0.838.14 +Mime-Version: 1.0 +Content-Type: application/x-pkcs7-mime; name="deming.p7m" +Content-Transfer-Encoding: base64 +X-Mozilla-Status: 0005 +Content-Length: 2882 + +MIAGCSqGSIb3DQEHAqCAMIACAQExDjAMBggqhkiG9w0CBQUAMIAGCSqGSIb3DQEHAaCAJIAEggFo +Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQpDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0 +DQpDb250ZW50LURpc3Bvc2l0aW9uOiBpbmxpbmUNCg0KVGhpcyBzaWduZWQgbWVzc2FnZSBpcyBE +ZW1pbmcgU29mdHdhcmUncyBpbmRpY2F0aW9uIG9mIGludGVyb3BlcmFiaWxpdHkNCiByZWFkaW5l +c3MuICBJIHdpbGwgYmUgaW4gY29udGFjdCB3aXRoIEFyanVuIGFuZCBSYXBoIHRvIGNvbXBsZXRl +IHRoZSANCm5leHQgcGhhc2Ugb2YgdGVzdGluZy4NCg0KTGV0J3Mga2VlcCBnb2luZyENCg0KQmxh +a2UNCi0tDQpCbGFrZSBDLiBSYW1zZGVsbA0KREVNSU5HIFNPRlRXQVJFLCBJTkMuDQo8aHR0cDov +L3d3dy5kZW1pbmcuY29tPg0KAAAAAAAAoIAwggIOMIIBdwIRAJZvpuhJTTXlMBB+6Wgpi9YwDQYJ +KoZIhvcNAQEEBQAwgZ0xETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j +LjEgMB4GA1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNVBAsTF1B1YmxpYyBQb2xp +Y3kgQXV0aG9yaXR5MSswKQYJKoZIhvcNAQkBFhxjbGFzczEtaW5jaWRlbnRAdmVyaXNpZ24uY29t +MB4XDTk2MDQyMzIzMzQzMVoXDTk2MDUyMzIzMzQzMVowNTERMA8GA1UEBxMISW50ZXJuZXQxIDAe +BgkqhkiG9w0BCQEWEUJsYWtlUkBkZW1pbmcuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAK5p +EHTIgBq3KMigUfgzLAd8p62GRu7DhRWlTRV4XzOzd54zZrLPdcBD6Awhize3McsBzfFg3Ksf0X6N +4YmffhUCAwEAATANBgkqhkiG9w0BAQQFAAOBgQDL2WVV2T068o+gQiVXWKpyJkDFL7Vscj5i12Jp +H8BSUZHzrWTeMTKcMPZIxXc+Tc7P6BLatWRaJ1Fn/j6uX1Gmw+CYA7ba8FKO1GdIjWQMQ8oD6Bqu +3zHyhEdGDHp7Ac2zzrlP9kk7y+y6sAwRp0GYu0IBbZUxynT+0Ajjo5W+yTCCAlkwggHCAgUCcgAA +ATANBgkqhkiG9w0BAQIFADBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4x +IDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNlIExldmVsMB4XDTk1MTIwNzAwMDAwMFoXDTk5MTIz +MTIzNTk1OVowgZ0xETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEg +MB4GA1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNVBAsTF1B1YmxpYyBQb2xpY3kg +QXV0aG9yaXR5MSswKQYJKoZIhvcNAQkBFhxjbGFzczEtaW5jaWRlbnRAdmVyaXNpZ24uY29tMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgeHrgXvkvVB1tR47OHIdk+rxL1rAi4LR4RKd59okk +rOpFdYzwbAUWA7jBphpSD7xSsBUxiOjp5YYhRDL5zExACvdiIEDJxPqwUvmkmNXYALKaGYWvJWsx +ALtk0Bpf82y0uxSmUrsdHirSGpaFleH3D2AiEsYMChQ7kpBW1vs5LQIDAQABMA0GCSqGSIb3DQEB +AgUAA4GBAKROBq7wk4Ynx1DXItt4EwC6/c6RcnU2RtpE6/uxsgtYFtaPoSUqtl/3kjovWUFEDRe+ +DBu6Ae3Vm3x3kklF9b9Dq9+IUIurDTqtx30bYTcuDdfNu3V8cz9/CFNeUAHb+RAremus3s/msgDv +uyo9NyzkSWUlPjsqolRPs1S9/yC4AAChgDCCAQwwdzANBgkqhkiG9w0BAQIFADBIMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xIDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNl +IExldmVsFw05NTEyMDcwMTA1MTBaFw05NjA0MDEwMTA0MjhaMA0GCSqGSIb3DQEBAgUAA4GBADAB +PXKyt8lQYnZLOILguT9MgQF2mCnvRpBonj38PIVscBRP/51VoJeBwdi0OGjqpCwjnfxQvkVl6BT/ +SCw9PXi2nN94lINJRTl8tJ/+BeU1PH/uTiuv+D1ouEPRA7nBD66j9xG/jy8rIKWm6MNzJL/wI0/r +Vrk3mMI69Y5NC9iTAAAxgDCCARgCAQEwgbMwgZ0xETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQK +Ew5WZXJpU2lnbiwgSW5jLjEgMB4GA1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNV +BAsTF1B1YmxpYyBQb2xpY3kgQXV0aG9yaXR5MSswKQYJKoZIhvcNAQkBFhxjbGFzczEtaW5jaWRl +bnRAdmVyaXNpZ24uY29tAhEAlm+m6ElNNeUwEH7paCmL1jAMBggqhkiG9w0CBQUAMA0GCSqGSIb3 +DQEBAQUABEAsnhQPeX87vT74Wac98iTe8Mhh1ZH2VbNtGPbJ24RVlSR56SPvsYB0FdrvmI4XfMqS +gYc5R346K3Oms8eL1do6AAAAAAAAAAA= + +From - Tue May 28 11:02:16 1996 +Return-Path: ray2@FrontierTech.com +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id KAA06913; Tue, 28 May 1996 10:39:26 -0700 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id KAA21382; Wed, 29 May 1996 10:39:17 -0700 +Received: from RSA.COM (RSA.COM [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id KAA04507; Tue, 28 May 1996 10:38:18 -0700 (PDT) +Received: from ns.frontiertech.com by RSA.COM with SMTP + id AA17193; Tue, 28 May 96 10:23:33 PDT +Received: by FrontierTech.COM (8.6.9/8.6.9) with SMTP id MAA17555 for ; Tue, 28 May 1996 12:26:15 -0500 +X-Mailer: SuperTCP Suite for Windows Version 2.1 (Mailer Version 1.02) +Message-Id: <31AB36CC-00000001@rock106.FrontierTech.com> +X-UIDL: 833305231.000 +From: Ray2@FrontierTech.com +Mime-Version: 1.0 +Content-Type: Application/x-pkcs7-mime +Content-Transfer-Encoding: Base64 +Date: Tue, 28 May 1996 12:24:23 cst +Subject: Frontier Technologies testing, here's my cert +To: smime-dev@RSA.COM +Status: U +X-Mozilla-Status: 0001 +Content-Length: 2122 + +MIAGCSqGSIb3DQEHAqCAMIACAQExDjAMBggqhkiG9w0CBQUAMIAGCSqGSIb3DQEHAaCAJIAE +Q01JTUUtVmVyc2lvbjogMS4wDQpDb250ZW50LVR5cGU6IFRleHQvUGxhaW47IENoYXJzZXQ9 +VVMtQVNDSUkNCg0KDQoAAAAAAACggDCCAhIwggF7AhEA62zEiHHV7taXo1K3a9lK6TANBgkq +hkiG9w0BAQQFADCBnTERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWduLCBJ +bmMuMSAwHgYDVQQLExdDbGFzcyAxIEFzc3VyYW5jZSBMZXZlbDEgMB4GA1UECxMXUHVibGlj +IFBvbGljeSBBdXRob3JpdHkxKzApBgkqhkiG9w0BCQEWHGNsYXNzMS1pbmNpZGVudEB2ZXJp +c2lnbi5jb20wHhcNOTYwNTEzMjAxOTM0WhcNOTYwNjEyMjAxOTM0WjA5MREwDwYDVQQHEwhJ +bnRlcm5ldDEkMCIGCSqGSIb3DQEJARYVUmF5MkBGcm9udGllclRlY2guQ09NMFwwDQYJKoZI +hvcNAQEBBQADSwAwSAJBAMy8QcW7RMrB4sTdQ8Nmb2DFmJmkWn+el+NdeamIDElX/qw9mIQu +4xNj1FfepfJNxzPvA0OtMKhy6+bkrlyMEU8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQBb9yc/ +VQmdwBImTtAaHTC1HGpXz96VywBjKpeWlx9ZDh8aGCYVeTKgTveTryOkxsA5YFLBmaE/dE6y +oCC9g0rvQSCdkeMzzrU/vzb8MAR3mUVYpq27GWyGscSis3OxT0mZp/sYEWn47n+XT5ViIku/ +UNAdN1jBH0+d9eIUs+IoWTCCAlkwggHCAgUCcgAAATANBgkqhkiG9w0BAQIFADBIMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xIDAeBgNVBAsTF0NsYXNzIDEgQXNz +dXJhbmNlIExldmVsMB4XDTk1MTIwNzAwMDAwMFoXDTk5MTIzMTIzNTk1OVowgZ0xETAPBgNV +BAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEgMB4GA1UECxMXQ2xhc3Mg +MSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNVBAsTF1B1YmxpYyBQb2xpY3kgQXV0aG9yaXR5MSsw +KQYJKoZIhvcNAQkBFhxjbGFzczEtaW5jaWRlbnRAdmVyaXNpZ24uY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDgeHrgXvkvVB1tR47OHIdk+rxL1rAi4LR4RKd59okkrOpFdYzw +bAUWA7jBphpSD7xSsBUxiOjp5YYhRDL5zExACvdiIEDJxPqwUvmkmNXYALKaGYWvJWsxALtk +0Bpf82y0uxSmUrsdHirSGpaFleH3D2AiEsYMChQ7kpBW1vs5LQIDAQABMA0GCSqGSIb3DQEB +AgUAA4GBAKROBq7wk4Ynx1DXItt4EwC6/c6RcnU2RtpE6/uxsgtYFtaPoSUqtl/3kjovWUFE +DRe+DBu6Ae3Vm3x3kklF9b9Dq9+IUIurDTqtx30bYTcuDdfNu3V8cz9/CFNeUAHb+RAremus +3s/msgDvuyo9NyzkSWUlPjsqolRPs1S9/yC4AAChgAAAMYAwggEYAgEBMIGzMIGdMREwDwYD +VQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xIDAeBgNVBAsTF0NsYXNz +IDEgQXNzdXJhbmNlIExldmVsMSAwHgYDVQQLExdQdWJsaWMgUG9saWN5IEF1dGhvcml0eTEr +MCkGCSqGSIb3DQEJARYcY2xhc3MxLWluY2lkZW50QHZlcmlzaWduLmNvbQIRAOtsxIhx1e7W +l6NSt2vZSukwDAYIKoZIhvcNAgUFADANBgkqhkiG9w0BAQEFAARARYPUJhkJG0zOTHUnRt3p +uWaGVnIgJrjtLTOfi/W/0CaGYEhNhsLLiQ7EbVkF8S/cDjsxywND2YjvdTh9/hNsMwAAAAAA +AAAA + +From - Mon Jun 10 11:45:25 1996 +Return-Path: owner-smime-dev@RSA.COM +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.6.12/8.6.9) with ESMTP id LAA06225; Mon, 10 Jun 1996 11:39:15 -0700 +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id LAA29912; Mon, 10 Jun 1996 11:38:04 -0700 +Received: from RSA.COM (RSA.COM [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id LAA03740; Mon, 10 Jun 1996 11:37:21 -0700 (PDT) +Received: by RSA.COM + id AA16878; Mon, 10 Jun 96 11:32:05 PDT +Message-Id: <9606101835.AA29051@www> +Date: Mon, 10 Jun 1996 14:37:52 -0500 +X-Mailer: OpenSoft ExpressMail Version 1.0 +Mime-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=rsa-md5; boundary="===OpenSoft===11339510===2===" +X-UIDL: 834432008.000 +From: jgildred@opensoft.com (John T. Gildred) +To: smime-dev@RSA.COM ('smime-dev@rsa.com') +Subject: Signed Confirmation +Sender: owner-smime-dev@RSA.COM +Precedence: bulk +Status: U +X-Mozilla-Status: 0005 +Content-Length: 2957 + + +--===OpenSoft===11339510===2=== +MIME-Version: 1.0 +Content-Type: text/plain; charset="us-ascii" + + +--===OpenSoft===11339510===2=== +Content-Type: application/x-pkcs7-signature +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHAqCCB8Ewgge9AgEBMQ4wDAYIKoZIhvcNAgUFADCABgkqhkiG +9w0BBwEAAKCCBncwggIDMIIBbAIFAnIAAAIwDQYJKoZIhvcNAQECBQAwSDELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMSAwHgYDVQQLExdDbGFz +cyAxIEFzc3VyYW5jZSBMZXZlbDAeFw05NTEyMTMxODI2NTVaFw05OTEyMzExODI2 +NTVaMEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEgMB4G +A1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwwgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAL3XxO2O1rN/OvhilSL91rW18hEdBt3tZG6A8A2VX1O1Qkv/gFY+ +fUrFXCawOpED1OT8AI3nz7wujgWbTQvBiIcR9pjWVzMV07lOV+GxrJB1AkT4+6S5 +OKrGzgoTc0eDxJT83qdkGuZx85yv6W4GcUbvKdlIEBAituzYFA+NNH8nAgMBAAEw +DQYJKoZIhvcNAQECBQADgYEAPSUL6fSN2Ei65ZNgVxV1zcIBTMxJjQ6IcjPTlgEu +FouajOzmU9P8DXCYTdlb4dArlAQpuZl7sN6l95AwTEYvcC7WcpGrFepA++/m6KB9 +PBtBIZJeG9HW9SZmq1CrsXGYF/2rivrSMdEwzaZYcwejZ4OXvBM6zMx8+5PBRaYt +vTgwggIPMIIBeAIRAIU4YBC74iL3XmlfPohD8dIwDQYJKoZIhvcNAQEEBQAwgZ0x +ETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEgMB4G +A1UECxMXQ2xhc3MgMSBBc3N1cmFuY2UgTGV2ZWwxIDAeBgNVBAsTF1B1YmxpYyBQ +b2xpY3kgQXV0aG9yaXR5MSswKQYJKoZIhvcNAQkBFhxjbGFzczEtaW5jaWRlbnRA +dmVyaXNpZ24uY29tMB4XDTk2MDYxMDAzMTEwOFoXDTk2MDcxMDAzMTEwOFowOTER +MA8GA1UEBxMISW50ZXJuZXQxJDAiBgkqhkiG9w0BCQEWFWpnaWxkcmVkQG9wZW5z +b2Z0LmNvbTBZMAoGBFUIAQECAgIAA0sAMEgCQQDeK7ftSrLOqEIp2FW6bveae+U4 +pDEcufIlRx6XCE/XxlGO7djwhjBwjmdBCLCWudHHACxVn11DwcZHrsNk9yBJAgMB +AAEwDQYJKoZIhvcNAQEEBQADgYEA0kbBxyATGyuQe7QkJbuyTMRiQW8djg5xLGtL +2erUxaPNPZp6+pHUg/u67kJo56492ERqljg/ULc8BohBEGUuwv4d5hSST0KHhk5y +UIIOT0FUXh/4M+iZBKsy+1ERGnZBYg2Kt9BoK1bIhedCtiA1pD7kUfztEOMj1QGM +k841UKwwggJZMIIBwgIFAnIAAAEwDQYJKoZIhvcNAQECBQAwSDELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMSAwHgYDVQQLExdDbGFzcyAxIEFz +c3VyYW5jZSBMZXZlbDAeFw05NTEyMDcwMDAwMDBaFw05OTEyMzEyMzU5NTlaMIGd +MREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xIDAe +BgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNlIExldmVsMSAwHgYDVQQLExdQdWJsaWMg +UG9saWN5IEF1dGhvcml0eTErMCkGCSqGSIb3DQEJARYcY2xhc3MxLWluY2lkZW50 +QHZlcmlzaWduLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4Hh64F75 +L1QdbUeOzhyHZPq8S9awIuC0eESnefaJJKzqRXWM8GwFFgO4waYaUg+8UrAVMYjo +6eWGIUQy+cxMQAr3YiBAycT6sFL5pJjV2ACymhmFryVrMQC7ZNAaX/NstLsUplK7 +HR4q0hqWhZXh9w9gIhLGDAoUO5KQVtb7OS0CAwEAATANBgkqhkiG9w0BAQIFAAOB +gQCkTgau8JOGJ8dQ1yLbeBMAuv3OkXJ1NkbaROv7sbILWBbWj6ElKrZf95I6L1lB +RA0XvgwbugHt1Zt8d5JJRfW/Q6vfiFCLqw06rcd9G2E3Lg3Xzbt1fHM/fwhTXlAB +2/kQK3prrN7P5rIA77sqPTcs5EllJT47KqJUT7NUvf8guDGCARwwggEYAgEBMIGz +MIGdMREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4x +IDAeBgNVBAsTF0NsYXNzIDEgQXNzdXJhbmNlIExldmVsMSAwHgYDVQQLExdQdWJs +aWMgUG9saWN5IEF1dGhvcml0eTErMCkGCSqGSIb3DQEJARYcY2xhc3MxLWluY2lk +ZW50QHZlcmlzaWduLmNvbQIRAIU4YBC74iL3XmlfPohD8dIwDAYIKoZIhvcNAgUF +ADANBgkqhkiG9w0BAQEFAARAyD0uuJsqRBcMalVVEGzeGmvtNymctzBxy2kCzhMf +YgMQk9JIRMSI/mgv/XXSAY/7Fwjvx7UO+MjMz+RTtznUxgAA +--===OpenSoft===11339510===2===-- + +From - Wed Sep 11 08:47:00 1996 +Return-Path: owner-smime-dev@RSA.COM +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.mcom.com (8.7.5/8.7.3) with SMTP id NAA01603; Mon, 9 Sep 1996 13:04:54 -0700 (PDT) +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id NAA29833; Mon, 9 Sep 1996 13:03:35 -0700 +Received: from RSA.COM (chirality.rsa.com [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id NAA01808; Mon, 9 Sep 1996 13:02:34 -0700 (PDT) +Received: by RSA.COM + id AA26187; Mon, 9 Sep 96 12:47:15 PDT +Message-Id: <01BB9E4D.CA27D8A0@Peter.verisign.com> +From: Peter Williams +To: "'smime-dev@rsa.com'" +Subject: plase help by returning what gets delivered... +Date: Mon, 9 Sep 1996 12:52:38 -0700 +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="---- =_NextPart_000_01BB9E4D.CA434FE0" +Sender: owner-smime-dev@RSA.COM +Precedence: bulk +X-UIDL: db360888b99be53e578173dc6a65a828 +X-Mozilla-Status: 0001 +Content-Length: 2880 + + +------ =_NextPart_000_01BB9E4D.CA434FE0 +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: 7bit + + +The first two bodypart sent above should be part of a MIME object. +One should be type text/html, the second application/octet-stream. + +Can anyone who cares send me back the MIME object for +this message actually delivered to their UA? + +Im finding Deming' s excellent tool to be be very useful +for signing attachements of any type, and being +able to reverify the bodypart content even once the attachement +is released from the mail system. + +Peter. + +------ =_NextPart_000_01BB9E4D.CA434FE0 +Content-Type: text/html; name="Page1.htm" +Content-Transfer-Encoding: 7bit + + + +New Page + + + + + + + + + + + + + + + + + + + + + + + +------ =_NextPart_000_01BB9E4D.CA434FE0 +Content-Type: application/x-pkcs7-signature; name="Page1.p7s" +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggHOMIIB +NwIEQAjsMTANBgkqhkiG9w0BAQQFADAuMSwwKgYDVQQDFCNQZXRlciBXaWxsaWFtcyA8cGV0ZXJA +VmVyaVNpZ24uY29tPjAeFw05NjA3MTYyMTIzMTJaFw05ODA3MTYyMTIzMTFaMC4xLDAqBgNVBAMU +I1BldGVyIFdpbGxpYW1zIDxwZXRlckBWZXJpU2lnbi5jb20+MIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQC0DQLdneDxs9u+7STPqBls/wZX89tHi4a8r/b629bqaEOoGbamNGPx9LSAjZxItPRG +2m4tEgY+oe8gYTPnKzPlZJyWmCxD8Cpi3dQF8/8NzKqEtxVEoldvUAdQB77BznGs5s8DC7GYIR89 +aJoyVk1IcxY+YQYj3hN2YWQ4/F5OGwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAHWOkUF8GfWNS9pA +bYZXesuYwxZ6FWgnD4A7WeS0ODYIdZ3MfQhYkyiIba/8ex+A8JhazpOsBRM0ydoHpspbWhhwTlah +/CUNk3V/eZLYpYsiwSTQYKBxuhYIfkaE0mXgAv+ef473du5NaNLIGI5cK7Vmbj9Bh/93K9Serto1 +BtxiAAAxgDCCAWMCAQEwNjAuMSwwKgYDVQQDFCNQZXRlciBXaWxsaWFtcyA8cGV0ZXJAVmVyaVNp +Z24uY29tPgIEQAjsMTAJBgUrDgMCGgUAoIGIMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ +KoZIhvcNAQkFMQ8XDTk2MDkwOTE5NDEzMlowIwYJKoZIhvcNAQkEMRYEFFusg4r4l+lJKA8GOuNP +xoTBiXuCMCkGCSqGSIb3DQEJDTEcExpTaWduZWQgYnkgU2VjdXJlIE1lc3NlbmdlcjANBgkqhkiG +9w0BAQEFAASBgLCjKzFaV8bOUloF1T3zjEFTOqSk7/MZoqv3xMwOYo76/81Jl36DBNIcngari3v5 +vIRWDwvw6gRnE4kkx0DGVu/zvXV2EX1BTwx47uLcExR99SilUZbkwf/Q2foBPbKXAVunCZ3SJcPG +X0GE3m1gBzM2KDEKEKLpvSTzBBpvZNIMAAAAAAAAAAA= + +------ =_NextPart_000_01BB9E4D.CA434FE0-- + +From - Mon Sep 23 13:04:41 1996 +Return-Path: owner-smime-dev@RSA.COM +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.mcom.com (8.7.5/8.7.3) with SMTP id JAA19830; Mon, 23 Sep 1996 09:27:04 -0700 (PDT) +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id JAA07645; Mon, 23 Sep 1996 09:25:43 -0700 +Received: from RSA.COM (chirality.rsa.com [192.80.211.33]) by ns.netscape.com (8.7.3/8.7.3) with SMTP id JAA28691; Mon, 23 Sep 1996 09:24:41 -0700 (PDT) +Received: by RSA.COM + id AA02291; Mon, 23 Sep 96 09:18:21 PDT +Date: Mon, 23 Sep 96 09:20:00 PDT +To: "S-MIME DEV" +From: "Ron Craswell" +Subject: multipart/signed test +Mime-Version: 1.0 +Content-Type: multipart/signed; boundary= + "---=_=_ 3784965-7724120-8948032 _=_=---"; micalg=rsa-sha1; protocol= + "application/x-pkcs7-signature" +Message-Id: <19960923092443.03af0217.in@peapod.deming.com> +Sender: owner-smime-dev@RSA.COM +Precedence: bulk +X-UIDL: b097620b95ad7baa11ee8c3d2f409640 +X-Mozilla-Status: 0001 +Content-Length: 4528 + + +-----=_=_ 3784965-7724120-8948032 _=_=--- +Content-Type: text/plain +Content-Transfer-Encoding: quoted-printable + +Here's a test multipart/signed message. Anyone who can read +this and verify the signature, please respond to me. + +Thanks, +Ron Craswell +Deming Software + + +-----=_=_ 3784965-7724120-8948032 _=_=--- +Content-Type: application/x-pkcs7-signature +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIAwggVD +MIIErKADAgECAhAqqMNhRDnyZ4/IFxlCEv25MA0GCSqGSIb3DQEBBAUAMGIxETAPBgNVBAcT +CEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24g +Q2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2NyaWJlcjAeFw05NjA5MjMwMDAwMDBaFw05 +NjA5MjgyMzU5NTlaMIIBJjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWdu +LCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVhbCBTdWJz +Y3JpYmVyMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvQ1BTIEluY29y +cC4gYnkgUmVmLixMSUFCLkxURChjKTk2MT4wPAYDVQQLEzVEaWdpdGFsIElEIENsYXNzIDEg +LSBTTUlNRSBEZW1pbmcgU29mdHdhcmUsIEluYy4gQmV0YTEaMBgGA1UEAxMRUm9uYWxkIEog +Q3Jhc3dlbGwxHjAcBgkqhkiG9w0BCQEWD3JvbmNAZGVtaW5nLmNvbTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEA+JwFnASUABZCioWmADLnZvMeKAI1voL+s9b01u7+YAv1UvtUFX57 +wT9sgN3LAOtdwNTv6JEzUXAFf8X5bys2uMy7a9cYirg5qozQ9VOcyX/CKt4H9AfTkxa+U56h +FvC0ghn3+Pw8W8aD3nuobORXM2E4fMIeCtexPN13WrmFkrkCAwEAAaOCAjIwggIuMAkGA1Ud +EwQCMAAwggIfBgNVHQMEggIWMIICEjCCAg4wggIKBgtghkgBhvhFAQcBATCCAfkWggGnVGhp +cyBjZXJ0aWZpY2F0ZSBpbmNvcnBvcmF0ZXMgYnkgcmVmZXJlbmNlLCBhbmQgaXRzIHVzZSBp +cyBzdHJpY3RseSBzdWJqZWN0IHRvLCB0aGUgVmVyaVNpZ24gQ2VydGlmaWNhdGlvbiBQcmFj +dGljZSBTdGF0ZW1lbnQgKENQUyksIGF2YWlsYWJsZSBhdDogaHR0cHM6Ly93d3cudmVyaXNp +Z24uY29tL0NQUzsgYnkgRS1tYWlsIGF0IENQUy1yZXF1ZXN0c0B2ZXJpc2lnbi5jb207IG9y +IGJ5IG1haWwgYXQgVmVyaVNpZ24sIEluYy4sIDI1OTMgQ29hc3QgQXZlLiwgTW91bnRhaW4g +VmlldywgQ0EgOTQwNDMgVVNBIFRlbC4gKzEgKDQxNSkgOTYxLTg4MzAgQ29weXJpZ2h0IChj +KSAxOTk2IFZlcmlTaWduLCBJbmMuICBBbGwgUmlnaHRzIFJlc2VydmVkLiBDRVJUQUlOIFdB +UlJBTlRJRVMgRElTQ0xBSU1FRCBhbmQgTElBQklMSVRZIExJTUlURUQuoA4GDGCGSAGG+EUB +BwEBAaEOBgxghkgBhvhFAQcBAQIwLDAqFihodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcmVw +b3NpdG9yeS9DUFMgMA0GCSqGSIb3DQEBBAUAA4GBAG2HnnegbT4k8xn0c5ciQF69M8J8NUlR +2lrDhHrIF5HCHYHrzOBFbRxBB7Q76HvkN+HKTZIJCNdHS/dk8TF5H56dmhkou93y3bca9Qoy +JDKBZ5EnNj96yK6xQ+/iNt8FHPaRyb2awC5WfvH5PoJvuPrBm+8fvG0PbsWxZl7lZYXJMIIC +eTCCAeKgAwIBAgIQNRGlUpBv59AppEAZ1BH8PjANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj +IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwNjI3MDAwMDAwWhcNOTcw +NjI3MjM1OTU5WjBiMREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIElu +Yy4xNDAyBgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmli +ZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALYUps9N0AUN2Moj0G+qtCmSY44s+G+W +1y6ddksRsTaNV8nD/RzGuv4eCLozypXqvuNbzQaot3kdRCrtc/KxUoNoEHBkkdc+a/n3XZ0U +Q5tul0WYgUfRLcvdu3LXTD9xquJA8lQ5vBbuz3zsuts/bCqzFrGGEp2ukzTVuNXQ9z6pAgMB +AAGjMzAxMA8GA1UdEwQIMAYBAf8CAQEwCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIC +BDANBgkqhkiG9w0BAQIFAAOBgQAp5cegGadvFEKCTSMz172YOml3GmyKkidr8nwM4cRS4Pic +40Cvj7E6DvdIGXTbqfsGTnkDbC8Awajv6QpNn6sdoUMNyarg76vMWuLZEg54YCdyPUhwam0B +CG9egiEUwbgmXODUqUdkerLsPeN7HvzNxJTuQo67x/m0BfWMLf6xOgAAoYAwggEnMIGRMA0G +CSqGSIb3DQEBAgUAMGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5WZXJpU2lnbiwg +SW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1YWwgU3Vic2Ny +aWJlchcNOTYwNzAxMTczMDQwWhcNOTcwNzAxMDAwMDAwWjANBgkqhkiG9w0BAQIFAAOBgQAY +u5Do9fwDsCKoES1bNi2XqVk1IMjRtHlhSj4PYnOTDfR3FCclJspcRzpdi7MBbke+vMBNe7lz +X1ZY9PhxEPCaMfvWL1BwPKxbB//ATSoZOJYje1BPQjlUaHuMgkPTueUHDdHheXx0f2Svzkmx +aKeoMflgqkij2jySdjmfv6qM6jCCASQwgY4wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMC +VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQ +cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NjA4MTMwMDMwNThaFw05NzA4MTIw +MDAwMDBaMA0GCSqGSIb3DQEBAgUAA4GBANXc7/6Xr1C26DcMIkXCDqtV2kUDjMlsP0khVDbv +o+a0kY475s1k6ZtG4v/HLeU+R0fWriZs+kP6Y+sdMGlxI7IVkId/1WoCHIA7F3HTmyA3MOBq +X4oHDh6+e+yqRZa95BlQuIpOaE785jbHCuUqPJ6cGxF8fTRzFxZoe7zK+40RAAAxgDCCAXcC +AQEwdjBiMREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAy +BgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmliZXICECqo +w2FEOfJnj8gXGUIS/bkwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEw +HAYJKoZIhvcNAQkFMQ8XDTk2MDkyMzE2MTE0NVowIwYJKoZIhvcNAQkEMRYEFDfU6g0eba3d +u4OWg+vZTtYXPu7wMA0GCSqGSIb3DQEBAQUABIGAg1K0GAAMYK1A+F9vi2PhdmE1AMWzQXsj +/LkFlEF/GDg5DDtQH8lcGHuCjQNQA3c9sE+dgqW7teF5dqaB+/ua3dvQzrwuS0PDtqQSvQcF +q5AD2i7qQrvF1Jr/Z1eyMMAEZP1TCQjTzxffsbHRwOshRVwewVzDQ9mX9MBBdnb4ziQAAAAA +AAAAAA== +-----=_=_ 3784965-7724120-8948032 _=_=----- + +From - Sat Nov 2 21:56:58 1996 +Return-Path: +Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com + (Netscape Mail Server v2.01) with SMTP id AAA20354; + Tue, 29 Oct 1996 12:15:27 -0700 +Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id MAA06386; Tue, 29 Oct 1996 12:14:10 -0800 +Received: from RSA.COM (chirality.rsa.com [192.80.211.33]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id MAA08725; Tue, 29 Oct 1996 12:13:42 -0800 (PST) +Received: by RSA.COM + id AA21317; Tue, 29 Oct 96 12:13:12 PPE +Date: Tue, 29 Oct 1996 15:12:00 -0500 +Message-Id: MSG961029151201#15@server1.opensoft.com +X-Mailer: OpenSoft ExpressMail Version 1.0 +Mime-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=rsa-sha; boundary="===OpenSoft===247233737===5===" +From: jgildred@opensoft.com (John T. Gildred) +To: smime-dev@RSA.COM ('smime-dev@rsa.com') +Subject: Signed SHA1 with VeriSign certification +Sender: owner-smime-dev@RSA.COM +Precedence: bulk +X-Mozilla-Status: 0001 +Content-Length: 4051 + + +--===OpenSoft===247233737===5=== +Content-Transfer-Encoding: 7bit +Content-Type: text/plain; charset="us-ascii" + +Fellow testers: + +Please let me know if this sig poses any problems. + +-John +--===OpenSoft===247233737===5=== +Content-Type: application/x-pkcs7-signature +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHAqCCCqYwggqiAgEBMQswCQYFKw4DAhoFADCABgkqhkiG9w0B +BwEAAKCCCaIwggIxMIIBmgIFAqQAAAEwDQYJKoZIhvcNAQECBQAwXzELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEy +OTAwMDAwMFoXDTk5MTIzMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoT +DlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVu +DLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVW +aR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqG +SIb3DQEBAgUAA4GBAFJzuppV3Nw/gn2wkJhiKoJMdgBuJT3VwglwVwEMD3cfGKH7 +HGAOoHU7SSFB/qdcLUxCSdP/KNiM6p3+yQfid4JTI95V885Ek/r6TL3KNvNbZrKe +yPIMXl7UobQhCTPKO1n8ksI4/K3ZliTgLfqjKfUzaHhOtLyfaTXiqJiUczvEMIIC +eTCCAeKgAwIBAgIQNRGlUpBv59AppEAZ1BH8PjANBgkqhkiG9w0BAQIFADBfMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNs +YXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN +OTYwNjI3MDAwMDAwWhcNOTcwNjI3MjM1OTU5WjBiMREwDwYDVQQHEwhJbnRlcm5l +dDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAyBgNVBAsTK1ZlcmlTaWduIENs +YXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmliZXIwgZ8wDQYJKoZIhvcNAQEB +BQADgY0AMIGJAoGBALYUps9N0AUN2Moj0G+qtCmSY44s+G+W1y6ddksRsTaNV8nD +/RzGuv4eCLozypXqvuNbzQaot3kdRCrtc/KxUoNoEHBkkdc+a/n3XZ0UQ5tul0WY +gUfRLcvdu3LXTD9xquJA8lQ5vBbuz3zsuts/bCqzFrGGEp2ukzTVuNXQ9z6pAgMB +AAGjMzAxMA8GA1UdEwQIMAYBAf8CAQEwCwYDVR0PBAQDAgEGMBEGCWCGSAGG+EIB +AQQEAwICBDANBgkqhkiG9w0BAQIFAAOBgQAp5cegGadvFEKCTSMz172YOml3GmyK +kidr8nwM4cRS4Pic40Cvj7E6DvdIGXTbqfsGTnkDbC8Awajv6QpNn6sdoUMNyarg +76vMWuLZEg54YCdyPUhwam0BCG9egiEUwbgmXODUqUdkerLsPeN7HvzNxJTuQo67 +x/m0BfWMLf6xOjCCBOwwggRVoAMCAQICEFFJf2qY+gHIW0t+SuyuYCIwDQYJKoZI +hvcNAQEEBQAwYjERMA8GA1UEBxMISW50ZXJuZXQxFzAVBgNVBAoTDlZlcmlTaWdu +LCBJbmMuMTQwMgYDVQQLEytWZXJpU2lnbiBDbGFzcyAxIENBIC0gSW5kaXZpZHVh +bCBTdWJzY3JpYmVyMB4XDTk2MTAyOTAwMDAwMFoXDTk2MTEyODIzNTk1OVowggEU +MREwDwYDVQQHEwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAy +BgNVBAsTK1ZlcmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmli +ZXIxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9DUFMgSW5j +b3JwLiBieSBSZWYuLExJQUIuTFREKGMpOTYxPTA7BgNVBAsTNERpZ2l0YWwgSUQg +Q2xhc3MgMSAtIFNNSU1FIE9wZW5Tb2Z0IENvcnBvcmF0aW9uIEJldGExKTAnBgkq +hkiG9w0BCQEWGnNtaW1lLWludGVyb3BAb3BlbnNvZnQuY29tMFswDQYJKoZIhvcN +AQEBBQADSgAwRwJADeNrTMucfTTQSuc+WPBUM0MxRhjkXFLepVhZel6y5GCrL9bC +iHm+QzA81DItelxpAMOY5gOhwyRu5Njr6ag57QIDAQABo4ICMjCCAi4wCQYDVR0T +BAIwADCCAh8GA1UdAwSCAhYwggISMIICDjCCAgoGC2CGSAGG+EUBBwEBMIIB+RaC +AadUaGlzIGNlcnRpZmljYXRlIGluY29ycG9yYXRlcyBieSByZWZlcmVuY2UsIGFu +ZCBpdHMgdXNlIGlzIHN0cmljdGx5IHN1YmplY3QgdG8sIHRoZSBWZXJpU2lnbiBD +ZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudCAoQ1BTKSwgYXZhaWxhYmxl +IGF0OiBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vQ1BTOyBieSBFLW1haWwgYXQg +Q1BTLXJlcXVlc3RzQHZlcmlzaWduLmNvbTsgb3IgYnkgbWFpbCBhdCBWZXJpU2ln +biwgSW5jLiwgMjU5MyBDb2FzdCBBdmUuLCBNb3VudGFpbiBWaWV3LCBDQSA5NDA0 +MyBVU0EgVGVsLiArMSAoNDE1KSA5NjEtODgzMCBDb3B5cmlnaHQgKGMpIDE5OTYg +VmVyaVNpZ24sIEluYy4gIEFsbCBSaWdodHMgUmVzZXJ2ZWQuIENFUlRBSU4gV0FS +UkFOVElFUyBESVNDTEFJTUVEIGFuZCBMSUFCSUxJVFkgTElNSVRFRC6gDgYMYIZI +AYb4RQEHAQEBoQ4GDGCGSAGG+EUBBwEBAjAsMCoWKGh0dHBzOi8vd3d3LnZlcmlz +aWduLmNvbS9yZXBvc2l0b3J5L0NQUyAwDQYJKoZIhvcNAQEEBQADgYEAq/arpsyo +Tf5GPrE0KqlupSKbhz6iSNk1xtuGUPL98T/ejjud1c1JqSmkR7/l70BUi2uzTy7q +WdoUaYs+7pfzeYCEezori5Ew/Z9PxF2XPf2gsgCmnSRKeiYFaqskBve2QUIKlQ0D +pkQgNhg+4ERibZmfwmP2ejmhPSlpBxa4sZIxgdowgdcCAQEwdjBiMREwDwYDVQQH +EwhJbnRlcm5ldDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNDAyBgNVBAsTK1Zl +cmlTaWduIENsYXNzIDEgQ0EgLSBJbmRpdmlkdWFsIFN1YnNjcmliZXICEFFJf2qY ++gHIW0t+SuyuYCIwCQYFKw4DAhoFADANBgkqhkiG9w0BAQEFAARAAtgPcxoY0qAX +TKNpfBPH5MH9JwgDdjNK4e8CntvLb70WnUuTxiEWGOReopn5QCerO5YPW2ion88j +xEzvtOYuMAAA +--===OpenSoft===247233737===5===-- +From - Mon Jul 29 02:26:23 1996 +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.netscape.com (8.7.5/8.7.3) with SMTP id CAA25028 for ; Mon, 29 Jul 1996 02:26:08 -0700 (PDT) +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id CAA12409 for ; Mon, 29 Jul 1996 02:24:55 -0700 +Received: from mm1 (mm1.sprynet.com [165.121.1.50]) by ns.netscape.com (8.7.3/8.7.3) with ESMTP id CAA14074 for ; Mon, 29 Jul 1996 02:24:05 -0700 (PDT) +Received: by mm1.sprynet.com id <148226-12799>; Mon, 29 Jul 1996 02:21:58 -0700 +From: The Post Office +Subject: email delivery error +Cc: The Postmaster +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; boundary="A41C7.838631588=_/mm1" +Precedence: junk +Message-Id: <96Jul29.022158-0700pdt.148226-12799+708@mm1.sprynet.com> +To: unlisted-recipients:; (no To-header on input) +Date: Mon, 29 Jul 1996 02:13:08 -0700 +X-UIDL: ee2855c88ed795f63bbcbfd279c80fab +X-Mozilla-Status: 0001 +Content-Length: 1263 + +Processing your mail message caused the following errors: + +error: err.nosuchuser: newsletter-request@imusic.com + +--A41C7.838631588=_/mm1 +Content-Type: message/delivery-status + +Reporting-MTA: dns; mm1 +Arrival-Date: Mon, 29 Jul 1996 02:12:50 -0700 + +Final-Recipient: RFC822; newsletter-request@imusic.com +Action: failed +Diagnostic-Code: X-LOCAL; 500 (err.nosuchuser) + +--A41C7.838631588=_/mm1 +Content-Type: message/rfc822 + +Received: from urchin.netscape.com ([198.95.250.59]) by mm1.sprynet.com with ESMTP id <148217-12799>; Mon, 29 Jul 1996 02:12:50 -0700 +Received: from gruntle (gruntle.mcom.com [205.217.230.10]) by urchin.netscape.com (8.7.5/8.7.3) with SMTP id CAA24688 for ; Mon, 29 Jul 1996 02:04:53 -0700 (PDT) +Sender: jwz@netscape.com +Message-ID: <31FC7EB4.41C6@netscape.com> +Date: Mon, 29 Jul 1996 02:04:52 -0700 +From: Jamie Zawinski +Organization: Netscape Communications Corporation, Mozilla Division +X-Mailer: Mozilla 3.0b6 (X11; U; IRIX 5.3 IP22) +MIME-Version: 1.0 +To: newsletter-request@imusic.com +Subject: unsubscribe +References: <96Jul29.013736-0700pdt.148116-12799+675@mm1.sprynet.com> +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit + +unsubscribe +--A41C7.838631588=_/mm1-- + +From - Fri Sep 27 12:03:19 1996 +Return-Path: owner-mhtml@SEGATE.SUNET.SE +Received: from maleman.mcom.com (maleman.mcom.com [198.93.92.3]) by urchin.mcom.com (8.7.5/8.7.3) with SMTP id JAA29055 for ; Fri, 27 Sep 1996 09:44:42 -0700 (PDT) +Received: from ns.netscape.com (ns.netscape.com.mcom.com [198.95.251.10]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id JAA01328; Fri, 27 Sep 1996 09:43:26 -0700 +Received: from SEGATE.SUNET.SE (segate.sunet.se [192.36.125.6]) by ns.netscape.com (8.7.3/8.7.3) with ESMTP id JAA28293; Fri, 27 Sep 1996 09:42:21 -0700 (PDT) +Received: from segate.sunet.se by SEGATE.SUNET.SE (LSMTP for OpenVMS v1.1a) with SMTP id <15.651C283F@SEGATE.SUNET.SE>; Fri, 27 Sep 1996 18:44:36 +0100 +Received: from SEGATE.SUNET.SE by SEGATE.SUNET.SE (LISTSERV release 1.8c) with + NJE id 12302 for MHTML@SEGATE.SUNET.SE; Fri, 27 Sep 1996 18:44:32 + +0200 +Received: from nugget.scr.atm.com (206.100.186.2) by SEGATE.SUNET.SE (LSMTP for + OpenVMS v1.1a) with SMTP id <10.616A9AEA@SEGATE.SUNET.SE>; Fri, 27 + Sep 1996 18:44:30 +0100 +Received: from mailman.scr.atm.com (mailman.scr.atm.com [206.100.186.54]) by + nugget.scr.atm.com (8.6.12/8.6.9) with ESMTP id JAA21526; Fri, 27 Sep + 1996 09:50:59 -0700 +From: izzy@nugget.scr.atm.com (Dr. Mark K. Joseph) +To: lewisg@Exchange.Microsoft.com +Cc: mhtml@SEGATE.SUNET.SE +Date: Fri, 27 Sep 1996 09:36:54 -0700 +MIME-Version: 1.0 +Message-ID: <19960927163654.izzy@scr.atm.com> +In-Reply-To: +Subject: RE: problem with relative urls and applets +X-Mailer: Emissary V2.03, by Attachmate Corp. +Content-Type: multipart/mixed; + boundary="=_27tW56g.bO1996u.N16d000A.r09Y.36:0008d3" +Content-Transfer-Encoding: 7bit +Sender: owner-mhtml@SEGATE.SUNET.SE +X-UIDL: 9f218600f41793d7a03f4710763907fb +X-Mozilla-Status: 0011 +Content-Length: 4879 + +--=_27tW56g.bO1996u.N16d000A.r09Y.36:0008d3 +Content-Type: text/plain; charset="us-ascii" +Content-Transfer-Encoding: 7bit + +On Thu, 26 Sep 1996 18:30:27 -0700 +"Lewis Geer (Exchange)" wrote: + +>Section 7: +>New Text: +>When the sending MUA sends objects that reference each other within an +>email message, the sending MUA SHOULD attempt to use the Content-ID +>method (as defined in section 8.3). This will avoid problems the +>receiving MUA will have in parsing non-typed fields (such as PARAM +>fields in OBJECT tags) that are contained in the html. In the case +>where the email message contains MICs, it may be necessary for the +>sending MUA to use the Content-Location method (as defined in section +>8.2) in order for the receiving MUA to be able to verify the MICS, as +>well as to verify the message against its WWW counterpoint. +> + +I for one agree with this change. MICs aside the "cid:" approach +is much easier to implement (speaking from experience). + +--=_27tW56g.bO1996u.N16d000A.r09Y.36:0008d3 +Content-Type: application/vcard +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; filename="MJOSEPH.VCF" +Content-Description: The Sender's Signature + +BEGIN:VCARD +NOTE: vCard Format: Version 2.0(Spec-4/29/96) +REV:1996-09-17T21:00:23Z +N:Joseph;Mark +EmissaryA.FN:Mark K. Joseph, Ph.D. +MAILER:Emissary 2.01 +EMAIL;work;pref;internet:izzy@scr.atm.com +TEL;WORK;PREF;MSG:(408) 471 - 3016 +TEL;WORK;FAX:(408) 471 - 3010 +TEL;HOME;FAX;MSG:(408) 475 - 8805 +TZ:-0800 +ORG:Attachmate Corporation;Internet Products Group +TITLE:Software Architect +LOGO;BASE64;gif: +R0lGODlhuQAwAPcAAP///+/v7+fn597e3tbW1s7OzsbGxr29va2traWlpZycnJSUlIyMjISEhHt7 +e3Nzc2tra2NjY1paWlJSUkpKSkJCQjk5OTExMSkpKSEhIRgYGBAQEAgICOfe1oR7c2NaUjEpIe/n +3s7Gva2lnIyEe0pCOaWcjJyUhL2tjFpSQox7WntrShgQANbGnM69lMa1jO/WlJSEWta9e8ata3tr +Qq2UUqWMSpR7OYRrKTkpAKWchIR7Y+/erefWpa2ca6WUY4x7SpyEQsalSr2cQmNSIbWUOYxzKaWE +KYRrIZx7Ie+9KUo5CGtSCMaUAKV7AFpCAP/33u/nzt7WvdbOtb21nK2ljJSMc4yEa//vvXtzWnNr +UmtjSufWnL2te//nnFJKMe/WhEpCKaWUWufOe861Y8atWoRzOXNjMe/OY9a1SqWMOffOUjEpEMal +Oe/GQpR7KVpKGL2cMd61Oee9MffGMdatKa2MIc6lIe+9Ib2UGMacGO+9GMacENalEJRzCLWMCK2E +CN6tCNalAIxrAGtSAEo5AMa9nLWla9a9Y72lUvfWY3trMbWcQnNjKefGUu/OUt69SufGSpyEMda1 +Qt69QqWMMc6tOffOQta1OZyEKcalMe/GOc6tMb2cKd61KVpKEL2cIe/GKYxzGNatIbWUGN61GFJC +CK2MENatEO+9EL2UCM6lCO+9COe1CO+9AOe1AN6tAL2UALWMAJx7AJRzAHNaAN7Wtb21lK2lhP/v +rYR7UufWjM69c8a1a/fee2NaMe/Wc5yMSvfec6WUSufOY9a9Uox7McatQu/OSoRzKa2UKe/GIYxz +EOe9GN61EIRrCN61CNatAM6lAIRrAHtjACkhAP/3zu/nvdbOpbWthN7OhNbGe7WlWs69Y1JKIXNj +GL21hKWca/fnjN7Oc0I5CMbGvf//797ezsbGtbW1pefnzpSUhEpKQtbWvcbGrb29pYSEc2trWpSU +e1paSnt7Y1JSQmNjSkJCMVpaQiEhGEJCKTk5IRgYCBAQAAgIAAAAACwAAAAAuQAwAAAI/wABCBxI +sKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN +hxH+6dyZ4WbBnTt93gQK1CDRfz+Jljx604JSmAGO6kSQtChBpiSx1qzw9OUEqf82VA16tatIrTS5 +Wn0JVudYt2XXnjU706nckwcIRm1LFcCBA0cN/BV89C8BvQ3U6qygICECu/8qpHuLFEDOfxkaDxz8 +N4DABzovFCA4QO2FvgULRMgAdIKBzQcuEB1ccMDXxYc35h0ou21l38ArCATse0JBB20jDDxaQKpn +AEQNIDgqFsAGqQRB+24MfOAAvh+B//8WD1b4dPEPBl73XZ08XKLIpVZYT12gYt/ffQtUAPxCx/w7 +OcAAUdy5d5RwBgp0W3DQuVeggWAJBKF+zaHHUW9kaYVWg3Jp+NRRFzRAX1AGijUhWArwB5R/AAiA +1X2VSUjUAAKNGGNGWHl4F1oO9NjjbhwGddlOxskIVDog1shUfUHu5N9eQElwQANUUhkXWZDBBUCF +OwHZZJEYcamTBvYRxYCRZC1HV0EHQIAdWgpUIKecKnaolFbErRXfTsIZlM6CVsE4EIyc5ZnmRawB +1RcBOdK1YQE2vrkmZVe6hRaeRPVZp34AZBnjhBpd+qGjZkUa4YZGmbWkql0ZQJQFTXL/Kiia5GV0 +nnvpbagVjDxhaOmkld64qp1rGRpZW77C5amaCWJkqn66dpUkrUjBmamoRWGbprGe/uMAs2TBOBoA +yWYF6lEZ/EXtAwaIqWWslhHVE7WbvjvsoVq52h24yhK1wV+3hkbQnHNiFDCubVG7WGACJTvetffa +eyerxYr3HHYA8PorUBkI4O4/CWSskwMVfAeRjf8eIJjKkWr8MMTufUZerhSTWLOWxrocIQB7KmVs +wvbxnIEGNzJ0lGYE1fuPixhrXMGAYNlIo8i+sajtxvi2mqnDQMcKl9JoCeeAbUUrpDRCR0XQc5qJ +AiWcdvA1Wd2WbQF5dbU3x5gzuVIV/1CvcgAcrGUAzwI+UHqa9SkUAhBU4MC4DSFAsgOoxcQABRM0 +8NxFB0x+plCghy766KSXbvrpqKeuukQBSOBjj40V4MDcEfno5egkz7u6QhfQ+E96iv+DAUVRTb2Q +t0tBftAGfSpu0QFgzkRVcwJ9Dt1otwMwQPYE5aTXc7cXTSP3r5E2nEEFeEk9Qs0hDQGbBuVGAPg/ +Za48QR4TtJsBm/slkPEYkU1BpmMdAQokKgGYXULCMpCcRCAC0wFSTspXgAxUQDa7Kd76AKAA1igA +OQ3wDlIu+L8NZKB8RtFdQTawgIyh5joGuMBXBgAaxQFGQoYDQAa+9Q/rCTAD3gNAAP9A4xnk4ch5 +1smAfxrwqcYQbYFIi8oCAmCy5RgOORMIwG7Wx5WBNIdy0NncP3ynu39ULjtlq1F1XCWQkP3DOBi4 +gHL+AbkBCcSCy2lMVAYygQT8gwPQ6VNPQJaxjfwjN2pSUvX+cQANIDFpN4rKty5Au3/0DzNX0eM/ +kAYd/4CGj/9IxwYMt0GDdPEgS1NQjAYkgAZxUFjpgc77RCajskjokiGknUWC6EVLSihxaUwKQb4i +Ib/tBylTKyUB4yXEY0roAZp5V8N8eRDkDGw5ywleT77juwlArjJVhE5jZLMApG0SAHa8SgNiiSNd +ZmADAyCAA1j0SioOD23shM6ZviOqgefIZm6UJAhyCnAB0ABSQn3a5Li8dwDD/Y6eRukTQbFpmUre +8TfpCNkrf7kcB5Bpk8/hD0Ih2sP7VYQCPYpeAwaggAvcTkRnHIgAIrBO1ISwRRnYnANyuNKffKsB +KlUPAFfjJQ18SyGXyeLAXEqaozagldaBaiCZ1z853XFzC+jLDn9y09159Xj9s8gAIPrVshYkJ2GV +yHcCQFazupUjBwDgW+dK17qWNSAAOw== + +URL:http://www.atm.com +LABEL;WORK;PARCEL;POSTAL;DOM;QUOTED-PRINTABLE:140 Du Bois Street, Suite C=0A= +Santa Cruz, CA 95060 +EMAIL;home;internet:markjoseph@dhnet.com +EmissaryA.URL:http://www.dhnet.com +END:VCARD + +--=_27tW56g.bO1996u.N16d000A.r09Y.36:0008d3-- diff --git a/UnitTests/TestData/mbox/content-length.unix-offsets.json b/UnitTests/TestData/mbox/content-length.unix-offsets.json new file mode 100644 index 0000000000..f20b4d593b --- /dev/null +++ b/UnitTests/TestData/mbox/content-length.unix-offsets.json @@ -0,0 +1,1330 @@ +[ + { + "mboxMarkerOffset": 0, + "lineNumber": 2, + "beginOffset": 8, + "headersEndOffset": 657, + "endOffset": 1888, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 2, + "beginOffset": 8, + "headersEndOffset": 657, + "endOffset": 1888, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 20, + "beginOffset": 706, + "headersEndOffset": 732, + "endOffset": 806, + "octets": 74, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 28, + "beginOffset": 856, + "headersEndOffset": 918, + "endOffset": 1837, + "message": { + "lineNumber": 31, + "beginOffset": 918, + "headersEndOffset": 1700, + "endOffset": 1837, + "body": { + "mimeType": "text/plain", + "lineNumber": 31, + "beginOffset": 918, + "headersEndOffset": 1700, + "endOffset": 1837, + "octets": 137, + "lines": 4 + }, + "octets": 137 + }, + "octets": 919, + "lines": 21 + } + ], + "octets": 1231, + "lines": 34 + }, + "octets": 1231 + }, + { + "mboxMarkerOffset": 1889, + "lineNumber": 54, + "beginOffset": 1897, + "headersEndOffset": 2365, + "endOffset": 8122, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 54, + "beginOffset": 1897, + "headersEndOffset": 2365, + "endOffset": 8122, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 69, + "beginOffset": 2438, + "headersEndOffset": 2582, + "endOffset": 3048, + "message": { + "lineNumber": 74, + "beginOffset": 2582, + "headersEndOffset": 3011, + "endOffset": 3048, + "body": { + "mimeType": "text/plain", + "lineNumber": 74, + "beginOffset": 2582, + "headersEndOffset": 3011, + "endOffset": 3048, + "octets": 37, + "lines": 2 + }, + "octets": 37 + }, + "octets": 466, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 89, + "beginOffset": 3076, + "headersEndOffset": 3199, + "endOffset": 3657, + "octets": 458, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 101, + "beginOffset": 3685, + "headersEndOffset": 3808, + "endOffset": 4294, + "octets": 486, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 113, + "beginOffset": 4322, + "headersEndOffset": 4449, + "endOffset": 4976, + "octets": 527, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 126, + "beginOffset": 5004, + "headersEndOffset": 5129, + "endOffset": 5627, + "octets": 498, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 138, + "beginOffset": 5655, + "headersEndOffset": 5799, + "endOffset": 6265, + "message": { + "lineNumber": 143, + "beginOffset": 5799, + "headersEndOffset": 6228, + "endOffset": 6265, + "body": { + "mimeType": "text/plain", + "lineNumber": 143, + "beginOffset": 5799, + "headersEndOffset": 6228, + "endOffset": 6265, + "octets": 37, + "lines": 1 + }, + "octets": 37 + }, + "octets": 466, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 157, + "beginOffset": 6293, + "headersEndOffset": 6464, + "endOffset": 7960, + "message": { + "lineNumber": 162, + "beginOffset": 6464, + "headersEndOffset": 7034, + "endOffset": 7960, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 162, + "beginOffset": 6464, + "headersEndOffset": 7034, + "endOffset": 7960, + "message": { + "lineNumber": 177, + "beginOffset": 7034, + "headersEndOffset": 7545, + "endOffset": 7960, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 177, + "beginOffset": 7034, + "headersEndOffset": 7545, + "endOffset": 7960, + "message": { + "lineNumber": 191, + "beginOffset": 7545, + "headersEndOffset": 7955, + "endOffset": 7960, + "body": { + "mimeType": "text/plain", + "lineNumber": 191, + "beginOffset": 7545, + "headersEndOffset": 7955, + "endOffset": 7960, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 415, + "lines": 12 + }, + "octets": 415 + }, + "octets": 926, + "lines": 26 + }, + "octets": 926 + }, + "octets": 1496, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 205, + "beginOffset": 7988, + "headersEndOffset": 8041, + "endOffset": 8093, + "octets": 52, + "lines": 1 + } + ], + "octets": 5757, + "lines": 145 + }, + "octets": 5757 + }, + { + "mboxMarkerOffset": 8123, + "lineNumber": 212, + "beginOffset": 8131, + "headersEndOffset": 8602, + "endOffset": 14394, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 212, + "beginOffset": 8131, + "headersEndOffset": 8602, + "endOffset": 14394, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 227, + "beginOffset": 8675, + "headersEndOffset": 8823, + "endOffset": 9288, + "message": { + "lineNumber": 232, + "beginOffset": 8823, + "headersEndOffset": 9251, + "endOffset": 9288, + "body": { + "mimeType": "text/plain", + "lineNumber": 232, + "beginOffset": 8823, + "headersEndOffset": 9251, + "endOffset": 9288, + "octets": 37, + "lines": 2 + }, + "octets": 37 + }, + "octets": 465, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 247, + "beginOffset": 9316, + "headersEndOffset": 9443, + "endOffset": 9901, + "octets": 458, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 259, + "beginOffset": 9929, + "headersEndOffset": 10056, + "endOffset": 10542, + "octets": 486, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 271, + "beginOffset": 10570, + "headersEndOffset": 10701, + "endOffset": 11228, + "octets": 527, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 284, + "beginOffset": 11256, + "headersEndOffset": 11385, + "endOffset": 11883, + "octets": 498, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 296, + "beginOffset": 11911, + "headersEndOffset": 12059, + "endOffset": 12524, + "message": { + "lineNumber": 301, + "beginOffset": 12059, + "headersEndOffset": 12487, + "endOffset": 12524, + "body": { + "mimeType": "text/plain", + "lineNumber": 301, + "beginOffset": 12059, + "headersEndOffset": 12487, + "endOffset": 12524, + "octets": 37, + "lines": 1 + }, + "octets": 37 + }, + "octets": 465, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 315, + "beginOffset": 12552, + "headersEndOffset": 12727, + "endOffset": 14228, + "message": { + "lineNumber": 320, + "beginOffset": 12727, + "headersEndOffset": 13300, + "endOffset": 14228, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 320, + "beginOffset": 12727, + "headersEndOffset": 13300, + "endOffset": 14228, + "message": { + "lineNumber": 335, + "beginOffset": 13300, + "headersEndOffset": 13814, + "endOffset": 14228, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 335, + "beginOffset": 13300, + "headersEndOffset": 13814, + "endOffset": 14228, + "message": { + "lineNumber": 349, + "beginOffset": 13814, + "headersEndOffset": 14223, + "endOffset": 14228, + "body": { + "mimeType": "text/plain", + "lineNumber": 349, + "beginOffset": 13814, + "headersEndOffset": 14223, + "endOffset": 14228, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 414, + "lines": 12 + }, + "octets": 414 + }, + "octets": 928, + "lines": 26 + }, + "octets": 928 + }, + "octets": 1501, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 363, + "beginOffset": 14256, + "headersEndOffset": 14313, + "endOffset": 14365, + "octets": 52, + "lines": 1 + } + ], + "octets": 5792, + "lines": 145 + }, + "octets": 5792 + }, + { + "mboxMarkerOffset": 14395, + "lineNumber": 370, + "beginOffset": 14427, + "headersEndOffset": 15930, + "endOffset": 22485, + "body": { + "mimeType": "multipart/related", + "lineNumber": 370, + "beginOffset": 14427, + "headersEndOffset": 15930, + "endOffset": 22485, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 398, + "beginOffset": 15975, + "headersEndOffset": 16066, + "endOffset": 21265, + "octets": 5199, + "lines": 111 + }, + { + "mimeType": "image/gif", + "lineNumber": 514, + "beginOffset": 21310, + "headersEndOffset": 21509, + "endOffset": 22438, + "octets": 929, + "lines": 13 + } + ], + "octets": 6555, + "lines": 139 + }, + "octets": 6555 + }, + { + "mboxMarkerOffset": 22486, + "lineNumber": 537, + "beginOffset": 22518, + "headersEndOffset": 23752, + "endOffset": 771037, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 537, + "beginOffset": 22518, + "headersEndOffset": 23752, + "endOffset": 771037, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 562, + "beginOffset": 23836, + "headersEndOffset": 23912, + "endOffset": 23939, + "octets": 27, + "lines": 3 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 570, + "beginOffset": 23978, + "headersEndOffset": 24068, + "endOffset": 770996, + "message": { + "lineNumber": 574, + "beginOffset": 24068, + "headersEndOffset": 24889, + "endOffset": 770996, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 574, + "beginOffset": 24068, + "headersEndOffset": 24889, + "endOffset": 770996, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 592, + "beginOffset": 24929, + "headersEndOffset": 25005, + "endOffset": 25632, + "octets": 627, + "lines": 16 + }, + { + "mimeType": "multipart/related", + "lineNumber": 613, + "beginOffset": 25672, + "headersEndOffset": 25754, + "endOffset": 770952, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 617, + "beginOffset": 25794, + "headersEndOffset": 25869, + "endOffset": 26719, + "octets": 850, + "lines": 18 + }, + { + "mimeType": "image/tiff", + "lineNumber": 640, + "beginOffset": 26759, + "headersEndOffset": 26943, + "endOffset": 770910, + "octets": 743967, + "lines": 10192 + } + ], + "octets": 745198, + "lines": 10223 + } + ], + "octets": 746107, + "lines": 10252 + }, + "octets": 746107 + }, + "octets": 746928, + "lines": 10268 + } + ], + "octets": 747285, + "lines": 10285 + }, + "octets": 747285 + }, + { + "mboxMarkerOffset": 771038, + "lineNumber": 10846, + "beginOffset": 771070, + "headersEndOffset": 772334, + "endOffset": 818962, + "body": { + "mimeType": "multipart/related", + "lineNumber": 10846, + "beginOffset": 771070, + "headersEndOffset": 772334, + "endOffset": 818962, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 10870, + "beginOffset": 772379, + "headersEndOffset": 772470, + "endOffset": 774852, + "octets": 2382, + "lines": 50 + }, + { + "mimeType": "image/gif", + "lineNumber": 10925, + "beginOffset": 774897, + "headersEndOffset": 775056, + "endOffset": 781079, + "octets": 6023, + "lines": 79 + }, + { + "mimeType": "image/gif", + "lineNumber": 11011, + "beginOffset": 781124, + "headersEndOffset": 781282, + "endOffset": 793355, + "octets": 12073, + "lines": 157 + }, + { + "mimeType": "image/gif", + "lineNumber": 11175, + "beginOffset": 793400, + "headersEndOffset": 793560, + "endOffset": 815274, + "octets": 21714, + "lines": 282 + }, + { + "mimeType": "image/gif", + "lineNumber": 11464, + "beginOffset": 815319, + "headersEndOffset": 815522, + "endOffset": 818915, + "octets": 3393, + "lines": 45 + } + ], + "octets": 46628, + "lines": 649 + }, + "octets": 46628 + }, + { + "mboxMarkerOffset": 818963, + "lineNumber": 11519, + "beginOffset": 818971, + "headersEndOffset": 819882, + "endOffset": 822461, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11519, + "beginOffset": 818971, + "headersEndOffset": 819882, + "endOffset": 822461, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 11542, + "beginOffset": 819891, + "headersEndOffset": 819920, + "endOffset": 822450, + "octets": 2530, + "lines": 96 + } + ], + "octets": 2579, + "lines": 102 + }, + "octets": 2579 + }, + { + "mboxMarkerOffset": 822462, + "lineNumber": 11644, + "beginOffset": 822494, + "headersEndOffset": 823647, + "endOffset": 825431, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 11644, + "beginOffset": 822494, + "headersEndOffset": 823647, + "endOffset": 825431, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11663, + "beginOffset": 823664, + "headersEndOffset": 823665, + "endOffset": 824566, + "octets": 901, + "lines": 20 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 11686, + "beginOffset": 824584, + "headersEndOffset": 824663, + "endOffset": 825411, + "octets": 748, + "lines": 12 + } + ], + "octets": 1784, + "lines": 41 + }, + "octets": 1784 + }, + { + "mboxMarkerOffset": 825432, + "lineNumber": 11705, + "beginOffset": 825464, + "headersEndOffset": 826606, + "endOffset": 830015, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11705, + "beginOffset": 825464, + "headersEndOffset": 826606, + "endOffset": 830015, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11728, + "beginOffset": 826786, + "headersEndOffset": 826864, + "endOffset": 827605, + "octets": 741, + "lines": 14 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 11746, + "beginOffset": 827613, + "headersEndOffset": 827791, + "endOffset": 830006, + "octets": 2215, + "lines": 31 + } + ], + "octets": 3409, + "lines": 60 + }, + "octets": 3409 + }, + { + "mboxMarkerOffset": 830016, + "lineNumber": 11785, + "beginOffset": 830048, + "headersEndOffset": 831185, + "endOffset": 837039, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 11785, + "beginOffset": 830048, + "headersEndOffset": 831185, + "endOffset": 837039, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 11812, + "beginOffset": 831379, + "headersEndOffset": 831457, + "endOffset": 834269, + "octets": 2812, + "lines": 47 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 11863, + "beginOffset": 834291, + "headersEndOffset": 834469, + "endOffset": 837016, + "octets": 2547, + "lines": 35 + } + ], + "octets": 5854, + "lines": 97 + }, + "octets": 5854 + }, + { + "mboxMarkerOffset": 837040, + "lineNumber": 11906, + "beginOffset": 837072, + "headersEndOffset": 837972, + "endOffset": 853721, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 11906, + "beginOffset": 837072, + "headersEndOffset": 837972, + "endOffset": 853721, + "children": [ + { + "mimeType": "image/jpeg", + "lineNumber": 11927, + "beginOffset": 838045, + "headersEndOffset": 838179, + "endOffset": 848901, + "octets": 10722, + "lines": 147 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12079, + "beginOffset": 848929, + "headersEndOffset": 849080, + "endOffset": 853691, + "octets": 4611, + "lines": 64 + } + ], + "octets": 15749, + "lines": 224 + }, + "octets": 15749 + }, + { + "mboxMarkerOffset": 853722, + "lineNumber": 12150, + "beginOffset": 853754, + "headersEndOffset": 855145, + "endOffset": 856576, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12150, + "beginOffset": 853754, + "headersEndOffset": 855145, + "endOffset": 856576, + "octets": 1431, + "lines": 20 + }, + "octets": 1431 + }, + { + "mboxMarkerOffset": 856577, + "lineNumber": 12195, + "beginOffset": 856609, + "headersEndOffset": 857962, + "endOffset": 862354, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12195, + "beginOffset": 856609, + "headersEndOffset": 857962, + "endOffset": 862354, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12221, + "beginOffset": 858007, + "headersEndOffset": 858071, + "endOffset": 858178, + "octets": 107, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12229, + "beginOffset": 858223, + "headersEndOffset": 858374, + "endOffset": 862307, + "octets": 3933, + "lines": 54 + } + ], + "octets": 4392, + "lines": 69 + }, + "octets": 4392 + }, + { + "mboxMarkerOffset": 862355, + "lineNumber": 12290, + "beginOffset": 862387, + "headersEndOffset": 863597, + "endOffset": 867092, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12290, + "beginOffset": 862387, + "headersEndOffset": 863597, + "endOffset": 867092, + "octets": 3495, + "lines": 55 + }, + "octets": 3495 + }, + { + "mboxMarkerOffset": 867093, + "lineNumber": 12368, + "beginOffset": 867125, + "headersEndOffset": 868202, + "endOffset": 868863, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12368, + "beginOffset": 867125, + "headersEndOffset": 868202, + "endOffset": 868863, + "octets": 661, + "lines": 10 + }, + "octets": 661 + }, + { + "mboxMarkerOffset": 868864, + "lineNumber": 12400, + "beginOffset": 868896, + "headersEndOffset": 869679, + "endOffset": 872491, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 12400, + "beginOffset": 868896, + "headersEndOffset": 869679, + "endOffset": 872491, + "message": { + "lineNumber": 12419, + "beginOffset": 869679, + "headersEndOffset": 871059, + "endOffset": 872491, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12419, + "beginOffset": 869679, + "headersEndOffset": 871059, + "endOffset": 872491, + "octets": 1432, + "lines": 20 + }, + "octets": 1432 + }, + "octets": 2812, + "lines": 43 + }, + "octets": 2812 + }, + { + "mboxMarkerOffset": 872492, + "lineNumber": 12464, + "beginOffset": 872524, + "headersEndOffset": 873234, + "endOffset": 876422, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 12464, + "beginOffset": 872524, + "headersEndOffset": 873234, + "endOffset": 876422, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12484, + "beginOffset": 873307, + "headersEndOffset": 873383, + "endOffset": 873398, + "octets": 15, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 12490, + "beginOffset": 873426, + "headersEndOffset": 873580, + "endOffset": 876392, + "message": { + "lineNumber": 12494, + "beginOffset": 873580, + "headersEndOffset": 874960, + "endOffset": 876392, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12494, + "beginOffset": 873580, + "headersEndOffset": 874960, + "endOffset": 876392, + "octets": 1432, + "lines": 20 + }, + "octets": 1432 + }, + "octets": 2812, + "lines": 43 + } + ], + "octets": 3188, + "lines": 58 + }, + "octets": 3188 + }, + { + "mboxMarkerOffset": 876423, + "lineNumber": 12541, + "beginOffset": 876455, + "headersEndOffset": 877120, + "endOffset": 883131, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12541, + "beginOffset": 876455, + "headersEndOffset": 877120, + "endOffset": 883131, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12560, + "beginOffset": 877221, + "headersEndOffset": 877297, + "endOffset": 877338, + "octets": 41, + "lines": 2 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12566, + "beginOffset": 877380, + "headersEndOffset": 877531, + "endOffset": 883087, + "octets": 5556, + "lines": 77 + } + ], + "octets": 6011, + "lines": 91 + }, + "octets": 6011 + }, + { + "mboxMarkerOffset": 883132, + "lineNumber": 12650, + "beginOffset": 883164, + "headersEndOffset": 884226, + "endOffset": 894462, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12650, + "beginOffset": 883164, + "headersEndOffset": 884226, + "endOffset": 894462, + "octets": 10236, + "lines": 141 + }, + "octets": 10236 + }, + { + "mboxMarkerOffset": 894463, + "lineNumber": 12813, + "beginOffset": 894495, + "headersEndOffset": 895871, + "endOffset": 898684, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 12813, + "beginOffset": 894495, + "headersEndOffset": 895871, + "endOffset": 898684, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 12840, + "beginOffset": 895972, + "headersEndOffset": 896048, + "endOffset": 896659, + "octets": 611, + "lines": 17 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 12861, + "beginOffset": 896701, + "headersEndOffset": 896852, + "endOffset": 898640, + "octets": 1788, + "lines": 25 + } + ], + "octets": 2813, + "lines": 54 + }, + "octets": 2813 + }, + { + "mboxMarkerOffset": 898685, + "lineNumber": 12893, + "beginOffset": 898717, + "headersEndOffset": 899265, + "endOffset": 899788, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12893, + "beginOffset": 898717, + "headersEndOffset": 899265, + "endOffset": 899788, + "octets": 523, + "lines": 8 + }, + "octets": 523 + }, + { + "mboxMarkerOffset": 899789, + "lineNumber": 12917, + "beginOffset": 899821, + "headersEndOffset": 901036, + "endOffset": 903918, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 12917, + "beginOffset": 899821, + "headersEndOffset": 901036, + "endOffset": 903918, + "octets": 2882, + "lines": 38 + }, + "octets": 2882 + }, + { + "mboxMarkerOffset": 903919, + "lineNumber": 12977, + "beginOffset": 903951, + "headersEndOffset": 905109, + "endOffset": 907231, + "body": { + "mimeType": "Application/x-pkcs7-mime", + "lineNumber": 12977, + "beginOffset": 903951, + "headersEndOffset": 905109, + "endOffset": 907231, + "octets": 2122, + "lines": 30 + }, + "octets": 2122 + }, + { + "mboxMarkerOffset": 907232, + "lineNumber": 13030, + "beginOffset": 907264, + "headersEndOffset": 908342, + "endOffset": 911299, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13030, + "beginOffset": 907264, + "headersEndOffset": 908342, + "endOffset": 911299, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13053, + "beginOffset": 908375, + "headersEndOffset": 908439, + "endOffset": 908439, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13058, + "beginOffset": 908472, + "headersEndOffset": 908551, + "endOffset": 911264, + "octets": 2713, + "lines": 42 + } + ], + "octets": 2957, + "lines": 53 + }, + "octets": 2957 + }, + { + "mboxMarkerOffset": 911300, + "lineNumber": 13106, + "beginOffset": 911332, + "headersEndOffset": 912369, + "endOffset": 915249, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 13106, + "beginOffset": 911332, + "headersEndOffset": 912369, + "endOffset": 915249, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13127, + "beginOffset": 912410, + "headersEndOffset": 912488, + "endOffset": 912941, + "octets": 453, + "lines": 14 + }, + { + "mimeType": "text/html", + "lineNumber": 13145, + "beginOffset": 912982, + "headersEndOffset": 913057, + "endOffset": 913868, + "octets": 811, + "lines": 27 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13176, + "beginOffset": 913909, + "headersEndOffset": 914006, + "endOffset": 915206, + "octets": 1200, + "lines": 16 + } + ], + "octets": 2880, + "lines": 72 + }, + "octets": 2880 + }, + { + "mboxMarkerOffset": 915250, + "lineNumber": 13199, + "beginOffset": 915282, + "headersEndOffset": 916357, + "endOffset": 920885, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13199, + "beginOffset": 915282, + "headersEndOffset": 916357, + "endOffset": 920885, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13222, + "beginOffset": 916400, + "headersEndOffset": 916470, + "endOffset": 916622, + "octets": 152, + "lines": 7 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13234, + "beginOffset": 916665, + "headersEndOffset": 916744, + "endOffset": 920840, + "octets": 4096, + "lines": 57 + } + ], + "octets": 4528, + "lines": 75 + }, + "octets": 4528 + }, + { + "mboxMarkerOffset": 920886, + "lineNumber": 13297, + "beginOffset": 920918, + "headersEndOffset": 922020, + "endOffset": 926071, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 13297, + "beginOffset": 920918, + "headersEndOffset": 922020, + "endOffset": 926071, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13320, + "beginOffset": 922054, + "headersEndOffset": 922132, + "endOffset": 922206, + "octets": 74, + "lines": 5 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 13329, + "beginOffset": 922240, + "headersEndOffset": 922319, + "endOffset": 926036, + "octets": 3717, + "lines": 58 + } + ], + "octets": 4051, + "lines": 73 + }, + "octets": 4051 + }, + { + "mboxMarkerOffset": 926072, + "lineNumber": 13392, + "beginOffset": 926104, + "headersEndOffset": 927232, + "endOffset": 928495, + "body": { + "mimeType": "multipart/report", + "lineNumber": 13392, + "beginOffset": 926104, + "headersEndOffset": 927232, + "endOffset": 928495, + "children": [ + { + "mimeType": "message/delivery-status", + "lineNumber": 13414, + "beginOffset": 927369, + "headersEndOffset": 927408, + "endOffset": 927596, + "octets": 188, + "lines": 6 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 13424, + "beginOffset": 927621, + "headersEndOffset": 927651, + "endOffset": 928468, + "message": { + "lineNumber": 13426, + "beginOffset": 927651, + "headersEndOffset": 928457, + "endOffset": 928468, + "body": { + "mimeType": "text/plain", + "lineNumber": 13426, + "beginOffset": 927651, + "headersEndOffset": 928457, + "endOffset": 928468, + "octets": 11, + "lines": 1 + }, + "octets": 11 + }, + "octets": 817, + "lines": 16 + } + ], + "octets": 1263, + "lines": 34 + }, + "octets": 1263 + }, + { + "mboxMarkerOffset": 928496, + "lineNumber": 13445, + "beginOffset": 928528, + "headersEndOffset": 930393, + "endOffset": 935272, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 13445, + "beginOffset": 928528, + "headersEndOffset": 930393, + "endOffset": 935272, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 13477, + "beginOffset": 930437, + "headersEndOffset": 930515, + "endOffset": 931378, + "octets": 863, + "lines": 18 + }, + { + "mimeType": "application/vcard", + "lineNumber": 13500, + "beginOffset": 931423, + "headersEndOffset": 931584, + "endOffset": 935225, + "octets": 3641, + "lines": 61 + } + ], + "octets": 4879, + "lines": 92 + }, + "octets": 4879 + } +] \ No newline at end of file diff --git a/UnitTests/TestData/mbox/jwz-summary.txt b/UnitTests/TestData/mbox/jwz-summary.txt index 5b1b29c725..83e0ab6200 100644 --- a/UnitTests/TestData/mbox/jwz-summary.txt +++ b/UnitTests/TestData/mbox/jwz-summary.txt @@ -1,5 +1,5 @@ From - -From: nsb +From: "Nathaniel Borenstein" To: abel, bianchi, braun, cameron, carmen, jfp, jxr, kraut, lamb, lowery, lynn, mlittman, nancyg, sau, shoshi, slr, stornett@flash, tkl Subject: Star Trek Party! Date: Thu, 19 Sep 1991 12:41:43 -0400 @@ -540,7 +540,7 @@ Content-Type: multipart/alternative Content-Type: text/richtext From - -From: nsb +From: "Nathaniel Borenstein" To: dnd Subject: Re: Happy New Year Date: Tue, 29 Sep 1992 10:19:23 -0400 @@ -739,7 +739,7 @@ Content-Type: multipart/mixed Content-Type: text/plain From - -From: devetzis +From: "Taso N. Devetzis" To: nsb Subject: greek mail Date: Tue, 16 Jun 1992 20:33:31 -0400 @@ -1195,7 +1195,7 @@ Content-Type: MESSAGE/RFC822 Content-Type: TEXT/PLAIN From - -From: nsb +From: "Nathaniel Borenstein" To: "David A. Braun" , "John Lamb" , "Michael Littman" Subject: Singing today? Date: Thu, 12 Dec 1991 11:38:21 -0500 diff --git a/UnitTests/TestData/mbox/jwz.dos-offsets.json b/UnitTests/TestData/mbox/jwz.dos-offsets.json new file mode 100644 index 0000000000..cfbdf12a11 --- /dev/null +++ b/UnitTests/TestData/mbox/jwz.dos-offsets.json @@ -0,0 +1,9567 @@ +[ + { + "mboxMarkerOffset": 0, + "lineNumber": 2, + "beginOffset": 9, + "headersEndOffset": 531, + "endOffset": 181624, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 2, + "beginOffset": 9, + "headersEndOffset": 531, + "endOffset": 181624, + "children": [ + { + "mimeType": "multipart/parallel", + "lineNumber": 16, + "beginOffset": 549, + "headersEndOffset": 648, + "endOffset": 33041, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 20, + "beginOffset": 680, + "headersEndOffset": 682, + "endOffset": 1413, + "octets": 731, + "lines": 17 + }, + { + "mimeType": "audio/basic", + "lineNumber": 39, + "beginOffset": 1447, + "headersEndOffset": 1535, + "endOffset": 33007, + "octets": 31472, + "lines": 426 + } + ], + "octets": 32393, + "lines": 452 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 472, + "beginOffset": 33061, + "headersEndOffset": 33157, + "endOffset": 133672, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 476, + "beginOffset": 33189, + "headersEndOffset": 33275, + "endOffset": 59275, + "octets": 26000, + "lines": 352 + }, + { + "mimeType": "image/gif", + "lineNumber": 834, + "beginOffset": 59309, + "headersEndOffset": 59395, + "endOffset": 78061, + "octets": 18666, + "lines": 253 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 1093, + "beginOffset": 78095, + "headersEndOffset": 78212, + "endOffset": 124337, + "octets": 46125, + "lines": 2437 + }, + { + "mimeType": "application/atomicmail", + "lineNumber": 3534, + "beginOffset": 124371, + "headersEndOffset": 124435, + "endOffset": 133638, + "octets": 9203, + "lines": 357 + } + ], + "octets": 100515, + "lines": 3421 + }, + { + "mimeType": "audio/basic", + "lineNumber": 3897, + "beginOffset": 133692, + "headersEndOffset": 133780, + "endOffset": 181602, + "octets": 47822, + "lines": 647 + } + ], + "octets": 181093, + "lines": 4535 + }, + "octets": 181093 + }, + { + "mboxMarkerOffset": 181626, + "lineNumber": 4552, + "beginOffset": 181635, + "headersEndOffset": 182198, + "endOffset": 319322, + "body": { + "mimeType": "audio/basic", + "lineNumber": 4552, + "beginOffset": 181635, + "headersEndOffset": 182198, + "endOffset": 319322, + "octets": 137124, + "lines": 1854 + }, + "octets": 137124 + }, + { + "mboxMarkerOffset": 319324, + "lineNumber": 6422, + "beginOffset": 319333, + "headersEndOffset": 319720, + "endOffset": 319924, + "body": { + "mimeType": "text/plain", + "lineNumber": 6422, + "beginOffset": 319333, + "headersEndOffset": 319720, + "endOffset": 319924, + "octets": 204, + "lines": 4 + }, + "octets": 204 + }, + { + "mboxMarkerOffset": 319926, + "lineNumber": 6435, + "beginOffset": 319935, + "headersEndOffset": 320596, + "endOffset": 326365, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 6435, + "beginOffset": 319935, + "headersEndOffset": 320596, + "endOffset": 326365, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6454, + "beginOffset": 320795, + "headersEndOffset": 320841, + "endOffset": 321080, + "octets": 239, + "lines": 6 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 6464, + "beginOffset": 321123, + "headersEndOffset": 321211, + "endOffset": 326322, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6468, + "beginOffset": 321254, + "headersEndOffset": 321348, + "endOffset": 321497, + "octets": 149, + "lines": 3 + }, + { + "mimeType": "image/gif", + "lineNumber": 6476, + "beginOffset": 321542, + "headersEndOffset": 321656, + "endOffset": 326088, + "octets": 4432, + "lines": 64 + }, + { + "mimeType": "text/richtext", + "lineNumber": 6546, + "beginOffset": 326133, + "headersEndOffset": 326227, + "endOffset": 326275, + "octets": 48, + "lines": 3 + } + ], + "octets": 5111, + "lines": 87 + } + ], + "octets": 5769, + "lines": 106 + }, + "octets": 5769 + }, + { + "mboxMarkerOffset": 326367, + "lineNumber": 6557, + "beginOffset": 326376, + "headersEndOffset": 327141, + "endOffset": 350773, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 6557, + "beginOffset": 326376, + "headersEndOffset": 327141, + "endOffset": 350773, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6579, + "beginOffset": 327403, + "headersEndOffset": 327479, + "endOffset": 327915, + "octets": 436, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 6596, + "beginOffset": 327980, + "headersEndOffset": 328012, + "endOffset": 350454, + "message": { + "lineNumber": 6598, + "beginOffset": 328012, + "headersEndOffset": 328864, + "endOffset": 350454, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 6598, + "beginOffset": 328012, + "headersEndOffset": 328864, + "endOffset": 350454, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6623, + "beginOffset": 329179, + "headersEndOffset": 329276, + "endOffset": 329386, + "octets": 110, + "lines": 6 + }, + { + "mimeType": "audio/basic", + "lineNumber": 6634, + "beginOffset": 329419, + "headersEndOffset": 329511, + "endOffset": 350421, + "octets": 20910, + "lines": 283 + }, + { + "mimeType": "text/plain", + "lineNumber": 6922, + "beginOffset": 350454, + "headersEndOffset": 350454, + "endOffset": 350454, + "octets": 0, + "lines": 0 + } + ], + "octets": 21590, + "lines": 308 + }, + "octets": 21590 + }, + "octets": 22442, + "lines": 324 + }, + { + "mimeType": "text/richtext", + "lineNumber": 6924, + "beginOffset": 350519, + "headersEndOffset": 350595, + "endOffset": 350706, + "octets": 111, + "lines": 4 + } + ], + "octets": 23632, + "lines": 359 + }, + "octets": 23632 + }, + { + "mboxMarkerOffset": 350775, + "lineNumber": 6935, + "beginOffset": 350784, + "headersEndOffset": 351518, + "endOffset": 2139219, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 6935, + "beginOffset": 350784, + "headersEndOffset": 351518, + "endOffset": 2139219, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6955, + "beginOffset": 351717, + "headersEndOffset": 351763, + "endOffset": 352541, + "octets": 778, + "lines": 18 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 6977, + "beginOffset": 352584, + "headersEndOffset": 352672, + "endOffset": 2139176, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6981, + "beginOffset": 352715, + "headersEndOffset": 352809, + "endOffset": 353038, + "octets": 229, + "lines": 4 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 6990, + "beginOffset": 353083, + "headersEndOffset": 353195, + "endOffset": 1037241, + "octets": 684046, + "lines": 8982 + }, + { + "mimeType": "text/richtext", + "lineNumber": 15978, + "beginOffset": 1037286, + "headersEndOffset": 1037380, + "endOffset": 1037501, + "octets": 121, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 15988, + "beginOffset": 1037546, + "headersEndOffset": 1037676, + "endOffset": 1727872, + "octets": 690196, + "lines": 9060 + }, + { + "mimeType": "text/richtext", + "lineNumber": 25054, + "beginOffset": 1727917, + "headersEndOffset": 1728011, + "endOffset": 1728023, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 25061, + "beginOffset": 1728068, + "headersEndOffset": 1728189, + "endOffset": 1797301, + "octets": 69112, + "lines": 934 + }, + { + "mimeType": "text/richtext", + "lineNumber": 26001, + "beginOffset": 1797346, + "headersEndOffset": 1797440, + "endOffset": 1797583, + "octets": 143, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 26011, + "beginOffset": 1797628, + "headersEndOffset": 1797750, + "endOffset": 2138984, + "octets": 341234, + "lines": 4472 + }, + { + "mimeType": "text/richtext", + "lineNumber": 30489, + "beginOffset": 2139029, + "headersEndOffset": 2139123, + "endOffset": 2139129, + "octets": 6, + "lines": 1 + } + ], + "octets": 1786504, + "lines": 23515 + } + ], + "octets": 1787701, + "lines": 23546 + }, + "octets": 1787701 + }, + { + "mboxMarkerOffset": 2139221, + "lineNumber": 30498, + "beginOffset": 2139230, + "headersEndOffset": 2140267, + "endOffset": 2141431, + "body": { + "mimeType": "text/plain", + "lineNumber": 30498, + "beginOffset": 2139230, + "headersEndOffset": 2140267, + "endOffset": 2141431, + "octets": 1164, + "lines": 39 + }, + "octets": 1164 + }, + { + "mboxMarkerOffset": 2141433, + "lineNumber": 30560, + "beginOffset": 2141442, + "headersEndOffset": 2141689, + "endOffset": 2307345, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 30560, + "beginOffset": 2141442, + "headersEndOffset": 2141689, + "endOffset": 2307345, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 30570, + "beginOffset": 2141705, + "headersEndOffset": 2141707, + "endOffset": 2142012, + "octets": 305, + "lines": 6 + }, + { + "mimeType": "multipart/parallel", + "lineNumber": 30578, + "beginOffset": 2142030, + "headersEndOffset": 2142109, + "endOffset": 2302335, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 30582, + "beginOffset": 2142126, + "headersEndOffset": 2142207, + "endOffset": 2145483, + "octets": 3276, + "lines": 17 + }, + { + "mimeType": "audio/basic", + "lineNumber": 30604, + "beginOffset": 2145502, + "headersEndOffset": 2145610, + "endOffset": 2302316, + "octets": 156706, + "lines": 808 + } + ], + "octets": 160226, + "lines": 837 + }, + { + "mimeType": "application/atomicmail", + "lineNumber": 31419, + "beginOffset": 2302353, + "headersEndOffset": 2302412, + "endOffset": 2307327, + "octets": 4915, + "lines": 195 + } + ], + "octets": 165656, + "lines": 1050 + }, + "octets": 165656 + }, + { + "mboxMarkerOffset": 2307347, + "lineNumber": 31620, + "beginOffset": 2307356, + "headersEndOffset": 2308328, + "endOffset": 2655844, + "body": { + "mimeType": "audio/basic", + "lineNumber": 31620, + "beginOffset": 2307356, + "headersEndOffset": 2308328, + "endOffset": 2655844, + "octets": 347516, + "lines": 4456 + }, + "octets": 347516 + }, + { + "mboxMarkerOffset": 2655846, + "lineNumber": 36098, + "beginOffset": 2655855, + "headersEndOffset": 2655994, + "endOffset": 2688506, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 36098, + "beginOffset": 2655855, + "headersEndOffset": 2655994, + "endOffset": 2688506, + "children": [ + { + "mimeType": "multipart/parallel", + "lineNumber": 36104, + "beginOffset": 2656012, + "headersEndOffset": 2656087, + "endOffset": 2688486, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 36107, + "beginOffset": 2656119, + "headersEndOffset": 2656121, + "endOffset": 2656845, + "octets": 724, + "lines": 18 + }, + { + "mimeType": "audio/basic", + "lineNumber": 36127, + "beginOffset": 2656879, + "headersEndOffset": 2656980, + "endOffset": 2688452, + "octets": 31472, + "lines": 426 + } + ], + "octets": 32399, + "lines": 453 + } + ], + "octets": 32512, + "lines": 457 + }, + "octets": 32512 + }, + { + "mboxMarkerOffset": 2688508, + "lineNumber": 36561, + "beginOffset": 2688517, + "headersEndOffset": 2689088, + "endOffset": 2746649, + "body": { + "mimeType": "image/pbm", + "lineNumber": 36561, + "beginOffset": 2688517, + "headersEndOffset": 2689088, + "endOffset": 2746649, + "octets": 57561, + "lines": 782 + }, + "octets": 57561 + }, + { + "mboxMarkerOffset": 2746651, + "lineNumber": 37359, + "beginOffset": 2746660, + "headersEndOffset": 2747410, + "endOffset": 2779395, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 37359, + "beginOffset": 2746660, + "headersEndOffset": 2747410, + "endOffset": 2779395, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37385, + "beginOffset": 2748003, + "headersEndOffset": 2748005, + "endOffset": 2748571, + "octets": 566, + "lines": 14 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 37402, + "beginOffset": 2748632, + "headersEndOffset": 2748738, + "endOffset": 2779334, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 37406, + "beginOffset": 2748799, + "headersEndOffset": 2748875, + "endOffset": 2749301, + "octets": 426, + "lines": 7 + }, + { + "mimeType": "image/xwd", + "lineNumber": 37418, + "beginOffset": 2749364, + "headersEndOffset": 2749426, + "endOffset": 2779088, + "octets": 29662, + "lines": 401 + }, + { + "mimeType": "text/plain", + "lineNumber": 37824, + "beginOffset": 2779151, + "headersEndOffset": 2779224, + "endOffset": 2779269, + "octets": 45, + "lines": 4 + } + ], + "octets": 30596, + "lines": 428 + } + ], + "octets": 31985, + "lines": 459 + }, + "octets": 31985 + }, + { + "mboxMarkerOffset": 2779397, + "lineNumber": 37836, + "beginOffset": 2779406, + "headersEndOffset": 2780075, + "endOffset": 2785076, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 37836, + "beginOffset": 2779406, + "headersEndOffset": 2780075, + "endOffset": 2785076, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37860, + "beginOffset": 2780452, + "headersEndOffset": 2780454, + "endOffset": 2781302, + "octets": 848, + "lines": 27 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 37890, + "beginOffset": 2781334, + "headersEndOffset": 2781410, + "endOffset": 2785042, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37894, + "beginOffset": 2781442, + "headersEndOffset": 2781470, + "endOffset": 2781612, + "octets": 142, + "lines": 6 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 37903, + "beginOffset": 2781646, + "headersEndOffset": 2781714, + "endOffset": 2782928, + "octets": 1214, + "lines": 17 + }, + { + "mimeType": "text/plain", + "lineNumber": 37925, + "beginOffset": 2782962, + "headersEndOffset": 2782990, + "endOffset": 2783058, + "octets": 68, + "lines": 1 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 37929, + "beginOffset": 2783092, + "headersEndOffset": 2783160, + "endOffset": 2784382, + "octets": 1222, + "lines": 17 + }, + { + "mimeType": "text/richtext", + "lineNumber": 37951, + "beginOffset": 2784416, + "headersEndOffset": 2784447, + "endOffset": 2785006, + "octets": 559, + "lines": 14 + } + ], + "octets": 3632, + "lines": 75 + } + ], + "octets": 5001, + "lines": 118 + }, + "octets": 5001 + }, + { + "mboxMarkerOffset": 2785078, + "lineNumber": 37972, + "beginOffset": 2785087, + "headersEndOffset": 2786084, + "endOffset": 2787498, + "body": { + "mimeType": "text/plain", + "lineNumber": 37972, + "beginOffset": 2785087, + "headersEndOffset": 2786084, + "endOffset": 2787498, + "octets": 1414, + "lines": 32 + }, + "octets": 1414 + }, + { + "mboxMarkerOffset": 2787500, + "lineNumber": 38027, + "beginOffset": 2787509, + "headersEndOffset": 2787772, + "endOffset": 2788033, + "body": { + "mimeType": "text/plain", + "lineNumber": 38027, + "beginOffset": 2787509, + "headersEndOffset": 2787772, + "endOffset": 2788033, + "octets": 261, + "lines": 6 + }, + "octets": 261 + }, + { + "mboxMarkerOffset": 2788035, + "lineNumber": 38041, + "beginOffset": 2788044, + "headersEndOffset": 2788716, + "endOffset": 2789453, + "body": { + "mimeType": "text/plain", + "lineNumber": 38041, + "beginOffset": 2788044, + "headersEndOffset": 2788716, + "endOffset": 2789453, + "octets": 737, + "lines": 14 + }, + "octets": 737 + }, + { + "mboxMarkerOffset": 2789455, + "lineNumber": 38071, + "beginOffset": 2789464, + "headersEndOffset": 2790463, + "endOffset": 3227750, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 38071, + "beginOffset": 2789464, + "headersEndOffset": 2790463, + "endOffset": 3227750, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 38088, + "beginOffset": 2790507, + "headersEndOffset": 2790555, + "endOffset": 2790632, + "octets": 77, + "lines": 5 + }, + { + "mimeType": "multipart/appledouble", + "lineNumber": 38097, + "beginOffset": 2790674, + "headersEndOffset": 2790763, + "endOffset": 3227708, + "children": [ + { + "mimeType": "application/applefile", + "lineNumber": 38102, + "beginOffset": 2790808, + "headersEndOffset": 2790967, + "endOffset": 2857841, + "octets": 66874, + "lines": 957 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 39065, + "beginOffset": 2857884, + "headersEndOffset": 2858099, + "endOffset": 3227661, + "octets": 369562, + "lines": 5281 + } + ], + "octets": 436945, + "lines": 6256 + } + ], + "octets": 437287, + "lines": 6272 + }, + "octets": 437287 + }, + { + "mboxMarkerOffset": 3227752, + "lineNumber": 44358, + "beginOffset": 3227761, + "headersEndOffset": 3228760, + "endOffset": 3666046, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 44358, + "beginOffset": 3227761, + "headersEndOffset": 3228760, + "endOffset": 3666046, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 44375, + "beginOffset": 3228804, + "headersEndOffset": 3228852, + "endOffset": 3228929, + "octets": 77, + "lines": 5 + }, + { + "mimeType": "multipart/header-set", + "lineNumber": 44384, + "beginOffset": 3228971, + "headersEndOffset": 3229059, + "endOffset": 3666004, + "children": [ + { + "mimeType": "application/applefile", + "lineNumber": 44389, + "beginOffset": 3229104, + "headersEndOffset": 3229263, + "endOffset": 3296137, + "octets": 66874, + "lines": 957 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 45352, + "beginOffset": 3296180, + "headersEndOffset": 3296395, + "endOffset": 3665957, + "octets": 369562, + "lines": 5281 + } + ], + "octets": 436945, + "lines": 6256 + } + ], + "octets": 437286, + "lines": 6272 + }, + "octets": 437286 + }, + { + "mboxMarkerOffset": 3666048, + "lineNumber": 50645, + "beginOffset": 3666057, + "headersEndOffset": 3666630, + "endOffset": 3667232, + "body": { + "mimeType": "Message/rfc822", + "lineNumber": 50645, + "beginOffset": 3666057, + "headersEndOffset": 3666630, + "endOffset": 3667232, + "message": { + "lineNumber": 50660, + "beginOffset": 3666630, + "headersEndOffset": 3666692, + "endOffset": 3667232, + "body": { + "mimeType": "text/plain", + "lineNumber": 50660, + "beginOffset": 3666630, + "headersEndOffset": 3666692, + "endOffset": 3667232, + "octets": 540, + "lines": 14 + }, + "octets": 540 + }, + "octets": 602, + "lines": 17 + }, + "octets": 602 + }, + { + "mboxMarkerOffset": 3667234, + "lineNumber": 50678, + "beginOffset": 3667243, + "headersEndOffset": 3667974, + "endOffset": 3669418, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50678, + "beginOffset": 3667243, + "headersEndOffset": 3667974, + "endOffset": 3669418, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50698, + "beginOffset": 3668020, + "headersEndOffset": 3668048, + "endOffset": 3668234, + "octets": 186, + "lines": 6 + }, + { + "mimeType": "application/postscript", + "lineNumber": 50708, + "beginOffset": 3668280, + "headersEndOffset": 3668355, + "endOffset": 3669259, + "octets": 904, + "lines": 12 + } + ], + "octets": 1444, + "lines": 33 + }, + "octets": 1444 + }, + { + "mboxMarkerOffset": 3669420, + "lineNumber": 50731, + "beginOffset": 3669429, + "headersEndOffset": 3669982, + "endOffset": 3674811, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50731, + "beginOffset": 3669429, + "headersEndOffset": 3669982, + "endOffset": 3674811, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50748, + "beginOffset": 3670061, + "headersEndOffset": 3670063, + "endOffset": 3670465, + "octets": 402, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 50761, + "beginOffset": 3670507, + "headersEndOffset": 3670539, + "endOffset": 3674767, + "message": { + "lineNumber": 50763, + "beginOffset": 3670539, + "headersEndOffset": 3671342, + "endOffset": 3674767, + "body": { + "mimeType": "text/plain", + "lineNumber": 50763, + "beginOffset": 3670539, + "headersEndOffset": 3671342, + "endOffset": 3674767, + "octets": 3425, + "lines": 72 + }, + "octets": 3425 + }, + "octets": 4228, + "lines": 88 + } + ], + "octets": 4829, + "lines": 108 + }, + "octets": 4829 + }, + { + "mboxMarkerOffset": 3674813, + "lineNumber": 50855, + "beginOffset": 3674822, + "headersEndOffset": 3675488, + "endOffset": 3676752, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50855, + "beginOffset": 3674822, + "headersEndOffset": 3675488, + "endOffset": 3676752, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50873, + "beginOffset": 3675538, + "headersEndOffset": 3675566, + "endOffset": 3675644, + "octets": 78, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 50881, + "beginOffset": 3675696, + "headersEndOffset": 3675761, + "endOffset": 3676700, + "message": { + "lineNumber": 50884, + "beginOffset": 3675761, + "headersEndOffset": 3676560, + "endOffset": 3676700, + "body": { + "mimeType": "text/plain", + "lineNumber": 50884, + "beginOffset": 3675761, + "headersEndOffset": 3676560, + "endOffset": 3676700, + "octets": 140, + "lines": 4 + }, + "octets": 140 + }, + "octets": 939, + "lines": 21 + } + ], + "octets": 1264, + "lines": 34 + }, + "octets": 1264 + }, + { + "mboxMarkerOffset": 3676754, + "lineNumber": 50907, + "beginOffset": 3676763, + "headersEndOffset": 3677286, + "endOffset": 3678750, + "body": { + "mimeType": "Application/octet-stream", + "lineNumber": 50907, + "beginOffset": 3676763, + "headersEndOffset": 3677286, + "endOffset": 3678750, + "octets": 1464, + "lines": 45 + }, + "octets": 1464 + }, + { + "mboxMarkerOffset": 3678752, + "lineNumber": 50967, + "beginOffset": 3678804, + "headersEndOffset": 3679391, + "endOffset": 3740046, + "body": { + "mimeType": "message/partial", + "lineNumber": 50967, + "beginOffset": 3678804, + "headersEndOffset": 3679391, + "endOffset": 3740046, + "octets": 60655, + "lines": 954 + }, + "octets": 60655 + }, + { + "mboxMarkerOffset": 3740048, + "lineNumber": 51938, + "beginOffset": 3740100, + "headersEndOffset": 3740684, + "endOffset": 3801451, + "body": { + "mimeType": "message/partial", + "lineNumber": 51938, + "beginOffset": 3740100, + "headersEndOffset": 3740684, + "endOffset": 3801451, + "octets": 60767, + "lines": 960 + }, + "octets": 60767 + }, + { + "mboxMarkerOffset": 3801453, + "lineNumber": 52915, + "beginOffset": 3801462, + "headersEndOffset": 3802023, + "endOffset": 3802919, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 52915, + "beginOffset": 3801462, + "headersEndOffset": 3802023, + "endOffset": 3802919, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 52930, + "beginOffset": 3802041, + "headersEndOffset": 3802070, + "endOffset": 3802145, + "octets": 75, + "lines": 4 + }, + { + "mimeType": "text/plain", + "lineNumber": 52938, + "beginOffset": 3802163, + "headersEndOffset": 3802247, + "endOffset": 3802897, + "octets": 650, + "lines": 9 + } + ], + "octets": 896, + "lines": 25 + }, + "octets": 896 + }, + { + "mboxMarkerOffset": 3802921, + "lineNumber": 52955, + "beginOffset": 3802930, + "headersEndOffset": 3803695, + "endOffset": 3845795, + "body": { + "mimeType": "image/gif", + "lineNumber": 52955, + "beginOffset": 3802930, + "headersEndOffset": 3803695, + "endOffset": 3845795, + "octets": 42100, + "lines": 570 + }, + "octets": 42100 + }, + { + "mboxMarkerOffset": 3845797, + "lineNumber": 53545, + "beginOffset": 3845806, + "headersEndOffset": 3846985, + "endOffset": 3855393, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 53545, + "beginOffset": 3845806, + "headersEndOffset": 3846985, + "endOffset": 3855393, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 53571, + "beginOffset": 3846991, + "headersEndOffset": 3846993, + "endOffset": 3848958, + "octets": 1965, + "lines": 43 + }, + { + "mimeType": "image/gif", + "lineNumber": 53617, + "beginOffset": 3848966, + "headersEndOffset": 3849075, + "endOffset": 3855383, + "octets": 6308, + "lines": 86 + } + ], + "octets": 8408, + "lines": 139 + }, + "octets": 8408 + }, + { + "mboxMarkerOffset": 3855395, + "lineNumber": 53711, + "beginOffset": 3855404, + "headersEndOffset": 3856880, + "endOffset": 3965263, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 53711, + "beginOffset": 3855404, + "headersEndOffset": 3856880, + "endOffset": 3965263, + "octets": 108383, + "lines": 1570 + }, + "octets": 108383 + }, + { + "mboxMarkerOffset": 3965265, + "lineNumber": 55311, + "beginOffset": 3965274, + "headersEndOffset": 3965889, + "endOffset": 3969308, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55311, + "beginOffset": 3965274, + "headersEndOffset": 3965889, + "endOffset": 3969308, + "message": { + "lineNumber": 55327, + "beginOffset": 3965889, + "headersEndOffset": 3966475, + "endOffset": 3969308, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55327, + "beginOffset": 3965889, + "headersEndOffset": 3966475, + "endOffset": 3969308, + "message": { + "lineNumber": 55343, + "beginOffset": 3966475, + "headersEndOffset": 3967033, + "endOffset": 3969308, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55343, + "beginOffset": 3966475, + "headersEndOffset": 3967033, + "endOffset": 3969308, + "message": { + "lineNumber": 55359, + "beginOffset": 3967033, + "headersEndOffset": 3967597, + "endOffset": 3969308, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55359, + "beginOffset": 3967033, + "headersEndOffset": 3967597, + "endOffset": 3969308, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55378, + "beginOffset": 3967704, + "headersEndOffset": 3967783, + "endOffset": 3967833, + "octets": 50, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 55384, + "beginOffset": 3967894, + "headersEndOffset": 3967959, + "endOffset": 3969241, + "message": { + "lineNumber": 55387, + "beginOffset": 3967959, + "headersEndOffset": 3968475, + "endOffset": 3969241, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55387, + "beginOffset": 3967959, + "headersEndOffset": 3968475, + "endOffset": 3969241, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55406, + "beginOffset": 3968572, + "headersEndOffset": 3968651, + "endOffset": 3968778, + "octets": 127, + "lines": 5 + }, + { + "mimeType": "text/html", + "lineNumber": 55416, + "beginOffset": 3968829, + "headersEndOffset": 3968901, + "endOffset": 3969188, + "octets": 287, + "lines": 5 + } + ], + "octets": 766, + "lines": 22 + }, + "octets": 766 + }, + "octets": 1282, + "lines": 38 + } + ], + "octets": 1711, + "lines": 54 + }, + "octets": 1711 + }, + "octets": 2275, + "lines": 70 + }, + "octets": 2275 + }, + "octets": 2833, + "lines": 86 + }, + "octets": 2833 + }, + "octets": 3419, + "lines": 102 + }, + "octets": 3419 + }, + { + "mboxMarkerOffset": 3969310, + "lineNumber": 55431, + "beginOffset": 3969319, + "headersEndOffset": 3970038, + "endOffset": 4233718, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55431, + "beginOffset": 3969319, + "headersEndOffset": 3970038, + "endOffset": 4233718, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55448, + "beginOffset": 3970066, + "headersEndOffset": 3970068, + "endOffset": 3970110, + "octets": 42, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 55452, + "beginOffset": 3970140, + "headersEndOffset": 3970290, + "endOffset": 4047906, + "octets": 77616, + "lines": 401 + }, + { + "mimeType": "text/plain", + "lineNumber": 55859, + "beginOffset": 4047936, + "headersEndOffset": 4047938, + "endOffset": 4047972, + "octets": 34, + "lines": 3 + }, + { + "mimeType": "audio/basic", + "lineNumber": 55865, + "beginOffset": 4048002, + "headersEndOffset": 4048154, + "endOffset": 4151890, + "octets": 103736, + "lines": 535 + }, + { + "mimeType": "text/plain", + "lineNumber": 56406, + "beginOffset": 4151920, + "headersEndOffset": 4151922, + "endOffset": 4152086, + "octets": 164, + "lines": 5 + }, + { + "mimeType": "application/x-annotate", + "lineNumber": 56413, + "beginOffset": 4152116, + "headersEndOffset": 4152208, + "endOffset": 4233632, + "octets": 81424, + "lines": 1235 + }, + { + "mimeType": "text/plain", + "lineNumber": 57652, + "beginOffset": 4233662, + "headersEndOffset": 4233664, + "endOffset": 4233686, + "octets": 22, + "lines": 3 + } + ], + "octets": 263680, + "lines": 2210 + }, + "octets": 263680 + }, + { + "mboxMarkerOffset": 4233720, + "lineNumber": 57659, + "beginOffset": 4233729, + "headersEndOffset": 4234408, + "endOffset": 4235418, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 57659, + "beginOffset": 4233729, + "headersEndOffset": 4234408, + "endOffset": 4235418, + "octets": 1010, + "lines": 18 + }, + "octets": 1010 + }, + { + "mboxMarkerOffset": 4235420, + "lineNumber": 57693, + "beginOffset": 4235429, + "headersEndOffset": 4236508, + "endOffset": 4239644, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 57693, + "beginOffset": 4235429, + "headersEndOffset": 4236508, + "endOffset": 4239644, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 57720, + "beginOffset": 4236707, + "headersEndOffset": 4236753, + "endOffset": 4237170, + "octets": 417, + "lines": 13 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 57737, + "beginOffset": 4237213, + "headersEndOffset": 4237301, + "endOffset": 4239599, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 57741, + "beginOffset": 4237344, + "headersEndOffset": 4237438, + "endOffset": 4237667, + "octets": 229, + "lines": 4 + }, + { + "mimeType": "image/x-xbm", + "lineNumber": 57750, + "beginOffset": 4237712, + "headersEndOffset": 4237835, + "endOffset": 4239256, + "octets": 1421, + "lines": 37 + }, + { + "mimeType": "text/richtext", + "lineNumber": 57793, + "beginOffset": 4239301, + "headersEndOffset": 4239395, + "endOffset": 4239552, + "octets": 157, + "lines": 9 + } + ], + "octets": 2298, + "lines": 67 + } + ], + "octets": 3136, + "lines": 93 + }, + "octets": 3136 + }, + { + "mboxMarkerOffset": 4239646, + "lineNumber": 57811, + "beginOffset": 4239655, + "headersEndOffset": 4240341, + "endOffset": 4245810, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 57811, + "beginOffset": 4239655, + "headersEndOffset": 4240341, + "endOffset": 4245810, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 57828, + "beginOffset": 4240358, + "headersEndOffset": 4240387, + "endOffset": 4240471, + "octets": 84, + "lines": 6 + }, + { + "mimeType": "image/gif", + "lineNumber": 57838, + "beginOffset": 4240490, + "headersEndOffset": 4240553, + "endOffset": 4245787, + "octets": 5234, + "lines": 71 + } + ], + "octets": 5469, + "lines": 88 + }, + "octets": 5469 + }, + { + "mboxMarkerOffset": 4245812, + "lineNumber": 57917, + "beginOffset": 4245821, + "headersEndOffset": 4246287, + "endOffset": 4257886, + "body": { + "mimeType": "Image/JPEG", + "lineNumber": 57917, + "beginOffset": 4245821, + "headersEndOffset": 4246287, + "endOffset": 4257886, + "octets": 11599, + "lines": 185 + }, + "octets": 11599 + }, + { + "mboxMarkerOffset": 4257888, + "lineNumber": 58118, + "beginOffset": 4257897, + "headersEndOffset": 4258477, + "endOffset": 4259836, + "body": { + "mimeType": "Multipart/Mixed", + "lineNumber": 58118, + "beginOffset": 4257897, + "headersEndOffset": 4258477, + "endOffset": 4259836, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 58134, + "beginOffset": 4258489, + "headersEndOffset": 4258491, + "endOffset": 4258530, + "octets": 39, + "lines": 1 + }, + { + "mimeType": "Multipart/MIXED", + "lineNumber": 58138, + "beginOffset": 4258544, + "headersEndOffset": 4258601, + "endOffset": 4259820, + "children": [ + { + "mimeType": "Message/External-body", + "lineNumber": 58141, + "beginOffset": 4258616, + "headersEndOffset": 4258736, + "endOffset": 4258885, + "message": { + "lineNumber": 58145, + "beginOffset": 4258736, + "headersEndOffset": 4258816, + "endOffset": 4258885, + "body": { + "mimeType": "text/plain", + "lineNumber": 58145, + "beginOffset": 4258736, + "headersEndOffset": 4258816, + "endOffset": 4258885, + "octets": 69, + "lines": 2 + }, + "octets": 69 + }, + "octets": 149, + "lines": 5 + }, + { + "mimeType": "Message/External-body", + "lineNumber": 58152, + "beginOffset": 4258902, + "headersEndOffset": 4259095, + "endOffset": 4259173, + "message": { + "lineNumber": 58158, + "beginOffset": 4259095, + "headersEndOffset": 4259173, + "endOffset": 4259173, + "body": { + "mimeType": "text/plain", + "lineNumber": 58158, + "beginOffset": 4259095, + "headersEndOffset": 4259173, + "endOffset": 4259173, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 78, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58162, + "beginOffset": 4259190, + "headersEndOffset": 4259332, + "endOffset": 4259401, + "message": { + "lineNumber": 58169, + "beginOffset": 4259332, + "headersEndOffset": 4259401, + "endOffset": 4259401, + "body": { + "mimeType": "TEXT/HTML", + "lineNumber": 58169, + "beginOffset": 4259332, + "headersEndOffset": 4259401, + "endOffset": 4259401, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 69, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58173, + "beginOffset": 4259418, + "headersEndOffset": 4259535, + "endOffset": 4259605, + "message": { + "lineNumber": 58177, + "beginOffset": 4259535, + "headersEndOffset": 4259605, + "endOffset": 4259605, + "body": { + "mimeType": "image/gif", + "lineNumber": 58177, + "beginOffset": 4259535, + "headersEndOffset": 4259605, + "endOffset": 4259605, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 70, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58181, + "beginOffset": 4259622, + "headersEndOffset": 4259731, + "endOffset": 4259801, + "message": { + "lineNumber": 58185, + "beginOffset": 4259731, + "headersEndOffset": 4259801, + "endOffset": 4259801, + "body": { + "mimeType": "image/gif", + "lineNumber": 58185, + "beginOffset": 4259731, + "headersEndOffset": 4259801, + "endOffset": 4259801, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 70, + "lines": 2 + } + ], + "octets": 1219, + "lines": 49 + } + ], + "octets": 1359, + "lines": 58 + }, + "octets": 1359 + }, + { + "mboxMarkerOffset": 4259838, + "lineNumber": 58193, + "beginOffset": 4259847, + "headersEndOffset": 4260427, + "endOffset": 4264394, + "body": { + "mimeType": "Multipart/Mixed", + "lineNumber": 58193, + "beginOffset": 4259847, + "headersEndOffset": 4260427, + "endOffset": 4264394, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 58209, + "beginOffset": 4260439, + "headersEndOffset": 4260441, + "endOffset": 4263710, + "octets": 3269, + "lines": 65 + }, + { + "mimeType": "Multipart/Alternative", + "lineNumber": 58277, + "beginOffset": 4263724, + "headersEndOffset": 4263787, + "endOffset": 4264378, + "children": [ + { + "mimeType": "Message/External-body", + "lineNumber": 58280, + "beginOffset": 4263802, + "headersEndOffset": 4263922, + "endOffset": 4264071, + "message": { + "lineNumber": 58284, + "beginOffset": 4263922, + "headersEndOffset": 4264002, + "endOffset": 4264071, + "body": { + "mimeType": "text/plain", + "lineNumber": 58284, + "beginOffset": 4263922, + "headersEndOffset": 4264002, + "endOffset": 4264071, + "octets": 69, + "lines": 2 + }, + "octets": 69 + }, + "octets": 149, + "lines": 5 + }, + { + "mimeType": "Message/External-body", + "lineNumber": 58291, + "beginOffset": 4264088, + "headersEndOffset": 4264281, + "endOffset": 4264359, + "message": { + "lineNumber": 58297, + "beginOffset": 4264281, + "headersEndOffset": 4264359, + "endOffset": 4264359, + "body": { + "mimeType": "text/plain", + "lineNumber": 58297, + "beginOffset": 4264281, + "headersEndOffset": 4264359, + "endOffset": 4264359, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 78, + "lines": 2 + } + ], + "octets": 591, + "lines": 22 + } + ], + "octets": 3967, + "lines": 95 + }, + "octets": 3967 + }, + { + "mboxMarkerOffset": 4264396, + "lineNumber": 58305, + "beginOffset": 4264405, + "headersEndOffset": 4264885, + "endOffset": 4270786, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58305, + "beginOffset": 4264405, + "headersEndOffset": 4264885, + "endOffset": 4270786, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 58320, + "beginOffset": 4264961, + "headersEndOffset": 4265110, + "endOffset": 4265589, + "message": { + "lineNumber": 58325, + "beginOffset": 4265110, + "headersEndOffset": 4265550, + "endOffset": 4265589, + "body": { + "mimeType": "text/plain", + "lineNumber": 58325, + "beginOffset": 4265110, + "headersEndOffset": 4265550, + "endOffset": 4265589, + "octets": 39, + "lines": 2 + }, + "octets": 39 + }, + "octets": 479, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 58340, + "beginOffset": 4265619, + "headersEndOffset": 4265746, + "endOffset": 4266210, + "octets": 464, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58352, + "beginOffset": 4266240, + "headersEndOffset": 4266367, + "endOffset": 4266859, + "octets": 492, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58364, + "beginOffset": 4266889, + "headersEndOffset": 4267020, + "endOffset": 4267554, + "octets": 534, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 58377, + "beginOffset": 4267584, + "headersEndOffset": 4267713, + "endOffset": 4268217, + "octets": 504, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58389, + "beginOffset": 4268247, + "headersEndOffset": 4268396, + "endOffset": 4268874, + "message": { + "lineNumber": 58394, + "beginOffset": 4268396, + "headersEndOffset": 4268836, + "endOffset": 4268874, + "body": { + "mimeType": "text/plain", + "lineNumber": 58394, + "beginOffset": 4268396, + "headersEndOffset": 4268836, + "endOffset": 4268874, + "octets": 38, + "lines": 1 + }, + "octets": 38 + }, + "octets": 478, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58408, + "beginOffset": 4268904, + "headersEndOffset": 4269080, + "endOffset": 4270617, + "message": { + "lineNumber": 58413, + "beginOffset": 4269080, + "headersEndOffset": 4269665, + "endOffset": 4270617, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58413, + "beginOffset": 4269080, + "headersEndOffset": 4269665, + "endOffset": 4270617, + "message": { + "lineNumber": 58428, + "beginOffset": 4269665, + "headersEndOffset": 4270190, + "endOffset": 4270617, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58428, + "beginOffset": 4269665, + "headersEndOffset": 4270190, + "endOffset": 4270617, + "message": { + "lineNumber": 58442, + "beginOffset": 4270190, + "headersEndOffset": 4270611, + "endOffset": 4270617, + "body": { + "mimeType": "text/plain", + "lineNumber": 58442, + "beginOffset": 4270190, + "headersEndOffset": 4270611, + "endOffset": 4270617, + "octets": 6, + "lines": 1 + }, + "octets": 6 + }, + "octets": 427, + "lines": 12 + }, + "octets": 427 + }, + "octets": 952, + "lines": 26 + }, + "octets": 952 + }, + "octets": 1537, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 58456, + "beginOffset": 4270647, + "headersEndOffset": 4270703, + "endOffset": 4270756, + "octets": 53, + "lines": 1 + } + ], + "octets": 5901, + "lines": 145 + }, + "octets": 5901 + }, + { + "mboxMarkerOffset": 4270788, + "lineNumber": 58463, + "beginOffset": 4270797, + "headersEndOffset": 4271280, + "endOffset": 4277216, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58463, + "beginOffset": 4270797, + "headersEndOffset": 4271280, + "endOffset": 4277216, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 58478, + "beginOffset": 4271356, + "headersEndOffset": 4271509, + "endOffset": 4271987, + "message": { + "lineNumber": 58483, + "beginOffset": 4271509, + "headersEndOffset": 4271948, + "endOffset": 4271987, + "body": { + "mimeType": "text/plain", + "lineNumber": 58483, + "beginOffset": 4271509, + "headersEndOffset": 4271948, + "endOffset": 4271987, + "octets": 39, + "lines": 2 + }, + "octets": 39 + }, + "octets": 478, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 58498, + "beginOffset": 4272017, + "headersEndOffset": 4272148, + "endOffset": 4272612, + "octets": 464, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58510, + "beginOffset": 4272642, + "headersEndOffset": 4272773, + "endOffset": 4273265, + "octets": 492, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58522, + "beginOffset": 4273295, + "headersEndOffset": 4273430, + "endOffset": 4273964, + "octets": 534, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 58535, + "beginOffset": 4273994, + "headersEndOffset": 4274127, + "endOffset": 4274631, + "octets": 504, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58547, + "beginOffset": 4274661, + "headersEndOffset": 4274814, + "endOffset": 4275291, + "message": { + "lineNumber": 58552, + "beginOffset": 4274814, + "headersEndOffset": 4275253, + "endOffset": 4275291, + "body": { + "mimeType": "text/plain", + "lineNumber": 58552, + "beginOffset": 4274814, + "headersEndOffset": 4275253, + "endOffset": 4275291, + "octets": 38, + "lines": 1 + }, + "octets": 38 + }, + "octets": 477, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58566, + "beginOffset": 4275321, + "headersEndOffset": 4275501, + "endOffset": 4277043, + "message": { + "lineNumber": 58571, + "beginOffset": 4275501, + "headersEndOffset": 4276089, + "endOffset": 4277043, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58571, + "beginOffset": 4275501, + "headersEndOffset": 4276089, + "endOffset": 4277043, + "message": { + "lineNumber": 58586, + "beginOffset": 4276089, + "headersEndOffset": 4276617, + "endOffset": 4277043, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58586, + "beginOffset": 4276089, + "headersEndOffset": 4276617, + "endOffset": 4277043, + "message": { + "lineNumber": 58600, + "beginOffset": 4276617, + "headersEndOffset": 4277037, + "endOffset": 4277043, + "body": { + "mimeType": "text/plain", + "lineNumber": 58600, + "beginOffset": 4276617, + "headersEndOffset": 4277037, + "endOffset": 4277043, + "octets": 6, + "lines": 1 + }, + "octets": 6 + }, + "octets": 426, + "lines": 12 + }, + "octets": 426 + }, + "octets": 954, + "lines": 26 + }, + "octets": 954 + }, + "octets": 1542, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 58614, + "beginOffset": 4277073, + "headersEndOffset": 4277133, + "endOffset": 4277186, + "octets": 53, + "lines": 1 + } + ], + "octets": 5936, + "lines": 145 + }, + "octets": 5936 + }, + { + "mboxMarkerOffset": 4277218, + "lineNumber": 58621, + "beginOffset": 4277227, + "headersEndOffset": 4277931, + "endOffset": 4298376, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58621, + "beginOffset": 4277227, + "headersEndOffset": 4277931, + "endOffset": 4298376, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 58641, + "beginOffset": 4277981, + "headersEndOffset": 4278012, + "endOffset": 4278458, + "octets": 446, + "lines": 30 + }, + { + "mimeType": "text/enriched", + "lineNumber": 58675, + "beginOffset": 4278467, + "headersEndOffset": 4278543, + "endOffset": 4279216, + "octets": 673, + "lines": 42 + }, + { + "mimeType": "text/plain", + "lineNumber": 58722, + "beginOffset": 4279225, + "headersEndOffset": 4279227, + "endOffset": 4279245, + "octets": 18, + "lines": 1 + }, + { + "mimeType": "text/plain", + "lineNumber": 58725, + "beginOffset": 4279254, + "headersEndOffset": 4279256, + "endOffset": 4279267, + "octets": 11, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58728, + "beginOffset": 4279276, + "headersEndOffset": 4279308, + "endOffset": 4279824, + "message": { + "lineNumber": 58730, + "beginOffset": 4279308, + "headersEndOffset": 4279530, + "endOffset": 4279824, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58730, + "beginOffset": 4279308, + "headersEndOffset": 4279530, + "endOffset": 4279824, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 58738, + "beginOffset": 4279537, + "headersEndOffset": 4279564, + "endOffset": 4279587, + "octets": 23, + "lines": 1 + }, + { + "mimeType": "image/unknown", + "lineNumber": 58742, + "beginOffset": 4279596, + "headersEndOffset": 4279776, + "endOffset": 4279815, + "octets": 39, + "lines": 1 + } + ], + "octets": 294, + "lines": 13 + }, + "octets": 294 + }, + "octets": 516, + "lines": 20 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 58751, + "beginOffset": 4279833, + "headersEndOffset": 4279914, + "endOffset": 4289472, + "octets": 9558, + "lines": 128 + }, + { + "mimeType": "image/unknown", + "lineNumber": 58883, + "beginOffset": 4289481, + "headersEndOffset": 4289661, + "endOffset": 4289700, + "octets": 39, + "lines": 1 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 58891, + "beginOffset": 4289709, + "headersEndOffset": 4289861, + "endOffset": 4297809, + "octets": 7948, + "lines": 128 + }, + { + "mimeType": "multipart/digest", + "lineNumber": 59024, + "beginOffset": 4297818, + "headersEndOffset": 4297872, + "endOffset": 4298324, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 59027, + "beginOffset": 4297883, + "headersEndOffset": 4297885, + "endOffset": 4297919, + "message": { + "lineNumber": 59028, + "beginOffset": 4297885, + "headersEndOffset": 4297914, + "endOffset": 4297919, + "body": { + "mimeType": "text/plain", + "lineNumber": 59028, + "beginOffset": 4297885, + "headersEndOffset": 4297914, + "endOffset": 4297919, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 34, + "lines": 4 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59033, + "beginOffset": 4297932, + "headersEndOffset": 4297934, + "endOffset": 4297968, + "message": { + "lineNumber": 59034, + "beginOffset": 4297934, + "headersEndOffset": 4297963, + "endOffset": 4297968, + "body": { + "mimeType": "text/plain", + "lineNumber": 59034, + "beginOffset": 4297934, + "headersEndOffset": 4297963, + "endOffset": 4297968, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 34, + "lines": 4 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59039, + "beginOffset": 4297981, + "headersEndOffset": 4297983, + "endOffset": 4298017, + "message": { + "lineNumber": 59040, + "beginOffset": 4297983, + "headersEndOffset": 4298012, + "endOffset": 4298017, + "body": { + "mimeType": "text/plain", + "lineNumber": 59040, + "beginOffset": 4297983, + "headersEndOffset": 4298012, + "endOffset": 4298017, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 34, + "lines": 4 + }, + { + "mimeType": "text/html", + "lineNumber": 59045, + "beginOffset": 4298030, + "headersEndOffset": 4298057, + "endOffset": 4298140, + "octets": 83, + "lines": 2 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59050, + "beginOffset": 4298153, + "headersEndOffset": 4298155, + "endOffset": 4298262, + "message": { + "lineNumber": 59051, + "beginOffset": 4298155, + "headersEndOffset": 4298213, + "endOffset": 4298262, + "body": { + "mimeType": "text/richtext", + "lineNumber": 59051, + "beginOffset": 4298155, + "headersEndOffset": 4298213, + "endOffset": 4298262, + "octets": 49, + "lines": 1 + }, + "octets": 49 + }, + "octets": 107, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59057, + "beginOffset": 4298275, + "headersEndOffset": 4298277, + "endOffset": 4298311, + "message": { + "lineNumber": 59058, + "beginOffset": 4298277, + "headersEndOffset": 4298306, + "endOffset": 4298311, + "body": { + "mimeType": "text/plain", + "lineNumber": 59058, + "beginOffset": 4298277, + "headersEndOffset": 4298306, + "endOffset": 4298311, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 34, + "lines": 4 + } + ], + "octets": 452, + "lines": 37 + } + ], + "octets": 20445, + "lines": 428 + }, + "octets": 20445 + }, + { + "mboxMarkerOffset": 4298378, + "lineNumber": 59067, + "beginOffset": 4298387, + "headersEndOffset": 4299063, + "endOffset": 4372265, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 59067, + "beginOffset": 4298387, + "headersEndOffset": 4299063, + "endOffset": 4372265, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 59083, + "beginOffset": 4299090, + "headersEndOffset": 4299092, + "endOffset": 4300338, + "octets": 1246, + "lines": 27 + }, + { + "mimeType": "image/pbm", + "lineNumber": 59112, + "beginOffset": 4300367, + "headersEndOffset": 4300517, + "endOffset": 4372203, + "octets": 71686, + "lines": 370 + }, + { + "mimeType": "text/plain", + "lineNumber": 59488, + "beginOffset": 4372232, + "headersEndOffset": 4372234, + "endOffset": 4372234, + "octets": 0, + "lines": 0 + } + ], + "octets": 73202, + "lines": 409 + }, + "octets": 73202 + }, + { + "mboxMarkerOffset": 4372267, + "lineNumber": 59493, + "beginOffset": 4372276, + "headersEndOffset": 4373229, + "endOffset": 4625700, + "body": { + "mimeType": "message/partial", + "lineNumber": 59493, + "beginOffset": 4372276, + "headersEndOffset": 4373229, + "endOffset": 4625700, + "octets": 252471, + "lines": 3430 + }, + "octets": 252471 + }, + { + "mboxMarkerOffset": 4625702, + "lineNumber": 62945, + "beginOffset": 4625711, + "headersEndOffset": 4626660, + "endOffset": 4682261, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 62945, + "beginOffset": 4625711, + "headersEndOffset": 4626660, + "endOffset": 4682261, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 62971, + "beginOffset": 4626905, + "headersEndOffset": 4626981, + "endOffset": 4627454, + "octets": 473, + "lines": 9 + }, + { + "mimeType": "image/gif", + "lineNumber": 62985, + "beginOffset": 4627502, + "headersEndOffset": 4627564, + "endOffset": 4652132, + "octets": 24568, + "lines": 332 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63322, + "beginOffset": 4652180, + "headersEndOffset": 4652256, + "endOffset": 4652714, + "octets": 458, + "lines": 10 + }, + { + "mimeType": "image/gif", + "lineNumber": 63337, + "beginOffset": 4652762, + "headersEndOffset": 4652824, + "endOffset": 4664192, + "octets": 11368, + "lines": 154 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63496, + "beginOffset": 4664240, + "headersEndOffset": 4664316, + "endOffset": 4664626, + "octets": 310, + "lines": 6 + }, + { + "mimeType": "image/gif", + "lineNumber": 63507, + "beginOffset": 4664674, + "headersEndOffset": 4664736, + "endOffset": 4681412, + "octets": 16676, + "lines": 226 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63738, + "beginOffset": 4681460, + "headersEndOffset": 4681536, + "endOffset": 4682211, + "octets": 675, + "lines": 15 + } + ], + "octets": 55601, + "lines": 792 + }, + "octets": 55601 + }, + { + "mboxMarkerOffset": 4682263, + "lineNumber": 63760, + "beginOffset": 4682272, + "headersEndOffset": 4683107, + "endOffset": 4731150, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 63760, + "beginOffset": 4682272, + "headersEndOffset": 4683107, + "endOffset": 4731150, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 63777, + "beginOffset": 4683137, + "headersEndOffset": 4683139, + "endOffset": 4683807, + "octets": 668, + "lines": 18 + }, + { + "mimeType": "Image/JPEG", + "lineNumber": 63798, + "beginOffset": 4683839, + "headersEndOffset": 4683902, + "endOffset": 4731116, + "octets": 47214, + "lines": 762 + } + ], + "octets": 48043, + "lines": 788 + }, + "octets": 48043 + }, + { + "mboxMarkerOffset": 4731152, + "lineNumber": 64566, + "beginOffset": 4731161, + "headersEndOffset": 4731922, + "endOffset": 4767575, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 64566, + "beginOffset": 4731161, + "headersEndOffset": 4731922, + "endOffset": 4767575, + "children": [ + { + "mimeType": "text/enriched", + "lineNumber": 64588, + "beginOffset": 4732387, + "headersEndOffset": 4732463, + "endOffset": 4737938, + "octets": 5475, + "lines": 160 + }, + { + "mimeType": "image/gif", + "lineNumber": 64753, + "beginOffset": 4737964, + "headersEndOffset": 4738065, + "endOffset": 4740681, + "octets": 2616, + "lines": 36 + }, + { + "mimeType": "text/enriched", + "lineNumber": 64795, + "beginOffset": 4740707, + "headersEndOffset": 4740783, + "endOffset": 4741311, + "octets": 528, + "lines": 10 + }, + { + "mimeType": "audio/basic", + "lineNumber": 64810, + "beginOffset": 4741337, + "headersEndOffset": 4741455, + "endOffset": 4764831, + "octets": 23376, + "lines": 316 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65132, + "beginOffset": 4764857, + "headersEndOffset": 4764933, + "endOffset": 4765525, + "octets": 592, + "lines": 14 + }, + { + "mimeType": "message/external-body", + "lineNumber": 65151, + "beginOffset": 4765551, + "headersEndOffset": 4765640, + "endOffset": 4765711, + "message": { + "lineNumber": 65155, + "beginOffset": 4765640, + "headersEndOffset": 4765711, + "endOffset": 4765711, + "body": { + "mimeType": "text/plain", + "lineNumber": 65155, + "beginOffset": 4765640, + "headersEndOffset": 4765711, + "endOffset": 4765711, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 71, + "lines": 2 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65159, + "beginOffset": 4765737, + "headersEndOffset": 4765813, + "endOffset": 4766094, + "octets": 281, + "lines": 5 + }, + { + "mimeType": "message/external-body", + "lineNumber": 65169, + "beginOffset": 4766120, + "headersEndOffset": 4766273, + "endOffset": 4766344, + "message": { + "lineNumber": 65176, + "beginOffset": 4766273, + "headersEndOffset": 4766344, + "endOffset": 4766344, + "body": { + "mimeType": "text/plain", + "lineNumber": 65176, + "beginOffset": 4766273, + "headersEndOffset": 4766344, + "endOffset": 4766344, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 71, + "lines": 2 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65180, + "beginOffset": 4766370, + "headersEndOffset": 4766446, + "endOffset": 4767549, + "octets": 1103, + "lines": 34 + } + ], + "octets": 35653, + "lines": 639 + }, + "octets": 35653 + }, + { + "mboxMarkerOffset": 4767577, + "lineNumber": 65220, + "beginOffset": 4767586, + "headersEndOffset": 4767753, + "endOffset": 4845389, + "body": { + "mimeType": "Multipart/mixed", + "lineNumber": 65220, + "beginOffset": 4767586, + "headersEndOffset": 4767753, + "endOffset": 4845389, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 65227, + "beginOffset": 4767766, + "headersEndOffset": 4767838, + "endOffset": 4845327, + "octets": 77489, + "lines": 1145 + }, + { + "mimeType": "text/plain", + "lineNumber": 66377, + "beginOffset": 4845342, + "headersEndOffset": 4845344, + "endOffset": 4845374, + "octets": 30, + "lines": 1 + } + ], + "octets": 77636, + "lines": 1154 + }, + "octets": 77636 + }, + { + "mboxMarkerOffset": 4845391, + "lineNumber": 66381, + "beginOffset": 4845400, + "headersEndOffset": 4846638, + "endOffset": 4977202, + "body": { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 66381, + "beginOffset": 4845400, + "headersEndOffset": 4846638, + "endOffset": 4977202, + "children": [ + { + "mimeType": "TEXT/plain", + "lineNumber": 66405, + "beginOffset": 4846677, + "headersEndOffset": 4846723, + "endOffset": 4847183, + "octets": 460, + "lines": 8 + }, + { + "mimeType": "AUDIO/basic", + "lineNumber": 66417, + "beginOffset": 4847224, + "headersEndOffset": 4847321, + "endOffset": 4977159, + "octets": 129838, + "lines": 2095 + } + ], + "octets": 130564, + "lines": 2114 + }, + "octets": 130564 + }, + { + "mboxMarkerOffset": 4977204, + "lineNumber": 68520, + "beginOffset": 4977213, + "headersEndOffset": 4977982, + "endOffset": 5154286, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 68520, + "beginOffset": 4977213, + "headersEndOffset": 4977982, + "endOffset": 5154286, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 68544, + "beginOffset": 4978386, + "headersEndOffset": 4978388, + "endOffset": 4979201, + "octets": 813, + "lines": 18 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 68565, + "beginOffset": 4979262, + "headersEndOffset": 4979368, + "endOffset": 5154225, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 68569, + "beginOffset": 4979429, + "headersEndOffset": 4979505, + "endOffset": 4980001, + "octets": 496, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 68581, + "beginOffset": 4980064, + "headersEndOffset": 4980164, + "endOffset": 4993344, + "octets": 13180, + "lines": 190 + }, + { + "mimeType": "text/plain", + "lineNumber": 68777, + "beginOffset": 4993407, + "headersEndOffset": 4993480, + "endOffset": 4993501, + "octets": 21, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 68783, + "beginOffset": 4993564, + "headersEndOffset": 4993664, + "endOffset": 5050148, + "octets": 56484, + "lines": 764 + }, + { + "mimeType": "text/plain", + "lineNumber": 69553, + "beginOffset": 5050211, + "headersEndOffset": 5050284, + "endOffset": 5050341, + "octets": 57, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 69563, + "beginOffset": 5050404, + "headersEndOffset": 5050468, + "endOffset": 5154020, + "octets": 103552, + "lines": 1400 + }, + { + "mimeType": "text/plain", + "lineNumber": 70968, + "beginOffset": 5154083, + "headersEndOffset": 5154156, + "endOffset": 5154160, + "octets": 4, + "lines": 2 + } + ], + "octets": 174857, + "lines": 2407 + } + ], + "octets": 176304, + "lines": 2440 + }, + "octets": 176304 + }, + { + "mboxMarkerOffset": 5154288, + "lineNumber": 70978, + "beginOffset": 5154297, + "headersEndOffset": 5154999, + "endOffset": 5373282, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 70978, + "beginOffset": 5154297, + "headersEndOffset": 5154999, + "endOffset": 5373282, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 70998, + "beginOffset": 5155198, + "headersEndOffset": 5155244, + "endOffset": 5156788, + "octets": 1544, + "lines": 29 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 71031, + "beginOffset": 5156831, + "headersEndOffset": 5156919, + "endOffset": 5373239, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 71035, + "beginOffset": 5156962, + "headersEndOffset": 5157056, + "endOffset": 5157976, + "octets": 920, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 71053, + "beginOffset": 5158021, + "headersEndOffset": 5158116, + "endOffset": 5193480, + "octets": 35364, + "lines": 506 + }, + { + "mimeType": "text/richtext", + "lineNumber": 71565, + "beginOffset": 5193525, + "headersEndOffset": 5193619, + "endOffset": 5193631, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 71572, + "beginOffset": 5193676, + "headersEndOffset": 5193771, + "endOffset": 5215415, + "octets": 21644, + "lines": 310 + }, + { + "mimeType": "text/richtext", + "lineNumber": 71888, + "beginOffset": 5215460, + "headersEndOffset": 5215554, + "endOffset": 5215566, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 71895, + "beginOffset": 5215611, + "headersEndOffset": 5215706, + "endOffset": 5248620, + "octets": 32914, + "lines": 471 + }, + { + "mimeType": "text/richtext", + "lineNumber": 72372, + "beginOffset": 5248665, + "headersEndOffset": 5248759, + "endOffset": 5248771, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 72379, + "beginOffset": 5248816, + "headersEndOffset": 5248911, + "endOffset": 5282837, + "octets": 33926, + "lines": 485 + }, + { + "mimeType": "text/richtext", + "lineNumber": 72870, + "beginOffset": 5282882, + "headersEndOffset": 5282976, + "endOffset": 5282988, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 72877, + "beginOffset": 5283033, + "headersEndOffset": 5283128, + "endOffset": 5311368, + "octets": 28240, + "lines": 404 + }, + { + "mimeType": "text/richtext", + "lineNumber": 73287, + "beginOffset": 5311413, + "headersEndOffset": 5311507, + "endOffset": 5311519, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 73294, + "beginOffset": 5311564, + "headersEndOffset": 5311659, + "endOffset": 5345639, + "octets": 33980, + "lines": 486 + }, + { + "mimeType": "text/richtext", + "lineNumber": 73786, + "beginOffset": 5345684, + "headersEndOffset": 5345778, + "endOffset": 5345790, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 73793, + "beginOffset": 5345835, + "headersEndOffset": 5345930, + "endOffset": 5372976, + "octets": 27046, + "lines": 387 + }, + { + "mimeType": "text/richtext", + "lineNumber": 74186, + "beginOffset": 5373021, + "headersEndOffset": 5373115, + "endOffset": 5373192, + "octets": 77, + "lines": 3 + } + ], + "octets": 216320, + "lines": 3160 + } + ], + "octets": 218283, + "lines": 3202 + }, + "octets": 218283 + }, + { + "mboxMarkerOffset": 5373284, + "lineNumber": 74197, + "beginOffset": 5373293, + "headersEndOffset": 5373698, + "endOffset": 5464350, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 74197, + "beginOffset": 5373293, + "headersEndOffset": 5373698, + "endOffset": 5464350, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 74215, + "beginOffset": 5373947, + "headersEndOffset": 5374045, + "endOffset": 5374257, + "octets": 212, + "lines": 9 + }, + { + "mimeType": "audio/basic", + "lineNumber": 74229, + "beginOffset": 5374309, + "headersEndOffset": 5374373, + "endOffset": 5464185, + "octets": 89812, + "lines": 1214 + }, + { + "mimeType": "text/plain", + "lineNumber": 75448, + "beginOffset": 5464237, + "headersEndOffset": 5464265, + "endOffset": 5464296, + "octets": 31, + "lines": 1 + } + ], + "octets": 90652, + "lines": 1243 + }, + "octets": 90652 + }, + { + "mboxMarkerOffset": 5464352, + "lineNumber": 75455, + "beginOffset": 5464361, + "headersEndOffset": 5465317, + "endOffset": 5516722, + "body": { + "mimeType": "message/partial", + "lineNumber": 75455, + "beginOffset": 5464361, + "headersEndOffset": 5465317, + "endOffset": 5516722, + "octets": 51405, + "lines": 696 + }, + "octets": 51405 + }, + { + "mboxMarkerOffset": 5516724, + "lineNumber": 76173, + "beginOffset": 5516733, + "headersEndOffset": 5517362, + "endOffset": 5588100, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 76173, + "beginOffset": 5516733, + "headersEndOffset": 5517362, + "endOffset": 5588100, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 76191, + "beginOffset": 5517381, + "headersEndOffset": 5517383, + "endOffset": 5521801, + "octets": 4418, + "lines": 101 + }, + { + "mimeType": "multipart/digest", + "lineNumber": 76295, + "beginOffset": 5521822, + "headersEndOffset": 5521966, + "endOffset": 5588021, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 76299, + "beginOffset": 5521998, + "headersEndOffset": 5522000, + "endOffset": 5522748, + "message": { + "lineNumber": 76300, + "beginOffset": 5522000, + "headersEndOffset": 5522109, + "endOffset": 5522748, + "body": { + "mimeType": "text/plain", + "lineNumber": 76300, + "beginOffset": 5522000, + "headersEndOffset": 5522109, + "endOffset": 5522748, + "octets": 639, + "lines": 18 + }, + "octets": 639 + }, + "octets": 748, + "lines": 22 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76324, + "beginOffset": 5522782, + "headersEndOffset": 5522784, + "endOffset": 5523662, + "message": { + "lineNumber": 76325, + "beginOffset": 5522784, + "headersEndOffset": 5522909, + "endOffset": 5523662, + "body": { + "mimeType": "text/plain", + "lineNumber": 76325, + "beginOffset": 5522784, + "headersEndOffset": 5522909, + "endOffset": 5523662, + "octets": 753, + "lines": 20 + }, + "octets": 753 + }, + "octets": 878, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76351, + "beginOffset": 5523696, + "headersEndOffset": 5523698, + "endOffset": 5524481, + "message": { + "lineNumber": 76352, + "beginOffset": 5523698, + "headersEndOffset": 5523821, + "endOffset": 5524481, + "body": { + "mimeType": "text/plain", + "lineNumber": 76352, + "beginOffset": 5523698, + "headersEndOffset": 5523821, + "endOffset": 5524481, + "octets": 660, + "lines": 14 + }, + "octets": 660 + }, + "octets": 783, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76372, + "beginOffset": 5524515, + "headersEndOffset": 5524517, + "endOffset": 5525170, + "message": { + "lineNumber": 76373, + "beginOffset": 5524517, + "headersEndOffset": 5524677, + "endOffset": 5525170, + "body": { + "mimeType": "text/plain", + "lineNumber": 76373, + "beginOffset": 5524517, + "headersEndOffset": 5524677, + "endOffset": 5525170, + "octets": 493, + "lines": 10 + }, + "octets": 493 + }, + "octets": 653, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76389, + "beginOffset": 5525204, + "headersEndOffset": 5525206, + "endOffset": 5525951, + "message": { + "lineNumber": 76390, + "beginOffset": 5525206, + "headersEndOffset": 5525364, + "endOffset": 5525951, + "body": { + "mimeType": "text/plain", + "lineNumber": 76390, + "beginOffset": 5525206, + "headersEndOffset": 5525364, + "endOffset": 5525951, + "octets": 587, + "lines": 15 + }, + "octets": 587 + }, + "octets": 745, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76411, + "beginOffset": 5525985, + "headersEndOffset": 5525987, + "endOffset": 5527449, + "message": { + "lineNumber": 76412, + "beginOffset": 5525987, + "headersEndOffset": 5526148, + "endOffset": 5527449, + "body": { + "mimeType": "text/plain", + "lineNumber": 76412, + "beginOffset": 5525987, + "headersEndOffset": 5526148, + "endOffset": 5527449, + "octets": 1301, + "lines": 26 + }, + "octets": 1301 + }, + "octets": 1462, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76444, + "beginOffset": 5527483, + "headersEndOffset": 5527485, + "endOffset": 5528052, + "message": { + "lineNumber": 76445, + "beginOffset": 5527485, + "headersEndOffset": 5527642, + "endOffset": 5528052, + "body": { + "mimeType": "text/plain", + "lineNumber": 76445, + "beginOffset": 5527485, + "headersEndOffset": 5527642, + "endOffset": 5528052, + "octets": 410, + "lines": 9 + }, + "octets": 410 + }, + "octets": 567, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76460, + "beginOffset": 5528086, + "headersEndOffset": 5528088, + "endOffset": 5528642, + "message": { + "lineNumber": 76461, + "beginOffset": 5528088, + "headersEndOffset": 5528239, + "endOffset": 5528642, + "body": { + "mimeType": "text/plain", + "lineNumber": 76461, + "beginOffset": 5528088, + "headersEndOffset": 5528239, + "endOffset": 5528642, + "octets": 403, + "lines": 7 + }, + "octets": 403 + }, + "octets": 554, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76474, + "beginOffset": 5528676, + "headersEndOffset": 5528678, + "endOffset": 5529476, + "message": { + "lineNumber": 76475, + "beginOffset": 5528678, + "headersEndOffset": 5528825, + "endOffset": 5529476, + "body": { + "mimeType": "text/plain", + "lineNumber": 76475, + "beginOffset": 5528678, + "headersEndOffset": 5528825, + "endOffset": 5529476, + "octets": 651, + "lines": 11 + }, + "octets": 651 + }, + "octets": 798, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76492, + "beginOffset": 5529510, + "headersEndOffset": 5529512, + "endOffset": 5530649, + "message": { + "lineNumber": 76493, + "beginOffset": 5529512, + "headersEndOffset": 5529653, + "endOffset": 5530649, + "body": { + "mimeType": "text/plain", + "lineNumber": 76493, + "beginOffset": 5529512, + "headersEndOffset": 5529653, + "endOffset": 5530649, + "octets": 996, + "lines": 19 + }, + "octets": 996 + }, + "octets": 1137, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76518, + "beginOffset": 5530683, + "headersEndOffset": 5530685, + "endOffset": 5531753, + "message": { + "lineNumber": 76519, + "beginOffset": 5530685, + "headersEndOffset": 5530836, + "endOffset": 5531753, + "body": { + "mimeType": "text/plain", + "lineNumber": 76519, + "beginOffset": 5530685, + "headersEndOffset": 5530836, + "endOffset": 5531753, + "octets": 917, + "lines": 27 + }, + "octets": 917 + }, + "octets": 1068, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76552, + "beginOffset": 5531787, + "headersEndOffset": 5531789, + "endOffset": 5532494, + "message": { + "lineNumber": 76553, + "beginOffset": 5531789, + "headersEndOffset": 5531924, + "endOffset": 5532494, + "body": { + "mimeType": "text/plain", + "lineNumber": 76553, + "beginOffset": 5531789, + "headersEndOffset": 5531924, + "endOffset": 5532494, + "octets": 570, + "lines": 11 + }, + "octets": 570 + }, + "octets": 705, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76570, + "beginOffset": 5532528, + "headersEndOffset": 5532530, + "endOffset": 5533113, + "message": { + "lineNumber": 76571, + "beginOffset": 5532530, + "headersEndOffset": 5532666, + "endOffset": 5533113, + "body": { + "mimeType": "text/plain", + "lineNumber": 76571, + "beginOffset": 5532530, + "headersEndOffset": 5532666, + "endOffset": 5533113, + "octets": 447, + "lines": 10 + }, + "octets": 447 + }, + "octets": 583, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76587, + "beginOffset": 5533147, + "headersEndOffset": 5533149, + "endOffset": 5533837, + "message": { + "lineNumber": 76588, + "beginOffset": 5533149, + "headersEndOffset": 5533270, + "endOffset": 5533837, + "body": { + "mimeType": "text/plain", + "lineNumber": 76588, + "beginOffset": 5533149, + "headersEndOffset": 5533270, + "endOffset": 5533837, + "octets": 567, + "lines": 15 + }, + "octets": 567 + }, + "octets": 688, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76609, + "beginOffset": 5533871, + "headersEndOffset": 5533873, + "endOffset": 5534185, + "message": { + "lineNumber": 76610, + "beginOffset": 5533873, + "headersEndOffset": 5533992, + "endOffset": 5534185, + "body": { + "mimeType": "text/plain", + "lineNumber": 76610, + "beginOffset": 5533873, + "headersEndOffset": 5533992, + "endOffset": 5534185, + "octets": 193, + "lines": 8 + }, + "octets": 193 + }, + "octets": 312, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76624, + "beginOffset": 5534219, + "headersEndOffset": 5534221, + "endOffset": 5534677, + "message": { + "lineNumber": 76625, + "beginOffset": 5534221, + "headersEndOffset": 5534342, + "endOffset": 5534677, + "body": { + "mimeType": "text/plain", + "lineNumber": 76625, + "beginOffset": 5534221, + "headersEndOffset": 5534342, + "endOffset": 5534677, + "octets": 335, + "lines": 7 + }, + "octets": 335 + }, + "octets": 456, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76638, + "beginOffset": 5534711, + "headersEndOffset": 5534713, + "endOffset": 5535528, + "message": { + "lineNumber": 76639, + "beginOffset": 5534713, + "headersEndOffset": 5534840, + "endOffset": 5535528, + "body": { + "mimeType": "text/plain", + "lineNumber": 76639, + "beginOffset": 5534713, + "headersEndOffset": 5534840, + "endOffset": 5535528, + "octets": 688, + "lines": 21 + }, + "octets": 688 + }, + "octets": 815, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76666, + "beginOffset": 5535562, + "headersEndOffset": 5535564, + "endOffset": 5535799, + "message": { + "lineNumber": 76667, + "beginOffset": 5535564, + "headersEndOffset": 5535692, + "endOffset": 5535799, + "body": { + "mimeType": "text/plain", + "lineNumber": 76667, + "beginOffset": 5535564, + "headersEndOffset": 5535692, + "endOffset": 5535799, + "octets": 107, + "lines": 5 + }, + "octets": 107 + }, + "octets": 235, + "lines": 9 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76678, + "beginOffset": 5535833, + "headersEndOffset": 5535835, + "endOffset": 5536838, + "message": { + "lineNumber": 76679, + "beginOffset": 5535835, + "headersEndOffset": 5535981, + "endOffset": 5536838, + "body": { + "mimeType": "text/plain", + "lineNumber": 76679, + "beginOffset": 5535835, + "headersEndOffset": 5535981, + "endOffset": 5536838, + "octets": 857, + "lines": 21 + }, + "octets": 857 + }, + "octets": 1003, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76706, + "beginOffset": 5536872, + "headersEndOffset": 5536874, + "endOffset": 5537416, + "message": { + "lineNumber": 76707, + "beginOffset": 5536874, + "headersEndOffset": 5536988, + "endOffset": 5537416, + "body": { + "mimeType": "text/plain", + "lineNumber": 76707, + "beginOffset": 5536874, + "headersEndOffset": 5536988, + "endOffset": 5537416, + "octets": 428, + "lines": 9 + }, + "octets": 428 + }, + "octets": 542, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76722, + "beginOffset": 5537450, + "headersEndOffset": 5537452, + "endOffset": 5537867, + "message": { + "lineNumber": 76723, + "beginOffset": 5537452, + "headersEndOffset": 5537628, + "endOffset": 5537867, + "body": { + "mimeType": "text/plain", + "lineNumber": 76723, + "beginOffset": 5537452, + "headersEndOffset": 5537628, + "endOffset": 5537867, + "octets": 239, + "lines": 9 + }, + "octets": 239 + }, + "octets": 415, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76738, + "beginOffset": 5537901, + "headersEndOffset": 5537903, + "endOffset": 5538444, + "message": { + "lineNumber": 76739, + "beginOffset": 5537903, + "headersEndOffset": 5538033, + "endOffset": 5538444, + "body": { + "mimeType": "text/plain", + "lineNumber": 76739, + "beginOffset": 5537903, + "headersEndOffset": 5538033, + "endOffset": 5538444, + "octets": 411, + "lines": 12 + }, + "octets": 411 + }, + "octets": 541, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76757, + "beginOffset": 5538478, + "headersEndOffset": 5538480, + "endOffset": 5539533, + "message": { + "lineNumber": 76758, + "beginOffset": 5538480, + "headersEndOffset": 5538601, + "endOffset": 5539533, + "body": { + "mimeType": "text/plain", + "lineNumber": 76758, + "beginOffset": 5538480, + "headersEndOffset": 5538601, + "endOffset": 5539533, + "octets": 932, + "lines": 28 + }, + "octets": 932 + }, + "octets": 1053, + "lines": 32 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76792, + "beginOffset": 5539567, + "headersEndOffset": 5539569, + "endOffset": 5540001, + "message": { + "lineNumber": 76793, + "beginOffset": 5539569, + "headersEndOffset": 5539701, + "endOffset": 5540001, + "body": { + "mimeType": "text/plain", + "lineNumber": 76793, + "beginOffset": 5539569, + "headersEndOffset": 5539701, + "endOffset": 5540001, + "octets": 300, + "lines": 9 + }, + "octets": 300 + }, + "octets": 432, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76808, + "beginOffset": 5540035, + "headersEndOffset": 5540037, + "endOffset": 5540594, + "message": { + "lineNumber": 76809, + "beginOffset": 5540037, + "headersEndOffset": 5540170, + "endOffset": 5540594, + "body": { + "mimeType": "text/plain", + "lineNumber": 76809, + "beginOffset": 5540037, + "headersEndOffset": 5540170, + "endOffset": 5540594, + "octets": 424, + "lines": 14 + }, + "octets": 424 + }, + "octets": 557, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76829, + "beginOffset": 5540628, + "headersEndOffset": 5540630, + "endOffset": 5540898, + "message": { + "lineNumber": 76830, + "beginOffset": 5540630, + "headersEndOffset": 5540749, + "endOffset": 5540898, + "body": { + "mimeType": "text/plain", + "lineNumber": 76830, + "beginOffset": 5540630, + "headersEndOffset": 5540749, + "endOffset": 5540898, + "octets": 149, + "lines": 4 + }, + "octets": 149 + }, + "octets": 268, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76840, + "beginOffset": 5540932, + "headersEndOffset": 5540934, + "endOffset": 5541249, + "message": { + "lineNumber": 76841, + "beginOffset": 5540934, + "headersEndOffset": 5541063, + "endOffset": 5541249, + "body": { + "mimeType": "text/plain", + "lineNumber": 76841, + "beginOffset": 5540934, + "headersEndOffset": 5541063, + "endOffset": 5541249, + "octets": 186, + "lines": 7 + }, + "octets": 186 + }, + "octets": 315, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76854, + "beginOffset": 5541283, + "headersEndOffset": 5541285, + "endOffset": 5542149, + "message": { + "lineNumber": 76855, + "beginOffset": 5541285, + "headersEndOffset": 5541419, + "endOffset": 5542149, + "body": { + "mimeType": "text/plain", + "lineNumber": 76855, + "beginOffset": 5541285, + "headersEndOffset": 5541419, + "endOffset": 5542149, + "octets": 730, + "lines": 14 + }, + "octets": 730 + }, + "octets": 864, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76875, + "beginOffset": 5542183, + "headersEndOffset": 5542185, + "endOffset": 5543318, + "message": { + "lineNumber": 76876, + "beginOffset": 5542185, + "headersEndOffset": 5542335, + "endOffset": 5543318, + "body": { + "mimeType": "text/plain", + "lineNumber": 76876, + "beginOffset": 5542185, + "headersEndOffset": 5542335, + "endOffset": 5543318, + "octets": 983, + "lines": 26 + }, + "octets": 983 + }, + "octets": 1133, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76908, + "beginOffset": 5543352, + "headersEndOffset": 5543354, + "endOffset": 5543746, + "message": { + "lineNumber": 76909, + "beginOffset": 5543354, + "headersEndOffset": 5543492, + "endOffset": 5543746, + "body": { + "mimeType": "text/plain", + "lineNumber": 76909, + "beginOffset": 5543354, + "headersEndOffset": 5543492, + "endOffset": 5543746, + "octets": 254, + "lines": 7 + }, + "octets": 254 + }, + "octets": 392, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76922, + "beginOffset": 5543780, + "headersEndOffset": 5543782, + "endOffset": 5544041, + "message": { + "lineNumber": 76923, + "beginOffset": 5543782, + "headersEndOffset": 5543908, + "endOffset": 5544041, + "body": { + "mimeType": "text/plain", + "lineNumber": 76923, + "beginOffset": 5543782, + "headersEndOffset": 5543908, + "endOffset": 5544041, + "octets": 133, + "lines": 6 + }, + "octets": 133 + }, + "octets": 259, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76935, + "beginOffset": 5544075, + "headersEndOffset": 5544077, + "endOffset": 5545018, + "message": { + "lineNumber": 76936, + "beginOffset": 5544077, + "headersEndOffset": 5544257, + "endOffset": 5545018, + "body": { + "mimeType": "text/plain", + "lineNumber": 76936, + "beginOffset": 5544077, + "headersEndOffset": 5544257, + "endOffset": 5545018, + "octets": 761, + "lines": 16 + }, + "octets": 761 + }, + "octets": 941, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76959, + "beginOffset": 5545052, + "headersEndOffset": 5545054, + "endOffset": 5545633, + "message": { + "lineNumber": 76960, + "beginOffset": 5545054, + "headersEndOffset": 5545218, + "endOffset": 5545633, + "body": { + "mimeType": "text/plain", + "lineNumber": 76960, + "beginOffset": 5545054, + "headersEndOffset": 5545218, + "endOffset": 5545633, + "octets": 415, + "lines": 16 + }, + "octets": 415 + }, + "octets": 579, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76982, + "beginOffset": 5545667, + "headersEndOffset": 5545669, + "endOffset": 5547113, + "message": { + "lineNumber": 76983, + "beginOffset": 5545669, + "headersEndOffset": 5545805, + "endOffset": 5547113, + "body": { + "mimeType": "text/plain", + "lineNumber": 76983, + "beginOffset": 5545669, + "headersEndOffset": 5545805, + "endOffset": 5547113, + "octets": 1308, + "lines": 21 + }, + "octets": 1308 + }, + "octets": 1444, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77010, + "beginOffset": 5547147, + "headersEndOffset": 5547149, + "endOffset": 5547408, + "message": { + "lineNumber": 77011, + "beginOffset": 5547149, + "headersEndOffset": 5547259, + "endOffset": 5547408, + "body": { + "mimeType": "text/plain", + "lineNumber": 77011, + "beginOffset": 5547149, + "headersEndOffset": 5547259, + "endOffset": 5547408, + "octets": 149, + "lines": 6 + }, + "octets": 149 + }, + "octets": 259, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77023, + "beginOffset": 5547442, + "headersEndOffset": 5547444, + "endOffset": 5547895, + "message": { + "lineNumber": 77024, + "beginOffset": 5547444, + "headersEndOffset": 5547585, + "endOffset": 5547895, + "body": { + "mimeType": "text/plain", + "lineNumber": 77024, + "beginOffset": 5547444, + "headersEndOffset": 5547585, + "endOffset": 5547895, + "octets": 310, + "lines": 11 + }, + "octets": 310 + }, + "octets": 451, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77041, + "beginOffset": 5547929, + "headersEndOffset": 5547931, + "endOffset": 5548254, + "message": { + "lineNumber": 77042, + "beginOffset": 5547931, + "headersEndOffset": 5548061, + "endOffset": 5548254, + "body": { + "mimeType": "text/plain", + "lineNumber": 77042, + "beginOffset": 5547931, + "headersEndOffset": 5548061, + "endOffset": 5548254, + "octets": 193, + "lines": 6 + }, + "octets": 193 + }, + "octets": 323, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77054, + "beginOffset": 5548288, + "headersEndOffset": 5548290, + "endOffset": 5548809, + "message": { + "lineNumber": 77055, + "beginOffset": 5548290, + "headersEndOffset": 5548399, + "endOffset": 5548809, + "body": { + "mimeType": "text/plain", + "lineNumber": 77055, + "beginOffset": 5548290, + "headersEndOffset": 5548399, + "endOffset": 5548809, + "octets": 410, + "lines": 12 + }, + "octets": 410 + }, + "octets": 519, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77073, + "beginOffset": 5548843, + "headersEndOffset": 5548845, + "endOffset": 5549293, + "message": { + "lineNumber": 77074, + "beginOffset": 5548845, + "headersEndOffset": 5548983, + "endOffset": 5549293, + "body": { + "mimeType": "text/plain", + "lineNumber": 77074, + "beginOffset": 5548845, + "headersEndOffset": 5548983, + "endOffset": 5549293, + "octets": 310, + "lines": 8 + }, + "octets": 310 + }, + "octets": 448, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77088, + "beginOffset": 5549327, + "headersEndOffset": 5549329, + "endOffset": 5550111, + "message": { + "lineNumber": 77089, + "beginOffset": 5549329, + "headersEndOffset": 5549476, + "endOffset": 5550111, + "body": { + "mimeType": "text/plain", + "lineNumber": 77089, + "beginOffset": 5549329, + "headersEndOffset": 5549476, + "endOffset": 5550111, + "octets": 635, + "lines": 17 + }, + "octets": 635 + }, + "octets": 782, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77112, + "beginOffset": 5550145, + "headersEndOffset": 5550147, + "endOffset": 5550789, + "message": { + "lineNumber": 77113, + "beginOffset": 5550147, + "headersEndOffset": 5550304, + "endOffset": 5550789, + "body": { + "mimeType": "text/plain", + "lineNumber": 77113, + "beginOffset": 5550147, + "headersEndOffset": 5550304, + "endOffset": 5550789, + "octets": 485, + "lines": 10 + }, + "octets": 485 + }, + "octets": 642, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77129, + "beginOffset": 5550823, + "headersEndOffset": 5550825, + "endOffset": 5552161, + "message": { + "lineNumber": 77130, + "beginOffset": 5550825, + "headersEndOffset": 5550962, + "endOffset": 5552161, + "body": { + "mimeType": "text/plain", + "lineNumber": 77130, + "beginOffset": 5550825, + "headersEndOffset": 5550962, + "endOffset": 5552161, + "octets": 1199, + "lines": 27 + }, + "octets": 1199 + }, + "octets": 1336, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77163, + "beginOffset": 5552195, + "headersEndOffset": 5552197, + "endOffset": 5552644, + "message": { + "lineNumber": 77164, + "beginOffset": 5552197, + "headersEndOffset": 5552377, + "endOffset": 5552644, + "body": { + "mimeType": "text/plain", + "lineNumber": 77164, + "beginOffset": 5552197, + "headersEndOffset": 5552377, + "endOffset": 5552644, + "octets": 267, + "lines": 8 + }, + "octets": 267 + }, + "octets": 447, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77178, + "beginOffset": 5552678, + "headersEndOffset": 5552680, + "endOffset": 5552996, + "message": { + "lineNumber": 77179, + "beginOffset": 5552680, + "headersEndOffset": 5552799, + "endOffset": 5552996, + "body": { + "mimeType": "text/plain", + "lineNumber": 77179, + "beginOffset": 5552680, + "headersEndOffset": 5552799, + "endOffset": 5552996, + "octets": 197, + "lines": 4 + }, + "octets": 197 + }, + "octets": 316, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77189, + "beginOffset": 5553030, + "headersEndOffset": 5553032, + "endOffset": 5554065, + "message": { + "lineNumber": 77190, + "beginOffset": 5553032, + "headersEndOffset": 5553176, + "endOffset": 5554065, + "body": { + "mimeType": "text/plain", + "lineNumber": 77190, + "beginOffset": 5553032, + "headersEndOffset": 5553176, + "endOffset": 5554065, + "octets": 889, + "lines": 24 + }, + "octets": 889 + }, + "octets": 1033, + "lines": 28 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77220, + "beginOffset": 5554099, + "headersEndOffset": 5554101, + "endOffset": 5554955, + "message": { + "lineNumber": 77221, + "beginOffset": 5554101, + "headersEndOffset": 5554230, + "endOffset": 5554955, + "body": { + "mimeType": "text/plain", + "lineNumber": 77221, + "beginOffset": 5554101, + "headersEndOffset": 5554230, + "endOffset": 5554955, + "octets": 725, + "lines": 11 + }, + "octets": 725 + }, + "octets": 854, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77238, + "beginOffset": 5554989, + "headersEndOffset": 5554991, + "endOffset": 5555827, + "message": { + "lineNumber": 77239, + "beginOffset": 5554991, + "headersEndOffset": 5555107, + "endOffset": 5555827, + "body": { + "mimeType": "text/plain", + "lineNumber": 77239, + "beginOffset": 5554991, + "headersEndOffset": 5555107, + "endOffset": 5555827, + "octets": 720, + "lines": 17 + }, + "octets": 720 + }, + "octets": 836, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77262, + "beginOffset": 5555861, + "headersEndOffset": 5555863, + "endOffset": 5556390, + "message": { + "lineNumber": 77263, + "beginOffset": 5555863, + "headersEndOffset": 5555999, + "endOffset": 5556390, + "body": { + "mimeType": "text/plain", + "lineNumber": 77263, + "beginOffset": 5555863, + "headersEndOffset": 5555999, + "endOffset": 5556390, + "octets": 391, + "lines": 11 + }, + "octets": 391 + }, + "octets": 527, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77280, + "beginOffset": 5556424, + "headersEndOffset": 5556426, + "endOffset": 5557567, + "message": { + "lineNumber": 77281, + "beginOffset": 5556426, + "headersEndOffset": 5556566, + "endOffset": 5557567, + "body": { + "mimeType": "text/plain", + "lineNumber": 77281, + "beginOffset": 5556426, + "headersEndOffset": 5556566, + "endOffset": 5557567, + "octets": 1001, + "lines": 24 + }, + "octets": 1001 + }, + "octets": 1141, + "lines": 28 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77311, + "beginOffset": 5557601, + "headersEndOffset": 5557603, + "endOffset": 5558229, + "message": { + "lineNumber": 77312, + "beginOffset": 5557603, + "headersEndOffset": 5557752, + "endOffset": 5558229, + "body": { + "mimeType": "text/plain", + "lineNumber": 77312, + "beginOffset": 5557603, + "headersEndOffset": 5557752, + "endOffset": 5558229, + "octets": 477, + "lines": 10 + }, + "octets": 477 + }, + "octets": 626, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77328, + "beginOffset": 5558263, + "headersEndOffset": 5558265, + "endOffset": 5558691, + "message": { + "lineNumber": 77329, + "beginOffset": 5558265, + "headersEndOffset": 5558402, + "endOffset": 5558691, + "body": { + "mimeType": "text/plain", + "lineNumber": 77329, + "beginOffset": 5558265, + "headersEndOffset": 5558402, + "endOffset": 5558691, + "octets": 289, + "lines": 10 + }, + "octets": 289 + }, + "octets": 426, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77345, + "beginOffset": 5558725, + "headersEndOffset": 5558727, + "endOffset": 5559142, + "message": { + "lineNumber": 77346, + "beginOffset": 5558727, + "headersEndOffset": 5558856, + "endOffset": 5559142, + "body": { + "mimeType": "text/plain", + "lineNumber": 77346, + "beginOffset": 5558727, + "headersEndOffset": 5558856, + "endOffset": 5559142, + "octets": 286, + "lines": 4 + }, + "octets": 286 + }, + "octets": 415, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77356, + "beginOffset": 5559176, + "headersEndOffset": 5559178, + "endOffset": 5559973, + "message": { + "lineNumber": 77357, + "beginOffset": 5559178, + "headersEndOffset": 5559303, + "endOffset": 5559973, + "body": { + "mimeType": "text/plain", + "lineNumber": 77357, + "beginOffset": 5559178, + "headersEndOffset": 5559303, + "endOffset": 5559973, + "octets": 670, + "lines": 27 + }, + "octets": 670 + }, + "octets": 795, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77390, + "beginOffset": 5560007, + "headersEndOffset": 5560009, + "endOffset": 5562461, + "message": { + "lineNumber": 77391, + "beginOffset": 5560009, + "headersEndOffset": 5560157, + "endOffset": 5562461, + "body": { + "mimeType": "text/plain", + "lineNumber": 77391, + "beginOffset": 5560009, + "headersEndOffset": 5560157, + "endOffset": 5562461, + "octets": 2304, + "lines": 46 + }, + "octets": 2304 + }, + "octets": 2452, + "lines": 50 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77443, + "beginOffset": 5562495, + "headersEndOffset": 5562497, + "endOffset": 5563432, + "message": { + "lineNumber": 77444, + "beginOffset": 5562497, + "headersEndOffset": 5562623, + "endOffset": 5563432, + "body": { + "mimeType": "text/plain", + "lineNumber": 77444, + "beginOffset": 5562497, + "headersEndOffset": 5562623, + "endOffset": 5563432, + "octets": 809, + "lines": 17 + }, + "octets": 809 + }, + "octets": 935, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77467, + "beginOffset": 5563466, + "headersEndOffset": 5563468, + "endOffset": 5563802, + "message": { + "lineNumber": 77468, + "beginOffset": 5563468, + "headersEndOffset": 5563566, + "endOffset": 5563802, + "body": { + "mimeType": "text/plain", + "lineNumber": 77468, + "beginOffset": 5563468, + "headersEndOffset": 5563566, + "endOffset": 5563802, + "octets": 236, + "lines": 10 + }, + "octets": 236 + }, + "octets": 334, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77484, + "beginOffset": 5563836, + "headersEndOffset": 5563838, + "endOffset": 5564651, + "message": { + "lineNumber": 77485, + "beginOffset": 5563838, + "headersEndOffset": 5563963, + "endOffset": 5564651, + "body": { + "mimeType": "text/plain", + "lineNumber": 77485, + "beginOffset": 5563838, + "headersEndOffset": 5563963, + "endOffset": 5564651, + "octets": 688, + "lines": 20 + }, + "octets": 688 + }, + "octets": 813, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77511, + "beginOffset": 5564685, + "headersEndOffset": 5564687, + "endOffset": 5567416, + "message": { + "lineNumber": 77512, + "beginOffset": 5564687, + "headersEndOffset": 5564801, + "endOffset": 5567416, + "body": { + "mimeType": "text/plain", + "lineNumber": 77512, + "beginOffset": 5564687, + "headersEndOffset": 5564801, + "endOffset": 5567416, + "octets": 2615, + "lines": 68 + }, + "octets": 2615 + }, + "octets": 2729, + "lines": 72 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77586, + "beginOffset": 5567450, + "headersEndOffset": 5567452, + "endOffset": 5568805, + "message": { + "lineNumber": 77587, + "beginOffset": 5567452, + "headersEndOffset": 5567562, + "endOffset": 5568805, + "body": { + "mimeType": "text/plain", + "lineNumber": 77587, + "beginOffset": 5567452, + "headersEndOffset": 5567562, + "endOffset": 5568805, + "octets": 1243, + "lines": 34 + }, + "octets": 1243 + }, + "octets": 1353, + "lines": 38 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77627, + "beginOffset": 5568839, + "headersEndOffset": 5568841, + "endOffset": 5570791, + "message": { + "lineNumber": 77628, + "beginOffset": 5568841, + "headersEndOffset": 5568951, + "endOffset": 5570791, + "body": { + "mimeType": "text/plain", + "lineNumber": 77628, + "beginOffset": 5568841, + "headersEndOffset": 5568951, + "endOffset": 5570791, + "octets": 1840, + "lines": 43 + }, + "octets": 1840 + }, + "octets": 1950, + "lines": 47 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77677, + "beginOffset": 5570825, + "headersEndOffset": 5570827, + "endOffset": 5571542, + "message": { + "lineNumber": 77678, + "beginOffset": 5570827, + "headersEndOffset": 5570960, + "endOffset": 5571542, + "body": { + "mimeType": "text/plain", + "lineNumber": 77678, + "beginOffset": 5570827, + "headersEndOffset": 5570960, + "endOffset": 5571542, + "octets": 582, + "lines": 12 + }, + "octets": 582 + }, + "octets": 715, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77696, + "beginOffset": 5571576, + "headersEndOffset": 5571578, + "endOffset": 5573024, + "message": { + "lineNumber": 77697, + "beginOffset": 5571578, + "headersEndOffset": 5571670, + "endOffset": 5573024, + "body": { + "mimeType": "text/plain", + "lineNumber": 77697, + "beginOffset": 5571578, + "headersEndOffset": 5571670, + "endOffset": 5573024, + "octets": 1354, + "lines": 20 + }, + "octets": 1354 + }, + "octets": 1446, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77723, + "beginOffset": 5573058, + "headersEndOffset": 5573060, + "endOffset": 5575356, + "message": { + "lineNumber": 77724, + "beginOffset": 5573060, + "headersEndOffset": 5573180, + "endOffset": 5575356, + "body": { + "mimeType": "text/plain", + "lineNumber": 77724, + "beginOffset": 5573060, + "headersEndOffset": 5573180, + "endOffset": 5575356, + "octets": 2176, + "lines": 49 + }, + "octets": 2176 + }, + "octets": 2296, + "lines": 53 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77779, + "beginOffset": 5575390, + "headersEndOffset": 5575392, + "endOffset": 5577580, + "message": { + "lineNumber": 77780, + "beginOffset": 5575392, + "headersEndOffset": 5575517, + "endOffset": 5577580, + "body": { + "mimeType": "text/plain", + "lineNumber": 77780, + "beginOffset": 5575392, + "headersEndOffset": 5575517, + "endOffset": 5577580, + "octets": 2063, + "lines": 42 + }, + "octets": 2063 + }, + "octets": 2188, + "lines": 46 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77828, + "beginOffset": 5577614, + "headersEndOffset": 5577616, + "endOffset": 5578437, + "message": { + "lineNumber": 77829, + "beginOffset": 5577616, + "headersEndOffset": 5577741, + "endOffset": 5578437, + "body": { + "mimeType": "text/plain", + "lineNumber": 77829, + "beginOffset": 5577616, + "headersEndOffset": 5577741, + "endOffset": 5578437, + "octets": 696, + "lines": 19 + }, + "octets": 696 + }, + "octets": 821, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77854, + "beginOffset": 5578471, + "headersEndOffset": 5578473, + "endOffset": 5579450, + "message": { + "lineNumber": 77855, + "beginOffset": 5578473, + "headersEndOffset": 5578614, + "endOffset": 5579450, + "body": { + "mimeType": "text/plain", + "lineNumber": 77855, + "beginOffset": 5578473, + "headersEndOffset": 5578614, + "endOffset": 5579450, + "octets": 836, + "lines": 16 + }, + "octets": 836 + }, + "octets": 977, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77877, + "beginOffset": 5579484, + "headersEndOffset": 5579486, + "endOffset": 5580359, + "message": { + "lineNumber": 77878, + "beginOffset": 5579486, + "headersEndOffset": 5579614, + "endOffset": 5580359, + "body": { + "mimeType": "text/plain", + "lineNumber": 77878, + "beginOffset": 5579486, + "headersEndOffset": 5579614, + "endOffset": 5580359, + "octets": 745, + "lines": 21 + }, + "octets": 745 + }, + "octets": 873, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77905, + "beginOffset": 5580393, + "headersEndOffset": 5580395, + "endOffset": 5581257, + "message": { + "lineNumber": 77906, + "beginOffset": 5580395, + "headersEndOffset": 5580501, + "endOffset": 5581257, + "body": { + "mimeType": "text/plain", + "lineNumber": 77906, + "beginOffset": 5580395, + "headersEndOffset": 5580501, + "endOffset": 5581257, + "octets": 756, + "lines": 16 + }, + "octets": 756 + }, + "octets": 862, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77928, + "beginOffset": 5581291, + "headersEndOffset": 5581293, + "endOffset": 5581820, + "message": { + "lineNumber": 77929, + "beginOffset": 5581293, + "headersEndOffset": 5581454, + "endOffset": 5581820, + "body": { + "mimeType": "text/plain", + "lineNumber": 77929, + "beginOffset": 5581293, + "headersEndOffset": 5581454, + "endOffset": 5581820, + "octets": 366, + "lines": 7 + }, + "octets": 366 + }, + "octets": 527, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77943, + "beginOffset": 5581854, + "headersEndOffset": 5581856, + "endOffset": 5582597, + "message": { + "lineNumber": 77944, + "beginOffset": 5581856, + "headersEndOffset": 5581947, + "endOffset": 5582597, + "body": { + "mimeType": "text/plain", + "lineNumber": 77944, + "beginOffset": 5581856, + "headersEndOffset": 5581947, + "endOffset": 5582597, + "octets": 650, + "lines": 15 + }, + "octets": 650 + }, + "octets": 741, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77965, + "beginOffset": 5582631, + "headersEndOffset": 5582633, + "endOffset": 5583169, + "message": { + "lineNumber": 77966, + "beginOffset": 5582633, + "headersEndOffset": 5582786, + "endOffset": 5583169, + "body": { + "mimeType": "text/plain", + "lineNumber": 77966, + "beginOffset": 5582633, + "headersEndOffset": 5582786, + "endOffset": 5583169, + "octets": 383, + "lines": 17 + }, + "octets": 383 + }, + "octets": 536, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77989, + "beginOffset": 5583203, + "headersEndOffset": 5583205, + "endOffset": 5583604, + "message": { + "lineNumber": 77990, + "beginOffset": 5583205, + "headersEndOffset": 5583310, + "endOffset": 5583604, + "body": { + "mimeType": "text/plain", + "lineNumber": 77990, + "beginOffset": 5583205, + "headersEndOffset": 5583310, + "endOffset": 5583604, + "octets": 294, + "lines": 6 + }, + "octets": 294 + }, + "octets": 399, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78002, + "beginOffset": 5583638, + "headersEndOffset": 5583640, + "endOffset": 5584267, + "message": { + "lineNumber": 78003, + "beginOffset": 5583640, + "headersEndOffset": 5583772, + "endOffset": 5584267, + "body": { + "mimeType": "text/plain", + "lineNumber": 78003, + "beginOffset": 5583640, + "headersEndOffset": 5583772, + "endOffset": 5584267, + "octets": 495, + "lines": 16 + }, + "octets": 495 + }, + "octets": 627, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78025, + "beginOffset": 5584301, + "headersEndOffset": 5584303, + "endOffset": 5584803, + "message": { + "lineNumber": 78026, + "beginOffset": 5584303, + "headersEndOffset": 5584404, + "endOffset": 5584803, + "body": { + "mimeType": "text/plain", + "lineNumber": 78026, + "beginOffset": 5584303, + "headersEndOffset": 5584404, + "endOffset": 5584803, + "octets": 399, + "lines": 19 + }, + "octets": 399 + }, + "octets": 500, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78051, + "beginOffset": 5584837, + "headersEndOffset": 5584839, + "endOffset": 5586303, + "message": { + "lineNumber": 78052, + "beginOffset": 5584839, + "headersEndOffset": 5584958, + "endOffset": 5586303, + "body": { + "mimeType": "text/plain", + "lineNumber": 78052, + "beginOffset": 5584839, + "headersEndOffset": 5584958, + "endOffset": 5586303, + "octets": 1345, + "lines": 26 + }, + "octets": 1345 + }, + "octets": 1464, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78084, + "beginOffset": 5586337, + "headersEndOffset": 5586339, + "endOffset": 5586747, + "message": { + "lineNumber": 78085, + "beginOffset": 5586339, + "headersEndOffset": 5586443, + "endOffset": 5586747, + "body": { + "mimeType": "text/plain", + "lineNumber": 78085, + "beginOffset": 5586339, + "headersEndOffset": 5586443, + "endOffset": 5586747, + "octets": 304, + "lines": 9 + }, + "octets": 304 + }, + "octets": 408, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78100, + "beginOffset": 5586781, + "headersEndOffset": 5586783, + "endOffset": 5587985, + "message": { + "lineNumber": 78101, + "beginOffset": 5586783, + "headersEndOffset": 5586930, + "endOffset": 5587985, + "body": { + "mimeType": "text/plain", + "lineNumber": 78101, + "beginOffset": 5586783, + "headersEndOffset": 5586930, + "endOffset": 5587985, + "octets": 1055, + "lines": 36 + }, + "octets": 1055 + }, + "octets": 1202, + "lines": 40 + } + ], + "octets": 66055, + "lines": 1845 + } + ], + "octets": 70738, + "lines": 1958 + }, + "octets": 70738 + }, + { + "mboxMarkerOffset": 5588102, + "lineNumber": 78149, + "beginOffset": 5588111, + "headersEndOffset": 5588934, + "endOffset": 5590853, + "body": { + "mimeType": "text/plain", + "lineNumber": 78149, + "beginOffset": 5588111, + "headersEndOffset": 5588934, + "endOffset": 5590853, + "octets": 1919, + "lines": 49 + }, + "octets": 1919 + }, + { + "mboxMarkerOffset": 5590855, + "lineNumber": 78214, + "beginOffset": 5590864, + "headersEndOffset": 5591607, + "endOffset": 5748407, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 78214, + "beginOffset": 5590864, + "headersEndOffset": 5591607, + "endOffset": 5748407, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 78231, + "beginOffset": 5591635, + "headersEndOffset": 5591637, + "endOffset": 5591750, + "octets": 113, + "lines": 2 + }, + { + "mimeType": "application/x-annotate", + "lineNumber": 78235, + "beginOffset": 5591780, + "headersEndOffset": 5591872, + "endOffset": 5724575, + "octets": 132703, + "lines": 2012 + }, + { + "mimeType": "text/plain", + "lineNumber": 80251, + "beginOffset": 5724605, + "headersEndOffset": 5724607, + "endOffset": 5724663, + "octets": 56, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 80255, + "beginOffset": 5724693, + "headersEndOffset": 5724843, + "endOffset": 5739817, + "octets": 14974, + "lines": 78 + }, + { + "mimeType": "text/plain", + "lineNumber": 80339, + "beginOffset": 5739847, + "headersEndOffset": 5739849, + "endOffset": 5739944, + "octets": 95, + "lines": 6 + }, + { + "mimeType": "image/pbm", + "lineNumber": 80347, + "beginOffset": 5739974, + "headersEndOffset": 5740124, + "endOffset": 5748266, + "octets": 8142, + "lines": 42 + }, + { + "mimeType": "text/plain", + "lineNumber": 80395, + "beginOffset": 5748296, + "headersEndOffset": 5748298, + "endOffset": 5748375, + "octets": 77, + "lines": 4 + } + ], + "octets": 156800, + "lines": 2171 + }, + "octets": 156800 + }, + { + "mboxMarkerOffset": 5748409, + "lineNumber": 80403, + "beginOffset": 5748418, + "headersEndOffset": 5748956, + "endOffset": 5749545, + "body": { + "mimeType": "text/richtext", + "lineNumber": 80403, + "beginOffset": 5748418, + "headersEndOffset": 5748956, + "endOffset": 5749545, + "octets": 589, + "lines": 21 + }, + "octets": 589 + }, + { + "mboxMarkerOffset": 5749547, + "lineNumber": 80441, + "beginOffset": 5749556, + "headersEndOffset": 5750765, + "endOffset": 5811866, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 80441, + "beginOffset": 5749556, + "headersEndOffset": 5750765, + "endOffset": 5811866, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 80468, + "beginOffset": 5750964, + "headersEndOffset": 5751010, + "endOffset": 5751766, + "octets": 756, + "lines": 26 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 80498, + "beginOffset": 5751809, + "headersEndOffset": 5751897, + "endOffset": 5811821, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 80502, + "beginOffset": 5751940, + "headersEndOffset": 5752034, + "endOffset": 5752861, + "octets": 827, + "lines": 25 + }, + { + "mimeType": "image/gif", + "lineNumber": 80532, + "beginOffset": 5752906, + "headersEndOffset": 5753003, + "endOffset": 5811629, + "octets": 58626, + "lines": 755 + }, + { + "mimeType": "text/richtext", + "lineNumber": 81293, + "beginOffset": 5811674, + "headersEndOffset": 5811768, + "endOffset": 5811774, + "octets": 6, + "lines": 1 + } + ], + "octets": 59924, + "lines": 798 + } + ], + "octets": 61101, + "lines": 837 + }, + "octets": 61101 + }, + { + "mboxMarkerOffset": 5811868, + "lineNumber": 81303, + "beginOffset": 5811877, + "headersEndOffset": 5812634, + "endOffset": 5869132, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 81303, + "beginOffset": 5811877, + "headersEndOffset": 5812634, + "endOffset": 5869132, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 81322, + "beginOffset": 5812686, + "headersEndOffset": 5812779, + "endOffset": 5812960, + "octets": 181, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 81334, + "beginOffset": 5813012, + "headersEndOffset": 5813074, + "endOffset": 5869078, + "octets": 56004, + "lines": 757 + } + ], + "octets": 56498, + "lines": 775 + }, + "octets": 56498 + }, + { + "mboxMarkerOffset": 5869134, + "lineNumber": 82097, + "beginOffset": 5869167, + "headersEndOffset": 5870664, + "endOffset": 5872038, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 82097, + "beginOffset": 5869167, + "headersEndOffset": 5870664, + "endOffset": 5872038, + "octets": 1374, + "lines": 34 + }, + "octets": 1374 + }, + { + "mboxMarkerOffset": 5872040, + "lineNumber": 82163, + "beginOffset": 5872049, + "headersEndOffset": 5872857, + "endOffset": 5899485, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 82163, + "beginOffset": 5872049, + "headersEndOffset": 5872857, + "endOffset": 5899485, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 82180, + "beginOffset": 5872931, + "headersEndOffset": 5873010, + "endOffset": 5873393, + "octets": 383, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 82198, + "beginOffset": 5873421, + "headersEndOffset": 5873515, + "endOffset": 5899455, + "message": { + "lineNumber": 82202, + "beginOffset": 5873515, + "headersEndOffset": 5874597, + "endOffset": 5899455, + "body": { + "mimeType": "text/html", + "lineNumber": 82202, + "beginOffset": 5873515, + "headersEndOffset": 5874597, + "endOffset": 5899455, + "octets": 24858, + "lines": 463 + }, + "octets": 24858 + }, + "octets": 25940, + "lines": 477 + } + ], + "octets": 26628, + "lines": 504 + }, + "octets": 26628 + }, + { + "mboxMarkerOffset": 5899487, + "lineNumber": 82683, + "beginOffset": 5899496, + "headersEndOffset": 5900178, + "endOffset": 5923009, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 82683, + "beginOffset": 5899496, + "headersEndOffset": 5900178, + "endOffset": 5923009, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 82700, + "beginOffset": 5900275, + "headersEndOffset": 5900356, + "endOffset": 5900391, + "octets": 35, + "lines": 1 + }, + { + "mimeType": "image/gif", + "lineNumber": 82706, + "beginOffset": 5900442, + "headersEndOffset": 5900504, + "endOffset": 5922958, + "octets": 22454, + "lines": 304 + } + ], + "octets": 22831, + "lines": 317 + }, + "octets": 22831 + }, + { + "mboxMarkerOffset": 5923011, + "lineNumber": 83015, + "beginOffset": 5923044, + "headersEndOffset": 5923581, + "endOffset": 5925456, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 83015, + "beginOffset": 5923044, + "headersEndOffset": 5923581, + "endOffset": 5925456, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 83029, + "beginOffset": 5923590, + "headersEndOffset": 5923636, + "endOffset": 5924829, + "octets": 1193, + "lines": 21 + }, + { + "mimeType": "text/plain", + "lineNumber": 83054, + "beginOffset": 5924840, + "headersEndOffset": 5924970, + "endOffset": 5925118, + "octets": 148, + "lines": 3 + }, + { + "mimeType": "text/plain", + "lineNumber": 83062, + "beginOffset": 5925129, + "headersEndOffset": 5925249, + "endOffset": 5925445, + "octets": 196, + "lines": 3 + } + ], + "octets": 1875, + "lines": 42 + }, + "octets": 1875 + }, + { + "mboxMarkerOffset": 5925458, + "lineNumber": 83071, + "beginOffset": 5925467, + "headersEndOffset": 5926279, + "endOffset": 6186575, + "body": { + "mimeType": "audio/basic", + "lineNumber": 83071, + "beginOffset": 5925467, + "headersEndOffset": 5926279, + "endOffset": 6186575, + "octets": 260296, + "lines": 3518 + }, + "octets": 260296 + }, + { + "mboxMarkerOffset": 6186577, + "lineNumber": 86609, + "beginOffset": 6186586, + "headersEndOffset": 6187457, + "endOffset": 6287418, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 86609, + "beginOffset": 6186586, + "headersEndOffset": 6187457, + "endOffset": 6287418, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 86630, + "beginOffset": 6187474, + "headersEndOffset": 6187554, + "endOffset": 6187752, + "octets": 198, + "lines": 9 + }, + { + "mimeType": "image/pbm", + "lineNumber": 86643, + "beginOffset": 6187769, + "headersEndOffset": 6187877, + "endOffset": 6287399, + "octets": 99522, + "lines": 1276 + } + ], + "octets": 99961, + "lines": 1296 + }, + "octets": 99961 + }, + { + "mboxMarkerOffset": 6287420, + "lineNumber": 87926, + "beginOffset": 6287429, + "headersEndOffset": 6288325, + "endOffset": 6373131, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 87926, + "beginOffset": 6287429, + "headersEndOffset": 6288325, + "endOffset": 6373131, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 87946, + "beginOffset": 6288335, + "headersEndOffset": 6288383, + "endOffset": 6289347, + "octets": 964, + "lines": 21 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 87971, + "beginOffset": 6289359, + "headersEndOffset": 6289424, + "endOffset": 6373117, + "children": [ + { + "mimeType": "multipart/mixed", + "lineNumber": 87975, + "beginOffset": 6289449, + "headersEndOffset": 6289818, + "endOffset": 6373090, + "children": [ + { + "mimeType": "multipart/mixed", + "lineNumber": 87984, + "beginOffset": 6289841, + "headersEndOffset": 6289946, + "endOffset": 6291930, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 87988, + "beginOffset": 6289969, + "headersEndOffset": 6290096, + "endOffset": 6290470, + "octets": 374, + "lines": 8 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88002, + "beginOffset": 6290495, + "headersEndOffset": 6290621, + "endOffset": 6291023, + "octets": 402, + "lines": 10 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88018, + "beginOffset": 6291048, + "headersEndOffset": 6291177, + "endOffset": 6291903, + "octets": 726, + "lines": 18 + } + ], + "octets": 1984, + "lines": 55 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 88044, + "beginOffset": 6291955, + "headersEndOffset": 6292057, + "endOffset": 6369276, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 88048, + "beginOffset": 6292080, + "headersEndOffset": 6292216, + "endOffset": 6309101, + "octets": 16885, + "lines": 470 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88524, + "beginOffset": 6309126, + "headersEndOffset": 6309261, + "endOffset": 6323910, + "octets": 14649, + "lines": 395 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 88925, + "beginOffset": 6323935, + "headersEndOffset": 6324039, + "endOffset": 6368422, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 88929, + "beginOffset": 6324062, + "headersEndOffset": 6324208, + "endOffset": 6330524, + "octets": 6316, + "lines": 164 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89099, + "beginOffset": 6330549, + "headersEndOffset": 6330680, + "endOffset": 6336095, + "octets": 5415, + "lines": 160 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89265, + "beginOffset": 6336120, + "headersEndOffset": 6336261, + "endOffset": 6343756, + "octets": 7495, + "lines": 197 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89468, + "beginOffset": 6343781, + "headersEndOffset": 6343909, + "endOffset": 6350569, + "octets": 6660, + "lines": 184 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89658, + "beginOffset": 6350594, + "headersEndOffset": 6350735, + "endOffset": 6368395, + "octets": 17660, + "lines": 492 + } + ], + "octets": 44383, + "lines": 1228 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90158, + "beginOffset": 6368447, + "headersEndOffset": 6368545, + "endOffset": 6369249, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90162, + "beginOffset": 6368568, + "headersEndOffset": 6368706, + "endOffset": 6369222, + "octets": 516, + "lines": 21 + } + ], + "octets": 704, + "lines": 28 + } + ], + "octets": 77219, + "lines": 2144 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90193, + "beginOffset": 6369301, + "headersEndOffset": 6369415, + "endOffset": 6373063, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90197, + "beginOffset": 6369438, + "headersEndOffset": 6369580, + "endOffset": 6370758, + "octets": 1178, + "lines": 29 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90232, + "beginOffset": 6370783, + "headersEndOffset": 6370913, + "endOffset": 6372168, + "octets": 1255, + "lines": 35 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90273, + "beginOffset": 6372193, + "headersEndOffset": 6372337, + "endOffset": 6373036, + "octets": 699, + "lines": 22 + } + ], + "octets": 3648, + "lines": 105 + } + ], + "octets": 83272, + "lines": 2320 + } + ], + "octets": 83693, + "lines": 2332 + } + ], + "octets": 84806, + "lines": 2362 + }, + "octets": 84806 + }, + { + "mboxMarkerOffset": 6373133, + "lineNumber": 90309, + "beginOffset": 6373142, + "headersEndOffset": 6373961, + "endOffset": 6383386, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 90309, + "beginOffset": 6373142, + "headersEndOffset": 6373961, + "endOffset": 6383386, + "octets": 9425, + "lines": 226 + }, + "octets": 9425 + }, + { + "mboxMarkerOffset": 6383388, + "lineNumber": 90554, + "beginOffset": 6383397, + "headersEndOffset": 6384141, + "endOffset": 6477811, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 90554, + "beginOffset": 6383397, + "headersEndOffset": 6384141, + "endOffset": 6477811, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 90574, + "beginOffset": 6384340, + "headersEndOffset": 6384386, + "endOffset": 6385165, + "octets": 779, + "lines": 23 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90601, + "beginOffset": 6385208, + "headersEndOffset": 6385296, + "endOffset": 6477768, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90605, + "beginOffset": 6385339, + "headersEndOffset": 6385433, + "endOffset": 6385767, + "octets": 334, + "lines": 7 + }, + { + "mimeType": "audio/basic", + "lineNumber": 90617, + "beginOffset": 6385812, + "headersEndOffset": 6385910, + "endOffset": 6408254, + "octets": 22344, + "lines": 320 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90943, + "beginOffset": 6408299, + "headersEndOffset": 6408393, + "endOffset": 6408564, + "octets": 171, + "lines": 5 + }, + { + "mimeType": "audio/basic", + "lineNumber": 90953, + "beginOffset": 6408609, + "headersEndOffset": 6408710, + "endOffset": 6456608, + "octets": 47898, + "lines": 685 + }, + { + "mimeType": "text/richtext", + "lineNumber": 91644, + "beginOffset": 6456653, + "headersEndOffset": 6456747, + "endOffset": 6456819, + "octets": 72, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 91651, + "beginOffset": 6456864, + "headersEndOffset": 6456958, + "endOffset": 6477470, + "octets": 20512, + "lines": 294 + }, + { + "mimeType": "text/richtext", + "lineNumber": 91951, + "beginOffset": 6477515, + "headersEndOffset": 6477609, + "endOffset": 6477721, + "octets": 112, + "lines": 8 + } + ], + "octets": 92472, + "lines": 1360 + } + ], + "octets": 93670, + "lines": 1396 + }, + "octets": 93670 + }, + { + "mboxMarkerOffset": 6477813, + "lineNumber": 91967, + "beginOffset": 6477822, + "headersEndOffset": 6478593, + "endOffset": 6513758, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 91967, + "beginOffset": 6477822, + "headersEndOffset": 6478593, + "endOffset": 6513758, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 91989, + "beginOffset": 6478838, + "headersEndOffset": 6478914, + "endOffset": 6479347, + "octets": 433, + "lines": 13 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 92007, + "beginOffset": 6479395, + "headersEndOffset": 6479459, + "endOffset": 6513483, + "octets": 34024, + "lines": 460 + }, + { + "mimeType": "text/richtext", + "lineNumber": 92472, + "beginOffset": 6513531, + "headersEndOffset": 6513607, + "endOffset": 6513708, + "octets": 101, + "lines": 7 + } + ], + "octets": 35165, + "lines": 500 + }, + "octets": 35165 + }, + { + "mboxMarkerOffset": 6513760, + "lineNumber": 92486, + "beginOffset": 6513803, + "headersEndOffset": 6513957, + "endOffset": 6557679, + "body": { + "mimeType": "text/plain", + "lineNumber": 92486, + "beginOffset": 6513803, + "headersEndOffset": 6513957, + "endOffset": 6557679, + "octets": 43722, + "lines": 693 + }, + "octets": 43722 + }, + { + "mboxMarkerOffset": 6557681, + "lineNumber": 93187, + "beginOffset": 6557714, + "headersEndOffset": 6558312, + "endOffset": 6583936, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93187, + "beginOffset": 6557714, + "headersEndOffset": 6558312, + "endOffset": 6583936, + "children": [ + { + "mimeType": "multipart/alternative", + "lineNumber": 93205, + "beginOffset": 6558400, + "headersEndOffset": 6558521, + "endOffset": 6562620, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93210, + "beginOffset": 6558563, + "headersEndOffset": 6558644, + "endOffset": 6559954, + "octets": 1310, + "lines": 38 + }, + { + "mimeType": "text/html", + "lineNumber": 93253, + "beginOffset": 6559996, + "headersEndOffset": 6560078, + "endOffset": 6562574, + "octets": 2496, + "lines": 32 + } + ], + "octets": 4099, + "lines": 83 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 93293, + "beginOffset": 6562662, + "headersEndOffset": 6562872, + "endOffset": 6583892, + "octets": 21020, + "lines": 270 + } + ], + "octets": 25624, + "lines": 368 + }, + "octets": 25624 + }, + { + "mboxMarkerOffset": 6583938, + "lineNumber": 93572, + "beginOffset": 6583971, + "headersEndOffset": 6584388, + "endOffset": 6587266, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93572, + "beginOffset": 6583971, + "headersEndOffset": 6584388, + "endOffset": 6587266, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93586, + "beginOffset": 6584457, + "headersEndOffset": 6584459, + "endOffset": 6584523, + "octets": 64, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93590, + "beginOffset": 6584546, + "headersEndOffset": 6584622, + "endOffset": 6586388, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93593, + "beginOffset": 6584650, + "headersEndOffset": 6584760, + "endOffset": 6584843, + "octets": 83, + "lines": 3 + }, + { + "mimeType": "text/richtext", + "lineNumber": 93602, + "beginOffset": 6584873, + "headersEndOffset": 6584986, + "endOffset": 6585148, + "octets": 162, + "lines": 4 + }, + { + "mimeType": "text/enriched", + "lineNumber": 93612, + "beginOffset": 6585178, + "headersEndOffset": 6585291, + "endOffset": 6585464, + "octets": 173, + "lines": 10 + }, + { + "mimeType": "text/html", + "lineNumber": 93628, + "beginOffset": 6585494, + "headersEndOffset": 6585603, + "endOffset": 6585767, + "octets": 164, + "lines": 3 + }, + { + "mimeType": "text/something-you-dont-know", + "lineNumber": 93637, + "beginOffset": 6585797, + "headersEndOffset": 6585925, + "endOffset": 6586358, + "octets": 433, + "lines": 6 + } + ], + "octets": 1766, + "lines": 57 + }, + { + "mimeType": "text/plain", + "lineNumber": 93650, + "beginOffset": 6586411, + "headersEndOffset": 6586413, + "endOffset": 6586582, + "octets": 169, + "lines": 4 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93657, + "beginOffset": 6586605, + "headersEndOffset": 6586657, + "endOffset": 6587208, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93660, + "beginOffset": 6586663, + "headersEndOffset": 6586691, + "endOffset": 6586745, + "octets": 54, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93665, + "beginOffset": 6586753, + "headersEndOffset": 6586805, + "endOffset": 6587081, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93668, + "beginOffset": 6586811, + "headersEndOffset": 6586839, + "endOffset": 6586893, + "octets": 54, + "lines": 1 + }, + { + "mimeType": "text/html", + "lineNumber": 93673, + "beginOffset": 6586901, + "headersEndOffset": 6586928, + "endOffset": 6586979, + "octets": 51, + "lines": 1 + }, + { + "mimeType": "text/x-barf", + "lineNumber": 93678, + "beginOffset": 6586987, + "headersEndOffset": 6587016, + "endOffset": 6587071, + "octets": 55, + "lines": 1 + } + ], + "octets": 276, + "lines": 16 + }, + { + "mimeType": "application/spankme", + "lineNumber": 93685, + "beginOffset": 6587089, + "headersEndOffset": 6587184, + "endOffset": 6587200, + "octets": 16, + "lines": 1 + } + ], + "octets": 551, + "lines": 32 + }, + { + "mimeType": "text/plain", + "lineNumber": 93692, + "beginOffset": 6587231, + "headersEndOffset": 6587233, + "endOffset": 6587243, + "octets": 10, + "lines": 1 + } + ], + "octets": 2878, + "lines": 113 + }, + "octets": 2878 + }, + { + "mboxMarkerOffset": 6587268, + "lineNumber": 93697, + "beginOffset": 6587301, + "headersEndOffset": 6587716, + "endOffset": 6955939, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93697, + "beginOffset": 6587301, + "headersEndOffset": 6587716, + "endOffset": 6955939, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93711, + "beginOffset": 6587785, + "headersEndOffset": 6587787, + "endOffset": 6587855, + "octets": 68, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93715, + "beginOffset": 6587878, + "headersEndOffset": 6587954, + "endOffset": 6955908, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93718, + "beginOffset": 6587982, + "headersEndOffset": 6588142, + "endOffset": 6645008, + "octets": 56866, + "lines": 1603 + }, + { + "mimeType": "text/html", + "lineNumber": 95327, + "beginOffset": 6645038, + "headersEndOffset": 6645197, + "endOffset": 6754228, + "octets": 109031, + "lines": 2982 + }, + { + "mimeType": "application/postscript", + "lineNumber": 98315, + "beginOffset": 6754258, + "headersEndOffset": 6754408, + "endOffset": 6955876, + "octets": 201468, + "lines": 13109 + } + ], + "octets": 367954, + "lines": 17713 + } + ], + "octets": 368223, + "lines": 17726 + }, + "octets": 368223 + }, + { + "mboxMarkerOffset": 6955941, + "lineNumber": 111435, + "beginOffset": 6955950, + "headersEndOffset": 6956567, + "endOffset": 6958045, + "body": { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 111435, + "beginOffset": 6955950, + "headersEndOffset": 6956567, + "endOffset": 6958045, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 111453, + "beginOffset": 6956828, + "headersEndOffset": 6956943, + "endOffset": 6956943, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 111458, + "beginOffset": 6956986, + "headersEndOffset": 6957087, + "endOffset": 6958002, + "message": { + "lineNumber": 111461, + "beginOffset": 6957087, + "headersEndOffset": 6957640, + "endOffset": 6958002, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 111461, + "beginOffset": 6957087, + "headersEndOffset": 6957640, + "endOffset": 6958002, + "octets": 362, + "lines": 16 + }, + "octets": 362 + }, + "octets": 915, + "lines": 28 + } + ], + "octets": 1478, + "lines": 43 + }, + "octets": 1478 + }, + { + "mboxMarkerOffset": 6958047, + "lineNumber": 111492, + "beginOffset": 6958056, + "headersEndOffset": 6958361, + "endOffset": 6970685, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111492, + "beginOffset": 6958056, + "headersEndOffset": 6958361, + "endOffset": 6970685, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111502, + "beginOffset": 6958401, + "headersEndOffset": 6958654, + "endOffset": 6959403, + "octets": 749, + "lines": 30 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 111541, + "beginOffset": 6959445, + "headersEndOffset": 6959773, + "endOffset": 6970643, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12324, + "lines": 197 + }, + "octets": 12324 + }, + { + "mboxMarkerOffset": 6970687, + "lineNumber": 111699, + "beginOffset": 6970696, + "headersEndOffset": 6971001, + "endOffset": 6983293, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111699, + "beginOffset": 6970696, + "headersEndOffset": 6971001, + "endOffset": 6983293, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111709, + "beginOffset": 6971041, + "headersEndOffset": 6971294, + "endOffset": 6972042, + "octets": 748, + "lines": 30 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 111748, + "beginOffset": 6972084, + "headersEndOffset": 6972381, + "endOffset": 6983251, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12292, + "lines": 197 + }, + "octets": 12292 + }, + { + "mboxMarkerOffset": 6983295, + "lineNumber": 111906, + "beginOffset": 6983328, + "headersEndOffset": 6984857, + "endOffset": 6991551, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111906, + "beginOffset": 6983328, + "headersEndOffset": 6984857, + "endOffset": 6991551, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111934, + "beginOffset": 6984904, + "headersEndOffset": 6984998, + "endOffset": 6990308, + "octets": 5310, + "lines": 111 + }, + { + "mimeType": "image/gif", + "lineNumber": 112050, + "beginOffset": 6990355, + "headersEndOffset": 6990560, + "endOffset": 6991502, + "octets": 942, + "lines": 13 + } + ], + "octets": 6694, + "lines": 139 + }, + "octets": 6694 + }, + { + "mboxMarkerOffset": 6991553, + "lineNumber": 112073, + "beginOffset": 6991586, + "headersEndOffset": 6992045, + "endOffset": 7209679, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 112073, + "beginOffset": 6991586, + "headersEndOffset": 6992045, + "endOffset": 7209679, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 112086, + "beginOffset": 6992085, + "headersEndOffset": 6992113, + "endOffset": 6992366, + "octets": 253, + "lines": 6 + }, + { + "mimeType": "multipart/related", + "lineNumber": 112096, + "beginOffset": 6992408, + "headersEndOffset": 6992497, + "endOffset": 7209637, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 112100, + "beginOffset": 6992537, + "headersEndOffset": 6992736, + "endOffset": 7000063, + "octets": 7327, + "lines": 179 + }, + { + "mimeType": "image/gif", + "lineNumber": 112286, + "beginOffset": 7000105, + "headersEndOffset": 7000286, + "endOffset": 7008376, + "octets": 8090, + "lines": 110 + }, + { + "mimeType": "image/gif", + "lineNumber": 112402, + "beginOffset": 7008418, + "headersEndOffset": 7008582, + "endOffset": 7016138, + "octets": 7556, + "lines": 103 + }, + { + "mimeType": "image/gif", + "lineNumber": 112511, + "beginOffset": 7016180, + "headersEndOffset": 7016343, + "endOffset": 7019721, + "octets": 3378, + "lines": 46 + }, + { + "mimeType": "image/gif", + "lineNumber": 112563, + "beginOffset": 7019763, + "headersEndOffset": 7019927, + "endOffset": 7028493, + "octets": 8566, + "lines": 116 + }, + { + "mimeType": "image/gif", + "lineNumber": 112685, + "beginOffset": 7028535, + "headersEndOffset": 7028696, + "endOffset": 7134494, + "octets": 105798, + "lines": 1430 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 114121, + "beginOffset": 7134536, + "headersEndOffset": 7134700, + "endOffset": 7173586, + "octets": 38886, + "lines": 526 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 114653, + "beginOffset": 7173628, + "headersEndOffset": 7173797, + "endOffset": 7209595, + "octets": 35798, + "lines": 484 + } + ], + "octets": 217140, + "lines": 3044 + } + ], + "octets": 217634, + "lines": 3059 + }, + "octets": 217634 + }, + { + "mboxMarkerOffset": 7209681, + "lineNumber": 115145, + "beginOffset": 7209690, + "headersEndOffset": 7209994, + "endOffset": 7221844, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115145, + "beginOffset": 7209690, + "headersEndOffset": 7209994, + "endOffset": 7221844, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115155, + "beginOffset": 7210034, + "headersEndOffset": 7210195, + "endOffset": 7210773, + "octets": 578, + "lines": 27 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115189, + "beginOffset": 7210815, + "headersEndOffset": 7210932, + "endOffset": 7221802, + "octets": 10870, + "lines": 147 + } + ], + "octets": 11850, + "lines": 188 + }, + "octets": 11850 + }, + { + "mboxMarkerOffset": 7221846, + "lineNumber": 115343, + "beginOffset": 7221855, + "headersEndOffset": 7222159, + "endOffset": 7234277, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115343, + "beginOffset": 7221855, + "headersEndOffset": 7222159, + "endOffset": 7234277, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115353, + "beginOffset": 7222199, + "headersEndOffset": 7222417, + "endOffset": 7223042, + "octets": 625, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115389, + "beginOffset": 7223084, + "headersEndOffset": 7223365, + "endOffset": 7234235, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12118, + "lines": 193 + }, + "octets": 12118 + }, + { + "mboxMarkerOffset": 7234279, + "lineNumber": 115546, + "beginOffset": 7234288, + "headersEndOffset": 7234592, + "endOffset": 7246617, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115546, + "beginOffset": 7234288, + "headersEndOffset": 7234592, + "endOffset": 7246617, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115556, + "beginOffset": 7234632, + "headersEndOffset": 7234854, + "endOffset": 7235483, + "octets": 629, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115592, + "beginOffset": 7235525, + "headersEndOffset": 7235705, + "endOffset": 7246575, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12025, + "lines": 191 + }, + "octets": 12025 + }, + { + "mboxMarkerOffset": 7246619, + "lineNumber": 115747, + "beginOffset": 7246628, + "headersEndOffset": 7246932, + "endOffset": 7259151, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115747, + "beginOffset": 7246628, + "headersEndOffset": 7246932, + "endOffset": 7259151, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115757, + "beginOffset": 7246972, + "headersEndOffset": 7247224, + "endOffset": 7247884, + "octets": 660, + "lines": 29 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115795, + "beginOffset": 7247926, + "headersEndOffset": 7248239, + "endOffset": 7259109, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12219, + "lines": 196 + }, + "octets": 12219 + }, + { + "mboxMarkerOffset": 7259153, + "lineNumber": 115953, + "beginOffset": 7259162, + "headersEndOffset": 7259466, + "endOffset": 7271535, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115953, + "beginOffset": 7259162, + "headersEndOffset": 7259466, + "endOffset": 7271535, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115963, + "beginOffset": 7259506, + "headersEndOffset": 7259728, + "endOffset": 7260401, + "octets": 673, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115999, + "beginOffset": 7260443, + "headersEndOffset": 7260623, + "endOffset": 7271493, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12069, + "lines": 191 + }, + "octets": 12069 + }, + { + "mboxMarkerOffset": 7271537, + "lineNumber": 116154, + "beginOffset": 7271546, + "headersEndOffset": 7271850, + "endOffset": 7284139, + "body": { + "mimeType": "multipart/related", + "lineNumber": 116154, + "beginOffset": 7271546, + "headersEndOffset": 7271850, + "endOffset": 7284139, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 116164, + "beginOffset": 7271890, + "headersEndOffset": 7272142, + "endOffset": 7272841, + "octets": 699, + "lines": 29 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 116202, + "beginOffset": 7272883, + "headersEndOffset": 7273227, + "endOffset": 7284097, + "octets": 10870, + "lines": 147 + } + ], + "octets": 12289, + "lines": 196 + }, + "octets": 12289 + }, + { + "mboxMarkerOffset": 7284141, + "lineNumber": 116360, + "beginOffset": 7284174, + "headersEndOffset": 7285430, + "endOffset": 8043000, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 116360, + "beginOffset": 7284174, + "headersEndOffset": 7285430, + "endOffset": 8043000, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 116385, + "beginOffset": 7285517, + "headersEndOffset": 7285596, + "endOffset": 7285626, + "octets": 30, + "lines": 3 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 116393, + "beginOffset": 7285667, + "headersEndOffset": 7285761, + "endOffset": 8042957, + "message": { + "lineNumber": 116397, + "beginOffset": 7285761, + "headersEndOffset": 7286598, + "endOffset": 8042957, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 116397, + "beginOffset": 7285761, + "headersEndOffset": 7286598, + "endOffset": 8042957, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 116415, + "beginOffset": 7286640, + "headersEndOffset": 7286719, + "endOffset": 7287362, + "octets": 643, + "lines": 16 + }, + { + "mimeType": "multipart/related", + "lineNumber": 116436, + "beginOffset": 7287404, + "headersEndOffset": 7287488, + "endOffset": 8042909, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 116440, + "beginOffset": 7287530, + "headersEndOffset": 7287608, + "endOffset": 7288476, + "octets": 868, + "lines": 18 + }, + { + "mimeType": "image/tiff", + "lineNumber": 116463, + "beginOffset": 7288518, + "headersEndOffset": 7288707, + "endOffset": 8042865, + "octets": 754158, + "lines": 10192 + } + ], + "octets": 755421, + "lines": 10223 + } + ], + "octets": 756359, + "lines": 10252 + }, + "octets": 756359 + }, + "octets": 757196, + "lines": 10268 + } + ], + "octets": 757570, + "lines": 10285 + }, + "octets": 757570 + }, + { + "mboxMarkerOffset": 8043002, + "lineNumber": 126669, + "beginOffset": 8043035, + "headersEndOffset": 8044321, + "endOffset": 8091598, + "body": { + "mimeType": "multipart/related", + "lineNumber": 126669, + "beginOffset": 8043035, + "headersEndOffset": 8044321, + "endOffset": 8091598, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 126693, + "beginOffset": 8044368, + "headersEndOffset": 8044462, + "endOffset": 8046894, + "octets": 2432, + "lines": 50 + }, + { + "mimeType": "image/gif", + "lineNumber": 126748, + "beginOffset": 8046941, + "headersEndOffset": 8047105, + "endOffset": 8053207, + "octets": 6102, + "lines": 79 + }, + { + "mimeType": "image/gif", + "lineNumber": 126834, + "beginOffset": 8053254, + "headersEndOffset": 8053417, + "endOffset": 8065647, + "octets": 12230, + "lines": 157 + }, + { + "mimeType": "image/gif", + "lineNumber": 126998, + "beginOffset": 8065694, + "headersEndOffset": 8065859, + "endOffset": 8087855, + "octets": 21996, + "lines": 282 + }, + { + "mimeType": "image/gif", + "lineNumber": 127287, + "beginOffset": 8087902, + "headersEndOffset": 8088111, + "endOffset": 8091549, + "octets": 3438, + "lines": 45 + } + ], + "octets": 47277, + "lines": 649 + }, + "octets": 47277 + }, + { + "mboxMarkerOffset": 8091600, + "lineNumber": 127342, + "beginOffset": 8091609, + "headersEndOffset": 8092367, + "endOffset": 8644457, + "body": { + "mimeType": "audio/basic", + "lineNumber": 127342, + "beginOffset": 8091609, + "headersEndOffset": 8092367, + "endOffset": 8644457, + "octets": 552090, + "lines": 7474 + }, + "octets": 552090 + }, + { + "mboxMarkerOffset": 8644459, + "lineNumber": 134835, + "beginOffset": 8644468, + "headersEndOffset": 8645400, + "endOffset": 8648081, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 134835, + "beginOffset": 8644468, + "headersEndOffset": 8645400, + "endOffset": 8648081, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 134858, + "beginOffset": 8645411, + "headersEndOffset": 8645442, + "endOffset": 8648068, + "octets": 2626, + "lines": 96 + } + ], + "octets": 2681, + "lines": 102 + }, + "octets": 2681 + }, + { + "mboxMarkerOffset": 8648083, + "lineNumber": 134960, + "beginOffset": 8648116, + "headersEndOffset": 8648726, + "endOffset": 8650562, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 134960, + "beginOffset": 8648116, + "headersEndOffset": 8648726, + "endOffset": 8650562, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 134984, + "beginOffset": 8649031, + "headersEndOffset": 8649078, + "endOffset": 8650186, + "octets": 1108, + "lines": 26 + }, + { + "mimeType": "application/pgp-signature", + "lineNumber": 135014, + "beginOffset": 8650206, + "headersEndOffset": 8650249, + "endOffset": 8650542, + "octets": 293, + "lines": 9 + } + ], + "octets": 1836, + "lines": 51 + }, + "octets": 1836 + }, + { + "mboxMarkerOffset": 8650564, + "lineNumber": 135028, + "beginOffset": 8650573, + "headersEndOffset": 8651756, + "endOffset": 8653178, + "body": { + "mimeType": "application/pgp", + "lineNumber": 135028, + "beginOffset": 8650573, + "headersEndOffset": 8651756, + "endOffset": 8653178, + "octets": 1422, + "lines": 40 + }, + "octets": 1422 + }, + { + "mboxMarkerOffset": 8653180, + "lineNumber": 135090, + "beginOffset": 8653189, + "headersEndOffset": 8653839, + "endOffset": 8654840, + "body": { + "mimeType": "text/plain", + "lineNumber": 135090, + "beginOffset": 8653189, + "headersEndOffset": 8653839, + "endOffset": 8654840, + "octets": 1001, + "lines": 27 + }, + "octets": 1001 + }, + { + "mboxMarkerOffset": 8654842, + "lineNumber": 135136, + "beginOffset": 8654851, + "headersEndOffset": 8655631, + "endOffset": 8658633, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135136, + "beginOffset": 8654851, + "headersEndOffset": 8655631, + "endOffset": 8658633, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135158, + "beginOffset": 8655830, + "headersEndOffset": 8655876, + "endOffset": 8656708, + "octets": 832, + "lines": 15 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135177, + "beginOffset": 8656751, + "headersEndOffset": 8656839, + "endOffset": 8658588, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135181, + "beginOffset": 8656882, + "headersEndOffset": 8656976, + "endOffset": 8657477, + "octets": 501, + "lines": 10 + }, + { + "mimeType": "message/external-body", + "lineNumber": 135196, + "beginOffset": 8657522, + "headersEndOffset": 8657715, + "endOffset": 8657748, + "message": { + "lineNumber": 135203, + "beginOffset": 8657715, + "headersEndOffset": 8657744, + "endOffset": 8657748, + "body": { + "mimeType": "audio/basic", + "lineNumber": 135203, + "beginOffset": 8657715, + "headersEndOffset": 8657744, + "endOffset": 8657748, + "octets": 4, + "lines": 2 + }, + "octets": 4 + }, + "octets": 33, + "lines": 4 + }, + { + "mimeType": "text/plain", + "lineNumber": 135209, + "beginOffset": 8657793, + "headersEndOffset": 8657884, + "endOffset": 8657889, + "octets": 5, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 135216, + "beginOffset": 8657934, + "headersEndOffset": 8658142, + "endOffset": 8658173, + "message": { + "lineNumber": 135223, + "beginOffset": 8658142, + "headersEndOffset": 8658169, + "endOffset": 8658173, + "body": { + "mimeType": "image/gif", + "lineNumber": 135223, + "beginOffset": 8658142, + "headersEndOffset": 8658169, + "endOffset": 8658173, + "octets": 4, + "lines": 2 + }, + "octets": 4 + }, + "octets": 31, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135229, + "beginOffset": 8658218, + "headersEndOffset": 8658312, + "endOffset": 8658541, + "octets": 229, + "lines": 7 + } + ], + "octets": 1749, + "lines": 61 + } + ], + "octets": 3002, + "lines": 89 + }, + "octets": 3002 + }, + { + "mboxMarkerOffset": 8658635, + "lineNumber": 135245, + "beginOffset": 8658644, + "headersEndOffset": 8659476, + "endOffset": 8660904, + "body": { + "mimeType": "text/richtext", + "lineNumber": 135245, + "beginOffset": 8658644, + "headersEndOffset": 8659476, + "endOffset": 8660904, + "octets": 1428, + "lines": 42 + }, + "octets": 1428 + }, + { + "mboxMarkerOffset": 8660906, + "lineNumber": 135307, + "beginOffset": 8660915, + "headersEndOffset": 8661072, + "endOffset": 8665806, + "body": { + "mimeType": "message/partial", + "lineNumber": 135307, + "beginOffset": 8660915, + "headersEndOffset": 8661072, + "endOffset": 8665806, + "octets": 4734, + "lines": 64 + }, + "octets": 4734 + }, + { + "mboxMarkerOffset": 8665808, + "lineNumber": 135377, + "beginOffset": 8665817, + "headersEndOffset": 8667595, + "endOffset": 8679245, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135377, + "beginOffset": 8665817, + "headersEndOffset": 8667595, + "endOffset": 8679245, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135416, + "beginOffset": 8667794, + "headersEndOffset": 8667840, + "endOffset": 8669545, + "octets": 1705, + "lines": 38 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135458, + "beginOffset": 8669588, + "headersEndOffset": 8669676, + "endOffset": 8679200, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135462, + "beginOffset": 8669719, + "headersEndOffset": 8669813, + "endOffset": 8670384, + "octets": 571, + "lines": 14 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135481, + "beginOffset": 8670429, + "headersEndOffset": 8670493, + "endOffset": 8671377, + "octets": 884, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135498, + "beginOffset": 8671422, + "headersEndOffset": 8671516, + "endOffset": 8671567, + "octets": 51, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135508, + "beginOffset": 8671612, + "headersEndOffset": 8671676, + "endOffset": 8672560, + "octets": 884, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135525, + "beginOffset": 8672605, + "headersEndOffset": 8672699, + "endOffset": 8672750, + "octets": 51, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135535, + "beginOffset": 8672795, + "headersEndOffset": 8672859, + "endOffset": 8673743, + "octets": 884, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135552, + "beginOffset": 8673788, + "headersEndOffset": 8673882, + "endOffset": 8673927, + "octets": 45, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135562, + "beginOffset": 8673972, + "headersEndOffset": 8674036, + "endOffset": 8674264, + "octets": 228, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135571, + "beginOffset": 8674309, + "headersEndOffset": 8674403, + "endOffset": 8674472, + "octets": 69, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135581, + "beginOffset": 8674517, + "headersEndOffset": 8674581, + "endOffset": 8674809, + "octets": 228, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135590, + "beginOffset": 8674854, + "headersEndOffset": 8674948, + "endOffset": 8674997, + "octets": 49, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135600, + "beginOffset": 8675042, + "headersEndOffset": 8675106, + "endOffset": 8675334, + "octets": 228, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135609, + "beginOffset": 8675379, + "headersEndOffset": 8675473, + "endOffset": 8675776, + "octets": 303, + "lines": 11 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135625, + "beginOffset": 8675821, + "headersEndOffset": 8675885, + "endOffset": 8676769, + "octets": 884, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135642, + "beginOffset": 8676814, + "headersEndOffset": 8676908, + "endOffset": 8676952, + "octets": 44, + "lines": 4 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135651, + "beginOffset": 8676997, + "headersEndOffset": 8677061, + "endOffset": 8679003, + "octets": 1942, + "lines": 27 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135683, + "beginOffset": 8679048, + "headersEndOffset": 8679142, + "endOffset": 8679153, + "octets": 11, + "lines": 1 + } + ], + "octets": 9524, + "lines": 228 + } + ], + "octets": 11650, + "lines": 279 + }, + "octets": 11650 + }, + { + "mboxMarkerOffset": 8679247, + "lineNumber": 135693, + "beginOffset": 8679256, + "headersEndOffset": 8680000, + "endOffset": 8690837, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135693, + "beginOffset": 8679256, + "headersEndOffset": 8680000, + "endOffset": 8690837, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135713, + "beginOffset": 8680199, + "headersEndOffset": 8680245, + "endOffset": 8680884, + "octets": 639, + "lines": 12 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135729, + "beginOffset": 8680927, + "headersEndOffset": 8681015, + "endOffset": 8690794, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135733, + "beginOffset": 8681058, + "headersEndOffset": 8681152, + "endOffset": 8681693, + "octets": 541, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 135746, + "beginOffset": 8681738, + "headersEndOffset": 8681850, + "endOffset": 8690560, + "octets": 8710, + "lines": 125 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135877, + "beginOffset": 8690605, + "headersEndOffset": 8690699, + "endOffset": 8690747, + "octets": 48, + "lines": 3 + } + ], + "octets": 9779, + "lines": 153 + } + ], + "octets": 10837, + "lines": 178 + }, + "octets": 10837 + }, + { + "mboxMarkerOffset": 8690839, + "lineNumber": 135888, + "beginOffset": 8690848, + "headersEndOffset": 8691509, + "endOffset": 8771510, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 135888, + "beginOffset": 8690848, + "headersEndOffset": 8691509, + "endOffset": 8771510, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135905, + "beginOffset": 8691561, + "headersEndOffset": 8691654, + "endOffset": 8691757, + "octets": 103, + "lines": 6 + }, + { + "mimeType": "audio/basic", + "lineNumber": 135916, + "beginOffset": 8691809, + "headersEndOffset": 8691940, + "endOffset": 8771456, + "octets": 79516, + "lines": 1075 + } + ], + "octets": 80001, + "lines": 1093 + }, + "octets": 80001 + }, + { + "mboxMarkerOffset": 8771512, + "lineNumber": 136998, + "beginOffset": 8771521, + "headersEndOffset": 8772294, + "endOffset": 8960196, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 136998, + "beginOffset": 8771521, + "headersEndOffset": 8772294, + "endOffset": 8960196, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 137019, + "beginOffset": 8772493, + "headersEndOffset": 8772539, + "endOffset": 8773917, + "octets": 1378, + "lines": 28 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 137051, + "beginOffset": 8773960, + "headersEndOffset": 8774048, + "endOffset": 8960153, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 137055, + "beginOffset": 8774091, + "headersEndOffset": 8774185, + "endOffset": 8775346, + "octets": 1161, + "lines": 22 + }, + { + "mimeType": "audio/basic", + "lineNumber": 137082, + "beginOffset": 8775391, + "headersEndOffset": 8775493, + "endOffset": 8892315, + "octets": 116822, + "lines": 1579 + }, + { + "mimeType": "text/richtext", + "lineNumber": 138667, + "beginOffset": 8892360, + "headersEndOffset": 8892454, + "endOffset": 8892580, + "octets": 126, + "lines": 3 + }, + { + "mimeType": "image/gif", + "lineNumber": 138675, + "beginOffset": 8892625, + "headersEndOffset": 8892728, + "endOffset": 8959970, + "octets": 67242, + "lines": 961 + }, + { + "mimeType": "text/plain", + "lineNumber": 139642, + "beginOffset": 8960015, + "headersEndOffset": 8960106, + "endOffset": 8960106, + "octets": 0, + "lines": 0 + } + ], + "octets": 186105, + "lines": 2593 + } + ], + "octets": 187902, + "lines": 2634 + }, + "octets": 187902 + }, + { + "mboxMarkerOffset": 8960198, + "lineNumber": 139650, + "beginOffset": 8960207, + "headersEndOffset": 8961063, + "endOffset": 8962821, + "body": { + "mimeType": "application/x-pkcs", + "lineNumber": 139650, + "beginOffset": 8960207, + "headersEndOffset": 8961063, + "endOffset": 8962821, + "octets": 1758, + "lines": 25 + }, + "octets": 1758 + }, + { + "mboxMarkerOffset": 8962823, + "lineNumber": 139696, + "beginOffset": 8962832, + "headersEndOffset": 8963476, + "endOffset": 8964871, + "body": { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 139696, + "beginOffset": 8962832, + "headersEndOffset": 8963476, + "endOffset": 8964871, + "message": { + "lineNumber": 139710, + "beginOffset": 8963476, + "headersEndOffset": 8963972, + "endOffset": 8964871, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 139710, + "beginOffset": 8963476, + "headersEndOffset": 8963972, + "endOffset": 8964871, + "octets": 899, + "lines": 25 + }, + "octets": 899 + }, + "octets": 1395, + "lines": 38 + }, + "octets": 1395 + }, + { + "mboxMarkerOffset": 8964873, + "lineNumber": 139749, + "beginOffset": 8964882, + "headersEndOffset": 8965340, + "endOffset": 9057985, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 139749, + "beginOffset": 8964882, + "headersEndOffset": 8965340, + "endOffset": 9057985, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 139763, + "beginOffset": 8965350, + "headersEndOffset": 8965352, + "endOffset": 8965393, + "octets": 41, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 139767, + "beginOffset": 8965405, + "headersEndOffset": 8965469, + "endOffset": 9057967, + "octets": 92498, + "lines": 1250 + } + ], + "octets": 92645, + "lines": 1261 + }, + "octets": 92645 + }, + { + "mboxMarkerOffset": 9057987, + "lineNumber": 141025, + "beginOffset": 9057996, + "headersEndOffset": 9058498, + "endOffset": 9059667, + "body": { + "mimeType": "text/plain", + "lineNumber": 141025, + "beginOffset": 9057996, + "headersEndOffset": 9058498, + "endOffset": 9059667, + "octets": 1169, + "lines": 27 + }, + "octets": 1169 + }, + { + "mboxMarkerOffset": 9059669, + "lineNumber": 141066, + "beginOffset": 9059678, + "headersEndOffset": 9060843, + "endOffset": 9156930, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 141066, + "beginOffset": 9059678, + "headersEndOffset": 9060843, + "endOffset": 9156930, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 141092, + "beginOffset": 9060849, + "headersEndOffset": 9060851, + "endOffset": 9061403, + "octets": 552, + "lines": 12 + }, + { + "mimeType": "image/gif", + "lineNumber": 141107, + "beginOffset": 9061411, + "headersEndOffset": 9061531, + "endOffset": 9119961, + "octets": 58430, + "lines": 790 + }, + { + "mimeType": "text/plain", + "lineNumber": 141902, + "beginOffset": 9119969, + "headersEndOffset": 9119971, + "endOffset": 9123837, + "octets": 3866, + "lines": 83 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 141988, + "beginOffset": 9123845, + "headersEndOffset": 9124003, + "endOffset": 9154647, + "octets": 30644, + "lines": 1010 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 143003, + "beginOffset": 9154655, + "headersEndOffset": 9154764, + "endOffset": 9155504, + "octets": 740, + "lines": 24 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 143032, + "beginOffset": 9155512, + "headersEndOffset": 9155632, + "endOffset": 9156920, + "octets": 1288, + "lines": 25 + } + ], + "octets": 96087, + "lines": 1970 + }, + "octets": 96087 + }, + { + "mboxMarkerOffset": 9156932, + "lineNumber": 143063, + "beginOffset": 9156965, + "headersEndOffset": 9158136, + "endOffset": 9159961, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 143063, + "beginOffset": 9156965, + "headersEndOffset": 9158136, + "endOffset": 9159961, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143082, + "beginOffset": 9158154, + "headersEndOffset": 9158156, + "endOffset": 9159077, + "octets": 921, + "lines": 20 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 143105, + "beginOffset": 9159097, + "headersEndOffset": 9159179, + "endOffset": 9159939, + "octets": 760, + "lines": 12 + } + ], + "octets": 1825, + "lines": 41 + }, + "octets": 1825 + }, + { + "mboxMarkerOffset": 9159963, + "lineNumber": 143124, + "beginOffset": 9159996, + "headersEndOffset": 9161157, + "endOffset": 9164625, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 143124, + "beginOffset": 9159996, + "headersEndOffset": 9161157, + "endOffset": 9164625, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143147, + "beginOffset": 9161341, + "headersEndOffset": 9161422, + "endOffset": 9162176, + "octets": 754, + "lines": 14 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143165, + "beginOffset": 9162186, + "headersEndOffset": 9162369, + "endOffset": 9164615, + "octets": 2246, + "lines": 31 + } + ], + "octets": 3468, + "lines": 60 + }, + "octets": 3468 + }, + { + "mboxMarkerOffset": 9164627, + "lineNumber": 143204, + "beginOffset": 9164660, + "headersEndOffset": 9165820, + "endOffset": 9171770, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 143204, + "beginOffset": 9164660, + "headersEndOffset": 9165820, + "endOffset": 9171770, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143231, + "beginOffset": 9166018, + "headersEndOffset": 9166099, + "endOffset": 9168957, + "octets": 2858, + "lines": 47 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143282, + "beginOffset": 9168981, + "headersEndOffset": 9169164, + "endOffset": 9171746, + "octets": 2582, + "lines": 35 + } + ], + "octets": 5950, + "lines": 97 + }, + "octets": 5950 + }, + { + "mboxMarkerOffset": 9171772, + "lineNumber": 143325, + "beginOffset": 9171781, + "headersEndOffset": 9171996, + "endOffset": 9176246, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143325, + "beginOffset": 9171781, + "headersEndOffset": 9171996, + "endOffset": 9176246, + "octets": 4250, + "lines": 58 + }, + "octets": 4250 + }, + { + "mboxMarkerOffset": 9176248, + "lineNumber": 143391, + "beginOffset": 9176281, + "headersEndOffset": 9177199, + "endOffset": 9193172, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 143391, + "beginOffset": 9176281, + "headersEndOffset": 9177199, + "endOffset": 9193172, + "children": [ + { + "mimeType": "image/jpeg", + "lineNumber": 143412, + "beginOffset": 9177275, + "headersEndOffset": 9177413, + "endOffset": 9188281, + "octets": 10868, + "lines": 147 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 143564, + "beginOffset": 9188311, + "headersEndOffset": 9188466, + "endOffset": 9193140, + "octets": 4674, + "lines": 64 + } + ], + "octets": 15973, + "lines": 224 + }, + "octets": 15973 + }, + { + "mboxMarkerOffset": 9193174, + "lineNumber": 143635, + "beginOffset": 9193207, + "headersEndOffset": 9194031, + "endOffset": 9211049, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143635, + "beginOffset": 9193207, + "headersEndOffset": 9194031, + "endOffset": 9211049, + "octets": 17018, + "lines": 258 + }, + "octets": 17018 + }, + { + "mboxMarkerOffset": 9211051, + "lineNumber": 143911, + "beginOffset": 9211084, + "headersEndOffset": 9211913, + "endOffset": 9237261, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143911, + "beginOffset": 9211084, + "headersEndOffset": 9211913, + "endOffset": 9237261, + "octets": 25348, + "lines": 385 + }, + "octets": 25348 + }, + { + "mboxMarkerOffset": 9237263, + "lineNumber": 144314, + "beginOffset": 9237296, + "headersEndOffset": 9238125, + "endOffset": 9274811, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 144314, + "beginOffset": 9237296, + "headersEndOffset": 9238125, + "endOffset": 9274811, + "octets": 36686, + "lines": 556 + }, + "octets": 36686 + }, + { + "mboxMarkerOffset": 9274813, + "lineNumber": 144888, + "beginOffset": 9274846, + "headersEndOffset": 9275678, + "endOffset": 9327768, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 144888, + "beginOffset": 9274846, + "headersEndOffset": 9275678, + "endOffset": 9327768, + "octets": 52090, + "lines": 790 + }, + "octets": 52090 + }, + { + "mboxMarkerOffset": 9327770, + "lineNumber": 145696, + "beginOffset": 9327803, + "headersEndOffset": 9329218, + "endOffset": 9330668, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145696, + "beginOffset": 9327803, + "headersEndOffset": 9329218, + "endOffset": 9330668, + "octets": 1450, + "lines": 20 + }, + "octets": 1450 + }, + { + "mboxMarkerOffset": 9330670, + "lineNumber": 145741, + "beginOffset": 9330703, + "headersEndOffset": 9332080, + "endOffset": 9336541, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 145741, + "beginOffset": 9330703, + "headersEndOffset": 9332080, + "endOffset": 9336541, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 145767, + "beginOffset": 9332127, + "headersEndOffset": 9332194, + "endOffset": 9332304, + "octets": 110, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 145775, + "beginOffset": 9332351, + "headersEndOffset": 9332506, + "endOffset": 9336492, + "octets": 3986, + "lines": 54 + } + ], + "octets": 4461, + "lines": 69 + }, + "octets": 4461 + }, + { + "mboxMarkerOffset": 9336543, + "lineNumber": 145836, + "beginOffset": 9336576, + "headersEndOffset": 9337807, + "endOffset": 9341357, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145836, + "beginOffset": 9336576, + "headersEndOffset": 9337807, + "endOffset": 9341357, + "octets": 3550, + "lines": 55 + }, + "octets": 3550 + }, + { + "mboxMarkerOffset": 9341359, + "lineNumber": 145914, + "beginOffset": 9341392, + "headersEndOffset": 9342490, + "endOffset": 9343160, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145914, + "beginOffset": 9341392, + "headersEndOffset": 9342490, + "endOffset": 9343160, + "octets": 670, + "lines": 10 + }, + "octets": 670 + }, + { + "mboxMarkerOffset": 9343162, + "lineNumber": 145946, + "beginOffset": 9343171, + "headersEndOffset": 9343574, + "endOffset": 9351298, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145946, + "beginOffset": 9343171, + "headersEndOffset": 9343574, + "endOffset": 9351298, + "octets": 7724, + "lines": 105 + }, + "octets": 7724 + }, + { + "mboxMarkerOffset": 9351300, + "lineNumber": 146063, + "beginOffset": 9351333, + "headersEndOffset": 9352135, + "endOffset": 9354990, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 146063, + "beginOffset": 9351333, + "headersEndOffset": 9352135, + "endOffset": 9354990, + "message": { + "lineNumber": 146082, + "beginOffset": 9352135, + "headersEndOffset": 9353538, + "endOffset": 9354990, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146082, + "beginOffset": 9352135, + "headersEndOffset": 9353538, + "endOffset": 9354990, + "octets": 1452, + "lines": 20 + }, + "octets": 1452 + }, + "octets": 2855, + "lines": 43 + }, + "octets": 2855 + }, + { + "mboxMarkerOffset": 9354992, + "lineNumber": 146127, + "beginOffset": 9355025, + "headersEndOffset": 9355752, + "endOffset": 9358998, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 146127, + "beginOffset": 9355025, + "headersEndOffset": 9355752, + "endOffset": 9358998, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146147, + "beginOffset": 9355828, + "headersEndOffset": 9355907, + "endOffset": 9355923, + "octets": 16, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 146153, + "beginOffset": 9355953, + "headersEndOffset": 9356111, + "endOffset": 9358966, + "message": { + "lineNumber": 146157, + "beginOffset": 9356111, + "headersEndOffset": 9357514, + "endOffset": 9358966, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146157, + "beginOffset": 9356111, + "headersEndOffset": 9357514, + "endOffset": 9358966, + "octets": 1452, + "lines": 20 + }, + "octets": 1452 + }, + "octets": 2855, + "lines": 43 + } + ], + "octets": 3246, + "lines": 58 + }, + "octets": 3246 + }, + { + "mboxMarkerOffset": 9359000, + "lineNumber": 146204, + "beginOffset": 9359033, + "headersEndOffset": 9359714, + "endOffset": 9365816, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146204, + "beginOffset": 9359033, + "headersEndOffset": 9359714, + "endOffset": 9365816, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146223, + "beginOffset": 9359818, + "headersEndOffset": 9359897, + "endOffset": 9359939, + "octets": 42, + "lines": 2 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146229, + "beginOffset": 9359983, + "headersEndOffset": 9360138, + "endOffset": 9365770, + "octets": 5632, + "lines": 77 + } + ], + "octets": 6102, + "lines": 91 + }, + "octets": 6102 + }, + { + "mboxMarkerOffset": 9365818, + "lineNumber": 146313, + "beginOffset": 9365851, + "headersEndOffset": 9366934, + "endOffset": 9377310, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146313, + "beginOffset": 9365851, + "headersEndOffset": 9366934, + "endOffset": 9377310, + "octets": 10376, + "lines": 141 + }, + "octets": 10376 + }, + { + "mboxMarkerOffset": 9377312, + "lineNumber": 146476, + "beginOffset": 9377345, + "headersEndOffset": 9378745, + "endOffset": 9381612, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146476, + "beginOffset": 9377345, + "headersEndOffset": 9378745, + "endOffset": 9381612, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146503, + "beginOffset": 9378849, + "headersEndOffset": 9378928, + "endOffset": 9379555, + "octets": 627, + "lines": 17 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146524, + "beginOffset": 9379599, + "headersEndOffset": 9379754, + "endOffset": 9381566, + "octets": 1812, + "lines": 25 + } + ], + "octets": 2867, + "lines": 54 + }, + "octets": 2867 + }, + { + "mboxMarkerOffset": 9381614, + "lineNumber": 146556, + "beginOffset": 9381647, + "headersEndOffset": 9382210, + "endOffset": 9382740, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146556, + "beginOffset": 9381647, + "headersEndOffset": 9382210, + "endOffset": 9382740, + "octets": 530, + "lines": 8 + }, + "octets": 530 + }, + { + "mboxMarkerOffset": 9382742, + "lineNumber": 146580, + "beginOffset": 9382751, + "headersEndOffset": 9384087, + "endOffset": 9385042, + "body": { + "mimeType": "MULTIPART/SIGNED", + "lineNumber": 146580, + "beginOffset": 9382751, + "headersEndOffset": 9384087, + "endOffset": 9385042, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146605, + "beginOffset": 9384349, + "headersEndOffset": 9384395, + "endOffset": 9384998, + "octets": 603, + "lines": 15 + } + ], + "octets": 955, + "lines": 24 + }, + "octets": 955 + }, + { + "mboxMarkerOffset": 9385044, + "lineNumber": 146625, + "beginOffset": 9385053, + "headersEndOffset": 9386420, + "endOffset": 9395402, + "body": { + "mimeType": "MULTIPART/SIGNED", + "lineNumber": 146625, + "beginOffset": 9385053, + "headersEndOffset": 9386420, + "endOffset": 9395402, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146650, + "beginOffset": 9386682, + "headersEndOffset": 9386728, + "endOffset": 9386835, + "octets": 107, + "lines": 6 + }, + { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 146660, + "beginOffset": 9386879, + "headersEndOffset": 9387046, + "endOffset": 9389799, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146669, + "beginOffset": 9387306, + "headersEndOffset": 9387416, + "endOffset": 9387511, + "octets": 95, + "lines": 4 + }, + { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 146678, + "beginOffset": 9387553, + "headersEndOffset": 9387649, + "endOffset": 9389055, + "message": { + "lineNumber": 146681, + "beginOffset": 9387649, + "headersEndOffset": 9388845, + "endOffset": 9389055, + "body": { + "mimeType": "text/plain", + "lineNumber": 146681, + "beginOffset": 9387649, + "headersEndOffset": 9388845, + "endOffset": 9389055, + "octets": 210, + "lines": 5 + }, + "octets": 210 + }, + "octets": 1406, + "lines": 34 + }, + { + "mimeType": "TEXT/X-VCARD", + "lineNumber": 146717, + "beginOffset": 9389097, + "headersEndOffset": 9389267, + "endOffset": 9389757, + "octets": 490, + "lines": 11 + } + ], + "octets": 2753, + "lines": 70 + }, + { + "mimeType": "APPLICATION/X-PKCS7-SIGNATURE", + "lineNumber": 146735, + "beginOffset": 9389843, + "headersEndOffset": 9390060, + "endOffset": 9395354, + "octets": 5294, + "lines": 72 + } + ], + "octets": 8982, + "lines": 169 + }, + "octets": 8982 + }, + { + "mboxMarkerOffset": 9395404, + "lineNumber": 146816, + "beginOffset": 9395437, + "headersEndOffset": 9396672, + "endOffset": 9399592, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146816, + "beginOffset": 9395437, + "headersEndOffset": 9396672, + "endOffset": 9399592, + "octets": 2920, + "lines": 38 + }, + "octets": 2920 + }, + { + "mboxMarkerOffset": 9399594, + "lineNumber": 146876, + "beginOffset": 9399627, + "headersEndOffset": 9400806, + "endOffset": 9402958, + "body": { + "mimeType": "Application/x-pkcs7-mime", + "lineNumber": 146876, + "beginOffset": 9399627, + "headersEndOffset": 9400806, + "endOffset": 9402958, + "octets": 2152, + "lines": 30 + }, + "octets": 2152 + }, + { + "mboxMarkerOffset": 9402960, + "lineNumber": 146929, + "beginOffset": 9402993, + "headersEndOffset": 9404092, + "endOffset": 9407102, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146929, + "beginOffset": 9402993, + "headersEndOffset": 9404092, + "endOffset": 9407102, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146952, + "beginOffset": 9404127, + "headersEndOffset": 9404194, + "endOffset": 9404194, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146957, + "beginOffset": 9404229, + "headersEndOffset": 9404311, + "endOffset": 9407065, + "octets": 2754, + "lines": 42 + } + ], + "octets": 3010, + "lines": 53 + }, + "octets": 3010 + }, + { + "mboxMarkerOffset": 9407104, + "lineNumber": 147005, + "beginOffset": 9407137, + "headersEndOffset": 9408193, + "endOffset": 9411145, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 147005, + "beginOffset": 9407137, + "headersEndOffset": 9408193, + "endOffset": 9411145, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147026, + "beginOffset": 9408236, + "headersEndOffset": 9408317, + "endOffset": 9408783, + "octets": 466, + "lines": 14 + }, + { + "mimeType": "text/html", + "lineNumber": 147044, + "beginOffset": 9408826, + "headersEndOffset": 9408904, + "endOffset": 9409741, + "octets": 837, + "lines": 27 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147075, + "beginOffset": 9409784, + "headersEndOffset": 9409884, + "endOffset": 9411100, + "octets": 1216, + "lines": 16 + } + ], + "octets": 2952, + "lines": 72 + }, + "octets": 2952 + }, + { + "mboxMarkerOffset": 9411147, + "lineNumber": 147098, + "beginOffset": 9411180, + "headersEndOffset": 9412276, + "endOffset": 9416879, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147098, + "beginOffset": 9411180, + "headersEndOffset": 9412276, + "endOffset": 9416879, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147121, + "beginOffset": 9412321, + "headersEndOffset": 9412394, + "endOffset": 9412553, + "octets": 159, + "lines": 7 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147133, + "beginOffset": 9412598, + "headersEndOffset": 9412680, + "endOffset": 9416832, + "octets": 4152, + "lines": 57 + } + ], + "octets": 4603, + "lines": 75 + }, + "octets": 4603 + }, + { + "mboxMarkerOffset": 9416881, + "lineNumber": 147196, + "beginOffset": 9416890, + "headersEndOffset": 9417456, + "endOffset": 9421944, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147196, + "beginOffset": 9416890, + "headersEndOffset": 9417456, + "endOffset": 9421944, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147213, + "beginOffset": 9417502, + "headersEndOffset": 9417569, + "endOffset": 9417727, + "octets": 158, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147221, + "beginOffset": 9417773, + "headersEndOffset": 9417928, + "endOffset": 9421898, + "octets": 3970, + "lines": 54 + } + ], + "octets": 4488, + "lines": 69 + }, + "octets": 4488 + }, + { + "mboxMarkerOffset": 9421946, + "lineNumber": 147281, + "beginOffset": 9421979, + "headersEndOffset": 9423163, + "endOffset": 9427294, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 147281, + "beginOffset": 9421979, + "headersEndOffset": 9423163, + "endOffset": 9427294, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147305, + "beginOffset": 9423344, + "headersEndOffset": 9423425, + "endOffset": 9423502, + "octets": 77, + "lines": 5 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 147315, + "beginOffset": 9423545, + "headersEndOffset": 9423643, + "endOffset": 9427249, + "octets": 3606, + "lines": 47 + } + ], + "octets": 4131, + "lines": 66 + }, + "octets": 4131 + }, + { + "mboxMarkerOffset": 9427296, + "lineNumber": 147369, + "beginOffset": 9427329, + "headersEndOffset": 9428452, + "endOffset": 9432575, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147369, + "beginOffset": 9427329, + "headersEndOffset": 9428452, + "endOffset": 9432575, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147392, + "beginOffset": 9428488, + "headersEndOffset": 9428569, + "endOffset": 9428647, + "octets": 78, + "lines": 5 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147401, + "beginOffset": 9428683, + "headersEndOffset": 9428765, + "endOffset": 9432539, + "octets": 3774, + "lines": 58 + } + ], + "octets": 4123, + "lines": 73 + }, + "octets": 4123 + }, + { + "mboxMarkerOffset": 9432577, + "lineNumber": 147464, + "beginOffset": 9432610, + "headersEndOffset": 9433755, + "endOffset": 9435052, + "body": { + "mimeType": "multipart/report", + "lineNumber": 147464, + "beginOffset": 9432610, + "headersEndOffset": 9433755, + "endOffset": 9435052, + "children": [ + { + "mimeType": "message/delivery-status", + "lineNumber": 147486, + "beginOffset": 9433897, + "headersEndOffset": 9433938, + "endOffset": 9434132, + "octets": 194, + "lines": 6 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 147496, + "beginOffset": 9434159, + "headersEndOffset": 9434191, + "endOffset": 9435023, + "message": { + "lineNumber": 147498, + "beginOffset": 9434191, + "headersEndOffset": 9435012, + "endOffset": 9435023, + "body": { + "mimeType": "text/plain", + "lineNumber": 147498, + "beginOffset": 9434191, + "headersEndOffset": 9435012, + "endOffset": 9435023, + "octets": 11, + "lines": 1 + }, + "octets": 11 + }, + "octets": 832, + "lines": 16 + } + ], + "octets": 1297, + "lines": 34 + }, + "octets": 1297 + }, + { + "mboxMarkerOffset": 9435054, + "lineNumber": 147517, + "beginOffset": 9435101, + "headersEndOffset": 9435272, + "endOffset": 9470358, + "body": { + "mimeType": "text/plain", + "lineNumber": 147517, + "beginOffset": 9435101, + "headersEndOffset": 9435272, + "endOffset": 9470358, + "octets": 35086, + "lines": 592 + }, + "octets": 35086 + }, + { + "mboxMarkerOffset": 9470360, + "lineNumber": 148117, + "beginOffset": 9470407, + "headersEndOffset": 9470571, + "endOffset": 9505657, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 148117, + "beginOffset": 9470407, + "headersEndOffset": 9470571, + "endOffset": 9505657, + "octets": 35086, + "lines": 592 + }, + "octets": 35086 + }, + { + "mboxMarkerOffset": 9505659, + "lineNumber": 148717, + "beginOffset": 9505668, + "headersEndOffset": 9506276, + "endOffset": 9507714, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 148717, + "beginOffset": 9505668, + "headersEndOffset": 9506276, + "endOffset": 9507714, + "octets": 1438, + "lines": 39 + }, + "octets": 1438 + }, + { + "mboxMarkerOffset": 9507716, + "lineNumber": 148768, + "beginOffset": 9507725, + "headersEndOffset": 9508642, + "endOffset": 9754778, + "body": { + "mimeType": "MULTIPART/mixed", + "lineNumber": 148768, + "beginOffset": 9507725, + "headersEndOffset": 9508642, + "endOffset": 9754778, + "children": [ + { + "mimeType": "TEXT/plain", + "lineNumber": 148786, + "beginOffset": 9508682, + "headersEndOffset": 9508710, + "endOffset": 9509065, + "octets": 355, + "lines": 10 + }, + { + "mimeType": "AUDIO/basic", + "lineNumber": 148800, + "beginOffset": 9509107, + "headersEndOffset": 9509204, + "endOffset": 9754734, + "octets": 245530, + "lines": 3961 + } + ], + "octets": 246136, + "lines": 3982 + }, + "octets": 246136 + }, + { + "mboxMarkerOffset": 9754780, + "lineNumber": 152769, + "beginOffset": 9754789, + "headersEndOffset": 9755397, + "endOffset": 9834353, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 152769, + "beginOffset": 9754789, + "headersEndOffset": 9755397, + "endOffset": 9834353, + "children": [ + { + "mimeType": "image/pbm", + "lineNumber": 152786, + "beginOffset": 9755461, + "headersEndOffset": 9755625, + "endOffset": 9834319, + "octets": 78694, + "lines": 406 + } + ], + "octets": 78956, + "lines": 416 + }, + "octets": 78956 + }, + { + "mboxMarkerOffset": 9834355, + "lineNumber": 153201, + "beginOffset": 9834364, + "headersEndOffset": 9834521, + "endOffset": 9838129, + "body": { + "mimeType": "message/partial", + "lineNumber": 153201, + "beginOffset": 9834364, + "headersEndOffset": 9834521, + "endOffset": 9838129, + "octets": 3608, + "lines": 49 + }, + "octets": 3608 + }, + { + "mboxMarkerOffset": 9838131, + "lineNumber": 153256, + "beginOffset": 9838140, + "headersEndOffset": 9838928, + "endOffset": 9869675, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 153256, + "beginOffset": 9838140, + "headersEndOffset": 9838928, + "endOffset": 9869675, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153276, + "beginOffset": 9839127, + "headersEndOffset": 9839173, + "endOffset": 9839594, + "octets": 421, + "lines": 7 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 153287, + "beginOffset": 9839637, + "headersEndOffset": 9839725, + "endOffset": 9869632, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 153291, + "beginOffset": 9839768, + "headersEndOffset": 9839862, + "endOffset": 9839934, + "octets": 72, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153297, + "beginOffset": 9839979, + "headersEndOffset": 9840082, + "endOffset": 9850936, + "octets": 10854, + "lines": 157 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153460, + "beginOffset": 9850981, + "headersEndOffset": 9851075, + "endOffset": 9851141, + "octets": 66, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153467, + "beginOffset": 9851186, + "headersEndOffset": 9851283, + "endOffset": 9857273, + "octets": 5990, + "lines": 87 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153560, + "beginOffset": 9857318, + "headersEndOffset": 9857412, + "endOffset": 9857447, + "octets": 35, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153567, + "beginOffset": 9857492, + "headersEndOffset": 9857597, + "endOffset": 9869413, + "octets": 11816, + "lines": 170 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153743, + "beginOffset": 9869458, + "headersEndOffset": 9869552, + "endOffset": 9869585, + "octets": 33, + "lines": 2 + } + ], + "octets": 29907, + "lines": 460 + } + ], + "octets": 30747, + "lines": 480 + }, + "octets": 30747 + }, + { + "mboxMarkerOffset": 9869677, + "lineNumber": 153753, + "beginOffset": 9869686, + "headersEndOffset": 9869745, + "endOffset": 9870980, + "body": { + "mimeType": "text/plain", + "lineNumber": 153753, + "beginOffset": 9869686, + "headersEndOffset": 9869745, + "endOffset": 9870980, + "octets": 1235, + "lines": 28 + }, + "octets": 1235 + }, + { + "mboxMarkerOffset": 9870982, + "lineNumber": 153785, + "beginOffset": 9871015, + "headersEndOffset": 9871171, + "endOffset": 9874346, + "body": { + "mimeType": "text/plain", + "lineNumber": 153785, + "beginOffset": 9871015, + "headersEndOffset": 9871171, + "endOffset": 9874346, + "octets": 3175, + "lines": 68 + }, + "octets": 3175 + }, + { + "mboxMarkerOffset": 9874348, + "lineNumber": 153859, + "beginOffset": 9874381, + "headersEndOffset": 9876277, + "endOffset": 9881248, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 153859, + "beginOffset": 9874381, + "headersEndOffset": 9876277, + "endOffset": 9881248, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153891, + "beginOffset": 9876322, + "headersEndOffset": 9876403, + "endOffset": 9877284, + "octets": 881, + "lines": 18 + }, + { + "mimeType": "application/vcard", + "lineNumber": 153914, + "beginOffset": 9877331, + "headersEndOffset": 9877497, + "endOffset": 9881199, + "octets": 3702, + "lines": 61 + } + ], + "octets": 4971, + "lines": 92 + }, + "octets": 4971 + }, + { + "mboxMarkerOffset": 9881250, + "lineNumber": 153984, + "beginOffset": 9881259, + "headersEndOffset": 9881826, + "endOffset": 10000273, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 153984, + "beginOffset": 9881259, + "headersEndOffset": 9881826, + "endOffset": 10000273, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153999, + "beginOffset": 9881845, + "headersEndOffset": 9881874, + "endOffset": 9882856, + "octets": 982, + "lines": 19 + }, + { + "mimeType": "image/pgm", + "lineNumber": 154022, + "beginOffset": 9882875, + "headersEndOffset": 9882938, + "endOffset": 10000250, + "octets": 117312, + "lines": 1586 + } + ], + "octets": 118447, + "lines": 1617 + }, + "octets": 118447 + }, + { + "mboxMarkerOffset": 10000275, + "lineNumber": 155616, + "beginOffset": 10000284, + "headersEndOffset": 10001099, + "endOffset": 10026556, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 155616, + "beginOffset": 10000284, + "headersEndOffset": 10001099, + "endOffset": 10026556, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 155639, + "beginOffset": 10001298, + "headersEndOffset": 10001344, + "endOffset": 10010656, + "octets": 9312, + "lines": 349 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 155992, + "beginOffset": 10010699, + "headersEndOffset": 10010787, + "endOffset": 10026511, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 155996, + "beginOffset": 10010830, + "headersEndOffset": 10010924, + "endOffset": 10013768, + "octets": 2844, + "lines": 69 + }, + { + "mimeType": "message/external-body", + "lineNumber": 156070, + "beginOffset": 10013813, + "headersEndOffset": 10014016, + "endOffset": 10014049, + "message": { + "lineNumber": 156077, + "beginOffset": 10014016, + "headersEndOffset": 10014045, + "endOffset": 10014049, + "body": { + "mimeType": "text/X-HTML", + "lineNumber": 156077, + "beginOffset": 10014016, + "headersEndOffset": 10014045, + "endOffset": 10014049, + "octets": 4, + "lines": 2 + }, + "octets": 4 + }, + "octets": 33, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156083, + "beginOffset": 10014094, + "headersEndOffset": 10014188, + "endOffset": 10015184, + "octets": 996, + "lines": 22 + }, + { + "mimeType": "text/SGML", + "lineNumber": 156110, + "beginOffset": 10015229, + "headersEndOffset": 10015349, + "endOffset": 10015723, + "octets": 374, + "lines": 15 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156131, + "beginOffset": 10015768, + "headersEndOffset": 10015862, + "endOffset": 10015874, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 156138, + "beginOffset": 10015919, + "headersEndOffset": 10016110, + "endOffset": 10016141, + "message": { + "lineNumber": 156144, + "beginOffset": 10016110, + "headersEndOffset": 10016139, + "endOffset": 10016141, + "body": { + "mimeType": "text/X-HTML", + "lineNumber": 156144, + "beginOffset": 10016110, + "headersEndOffset": 10016139, + "endOffset": 10016141, + "octets": 2, + "lines": 1 + }, + "octets": 2 + }, + "octets": 31, + "lines": 3 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156149, + "beginOffset": 10016186, + "headersEndOffset": 10016280, + "endOffset": 10016292, + "octets": 12, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 156156, + "beginOffset": 10016337, + "headersEndOffset": 10016447, + "endOffset": 10019473, + "octets": 3026, + "lines": 43 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156205, + "beginOffset": 10019518, + "headersEndOffset": 10019612, + "endOffset": 10026464, + "octets": 6852, + "lines": 260 + } + ], + "octets": 15724, + "lines": 475 + } + ], + "octets": 25457, + "lines": 837 + }, + "octets": 25457 + }, + { + "mboxMarkerOffset": 10026558, + "lineNumber": 156474, + "beginOffset": 10026567, + "headersEndOffset": 10027702, + "endOffset": 10058732, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 156474, + "beginOffset": 10026567, + "headersEndOffset": 10027702, + "endOffset": 10058732, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 156498, + "beginOffset": 10027713, + "headersEndOffset": 10027715, + "endOffset": 10028056, + "octets": 341, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 156509, + "beginOffset": 10028069, + "headersEndOffset": 10028131, + "endOffset": 10058521, + "octets": 30390, + "lines": 411 + }, + { + "mimeType": "text/plain", + "lineNumber": 156925, + "beginOffset": 10058534, + "headersEndOffset": 10058536, + "endOffset": 10058717, + "octets": 181, + "lines": 9 + } + ], + "octets": 31030, + "lines": 440 + }, + "octets": 31030 + }, + { + "mboxMarkerOffset": 10058734, + "lineNumber": 156939, + "beginOffset": 10058743, + "headersEndOffset": 10060481, + "endOffset": 10246231, + "body": { + "mimeType": "text/plain", + "lineNumber": 156939, + "beginOffset": 10058743, + "headersEndOffset": 10060481, + "endOffset": 10246231, + "octets": 185750, + "lines": 2951 + }, + "octets": 185750 + }, + { + "mboxMarkerOffset": 10246233, + "lineNumber": 159921, + "beginOffset": 10246242, + "headersEndOffset": 10246965, + "endOffset": 10331708, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 159921, + "beginOffset": 10246242, + "headersEndOffset": 10246965, + "endOffset": 10331708, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 159938, + "beginOffset": 10246993, + "headersEndOffset": 10246995, + "endOffset": 10247016, + "octets": 21, + "lines": 1 + }, + { + "mimeType": "image/pgm", + "lineNumber": 159941, + "beginOffset": 10247046, + "headersEndOffset": 10247203, + "endOffset": 10331377, + "octets": 84174, + "lines": 434 + }, + { + "mimeType": "text/plain", + "lineNumber": 160381, + "beginOffset": 10331407, + "headersEndOffset": 10331409, + "endOffset": 10331676, + "octets": 267, + "lines": 9 + } + ], + "octets": 84743, + "lines": 455 + }, + "octets": 84743 + }, + { + "mboxMarkerOffset": 10331710, + "lineNumber": 160394, + "beginOffset": 10331719, + "headersEndOffset": 10332401, + "endOffset": 10554623, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 160394, + "beginOffset": 10331719, + "headersEndOffset": 10332401, + "endOffset": 10554623, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 160410, + "beginOffset": 10332429, + "headersEndOffset": 10332431, + "endOffset": 10332497, + "octets": 66, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 160413, + "beginOffset": 10332527, + "headersEndOffset": 10332693, + "endOffset": 10365025, + "octets": 32332, + "lines": 167 + }, + { + "mimeType": "text/plain", + "lineNumber": 160586, + "beginOffset": 10365055, + "headersEndOffset": 10365057, + "endOffset": 10365075, + "octets": 18, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 160590, + "beginOffset": 10365105, + "headersEndOffset": 10365269, + "endOffset": 10366359, + "octets": 1090, + "lines": 6 + }, + { + "mimeType": "text/plain", + "lineNumber": 160602, + "beginOffset": 10366389, + "headersEndOffset": 10366391, + "endOffset": 10366423, + "octets": 32, + "lines": 2 + }, + { + "mimeType": "application/x-annotate-2", + "lineNumber": 160607, + "beginOffset": 10366453, + "headersEndOffset": 10366524, + "endOffset": 10554551, + "octets": 188027, + "lines": 1990 + }, + { + "mimeType": "text/plain", + "lineNumber": 162602, + "beginOffset": 10554581, + "headersEndOffset": 10554583, + "endOffset": 10554591, + "octets": 8, + "lines": 1 + } + ], + "octets": 222222, + "lines": 2196 + }, + "octets": 222222 + }, + { + "mboxMarkerOffset": 10554625, + "lineNumber": 162607, + "beginOffset": 10554634, + "headersEndOffset": 10554906, + "endOffset": 10630586, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 162607, + "beginOffset": 10554634, + "headersEndOffset": 10554906, + "endOffset": 10630586, + "octets": 75680, + "lines": 1023 + }, + "octets": 75680 + }, + { + "mboxMarkerOffset": 10630588, + "lineNumber": 163639, + "beginOffset": 10630597, + "headersEndOffset": 10631896, + "endOffset": 10687748, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 163639, + "beginOffset": 10630597, + "headersEndOffset": 10631896, + "endOffset": 10687748, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 163673, + "beginOffset": 10632489, + "headersEndOffset": 10632491, + "endOffset": 10634372, + "octets": 1881, + "lines": 34 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 163710, + "beginOffset": 10634433, + "headersEndOffset": 10634539, + "endOffset": 10687685, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 163714, + "beginOffset": 10634600, + "headersEndOffset": 10634676, + "endOffset": 10636704, + "octets": 2028, + "lines": 29 + }, + { + "mimeType": "image/xwd", + "lineNumber": 163748, + "beginOffset": 10636767, + "headersEndOffset": 10636829, + "endOffset": 10644867, + "octets": 8038, + "lines": 109 + }, + { + "mimeType": "text/plain", + "lineNumber": 163862, + "beginOffset": 10644930, + "headersEndOffset": 10645003, + "endOffset": 10645008, + "octets": 5, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 163869, + "beginOffset": 10645071, + "headersEndOffset": 10645168, + "endOffset": 10687620, + "octets": 42452, + "lines": 574 + } + ], + "octets": 53146, + "lines": 736 + } + ], + "octets": 55852, + "lines": 787 + }, + "octets": 55852 + }, + { + "mboxMarkerOffset": 10687750, + "lineNumber": 164453, + "beginOffset": 10687759, + "headersEndOffset": 10687916, + "endOffset": 10692786, + "body": { + "mimeType": "message/partial", + "lineNumber": 164453, + "beginOffset": 10687759, + "headersEndOffset": 10687916, + "endOffset": 10692786, + "octets": 4870, + "lines": 68 + }, + "octets": 4870 + }, + { + "mboxMarkerOffset": 10692788, + "lineNumber": 164527, + "beginOffset": 10692797, + "headersEndOffset": 10693559, + "endOffset": 10700991, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 164527, + "beginOffset": 10692797, + "headersEndOffset": 10693559, + "endOffset": 10700991, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 164551, + "beginOffset": 10693945, + "headersEndOffset": 10693947, + "endOffset": 10694323, + "octets": 376, + "lines": 8 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 164562, + "beginOffset": 10694366, + "headersEndOffset": 10694454, + "endOffset": 10700946, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 164566, + "beginOffset": 10694497, + "headersEndOffset": 10694570, + "endOffset": 10694663, + "octets": 93, + "lines": 4 + }, + { + "mimeType": "image/gif", + "lineNumber": 164575, + "beginOffset": 10694708, + "headersEndOffset": 10694826, + "endOffset": 10700572, + "octets": 5746, + "lines": 83 + }, + { + "mimeType": "text/plain", + "lineNumber": 164664, + "beginOffset": 10700617, + "headersEndOffset": 10700690, + "endOffset": 10700899, + "octets": 209, + "lines": 6 + } + ], + "octets": 6492, + "lines": 110 + } + ], + "octets": 7432, + "lines": 133 + }, + "octets": 7432 + } +] \ No newline at end of file diff --git a/UnitTests/TestData/mbox/jwz.unix-offsets.json b/UnitTests/TestData/mbox/jwz.unix-offsets.json new file mode 100644 index 0000000000..b560f4418c --- /dev/null +++ b/UnitTests/TestData/mbox/jwz.unix-offsets.json @@ -0,0 +1,9567 @@ +[ + { + "mboxMarkerOffset": 0, + "lineNumber": 2, + "beginOffset": 8, + "headersEndOffset": 517, + "endOffset": 177075, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 2, + "beginOffset": 8, + "headersEndOffset": 517, + "endOffset": 177075, + "children": [ + { + "mimeType": "multipart/parallel", + "lineNumber": 16, + "beginOffset": 534, + "headersEndOffset": 630, + "endOffset": 32572, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 20, + "beginOffset": 661, + "headersEndOffset": 662, + "endOffset": 1377, + "octets": 715, + "lines": 17 + }, + { + "mimeType": "audio/basic", + "lineNumber": 39, + "beginOffset": 1409, + "headersEndOffset": 1493, + "endOffset": 32539, + "octets": 31046, + "lines": 426 + } + ], + "octets": 31942, + "lines": 452 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 472, + "beginOffset": 32590, + "headersEndOffset": 32683, + "endOffset": 129778, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 476, + "beginOffset": 32714, + "headersEndOffset": 32796, + "endOffset": 58444, + "octets": 25648, + "lines": 352 + }, + { + "mimeType": "image/gif", + "lineNumber": 834, + "beginOffset": 58476, + "headersEndOffset": 58558, + "endOffset": 76971, + "octets": 18413, + "lines": 253 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 1093, + "beginOffset": 77003, + "headersEndOffset": 77117, + "endOffset": 120806, + "octets": 43689, + "lines": 2437 + }, + { + "mimeType": "application/atomicmail", + "lineNumber": 3534, + "beginOffset": 120838, + "headersEndOffset": 120899, + "endOffset": 129745, + "octets": 8846, + "lines": 357 + } + ], + "octets": 97095, + "lines": 3421 + }, + { + "mimeType": "audio/basic", + "lineNumber": 3897, + "beginOffset": 129796, + "headersEndOffset": 129880, + "endOffset": 177055, + "octets": 47175, + "lines": 647 + } + ], + "octets": 176558, + "lines": 4535 + }, + "octets": 176558 + }, + { + "mboxMarkerOffset": 177076, + "lineNumber": 4552, + "beginOffset": 177084, + "headersEndOffset": 177633, + "endOffset": 312903, + "body": { + "mimeType": "audio/basic", + "lineNumber": 4552, + "beginOffset": 177084, + "headersEndOffset": 177633, + "endOffset": 312903, + "octets": 135270, + "lines": 1854 + }, + "octets": 135270 + }, + { + "mboxMarkerOffset": 312904, + "lineNumber": 6422, + "beginOffset": 312912, + "headersEndOffset": 313291, + "endOffset": 313492, + "body": { + "mimeType": "text/plain", + "lineNumber": 6422, + "beginOffset": 312912, + "headersEndOffset": 313291, + "endOffset": 313492, + "octets": 201, + "lines": 4 + }, + "octets": 201 + }, + { + "mboxMarkerOffset": 313493, + "lineNumber": 6435, + "beginOffset": 313501, + "headersEndOffset": 314147, + "endOffset": 319811, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 6435, + "beginOffset": 313501, + "headersEndOffset": 314147, + "endOffset": 319811, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6454, + "beginOffset": 314342, + "headersEndOffset": 314386, + "endOffset": 314619, + "octets": 233, + "lines": 6 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 6464, + "beginOffset": 314660, + "headersEndOffset": 314745, + "endOffset": 319769, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6468, + "beginOffset": 314787, + "headersEndOffset": 314878, + "endOffset": 315024, + "octets": 146, + "lines": 3 + }, + { + "mimeType": "image/gif", + "lineNumber": 6476, + "beginOffset": 315067, + "headersEndOffset": 315177, + "endOffset": 319545, + "octets": 4368, + "lines": 64 + }, + { + "mimeType": "text/richtext", + "lineNumber": 6546, + "beginOffset": 319588, + "headersEndOffset": 319679, + "endOffset": 319724, + "octets": 45, + "lines": 3 + } + ], + "octets": 5024, + "lines": 87 + } + ], + "octets": 5664, + "lines": 106 + }, + "octets": 5664 + }, + { + "mboxMarkerOffset": 319812, + "lineNumber": 6557, + "beginOffset": 319820, + "headersEndOffset": 320568, + "endOffset": 343841, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 6557, + "beginOffset": 319820, + "headersEndOffset": 320568, + "endOffset": 343841, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6579, + "beginOffset": 320825, + "headersEndOffset": 320898, + "endOffset": 321322, + "octets": 424, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 6596, + "beginOffset": 321385, + "headersEndOffset": 321415, + "endOffset": 343533, + "message": { + "lineNumber": 6598, + "beginOffset": 321415, + "headersEndOffset": 322251, + "endOffset": 343533, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 6598, + "beginOffset": 321415, + "headersEndOffset": 322251, + "endOffset": 343533, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6623, + "beginOffset": 322557, + "headersEndOffset": 322651, + "endOffset": 322755, + "octets": 104, + "lines": 6 + }, + { + "mimeType": "audio/basic", + "lineNumber": 6634, + "beginOffset": 322786, + "headersEndOffset": 322875, + "endOffset": 343502, + "octets": 20627, + "lines": 283 + }, + { + "mimeType": "text/plain", + "lineNumber": 6922, + "beginOffset": 343533, + "headersEndOffset": 343533, + "endOffset": 343533, + "octets": 0, + "lines": 0 + } + ], + "octets": 21282, + "lines": 308 + }, + "octets": 21282 + }, + "octets": 22118, + "lines": 324 + }, + { + "mimeType": "text/richtext", + "lineNumber": 6924, + "beginOffset": 343596, + "headersEndOffset": 343669, + "endOffset": 343776, + "octets": 107, + "lines": 4 + } + ], + "octets": 23273, + "lines": 359 + }, + "octets": 23273 + }, + { + "mboxMarkerOffset": 343842, + "lineNumber": 6935, + "beginOffset": 343850, + "headersEndOffset": 344568, + "endOffset": 2108724, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 6935, + "beginOffset": 343850, + "headersEndOffset": 344568, + "endOffset": 2108724, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 6955, + "beginOffset": 344763, + "headersEndOffset": 344807, + "endOffset": 345567, + "octets": 760, + "lines": 18 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 6977, + "beginOffset": 345608, + "headersEndOffset": 345693, + "endOffset": 2108682, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 6981, + "beginOffset": 345735, + "headersEndOffset": 345826, + "endOffset": 346051, + "octets": 225, + "lines": 4 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 6990, + "beginOffset": 346094, + "headersEndOffset": 346202, + "endOffset": 1021266, + "octets": 675064, + "lines": 8982 + }, + { + "mimeType": "text/richtext", + "lineNumber": 15978, + "beginOffset": 1021309, + "headersEndOffset": 1021400, + "endOffset": 1021516, + "octets": 116, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 15988, + "beginOffset": 1021559, + "headersEndOffset": 1021685, + "endOffset": 1702821, + "octets": 681136, + "lines": 9060 + }, + { + "mimeType": "text/richtext", + "lineNumber": 25054, + "beginOffset": 1702864, + "headersEndOffset": 1702955, + "endOffset": 1702965, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 25061, + "beginOffset": 1703008, + "headersEndOffset": 1703125, + "endOffset": 1771303, + "octets": 68178, + "lines": 934 + }, + { + "mimeType": "text/richtext", + "lineNumber": 26001, + "beginOffset": 1771346, + "headersEndOffset": 1771437, + "endOffset": 1771575, + "octets": 138, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 26011, + "beginOffset": 1771618, + "headersEndOffset": 1771736, + "endOffset": 2108498, + "octets": 336762, + "lines": 4472 + }, + { + "mimeType": "text/richtext", + "lineNumber": 30489, + "beginOffset": 2108541, + "headersEndOffset": 2108632, + "endOffset": 2108637, + "octets": 5, + "lines": 1 + } + ], + "octets": 1762989, + "lines": 23515 + } + ], + "octets": 1764156, + "lines": 23546 + }, + "octets": 1764156 + }, + { + "mboxMarkerOffset": 2108725, + "lineNumber": 30498, + "beginOffset": 2108733, + "headersEndOffset": 2109749, + "endOffset": 2110874, + "body": { + "mimeType": "text/plain", + "lineNumber": 30498, + "beginOffset": 2108733, + "headersEndOffset": 2109749, + "endOffset": 2110874, + "octets": 1125, + "lines": 39 + }, + "octets": 1125 + }, + { + "mboxMarkerOffset": 2110875, + "lineNumber": 30560, + "beginOffset": 2110883, + "headersEndOffset": 2111121, + "endOffset": 2275728, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 30560, + "beginOffset": 2110883, + "headersEndOffset": 2111121, + "endOffset": 2275728, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 30570, + "beginOffset": 2111136, + "headersEndOffset": 2111137, + "endOffset": 2111437, + "octets": 300, + "lines": 6 + }, + { + "mimeType": "multipart/parallel", + "lineNumber": 30578, + "beginOffset": 2111453, + "headersEndOffset": 2111529, + "endOffset": 2270919, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 30582, + "beginOffset": 2111545, + "headersEndOffset": 2111622, + "endOffset": 2114882, + "octets": 3260, + "lines": 17 + }, + { + "mimeType": "audio/basic", + "lineNumber": 30604, + "beginOffset": 2114899, + "headersEndOffset": 2115002, + "endOffset": 2270901, + "octets": 155899, + "lines": 808 + } + ], + "octets": 159390, + "lines": 837 + }, + { + "mimeType": "application/atomicmail", + "lineNumber": 31419, + "beginOffset": 2270935, + "headersEndOffset": 2270991, + "endOffset": 2275711, + "octets": 4720, + "lines": 195 + } + ], + "octets": 164607, + "lines": 1050 + }, + "octets": 164607 + }, + { + "mboxMarkerOffset": 2275729, + "lineNumber": 31620, + "beginOffset": 2275737, + "headersEndOffset": 2276689, + "endOffset": 2619749, + "body": { + "mimeType": "audio/basic", + "lineNumber": 31620, + "beginOffset": 2275737, + "headersEndOffset": 2276689, + "endOffset": 2619749, + "octets": 343060, + "lines": 4456 + }, + "octets": 343060 + }, + { + "mboxMarkerOffset": 2619750, + "lineNumber": 36098, + "beginOffset": 2619758, + "headersEndOffset": 2619892, + "endOffset": 2651948, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 36098, + "beginOffset": 2619758, + "headersEndOffset": 2619892, + "endOffset": 2651948, + "children": [ + { + "mimeType": "multipart/parallel", + "lineNumber": 36104, + "beginOffset": 2619909, + "headersEndOffset": 2619982, + "endOffset": 2651929, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 36107, + "beginOffset": 2620013, + "headersEndOffset": 2620014, + "endOffset": 2620721, + "octets": 707, + "lines": 18 + }, + { + "mimeType": "audio/basic", + "lineNumber": 36127, + "beginOffset": 2620753, + "headersEndOffset": 2620850, + "endOffset": 2651896, + "octets": 31046, + "lines": 426 + } + ], + "octets": 31947, + "lines": 453 + } + ], + "octets": 32056, + "lines": 457 + }, + "octets": 32056 + }, + { + "mboxMarkerOffset": 2651949, + "lineNumber": 36561, + "beginOffset": 2651957, + "headersEndOffset": 2652514, + "endOffset": 2709293, + "body": { + "mimeType": "image/pbm", + "lineNumber": 36561, + "beginOffset": 2651957, + "headersEndOffset": 2652514, + "endOffset": 2709293, + "octets": 56779, + "lines": 782 + }, + "octets": 56779 + }, + { + "mboxMarkerOffset": 2709294, + "lineNumber": 37359, + "beginOffset": 2709302, + "headersEndOffset": 2710035, + "endOffset": 2741562, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 37359, + "beginOffset": 2709302, + "headersEndOffset": 2710035, + "endOffset": 2741562, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37385, + "beginOffset": 2710619, + "headersEndOffset": 2710620, + "endOffset": 2711172, + "octets": 552, + "lines": 14 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 37402, + "beginOffset": 2711231, + "headersEndOffset": 2711334, + "endOffset": 2741502, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 37406, + "beginOffset": 2711394, + "headersEndOffset": 2711467, + "endOffset": 2711886, + "octets": 419, + "lines": 7 + }, + { + "mimeType": "image/xwd", + "lineNumber": 37418, + "beginOffset": 2711947, + "headersEndOffset": 2712006, + "endOffset": 2741267, + "octets": 29261, + "lines": 401 + }, + { + "mimeType": "text/plain", + "lineNumber": 37824, + "beginOffset": 2741328, + "headersEndOffset": 2741398, + "endOffset": 2741439, + "octets": 41, + "lines": 4 + } + ], + "octets": 30168, + "lines": 428 + } + ], + "octets": 31527, + "lines": 459 + }, + "octets": 31527 + }, + { + "mboxMarkerOffset": 2741563, + "lineNumber": 37836, + "beginOffset": 2741571, + "headersEndOffset": 2742224, + "endOffset": 2747107, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 37836, + "beginOffset": 2741571, + "headersEndOffset": 2742224, + "endOffset": 2747107, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37860, + "beginOffset": 2742593, + "headersEndOffset": 2742594, + "endOffset": 2743415, + "octets": 821, + "lines": 27 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 37890, + "beginOffset": 2743445, + "headersEndOffset": 2743518, + "endOffset": 2747075, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 37894, + "beginOffset": 2743549, + "headersEndOffset": 2743575, + "endOffset": 2743712, + "octets": 137, + "lines": 6 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 37903, + "beginOffset": 2743744, + "headersEndOffset": 2743809, + "endOffset": 2745006, + "octets": 1197, + "lines": 17 + }, + { + "mimeType": "text/plain", + "lineNumber": 37925, + "beginOffset": 2745038, + "headersEndOffset": 2745064, + "endOffset": 2745132, + "octets": 68, + "lines": 1 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 37929, + "beginOffset": 2745164, + "headersEndOffset": 2745229, + "endOffset": 2746434, + "octets": 1205, + "lines": 17 + }, + { + "mimeType": "text/richtext", + "lineNumber": 37951, + "beginOffset": 2746466, + "headersEndOffset": 2746495, + "endOffset": 2747041, + "octets": 546, + "lines": 14 + } + ], + "octets": 3557, + "lines": 75 + } + ], + "octets": 4883, + "lines": 118 + }, + "octets": 4883 + }, + { + "mboxMarkerOffset": 2747108, + "lineNumber": 37972, + "beginOffset": 2747116, + "headersEndOffset": 2748092, + "endOffset": 2749474, + "body": { + "mimeType": "text/plain", + "lineNumber": 37972, + "beginOffset": 2747116, + "headersEndOffset": 2748092, + "endOffset": 2749474, + "octets": 1382, + "lines": 32 + }, + "octets": 1382 + }, + { + "mboxMarkerOffset": 2749475, + "lineNumber": 38027, + "beginOffset": 2749483, + "headersEndOffset": 2749739, + "endOffset": 2749995, + "body": { + "mimeType": "text/plain", + "lineNumber": 38027, + "beginOffset": 2749483, + "headersEndOffset": 2749739, + "endOffset": 2749995, + "octets": 256, + "lines": 6 + }, + "octets": 256 + }, + { + "mboxMarkerOffset": 2749996, + "lineNumber": 38041, + "beginOffset": 2750004, + "headersEndOffset": 2750661, + "endOffset": 2751385, + "body": { + "mimeType": "text/plain", + "lineNumber": 38041, + "beginOffset": 2750004, + "headersEndOffset": 2750661, + "endOffset": 2751385, + "octets": 724, + "lines": 14 + }, + "octets": 724 + }, + { + "mboxMarkerOffset": 2751386, + "lineNumber": 38071, + "beginOffset": 2751394, + "headersEndOffset": 2752379, + "endOffset": 3183395, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 38071, + "beginOffset": 2751394, + "headersEndOffset": 2752379, + "endOffset": 3183395, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 38088, + "beginOffset": 2752420, + "headersEndOffset": 2752466, + "endOffset": 2752538, + "octets": 72, + "lines": 5 + }, + { + "mimeType": "multipart/appledouble", + "lineNumber": 38097, + "beginOffset": 2752578, + "headersEndOffset": 2752665, + "endOffset": 3183354, + "children": [ + { + "mimeType": "application/applefile", + "lineNumber": 38102, + "beginOffset": 2752707, + "headersEndOffset": 2752862, + "endOffset": 2818779, + "octets": 65917, + "lines": 957 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 39065, + "beginOffset": 2818820, + "headersEndOffset": 2819029, + "endOffset": 3183310, + "octets": 364281, + "lines": 5281 + } + ], + "octets": 430689, + "lines": 6256 + } + ], + "octets": 431016, + "lines": 6272 + }, + "octets": 431016 + }, + { + "mboxMarkerOffset": 3183396, + "lineNumber": 44358, + "beginOffset": 3183404, + "headersEndOffset": 3184389, + "endOffset": 3615404, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 44358, + "beginOffset": 3183404, + "headersEndOffset": 3184389, + "endOffset": 3615404, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 44375, + "beginOffset": 3184430, + "headersEndOffset": 3184476, + "endOffset": 3184548, + "octets": 72, + "lines": 5 + }, + { + "mimeType": "multipart/header-set", + "lineNumber": 44384, + "beginOffset": 3184588, + "headersEndOffset": 3184674, + "endOffset": 3615363, + "children": [ + { + "mimeType": "application/applefile", + "lineNumber": 44389, + "beginOffset": 3184716, + "headersEndOffset": 3184871, + "endOffset": 3250788, + "octets": 65917, + "lines": 957 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 45352, + "beginOffset": 3250829, + "headersEndOffset": 3251038, + "endOffset": 3615319, + "octets": 364281, + "lines": 5281 + } + ], + "octets": 430689, + "lines": 6256 + } + ], + "octets": 431015, + "lines": 6272 + }, + "octets": 431015 + }, + { + "mboxMarkerOffset": 3615405, + "lineNumber": 50645, + "beginOffset": 3615413, + "headersEndOffset": 3615971, + "endOffset": 3616557, + "body": { + "mimeType": "Message/rfc822", + "lineNumber": 50645, + "beginOffset": 3615413, + "headersEndOffset": 3615971, + "endOffset": 3616557, + "message": { + "lineNumber": 50660, + "beginOffset": 3615971, + "headersEndOffset": 3616030, + "endOffset": 3616557, + "body": { + "mimeType": "text/plain", + "lineNumber": 50660, + "beginOffset": 3615971, + "headersEndOffset": 3616030, + "endOffset": 3616557, + "octets": 527, + "lines": 14 + }, + "octets": 527 + }, + "octets": 586, + "lines": 17 + }, + "octets": 586 + }, + { + "mboxMarkerOffset": 3616558, + "lineNumber": 50678, + "beginOffset": 3616566, + "headersEndOffset": 3617279, + "endOffset": 3618690, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50678, + "beginOffset": 3616566, + "headersEndOffset": 3617279, + "endOffset": 3618690, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50698, + "beginOffset": 3617323, + "headersEndOffset": 3617349, + "endOffset": 3617529, + "octets": 180, + "lines": 6 + }, + { + "mimeType": "application/postscript", + "lineNumber": 50708, + "beginOffset": 3617573, + "headersEndOffset": 3617645, + "endOffset": 3618537, + "octets": 892, + "lines": 12 + } + ], + "octets": 1411, + "lines": 33 + }, + "octets": 1411 + }, + { + "mboxMarkerOffset": 3618691, + "lineNumber": 50731, + "beginOffset": 3618699, + "headersEndOffset": 3619238, + "endOffset": 3623959, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50731, + "beginOffset": 3618699, + "headersEndOffset": 3619238, + "endOffset": 3623959, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50748, + "beginOffset": 3619314, + "headersEndOffset": 3619315, + "endOffset": 3619707, + "octets": 392, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 50761, + "beginOffset": 3619747, + "headersEndOffset": 3619777, + "endOffset": 3623917, + "message": { + "lineNumber": 50763, + "beginOffset": 3619777, + "headersEndOffset": 3620564, + "endOffset": 3623917, + "body": { + "mimeType": "text/plain", + "lineNumber": 50763, + "beginOffset": 3619777, + "headersEndOffset": 3620564, + "endOffset": 3623917, + "octets": 3353, + "lines": 72 + }, + "octets": 3353 + }, + "octets": 4140, + "lines": 88 + } + ], + "octets": 4721, + "lines": 108 + }, + "octets": 4721 + }, + { + "mboxMarkerOffset": 3623960, + "lineNumber": 50855, + "beginOffset": 3623968, + "headersEndOffset": 3624617, + "endOffset": 3625848, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 50855, + "beginOffset": 3623968, + "headersEndOffset": 3624617, + "endOffset": 3625848, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 50873, + "beginOffset": 3624666, + "headersEndOffset": 3624692, + "endOffset": 3624766, + "octets": 74, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 50881, + "beginOffset": 3624816, + "headersEndOffset": 3624878, + "endOffset": 3625797, + "message": { + "lineNumber": 50884, + "beginOffset": 3624878, + "headersEndOffset": 3625660, + "endOffset": 3625797, + "body": { + "mimeType": "text/plain", + "lineNumber": 50884, + "beginOffset": 3624878, + "headersEndOffset": 3625660, + "endOffset": 3625797, + "octets": 137, + "lines": 4 + }, + "octets": 137 + }, + "octets": 919, + "lines": 21 + } + ], + "octets": 1231, + "lines": 34 + }, + "octets": 1231 + }, + { + "mboxMarkerOffset": 3625849, + "lineNumber": 50907, + "beginOffset": 3625857, + "headersEndOffset": 3626367, + "endOffset": 3627786, + "body": { + "mimeType": "Application/octet-stream", + "lineNumber": 50907, + "beginOffset": 3625857, + "headersEndOffset": 3626367, + "endOffset": 3627786, + "octets": 1419, + "lines": 45 + }, + "octets": 1419 + }, + { + "mboxMarkerOffset": 3627787, + "lineNumber": 50967, + "beginOffset": 3627838, + "headersEndOffset": 3628410, + "endOffset": 3688111, + "body": { + "mimeType": "message/partial", + "lineNumber": 50967, + "beginOffset": 3627838, + "headersEndOffset": 3628410, + "endOffset": 3688111, + "octets": 59701, + "lines": 954 + }, + "octets": 59701 + }, + { + "mboxMarkerOffset": 3688112, + "lineNumber": 51938, + "beginOffset": 3688163, + "headersEndOffset": 3688732, + "endOffset": 3748539, + "body": { + "mimeType": "message/partial", + "lineNumber": 51938, + "beginOffset": 3688163, + "headersEndOffset": 3688732, + "endOffset": 3748539, + "octets": 59807, + "lines": 960 + }, + "octets": 59807 + }, + { + "mboxMarkerOffset": 3748540, + "lineNumber": 52915, + "beginOffset": 3748548, + "headersEndOffset": 3749096, + "endOffset": 3749967, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 52915, + "beginOffset": 3748548, + "headersEndOffset": 3749096, + "endOffset": 3749967, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 52930, + "beginOffset": 3749112, + "headersEndOffset": 3749139, + "endOffset": 3749210, + "octets": 71, + "lines": 4 + }, + { + "mimeType": "text/plain", + "lineNumber": 52938, + "beginOffset": 3749226, + "headersEndOffset": 3749307, + "endOffset": 3749948, + "octets": 641, + "lines": 9 + } + ], + "octets": 871, + "lines": 25 + }, + "octets": 871 + }, + { + "mboxMarkerOffset": 3749968, + "lineNumber": 52955, + "beginOffset": 3749976, + "headersEndOffset": 3750723, + "endOffset": 3792253, + "body": { + "mimeType": "image/gif", + "lineNumber": 52955, + "beginOffset": 3749976, + "headersEndOffset": 3750723, + "endOffset": 3792253, + "octets": 41530, + "lines": 570 + }, + "octets": 41530 + }, + { + "mboxMarkerOffset": 3792254, + "lineNumber": 53545, + "beginOffset": 3792262, + "headersEndOffset": 3793416, + "endOffset": 3801685, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 53545, + "beginOffset": 3792262, + "headersEndOffset": 3793416, + "endOffset": 3801685, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 53571, + "beginOffset": 3793421, + "headersEndOffset": 3793422, + "endOffset": 3795344, + "octets": 1922, + "lines": 43 + }, + { + "mimeType": "image/gif", + "lineNumber": 53617, + "beginOffset": 3795350, + "headersEndOffset": 3795455, + "endOffset": 3801677, + "octets": 6222, + "lines": 86 + } + ], + "octets": 8269, + "lines": 139 + }, + "octets": 8269 + }, + { + "mboxMarkerOffset": 3801686, + "lineNumber": 53711, + "beginOffset": 3801694, + "headersEndOffset": 3803142, + "endOffset": 3909955, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 53711, + "beginOffset": 3801694, + "headersEndOffset": 3803142, + "endOffset": 3909955, + "octets": 106813, + "lines": 1570 + }, + "octets": 106813 + }, + { + "mboxMarkerOffset": 3909956, + "lineNumber": 55311, + "beginOffset": 3909964, + "headersEndOffset": 3910563, + "endOffset": 3913880, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55311, + "beginOffset": 3909964, + "headersEndOffset": 3910563, + "endOffset": 3913880, + "message": { + "lineNumber": 55327, + "beginOffset": 3910563, + "headersEndOffset": 3911133, + "endOffset": 3913880, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55327, + "beginOffset": 3910563, + "headersEndOffset": 3911133, + "endOffset": 3913880, + "message": { + "lineNumber": 55343, + "beginOffset": 3911133, + "headersEndOffset": 3911675, + "endOffset": 3913880, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 55343, + "beginOffset": 3911133, + "headersEndOffset": 3911675, + "endOffset": 3913880, + "message": { + "lineNumber": 55359, + "beginOffset": 3911675, + "headersEndOffset": 3912223, + "endOffset": 3913880, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55359, + "beginOffset": 3911675, + "headersEndOffset": 3912223, + "endOffset": 3913880, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55378, + "beginOffset": 3912327, + "headersEndOffset": 3912403, + "endOffset": 3912452, + "octets": 49, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 55384, + "beginOffset": 3912511, + "headersEndOffset": 3912573, + "endOffset": 3913817, + "message": { + "lineNumber": 55387, + "beginOffset": 3912573, + "headersEndOffset": 3913073, + "endOffset": 3913817, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55387, + "beginOffset": 3912573, + "headersEndOffset": 3913073, + "endOffset": 3913817, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55406, + "beginOffset": 3913167, + "headersEndOffset": 3913243, + "endOffset": 3913365, + "octets": 122, + "lines": 5 + }, + { + "mimeType": "text/html", + "lineNumber": 55416, + "beginOffset": 3913414, + "headersEndOffset": 3913483, + "endOffset": 3913766, + "octets": 283, + "lines": 5 + } + ], + "octets": 744, + "lines": 22 + }, + "octets": 744 + }, + "octets": 1244, + "lines": 38 + } + ], + "octets": 1657, + "lines": 54 + }, + "octets": 1657 + }, + "octets": 2205, + "lines": 70 + }, + "octets": 2205 + }, + "octets": 2747, + "lines": 86 + }, + "octets": 2747 + }, + "octets": 3317, + "lines": 102 + }, + "octets": 3317 + }, + { + "mboxMarkerOffset": 3913881, + "lineNumber": 55431, + "beginOffset": 3913889, + "headersEndOffset": 3914592, + "endOffset": 4176062, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 55431, + "beginOffset": 3913889, + "headersEndOffset": 3914592, + "endOffset": 4176062, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 55448, + "beginOffset": 3914619, + "headersEndOffset": 3914620, + "endOffset": 3914661, + "octets": 41, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 55452, + "beginOffset": 3914689, + "headersEndOffset": 3914834, + "endOffset": 3992050, + "octets": 77216, + "lines": 401 + }, + { + "mimeType": "text/plain", + "lineNumber": 55859, + "beginOffset": 3992078, + "headersEndOffset": 3992079, + "endOffset": 3992110, + "octets": 31, + "lines": 3 + }, + { + "mimeType": "audio/basic", + "lineNumber": 55865, + "beginOffset": 3992138, + "headersEndOffset": 3992285, + "endOffset": 4095487, + "octets": 103202, + "lines": 535 + }, + { + "mimeType": "text/plain", + "lineNumber": 56406, + "beginOffset": 4095515, + "headersEndOffset": 4095516, + "endOffset": 4095676, + "octets": 160, + "lines": 5 + }, + { + "mimeType": "application/x-annotate", + "lineNumber": 56413, + "beginOffset": 4095704, + "headersEndOffset": 4095793, + "endOffset": 4175983, + "octets": 80190, + "lines": 1235 + }, + { + "mimeType": "text/plain", + "lineNumber": 57652, + "beginOffset": 4176011, + "headersEndOffset": 4176012, + "endOffset": 4176032, + "octets": 20, + "lines": 3 + } + ], + "octets": 261470, + "lines": 2210 + }, + "octets": 261470 + }, + { + "mboxMarkerOffset": 4176063, + "lineNumber": 57659, + "beginOffset": 4176071, + "headersEndOffset": 4176736, + "endOffset": 4177728, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 57659, + "beginOffset": 4176071, + "headersEndOffset": 4176736, + "endOffset": 4177728, + "octets": 992, + "lines": 18 + }, + "octets": 992 + }, + { + "mboxMarkerOffset": 4177729, + "lineNumber": 57693, + "beginOffset": 4177737, + "headersEndOffset": 4178793, + "endOffset": 4181836, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 57693, + "beginOffset": 4177737, + "headersEndOffset": 4178793, + "endOffset": 4181836, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 57720, + "beginOffset": 4178988, + "headersEndOffset": 4179032, + "endOffset": 4179436, + "octets": 404, + "lines": 13 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 57737, + "beginOffset": 4179477, + "headersEndOffset": 4179562, + "endOffset": 4181793, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 57741, + "beginOffset": 4179604, + "headersEndOffset": 4179695, + "endOffset": 4179920, + "octets": 225, + "lines": 4 + }, + { + "mimeType": "image/x-xbm", + "lineNumber": 57750, + "beginOffset": 4179963, + "headersEndOffset": 4180082, + "endOffset": 4181466, + "octets": 1384, + "lines": 37 + }, + { + "mimeType": "text/richtext", + "lineNumber": 57793, + "beginOffset": 4181509, + "headersEndOffset": 4181600, + "endOffset": 4181748, + "octets": 148, + "lines": 9 + } + ], + "octets": 2231, + "lines": 67 + } + ], + "octets": 3043, + "lines": 93 + }, + "octets": 3043 + }, + { + "mboxMarkerOffset": 4181837, + "lineNumber": 57811, + "beginOffset": 4181845, + "headersEndOffset": 4182515, + "endOffset": 4187896, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 57811, + "beginOffset": 4181845, + "headersEndOffset": 4182515, + "endOffset": 4187896, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 57828, + "beginOffset": 4182531, + "headersEndOffset": 4182558, + "endOffset": 4182636, + "octets": 78, + "lines": 6 + }, + { + "mimeType": "image/gif", + "lineNumber": 57838, + "beginOffset": 4182653, + "headersEndOffset": 4182713, + "endOffset": 4187876, + "octets": 5163, + "lines": 71 + } + ], + "octets": 5381, + "lines": 88 + }, + "octets": 5381 + }, + { + "mboxMarkerOffset": 4187897, + "lineNumber": 57917, + "beginOffset": 4187905, + "headersEndOffset": 4188357, + "endOffset": 4199771, + "body": { + "mimeType": "Image/JPEG", + "lineNumber": 57917, + "beginOffset": 4187905, + "headersEndOffset": 4188357, + "endOffset": 4199771, + "octets": 11414, + "lines": 185 + }, + "octets": 11414 + }, + { + "mboxMarkerOffset": 4199772, + "lineNumber": 58118, + "beginOffset": 4199780, + "headersEndOffset": 4200345, + "endOffset": 4201646, + "body": { + "mimeType": "Multipart/Mixed", + "lineNumber": 58118, + "beginOffset": 4199780, + "headersEndOffset": 4200345, + "endOffset": 4201646, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 58134, + "beginOffset": 4200356, + "headersEndOffset": 4200357, + "endOffset": 4200395, + "octets": 38, + "lines": 1 + }, + { + "mimeType": "Multipart/MIXED", + "lineNumber": 58138, + "beginOffset": 4200407, + "headersEndOffset": 4200462, + "endOffset": 4201632, + "children": [ + { + "mimeType": "Message/External-body", + "lineNumber": 58141, + "beginOffset": 4200476, + "headersEndOffset": 4200592, + "endOffset": 4200736, + "message": { + "lineNumber": 58145, + "beginOffset": 4200592, + "headersEndOffset": 4200669, + "endOffset": 4200736, + "body": { + "mimeType": "text/plain", + "lineNumber": 58145, + "beginOffset": 4200592, + "headersEndOffset": 4200669, + "endOffset": 4200736, + "octets": 67, + "lines": 2 + }, + "octets": 67 + }, + "octets": 144, + "lines": 5 + }, + { + "mimeType": "Message/External-body", + "lineNumber": 58152, + "beginOffset": 4200751, + "headersEndOffset": 4200938, + "endOffset": 4201014, + "message": { + "lineNumber": 58158, + "beginOffset": 4200938, + "headersEndOffset": 4201014, + "endOffset": 4201014, + "body": { + "mimeType": "text/plain", + "lineNumber": 58158, + "beginOffset": 4200938, + "headersEndOffset": 4201014, + "endOffset": 4201014, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 76, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58162, + "beginOffset": 4201029, + "headersEndOffset": 4201164, + "endOffset": 4201231, + "message": { + "lineNumber": 58169, + "beginOffset": 4201164, + "headersEndOffset": 4201231, + "endOffset": 4201231, + "body": { + "mimeType": "TEXT/HTML", + "lineNumber": 58169, + "beginOffset": 4201164, + "headersEndOffset": 4201231, + "endOffset": 4201231, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 67, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58173, + "beginOffset": 4201246, + "headersEndOffset": 4201359, + "endOffset": 4201427, + "message": { + "lineNumber": 58177, + "beginOffset": 4201359, + "headersEndOffset": 4201427, + "endOffset": 4201427, + "body": { + "mimeType": "image/gif", + "lineNumber": 58177, + "beginOffset": 4201359, + "headersEndOffset": 4201427, + "endOffset": 4201427, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 68, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 58181, + "beginOffset": 4201442, + "headersEndOffset": 4201547, + "endOffset": 4201615, + "message": { + "lineNumber": 58185, + "beginOffset": 4201547, + "headersEndOffset": 4201615, + "endOffset": 4201615, + "body": { + "mimeType": "image/gif", + "lineNumber": 58185, + "beginOffset": 4201547, + "headersEndOffset": 4201615, + "endOffset": 4201615, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 68, + "lines": 2 + } + ], + "octets": 1170, + "lines": 49 + } + ], + "octets": 1301, + "lines": 58 + }, + "octets": 1301 + }, + { + "mboxMarkerOffset": 4201647, + "lineNumber": 58193, + "beginOffset": 4201655, + "headersEndOffset": 4202220, + "endOffset": 4206092, + "body": { + "mimeType": "Multipart/Mixed", + "lineNumber": 58193, + "beginOffset": 4201655, + "headersEndOffset": 4202220, + "endOffset": 4206092, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 58209, + "beginOffset": 4202231, + "headersEndOffset": 4202232, + "endOffset": 4205436, + "octets": 3204, + "lines": 65 + }, + { + "mimeType": "Multipart/Alternative", + "lineNumber": 58277, + "beginOffset": 4205448, + "headersEndOffset": 4205509, + "endOffset": 4206078, + "children": [ + { + "mimeType": "Message/External-body", + "lineNumber": 58280, + "beginOffset": 4205523, + "headersEndOffset": 4205639, + "endOffset": 4205783, + "message": { + "lineNumber": 58284, + "beginOffset": 4205639, + "headersEndOffset": 4205716, + "endOffset": 4205783, + "body": { + "mimeType": "text/plain", + "lineNumber": 58284, + "beginOffset": 4205639, + "headersEndOffset": 4205716, + "endOffset": 4205783, + "octets": 67, + "lines": 2 + }, + "octets": 67 + }, + "octets": 144, + "lines": 5 + }, + { + "mimeType": "Message/External-body", + "lineNumber": 58291, + "beginOffset": 4205798, + "headersEndOffset": 4205985, + "endOffset": 4206061, + "message": { + "lineNumber": 58297, + "beginOffset": 4205985, + "headersEndOffset": 4206061, + "endOffset": 4206061, + "body": { + "mimeType": "text/plain", + "lineNumber": 58297, + "beginOffset": 4205985, + "headersEndOffset": 4206061, + "endOffset": 4206061, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 76, + "lines": 2 + } + ], + "octets": 569, + "lines": 22 + } + ], + "octets": 3872, + "lines": 95 + }, + "octets": 3872 + }, + { + "mboxMarkerOffset": 4206093, + "lineNumber": 58305, + "beginOffset": 4206101, + "headersEndOffset": 4206569, + "endOffset": 4212326, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58305, + "beginOffset": 4206101, + "headersEndOffset": 4206569, + "endOffset": 4212326, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 58320, + "beginOffset": 4206642, + "headersEndOffset": 4206786, + "endOffset": 4207252, + "message": { + "lineNumber": 58325, + "beginOffset": 4206786, + "headersEndOffset": 4207215, + "endOffset": 4207252, + "body": { + "mimeType": "text/plain", + "lineNumber": 58325, + "beginOffset": 4206786, + "headersEndOffset": 4207215, + "endOffset": 4207252, + "octets": 37, + "lines": 2 + }, + "octets": 37 + }, + "octets": 466, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 58340, + "beginOffset": 4207280, + "headersEndOffset": 4207403, + "endOffset": 4207861, + "octets": 458, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58352, + "beginOffset": 4207889, + "headersEndOffset": 4208012, + "endOffset": 4208498, + "octets": 486, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58364, + "beginOffset": 4208526, + "headersEndOffset": 4208653, + "endOffset": 4209180, + "octets": 527, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 58377, + "beginOffset": 4209208, + "headersEndOffset": 4209333, + "endOffset": 4209831, + "octets": 498, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58389, + "beginOffset": 4209859, + "headersEndOffset": 4210003, + "endOffset": 4210469, + "message": { + "lineNumber": 58394, + "beginOffset": 4210003, + "headersEndOffset": 4210432, + "endOffset": 4210469, + "body": { + "mimeType": "text/plain", + "lineNumber": 58394, + "beginOffset": 4210003, + "headersEndOffset": 4210432, + "endOffset": 4210469, + "octets": 37, + "lines": 1 + }, + "octets": 37 + }, + "octets": 466, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58408, + "beginOffset": 4210497, + "headersEndOffset": 4210668, + "endOffset": 4212164, + "message": { + "lineNumber": 58413, + "beginOffset": 4210668, + "headersEndOffset": 4211238, + "endOffset": 4212164, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58413, + "beginOffset": 4210668, + "headersEndOffset": 4211238, + "endOffset": 4212164, + "message": { + "lineNumber": 58428, + "beginOffset": 4211238, + "headersEndOffset": 4211749, + "endOffset": 4212164, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58428, + "beginOffset": 4211238, + "headersEndOffset": 4211749, + "endOffset": 4212164, + "message": { + "lineNumber": 58442, + "beginOffset": 4211749, + "headersEndOffset": 4212159, + "endOffset": 4212164, + "body": { + "mimeType": "text/plain", + "lineNumber": 58442, + "beginOffset": 4211749, + "headersEndOffset": 4212159, + "endOffset": 4212164, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 415, + "lines": 12 + }, + "octets": 415 + }, + "octets": 926, + "lines": 26 + }, + "octets": 926 + }, + "octets": 1496, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 58456, + "beginOffset": 4212192, + "headersEndOffset": 4212245, + "endOffset": 4212297, + "octets": 52, + "lines": 1 + } + ], + "octets": 5757, + "lines": 145 + }, + "octets": 5757 + }, + { + "mboxMarkerOffset": 4212327, + "lineNumber": 58463, + "beginOffset": 4212335, + "headersEndOffset": 4212806, + "endOffset": 4218598, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58463, + "beginOffset": 4212335, + "headersEndOffset": 4212806, + "endOffset": 4218598, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 58478, + "beginOffset": 4212879, + "headersEndOffset": 4213027, + "endOffset": 4213492, + "message": { + "lineNumber": 58483, + "beginOffset": 4213027, + "headersEndOffset": 4213455, + "endOffset": 4213492, + "body": { + "mimeType": "text/plain", + "lineNumber": 58483, + "beginOffset": 4213027, + "headersEndOffset": 4213455, + "endOffset": 4213492, + "octets": 37, + "lines": 2 + }, + "octets": 37 + }, + "octets": 465, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 58498, + "beginOffset": 4213520, + "headersEndOffset": 4213647, + "endOffset": 4214105, + "octets": 458, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58510, + "beginOffset": 4214133, + "headersEndOffset": 4214260, + "endOffset": 4214746, + "octets": 486, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 58522, + "beginOffset": 4214774, + "headersEndOffset": 4214905, + "endOffset": 4215432, + "octets": 527, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 58535, + "beginOffset": 4215460, + "headersEndOffset": 4215589, + "endOffset": 4216087, + "octets": 498, + "lines": 7 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58547, + "beginOffset": 4216115, + "headersEndOffset": 4216263, + "endOffset": 4216728, + "message": { + "lineNumber": 58552, + "beginOffset": 4216263, + "headersEndOffset": 4216691, + "endOffset": 4216728, + "body": { + "mimeType": "text/plain", + "lineNumber": 58552, + "beginOffset": 4216263, + "headersEndOffset": 4216691, + "endOffset": 4216728, + "octets": 37, + "lines": 1 + }, + "octets": 37 + }, + "octets": 465, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58566, + "beginOffset": 4216756, + "headersEndOffset": 4216931, + "endOffset": 4218432, + "message": { + "lineNumber": 58571, + "beginOffset": 4216931, + "headersEndOffset": 4217504, + "endOffset": 4218432, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58571, + "beginOffset": 4216931, + "headersEndOffset": 4217504, + "endOffset": 4218432, + "message": { + "lineNumber": 58586, + "beginOffset": 4217504, + "headersEndOffset": 4218018, + "endOffset": 4218432, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 58586, + "beginOffset": 4217504, + "headersEndOffset": 4218018, + "endOffset": 4218432, + "message": { + "lineNumber": 58600, + "beginOffset": 4218018, + "headersEndOffset": 4218427, + "endOffset": 4218432, + "body": { + "mimeType": "text/plain", + "lineNumber": 58600, + "beginOffset": 4218018, + "headersEndOffset": 4218427, + "endOffset": 4218432, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 414, + "lines": 12 + }, + "octets": 414 + }, + "octets": 928, + "lines": 26 + }, + "octets": 928 + }, + "octets": 1501, + "lines": 41 + }, + { + "mimeType": "text/html", + "lineNumber": 58614, + "beginOffset": 4218460, + "headersEndOffset": 4218517, + "endOffset": 4218569, + "octets": 52, + "lines": 1 + } + ], + "octets": 5792, + "lines": 145 + }, + "octets": 5792 + }, + { + "mboxMarkerOffset": 4218599, + "lineNumber": 58621, + "beginOffset": 4218607, + "headersEndOffset": 4219294, + "endOffset": 4239312, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58621, + "beginOffset": 4218607, + "headersEndOffset": 4219294, + "endOffset": 4239312, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 58641, + "beginOffset": 4219341, + "headersEndOffset": 4219370, + "endOffset": 4219786, + "octets": 416, + "lines": 30 + }, + { + "mimeType": "text/enriched", + "lineNumber": 58675, + "beginOffset": 4219793, + "headersEndOffset": 4219866, + "endOffset": 4220497, + "octets": 631, + "lines": 42 + }, + { + "mimeType": "text/plain", + "lineNumber": 58722, + "beginOffset": 4220504, + "headersEndOffset": 4220505, + "endOffset": 4220523, + "octets": 18, + "lines": 1 + }, + { + "mimeType": "text/plain", + "lineNumber": 58725, + "beginOffset": 4220530, + "headersEndOffset": 4220531, + "endOffset": 4220542, + "octets": 11, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 58728, + "beginOffset": 4220549, + "headersEndOffset": 4220579, + "endOffset": 4221076, + "message": { + "lineNumber": 58730, + "beginOffset": 4220579, + "headersEndOffset": 4220794, + "endOffset": 4221076, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 58730, + "beginOffset": 4220579, + "headersEndOffset": 4220794, + "endOffset": 4221076, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 58738, + "beginOffset": 4220800, + "headersEndOffset": 4220825, + "endOffset": 4220848, + "octets": 23, + "lines": 1 + }, + { + "mimeType": "image/unknown", + "lineNumber": 58742, + "beginOffset": 4220855, + "headersEndOffset": 4221030, + "endOffset": 4221068, + "octets": 38, + "lines": 1 + } + ], + "octets": 282, + "lines": 13 + }, + "octets": 282 + }, + "octets": 497, + "lines": 20 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 58751, + "beginOffset": 4221083, + "headersEndOffset": 4221161, + "endOffset": 4230592, + "octets": 9431, + "lines": 128 + }, + { + "mimeType": "image/unknown", + "lineNumber": 58883, + "beginOffset": 4230599, + "headersEndOffset": 4230774, + "endOffset": 4230812, + "octets": 38, + "lines": 1 + }, + { + "mimeType": "image/x-xbitmap", + "lineNumber": 58891, + "beginOffset": 4230819, + "headersEndOffset": 4230967, + "endOffset": 4238788, + "octets": 7821, + "lines": 128 + }, + { + "mimeType": "multipart/digest", + "lineNumber": 59024, + "beginOffset": 4238795, + "headersEndOffset": 4238847, + "endOffset": 4239263, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 59027, + "beginOffset": 4238857, + "headersEndOffset": 4238858, + "endOffset": 4238889, + "message": { + "lineNumber": 59028, + "beginOffset": 4238858, + "headersEndOffset": 4238884, + "endOffset": 4238889, + "body": { + "mimeType": "text/plain", + "lineNumber": 59028, + "beginOffset": 4238858, + "headersEndOffset": 4238884, + "endOffset": 4238889, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 31, + "lines": 4 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59033, + "beginOffset": 4238900, + "headersEndOffset": 4238901, + "endOffset": 4238932, + "message": { + "lineNumber": 59034, + "beginOffset": 4238901, + "headersEndOffset": 4238927, + "endOffset": 4238932, + "body": { + "mimeType": "text/plain", + "lineNumber": 59034, + "beginOffset": 4238901, + "headersEndOffset": 4238927, + "endOffset": 4238932, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 31, + "lines": 4 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59039, + "beginOffset": 4238943, + "headersEndOffset": 4238944, + "endOffset": 4238975, + "message": { + "lineNumber": 59040, + "beginOffset": 4238944, + "headersEndOffset": 4238970, + "endOffset": 4238975, + "body": { + "mimeType": "text/plain", + "lineNumber": 59040, + "beginOffset": 4238944, + "headersEndOffset": 4238970, + "endOffset": 4238975, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 31, + "lines": 4 + }, + { + "mimeType": "text/html", + "lineNumber": 59045, + "beginOffset": 4238986, + "headersEndOffset": 4239011, + "endOffset": 4239093, + "octets": 82, + "lines": 2 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59050, + "beginOffset": 4239104, + "headersEndOffset": 4239105, + "endOffset": 4239208, + "message": { + "lineNumber": 59051, + "beginOffset": 4239105, + "headersEndOffset": 4239159, + "endOffset": 4239208, + "body": { + "mimeType": "text/richtext", + "lineNumber": 59051, + "beginOffset": 4239105, + "headersEndOffset": 4239159, + "endOffset": 4239208, + "octets": 49, + "lines": 1 + }, + "octets": 49 + }, + "octets": 103, + "lines": 5 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 59057, + "beginOffset": 4239219, + "headersEndOffset": 4239220, + "endOffset": 4239251, + "message": { + "lineNumber": 59058, + "beginOffset": 4239220, + "headersEndOffset": 4239246, + "endOffset": 4239251, + "body": { + "mimeType": "text/plain", + "lineNumber": 59058, + "beginOffset": 4239220, + "headersEndOffset": 4239246, + "endOffset": 4239251, + "octets": 5, + "lines": 1 + }, + "octets": 5 + }, + "octets": 31, + "lines": 4 + } + ], + "octets": 416, + "lines": 37 + } + ], + "octets": 20018, + "lines": 428 + }, + "octets": 20018 + }, + { + "mboxMarkerOffset": 4239313, + "lineNumber": 59067, + "beginOffset": 4239321, + "headersEndOffset": 4239982, + "endOffset": 4312775, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 59067, + "beginOffset": 4239321, + "headersEndOffset": 4239982, + "endOffset": 4312775, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 59083, + "beginOffset": 4240008, + "headersEndOffset": 4240009, + "endOffset": 4241229, + "octets": 1220, + "lines": 27 + }, + { + "mimeType": "image/pbm", + "lineNumber": 59112, + "beginOffset": 4241256, + "headersEndOffset": 4241401, + "endOffset": 4312718, + "octets": 71317, + "lines": 370 + }, + { + "mimeType": "text/plain", + "lineNumber": 59488, + "beginOffset": 4312745, + "headersEndOffset": 4312746, + "endOffset": 4312746, + "octets": 0, + "lines": 0 + } + ], + "octets": 72793, + "lines": 409 + }, + "octets": 72793 + }, + { + "mboxMarkerOffset": 4312776, + "lineNumber": 59493, + "beginOffset": 4312784, + "headersEndOffset": 4313717, + "endOffset": 4562758, + "body": { + "mimeType": "message/partial", + "lineNumber": 59493, + "beginOffset": 4312784, + "headersEndOffset": 4313717, + "endOffset": 4562758, + "octets": 249041, + "lines": 3430 + }, + "octets": 249041 + }, + { + "mboxMarkerOffset": 4562759, + "lineNumber": 62945, + "beginOffset": 4562767, + "headersEndOffset": 4563695, + "endOffset": 4618504, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 62945, + "beginOffset": 4562767, + "headersEndOffset": 4563695, + "endOffset": 4618504, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 62971, + "beginOffset": 4563935, + "headersEndOffset": 4564008, + "endOffset": 4564472, + "octets": 464, + "lines": 9 + }, + { + "mimeType": "image/gif", + "lineNumber": 62985, + "beginOffset": 4564518, + "headersEndOffset": 4564577, + "endOffset": 4588813, + "octets": 24236, + "lines": 332 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63322, + "beginOffset": 4588859, + "headersEndOffset": 4588932, + "endOffset": 4589380, + "octets": 448, + "lines": 10 + }, + { + "mimeType": "image/gif", + "lineNumber": 63337, + "beginOffset": 4589426, + "headersEndOffset": 4589485, + "endOffset": 4600699, + "octets": 11214, + "lines": 154 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63496, + "beginOffset": 4600745, + "headersEndOffset": 4600818, + "endOffset": 4601122, + "octets": 304, + "lines": 6 + }, + { + "mimeType": "image/gif", + "lineNumber": 63507, + "beginOffset": 4601168, + "headersEndOffset": 4601227, + "endOffset": 4617677, + "octets": 16450, + "lines": 226 + }, + { + "mimeType": "text/richtext", + "lineNumber": 63738, + "beginOffset": 4617723, + "headersEndOffset": 4617796, + "endOffset": 4618456, + "octets": 660, + "lines": 15 + } + ], + "octets": 54809, + "lines": 792 + }, + "octets": 54809 + }, + { + "mboxMarkerOffset": 4618505, + "lineNumber": 63760, + "beginOffset": 4618513, + "headersEndOffset": 4619332, + "endOffset": 4666587, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 63760, + "beginOffset": 4618513, + "headersEndOffset": 4619332, + "endOffset": 4666587, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 63777, + "beginOffset": 4619361, + "headersEndOffset": 4619362, + "endOffset": 4620012, + "octets": 650, + "lines": 18 + }, + { + "mimeType": "Image/JPEG", + "lineNumber": 63798, + "beginOffset": 4620042, + "headersEndOffset": 4620102, + "endOffset": 4666555, + "octets": 46453, + "lines": 762 + } + ], + "octets": 47255, + "lines": 788 + }, + "octets": 47255 + }, + { + "mboxMarkerOffset": 4666588, + "lineNumber": 64566, + "beginOffset": 4666596, + "headersEndOffset": 4667343, + "endOffset": 4702358, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 64566, + "beginOffset": 4666596, + "headersEndOffset": 4667343, + "endOffset": 4702358, + "children": [ + { + "mimeType": "text/enriched", + "lineNumber": 64588, + "beginOffset": 4667800, + "headersEndOffset": 4667873, + "endOffset": 4673188, + "octets": 5315, + "lines": 160 + }, + { + "mimeType": "image/gif", + "lineNumber": 64753, + "beginOffset": 4673212, + "headersEndOffset": 4673309, + "endOffset": 4675889, + "octets": 2580, + "lines": 36 + }, + { + "mimeType": "text/enriched", + "lineNumber": 64795, + "beginOffset": 4675913, + "headersEndOffset": 4675986, + "endOffset": 4676504, + "octets": 518, + "lines": 10 + }, + { + "mimeType": "audio/basic", + "lineNumber": 64810, + "beginOffset": 4676528, + "headersEndOffset": 4676642, + "endOffset": 4699702, + "octets": 23060, + "lines": 316 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65132, + "beginOffset": 4699726, + "headersEndOffset": 4699799, + "endOffset": 4700377, + "octets": 578, + "lines": 14 + }, + { + "mimeType": "message/external-body", + "lineNumber": 65151, + "beginOffset": 4700401, + "headersEndOffset": 4700486, + "endOffset": 4700555, + "message": { + "lineNumber": 65155, + "beginOffset": 4700486, + "headersEndOffset": 4700555, + "endOffset": 4700555, + "body": { + "mimeType": "text/plain", + "lineNumber": 65155, + "beginOffset": 4700486, + "headersEndOffset": 4700555, + "endOffset": 4700555, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 69, + "lines": 2 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65159, + "beginOffset": 4700579, + "headersEndOffset": 4700652, + "endOffset": 4700928, + "octets": 276, + "lines": 5 + }, + { + "mimeType": "message/external-body", + "lineNumber": 65169, + "beginOffset": 4700952, + "headersEndOffset": 4701098, + "endOffset": 4701167, + "message": { + "lineNumber": 65176, + "beginOffset": 4701098, + "headersEndOffset": 4701167, + "endOffset": 4701167, + "body": { + "mimeType": "text/plain", + "lineNumber": 65176, + "beginOffset": 4701098, + "headersEndOffset": 4701167, + "endOffset": 4701167, + "octets": 0, + "lines": 0 + }, + "octets": 0 + }, + "octets": 69, + "lines": 2 + }, + { + "mimeType": "text/enriched", + "lineNumber": 65180, + "beginOffset": 4701191, + "headersEndOffset": 4701264, + "endOffset": 4702333, + "octets": 1069, + "lines": 34 + } + ], + "octets": 35015, + "lines": 639 + }, + "octets": 35015 + }, + { + "mboxMarkerOffset": 4702359, + "lineNumber": 65220, + "beginOffset": 4702367, + "headersEndOffset": 4702528, + "endOffset": 4779011, + "body": { + "mimeType": "Multipart/mixed", + "lineNumber": 65220, + "beginOffset": 4702367, + "headersEndOffset": 4702528, + "endOffset": 4779011, + "children": [ + { + "mimeType": "image/gif", + "lineNumber": 65227, + "beginOffset": 4702540, + "headersEndOffset": 4702609, + "endOffset": 4778953, + "octets": 76344, + "lines": 1145 + }, + { + "mimeType": "text/plain", + "lineNumber": 66377, + "beginOffset": 4778966, + "headersEndOffset": 4778967, + "endOffset": 4778997, + "octets": 30, + "lines": 1 + } + ], + "octets": 76483, + "lines": 1154 + }, + "octets": 76483 + }, + { + "mboxMarkerOffset": 4779012, + "lineNumber": 66381, + "beginOffset": 4779020, + "headersEndOffset": 4780235, + "endOffset": 4908685, + "body": { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 66381, + "beginOffset": 4779020, + "headersEndOffset": 4780235, + "endOffset": 4908685, + "children": [ + { + "mimeType": "TEXT/plain", + "lineNumber": 66405, + "beginOffset": 4780273, + "headersEndOffset": 4780317, + "endOffset": 4780769, + "octets": 452, + "lines": 8 + }, + { + "mimeType": "AUDIO/basic", + "lineNumber": 66417, + "beginOffset": 4780808, + "headersEndOffset": 4780901, + "endOffset": 4908644, + "octets": 127743, + "lines": 2095 + } + ], + "octets": 128450, + "lines": 2114 + }, + "octets": 128450 + }, + { + "mboxMarkerOffset": 4908686, + "lineNumber": 68520, + "beginOffset": 4908694, + "headersEndOffset": 4909446, + "endOffset": 5083311, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 68520, + "beginOffset": 4908694, + "headersEndOffset": 4909446, + "endOffset": 5083311, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 68544, + "beginOffset": 4909843, + "headersEndOffset": 4909844, + "endOffset": 4910639, + "octets": 795, + "lines": 18 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 68565, + "beginOffset": 4910698, + "headersEndOffset": 4910801, + "endOffset": 5083251, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 68569, + "beginOffset": 4910861, + "headersEndOffset": 4910934, + "endOffset": 4911423, + "octets": 489, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 68581, + "beginOffset": 4911484, + "headersEndOffset": 4911580, + "endOffset": 4924570, + "octets": 12990, + "lines": 190 + }, + { + "mimeType": "text/plain", + "lineNumber": 68777, + "beginOffset": 4924631, + "headersEndOffset": 4924701, + "endOffset": 4924721, + "octets": 20, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 68783, + "beginOffset": 4924782, + "headersEndOffset": 4924878, + "endOffset": 4980598, + "octets": 55720, + "lines": 764 + }, + { + "mimeType": "text/plain", + "lineNumber": 69553, + "beginOffset": 4980659, + "headersEndOffset": 4980729, + "endOffset": 4980781, + "octets": 52, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 69563, + "beginOffset": 4980842, + "headersEndOffset": 4980903, + "endOffset": 5083055, + "octets": 102152, + "lines": 1400 + }, + { + "mimeType": "text/plain", + "lineNumber": 70968, + "beginOffset": 5083116, + "headersEndOffset": 5083186, + "endOffset": 5083188, + "octets": 2, + "lines": 2 + } + ], + "octets": 172450, + "lines": 2407 + } + ], + "octets": 173865, + "lines": 2440 + }, + "octets": 173865 + }, + { + "mboxMarkerOffset": 5083312, + "lineNumber": 70978, + "beginOffset": 5083320, + "headersEndOffset": 5084006, + "endOffset": 5299088, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 70978, + "beginOffset": 5083320, + "headersEndOffset": 5084006, + "endOffset": 5299088, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 70998, + "beginOffset": 5084201, + "headersEndOffset": 5084245, + "endOffset": 5085760, + "octets": 1515, + "lines": 29 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 71031, + "beginOffset": 5085801, + "headersEndOffset": 5085886, + "endOffset": 5299046, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 71035, + "beginOffset": 5085928, + "headersEndOffset": 5086019, + "endOffset": 5086926, + "octets": 907, + "lines": 13 + }, + { + "mimeType": "image/gif", + "lineNumber": 71053, + "beginOffset": 5086969, + "headersEndOffset": 5087060, + "endOffset": 5121918, + "octets": 34858, + "lines": 506 + }, + { + "mimeType": "text/richtext", + "lineNumber": 71565, + "beginOffset": 5121961, + "headersEndOffset": 5122052, + "endOffset": 5122062, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 71572, + "beginOffset": 5122105, + "headersEndOffset": 5122196, + "endOffset": 5143530, + "octets": 21334, + "lines": 310 + }, + { + "mimeType": "text/richtext", + "lineNumber": 71888, + "beginOffset": 5143573, + "headersEndOffset": 5143664, + "endOffset": 5143674, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 71895, + "beginOffset": 5143717, + "headersEndOffset": 5143808, + "endOffset": 5176251, + "octets": 32443, + "lines": 471 + }, + { + "mimeType": "text/richtext", + "lineNumber": 72372, + "beginOffset": 5176294, + "headersEndOffset": 5176385, + "endOffset": 5176395, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 72379, + "beginOffset": 5176438, + "headersEndOffset": 5176529, + "endOffset": 5209970, + "octets": 33441, + "lines": 485 + }, + { + "mimeType": "text/richtext", + "lineNumber": 72870, + "beginOffset": 5210013, + "headersEndOffset": 5210104, + "endOffset": 5210114, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 72877, + "beginOffset": 5210157, + "headersEndOffset": 5210248, + "endOffset": 5238084, + "octets": 27836, + "lines": 404 + }, + { + "mimeType": "text/richtext", + "lineNumber": 73287, + "beginOffset": 5238127, + "headersEndOffset": 5238218, + "endOffset": 5238228, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 73294, + "beginOffset": 5238271, + "headersEndOffset": 5238362, + "endOffset": 5271856, + "octets": 33494, + "lines": 486 + }, + { + "mimeType": "text/richtext", + "lineNumber": 73786, + "beginOffset": 5271899, + "headersEndOffset": 5271990, + "endOffset": 5272000, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 73793, + "beginOffset": 5272043, + "headersEndOffset": 5272134, + "endOffset": 5298793, + "octets": 26659, + "lines": 387 + }, + { + "mimeType": "text/richtext", + "lineNumber": 74186, + "beginOffset": 5298836, + "headersEndOffset": 5298927, + "endOffset": 5299001, + "octets": 74, + "lines": 3 + } + ], + "octets": 213160, + "lines": 3160 + } + ], + "octets": 215082, + "lines": 3202 + }, + "octets": 215082 + }, + { + "mboxMarkerOffset": 5299089, + "lineNumber": 74197, + "beginOffset": 5299097, + "headersEndOffset": 5299489, + "endOffset": 5388898, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 74197, + "beginOffset": 5299097, + "headersEndOffset": 5299489, + "endOffset": 5388898, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 74215, + "beginOffset": 5299733, + "headersEndOffset": 5299828, + "endOffset": 5300031, + "octets": 203, + "lines": 9 + }, + { + "mimeType": "audio/basic", + "lineNumber": 74229, + "beginOffset": 5300081, + "headersEndOffset": 5300142, + "endOffset": 5388740, + "octets": 88598, + "lines": 1214 + }, + { + "mimeType": "text/plain", + "lineNumber": 75448, + "beginOffset": 5388790, + "headersEndOffset": 5388816, + "endOffset": 5388846, + "octets": 30, + "lines": 1 + } + ], + "octets": 89409, + "lines": 1243 + }, + "octets": 89409 + }, + { + "mboxMarkerOffset": 5388899, + "lineNumber": 75455, + "beginOffset": 5388907, + "headersEndOffset": 5389843, + "endOffset": 5440552, + "body": { + "mimeType": "message/partial", + "lineNumber": 75455, + "beginOffset": 5388907, + "headersEndOffset": 5389843, + "endOffset": 5440552, + "octets": 50709, + "lines": 696 + }, + "octets": 50709 + }, + { + "mboxMarkerOffset": 5440553, + "lineNumber": 76173, + "beginOffset": 5440561, + "headersEndOffset": 5441173, + "endOffset": 5509954, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 76173, + "beginOffset": 5440561, + "headersEndOffset": 5441173, + "endOffset": 5509954, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 76191, + "beginOffset": 5441191, + "headersEndOffset": 5441192, + "endOffset": 5445509, + "octets": 4317, + "lines": 101 + }, + { + "mimeType": "multipart/digest", + "lineNumber": 76295, + "beginOffset": 5445528, + "headersEndOffset": 5445669, + "endOffset": 5509879, + "children": [ + { + "mimeType": "message/rfc822", + "lineNumber": 76299, + "beginOffset": 5445700, + "headersEndOffset": 5445701, + "endOffset": 5446427, + "message": { + "lineNumber": 76300, + "beginOffset": 5445701, + "headersEndOffset": 5445806, + "endOffset": 5446427, + "body": { + "mimeType": "text/plain", + "lineNumber": 76300, + "beginOffset": 5445701, + "headersEndOffset": 5445806, + "endOffset": 5446427, + "octets": 621, + "lines": 18 + }, + "octets": 621 + }, + "octets": 726, + "lines": 22 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76324, + "beginOffset": 5446459, + "headersEndOffset": 5446460, + "endOffset": 5447314, + "message": { + "lineNumber": 76325, + "beginOffset": 5446460, + "headersEndOffset": 5446581, + "endOffset": 5447314, + "body": { + "mimeType": "text/plain", + "lineNumber": 76325, + "beginOffset": 5446460, + "headersEndOffset": 5446581, + "endOffset": 5447314, + "octets": 733, + "lines": 20 + }, + "octets": 733 + }, + "octets": 854, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76351, + "beginOffset": 5447346, + "headersEndOffset": 5447347, + "endOffset": 5448112, + "message": { + "lineNumber": 76352, + "beginOffset": 5447347, + "headersEndOffset": 5447466, + "endOffset": 5448112, + "body": { + "mimeType": "text/plain", + "lineNumber": 76352, + "beginOffset": 5447347, + "headersEndOffset": 5447466, + "endOffset": 5448112, + "octets": 646, + "lines": 14 + }, + "octets": 646 + }, + "octets": 765, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76372, + "beginOffset": 5448144, + "headersEndOffset": 5448145, + "endOffset": 5448784, + "message": { + "lineNumber": 76373, + "beginOffset": 5448145, + "headersEndOffset": 5448301, + "endOffset": 5448784, + "body": { + "mimeType": "text/plain", + "lineNumber": 76373, + "beginOffset": 5448145, + "headersEndOffset": 5448301, + "endOffset": 5448784, + "octets": 483, + "lines": 10 + }, + "octets": 483 + }, + "octets": 639, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76389, + "beginOffset": 5448816, + "headersEndOffset": 5448817, + "endOffset": 5449543, + "message": { + "lineNumber": 76390, + "beginOffset": 5448817, + "headersEndOffset": 5448971, + "endOffset": 5449543, + "body": { + "mimeType": "text/plain", + "lineNumber": 76390, + "beginOffset": 5448817, + "headersEndOffset": 5448971, + "endOffset": 5449543, + "octets": 572, + "lines": 15 + }, + "octets": 572 + }, + "octets": 726, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76411, + "beginOffset": 5449575, + "headersEndOffset": 5449576, + "endOffset": 5451008, + "message": { + "lineNumber": 76412, + "beginOffset": 5449576, + "headersEndOffset": 5449733, + "endOffset": 5451008, + "body": { + "mimeType": "text/plain", + "lineNumber": 76412, + "beginOffset": 5449576, + "headersEndOffset": 5449733, + "endOffset": 5451008, + "octets": 1275, + "lines": 26 + }, + "octets": 1275 + }, + "octets": 1432, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76444, + "beginOffset": 5451040, + "headersEndOffset": 5451041, + "endOffset": 5451595, + "message": { + "lineNumber": 76445, + "beginOffset": 5451041, + "headersEndOffset": 5451194, + "endOffset": 5451595, + "body": { + "mimeType": "text/plain", + "lineNumber": 76445, + "beginOffset": 5451041, + "headersEndOffset": 5451194, + "endOffset": 5451595, + "octets": 401, + "lines": 9 + }, + "octets": 401 + }, + "octets": 554, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76460, + "beginOffset": 5451627, + "headersEndOffset": 5451628, + "endOffset": 5452171, + "message": { + "lineNumber": 76461, + "beginOffset": 5451628, + "headersEndOffset": 5451775, + "endOffset": 5452171, + "body": { + "mimeType": "text/plain", + "lineNumber": 76461, + "beginOffset": 5451628, + "headersEndOffset": 5451775, + "endOffset": 5452171, + "octets": 396, + "lines": 7 + }, + "octets": 396 + }, + "octets": 543, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76474, + "beginOffset": 5452203, + "headersEndOffset": 5452204, + "endOffset": 5452987, + "message": { + "lineNumber": 76475, + "beginOffset": 5452204, + "headersEndOffset": 5452347, + "endOffset": 5452987, + "body": { + "mimeType": "text/plain", + "lineNumber": 76475, + "beginOffset": 5452204, + "headersEndOffset": 5452347, + "endOffset": 5452987, + "octets": 640, + "lines": 11 + }, + "octets": 640 + }, + "octets": 783, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76492, + "beginOffset": 5453019, + "headersEndOffset": 5453020, + "endOffset": 5454134, + "message": { + "lineNumber": 76493, + "beginOffset": 5453020, + "headersEndOffset": 5453157, + "endOffset": 5454134, + "body": { + "mimeType": "text/plain", + "lineNumber": 76493, + "beginOffset": 5453020, + "headersEndOffset": 5453157, + "endOffset": 5454134, + "octets": 977, + "lines": 19 + }, + "octets": 977 + }, + "octets": 1114, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76518, + "beginOffset": 5454166, + "headersEndOffset": 5454167, + "endOffset": 5455204, + "message": { + "lineNumber": 76519, + "beginOffset": 5454167, + "headersEndOffset": 5454314, + "endOffset": 5455204, + "body": { + "mimeType": "text/plain", + "lineNumber": 76519, + "beginOffset": 5454167, + "headersEndOffset": 5454314, + "endOffset": 5455204, + "octets": 890, + "lines": 27 + }, + "octets": 890 + }, + "octets": 1037, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76552, + "beginOffset": 5455236, + "headersEndOffset": 5455237, + "endOffset": 5455927, + "message": { + "lineNumber": 76553, + "beginOffset": 5455237, + "headersEndOffset": 5455368, + "endOffset": 5455927, + "body": { + "mimeType": "text/plain", + "lineNumber": 76553, + "beginOffset": 5455237, + "headersEndOffset": 5455368, + "endOffset": 5455927, + "octets": 559, + "lines": 11 + }, + "octets": 559 + }, + "octets": 690, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76570, + "beginOffset": 5455959, + "headersEndOffset": 5455960, + "endOffset": 5456529, + "message": { + "lineNumber": 76571, + "beginOffset": 5455960, + "headersEndOffset": 5456092, + "endOffset": 5456529, + "body": { + "mimeType": "text/plain", + "lineNumber": 76571, + "beginOffset": 5455960, + "headersEndOffset": 5456092, + "endOffset": 5456529, + "octets": 437, + "lines": 10 + }, + "octets": 437 + }, + "octets": 569, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76587, + "beginOffset": 5456561, + "headersEndOffset": 5456562, + "endOffset": 5457231, + "message": { + "lineNumber": 76588, + "beginOffset": 5456562, + "headersEndOffset": 5456679, + "endOffset": 5457231, + "body": { + "mimeType": "text/plain", + "lineNumber": 76588, + "beginOffset": 5456562, + "headersEndOffset": 5456679, + "endOffset": 5457231, + "octets": 552, + "lines": 15 + }, + "octets": 552 + }, + "octets": 669, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76609, + "beginOffset": 5457263, + "headersEndOffset": 5457264, + "endOffset": 5457564, + "message": { + "lineNumber": 76610, + "beginOffset": 5457264, + "headersEndOffset": 5457379, + "endOffset": 5457564, + "body": { + "mimeType": "text/plain", + "lineNumber": 76610, + "beginOffset": 5457264, + "headersEndOffset": 5457379, + "endOffset": 5457564, + "octets": 185, + "lines": 8 + }, + "octets": 185 + }, + "octets": 300, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76624, + "beginOffset": 5457596, + "headersEndOffset": 5457597, + "endOffset": 5458042, + "message": { + "lineNumber": 76625, + "beginOffset": 5457597, + "headersEndOffset": 5457714, + "endOffset": 5458042, + "body": { + "mimeType": "text/plain", + "lineNumber": 76625, + "beginOffset": 5457597, + "headersEndOffset": 5457714, + "endOffset": 5458042, + "octets": 328, + "lines": 7 + }, + "octets": 328 + }, + "octets": 445, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76638, + "beginOffset": 5458074, + "headersEndOffset": 5458075, + "endOffset": 5458865, + "message": { + "lineNumber": 76639, + "beginOffset": 5458075, + "headersEndOffset": 5458198, + "endOffset": 5458865, + "body": { + "mimeType": "text/plain", + "lineNumber": 76639, + "beginOffset": 5458075, + "headersEndOffset": 5458198, + "endOffset": 5458865, + "octets": 667, + "lines": 21 + }, + "octets": 667 + }, + "octets": 790, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76666, + "beginOffset": 5458897, + "headersEndOffset": 5458898, + "endOffset": 5459124, + "message": { + "lineNumber": 76667, + "beginOffset": 5458898, + "headersEndOffset": 5459022, + "endOffset": 5459124, + "body": { + "mimeType": "text/plain", + "lineNumber": 76667, + "beginOffset": 5458898, + "headersEndOffset": 5459022, + "endOffset": 5459124, + "octets": 102, + "lines": 5 + }, + "octets": 102 + }, + "octets": 226, + "lines": 9 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76678, + "beginOffset": 5459156, + "headersEndOffset": 5459157, + "endOffset": 5460135, + "message": { + "lineNumber": 76679, + "beginOffset": 5459157, + "headersEndOffset": 5459299, + "endOffset": 5460135, + "body": { + "mimeType": "text/plain", + "lineNumber": 76679, + "beginOffset": 5459157, + "headersEndOffset": 5459299, + "endOffset": 5460135, + "octets": 836, + "lines": 21 + }, + "octets": 836 + }, + "octets": 978, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76706, + "beginOffset": 5460167, + "headersEndOffset": 5460168, + "endOffset": 5460697, + "message": { + "lineNumber": 76707, + "beginOffset": 5460168, + "headersEndOffset": 5460278, + "endOffset": 5460697, + "body": { + "mimeType": "text/plain", + "lineNumber": 76707, + "beginOffset": 5460168, + "headersEndOffset": 5460278, + "endOffset": 5460697, + "octets": 419, + "lines": 9 + }, + "octets": 419 + }, + "octets": 529, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76722, + "beginOffset": 5460729, + "headersEndOffset": 5460730, + "endOffset": 5461132, + "message": { + "lineNumber": 76723, + "beginOffset": 5460730, + "headersEndOffset": 5460902, + "endOffset": 5461132, + "body": { + "mimeType": "text/plain", + "lineNumber": 76723, + "beginOffset": 5460730, + "headersEndOffset": 5460902, + "endOffset": 5461132, + "octets": 230, + "lines": 9 + }, + "octets": 230 + }, + "octets": 402, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76738, + "beginOffset": 5461164, + "headersEndOffset": 5461165, + "endOffset": 5461690, + "message": { + "lineNumber": 76739, + "beginOffset": 5461165, + "headersEndOffset": 5461291, + "endOffset": 5461690, + "body": { + "mimeType": "text/plain", + "lineNumber": 76739, + "beginOffset": 5461165, + "headersEndOffset": 5461291, + "endOffset": 5461690, + "octets": 399, + "lines": 12 + }, + "octets": 399 + }, + "octets": 525, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76757, + "beginOffset": 5461722, + "headersEndOffset": 5461723, + "endOffset": 5462744, + "message": { + "lineNumber": 76758, + "beginOffset": 5461723, + "headersEndOffset": 5461840, + "endOffset": 5462744, + "body": { + "mimeType": "text/plain", + "lineNumber": 76758, + "beginOffset": 5461723, + "headersEndOffset": 5461840, + "endOffset": 5462744, + "octets": 904, + "lines": 28 + }, + "octets": 904 + }, + "octets": 1021, + "lines": 32 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76792, + "beginOffset": 5462776, + "headersEndOffset": 5462777, + "endOffset": 5463196, + "message": { + "lineNumber": 76793, + "beginOffset": 5462777, + "headersEndOffset": 5462905, + "endOffset": 5463196, + "body": { + "mimeType": "text/plain", + "lineNumber": 76793, + "beginOffset": 5462777, + "headersEndOffset": 5462905, + "endOffset": 5463196, + "octets": 291, + "lines": 9 + }, + "octets": 291 + }, + "octets": 419, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76808, + "beginOffset": 5463228, + "headersEndOffset": 5463229, + "endOffset": 5463768, + "message": { + "lineNumber": 76809, + "beginOffset": 5463229, + "headersEndOffset": 5463358, + "endOffset": 5463768, + "body": { + "mimeType": "text/plain", + "lineNumber": 76809, + "beginOffset": 5463229, + "headersEndOffset": 5463358, + "endOffset": 5463768, + "octets": 410, + "lines": 14 + }, + "octets": 410 + }, + "octets": 539, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76829, + "beginOffset": 5463800, + "headersEndOffset": 5463801, + "endOffset": 5464061, + "message": { + "lineNumber": 76830, + "beginOffset": 5463801, + "headersEndOffset": 5463916, + "endOffset": 5464061, + "body": { + "mimeType": "text/plain", + "lineNumber": 76830, + "beginOffset": 5463801, + "headersEndOffset": 5463916, + "endOffset": 5464061, + "octets": 145, + "lines": 4 + }, + "octets": 145 + }, + "octets": 260, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76840, + "beginOffset": 5464093, + "headersEndOffset": 5464094, + "endOffset": 5464398, + "message": { + "lineNumber": 76841, + "beginOffset": 5464094, + "headersEndOffset": 5464219, + "endOffset": 5464398, + "body": { + "mimeType": "text/plain", + "lineNumber": 76841, + "beginOffset": 5464094, + "headersEndOffset": 5464219, + "endOffset": 5464398, + "octets": 179, + "lines": 7 + }, + "octets": 179 + }, + "octets": 304, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76854, + "beginOffset": 5464430, + "headersEndOffset": 5464431, + "endOffset": 5465277, + "message": { + "lineNumber": 76855, + "beginOffset": 5464431, + "headersEndOffset": 5464561, + "endOffset": 5465277, + "body": { + "mimeType": "text/plain", + "lineNumber": 76855, + "beginOffset": 5464431, + "headersEndOffset": 5464561, + "endOffset": 5465277, + "octets": 716, + "lines": 14 + }, + "octets": 716 + }, + "octets": 846, + "lines": 18 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76875, + "beginOffset": 5465309, + "headersEndOffset": 5465310, + "endOffset": 5466413, + "message": { + "lineNumber": 76876, + "beginOffset": 5465310, + "headersEndOffset": 5465456, + "endOffset": 5466413, + "body": { + "mimeType": "text/plain", + "lineNumber": 76876, + "beginOffset": 5465310, + "headersEndOffset": 5465456, + "endOffset": 5466413, + "octets": 957, + "lines": 26 + }, + "octets": 957 + }, + "octets": 1103, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76908, + "beginOffset": 5466445, + "headersEndOffset": 5466446, + "endOffset": 5466827, + "message": { + "lineNumber": 76909, + "beginOffset": 5466446, + "headersEndOffset": 5466580, + "endOffset": 5466827, + "body": { + "mimeType": "text/plain", + "lineNumber": 76909, + "beginOffset": 5466446, + "headersEndOffset": 5466580, + "endOffset": 5466827, + "octets": 247, + "lines": 7 + }, + "octets": 247 + }, + "octets": 381, + "lines": 11 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76922, + "beginOffset": 5466859, + "headersEndOffset": 5466860, + "endOffset": 5467109, + "message": { + "lineNumber": 76923, + "beginOffset": 5466860, + "headersEndOffset": 5466982, + "endOffset": 5467109, + "body": { + "mimeType": "text/plain", + "lineNumber": 76923, + "beginOffset": 5466860, + "headersEndOffset": 5466982, + "endOffset": 5467109, + "octets": 127, + "lines": 6 + }, + "octets": 127 + }, + "octets": 249, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76935, + "beginOffset": 5467141, + "headersEndOffset": 5467142, + "endOffset": 5468062, + "message": { + "lineNumber": 76936, + "beginOffset": 5467142, + "headersEndOffset": 5467317, + "endOffset": 5468062, + "body": { + "mimeType": "text/plain", + "lineNumber": 76936, + "beginOffset": 5467142, + "headersEndOffset": 5467317, + "endOffset": 5468062, + "octets": 745, + "lines": 16 + }, + "octets": 745 + }, + "octets": 920, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76959, + "beginOffset": 5468094, + "headersEndOffset": 5468095, + "endOffset": 5468654, + "message": { + "lineNumber": 76960, + "beginOffset": 5468095, + "headersEndOffset": 5468255, + "endOffset": 5468654, + "body": { + "mimeType": "text/plain", + "lineNumber": 76960, + "beginOffset": 5468095, + "headersEndOffset": 5468255, + "endOffset": 5468654, + "octets": 399, + "lines": 16 + }, + "octets": 399 + }, + "octets": 559, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 76982, + "beginOffset": 5468686, + "headersEndOffset": 5468687, + "endOffset": 5470106, + "message": { + "lineNumber": 76983, + "beginOffset": 5468687, + "headersEndOffset": 5468819, + "endOffset": 5470106, + "body": { + "mimeType": "text/plain", + "lineNumber": 76983, + "beginOffset": 5468687, + "headersEndOffset": 5468819, + "endOffset": 5470106, + "octets": 1287, + "lines": 21 + }, + "octets": 1287 + }, + "octets": 1419, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77010, + "beginOffset": 5470138, + "headersEndOffset": 5470139, + "endOffset": 5470388, + "message": { + "lineNumber": 77011, + "beginOffset": 5470139, + "headersEndOffset": 5470245, + "endOffset": 5470388, + "body": { + "mimeType": "text/plain", + "lineNumber": 77011, + "beginOffset": 5470139, + "headersEndOffset": 5470245, + "endOffset": 5470388, + "octets": 143, + "lines": 6 + }, + "octets": 143 + }, + "octets": 249, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77023, + "beginOffset": 5470420, + "headersEndOffset": 5470421, + "endOffset": 5470857, + "message": { + "lineNumber": 77024, + "beginOffset": 5470421, + "headersEndOffset": 5470558, + "endOffset": 5470857, + "body": { + "mimeType": "text/plain", + "lineNumber": 77024, + "beginOffset": 5470421, + "headersEndOffset": 5470558, + "endOffset": 5470857, + "octets": 299, + "lines": 11 + }, + "octets": 299 + }, + "octets": 436, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77041, + "beginOffset": 5470889, + "headersEndOffset": 5470890, + "endOffset": 5471203, + "message": { + "lineNumber": 77042, + "beginOffset": 5470890, + "headersEndOffset": 5471016, + "endOffset": 5471203, + "body": { + "mimeType": "text/plain", + "lineNumber": 77042, + "beginOffset": 5470890, + "headersEndOffset": 5471016, + "endOffset": 5471203, + "octets": 187, + "lines": 6 + }, + "octets": 187 + }, + "octets": 313, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77054, + "beginOffset": 5471235, + "headersEndOffset": 5471236, + "endOffset": 5471739, + "message": { + "lineNumber": 77055, + "beginOffset": 5471236, + "headersEndOffset": 5471341, + "endOffset": 5471739, + "body": { + "mimeType": "text/plain", + "lineNumber": 77055, + "beginOffset": 5471236, + "headersEndOffset": 5471341, + "endOffset": 5471739, + "octets": 398, + "lines": 12 + }, + "octets": 398 + }, + "octets": 503, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77073, + "beginOffset": 5471771, + "headersEndOffset": 5471772, + "endOffset": 5472208, + "message": { + "lineNumber": 77074, + "beginOffset": 5471772, + "headersEndOffset": 5471906, + "endOffset": 5472208, + "body": { + "mimeType": "text/plain", + "lineNumber": 77074, + "beginOffset": 5471772, + "headersEndOffset": 5471906, + "endOffset": 5472208, + "octets": 302, + "lines": 8 + }, + "octets": 302 + }, + "octets": 436, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77088, + "beginOffset": 5472240, + "headersEndOffset": 5472241, + "endOffset": 5473002, + "message": { + "lineNumber": 77089, + "beginOffset": 5472241, + "headersEndOffset": 5472384, + "endOffset": 5473002, + "body": { + "mimeType": "text/plain", + "lineNumber": 77089, + "beginOffset": 5472241, + "headersEndOffset": 5472384, + "endOffset": 5473002, + "octets": 618, + "lines": 17 + }, + "octets": 618 + }, + "octets": 761, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77112, + "beginOffset": 5473034, + "headersEndOffset": 5473035, + "endOffset": 5473663, + "message": { + "lineNumber": 77113, + "beginOffset": 5473035, + "headersEndOffset": 5473188, + "endOffset": 5473663, + "body": { + "mimeType": "text/plain", + "lineNumber": 77113, + "beginOffset": 5473035, + "headersEndOffset": 5473188, + "endOffset": 5473663, + "octets": 475, + "lines": 10 + }, + "octets": 475 + }, + "octets": 628, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77129, + "beginOffset": 5473695, + "headersEndOffset": 5473696, + "endOffset": 5475001, + "message": { + "lineNumber": 77130, + "beginOffset": 5473696, + "headersEndOffset": 5473829, + "endOffset": 5475001, + "body": { + "mimeType": "text/plain", + "lineNumber": 77130, + "beginOffset": 5473696, + "headersEndOffset": 5473829, + "endOffset": 5475001, + "octets": 1172, + "lines": 27 + }, + "octets": 1172 + }, + "octets": 1305, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77163, + "beginOffset": 5475033, + "headersEndOffset": 5475034, + "endOffset": 5475469, + "message": { + "lineNumber": 77164, + "beginOffset": 5475034, + "headersEndOffset": 5475210, + "endOffset": 5475469, + "body": { + "mimeType": "text/plain", + "lineNumber": 77164, + "beginOffset": 5475034, + "headersEndOffset": 5475210, + "endOffset": 5475469, + "octets": 259, + "lines": 8 + }, + "octets": 259 + }, + "octets": 435, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77178, + "beginOffset": 5475501, + "headersEndOffset": 5475502, + "endOffset": 5475810, + "message": { + "lineNumber": 77179, + "beginOffset": 5475502, + "headersEndOffset": 5475617, + "endOffset": 5475810, + "body": { + "mimeType": "text/plain", + "lineNumber": 77179, + "beginOffset": 5475502, + "headersEndOffset": 5475617, + "endOffset": 5475810, + "octets": 193, + "lines": 4 + }, + "octets": 193 + }, + "octets": 308, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77189, + "beginOffset": 5475842, + "headersEndOffset": 5475843, + "endOffset": 5476848, + "message": { + "lineNumber": 77190, + "beginOffset": 5475843, + "headersEndOffset": 5475983, + "endOffset": 5476848, + "body": { + "mimeType": "text/plain", + "lineNumber": 77190, + "beginOffset": 5475843, + "headersEndOffset": 5475983, + "endOffset": 5476848, + "octets": 865, + "lines": 24 + }, + "octets": 865 + }, + "octets": 1005, + "lines": 28 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77220, + "beginOffset": 5476880, + "headersEndOffset": 5476881, + "endOffset": 5477720, + "message": { + "lineNumber": 77221, + "beginOffset": 5476881, + "headersEndOffset": 5477006, + "endOffset": 5477720, + "body": { + "mimeType": "text/plain", + "lineNumber": 77221, + "beginOffset": 5476881, + "headersEndOffset": 5477006, + "endOffset": 5477720, + "octets": 714, + "lines": 11 + }, + "octets": 714 + }, + "octets": 839, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77238, + "beginOffset": 5477752, + "headersEndOffset": 5477753, + "endOffset": 5478568, + "message": { + "lineNumber": 77239, + "beginOffset": 5477753, + "headersEndOffset": 5477865, + "endOffset": 5478568, + "body": { + "mimeType": "text/plain", + "lineNumber": 77239, + "beginOffset": 5477753, + "headersEndOffset": 5477865, + "endOffset": 5478568, + "octets": 703, + "lines": 17 + }, + "octets": 703 + }, + "octets": 815, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77262, + "beginOffset": 5478600, + "headersEndOffset": 5478601, + "endOffset": 5479113, + "message": { + "lineNumber": 77263, + "beginOffset": 5478601, + "headersEndOffset": 5478733, + "endOffset": 5479113, + "body": { + "mimeType": "text/plain", + "lineNumber": 77263, + "beginOffset": 5478601, + "headersEndOffset": 5478733, + "endOffset": 5479113, + "octets": 380, + "lines": 11 + }, + "octets": 380 + }, + "octets": 512, + "lines": 15 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77280, + "beginOffset": 5479145, + "headersEndOffset": 5479146, + "endOffset": 5480259, + "message": { + "lineNumber": 77281, + "beginOffset": 5479146, + "headersEndOffset": 5479282, + "endOffset": 5480259, + "body": { + "mimeType": "text/plain", + "lineNumber": 77281, + "beginOffset": 5479146, + "headersEndOffset": 5479282, + "endOffset": 5480259, + "octets": 977, + "lines": 24 + }, + "octets": 977 + }, + "octets": 1113, + "lines": 28 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77311, + "beginOffset": 5480291, + "headersEndOffset": 5480292, + "endOffset": 5480904, + "message": { + "lineNumber": 77312, + "beginOffset": 5480292, + "headersEndOffset": 5480437, + "endOffset": 5480904, + "body": { + "mimeType": "text/plain", + "lineNumber": 77312, + "beginOffset": 5480292, + "headersEndOffset": 5480437, + "endOffset": 5480904, + "octets": 467, + "lines": 10 + }, + "octets": 467 + }, + "octets": 612, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77328, + "beginOffset": 5480936, + "headersEndOffset": 5480937, + "endOffset": 5481349, + "message": { + "lineNumber": 77329, + "beginOffset": 5480937, + "headersEndOffset": 5481070, + "endOffset": 5481349, + "body": { + "mimeType": "text/plain", + "lineNumber": 77329, + "beginOffset": 5480937, + "headersEndOffset": 5481070, + "endOffset": 5481349, + "octets": 279, + "lines": 10 + }, + "octets": 279 + }, + "octets": 412, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77345, + "beginOffset": 5481381, + "headersEndOffset": 5481382, + "endOffset": 5481789, + "message": { + "lineNumber": 77346, + "beginOffset": 5481382, + "headersEndOffset": 5481507, + "endOffset": 5481789, + "body": { + "mimeType": "text/plain", + "lineNumber": 77346, + "beginOffset": 5481382, + "headersEndOffset": 5481507, + "endOffset": 5481789, + "octets": 282, + "lines": 4 + }, + "octets": 282 + }, + "octets": 407, + "lines": 8 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77356, + "beginOffset": 5481821, + "headersEndOffset": 5481822, + "endOffset": 5482586, + "message": { + "lineNumber": 77357, + "beginOffset": 5481822, + "headersEndOffset": 5481943, + "endOffset": 5482586, + "body": { + "mimeType": "text/plain", + "lineNumber": 77357, + "beginOffset": 5481822, + "headersEndOffset": 5481943, + "endOffset": 5482586, + "octets": 643, + "lines": 27 + }, + "octets": 643 + }, + "octets": 764, + "lines": 31 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77390, + "beginOffset": 5482618, + "headersEndOffset": 5482619, + "endOffset": 5485021, + "message": { + "lineNumber": 77391, + "beginOffset": 5482619, + "headersEndOffset": 5482763, + "endOffset": 5485021, + "body": { + "mimeType": "text/plain", + "lineNumber": 77391, + "beginOffset": 5482619, + "headersEndOffset": 5482763, + "endOffset": 5485021, + "octets": 2258, + "lines": 46 + }, + "octets": 2258 + }, + "octets": 2402, + "lines": 50 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77443, + "beginOffset": 5485053, + "headersEndOffset": 5485054, + "endOffset": 5485968, + "message": { + "lineNumber": 77444, + "beginOffset": 5485054, + "headersEndOffset": 5485176, + "endOffset": 5485968, + "body": { + "mimeType": "text/plain", + "lineNumber": 77444, + "beginOffset": 5485054, + "headersEndOffset": 5485176, + "endOffset": 5485968, + "octets": 792, + "lines": 17 + }, + "octets": 792 + }, + "octets": 914, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77467, + "beginOffset": 5486000, + "headersEndOffset": 5486001, + "endOffset": 5486321, + "message": { + "lineNumber": 77468, + "beginOffset": 5486001, + "headersEndOffset": 5486095, + "endOffset": 5486321, + "body": { + "mimeType": "text/plain", + "lineNumber": 77468, + "beginOffset": 5486001, + "headersEndOffset": 5486095, + "endOffset": 5486321, + "octets": 226, + "lines": 10 + }, + "octets": 226 + }, + "octets": 320, + "lines": 14 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77484, + "beginOffset": 5486353, + "headersEndOffset": 5486354, + "endOffset": 5487143, + "message": { + "lineNumber": 77485, + "beginOffset": 5486354, + "headersEndOffset": 5486475, + "endOffset": 5487143, + "body": { + "mimeType": "text/plain", + "lineNumber": 77485, + "beginOffset": 5486354, + "headersEndOffset": 5486475, + "endOffset": 5487143, + "octets": 668, + "lines": 20 + }, + "octets": 668 + }, + "octets": 789, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77511, + "beginOffset": 5487175, + "headersEndOffset": 5487176, + "endOffset": 5489833, + "message": { + "lineNumber": 77512, + "beginOffset": 5487176, + "headersEndOffset": 5487286, + "endOffset": 5489833, + "body": { + "mimeType": "text/plain", + "lineNumber": 77512, + "beginOffset": 5487176, + "headersEndOffset": 5487286, + "endOffset": 5489833, + "octets": 2547, + "lines": 68 + }, + "octets": 2547 + }, + "octets": 2657, + "lines": 72 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77586, + "beginOffset": 5489865, + "headersEndOffset": 5489866, + "endOffset": 5491181, + "message": { + "lineNumber": 77587, + "beginOffset": 5489866, + "headersEndOffset": 5489972, + "endOffset": 5491181, + "body": { + "mimeType": "text/plain", + "lineNumber": 77587, + "beginOffset": 5489866, + "headersEndOffset": 5489972, + "endOffset": 5491181, + "octets": 1209, + "lines": 34 + }, + "octets": 1209 + }, + "octets": 1315, + "lines": 38 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77627, + "beginOffset": 5491213, + "headersEndOffset": 5491214, + "endOffset": 5493117, + "message": { + "lineNumber": 77628, + "beginOffset": 5491214, + "headersEndOffset": 5491320, + "endOffset": 5493117, + "body": { + "mimeType": "text/plain", + "lineNumber": 77628, + "beginOffset": 5491214, + "headersEndOffset": 5491320, + "endOffset": 5493117, + "octets": 1797, + "lines": 43 + }, + "octets": 1797 + }, + "octets": 1903, + "lines": 47 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77677, + "beginOffset": 5493149, + "headersEndOffset": 5493150, + "endOffset": 5493849, + "message": { + "lineNumber": 77678, + "beginOffset": 5493150, + "headersEndOffset": 5493279, + "endOffset": 5493849, + "body": { + "mimeType": "text/plain", + "lineNumber": 77678, + "beginOffset": 5493150, + "headersEndOffset": 5493279, + "endOffset": 5493849, + "octets": 570, + "lines": 12 + }, + "octets": 570 + }, + "octets": 699, + "lines": 16 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77696, + "beginOffset": 5493881, + "headersEndOffset": 5493882, + "endOffset": 5495304, + "message": { + "lineNumber": 77697, + "beginOffset": 5493882, + "headersEndOffset": 5493970, + "endOffset": 5495304, + "body": { + "mimeType": "text/plain", + "lineNumber": 77697, + "beginOffset": 5493882, + "headersEndOffset": 5493970, + "endOffset": 5495304, + "octets": 1334, + "lines": 20 + }, + "octets": 1334 + }, + "octets": 1422, + "lines": 24 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77723, + "beginOffset": 5495336, + "headersEndOffset": 5495337, + "endOffset": 5497580, + "message": { + "lineNumber": 77724, + "beginOffset": 5495337, + "headersEndOffset": 5495453, + "endOffset": 5497580, + "body": { + "mimeType": "text/plain", + "lineNumber": 77724, + "beginOffset": 5495337, + "headersEndOffset": 5495453, + "endOffset": 5497580, + "octets": 2127, + "lines": 49 + }, + "octets": 2127 + }, + "octets": 2243, + "lines": 53 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77779, + "beginOffset": 5497612, + "headersEndOffset": 5497613, + "endOffset": 5499755, + "message": { + "lineNumber": 77780, + "beginOffset": 5497613, + "headersEndOffset": 5497734, + "endOffset": 5499755, + "body": { + "mimeType": "text/plain", + "lineNumber": 77780, + "beginOffset": 5497613, + "headersEndOffset": 5497734, + "endOffset": 5499755, + "octets": 2021, + "lines": 42 + }, + "octets": 2021 + }, + "octets": 2142, + "lines": 46 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77828, + "beginOffset": 5499787, + "headersEndOffset": 5499788, + "endOffset": 5500586, + "message": { + "lineNumber": 77829, + "beginOffset": 5499788, + "headersEndOffset": 5499909, + "endOffset": 5500586, + "body": { + "mimeType": "text/plain", + "lineNumber": 77829, + "beginOffset": 5499788, + "headersEndOffset": 5499909, + "endOffset": 5500586, + "octets": 677, + "lines": 19 + }, + "octets": 677 + }, + "octets": 798, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77854, + "beginOffset": 5500618, + "headersEndOffset": 5500619, + "endOffset": 5501576, + "message": { + "lineNumber": 77855, + "beginOffset": 5500619, + "headersEndOffset": 5500756, + "endOffset": 5501576, + "body": { + "mimeType": "text/plain", + "lineNumber": 77855, + "beginOffset": 5500619, + "headersEndOffset": 5500756, + "endOffset": 5501576, + "octets": 820, + "lines": 16 + }, + "octets": 820 + }, + "octets": 957, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77877, + "beginOffset": 5501608, + "headersEndOffset": 5501609, + "endOffset": 5502457, + "message": { + "lineNumber": 77878, + "beginOffset": 5501609, + "headersEndOffset": 5501733, + "endOffset": 5502457, + "body": { + "mimeType": "text/plain", + "lineNumber": 77878, + "beginOffset": 5501609, + "headersEndOffset": 5501733, + "endOffset": 5502457, + "octets": 724, + "lines": 21 + }, + "octets": 724 + }, + "octets": 848, + "lines": 25 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77905, + "beginOffset": 5502489, + "headersEndOffset": 5502490, + "endOffset": 5503332, + "message": { + "lineNumber": 77906, + "beginOffset": 5502490, + "headersEndOffset": 5502592, + "endOffset": 5503332, + "body": { + "mimeType": "text/plain", + "lineNumber": 77906, + "beginOffset": 5502490, + "headersEndOffset": 5502592, + "endOffset": 5503332, + "octets": 740, + "lines": 16 + }, + "octets": 740 + }, + "octets": 842, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77928, + "beginOffset": 5503364, + "headersEndOffset": 5503365, + "endOffset": 5503880, + "message": { + "lineNumber": 77929, + "beginOffset": 5503365, + "headersEndOffset": 5503521, + "endOffset": 5503880, + "body": { + "mimeType": "text/plain", + "lineNumber": 77929, + "beginOffset": 5503365, + "headersEndOffset": 5503521, + "endOffset": 5503880, + "octets": 359, + "lines": 7 + }, + "octets": 359 + }, + "octets": 515, + "lines": 12 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77943, + "beginOffset": 5503912, + "headersEndOffset": 5503913, + "endOffset": 5504635, + "message": { + "lineNumber": 77944, + "beginOffset": 5503913, + "headersEndOffset": 5504000, + "endOffset": 5504635, + "body": { + "mimeType": "text/plain", + "lineNumber": 77944, + "beginOffset": 5503913, + "headersEndOffset": 5504000, + "endOffset": 5504635, + "octets": 635, + "lines": 15 + }, + "octets": 635 + }, + "octets": 722, + "lines": 19 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77965, + "beginOffset": 5504667, + "headersEndOffset": 5504668, + "endOffset": 5505183, + "message": { + "lineNumber": 77966, + "beginOffset": 5504668, + "headersEndOffset": 5504817, + "endOffset": 5505183, + "body": { + "mimeType": "text/plain", + "lineNumber": 77966, + "beginOffset": 5504668, + "headersEndOffset": 5504817, + "endOffset": 5505183, + "octets": 366, + "lines": 17 + }, + "octets": 366 + }, + "octets": 515, + "lines": 21 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 77989, + "beginOffset": 5505215, + "headersEndOffset": 5505216, + "endOffset": 5505605, + "message": { + "lineNumber": 77990, + "beginOffset": 5505216, + "headersEndOffset": 5505317, + "endOffset": 5505605, + "body": { + "mimeType": "text/plain", + "lineNumber": 77990, + "beginOffset": 5505216, + "headersEndOffset": 5505317, + "endOffset": 5505605, + "octets": 288, + "lines": 6 + }, + "octets": 288 + }, + "octets": 389, + "lines": 10 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78002, + "beginOffset": 5505637, + "headersEndOffset": 5505638, + "endOffset": 5506245, + "message": { + "lineNumber": 78003, + "beginOffset": 5505638, + "headersEndOffset": 5505766, + "endOffset": 5506245, + "body": { + "mimeType": "text/plain", + "lineNumber": 78003, + "beginOffset": 5505638, + "headersEndOffset": 5505766, + "endOffset": 5506245, + "octets": 479, + "lines": 16 + }, + "octets": 479 + }, + "octets": 607, + "lines": 20 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78025, + "beginOffset": 5506277, + "headersEndOffset": 5506278, + "endOffset": 5506755, + "message": { + "lineNumber": 78026, + "beginOffset": 5506278, + "headersEndOffset": 5506375, + "endOffset": 5506755, + "body": { + "mimeType": "text/plain", + "lineNumber": 78026, + "beginOffset": 5506278, + "headersEndOffset": 5506375, + "endOffset": 5506755, + "octets": 380, + "lines": 19 + }, + "octets": 380 + }, + "octets": 477, + "lines": 23 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78051, + "beginOffset": 5506787, + "headersEndOffset": 5506788, + "endOffset": 5508222, + "message": { + "lineNumber": 78052, + "beginOffset": 5506788, + "headersEndOffset": 5506903, + "endOffset": 5508222, + "body": { + "mimeType": "text/plain", + "lineNumber": 78052, + "beginOffset": 5506788, + "headersEndOffset": 5506903, + "endOffset": 5508222, + "octets": 1319, + "lines": 26 + }, + "octets": 1319 + }, + "octets": 1434, + "lines": 30 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78084, + "beginOffset": 5508254, + "headersEndOffset": 5508255, + "endOffset": 5508650, + "message": { + "lineNumber": 78085, + "beginOffset": 5508255, + "headersEndOffset": 5508355, + "endOffset": 5508650, + "body": { + "mimeType": "text/plain", + "lineNumber": 78085, + "beginOffset": 5508255, + "headersEndOffset": 5508355, + "endOffset": 5508650, + "octets": 295, + "lines": 9 + }, + "octets": 295 + }, + "octets": 395, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 78100, + "beginOffset": 5508682, + "headersEndOffset": 5508683, + "endOffset": 5509845, + "message": { + "lineNumber": 78101, + "beginOffset": 5508683, + "headersEndOffset": 5508826, + "endOffset": 5509845, + "body": { + "mimeType": "text/plain", + "lineNumber": 78101, + "beginOffset": 5508683, + "headersEndOffset": 5508826, + "endOffset": 5509845, + "octets": 1019, + "lines": 36 + }, + "octets": 1019 + }, + "octets": 1162, + "lines": 40 + } + ], + "octets": 64210, + "lines": 1845 + } + ], + "octets": 68781, + "lines": 1958 + }, + "octets": 68781 + }, + { + "mboxMarkerOffset": 5509955, + "lineNumber": 78149, + "beginOffset": 5509963, + "headersEndOffset": 5510771, + "endOffset": 5512642, + "body": { + "mimeType": "text/plain", + "lineNumber": 78149, + "beginOffset": 5509963, + "headersEndOffset": 5510771, + "endOffset": 5512642, + "octets": 1871, + "lines": 49 + }, + "octets": 1871 + }, + { + "mboxMarkerOffset": 5512643, + "lineNumber": 78214, + "beginOffset": 5512651, + "headersEndOffset": 5513378, + "endOffset": 5668007, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 78214, + "beginOffset": 5512651, + "headersEndOffset": 5513378, + "endOffset": 5668007, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 78231, + "beginOffset": 5513405, + "headersEndOffset": 5513406, + "endOffset": 5513518, + "octets": 112, + "lines": 2 + }, + { + "mimeType": "application/x-annotate", + "lineNumber": 78235, + "beginOffset": 5513546, + "headersEndOffset": 5513635, + "endOffset": 5644327, + "octets": 130692, + "lines": 2012 + }, + { + "mimeType": "text/plain", + "lineNumber": 80251, + "beginOffset": 5644355, + "headersEndOffset": 5644356, + "endOffset": 5644411, + "octets": 55, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 80255, + "beginOffset": 5644439, + "headersEndOffset": 5644584, + "endOffset": 5659481, + "octets": 14897, + "lines": 78 + }, + { + "mimeType": "text/plain", + "lineNumber": 80339, + "beginOffset": 5659509, + "headersEndOffset": 5659510, + "endOffset": 5659600, + "octets": 90, + "lines": 6 + }, + { + "mimeType": "image/pbm", + "lineNumber": 80347, + "beginOffset": 5659628, + "headersEndOffset": 5659773, + "endOffset": 5667874, + "octets": 8101, + "lines": 42 + }, + { + "mimeType": "text/plain", + "lineNumber": 80395, + "beginOffset": 5667902, + "headersEndOffset": 5667903, + "endOffset": 5667977, + "octets": 74, + "lines": 4 + } + ], + "octets": 154629, + "lines": 2171 + }, + "octets": 154629 + }, + { + "mboxMarkerOffset": 5668008, + "lineNumber": 80403, + "beginOffset": 5668016, + "headersEndOffset": 5668539, + "endOffset": 5669107, + "body": { + "mimeType": "text/richtext", + "lineNumber": 80403, + "beginOffset": 5668016, + "headersEndOffset": 5668539, + "endOffset": 5669107, + "octets": 568, + "lines": 21 + }, + "octets": 568 + }, + { + "mboxMarkerOffset": 5669108, + "lineNumber": 80441, + "beginOffset": 5669116, + "headersEndOffset": 5670302, + "endOffset": 5730566, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 80441, + "beginOffset": 5669116, + "headersEndOffset": 5670302, + "endOffset": 5730566, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 80468, + "beginOffset": 5670497, + "headersEndOffset": 5670541, + "endOffset": 5671271, + "octets": 730, + "lines": 26 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 80498, + "beginOffset": 5671312, + "headersEndOffset": 5671397, + "endOffset": 5730523, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 80502, + "beginOffset": 5671439, + "headersEndOffset": 5671530, + "endOffset": 5672332, + "octets": 802, + "lines": 25 + }, + { + "mimeType": "image/gif", + "lineNumber": 80532, + "beginOffset": 5672375, + "headersEndOffset": 5672468, + "endOffset": 5730339, + "octets": 57871, + "lines": 755 + }, + { + "mimeType": "text/richtext", + "lineNumber": 81293, + "beginOffset": 5730382, + "headersEndOffset": 5730473, + "endOffset": 5730478, + "octets": 5, + "lines": 1 + } + ], + "octets": 59126, + "lines": 798 + } + ], + "octets": 60264, + "lines": 837 + }, + "octets": 60264 + }, + { + "mboxMarkerOffset": 5730567, + "lineNumber": 81303, + "beginOffset": 5730575, + "headersEndOffset": 5731315, + "endOffset": 5787038, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 81303, + "beginOffset": 5730575, + "headersEndOffset": 5731315, + "endOffset": 5787038, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 81322, + "beginOffset": 5731365, + "headersEndOffset": 5731455, + "endOffset": 5731629, + "octets": 174, + "lines": 7 + }, + { + "mimeType": "image/gif", + "lineNumber": 81334, + "beginOffset": 5731679, + "headersEndOffset": 5731738, + "endOffset": 5786986, + "octets": 55248, + "lines": 757 + } + ], + "octets": 55723, + "lines": 775 + }, + "octets": 55723 + }, + { + "mboxMarkerOffset": 5787039, + "lineNumber": 82097, + "beginOffset": 5787071, + "headersEndOffset": 5788538, + "endOffset": 5789878, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 82097, + "beginOffset": 5787071, + "headersEndOffset": 5788538, + "endOffset": 5789878, + "octets": 1340, + "lines": 34 + }, + "octets": 1340 + }, + { + "mboxMarkerOffset": 5789879, + "lineNumber": 82163, + "beginOffset": 5789887, + "headersEndOffset": 5790681, + "endOffset": 5816805, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 82163, + "beginOffset": 5789887, + "headersEndOffset": 5790681, + "endOffset": 5816805, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 82180, + "beginOffset": 5790752, + "headersEndOffset": 5790828, + "endOffset": 5791198, + "octets": 370, + "lines": 13 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 82198, + "beginOffset": 5791224, + "headersEndOffset": 5791314, + "endOffset": 5816777, + "message": { + "lineNumber": 82202, + "beginOffset": 5791314, + "headersEndOffset": 5792382, + "endOffset": 5816777, + "body": { + "mimeType": "text/html", + "lineNumber": 82202, + "beginOffset": 5791314, + "headersEndOffset": 5792382, + "endOffset": 5816777, + "octets": 24395, + "lines": 463 + }, + "octets": 24395 + }, + "octets": 25463, + "lines": 477 + } + ], + "octets": 26124, + "lines": 504 + }, + "octets": 26124 + }, + { + "mboxMarkerOffset": 5816806, + "lineNumber": 82683, + "beginOffset": 5816814, + "headersEndOffset": 5817482, + "endOffset": 5839997, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 82683, + "beginOffset": 5816814, + "headersEndOffset": 5817482, + "endOffset": 5839997, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 82700, + "beginOffset": 5817576, + "headersEndOffset": 5817654, + "endOffset": 5817688, + "octets": 34, + "lines": 1 + }, + { + "mimeType": "image/gif", + "lineNumber": 82706, + "beginOffset": 5817737, + "headersEndOffset": 5817796, + "endOffset": 5839947, + "octets": 22151, + "lines": 304 + } + ], + "octets": 22515, + "lines": 317 + }, + "octets": 22515 + }, + { + "mboxMarkerOffset": 5839998, + "lineNumber": 83015, + "beginOffset": 5840030, + "headersEndOffset": 5840554, + "endOffset": 5842388, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 83015, + "beginOffset": 5840030, + "headersEndOffset": 5840554, + "endOffset": 5842388, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 83029, + "beginOffset": 5840562, + "headersEndOffset": 5840606, + "endOffset": 5841778, + "octets": 1172, + "lines": 21 + }, + { + "mimeType": "text/plain", + "lineNumber": 83054, + "beginOffset": 5841787, + "headersEndOffset": 5841913, + "endOffset": 5842059, + "octets": 146, + "lines": 3 + }, + { + "mimeType": "text/plain", + "lineNumber": 83062, + "beginOffset": 5842068, + "headersEndOffset": 5842184, + "endOffset": 5842378, + "octets": 194, + "lines": 3 + } + ], + "octets": 1834, + "lines": 42 + }, + "octets": 1834 + }, + { + "mboxMarkerOffset": 5842389, + "lineNumber": 83071, + "beginOffset": 5842397, + "headersEndOffset": 5843191, + "endOffset": 6099969, + "body": { + "mimeType": "audio/basic", + "lineNumber": 83071, + "beginOffset": 5842397, + "headersEndOffset": 5843191, + "endOffset": 6099969, + "octets": 256778, + "lines": 3518 + }, + "octets": 256778 + }, + { + "mboxMarkerOffset": 6099970, + "lineNumber": 86609, + "beginOffset": 6099978, + "headersEndOffset": 6100830, + "endOffset": 6199495, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 86609, + "beginOffset": 6099978, + "headersEndOffset": 6100830, + "endOffset": 6199495, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 86630, + "beginOffset": 6100845, + "headersEndOffset": 6100922, + "endOffset": 6101112, + "octets": 190, + "lines": 9 + }, + { + "mimeType": "image/pbm", + "lineNumber": 86643, + "beginOffset": 6101127, + "headersEndOffset": 6101231, + "endOffset": 6199478, + "octets": 98247, + "lines": 1276 + } + ], + "octets": 98665, + "lines": 1296 + }, + "octets": 98665 + }, + { + "mboxMarkerOffset": 6199496, + "lineNumber": 87926, + "beginOffset": 6199504, + "headersEndOffset": 6200381, + "endOffset": 6282825, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 87926, + "beginOffset": 6199504, + "headersEndOffset": 6200381, + "endOffset": 6282825, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 87946, + "beginOffset": 6200390, + "headersEndOffset": 6200436, + "endOffset": 6201379, + "octets": 943, + "lines": 21 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 87971, + "beginOffset": 6201389, + "headersEndOffset": 6201452, + "endOffset": 6282813, + "children": [ + { + "mimeType": "multipart/mixed", + "lineNumber": 87975, + "beginOffset": 6201475, + "headersEndOffset": 6201836, + "endOffset": 6282788, + "children": [ + { + "mimeType": "multipart/mixed", + "lineNumber": 87984, + "beginOffset": 6201858, + "headersEndOffset": 6201960, + "endOffset": 6203889, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 87988, + "beginOffset": 6201982, + "headersEndOffset": 6202105, + "endOffset": 6202471, + "octets": 366, + "lines": 8 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88002, + "beginOffset": 6202494, + "headersEndOffset": 6202616, + "endOffset": 6203008, + "octets": 392, + "lines": 10 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88018, + "beginOffset": 6203031, + "headersEndOffset": 6203156, + "endOffset": 6203864, + "octets": 708, + "lines": 18 + } + ], + "octets": 1929, + "lines": 55 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 88044, + "beginOffset": 6203912, + "headersEndOffset": 6204011, + "endOffset": 6279086, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 88048, + "beginOffset": 6204033, + "headersEndOffset": 6204165, + "endOffset": 6220580, + "octets": 16415, + "lines": 470 + }, + { + "mimeType": "text/richtext", + "lineNumber": 88524, + "beginOffset": 6220603, + "headersEndOffset": 6220734, + "endOffset": 6234988, + "octets": 14254, + "lines": 395 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 88925, + "beginOffset": 6235011, + "headersEndOffset": 6235112, + "endOffset": 6278267, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 88929, + "beginOffset": 6235134, + "headersEndOffset": 6235276, + "endOffset": 6241428, + "octets": 6152, + "lines": 164 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89099, + "beginOffset": 6241451, + "headersEndOffset": 6241578, + "endOffset": 6246833, + "octets": 5255, + "lines": 160 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89265, + "beginOffset": 6246856, + "headersEndOffset": 6246993, + "endOffset": 6254291, + "octets": 7298, + "lines": 197 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89468, + "beginOffset": 6254314, + "headersEndOffset": 6254438, + "endOffset": 6260914, + "octets": 6476, + "lines": 184 + }, + { + "mimeType": "text/richtext", + "lineNumber": 89658, + "beginOffset": 6260937, + "headersEndOffset": 6261074, + "endOffset": 6278242, + "octets": 17168, + "lines": 492 + } + ], + "octets": 43155, + "lines": 1228 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90158, + "beginOffset": 6278290, + "headersEndOffset": 6278385, + "endOffset": 6279061, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90162, + "beginOffset": 6278407, + "headersEndOffset": 6278541, + "endOffset": 6279036, + "octets": 495, + "lines": 21 + } + ], + "octets": 676, + "lines": 28 + } + ], + "octets": 75075, + "lines": 2144 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90193, + "beginOffset": 6279109, + "headersEndOffset": 6279220, + "endOffset": 6282763, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90197, + "beginOffset": 6279242, + "headersEndOffset": 6279380, + "endOffset": 6280529, + "octets": 1149, + "lines": 29 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90232, + "beginOffset": 6280552, + "headersEndOffset": 6280678, + "endOffset": 6281898, + "octets": 1220, + "lines": 35 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90273, + "beginOffset": 6281921, + "headersEndOffset": 6282061, + "endOffset": 6282738, + "octets": 677, + "lines": 22 + } + ], + "octets": 3543, + "lines": 105 + } + ], + "octets": 80952, + "lines": 2320 + } + ], + "octets": 81361, + "lines": 2332 + } + ], + "octets": 82444, + "lines": 2362 + }, + "octets": 82444 + }, + { + "mboxMarkerOffset": 6282826, + "lineNumber": 90309, + "beginOffset": 6282834, + "headersEndOffset": 6283636, + "endOffset": 6292835, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 90309, + "beginOffset": 6282834, + "headersEndOffset": 6283636, + "endOffset": 6292835, + "octets": 9199, + "lines": 226 + }, + "octets": 9199 + }, + { + "mboxMarkerOffset": 6292836, + "lineNumber": 90554, + "beginOffset": 6292844, + "headersEndOffset": 6293572, + "endOffset": 6385847, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 90554, + "beginOffset": 6292844, + "headersEndOffset": 6293572, + "endOffset": 6385847, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 90574, + "beginOffset": 6293767, + "headersEndOffset": 6293811, + "endOffset": 6294567, + "octets": 756, + "lines": 23 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 90601, + "beginOffset": 6294608, + "headersEndOffset": 6294693, + "endOffset": 6385805, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 90605, + "beginOffset": 6294735, + "headersEndOffset": 6294826, + "endOffset": 6295153, + "octets": 327, + "lines": 7 + }, + { + "mimeType": "audio/basic", + "lineNumber": 90617, + "beginOffset": 6295196, + "headersEndOffset": 6295290, + "endOffset": 6317314, + "octets": 22024, + "lines": 320 + }, + { + "mimeType": "text/richtext", + "lineNumber": 90943, + "beginOffset": 6317357, + "headersEndOffset": 6317448, + "endOffset": 6317614, + "octets": 166, + "lines": 5 + }, + { + "mimeType": "audio/basic", + "lineNumber": 90953, + "beginOffset": 6317657, + "headersEndOffset": 6317754, + "endOffset": 6364967, + "octets": 47213, + "lines": 685 + }, + { + "mimeType": "text/richtext", + "lineNumber": 91644, + "beginOffset": 6365010, + "headersEndOffset": 6365101, + "endOffset": 6365171, + "octets": 70, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 91651, + "beginOffset": 6365214, + "headersEndOffset": 6365304, + "endOffset": 6385522, + "octets": 20218, + "lines": 294 + }, + { + "mimeType": "text/richtext", + "lineNumber": 91951, + "beginOffset": 6385565, + "headersEndOffset": 6385656, + "endOffset": 6385760, + "octets": 104, + "lines": 8 + } + ], + "octets": 91112, + "lines": 1360 + } + ], + "octets": 92275, + "lines": 1396 + }, + "octets": 92275 + }, + { + "mboxMarkerOffset": 6385848, + "lineNumber": 91967, + "beginOffset": 6385856, + "headersEndOffset": 6386610, + "endOffset": 6421275, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 91967, + "beginOffset": 6385856, + "headersEndOffset": 6386610, + "endOffset": 6421275, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 91989, + "beginOffset": 6386850, + "headersEndOffset": 6386923, + "endOffset": 6387343, + "octets": 420, + "lines": 13 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 92007, + "beginOffset": 6387389, + "headersEndOffset": 6387450, + "endOffset": 6421014, + "octets": 33564, + "lines": 460 + }, + { + "mimeType": "text/richtext", + "lineNumber": 92472, + "beginOffset": 6421060, + "headersEndOffset": 6421133, + "endOffset": 6421227, + "octets": 94, + "lines": 7 + } + ], + "octets": 34665, + "lines": 500 + }, + "octets": 34665 + }, + { + "mboxMarkerOffset": 6421276, + "lineNumber": 92486, + "beginOffset": 6421318, + "headersEndOffset": 6421466, + "endOffset": 6464495, + "body": { + "mimeType": "text/plain", + "lineNumber": 92486, + "beginOffset": 6421318, + "headersEndOffset": 6421466, + "endOffset": 6464495, + "octets": 43029, + "lines": 693 + }, + "octets": 43029 + }, + { + "mboxMarkerOffset": 6464496, + "lineNumber": 93187, + "beginOffset": 6464528, + "headersEndOffset": 6465111, + "endOffset": 6490367, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93187, + "beginOffset": 6464528, + "headersEndOffset": 6465111, + "endOffset": 6490367, + "children": [ + { + "mimeType": "multipart/alternative", + "lineNumber": 93205, + "beginOffset": 6465196, + "headersEndOffset": 6465314, + "endOffset": 6469330, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93210, + "beginOffset": 6465354, + "headersEndOffset": 6465432, + "endOffset": 6466704, + "octets": 1272, + "lines": 38 + }, + { + "mimeType": "text/html", + "lineNumber": 93253, + "beginOffset": 6466744, + "headersEndOffset": 6466823, + "endOffset": 6469287, + "octets": 2464, + "lines": 32 + } + ], + "octets": 4016, + "lines": 83 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 93293, + "beginOffset": 6469370, + "headersEndOffset": 6469575, + "endOffset": 6490325, + "octets": 20750, + "lines": 270 + } + ], + "octets": 25256, + "lines": 368 + }, + "octets": 25256 + }, + { + "mboxMarkerOffset": 6490368, + "lineNumber": 93572, + "beginOffset": 6490400, + "headersEndOffset": 6490806, + "endOffset": 6493572, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93572, + "beginOffset": 6490400, + "headersEndOffset": 6490806, + "endOffset": 6493572, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93586, + "beginOffset": 6490872, + "headersEndOffset": 6490873, + "endOffset": 6490936, + "octets": 63, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93590, + "beginOffset": 6490957, + "headersEndOffset": 6491031, + "endOffset": 6492741, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93593, + "beginOffset": 6491058, + "headersEndOffset": 6491164, + "endOffset": 6491244, + "octets": 80, + "lines": 3 + }, + { + "mimeType": "text/richtext", + "lineNumber": 93602, + "beginOffset": 6491272, + "headersEndOffset": 6491381, + "endOffset": 6491539, + "octets": 158, + "lines": 4 + }, + { + "mimeType": "text/enriched", + "lineNumber": 93612, + "beginOffset": 6491567, + "headersEndOffset": 6491676, + "endOffset": 6491839, + "octets": 163, + "lines": 10 + }, + { + "mimeType": "text/html", + "lineNumber": 93628, + "beginOffset": 6491867, + "headersEndOffset": 6491972, + "endOffset": 6492133, + "octets": 161, + "lines": 3 + }, + { + "mimeType": "text/something-you-dont-know", + "lineNumber": 93637, + "beginOffset": 6492161, + "headersEndOffset": 6492285, + "endOffset": 6492712, + "octets": 427, + "lines": 6 + } + ], + "octets": 1710, + "lines": 57 + }, + { + "mimeType": "text/plain", + "lineNumber": 93650, + "beginOffset": 6492762, + "headersEndOffset": 6492763, + "endOffset": 6492928, + "octets": 165, + "lines": 4 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93657, + "beginOffset": 6492949, + "headersEndOffset": 6492999, + "endOffset": 6493519, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93660, + "beginOffset": 6493004, + "headersEndOffset": 6493030, + "endOffset": 6493083, + "octets": 53, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93665, + "beginOffset": 6493089, + "headersEndOffset": 6493139, + "endOffset": 6493399, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93668, + "beginOffset": 6493144, + "headersEndOffset": 6493170, + "endOffset": 6493223, + "octets": 53, + "lines": 1 + }, + { + "mimeType": "text/html", + "lineNumber": 93673, + "beginOffset": 6493229, + "headersEndOffset": 6493254, + "endOffset": 6493304, + "octets": 50, + "lines": 1 + }, + { + "mimeType": "text/x-barf", + "lineNumber": 93678, + "beginOffset": 6493310, + "headersEndOffset": 6493337, + "endOffset": 6493391, + "octets": 54, + "lines": 1 + } + ], + "octets": 260, + "lines": 16 + }, + { + "mimeType": "application/spankme", + "lineNumber": 93685, + "beginOffset": 6493405, + "headersEndOffset": 6493497, + "endOffset": 6493512, + "octets": 15, + "lines": 1 + } + ], + "octets": 520, + "lines": 32 + }, + { + "mimeType": "text/plain", + "lineNumber": 93692, + "beginOffset": 6493540, + "headersEndOffset": 6493541, + "endOffset": 6493550, + "octets": 9, + "lines": 1 + } + ], + "octets": 2766, + "lines": 113 + }, + "octets": 2766 + }, + { + "mboxMarkerOffset": 6493573, + "lineNumber": 93697, + "beginOffset": 6493605, + "headersEndOffset": 6494009, + "endOffset": 6844507, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 93697, + "beginOffset": 6493605, + "headersEndOffset": 6494009, + "endOffset": 6844507, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93711, + "beginOffset": 6494075, + "headersEndOffset": 6494076, + "endOffset": 6494143, + "octets": 67, + "lines": 1 + }, + { + "mimeType": "multipart/alternative", + "lineNumber": 93715, + "beginOffset": 6494164, + "headersEndOffset": 6494238, + "endOffset": 6844479, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 93718, + "beginOffset": 6494265, + "headersEndOffset": 6494421, + "endOffset": 6549684, + "octets": 55263, + "lines": 1603 + }, + { + "mimeType": "text/html", + "lineNumber": 95327, + "beginOffset": 6549712, + "headersEndOffset": 6549867, + "endOffset": 6655916, + "octets": 106049, + "lines": 2982 + }, + { + "mimeType": "application/postscript", + "lineNumber": 98315, + "beginOffset": 6655944, + "headersEndOffset": 6656090, + "endOffset": 6844449, + "octets": 188359, + "lines": 13109 + } + ], + "octets": 350241, + "lines": 17713 + } + ], + "octets": 350498, + "lines": 17726 + }, + "octets": 350498 + }, + { + "mboxMarkerOffset": 6844508, + "lineNumber": 111435, + "beginOffset": 6844516, + "headersEndOffset": 6845120, + "endOffset": 6846556, + "body": { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 111435, + "beginOffset": 6844516, + "headersEndOffset": 6845120, + "endOffset": 6846556, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 111453, + "beginOffset": 6845376, + "headersEndOffset": 6845488, + "endOffset": 6845488, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 111458, + "beginOffset": 6845529, + "headersEndOffset": 6845627, + "endOffset": 6846514, + "message": { + "lineNumber": 111461, + "beginOffset": 6845627, + "headersEndOffset": 6846168, + "endOffset": 6846514, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 111461, + "beginOffset": 6845627, + "headersEndOffset": 6846168, + "endOffset": 6846514, + "octets": 346, + "lines": 16 + }, + "octets": 346 + }, + "octets": 887, + "lines": 28 + } + ], + "octets": 1436, + "lines": 43 + }, + "octets": 1436 + }, + { + "mboxMarkerOffset": 6846557, + "lineNumber": 111492, + "beginOffset": 6846565, + "headersEndOffset": 6846861, + "endOffset": 6858989, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111492, + "beginOffset": 6846565, + "headersEndOffset": 6846861, + "endOffset": 6858989, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111502, + "beginOffset": 6846900, + "headersEndOffset": 6847146, + "endOffset": 6847865, + "octets": 719, + "lines": 30 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 111541, + "beginOffset": 6847905, + "headersEndOffset": 6848225, + "endOffset": 6858948, + "octets": 10723, + "lines": 147 + } + ], + "octets": 12128, + "lines": 197 + }, + "octets": 12128 + }, + { + "mboxMarkerOffset": 6858990, + "lineNumber": 111699, + "beginOffset": 6858998, + "headersEndOffset": 6859294, + "endOffset": 6871390, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111699, + "beginOffset": 6858998, + "headersEndOffset": 6859294, + "endOffset": 6871390, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111709, + "beginOffset": 6859333, + "headersEndOffset": 6859579, + "endOffset": 6860297, + "octets": 718, + "lines": 30 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 111748, + "beginOffset": 6860337, + "headersEndOffset": 6860626, + "endOffset": 6871349, + "octets": 10723, + "lines": 147 + } + ], + "octets": 12096, + "lines": 197 + }, + "octets": 12096 + }, + { + "mboxMarkerOffset": 6871391, + "lineNumber": 111906, + "beginOffset": 6871423, + "headersEndOffset": 6872926, + "endOffset": 6879481, + "body": { + "mimeType": "multipart/related", + "lineNumber": 111906, + "beginOffset": 6871423, + "headersEndOffset": 6872926, + "endOffset": 6879481, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 111934, + "beginOffset": 6872971, + "headersEndOffset": 6873062, + "endOffset": 6878261, + "octets": 5199, + "lines": 111 + }, + { + "mimeType": "image/gif", + "lineNumber": 112050, + "beginOffset": 6878306, + "headersEndOffset": 6878505, + "endOffset": 6879434, + "octets": 929, + "lines": 13 + } + ], + "octets": 6555, + "lines": 139 + }, + "octets": 6555 + }, + { + "mboxMarkerOffset": 6879482, + "lineNumber": 112073, + "beginOffset": 6879514, + "headersEndOffset": 6879961, + "endOffset": 7094537, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 112073, + "beginOffset": 6879514, + "headersEndOffset": 6879961, + "endOffset": 7094537, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 112086, + "beginOffset": 6880000, + "headersEndOffset": 6880026, + "endOffset": 6880273, + "octets": 247, + "lines": 6 + }, + { + "mimeType": "multipart/related", + "lineNumber": 112096, + "beginOffset": 6880313, + "headersEndOffset": 6880399, + "endOffset": 7094496, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 112100, + "beginOffset": 6880438, + "headersEndOffset": 6880632, + "endOffset": 6887780, + "octets": 7148, + "lines": 179 + }, + { + "mimeType": "image/gif", + "lineNumber": 112286, + "beginOffset": 6887820, + "headersEndOffset": 6887996, + "endOffset": 6895977, + "octets": 7981, + "lines": 110 + }, + { + "mimeType": "image/gif", + "lineNumber": 112402, + "beginOffset": 6896017, + "headersEndOffset": 6896176, + "endOffset": 6903630, + "octets": 7454, + "lines": 103 + }, + { + "mimeType": "image/gif", + "lineNumber": 112511, + "beginOffset": 6903670, + "headersEndOffset": 6903828, + "endOffset": 6907161, + "octets": 3333, + "lines": 46 + }, + { + "mimeType": "image/gif", + "lineNumber": 112563, + "beginOffset": 6907201, + "headersEndOffset": 6907360, + "endOffset": 6915811, + "octets": 8451, + "lines": 116 + }, + { + "mimeType": "image/gif", + "lineNumber": 112685, + "beginOffset": 6915851, + "headersEndOffset": 6916007, + "endOffset": 7020376, + "octets": 104369, + "lines": 1430 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 114121, + "beginOffset": 7020416, + "headersEndOffset": 7020575, + "endOffset": 7058936, + "octets": 38361, + "lines": 526 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 114653, + "beginOffset": 7058976, + "headersEndOffset": 7059140, + "endOffset": 7094455, + "octets": 35315, + "lines": 484 + } + ], + "octets": 214097, + "lines": 3044 + } + ], + "octets": 214576, + "lines": 3059 + }, + "octets": 214576 + }, + { + "mboxMarkerOffset": 7094538, + "lineNumber": 115145, + "beginOffset": 7094546, + "headersEndOffset": 7094841, + "endOffset": 7106504, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115145, + "beginOffset": 7094546, + "headersEndOffset": 7094841, + "endOffset": 7106504, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115155, + "beginOffset": 7094880, + "headersEndOffset": 7095036, + "endOffset": 7095587, + "octets": 551, + "lines": 27 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115189, + "beginOffset": 7095627, + "headersEndOffset": 7095740, + "endOffset": 7106463, + "octets": 10723, + "lines": 147 + } + ], + "octets": 11663, + "lines": 188 + }, + "octets": 11663 + }, + { + "mboxMarkerOffset": 7106505, + "lineNumber": 115343, + "beginOffset": 7106513, + "headersEndOffset": 7106808, + "endOffset": 7118734, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115343, + "beginOffset": 7106513, + "headersEndOffset": 7106808, + "endOffset": 7118734, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115353, + "beginOffset": 7106847, + "headersEndOffset": 7107059, + "endOffset": 7107656, + "octets": 597, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115389, + "beginOffset": 7107696, + "headersEndOffset": 7107970, + "endOffset": 7118693, + "octets": 10723, + "lines": 147 + } + ], + "octets": 11926, + "lines": 193 + }, + "octets": 11926 + }, + { + "mboxMarkerOffset": 7118735, + "lineNumber": 115546, + "beginOffset": 7118743, + "headersEndOffset": 7119038, + "endOffset": 7130873, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115546, + "beginOffset": 7118743, + "headersEndOffset": 7119038, + "endOffset": 7130873, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115556, + "beginOffset": 7119077, + "headersEndOffset": 7119293, + "endOffset": 7119894, + "octets": 601, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115592, + "beginOffset": 7119934, + "headersEndOffset": 7120109, + "endOffset": 7130832, + "octets": 10723, + "lines": 147 + } + ], + "octets": 11835, + "lines": 191 + }, + "octets": 11835 + }, + { + "mboxMarkerOffset": 7130874, + "lineNumber": 115747, + "beginOffset": 7130882, + "headersEndOffset": 7131177, + "endOffset": 7143201, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115747, + "beginOffset": 7130882, + "headersEndOffset": 7131177, + "endOffset": 7143201, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115757, + "beginOffset": 7131216, + "headersEndOffset": 7131461, + "endOffset": 7132092, + "octets": 631, + "lines": 29 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115795, + "beginOffset": 7132132, + "headersEndOffset": 7132437, + "endOffset": 7143160, + "octets": 10723, + "lines": 147 + } + ], + "octets": 12024, + "lines": 196 + }, + "octets": 12024 + }, + { + "mboxMarkerOffset": 7143202, + "lineNumber": 115953, + "beginOffset": 7143210, + "headersEndOffset": 7143505, + "endOffset": 7155384, + "body": { + "mimeType": "multipart/related", + "lineNumber": 115953, + "beginOffset": 7143210, + "headersEndOffset": 7143505, + "endOffset": 7155384, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 115963, + "beginOffset": 7143544, + "headersEndOffset": 7143760, + "endOffset": 7144405, + "octets": 645, + "lines": 28 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 115999, + "beginOffset": 7144445, + "headersEndOffset": 7144620, + "endOffset": 7155343, + "octets": 10723, + "lines": 147 + } + ], + "octets": 11879, + "lines": 191 + }, + "octets": 11879 + }, + { + "mboxMarkerOffset": 7155385, + "lineNumber": 116154, + "beginOffset": 7155393, + "headersEndOffset": 7155688, + "endOffset": 7167782, + "body": { + "mimeType": "multipart/related", + "lineNumber": 116154, + "beginOffset": 7155393, + "headersEndOffset": 7155688, + "endOffset": 7167782, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 116164, + "beginOffset": 7155727, + "headersEndOffset": 7155972, + "endOffset": 7156642, + "octets": 670, + "lines": 29 + }, + { + "mimeType": "image/jpeg", + "lineNumber": 116202, + "beginOffset": 7156682, + "headersEndOffset": 7157018, + "endOffset": 7167741, + "octets": 10723, + "lines": 147 + } + ], + "octets": 12094, + "lines": 196 + }, + "octets": 12094 + }, + { + "mboxMarkerOffset": 7167783, + "lineNumber": 116360, + "beginOffset": 7167815, + "headersEndOffset": 7169049, + "endOffset": 7916334, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 116360, + "beginOffset": 7167815, + "headersEndOffset": 7169049, + "endOffset": 7916334, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 116385, + "beginOffset": 7169133, + "headersEndOffset": 7169209, + "endOffset": 7169236, + "octets": 27, + "lines": 3 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 116393, + "beginOffset": 7169275, + "headersEndOffset": 7169365, + "endOffset": 7916293, + "message": { + "lineNumber": 116397, + "beginOffset": 7169365, + "headersEndOffset": 7170186, + "endOffset": 7916293, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 116397, + "beginOffset": 7169365, + "headersEndOffset": 7170186, + "endOffset": 7916293, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 116415, + "beginOffset": 7170226, + "headersEndOffset": 7170302, + "endOffset": 7170929, + "octets": 627, + "lines": 16 + }, + { + "mimeType": "multipart/related", + "lineNumber": 116436, + "beginOffset": 7170969, + "headersEndOffset": 7171051, + "endOffset": 7916249, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 116440, + "beginOffset": 7171091, + "headersEndOffset": 7171166, + "endOffset": 7172016, + "octets": 850, + "lines": 18 + }, + { + "mimeType": "image/tiff", + "lineNumber": 116463, + "beginOffset": 7172056, + "headersEndOffset": 7172240, + "endOffset": 7916207, + "octets": 743967, + "lines": 10192 + } + ], + "octets": 745198, + "lines": 10223 + } + ], + "octets": 746107, + "lines": 10252 + }, + "octets": 746107 + }, + "octets": 746928, + "lines": 10268 + } + ], + "octets": 747285, + "lines": 10285 + }, + "octets": 747285 + }, + { + "mboxMarkerOffset": 7916335, + "lineNumber": 126669, + "beginOffset": 7916367, + "headersEndOffset": 7917631, + "endOffset": 7964259, + "body": { + "mimeType": "multipart/related", + "lineNumber": 126669, + "beginOffset": 7916367, + "headersEndOffset": 7917631, + "endOffset": 7964259, + "children": [ + { + "mimeType": "text/html", + "lineNumber": 126693, + "beginOffset": 7917676, + "headersEndOffset": 7917767, + "endOffset": 7920149, + "octets": 2382, + "lines": 50 + }, + { + "mimeType": "image/gif", + "lineNumber": 126748, + "beginOffset": 7920194, + "headersEndOffset": 7920353, + "endOffset": 7926376, + "octets": 6023, + "lines": 79 + }, + { + "mimeType": "image/gif", + "lineNumber": 126834, + "beginOffset": 7926421, + "headersEndOffset": 7926579, + "endOffset": 7938652, + "octets": 12073, + "lines": 157 + }, + { + "mimeType": "image/gif", + "lineNumber": 126998, + "beginOffset": 7938697, + "headersEndOffset": 7938857, + "endOffset": 7960571, + "octets": 21714, + "lines": 282 + }, + { + "mimeType": "image/gif", + "lineNumber": 127287, + "beginOffset": 7960616, + "headersEndOffset": 7960819, + "endOffset": 7964212, + "octets": 3393, + "lines": 45 + } + ], + "octets": 46628, + "lines": 649 + }, + "octets": 46628 + }, + { + "mboxMarkerOffset": 7964260, + "lineNumber": 127342, + "beginOffset": 7964268, + "headersEndOffset": 7965009, + "endOffset": 8509625, + "body": { + "mimeType": "audio/basic", + "lineNumber": 127342, + "beginOffset": 7964268, + "headersEndOffset": 7965009, + "endOffset": 8509625, + "octets": 544616, + "lines": 7474 + }, + "octets": 544616 + }, + { + "mboxMarkerOffset": 8509626, + "lineNumber": 134835, + "beginOffset": 8509634, + "headersEndOffset": 8510545, + "endOffset": 8513124, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 134835, + "beginOffset": 8509634, + "headersEndOffset": 8510545, + "endOffset": 8513124, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 134858, + "beginOffset": 8510554, + "headersEndOffset": 8510583, + "endOffset": 8513113, + "octets": 2530, + "lines": 96 + } + ], + "octets": 2579, + "lines": 102 + }, + "octets": 2579 + }, + { + "mboxMarkerOffset": 8513125, + "lineNumber": 134960, + "beginOffset": 8513157, + "headersEndOffset": 8513751, + "endOffset": 8515537, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 134960, + "beginOffset": 8513157, + "headersEndOffset": 8513751, + "endOffset": 8515537, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 134984, + "beginOffset": 8514048, + "headersEndOffset": 8514093, + "endOffset": 8515175, + "octets": 1082, + "lines": 26 + }, + { + "mimeType": "application/pgp-signature", + "lineNumber": 135014, + "beginOffset": 8515193, + "headersEndOffset": 8515234, + "endOffset": 8515518, + "octets": 284, + "lines": 9 + } + ], + "octets": 1786, + "lines": 51 + }, + "octets": 1786 + }, + { + "mboxMarkerOffset": 8515538, + "lineNumber": 135028, + "beginOffset": 8515546, + "headersEndOffset": 8516708, + "endOffset": 8518091, + "body": { + "mimeType": "application/pgp", + "lineNumber": 135028, + "beginOffset": 8515546, + "headersEndOffset": 8516708, + "endOffset": 8518091, + "octets": 1383, + "lines": 40 + }, + "octets": 1383 + }, + { + "mboxMarkerOffset": 8518092, + "lineNumber": 135090, + "beginOffset": 8518100, + "headersEndOffset": 8518733, + "endOffset": 8519707, + "body": { + "mimeType": "text/plain", + "lineNumber": 135090, + "beginOffset": 8518100, + "headersEndOffset": 8518733, + "endOffset": 8519707, + "octets": 974, + "lines": 27 + }, + "octets": 974 + }, + { + "mboxMarkerOffset": 8519708, + "lineNumber": 135136, + "beginOffset": 8519716, + "headersEndOffset": 8520478, + "endOffset": 8523391, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135136, + "beginOffset": 8519716, + "headersEndOffset": 8520478, + "endOffset": 8523391, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135158, + "beginOffset": 8520673, + "headersEndOffset": 8520717, + "endOffset": 8521534, + "octets": 817, + "lines": 15 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135177, + "beginOffset": 8521575, + "headersEndOffset": 8521660, + "endOffset": 8523348, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135181, + "beginOffset": 8521702, + "headersEndOffset": 8521793, + "endOffset": 8522284, + "octets": 491, + "lines": 10 + }, + { + "mimeType": "message/external-body", + "lineNumber": 135196, + "beginOffset": 8522327, + "headersEndOffset": 8522513, + "endOffset": 8522542, + "message": { + "lineNumber": 135203, + "beginOffset": 8522513, + "headersEndOffset": 8522540, + "endOffset": 8522542, + "body": { + "mimeType": "audio/basic", + "lineNumber": 135203, + "beginOffset": 8522513, + "headersEndOffset": 8522540, + "endOffset": 8522542, + "octets": 2, + "lines": 2 + }, + "octets": 2 + }, + "octets": 29, + "lines": 4 + }, + { + "mimeType": "text/plain", + "lineNumber": 135209, + "beginOffset": 8522585, + "headersEndOffset": 8522673, + "endOffset": 8522676, + "octets": 3, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 135216, + "beginOffset": 8522719, + "headersEndOffset": 8522920, + "endOffset": 8522947, + "message": { + "lineNumber": 135223, + "beginOffset": 8522920, + "headersEndOffset": 8522945, + "endOffset": 8522947, + "body": { + "mimeType": "image/gif", + "lineNumber": 135223, + "beginOffset": 8522920, + "headersEndOffset": 8522945, + "endOffset": 8522947, + "octets": 2, + "lines": 2 + }, + "octets": 2 + }, + "octets": 27, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135229, + "beginOffset": 8522990, + "headersEndOffset": 8523081, + "endOffset": 8523303, + "octets": 222, + "lines": 7 + } + ], + "octets": 1688, + "lines": 61 + } + ], + "octets": 2913, + "lines": 89 + }, + "octets": 2913 + }, + { + "mboxMarkerOffset": 8523392, + "lineNumber": 135245, + "beginOffset": 8523400, + "headersEndOffset": 8524214, + "endOffset": 8525600, + "body": { + "mimeType": "text/richtext", + "lineNumber": 135245, + "beginOffset": 8523400, + "headersEndOffset": 8524214, + "endOffset": 8525600, + "octets": 1386, + "lines": 42 + }, + "octets": 1386 + }, + { + "mboxMarkerOffset": 8525601, + "lineNumber": 135307, + "beginOffset": 8525609, + "headersEndOffset": 8525761, + "endOffset": 8530432, + "body": { + "mimeType": "message/partial", + "lineNumber": 135307, + "beginOffset": 8525609, + "headersEndOffset": 8525761, + "endOffset": 8530432, + "octets": 4671, + "lines": 64 + }, + "octets": 4671 + }, + { + "mboxMarkerOffset": 8530433, + "lineNumber": 135377, + "beginOffset": 8530441, + "headersEndOffset": 8532184, + "endOffset": 8543555, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135377, + "beginOffset": 8530441, + "headersEndOffset": 8532184, + "endOffset": 8543555, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135416, + "beginOffset": 8532379, + "headersEndOffset": 8532423, + "endOffset": 8534090, + "octets": 1667, + "lines": 38 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135458, + "beginOffset": 8534131, + "headersEndOffset": 8534216, + "endOffset": 8543512, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135462, + "beginOffset": 8534258, + "headersEndOffset": 8534349, + "endOffset": 8534906, + "octets": 557, + "lines": 14 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135481, + "beginOffset": 8534949, + "headersEndOffset": 8535010, + "endOffset": 8535882, + "octets": 872, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135498, + "beginOffset": 8535925, + "headersEndOffset": 8536016, + "endOffset": 8536062, + "octets": 46, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135508, + "beginOffset": 8536105, + "headersEndOffset": 8536166, + "endOffset": 8537038, + "octets": 872, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135525, + "beginOffset": 8537081, + "headersEndOffset": 8537172, + "endOffset": 8537218, + "octets": 46, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135535, + "beginOffset": 8537261, + "headersEndOffset": 8537322, + "endOffset": 8538194, + "octets": 872, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135552, + "beginOffset": 8538237, + "headersEndOffset": 8538328, + "endOffset": 8538368, + "octets": 40, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135562, + "beginOffset": 8538411, + "headersEndOffset": 8538472, + "endOffset": 8538696, + "octets": 224, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135571, + "beginOffset": 8538739, + "headersEndOffset": 8538830, + "endOffset": 8538894, + "octets": 64, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135581, + "beginOffset": 8538937, + "headersEndOffset": 8538998, + "endOffset": 8539222, + "octets": 224, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135590, + "beginOffset": 8539265, + "headersEndOffset": 8539356, + "endOffset": 8539400, + "octets": 44, + "lines": 5 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135600, + "beginOffset": 8539443, + "headersEndOffset": 8539504, + "endOffset": 8539728, + "octets": 224, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135609, + "beginOffset": 8539771, + "headersEndOffset": 8539862, + "endOffset": 8540154, + "octets": 292, + "lines": 11 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135625, + "beginOffset": 8540197, + "headersEndOffset": 8540258, + "endOffset": 8541130, + "octets": 872, + "lines": 12 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135642, + "beginOffset": 8541173, + "headersEndOffset": 8541264, + "endOffset": 8541304, + "octets": 40, + "lines": 4 + }, + { + "mimeType": "image/x-xwd", + "lineNumber": 135651, + "beginOffset": 8541347, + "headersEndOffset": 8541408, + "endOffset": 8543323, + "octets": 1915, + "lines": 27 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135683, + "beginOffset": 8543366, + "headersEndOffset": 8543457, + "endOffset": 8543467, + "octets": 10, + "lines": 1 + } + ], + "octets": 9296, + "lines": 228 + } + ], + "octets": 11371, + "lines": 279 + }, + "octets": 11371 + }, + { + "mboxMarkerOffset": 8543556, + "lineNumber": 135693, + "beginOffset": 8543564, + "headersEndOffset": 8544292, + "endOffset": 8554952, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 135693, + "beginOffset": 8543564, + "headersEndOffset": 8544292, + "endOffset": 8554952, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135713, + "beginOffset": 8544487, + "headersEndOffset": 8544531, + "endOffset": 8545158, + "octets": 627, + "lines": 12 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 135729, + "beginOffset": 8545199, + "headersEndOffset": 8545284, + "endOffset": 8554910, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 135733, + "beginOffset": 8545326, + "headersEndOffset": 8545417, + "endOffset": 8545950, + "octets": 533, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 135746, + "beginOffset": 8545993, + "headersEndOffset": 8546101, + "endOffset": 8554686, + "octets": 8585, + "lines": 125 + }, + { + "mimeType": "text/richtext", + "lineNumber": 135877, + "beginOffset": 8554729, + "headersEndOffset": 8554820, + "endOffset": 8554865, + "octets": 45, + "lines": 3 + } + ], + "octets": 9626, + "lines": 153 + } + ], + "octets": 10660, + "lines": 178 + }, + "octets": 10660 + }, + { + "mboxMarkerOffset": 8554953, + "lineNumber": 135888, + "beginOffset": 8554961, + "headersEndOffset": 8555607, + "endOffset": 8634515, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 135888, + "beginOffset": 8554961, + "headersEndOffset": 8555607, + "endOffset": 8634515, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 135905, + "beginOffset": 8555657, + "headersEndOffset": 8555747, + "endOffset": 8555844, + "octets": 97, + "lines": 6 + }, + { + "mimeType": "audio/basic", + "lineNumber": 135916, + "beginOffset": 8555894, + "headersEndOffset": 8556021, + "endOffset": 8634463, + "octets": 78442, + "lines": 1075 + } + ], + "octets": 78908, + "lines": 1093 + }, + "octets": 78908 + }, + { + "mboxMarkerOffset": 8634516, + "lineNumber": 136998, + "beginOffset": 8634524, + "headersEndOffset": 8635280, + "endOffset": 8820549, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 136998, + "beginOffset": 8634524, + "headersEndOffset": 8635280, + "endOffset": 8820549, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 137019, + "beginOffset": 8635475, + "headersEndOffset": 8635519, + "endOffset": 8636869, + "octets": 1350, + "lines": 28 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 137051, + "beginOffset": 8636910, + "headersEndOffset": 8636995, + "endOffset": 8820507, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 137055, + "beginOffset": 8637037, + "headersEndOffset": 8637128, + "endOffset": 8638267, + "octets": 1139, + "lines": 22 + }, + { + "mimeType": "audio/basic", + "lineNumber": 137082, + "beginOffset": 8638310, + "headersEndOffset": 8638408, + "endOffset": 8753651, + "octets": 115243, + "lines": 1579 + }, + { + "mimeType": "text/richtext", + "lineNumber": 138667, + "beginOffset": 8753694, + "headersEndOffset": 8753785, + "endOffset": 8753908, + "octets": 123, + "lines": 3 + }, + { + "mimeType": "image/gif", + "lineNumber": 138675, + "beginOffset": 8753951, + "headersEndOffset": 8754050, + "endOffset": 8820331, + "octets": 66281, + "lines": 961 + }, + { + "mimeType": "text/plain", + "lineNumber": 139642, + "beginOffset": 8820374, + "headersEndOffset": 8820462, + "endOffset": 8820462, + "octets": 0, + "lines": 0 + } + ], + "octets": 183512, + "lines": 2593 + } + ], + "octets": 185269, + "lines": 2634 + }, + "octets": 185269 + }, + { + "mboxMarkerOffset": 8820550, + "lineNumber": 139650, + "beginOffset": 8820558, + "headersEndOffset": 8821395, + "endOffset": 8823128, + "body": { + "mimeType": "application/x-pkcs", + "lineNumber": 139650, + "beginOffset": 8820558, + "headersEndOffset": 8821395, + "endOffset": 8823128, + "octets": 1733, + "lines": 25 + }, + "octets": 1733 + }, + { + "mboxMarkerOffset": 8823129, + "lineNumber": 139696, + "beginOffset": 8823137, + "headersEndOffset": 8823767, + "endOffset": 8825125, + "body": { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 139696, + "beginOffset": 8823137, + "headersEndOffset": 8823767, + "endOffset": 8825125, + "message": { + "lineNumber": 139710, + "beginOffset": 8823767, + "headersEndOffset": 8824250, + "endOffset": 8825125, + "body": { + "mimeType": "TEXT/PLAIN", + "lineNumber": 139710, + "beginOffset": 8823767, + "headersEndOffset": 8824250, + "endOffset": 8825125, + "octets": 875, + "lines": 25 + }, + "octets": 875 + }, + "octets": 1358, + "lines": 38 + }, + "octets": 1358 + }, + { + "mboxMarkerOffset": 8825126, + "lineNumber": 139749, + "beginOffset": 8825134, + "headersEndOffset": 8825579, + "endOffset": 8916963, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 139749, + "beginOffset": 8825134, + "headersEndOffset": 8825579, + "endOffset": 8916963, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 139763, + "beginOffset": 8825588, + "headersEndOffset": 8825589, + "endOffset": 8825629, + "octets": 40, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 139767, + "beginOffset": 8825639, + "headersEndOffset": 8825700, + "endOffset": 8916949, + "octets": 91249, + "lines": 1250 + } + ], + "octets": 91384, + "lines": 1261 + }, + "octets": 91384 + }, + { + "mboxMarkerOffset": 8916964, + "lineNumber": 141025, + "beginOffset": 8916972, + "headersEndOffset": 8917462, + "endOffset": 8918604, + "body": { + "mimeType": "text/plain", + "lineNumber": 141025, + "beginOffset": 8916972, + "headersEndOffset": 8917462, + "endOffset": 8918604, + "octets": 1142, + "lines": 27 + }, + "octets": 1142 + }, + { + "mboxMarkerOffset": 8918605, + "lineNumber": 141066, + "beginOffset": 8918613, + "headersEndOffset": 8919753, + "endOffset": 9013870, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 141066, + "beginOffset": 8918613, + "headersEndOffset": 8919753, + "endOffset": 9013870, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 141092, + "beginOffset": 8919758, + "headersEndOffset": 8919759, + "endOffset": 8920299, + "octets": 540, + "lines": 12 + }, + { + "mimeType": "image/gif", + "lineNumber": 141107, + "beginOffset": 8920305, + "headersEndOffset": 8920421, + "endOffset": 8978062, + "octets": 57641, + "lines": 790 + }, + { + "mimeType": "text/plain", + "lineNumber": 141902, + "beginOffset": 8978068, + "headersEndOffset": 8978069, + "endOffset": 8981852, + "octets": 3783, + "lines": 83 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 141988, + "beginOffset": 8981858, + "headersEndOffset": 8982012, + "endOffset": 9011647, + "octets": 29635, + "lines": 1010 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 143003, + "beginOffset": 9011653, + "headersEndOffset": 9011759, + "endOffset": 9012475, + "octets": 716, + "lines": 24 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 143032, + "beginOffset": 9012481, + "headersEndOffset": 9012598, + "endOffset": 9013862, + "octets": 1264, + "lines": 25 + } + ], + "octets": 94117, + "lines": 1970 + }, + "octets": 94117 + }, + { + "mboxMarkerOffset": 9013871, + "lineNumber": 143063, + "beginOffset": 9013903, + "headersEndOffset": 9015056, + "endOffset": 9016840, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 143063, + "beginOffset": 9013903, + "headersEndOffset": 9015056, + "endOffset": 9016840, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143082, + "beginOffset": 9015073, + "headersEndOffset": 9015074, + "endOffset": 9015975, + "octets": 901, + "lines": 20 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 143105, + "beginOffset": 9015993, + "headersEndOffset": 9016072, + "endOffset": 9016820, + "octets": 748, + "lines": 12 + } + ], + "octets": 1784, + "lines": 41 + }, + "octets": 1784 + }, + { + "mboxMarkerOffset": 9016841, + "lineNumber": 143124, + "beginOffset": 9016873, + "headersEndOffset": 9018015, + "endOffset": 9021424, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 143124, + "beginOffset": 9016873, + "headersEndOffset": 9018015, + "endOffset": 9021424, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143147, + "beginOffset": 9018195, + "headersEndOffset": 9018273, + "endOffset": 9019014, + "octets": 741, + "lines": 14 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143165, + "beginOffset": 9019022, + "headersEndOffset": 9019200, + "endOffset": 9021415, + "octets": 2215, + "lines": 31 + } + ], + "octets": 3409, + "lines": 60 + }, + "octets": 3409 + }, + { + "mboxMarkerOffset": 9021425, + "lineNumber": 143204, + "beginOffset": 9021457, + "headersEndOffset": 9022594, + "endOffset": 9028448, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 143204, + "beginOffset": 9021457, + "headersEndOffset": 9022594, + "endOffset": 9028448, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 143231, + "beginOffset": 9022788, + "headersEndOffset": 9022866, + "endOffset": 9025678, + "octets": 2812, + "lines": 47 + }, + { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143282, + "beginOffset": 9025700, + "headersEndOffset": 9025878, + "endOffset": 9028425, + "octets": 2547, + "lines": 35 + } + ], + "octets": 5854, + "lines": 97 + }, + "octets": 5854 + }, + { + "mboxMarkerOffset": 9028449, + "lineNumber": 143325, + "beginOffset": 9028457, + "headersEndOffset": 9028665, + "endOffset": 9032858, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143325, + "beginOffset": 9028457, + "headersEndOffset": 9028665, + "endOffset": 9032858, + "octets": 4193, + "lines": 58 + }, + "octets": 4193 + }, + { + "mboxMarkerOffset": 9032859, + "lineNumber": 143391, + "beginOffset": 9032891, + "headersEndOffset": 9033791, + "endOffset": 9049540, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 143391, + "beginOffset": 9032891, + "headersEndOffset": 9033791, + "endOffset": 9049540, + "children": [ + { + "mimeType": "image/jpeg", + "lineNumber": 143412, + "beginOffset": 9033864, + "headersEndOffset": 9033998, + "endOffset": 9044720, + "octets": 10722, + "lines": 147 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 143564, + "beginOffset": 9044748, + "headersEndOffset": 9044899, + "endOffset": 9049510, + "octets": 4611, + "lines": 64 + } + ], + "octets": 15749, + "lines": 224 + }, + "octets": 15749 + }, + { + "mboxMarkerOffset": 9049541, + "lineNumber": 143635, + "beginOffset": 9049573, + "headersEndOffset": 9050380, + "endOffset": 9067141, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143635, + "beginOffset": 9049573, + "headersEndOffset": 9050380, + "endOffset": 9067141, + "octets": 16761, + "lines": 258 + }, + "octets": 16761 + }, + { + "mboxMarkerOffset": 9067142, + "lineNumber": 143911, + "beginOffset": 9067174, + "headersEndOffset": 9067986, + "endOffset": 9092950, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 143911, + "beginOffset": 9067174, + "headersEndOffset": 9067986, + "endOffset": 9092950, + "octets": 24964, + "lines": 385 + }, + "octets": 24964 + }, + { + "mboxMarkerOffset": 9092951, + "lineNumber": 144314, + "beginOffset": 9092983, + "headersEndOffset": 9093795, + "endOffset": 9129926, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 144314, + "beginOffset": 9092983, + "headersEndOffset": 9093795, + "endOffset": 9129926, + "octets": 36131, + "lines": 556 + }, + "octets": 36131 + }, + { + "mboxMarkerOffset": 9129927, + "lineNumber": 144888, + "beginOffset": 9129959, + "headersEndOffset": 9130774, + "endOffset": 9182075, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 144888, + "beginOffset": 9129959, + "headersEndOffset": 9130774, + "endOffset": 9182075, + "octets": 51301, + "lines": 790 + }, + "octets": 51301 + }, + { + "mboxMarkerOffset": 9182076, + "lineNumber": 145696, + "beginOffset": 9182108, + "headersEndOffset": 9183499, + "endOffset": 9184930, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145696, + "beginOffset": 9182108, + "headersEndOffset": 9183499, + "endOffset": 9184930, + "octets": 1431, + "lines": 20 + }, + "octets": 1431 + }, + { + "mboxMarkerOffset": 9184931, + "lineNumber": 145741, + "beginOffset": 9184963, + "headersEndOffset": 9186316, + "endOffset": 9190708, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 145741, + "beginOffset": 9184963, + "headersEndOffset": 9186316, + "endOffset": 9190708, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 145767, + "beginOffset": 9186361, + "headersEndOffset": 9186425, + "endOffset": 9186532, + "octets": 107, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 145775, + "beginOffset": 9186577, + "headersEndOffset": 9186728, + "endOffset": 9190661, + "octets": 3933, + "lines": 54 + } + ], + "octets": 4392, + "lines": 69 + }, + "octets": 4392 + }, + { + "mboxMarkerOffset": 9190709, + "lineNumber": 145836, + "beginOffset": 9190741, + "headersEndOffset": 9191951, + "endOffset": 9195446, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145836, + "beginOffset": 9190741, + "headersEndOffset": 9191951, + "endOffset": 9195446, + "octets": 3495, + "lines": 55 + }, + "octets": 3495 + }, + { + "mboxMarkerOffset": 9195447, + "lineNumber": 145914, + "beginOffset": 9195479, + "headersEndOffset": 9196556, + "endOffset": 9197217, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145914, + "beginOffset": 9195479, + "headersEndOffset": 9196556, + "endOffset": 9197217, + "octets": 661, + "lines": 10 + }, + "octets": 661 + }, + { + "mboxMarkerOffset": 9197218, + "lineNumber": 145946, + "beginOffset": 9197226, + "headersEndOffset": 9197618, + "endOffset": 9205238, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 145946, + "beginOffset": 9197226, + "headersEndOffset": 9197618, + "endOffset": 9205238, + "octets": 7620, + "lines": 105 + }, + "octets": 7620 + }, + { + "mboxMarkerOffset": 9205239, + "lineNumber": 146063, + "beginOffset": 9205271, + "headersEndOffset": 9206054, + "endOffset": 9208866, + "body": { + "mimeType": "message/rfc822", + "lineNumber": 146063, + "beginOffset": 9205271, + "headersEndOffset": 9206054, + "endOffset": 9208866, + "message": { + "lineNumber": 146082, + "beginOffset": 9206054, + "headersEndOffset": 9207434, + "endOffset": 9208866, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146082, + "beginOffset": 9206054, + "headersEndOffset": 9207434, + "endOffset": 9208866, + "octets": 1432, + "lines": 20 + }, + "octets": 1432 + }, + "octets": 2812, + "lines": 43 + }, + "octets": 2812 + }, + { + "mboxMarkerOffset": 9208867, + "lineNumber": 146127, + "beginOffset": 9208899, + "headersEndOffset": 9209609, + "endOffset": 9212797, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 146127, + "beginOffset": 9208899, + "headersEndOffset": 9209609, + "endOffset": 9212797, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146147, + "beginOffset": 9209682, + "headersEndOffset": 9209758, + "endOffset": 9209773, + "octets": 15, + "lines": 1 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 146153, + "beginOffset": 9209801, + "headersEndOffset": 9209955, + "endOffset": 9212767, + "message": { + "lineNumber": 146157, + "beginOffset": 9209955, + "headersEndOffset": 9211335, + "endOffset": 9212767, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146157, + "beginOffset": 9209955, + "headersEndOffset": 9211335, + "endOffset": 9212767, + "octets": 1432, + "lines": 20 + }, + "octets": 1432 + }, + "octets": 2812, + "lines": 43 + } + ], + "octets": 3188, + "lines": 58 + }, + "octets": 3188 + }, + { + "mboxMarkerOffset": 9212798, + "lineNumber": 146204, + "beginOffset": 9212830, + "headersEndOffset": 9213495, + "endOffset": 9219506, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146204, + "beginOffset": 9212830, + "headersEndOffset": 9213495, + "endOffset": 9219506, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146223, + "beginOffset": 9213596, + "headersEndOffset": 9213672, + "endOffset": 9213713, + "octets": 41, + "lines": 2 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146229, + "beginOffset": 9213755, + "headersEndOffset": 9213906, + "endOffset": 9219462, + "octets": 5556, + "lines": 77 + } + ], + "octets": 6011, + "lines": 91 + }, + "octets": 6011 + }, + { + "mboxMarkerOffset": 9219507, + "lineNumber": 146313, + "beginOffset": 9219539, + "headersEndOffset": 9220601, + "endOffset": 9230837, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146313, + "beginOffset": 9219539, + "headersEndOffset": 9220601, + "endOffset": 9230837, + "octets": 10236, + "lines": 141 + }, + "octets": 10236 + }, + { + "mboxMarkerOffset": 9230838, + "lineNumber": 146476, + "beginOffset": 9230870, + "headersEndOffset": 9232246, + "endOffset": 9235059, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146476, + "beginOffset": 9230870, + "headersEndOffset": 9232246, + "endOffset": 9235059, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146503, + "beginOffset": 9232347, + "headersEndOffset": 9232423, + "endOffset": 9233034, + "octets": 611, + "lines": 17 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146524, + "beginOffset": 9233076, + "headersEndOffset": 9233227, + "endOffset": 9235015, + "octets": 1788, + "lines": 25 + } + ], + "octets": 2813, + "lines": 54 + }, + "octets": 2813 + }, + { + "mboxMarkerOffset": 9235060, + "lineNumber": 146556, + "beginOffset": 9235092, + "headersEndOffset": 9235640, + "endOffset": 9236163, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146556, + "beginOffset": 9235092, + "headersEndOffset": 9235640, + "endOffset": 9236163, + "octets": 523, + "lines": 8 + }, + "octets": 523 + }, + { + "mboxMarkerOffset": 9236164, + "lineNumber": 146580, + "beginOffset": 9236172, + "headersEndOffset": 9237488, + "endOffset": 9238420, + "body": { + "mimeType": "MULTIPART/SIGNED", + "lineNumber": 146580, + "beginOffset": 9236172, + "headersEndOffset": 9237488, + "endOffset": 9238420, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146605, + "beginOffset": 9237745, + "headersEndOffset": 9237789, + "endOffset": 9238377, + "octets": 588, + "lines": 15 + } + ], + "octets": 932, + "lines": 24 + }, + "octets": 932 + }, + { + "mboxMarkerOffset": 9238421, + "lineNumber": 146625, + "beginOffset": 9238429, + "headersEndOffset": 9239776, + "endOffset": 9248589, + "body": { + "mimeType": "MULTIPART/SIGNED", + "lineNumber": 146625, + "beginOffset": 9238429, + "headersEndOffset": 9239776, + "endOffset": 9248589, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146650, + "beginOffset": 9240033, + "headersEndOffset": 9240077, + "endOffset": 9240178, + "octets": 101, + "lines": 6 + }, + { + "mimeType": "MULTIPART/MIXED", + "lineNumber": 146660, + "beginOffset": 9240220, + "headersEndOffset": 9240383, + "endOffset": 9243067, + "children": [ + { + "mimeType": "TEXT/PLAIN", + "lineNumber": 146669, + "beginOffset": 9240638, + "headersEndOffset": 9240745, + "endOffset": 9240836, + "octets": 91, + "lines": 4 + }, + { + "mimeType": "MESSAGE/RFC822", + "lineNumber": 146678, + "beginOffset": 9240876, + "headersEndOffset": 9240969, + "endOffset": 9242341, + "message": { + "lineNumber": 146681, + "beginOffset": 9240969, + "headersEndOffset": 9242136, + "endOffset": 9242341, + "body": { + "mimeType": "text/plain", + "lineNumber": 146681, + "beginOffset": 9240969, + "headersEndOffset": 9242136, + "endOffset": 9242341, + "octets": 205, + "lines": 5 + }, + "octets": 205 + }, + "octets": 1372, + "lines": 34 + }, + { + "mimeType": "TEXT/X-VCARD", + "lineNumber": 146717, + "beginOffset": 9242381, + "headersEndOffset": 9242547, + "endOffset": 9243026, + "octets": 479, + "lines": 11 + } + ], + "octets": 2684, + "lines": 70 + }, + { + "mimeType": "APPLICATION/X-PKCS7-SIGNATURE", + "lineNumber": 146735, + "beginOffset": 9243109, + "headersEndOffset": 9243321, + "endOffset": 9248544, + "octets": 5223, + "lines": 72 + } + ], + "octets": 8813, + "lines": 169 + }, + "octets": 8813 + }, + { + "mboxMarkerOffset": 9248590, + "lineNumber": 146816, + "beginOffset": 9248622, + "headersEndOffset": 9249837, + "endOffset": 9252719, + "body": { + "mimeType": "application/x-pkcs7-mime", + "lineNumber": 146816, + "beginOffset": 9248622, + "headersEndOffset": 9249837, + "endOffset": 9252719, + "octets": 2882, + "lines": 38 + }, + "octets": 2882 + }, + { + "mboxMarkerOffset": 9252720, + "lineNumber": 146876, + "beginOffset": 9252752, + "headersEndOffset": 9253910, + "endOffset": 9256032, + "body": { + "mimeType": "Application/x-pkcs7-mime", + "lineNumber": 146876, + "beginOffset": 9252752, + "headersEndOffset": 9253910, + "endOffset": 9256032, + "octets": 2122, + "lines": 30 + }, + "octets": 2122 + }, + { + "mboxMarkerOffset": 9256033, + "lineNumber": 146929, + "beginOffset": 9256065, + "headersEndOffset": 9257143, + "endOffset": 9260100, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 146929, + "beginOffset": 9256065, + "headersEndOffset": 9257143, + "endOffset": 9260100, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 146952, + "beginOffset": 9257176, + "headersEndOffset": 9257240, + "endOffset": 9257240, + "octets": 0, + "lines": 0 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 146957, + "beginOffset": 9257273, + "headersEndOffset": 9257352, + "endOffset": 9260065, + "octets": 2713, + "lines": 42 + } + ], + "octets": 2957, + "lines": 53 + }, + "octets": 2957 + }, + { + "mboxMarkerOffset": 9260101, + "lineNumber": 147005, + "beginOffset": 9260133, + "headersEndOffset": 9261170, + "endOffset": 9264050, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 147005, + "beginOffset": 9260133, + "headersEndOffset": 9261170, + "endOffset": 9264050, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147026, + "beginOffset": 9261211, + "headersEndOffset": 9261289, + "endOffset": 9261742, + "octets": 453, + "lines": 14 + }, + { + "mimeType": "text/html", + "lineNumber": 147044, + "beginOffset": 9261783, + "headersEndOffset": 9261858, + "endOffset": 9262669, + "octets": 811, + "lines": 27 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147075, + "beginOffset": 9262710, + "headersEndOffset": 9262807, + "endOffset": 9264007, + "octets": 1200, + "lines": 16 + } + ], + "octets": 2880, + "lines": 72 + }, + "octets": 2880 + }, + { + "mboxMarkerOffset": 9264051, + "lineNumber": 147098, + "beginOffset": 9264083, + "headersEndOffset": 9265158, + "endOffset": 9269686, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147098, + "beginOffset": 9264083, + "headersEndOffset": 9265158, + "endOffset": 9269686, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147121, + "beginOffset": 9265201, + "headersEndOffset": 9265271, + "endOffset": 9265423, + "octets": 152, + "lines": 7 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147133, + "beginOffset": 9265466, + "headersEndOffset": 9265545, + "endOffset": 9269641, + "octets": 4096, + "lines": 57 + } + ], + "octets": 4528, + "lines": 75 + }, + "octets": 4528 + }, + { + "mboxMarkerOffset": 9269687, + "lineNumber": 147196, + "beginOffset": 9269695, + "headersEndOffset": 9270246, + "endOffset": 9274666, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147196, + "beginOffset": 9269695, + "headersEndOffset": 9270246, + "endOffset": 9274666, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147213, + "beginOffset": 9270290, + "headersEndOffset": 9270354, + "endOffset": 9270509, + "octets": 155, + "lines": 4 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147221, + "beginOffset": 9270553, + "headersEndOffset": 9270704, + "endOffset": 9274621, + "octets": 3917, + "lines": 54 + } + ], + "octets": 4420, + "lines": 69 + }, + "octets": 4420 + }, + { + "mboxMarkerOffset": 9274667, + "lineNumber": 147281, + "beginOffset": 9274699, + "headersEndOffset": 9275863, + "endOffset": 9279928, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 147281, + "beginOffset": 9274699, + "headersEndOffset": 9275863, + "endOffset": 9279928, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147305, + "beginOffset": 9276040, + "headersEndOffset": 9276118, + "endOffset": 9276190, + "octets": 72, + "lines": 5 + }, + { + "mimeType": "application/octet-stream", + "lineNumber": 147315, + "beginOffset": 9276231, + "headersEndOffset": 9276326, + "endOffset": 9279885, + "octets": 3559, + "lines": 47 + } + ], + "octets": 4065, + "lines": 66 + }, + "octets": 4065 + }, + { + "mboxMarkerOffset": 9279929, + "lineNumber": 147369, + "beginOffset": 9279961, + "headersEndOffset": 9281063, + "endOffset": 9285114, + "body": { + "mimeType": "multipart/signed", + "lineNumber": 147369, + "beginOffset": 9279961, + "headersEndOffset": 9281063, + "endOffset": 9285114, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 147392, + "beginOffset": 9281097, + "headersEndOffset": 9281175, + "endOffset": 9281249, + "octets": 74, + "lines": 5 + }, + { + "mimeType": "application/x-pkcs7-signature", + "lineNumber": 147401, + "beginOffset": 9281283, + "headersEndOffset": 9281362, + "endOffset": 9285079, + "octets": 3717, + "lines": 58 + } + ], + "octets": 4051, + "lines": 73 + }, + "octets": 4051 + }, + { + "mboxMarkerOffset": 9285115, + "lineNumber": 147464, + "beginOffset": 9285147, + "headersEndOffset": 9286275, + "endOffset": 9287538, + "body": { + "mimeType": "multipart/report", + "lineNumber": 147464, + "beginOffset": 9285147, + "headersEndOffset": 9286275, + "endOffset": 9287538, + "children": [ + { + "mimeType": "message/delivery-status", + "lineNumber": 147486, + "beginOffset": 9286412, + "headersEndOffset": 9286451, + "endOffset": 9286639, + "octets": 188, + "lines": 6 + }, + { + "mimeType": "message/rfc822", + "lineNumber": 147496, + "beginOffset": 9286664, + "headersEndOffset": 9286694, + "endOffset": 9287511, + "message": { + "lineNumber": 147498, + "beginOffset": 9286694, + "headersEndOffset": 9287500, + "endOffset": 9287511, + "body": { + "mimeType": "text/plain", + "lineNumber": 147498, + "beginOffset": 9286694, + "headersEndOffset": 9287500, + "endOffset": 9287511, + "octets": 11, + "lines": 1 + }, + "octets": 11 + }, + "octets": 817, + "lines": 16 + } + ], + "octets": 1263, + "lines": 34 + }, + "octets": 1263 + }, + { + "mboxMarkerOffset": 9287539, + "lineNumber": 147517, + "beginOffset": 9287585, + "headersEndOffset": 9287750, + "endOffset": 9322244, + "body": { + "mimeType": "text/plain", + "lineNumber": 147517, + "beginOffset": 9287585, + "headersEndOffset": 9287750, + "endOffset": 9322244, + "octets": 34494, + "lines": 592 + }, + "octets": 34494 + }, + { + "mboxMarkerOffset": 9322245, + "lineNumber": 148117, + "beginOffset": 9322291, + "headersEndOffset": 9322449, + "endOffset": 9356943, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 148117, + "beginOffset": 9322291, + "headersEndOffset": 9322449, + "endOffset": 9356943, + "octets": 34494, + "lines": 592 + }, + "octets": 34494 + }, + { + "mboxMarkerOffset": 9356944, + "lineNumber": 148717, + "beginOffset": 9356952, + "headersEndOffset": 9357549, + "endOffset": 9358949, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 148717, + "beginOffset": 9356952, + "headersEndOffset": 9357549, + "endOffset": 9358949, + "octets": 1400, + "lines": 39 + }, + "octets": 1400 + }, + { + "mboxMarkerOffset": 9358950, + "lineNumber": 148768, + "beginOffset": 9358958, + "headersEndOffset": 9359858, + "endOffset": 9602012, + "body": { + "mimeType": "MULTIPART/mixed", + "lineNumber": 148768, + "beginOffset": 9358958, + "headersEndOffset": 9359858, + "endOffset": 9602012, + "children": [ + { + "mimeType": "TEXT/plain", + "lineNumber": 148786, + "beginOffset": 9359897, + "headersEndOffset": 9359923, + "endOffset": 9360268, + "octets": 345, + "lines": 10 + }, + { + "mimeType": "AUDIO/basic", + "lineNumber": 148800, + "beginOffset": 9360308, + "headersEndOffset": 9360401, + "endOffset": 9601970, + "octets": 241569, + "lines": 3961 + } + ], + "octets": 242154, + "lines": 3982 + }, + "octets": 242154 + }, + { + "mboxMarkerOffset": 9602013, + "lineNumber": 152769, + "beginOffset": 9602021, + "headersEndOffset": 9602615, + "endOffset": 9681155, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 152769, + "beginOffset": 9602021, + "headersEndOffset": 9602615, + "endOffset": 9681155, + "children": [ + { + "mimeType": "image/pbm", + "lineNumber": 152786, + "beginOffset": 9602676, + "headersEndOffset": 9602835, + "endOffset": 9681124, + "octets": 78289, + "lines": 406 + } + ], + "octets": 78540, + "lines": 416 + }, + "octets": 78540 + }, + { + "mboxMarkerOffset": 9681156, + "lineNumber": 153201, + "beginOffset": 9681164, + "headersEndOffset": 9681316, + "endOffset": 9684876, + "body": { + "mimeType": "message/partial", + "lineNumber": 153201, + "beginOffset": 9681164, + "headersEndOffset": 9681316, + "endOffset": 9684876, + "octets": 3560, + "lines": 49 + }, + "octets": 3560 + }, + { + "mboxMarkerOffset": 9684877, + "lineNumber": 153256, + "beginOffset": 9684885, + "headersEndOffset": 9685657, + "endOffset": 9715925, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 153256, + "beginOffset": 9684885, + "headersEndOffset": 9685657, + "endOffset": 9715925, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153276, + "beginOffset": 9685852, + "headersEndOffset": 9685896, + "endOffset": 9686310, + "octets": 414, + "lines": 7 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 153287, + "beginOffset": 9686351, + "headersEndOffset": 9686436, + "endOffset": 9715883, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 153291, + "beginOffset": 9686478, + "headersEndOffset": 9686569, + "endOffset": 9686640, + "octets": 71, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153297, + "beginOffset": 9686683, + "headersEndOffset": 9686782, + "endOffset": 9697479, + "octets": 10697, + "lines": 157 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153460, + "beginOffset": 9697522, + "headersEndOffset": 9697613, + "endOffset": 9697677, + "octets": 64, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153467, + "beginOffset": 9697720, + "headersEndOffset": 9697813, + "endOffset": 9703716, + "octets": 5903, + "lines": 87 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153560, + "beginOffset": 9703759, + "headersEndOffset": 9703850, + "endOffset": 9703883, + "octets": 33, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 153567, + "beginOffset": 9703926, + "headersEndOffset": 9704027, + "endOffset": 9715673, + "octets": 11646, + "lines": 170 + }, + { + "mimeType": "text/richtext", + "lineNumber": 153743, + "beginOffset": 9715716, + "headersEndOffset": 9715807, + "endOffset": 9715838, + "octets": 31, + "lines": 2 + } + ], + "octets": 29447, + "lines": 460 + } + ], + "octets": 30268, + "lines": 480 + }, + "octets": 30268 + }, + { + "mboxMarkerOffset": 9715926, + "lineNumber": 153753, + "beginOffset": 9715934, + "headersEndOffset": 9715990, + "endOffset": 9717198, + "body": { + "mimeType": "text/plain", + "lineNumber": 153753, + "beginOffset": 9715934, + "headersEndOffset": 9715990, + "endOffset": 9717198, + "octets": 1208, + "lines": 28 + }, + "octets": 1208 + }, + { + "mboxMarkerOffset": 9717199, + "lineNumber": 153785, + "beginOffset": 9717231, + "headersEndOffset": 9717382, + "endOffset": 9720490, + "body": { + "mimeType": "text/plain", + "lineNumber": 153785, + "beginOffset": 9717231, + "headersEndOffset": 9717382, + "endOffset": 9720490, + "octets": 3108, + "lines": 68 + }, + "octets": 3108 + }, + { + "mboxMarkerOffset": 9720491, + "lineNumber": 153859, + "beginOffset": 9720523, + "headersEndOffset": 9722388, + "endOffset": 9727267, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 153859, + "beginOffset": 9720523, + "headersEndOffset": 9722388, + "endOffset": 9727267, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153891, + "beginOffset": 9722432, + "headersEndOffset": 9722510, + "endOffset": 9723373, + "octets": 863, + "lines": 18 + }, + { + "mimeType": "application/vcard", + "lineNumber": 153914, + "beginOffset": 9723418, + "headersEndOffset": 9723579, + "endOffset": 9727220, + "octets": 3641, + "lines": 61 + } + ], + "octets": 4879, + "lines": 92 + }, + "octets": 4879 + }, + { + "mboxMarkerOffset": 9727268, + "lineNumber": 153984, + "beginOffset": 9727276, + "headersEndOffset": 9727830, + "endOffset": 9844660, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 153984, + "beginOffset": 9727276, + "headersEndOffset": 9727830, + "endOffset": 9844660, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 153999, + "beginOffset": 9727847, + "headersEndOffset": 9727874, + "endOffset": 9728837, + "octets": 963, + "lines": 19 + }, + { + "mimeType": "image/pgm", + "lineNumber": 154022, + "beginOffset": 9728854, + "headersEndOffset": 9728914, + "endOffset": 9844640, + "octets": 115726, + "lines": 1586 + } + ], + "octets": 116830, + "lines": 1617 + }, + "octets": 116830 + }, + { + "mboxMarkerOffset": 9844661, + "lineNumber": 155616, + "beginOffset": 9844669, + "headersEndOffset": 9845465, + "endOffset": 9870085, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 155616, + "beginOffset": 9844669, + "headersEndOffset": 9845465, + "endOffset": 9870085, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 155639, + "beginOffset": 9845660, + "headersEndOffset": 9845704, + "endOffset": 9854667, + "octets": 8963, + "lines": 349 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 155992, + "beginOffset": 9854708, + "headersEndOffset": 9854793, + "endOffset": 9870042, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 155996, + "beginOffset": 9854835, + "headersEndOffset": 9854926, + "endOffset": 9857701, + "octets": 2775, + "lines": 69 + }, + { + "mimeType": "message/external-body", + "lineNumber": 156070, + "beginOffset": 9857744, + "headersEndOffset": 9857940, + "endOffset": 9857969, + "message": { + "lineNumber": 156077, + "beginOffset": 9857940, + "headersEndOffset": 9857967, + "endOffset": 9857969, + "body": { + "mimeType": "text/X-HTML", + "lineNumber": 156077, + "beginOffset": 9857940, + "headersEndOffset": 9857967, + "endOffset": 9857969, + "octets": 2, + "lines": 2 + }, + "octets": 2 + }, + "octets": 29, + "lines": 4 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156083, + "beginOffset": 9858012, + "headersEndOffset": 9858103, + "endOffset": 9859077, + "octets": 974, + "lines": 22 + }, + { + "mimeType": "text/SGML", + "lineNumber": 156110, + "beginOffset": 9859120, + "headersEndOffset": 9859236, + "endOffset": 9859595, + "octets": 359, + "lines": 15 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156131, + "beginOffset": 9859638, + "headersEndOffset": 9859729, + "endOffset": 9859739, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "message/external-body", + "lineNumber": 156138, + "beginOffset": 9859782, + "headersEndOffset": 9859967, + "endOffset": 9859995, + "message": { + "lineNumber": 156144, + "beginOffset": 9859967, + "headersEndOffset": 9859994, + "endOffset": 9859995, + "body": { + "mimeType": "text/X-HTML", + "lineNumber": 156144, + "beginOffset": 9859967, + "headersEndOffset": 9859994, + "endOffset": 9859995, + "octets": 1, + "lines": 1 + }, + "octets": 1 + }, + "octets": 28, + "lines": 3 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156149, + "beginOffset": 9860038, + "headersEndOffset": 9860129, + "endOffset": 9860139, + "octets": 10, + "lines": 2 + }, + { + "mimeType": "image/gif", + "lineNumber": 156156, + "beginOffset": 9860182, + "headersEndOffset": 9860288, + "endOffset": 9863271, + "octets": 2983, + "lines": 43 + }, + { + "mimeType": "text/richtext", + "lineNumber": 156205, + "beginOffset": 9863314, + "headersEndOffset": 9863405, + "endOffset": 9869997, + "octets": 6592, + "lines": 260 + } + ], + "octets": 15249, + "lines": 475 + } + ], + "octets": 24620, + "lines": 837 + }, + "octets": 24620 + }, + { + "mboxMarkerOffset": 9870086, + "lineNumber": 156474, + "beginOffset": 9870094, + "headersEndOffset": 9871206, + "endOffset": 9901796, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 156474, + "beginOffset": 9870094, + "headersEndOffset": 9871206, + "endOffset": 9901796, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 156498, + "beginOffset": 9871216, + "headersEndOffset": 9871217, + "endOffset": 9871550, + "octets": 333, + "lines": 8 + }, + { + "mimeType": "image/gif", + "lineNumber": 156509, + "beginOffset": 9871561, + "headersEndOffset": 9871620, + "endOffset": 9901599, + "octets": 29979, + "lines": 411 + }, + { + "mimeType": "text/plain", + "lineNumber": 156925, + "beginOffset": 9901610, + "headersEndOffset": 9901611, + "endOffset": 9901783, + "octets": 172, + "lines": 9 + } + ], + "octets": 30590, + "lines": 440 + }, + "octets": 30590 + }, + { + "mboxMarkerOffset": 9901797, + "lineNumber": 156939, + "beginOffset": 9901805, + "headersEndOffset": 9903514, + "endOffset": 10086313, + "body": { + "mimeType": "text/plain", + "lineNumber": 156939, + "beginOffset": 9901805, + "headersEndOffset": 9903514, + "endOffset": 10086313, + "octets": 182799, + "lines": 2951 + }, + "octets": 182799 + }, + { + "mboxMarkerOffset": 10086314, + "lineNumber": 159921, + "beginOffset": 10086322, + "headersEndOffset": 10087029, + "endOffset": 10171317, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 159921, + "beginOffset": 10086322, + "headersEndOffset": 10087029, + "endOffset": 10171317, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 159938, + "beginOffset": 10087056, + "headersEndOffset": 10087057, + "endOffset": 10087078, + "octets": 21, + "lines": 1 + }, + { + "mimeType": "image/pgm", + "lineNumber": 159941, + "beginOffset": 10087106, + "headersEndOffset": 10087258, + "endOffset": 10170999, + "octets": 83741, + "lines": 434 + }, + { + "mimeType": "text/plain", + "lineNumber": 160381, + "beginOffset": 10171027, + "headersEndOffset": 10171028, + "endOffset": 10171287, + "octets": 259, + "lines": 9 + } + ], + "octets": 84288, + "lines": 455 + }, + "octets": 84288 + }, + { + "mboxMarkerOffset": 10171318, + "lineNumber": 160394, + "beginOffset": 10171326, + "headersEndOffset": 10171993, + "endOffset": 10392019, + "body": { + "mimeType": "multipart/mixed", + "lineNumber": 160394, + "beginOffset": 10171326, + "headersEndOffset": 10171993, + "endOffset": 10392019, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 160410, + "beginOffset": 10172020, + "headersEndOffset": 10172021, + "endOffset": 10172087, + "octets": 66, + "lines": 1 + }, + { + "mimeType": "audio/basic", + "lineNumber": 160413, + "beginOffset": 10172115, + "headersEndOffset": 10172276, + "endOffset": 10204442, + "octets": 32166, + "lines": 167 + }, + { + "mimeType": "text/plain", + "lineNumber": 160586, + "beginOffset": 10204470, + "headersEndOffset": 10204471, + "endOffset": 10204488, + "octets": 17, + "lines": 2 + }, + { + "mimeType": "image/pbm", + "lineNumber": 160590, + "beginOffset": 10204516, + "headersEndOffset": 10204675, + "endOffset": 10205760, + "octets": 1085, + "lines": 6 + }, + { + "mimeType": "text/plain", + "lineNumber": 160602, + "beginOffset": 10205788, + "headersEndOffset": 10205789, + "endOffset": 10205819, + "octets": 30, + "lines": 2 + }, + { + "mimeType": "application/x-annotate-2", + "lineNumber": 160607, + "beginOffset": 10205847, + "headersEndOffset": 10205915, + "endOffset": 10391952, + "octets": 186037, + "lines": 1990 + }, + { + "mimeType": "text/plain", + "lineNumber": 162602, + "beginOffset": 10391980, + "headersEndOffset": 10391981, + "endOffset": 10391989, + "octets": 8, + "lines": 1 + } + ], + "octets": 220026, + "lines": 2196 + }, + "octets": 220026 + }, + { + "mboxMarkerOffset": 10392020, + "lineNumber": 162607, + "beginOffset": 10392028, + "headersEndOffset": 10392292, + "endOffset": 10466950, + "body": { + "mimeType": "application/octet-stream", + "lineNumber": 162607, + "beginOffset": 10392028, + "headersEndOffset": 10392292, + "endOffset": 10466950, + "octets": 74658, + "lines": 1023 + }, + "octets": 74658 + }, + { + "mboxMarkerOffset": 10466951, + "lineNumber": 163639, + "beginOffset": 10466959, + "headersEndOffset": 10468233, + "endOffset": 10523298, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 163639, + "beginOffset": 10466959, + "headersEndOffset": 10468233, + "endOffset": 10523298, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 163673, + "beginOffset": 10468817, + "headersEndOffset": 10468818, + "endOffset": 10470665, + "octets": 1847, + "lines": 34 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 163710, + "beginOffset": 10470724, + "headersEndOffset": 10470827, + "endOffset": 10523237, + "children": [ + { + "mimeType": "text/richtext", + "lineNumber": 163714, + "beginOffset": 10470887, + "headersEndOffset": 10470960, + "endOffset": 10472959, + "octets": 1999, + "lines": 29 + }, + { + "mimeType": "image/xwd", + "lineNumber": 163748, + "beginOffset": 10473020, + "headersEndOffset": 10473079, + "endOffset": 10481008, + "octets": 7929, + "lines": 109 + }, + { + "mimeType": "text/plain", + "lineNumber": 163862, + "beginOffset": 10481069, + "headersEndOffset": 10481139, + "endOffset": 10481142, + "octets": 3, + "lines": 2 + }, + { + "mimeType": "audio/basic", + "lineNumber": 163869, + "beginOffset": 10481203, + "headersEndOffset": 10481296, + "endOffset": 10523174, + "octets": 41878, + "lines": 574 + } + ], + "octets": 52410, + "lines": 736 + } + ], + "octets": 55065, + "lines": 787 + }, + "octets": 55065 + }, + { + "mboxMarkerOffset": 10523299, + "lineNumber": 164453, + "beginOffset": 10523307, + "headersEndOffset": 10523459, + "endOffset": 10528262, + "body": { + "mimeType": "message/partial", + "lineNumber": 164453, + "beginOffset": 10523307, + "headersEndOffset": 10523459, + "endOffset": 10528262, + "octets": 4803, + "lines": 68 + }, + "octets": 4803 + }, + { + "mboxMarkerOffset": 10528263, + "lineNumber": 164527, + "beginOffset": 10528271, + "headersEndOffset": 10529016, + "endOffset": 10536315, + "body": { + "mimeType": "multipart/alternative", + "lineNumber": 164527, + "beginOffset": 10528271, + "headersEndOffset": 10529016, + "endOffset": 10536315, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 164551, + "beginOffset": 10529395, + "headersEndOffset": 10529396, + "endOffset": 10529764, + "octets": 368, + "lines": 8 + }, + { + "mimeType": "multipart/mixed", + "lineNumber": 164562, + "beginOffset": 10529805, + "headersEndOffset": 10529890, + "endOffset": 10536272, + "children": [ + { + "mimeType": "text/plain", + "lineNumber": 164566, + "beginOffset": 10529932, + "headersEndOffset": 10530002, + "endOffset": 10530091, + "octets": 89, + "lines": 4 + }, + { + "mimeType": "image/gif", + "lineNumber": 164575, + "beginOffset": 10530134, + "headersEndOffset": 10530248, + "endOffset": 10535911, + "octets": 5663, + "lines": 83 + }, + { + "mimeType": "text/plain", + "lineNumber": 164664, + "beginOffset": 10535954, + "headersEndOffset": 10536024, + "endOffset": 10536227, + "octets": 203, + "lines": 6 + } + ], + "octets": 6382, + "lines": 110 + } + ], + "octets": 7299, + "lines": 133 + }, + "octets": 7299 + } +] \ No newline at end of file diff --git a/UnitTests/TestData/messages/multipart-related-mhtml.txt b/UnitTests/TestData/messages/multipart-related-mhtml.txt new file mode 100644 index 0000000000..c10f544071 --- /dev/null +++ b/UnitTests/TestData/messages/multipart-related-mhtml.txt @@ -0,0 +1,47 @@ +MIME-Version: 1.0 +Content-Type: multipart/related; + type="text/html"; + boundary="----=_NextPart_115e1404-dbbc-4611-b4ce-d08a4b021c45" + +This is a multi-part message in MIME format. +------=_NextPart_115e1404-dbbc-4611-b4ce-d08a4b021c45 +Content-Type: image/png +Content-Transfer-Encoding: base64 +Content-Location: image1 + +iVBORw0KGgoAAAANSUhEUgAAAZAAAABOCAYAAAAO/EAnAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAW +JQAAFiUBSVIk8AAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuODc7gF0AAAL2SURBVHhe7d2x +ahRRFAZgn0ltBd/BWOZVfAptxNZtUgohIFFBCw1srQm7BmxMIhsQV0TFjHPCDruZXDZ3TzvfD183TPtz +750751ZTyL+Li+b4/Gczmc0BGKhpa/7776IZrqdYIJ/b8tjeGTdbowMABuph68Wnr5eLilKuFUi0zaOX +H5u7T940tx+/BmDAHjz/cLmoKOVKgUTLRNvce/q2+CIAhiUWE7GoKG1lXSmQH+0DsWQpvQSAYYpFxfsv +54umWOZKgXz/9ae5/+xd8QUADNOd1qvpt0VTLKNAAFhLgQCQokAASFEgAKQoEABSokD2J2eLplhGgQCw +VhTI3tFp07+PrkAAWCsKZPfwRIEAsBlbWACkOEQHIEWBAJCiQABIUSAApCgQAFKqCsQ8EAD6quaBmEgI +wKrqiYQRM9EB6FTPRO8SD2/vjJut0QEAAxVHGrErFbtTpRQLJB4+bktkMpsDMFDTVmnrqkuxQERERG6K +FQgARakViDMQADY+A/EVFgCd6q+w3AMBYFX1PRA30QHoq7qJ7l9YAPT5mSIAKQoEgBQFAkCKAgEgRYEA +kBIFsj85WzTFMgoEgLWiQPaOTpv+fXQFAsBaUSC7hycKBIDN2MICIMUhOgApCgSAFAUCQIoCASBFgQCQ +UlUg5oEA0Fc1D8REQgBWVU8kjJiJDkCneiZ6l3h4e2fcbI0OABioONKIXanYnSqlWCDx8HFbIpPZHICB +mrZKW1ddigUiIiJyU6xAAChKrUCcgQCw8RmIr7AA6FR/heUeCACrqu+BuIkOQF/VTXT/wgKgz88UAUhR +IACkKBAAUhQIACkKBICUKJD9ydmiKZZRIACsFQWyd3Ta9O+jKxAA1ooC2T08USAAbMYWFgApDtEBSFEg +AKQoEABSFAgAKQoEgJSqAjEPBIC+qnkgJhICsKp6ImHETHQAOtUz0bvEw9s742ZrdADAQMWRRuxKxe5U +KcUCiYeP2xKZzOYADNS0Vdq66lIsEBERkfVpmv/Cb/8ZH82DugAAAABJRU5ErkJggg== + + +------=_NextPart_115e1404-dbbc-4611-b4ce-d08a4b021c45 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +=0D=0A=0D=0A=09=0D=0A=09=09=0D=0A=09= +=09=0D=0A=09=09=0D=0A=09=09=09.cs2654AE3A{te= +xt-align:left;text-indent:0pt;margin:0pt=200pt=200pt=200pt}=0D=0A=09=09=09.csC8= +F6D76{color:#000000;background-color:transparent;font-family:Calibri;font-size:= +11pt;font-weight:normal;font-style:normal;}=0D=0A=09=09=0D=0A=09= +=0D=0A=09=0D=0A=09=09= +

def

= +=0D=0A=0D=0A + + +------=_NextPart_115e1404-dbbc-4611-b4ce-d08a4b021c45-- diff --git a/UnitTests/TestData/partial/rfc2046.0.eml b/UnitTests/TestData/partial/rfc2046.0.eml new file mode 100644 index 0000000000..726bc4abb5 --- /dev/null +++ b/UnitTests/TestData/partial/rfc2046.0.eml @@ -0,0 +1,19 @@ +X-Weird-Header-1: Foo +From: Bill@host.com +To: joe@otherhost.com +Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST) +Subject: Audio mail (part 1 of 2) +Message-ID: +MIME-Version: 1.0 +Content-type: message/partial; id="ABC@host.com"; + number=1; total=2 + +X-Weird-Header-1: Bar +X-Weird-Header-2: Hello +Message-ID: +Subject: Audio mail +MIME-Version: 1.0 +Content-type: audio/basic +Content-transfer-encoding: base64 + +... first half of encoded audio data goes here ... diff --git a/UnitTests/TestData/partial/rfc2046.1.eml b/UnitTests/TestData/partial/rfc2046.1.eml new file mode 100644 index 0000000000..e13ee67a50 --- /dev/null +++ b/UnitTests/TestData/partial/rfc2046.1.eml @@ -0,0 +1,10 @@ +From: Bill@host.com +To: joe@otherhost.com +Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST) +Subject: Audio mail (part 2 of 2) +MIME-Version: 1.0 +Message-ID: +Content-type: message/partial; + id="ABC@host.com"; number=2; total=2 + +... second half of encoded audio data goes here ... diff --git a/UnitTests/TestData/partial/rfc2046.eml b/UnitTests/TestData/partial/rfc2046.eml new file mode 100644 index 0000000000..a12da93f66 --- /dev/null +++ b/UnitTests/TestData/partial/rfc2046.eml @@ -0,0 +1,12 @@ +X-Weird-Header-1: Foo +From: Bill@host.com +To: joe@otherhost.com +Date: Fri, 26 Mar 1993 12:59:38 -0500 (EST) +Subject: Audio mail +Message-ID: +MIME-Version: 1.0 +Content-type: audio/basic +Content-transfer-encoding: base64 + +... first half of encoded audio data goes here ... +... second half of encoded audio data goes here ... diff --git a/UnitTests/TestData/smime/ca.cnf b/UnitTests/TestData/smime/ca.cnf new file mode 100644 index 0000000000..2409df1898 --- /dev/null +++ b/UnitTests/TestData/smime/ca.cnf @@ -0,0 +1,81 @@ +# +# OpenSSL example configuration file for automated certificate creation. +# + +# This definition stops the following lines choking if HOME or CN +# is undefined. +HOME = . +RANDFILE = $ENV::HOME/.rnd +CN = "Bruce Wayne" +EMAIL = "bruce.wayne@example.com" +ON = "Example Authority Inc." +default_ca = ca + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +# Don't prompt for fields: use those in section directly +prompt = no +distinguished_name = req_distinguished_name +x509_extensions = v3_ca # The extensions to add to the self signed cert +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +# Take CN, ON, and EMAIL from the environment so they can come from a script. +countryName = US +countryName_min = 2 +countryName_max = 2 +stateOrProvinceName = Massachusetts +localityName = Boston +organizationName = $ENV::ON +organizationalUnitName = IT +commonName = $ENV::CN +commonName_max = 64 +emailAddress = $ENV::EMAIL +emailAddress_max = 64 + +[ req_attributes ] +challengePassword = no.secret +challengePassword_min = 4 +challengePassword_max = 20 + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request for an end entity +# certificate + +basicConstraints=critical, CA:FALSE +keyUsage=critical, nonRepudiation, digitalSignature, keyEncipherment + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid + +[ dh_cert ] + +# These extensions are added when 'ca' signs a request for an end entity +# DH certificate + +basicConstraints=critical, CA:FALSE +keyUsage=critical, keyAgreement + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid + +[ v3_ca ] + + +# Extensions for a typical CA + +# PKIX recommendation. + +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always +basicConstraints = critical,CA:true +keyUsage = critical, cRLSign, keyCertSign +#keyUsage = critical, keyCertSign, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment + diff --git a/UnitTests/TestData/smime/certificate-authority.cfg b/UnitTests/TestData/smime/certificate-authority.cfg new file mode 100644 index 0000000000..4db8f1cc9c --- /dev/null +++ b/UnitTests/TestData/smime/certificate-authority.cfg @@ -0,0 +1,22 @@ +[PrivateKey] +Algorithm = RSA +BitLength = 4096 +FileName = certificate-authority.key + +[Subject] +CountryName = US +StateOrProvinceName = Massachusetts +LocalityName = Boston +OrganizationName = Example Authority Inc. +OrganizationalUnitName = IT +CommonName = Example Certification Authority +EmailAddress = root@example.com + +[Generator] +BasicConstraints = critical, CA:true +DaysValid = 3650 +Issuer = this +KeyUsage = critical, cRLSign, keyCertSign +SignatureAlgorithm = SHA256WithRSA +#Output = certificate-authority.pfx +Password = no.secret diff --git a/UnitTests/TestData/smime/certificate-authority.crt b/UnitTests/TestData/smime/certificate-authority.crt deleted file mode 100644 index 3ac3833b2e..0000000000 --- a/UnitTests/TestData/smime/certificate-authority.crt +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGmDCCBICgAwIBAgIJAL1Tka1O620zMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD -VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9u -MR8wHQYDVQQKExZFeGFtcGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVj -ZSBXYXluZTEfMB0GCSqGSIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbTAeFw0xNzA2 -MzAwMTAzMzBaFw0xODA2MzAwMTAzMzBaMIGOMQswCQYDVQQGEwJVUzEWMBQGA1UE -CBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9uMR8wHQYDVQQKExZFeGFt -cGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVjZSBXYXluZTEfMB0GCSqG -SIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAJr9a2EJ5qrut+xy6sT76oR064xh58oJruQJuT0p+Dw3b6Zx1Vor -RdAi/mwKwLyknkQm1vY0a3fl+z/epo3sD//HoP9NmFXbxV2VgIuMuZ+XBupPprzv -jjnds7ejsTC2Bssb8W5Q4PRpXushMjQcS/BWFQDAkxyMcyizJvLWK1ltLe5yle+N -3+T+1IdcA/Ucg+QfQ+DMU8DiLXVqmkfzK8stpjVhn0qEOlTs0el8x+3lCbHZbojJ -+4QTpUbcsXH9AdIxYOmRuREBXQMnF65gjwW4SIgN+1l5kJyEKHO/uj5BuFwJYm7s -IafxpNnXZX0VYtS7jtE1/SA2M6yJokvxwrmFdWWIpnM7ClowuZTnkhY8ey7/X8YJ -6o0rPHEAgAfutPTzBCudYx8d0eMPp5yxEGLoB/IQk4YgnX3Srz1BHmJri65MU28+ -oOAmWK4r+eakaD0EFRcrDaFYKagZtXJhHPYAZSILLvys90xawFS6Q0JZHtFq4d1Y -ofUZufknSVwKWO04NQVX+0JCN0cG6aPaQGYQCJlHkye4VnsEi3zFRaNpBuYhzrMF -jSW1ffsAc2s9HqJN1GpdYssMuobM/MRMGv27lWhmmPjTi1a8GKOtg8SS0EhNv96S -t/O7CVpBTwb6UVf0mtVmddSGpUdWaFGboYCfUhgsDfl57QawdEThhJaJAgMBAAGj -gfYwgfMwHQYDVR0OBBYEFKPy7nmCG9tPFt3HQvi8pT7TRRVdMIHDBgNVHSMEgbsw -gbiAFKPy7nmCG9tPFt3HQvi8pT7TRRVdoYGUpIGRMIGOMQswCQYDVQQGEwJVUzEW -MBQGA1UECBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9uMR8wHQYDVQQK -ExZFeGFtcGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVjZSBXYXluZTEf -MB0GCSqGSIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbYIJAL1Tka1O620zMAwGA1Ud -EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAJkEGLCcY8GH/cFhSVa+Mo7hPvoo -kJf2CQMlt1YPPlV1KYjX2JdYVWbhaoM0Zjn6x4u9sUZ+brgRXJiuFtJzyMvtEr8e -nA5zsik1cw6zeWBkV0LVTgXCeLy51x/j6Mo/CBlzt3Ib8h/PSF3+UIMZwTKXEq1x -adCCoklqCBUERiYd3RHJlxIsdG1Yf1yO/auB7dG2Sgh31xPLh9cZxOUiok8zZmGE -rQ35bVPSHioaSKFBjKv1X+p0X8LZpoGpH2s3tDs5r6VlvUDMSKEZ+OUtkaikmXbx -+0+sxRm7MuY3wI62US06qQhvTaiQUkWN1WRhLhkYcxy4Sby8cwr9izETelfgIE/j -vCH2gKcPAx78QZ9/Z9qHp+y1EtQuk7r1ublg1DdLQqDzgz1qcq93iLD1BoKwnU6m -OdSaHjcMZszH3msPDUUbXtTHC0+8K8pPpbZqpaK1C+AVdrVTvbi7WdDvd7O02lLm -2IzZLCytYyx/kb68qxAF7wIVNmJh2VVTKgB/N4TIn60an0GZ1ZVmhJ3tVwxG9EkP -egCgE6Av09s9Cex1ER16Ximt4AWSiVoJucbRuE1Qi1YjdKmnmUPge69Da4GV4XTw -u8cbJ1FNr329EjjZdtbK4CifuOHhyE1FFHD6xxAiGodqH78fu2V3oqLHtocUKz1k -r2+37rbw2rtgjR8o ------END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/certificate-authority.key b/UnitTests/TestData/smime/certificate-authority.key index b4e9de9b34..869d452178 100644 --- a/UnitTests/TestData/smime/certificate-authority.key +++ b/UnitTests/TestData/smime/certificate-authority.key @@ -1,51 +1,51 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/UnitTests/TestData/smime/certificate-authority.pfx b/UnitTests/TestData/smime/certificate-authority.pfx new file mode 100644 index 0000000000..6fbe97054d Binary files /dev/null and b/UnitTests/TestData/smime/certificate-authority.pfx differ diff --git a/UnitTests/TestData/smime/certificate-authority.srl b/UnitTests/TestData/smime/certificate-authority.srl deleted file mode 100644 index 88392afa16..0000000000 --- a/UnitTests/TestData/smime/certificate-authority.srl +++ /dev/null @@ -1 +0,0 @@ -A68B9B780627A14D diff --git a/UnitTests/TestData/smime/chain.crt b/UnitTests/TestData/smime/chain.crt deleted file mode 100644 index ed80f3557d..0000000000 --- a/UnitTests/TestData/smime/chain.crt +++ /dev/null @@ -1,71 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFojCCA4oCCQCmi5t4BiehTTANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMC -VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEfMB0G -A1UEChMWRXhhbXBsZSBBdXRob3JpdHkgSW5jLjEUMBIGA1UEAxMLQnJ1Y2UgV2F5 -bmUxHzAdBgkqhkiG9w0BCQEWEHJvb3RAZXhhbXBsZS5jb20wHhcNMTcwNjMwMDEw -MzMyWhcNMTgwNjMwMDEwMzMyWjCBljELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1h -c3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEfMB0GA1UEChMWRXhhbXBsZSBB -dXRob3JpdHkgSW5jLjEUMBIGA1UEAxMLQnJ1Y2UgV2F5bmUxJzAlBgkqhkiG9w0B -CQEWGGludGVybWVkaWF0ZUBleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJx2WQPRH26XdXy13g98vCxn/Qo18IEsHbyfnY9KPJz1US/H -EbmGQI1mwEjk9n2mnk5ntGeCO5lwswfPtGhct5oVbWl/kkahdwhim2LU3wdigSwL -IMsrq6uH0rBe/P9owwO+STVolfwc6buG9MrIK8fnNL6eUC86/6MnPbwu3WnWX6cK -DILiWyHWAWqqWNa6y7qgOCjjfUMudodCJgWBsSZJGJDEi7YJ7mvQT8xQ98MN+88U -GDHJRuzPUy986PMa6UcS6IzIZp+sIzfjPPx4uxbKq23kXy0ZwjBkTWSozmAvX+Sf -6ZHPKCeBn4DECs2S0jpYbhhztxeLmmrn1Ry09JOYLxwmUJN5rZJq1SS7xPj0DMMA -Fb5++4zmYXxTB4m9itJMbikLfnOcO6CnZtlLV31G1VBEgOmCAInq0hUFfgObizwL -oCJzXwO6FOO/SOAnivP07aEC2Tc/KFkqZEnC6CR4stUIMMLUdSL5jdCFVyntzQmc -Uf33ccbqeI5BlFHJvoymXLOV4vjB6NnKvV9n2EeXS6f+vTyk6kq3G67RtkqCi1Aq -bHef66DGv1q1If9yYmOeh3Zi8hm7ZrhdbCKctyPr9LDKcEx4TdUOuyTi0m8/cF1Z -Z7JHwJ2uhVhh1XeUBgbJCUwDOrIyzTH3WCDXEmKEz/vt6vwQX52trEUGBODDAgMB -AAEwDQYJKoZIhvcNAQEFBQADggIBAANLYo8Ks+3ZonKyPYlT2TQYHIrkeIR6ONih -e4AOTWjyWyntEYniTx4gFHxxJeU8nwLd/EZG7Oy97GG4o4LljU78bB8aTeS2l4kR -JyJl8SkPXruKGKtJJ74B19RhofRRROO6KDuLt6IDqPrx9CDx+oQMN8I2kfPaZII+ -puOn77PwGqxWOauMbOjNgcBDM0cDOsNjx+cCOEULAYRT/V6ilmBbnDaFCZaQj0u2 -BNQ/oRa2avWVpT8WByGr7DXXrn3ad1KmLNEP6pFwGzjOP1/gAydm2YxxoYmGGFQt -ylRQvQygoUBnzQkdstnmbHmdmdOslZnOVuNttAUmlXRUH0atNFG12FUFK3Wi4wzn -9Kh5i/8fCyOxnzANixHOEB+MsYYJbxzb/fcA7wanjJd8Tz/uQbxOrTe1KCKHvAd0 -ZgIuUV9IPzRRiGDV5V2dJddki52qexQx24xhFCJbt7s0EQG/F1rdf+atEzhJFclL -AMvPH435Aqf/sI/CT99QcUGY0GNXtNQdUb1HiVQ2SWoFgZpeemkDmoRM/wFloVjH -Wc9RZBszI2PqBGs688EGHyGSD9cjdkxUj9Jpss+B0M64r7Ktu/DC0/VtZGq6CUDX -IHma7oUKs8wOUNpxn2ZJPWlQb5njpz5wSRDel0nTxgKrcjmvKIlewfc2p9BPnsap -S8tVo/sW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGmDCCBICgAwIBAgIJAL1Tka1O620zMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYD -VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9u -MR8wHQYDVQQKExZFeGFtcGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVj -ZSBXYXluZTEfMB0GCSqGSIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbTAeFw0xNzA2 -MzAwMTAzMzBaFw0xODA2MzAwMTAzMzBaMIGOMQswCQYDVQQGEwJVUzEWMBQGA1UE -CBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9uMR8wHQYDVQQKExZFeGFt -cGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVjZSBXYXluZTEfMB0GCSqG -SIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAJr9a2EJ5qrut+xy6sT76oR064xh58oJruQJuT0p+Dw3b6Zx1Vor -RdAi/mwKwLyknkQm1vY0a3fl+z/epo3sD//HoP9NmFXbxV2VgIuMuZ+XBupPprzv -jjnds7ejsTC2Bssb8W5Q4PRpXushMjQcS/BWFQDAkxyMcyizJvLWK1ltLe5yle+N -3+T+1IdcA/Ucg+QfQ+DMU8DiLXVqmkfzK8stpjVhn0qEOlTs0el8x+3lCbHZbojJ -+4QTpUbcsXH9AdIxYOmRuREBXQMnF65gjwW4SIgN+1l5kJyEKHO/uj5BuFwJYm7s -IafxpNnXZX0VYtS7jtE1/SA2M6yJokvxwrmFdWWIpnM7ClowuZTnkhY8ey7/X8YJ -6o0rPHEAgAfutPTzBCudYx8d0eMPp5yxEGLoB/IQk4YgnX3Srz1BHmJri65MU28+ -oOAmWK4r+eakaD0EFRcrDaFYKagZtXJhHPYAZSILLvys90xawFS6Q0JZHtFq4d1Y -ofUZufknSVwKWO04NQVX+0JCN0cG6aPaQGYQCJlHkye4VnsEi3zFRaNpBuYhzrMF -jSW1ffsAc2s9HqJN1GpdYssMuobM/MRMGv27lWhmmPjTi1a8GKOtg8SS0EhNv96S -t/O7CVpBTwb6UVf0mtVmddSGpUdWaFGboYCfUhgsDfl57QawdEThhJaJAgMBAAGj -gfYwgfMwHQYDVR0OBBYEFKPy7nmCG9tPFt3HQvi8pT7TRRVdMIHDBgNVHSMEgbsw -gbiAFKPy7nmCG9tPFt3HQvi8pT7TRRVdoYGUpIGRMIGOMQswCQYDVQQGEwJVUzEW -MBQGA1UECBMNTWFzc2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9uMR8wHQYDVQQK -ExZFeGFtcGxlIEF1dGhvcml0eSBJbmMuMRQwEgYDVQQDEwtCcnVjZSBXYXluZTEf -MB0GCSqGSIb3DQEJARYQcm9vdEBleGFtcGxlLmNvbYIJAL1Tka1O620zMAwGA1Ud -EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAJkEGLCcY8GH/cFhSVa+Mo7hPvoo -kJf2CQMlt1YPPlV1KYjX2JdYVWbhaoM0Zjn6x4u9sUZ+brgRXJiuFtJzyMvtEr8e -nA5zsik1cw6zeWBkV0LVTgXCeLy51x/j6Mo/CBlzt3Ib8h/PSF3+UIMZwTKXEq1x -adCCoklqCBUERiYd3RHJlxIsdG1Yf1yO/auB7dG2Sgh31xPLh9cZxOUiok8zZmGE -rQ35bVPSHioaSKFBjKv1X+p0X8LZpoGpH2s3tDs5r6VlvUDMSKEZ+OUtkaikmXbx -+0+sxRm7MuY3wI62US06qQhvTaiQUkWN1WRhLhkYcxy4Sby8cwr9izETelfgIE/j -vCH2gKcPAx78QZ9/Z9qHp+y1EtQuk7r1ublg1DdLQqDzgz1qcq93iLD1BoKwnU6m -OdSaHjcMZszH3msPDUUbXtTHC0+8K8pPpbZqpaK1C+AVdrVTvbi7WdDvd7O02lLm -2IzZLCytYyx/kb68qxAF7wIVNmJh2VVTKgB/N4TIn60an0GZ1ZVmhJ3tVwxG9EkP -egCgE6Av09s9Cex1ER16Ximt4AWSiVoJucbRuE1Qi1YjdKmnmUPge69Da4GV4XTw -u8cbJ1FNr329EjjZdtbK4CifuOHhyE1FFHD6xxAiGodqH78fu2V3oqLHtocUKz1k -r2+37rbw2rtgjR8o ------END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/gencerts.sh b/UnitTests/TestData/smime/gencerts.sh index 5c8483f887..a6b4e29cca 100755 --- a/UnitTests/TestData/smime/gencerts.sh +++ b/UnitTests/TestData/smime/gencerts.sh @@ -1,57 +1,41 @@ #!/bin/sh # Create the private key for the root (CA) certificate -openssl genrsa -out certificate-authority.key 4096 > /dev/null +if [ ! -e "certificate-authority.key" ]; then + openssl genrsa -out certificate-authority.key 4096 > /dev/null +fi + +# Create the private key for the primary intermediate certificate +if [ ! -e "intermediate1.key" ]; then + openssl genrsa -out intermediate1.key 4096 > /dev/null +fi + +# Create the private key for the secondary intermediate certificate +if [ ! -e "intermediate2.key" ]; then + openssl genrsa -out intermediate2.key 4096 > /dev/null +fi + +# Create the private key for the leaf-node S/MIME certificate +if [ ! -e "smime.key" ]; then + openssl genrsa -out smime.key 4096 > /dev/null +fi + +if [ ! -e "BouncyCastle.Crypto.dll" ]; then + cp ../../bin/Debug/BouncyCastle.Crypto.dll . +fi + +mcs mkcert.cs -r:BouncyCastle.Crypto.dll # Create the root (CA) certificate -echo "========= Certificate Authority =========" -echo "Country Name: US" -echo "State or Province Name: Massachusetts" -echo "Locality Name: Boston" -echo "Organization Name: Example Authority Inc." -echo "Organizational Unit Name: " -echo "Common Name: Bruce Wayne" -echo "Email Address: root@example.com" -echo "=========================================" -openssl req -new -x509 -days 365 -nodes -key certificate-authority.key -out certificate-authority.crt \ - -subj "/C=US/ST=Massachusetts/L=Boston/O=Example Authority Inc./CN=Bruce Wayne/emailAddress=root@example.com" - -# Create the private key for the intermediate certificate -openssl genrsa -out intermediate.key 4096 > /dev/null - -# Create the intermediate certificate signing request (CSR) -echo "========= Intermediate Certificate =========" -echo "Country Name: US" -echo "State or Province Name: Massachusetts" -echo "Locality Name: Boston" -echo "Organization Name: Example Authority Inc." -echo "Organizational Unit Name: " -echo "Common Name: Bruce Wayne" -echo "Email Address: intermediate@example.com" -echo "=========================================" -openssl req -new -key intermediate.key -out intermediate.csr \ - -subj "/C=US/ST=Massachusetts/L=Boston/O=Example Authority Inc./CN=Bruce Wayne/emailAddress=intermediate@example.com" - -# Sign the CSR using the root (CA) certificate -openssl x509 -req -in intermediate.csr -CA certificate-authority.crt -CAkey certificate-authority.key \ - -CAcreateserial -days 365 -out intermediate.crt - -# Create the certificate chain -cat intermediate.crt certificate-authority.crt > chain.crt +mono ./mkcert.exe certificate-authority.cfg > fingerprints.txt + +# Create the primary intermediate certificate +mono ./mkcert.exe intermediate1.cfg >> fingerprints.txt + +# Create the secondary intermediate certificate +mono ./mkcert.exe intermediate2.cfg >> fingerprints.txt # Generate an S/MIME certificate for testing -echo "======== S/MIME Test Certificate ========" -echo "Country Name: US" -echo "State or Province Name: Massachusetts" -echo "Locality Name: Boston" -echo "Organization Name: " -echo "Common Name: MimeKit UnitTests" -echo "Email Address: mimekit@example.com" -echo "=========================================" -openssl genrsa -des3 -out smime.key 4096 > /dev/null -openssl req -new -key smime.key -out smime.csr \ - -subj "/C=US/ST=Massachusetts/L=Boston/CN=MimeKit UnitTests/emailAddress=mimekit@example.com" -openssl x509 -req -days 365 -in smime.csr -CA intermediate.crt -CAkey intermediate.key -set_serial 1 \ - -out smime.crt -setalias "mimekit@example.com" -addtrust emailProtection \ - -addreject clientAuth -addreject serverAuth -trustout -openssl pkcs12 -export -in smime.crt -inkey smime.key -out smime.p12 -chain -CAfile chain.crt +mono ./mkcert.exe smime.cfg >> fingerprints.txt + +cat fingerprints.txt diff --git a/UnitTests/TestData/smime/intermediate.crt b/UnitTests/TestData/smime/intermediate.crt deleted file mode 100644 index cd1a33f096..0000000000 --- a/UnitTests/TestData/smime/intermediate.crt +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFojCCA4oCCQCmi5t4BiehTTANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMC -VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEfMB0G -A1UEChMWRXhhbXBsZSBBdXRob3JpdHkgSW5jLjEUMBIGA1UEAxMLQnJ1Y2UgV2F5 -bmUxHzAdBgkqhkiG9w0BCQEWEHJvb3RAZXhhbXBsZS5jb20wHhcNMTcwNjMwMDEw -MzMyWhcNMTgwNjMwMDEwMzMyWjCBljELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1h -c3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjEfMB0GA1UEChMWRXhhbXBsZSBB -dXRob3JpdHkgSW5jLjEUMBIGA1UEAxMLQnJ1Y2UgV2F5bmUxJzAlBgkqhkiG9w0B -CQEWGGludGVybWVkaWF0ZUBleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAJx2WQPRH26XdXy13g98vCxn/Qo18IEsHbyfnY9KPJz1US/H -EbmGQI1mwEjk9n2mnk5ntGeCO5lwswfPtGhct5oVbWl/kkahdwhim2LU3wdigSwL -IMsrq6uH0rBe/P9owwO+STVolfwc6buG9MrIK8fnNL6eUC86/6MnPbwu3WnWX6cK -DILiWyHWAWqqWNa6y7qgOCjjfUMudodCJgWBsSZJGJDEi7YJ7mvQT8xQ98MN+88U -GDHJRuzPUy986PMa6UcS6IzIZp+sIzfjPPx4uxbKq23kXy0ZwjBkTWSozmAvX+Sf -6ZHPKCeBn4DECs2S0jpYbhhztxeLmmrn1Ry09JOYLxwmUJN5rZJq1SS7xPj0DMMA -Fb5++4zmYXxTB4m9itJMbikLfnOcO6CnZtlLV31G1VBEgOmCAInq0hUFfgObizwL -oCJzXwO6FOO/SOAnivP07aEC2Tc/KFkqZEnC6CR4stUIMMLUdSL5jdCFVyntzQmc -Uf33ccbqeI5BlFHJvoymXLOV4vjB6NnKvV9n2EeXS6f+vTyk6kq3G67RtkqCi1Aq -bHef66DGv1q1If9yYmOeh3Zi8hm7ZrhdbCKctyPr9LDKcEx4TdUOuyTi0m8/cF1Z -Z7JHwJ2uhVhh1XeUBgbJCUwDOrIyzTH3WCDXEmKEz/vt6vwQX52trEUGBODDAgMB -AAEwDQYJKoZIhvcNAQEFBQADggIBAANLYo8Ks+3ZonKyPYlT2TQYHIrkeIR6ONih -e4AOTWjyWyntEYniTx4gFHxxJeU8nwLd/EZG7Oy97GG4o4LljU78bB8aTeS2l4kR -JyJl8SkPXruKGKtJJ74B19RhofRRROO6KDuLt6IDqPrx9CDx+oQMN8I2kfPaZII+ -puOn77PwGqxWOauMbOjNgcBDM0cDOsNjx+cCOEULAYRT/V6ilmBbnDaFCZaQj0u2 -BNQ/oRa2avWVpT8WByGr7DXXrn3ad1KmLNEP6pFwGzjOP1/gAydm2YxxoYmGGFQt -ylRQvQygoUBnzQkdstnmbHmdmdOslZnOVuNttAUmlXRUH0atNFG12FUFK3Wi4wzn -9Kh5i/8fCyOxnzANixHOEB+MsYYJbxzb/fcA7wanjJd8Tz/uQbxOrTe1KCKHvAd0 -ZgIuUV9IPzRRiGDV5V2dJddki52qexQx24xhFCJbt7s0EQG/F1rdf+atEzhJFclL -AMvPH435Aqf/sI/CT99QcUGY0GNXtNQdUb1HiVQ2SWoFgZpeemkDmoRM/wFloVjH -Wc9RZBszI2PqBGs688EGHyGSD9cjdkxUj9Jpss+B0M64r7Ktu/DC0/VtZGq6CUDX -IHma7oUKs8wOUNpxn2ZJPWlQb5njpz5wSRDel0nTxgKrcjmvKIlewfc2p9BPnsap -S8tVo/sW ------END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/intermediate.csr b/UnitTests/TestData/smime/intermediate.csr deleted file mode 100644 index a65375a2cf..0000000000 --- a/UnitTests/TestData/smime/intermediate.csr +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIE3DCCAsQCAQAwgZYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl -dHRzMQ8wDQYDVQQHEwZCb3N0b24xHzAdBgNVBAoTFkV4YW1wbGUgQXV0aG9yaXR5 -IEluYy4xFDASBgNVBAMTC0JydWNlIFdheW5lMScwJQYJKoZIhvcNAQkBFhhpbnRl -cm1lZGlhdGVAZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCcdlkD0R9ul3V8td4PfLwsZ/0KNfCBLB28n52PSjyc9VEvxxG5hkCNZsBI -5PZ9pp5OZ7RngjuZcLMHz7RoXLeaFW1pf5JGoXcIYpti1N8HYoEsCyDLK6urh9Kw -Xvz/aMMDvkk1aJX8HOm7hvTKyCvH5zS+nlAvOv+jJz28Lt1p1l+nCgyC4lsh1gFq -qljWusu6oDgo431DLnaHQiYFgbEmSRiQxIu2Ce5r0E/MUPfDDfvPFBgxyUbsz1Mv -fOjzGulHEuiMyGafrCM34zz8eLsWyqtt5F8tGcIwZE1kqM5gL1/kn+mRzygngZ+A -xArNktI6WG4Yc7cXi5pq59UctPSTmC8cJlCTea2SatUku8T49AzDABW+fvuM5mF8 -UweJvYrSTG4pC35znDugp2bZS1d9RtVQRIDpggCJ6tIVBX4Dm4s8C6Aic18DuhTj -v0jgJ4rz9O2hAtk3PyhZKmRJwugkeLLVCDDC1HUi+Y3QhVcp7c0JnFH993HG6niO -QZRRyb6MplyzleL4wejZyr1fZ9hHl0un/r08pOpKtxuu0bZKgotQKmx3n+ugxr9a -tSH/cmJjnod2YvIZu2a4XWwinLcj6/SwynBMeE3VDrsk4tJvP3BdWWeyR8CdroVY -YdV3lAYGyQlMAzqyMs0x91gg1xJihM/77er8EF+draxFBgTgwwIDAQABoAAwDQYJ -KoZIhvcNAQEFBQADggIBACgz7EpZwzpWyEwYa9XHCP0cBEXPtHgzQgrXcqS34XlS -yxMBnHmcY3gCJyKCIdxyPblRVWAutceB0LVyKH8rERPaLlGFL54ThytjjBmuYZZW -62xW8oXtae4f1GkEhKJid8gCikv8dlUyS/E+1nI/8PS+6ZXXFuB/2ZiqLU+72r0A -7g8pjvqjsv45tkkmTPG47wfXrgdJAzYauhjqQ+eXRvNq9PGVq9YYuZ/e54teeDr4 -tzkFnIjND7qZnyv17t5GcsRPB0lnwW0+P+7nGSPorMH+qtKsMB9ktcNFD7IDjF3r -B7+keLbMWT+DPupmMdnlmQuC1XuUK9z8FkxPspBorCXZPF2LhZ6V+ciT6no0loCh -q4ShkrhQA1UgJProkuC6SyALTaugnNe1D0G6ekPr2eTUIUw2dKqUELohO9rBs9W7 -BL4S0LHXTpBAimZoP5NHHlHw9exitJqwzSP3Ssc6aBpnen/YKzoHox+ynx4eOkY0 -945WLI+BBUJ1bliYKBjnkaLC3sRCNwaSLMtcC+csQ/auQaMqAMrkq4Wic19hjjtR -Y8YA3CkchH2FG3P5m1DQuyUYm1IBGyP9IEH9/H9ll3SYAvHL3L1QH/EnKqW8IUCG -4AVwwFE6HvXbSBIXuHOZjvJpQaDrc08jxolObguIuQtEJrJb35QH9oPsW1Ys+m8e ------END CERTIFICATE REQUEST----- diff --git a/UnitTests/TestData/smime/intermediate.key b/UnitTests/TestData/smime/intermediate.key deleted file mode 100644 index 9db2f4f8f4..0000000000 --- a/UnitTests/TestData/smime/intermediate.key +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -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 ------END RSA PRIVATE KEY----- diff --git a/UnitTests/TestData/smime/intermediate1.cfg b/UnitTests/TestData/smime/intermediate1.cfg new file mode 100644 index 0000000000..70d830871b --- /dev/null +++ b/UnitTests/TestData/smime/intermediate1.cfg @@ -0,0 +1,22 @@ +[PrivateKey] +Algorithm = RSA +BitLength = 4096 +FileName = intermediate1.key + +[Subject] +CountryName = US +StateOrProvinceName = Massachusetts +LocalityName = Boston +OrganizationName = Example Authority Inc. +OrganizationalUnitName = IT +CommonName = Example Primary Intermediate CA + +[Generator] +BasicConstraints = critical, CA:true +DaysValid = 3650 +Issuer = certificate-authority.pfx +IssuerPassword = no.secret +KeyUsage = critical, cRLSign, keyCertSign +SignatureAlgorithm = SHA256WithRSA +#Output = intermediate1.pfx +Password = no.secret diff --git a/UnitTests/TestData/smime/intermediate1.key b/UnitTests/TestData/smime/intermediate1.key new file mode 100644 index 0000000000..b0ec36c320 --- /dev/null +++ b/UnitTests/TestData/smime/intermediate1.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/UnitTests/TestData/smime/intermediate1.pfx b/UnitTests/TestData/smime/intermediate1.pfx new file mode 100644 index 0000000000..62c345c2ab Binary files /dev/null and b/UnitTests/TestData/smime/intermediate1.pfx differ diff --git a/UnitTests/TestData/smime/intermediate2.cfg b/UnitTests/TestData/smime/intermediate2.cfg new file mode 100644 index 0000000000..1824f85011 --- /dev/null +++ b/UnitTests/TestData/smime/intermediate2.cfg @@ -0,0 +1,22 @@ +[PrivateKey] +Algorithm = RSA +BitLength = 4096 +FileName = intermediate2.key + +[Subject] +CountryName = US +StateOrProvinceName = Massachusetts +LocalityName = Boston +OrganizationName = Example Authority Inc. +OrganizationalUnitName = IT +CommonName = Example Secondary Intermediate CA + +[Generator] +BasicConstraints = critical, CA:true +DaysValid = 3650 +Issuer = intermediate1.pfx +IssuerPassword = no.secret +KeyUsage = critical, cRLSign, keyCertSign +SignatureAlgorithm = SHA256WithRSA +#Output = intermediate2.pfx +Password = no.secret diff --git a/UnitTests/TestData/smime/intermediate2.key b/UnitTests/TestData/smime/intermediate2.key new file mode 100644 index 0000000000..daa8edf7b1 --- /dev/null +++ b/UnitTests/TestData/smime/intermediate2.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/UnitTests/TestData/smime/intermediate2.pfx b/UnitTests/TestData/smime/intermediate2.pfx new file mode 100644 index 0000000000..d4fbd98e9f Binary files /dev/null and b/UnitTests/TestData/smime/intermediate2.pfx differ diff --git a/UnitTests/TestData/smime/mkcert.cs b/UnitTests/TestData/smime/mkcert.cs new file mode 100644 index 0000000000..890747cb09 --- /dev/null +++ b/UnitTests/TestData/smime/mkcert.cs @@ -0,0 +1,493 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Prng; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.X509.Extension; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; + +namespace CertificateGenerator +{ + class Program + { + public static void Main (string[] args) + { + var x509NameOids = CreateX509NameOidMapping (); + var oids = new List (); + var values = new List (); + var privateKey = new PrivateKeyOptions (); + var options = new GeneratorOptions (); + AsymmetricCipherKeyPair key; + string section = null; + string alias = null; + + options.Output = Path.ChangeExtension (args[0], ".pfx"); + + using (var reader = File.OpenText (args[0])) { + string line; + + while ((line = reader.ReadLine ()) != null) { + if (line.Length == 0 || line[0] == '#') + continue; + + if (line[0] == '[') { + int endIndex = line.IndexOf (']'); + + if (endIndex == -1) { + Console.Error.WriteLine ("Incomplete section: ", line); + return; + } + + section = line.Substring (1, endIndex - 1); + continue; + } + + var kvp = line.Split (new char[] { '=' }, 2); + var property = kvp[0].ToLowerInvariant ().Trim (); + var value = kvp[1].Trim (); + + switch (section.ToLowerInvariant ()) { + case "privatekey": + switch (property) { + case "algorithm": + privateKey.Algorithm = value; + break; + case "bitlength": + if (int.TryParse (value, out int bitLength)) { + privateKey.BitLength = bitLength; + } else { + Console.Error.WriteLine ("Invalid [PrivateKey] BitLength: {0}", value); + return; + } + break; + case "filename": + privateKey.FileName = value; + break; + default: + Console.Error.WriteLine ("Unknown [PrivateKey] property: {0}", kvp[0]); + return; + } + break; + case "subject": + if (x509NameOids.TryGetValue (property, out DerObjectIdentifier oid)) { + if (oid == X509Name.CN) + alias = value; + else if (alias == null && oid == X509Name.E) + alias = value; + + values.Add (value); + oids.Add (oid); + } else { + Console.Error.WriteLine ("Unknown [Subject] property: {0}", kvp[0]); + return; + } + break; + case "generator": + switch (property) { + case "basicconstraints": + options.BasicConstraints = value; + break; + case "daysvalid": + if (int.TryParse (value, out int days)) { + options.DaysValid = days; + } else { + Console.Error.WriteLine ("Invalid [Generator] DaysValid: {0}", value); + return; + } + break; + case "issuer": + options.Issuer = value; + break; + case "issuerpassword": + options.IssuerPassword = value; + break; + case "keyusage": + options.KeyUsage = value; + break; + case "output": + options.Output = value; + break; + case "password": + options.Password = value; + break; + case "signaturealgorithm": + options.SignatureAlgorithm = value; + break; + default: + Console.Error.WriteLine ("Unknown [Generator] property: {0}", kvp[0]); + return; + } + break; + default: + Console.Error.WriteLine ("Unknown section: {0}", section); + break; + } + } + } + + // Sanity Checks + if (!string.IsNullOrEmpty (privateKey.FileName) && !File.Exists (privateKey.FileName)) { + Console.Error.WriteLine ("[PrivateKey] FileName `{0}' does not exist!", privateKey.FileName); + return; + } + + if (oids.Count == 0) { + Console.Error.WriteLine ("No [Subject] specified."); + return; + } + + if (string.IsNullOrEmpty (options.Issuer)) { + Console.Error.WriteLine ("[Generator] Issuer property cannot be empty!"); + return; + } else if (options.Issuer != "this" && !File.Exists (options.Issuer)) { + Console.Error.WriteLine ("[Generator] Issuer `{0}' does not exist!", options.Issuer); + return; + } + + if (string.IsNullOrEmpty (options.Output)) { + Console.Error.WriteLine ("[Generator] Output property cannot be empty!"); + return; + } + + var randomGenerator = new CryptoApiRandomGenerator (); + var random = new SecureRandom (randomGenerator); + var subject = new X509Name (oids, values); + + if (string.IsNullOrEmpty (privateKey.FileName)) { + var keyGenerationParameters = new KeyGenerationParameters (random, privateKey.BitLength); + IAsymmetricCipherKeyPairGenerator keyPairGenerator; + + switch (privateKey.Algorithm.ToLowerInvariant ()) { + case "rsa": keyPairGenerator = new RsaKeyPairGenerator (); break; + case "ecdsa": keyPairGenerator = new ECKeyPairGenerator ("ECDSA"); break; + default: Console.Error.WriteLine ("Unsupported PrivateKey algorithm: {0}", privateKey.Algorithm); return; + } + keyPairGenerator.Init (keyGenerationParameters); + key = keyPairGenerator.GenerateKeyPair (); + } else { + try { + key = LoadAsymmetricCipherKeyPair (privateKey.FileName); + } catch (Exception ex) { + Console.Error.WriteLine ("[PrivateKey] Failed to load `{0}': {1}", privateKey.FileName, ex.Message); + return; + } + } + + AsymmetricKeyParameter signingKey; + X509Certificate issuerCertificate; + X509Certificate[] chain; + X509Name issuer; + + if (options.Issuer != "this") { + try { + chain = LoadPkcs12CertificateChain (options.Issuer, options.IssuerPassword, out signingKey); + issuerCertificate = chain[0]; + issuer = chain[0].SubjectDN; + } catch (Exception ex) { + Console.Error.WriteLine ("[Generator] failed to load `{0}': {1}", options.Issuer, ex.Message); + return; + } + } else { + chain = new X509Certificate[0]; + issuerCertificate = null; + signingKey = key.Private; + issuer = subject; + } + + string signatureAlgorithm; + + if (string.IsNullOrEmpty (options.SignatureAlgorithm)) { + if (signingKey is RsaPrivateCrtKeyParameters) { + signatureAlgorithm = "SHA256WithRSA"; + } else if (signingKey is ECPrivateKeyParameters ec) { + if (ec.AlgorithmName == "ECGOST3410") { + signatureAlgorithm = "GOST3411WithECGOST3410"; + } else { + signatureAlgorithm = "SHA256withECDSA"; + } + } else { + signatureAlgorithm = "GOST3411WithGOST3410"; + } + } else { + signatureAlgorithm = options.SignatureAlgorithm; + } + + int serialNumberIndex = oids.IndexOf (X509Name.SerialNumber); + BigInteger serialNumber; + + if (serialNumberIndex == -1) { + serialNumber = BigIntegers.CreateRandomInRange (BigInteger.One, BigInteger.ValueOf (long.MaxValue), random); + } else { + try { + serialNumber = new BigInteger (values[serialNumberIndex]); + } catch { + Console.Error.WriteLine ("Invalid [Subject] SerialNumber: {0}", values[serialNumberIndex]); + return; + } + } + + var notBefore = DateTime.UtcNow; + var notAfter = notBefore.AddDays (options.DaysValid); + + var signatureFactory = new Asn1SignatureFactory (signatureAlgorithm, signingKey, random); + var generator = new X509V3CertificateGenerator (); + generator.SetSerialNumber (serialNumber); + generator.SetPublicKey (key.Public); + generator.SetNotBefore (notBefore); + generator.SetNotAfter (notAfter); + generator.SetSubjectDN (subject); + generator.SetIssuerDN (issuer); + + generator.AddExtension (X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure (key.Public)); + + if (issuerCertificate != null) + generator.AddExtension (X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure (issuerCertificate)); + + if (!string.IsNullOrEmpty (options.BasicConstraints)) { + var basicConstraints = options.BasicConstraints.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + bool critical = false; + bool ca = false; + + foreach (var constraint in basicConstraints) { + switch (constraint.Trim ().ToLowerInvariant ()) { + case "critical": critical = true; break; + case "ca:false": ca = false; break; + case "ca:true": ca = true; break; + } + } + + generator.AddExtension (X509Extensions.BasicConstraints, critical, new BasicConstraints (ca)); + } + + if (!string.IsNullOrEmpty (options.KeyUsage)) { + var keyUsages = options.KeyUsage.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + bool critical = false; + int keyUsage = 0; + + foreach (var usage in keyUsages) { + switch (usage.Trim ().ToLowerInvariant ()) { + case "critical": critical = true; break; + case "digitalsignature": keyUsage |= X509KeyUsage.DigitalSignature; break; + case "nonrepudiation": keyUsage |= X509KeyUsage.NonRepudiation; break; + case "keyencipherment": keyUsage |= X509KeyUsage.KeyEncipherment; break; + case "dataencipherment": keyUsage |= X509KeyUsage.DataEncipherment; break; + case "keyagreement": keyUsage |= X509KeyUsage.KeyAgreement; break; + case "keycertsign": keyUsage |= X509KeyUsage.KeyCertSign; break; + case "crlsign": keyUsage |= X509KeyUsage.CrlSign; break; + case "encipheronly": keyUsage |= X509KeyUsage.EncipherOnly; break; + case "decipheronly": keyUsage |= X509KeyUsage.DecipherOnly; break; + } + } + + generator.AddExtension (X509Extensions.KeyUsage, critical, new KeyUsage (keyUsage)); + } + + var certificate = generator.Generate (signatureFactory); + var keyEntry = new AsymmetricKeyEntry (key.Private); + + var chainEntries = new X509CertificateEntry[chain.Length + 1]; + chainEntries[0] = new X509CertificateEntry (certificate); + for (int i = 0; i < chain.Length; i++) + chainEntries[i + 1] = new X509CertificateEntry (chain[i]); + + var pkcs12 = new Pkcs12Store (); + pkcs12.SetKeyEntry (alias ?? string.Empty, keyEntry, chainEntries); + + using (var stream = File.Create (options.Output)) + pkcs12.Save (stream, options.Password.ToCharArray (), random); + + Console.WriteLine ("{0} {1}", options.Output, GetFingerprint (certificate)); + } + + static AsymmetricCipherKeyPair LoadAsymmetricCipherKeyPair (string fileName) + { + using (var stream = File.OpenRead (fileName)) { + using (var reader = new StreamReader (stream)) { + var pem = new PemReader (reader); + var item = pem.ReadObject (); + + if (item is AsymmetricCipherKeyPair keyPair) + return keyPair; + + if (item is AsymmetricKeyParameter key && key.IsPrivate) { + if (key is RsaPrivateCrtKeyParameters rsa) { + var pub = new RsaKeyParameters (false, rsa.Modulus, rsa.Exponent); + + return new AsymmetricCipherKeyPair (pub, key); + } + } + + throw new Exception ("Invalid asymmetric key pair."); + } + } + } + + static X509Certificate[] LoadPkcs12CertificateChain (string fileName, string password, out AsymmetricKeyParameter key) + { + using (var stream = File.OpenRead (fileName)) { + var pkcs12 = new Pkcs12Store (stream, password.ToCharArray ()); + + foreach (string alias in pkcs12.Aliases) { + if (pkcs12.IsKeyEntry (alias)) { + var chain = pkcs12.GetCertificateChain (alias); + var entry = pkcs12.GetKey (alias); + + if (!entry.Key.IsPrivate) + continue; + + key = entry.Key; + + var certificates = new X509Certificate[chain.Length]; + for (int i = 0; i < chain.Length; i++) + certificates[i] = chain[i].Certificate; + + return certificates; + } + } + } + + throw new Exception ("Failed to locate private key entry."); + } + + static string GetFingerprint (X509Certificate certificate) + { + if (certificate == null) + throw new ArgumentNullException (nameof (certificate)); + + var encoded = certificate.GetEncoded (); + var fingerprint = new StringBuilder (); + var sha1 = new Sha1Digest (); + var data = new byte[20]; + + sha1.BlockUpdate (encoded, 0, encoded.Length); + sha1.DoFinal (data, 0); + + for (int i = 0; i < data.Length; i++) + fingerprint.Append (data[i].ToString ("x2")); + + return fingerprint.ToString (); + } + + static Dictionary CreateX509NameOidMapping () + { + var mapping = new Dictionary (); + mapping.Add ("c", X509Name.C); + mapping.Add ("countrycode", X509Name.C); + mapping.Add ("countryname", X509Name.C); + mapping.Add ("st", X509Name.ST); + mapping.Add ("stateorprovincename", X509Name.ST); + mapping.Add ("l", X509Name.L); + mapping.Add ("localityname", X509Name.L); + mapping.Add ("street", X509Name.Street); + mapping.Add ("postaladdress", X509Name.PostalAddress); + mapping.Add ("postalcode", X509Name.PostalCode); + mapping.Add ("o", X509Name.O); + mapping.Add ("organizationname", X509Name.O); + mapping.Add ("ou", X509Name.OU); + mapping.Add ("organizationalunitname", X509Name.OU); + mapping.Add ("cn", X509Name.CN); + mapping.Add ("commonname", X509Name.CN); + mapping.Add ("e", X509Name.E); + mapping.Add ("emailaddress", X509Name.E); + mapping.Add ("serialnumber", X509Name.SerialNumber); + mapping.Add ("t", X509Name.T); + mapping.Add ("title", X509Name.T); + mapping.Add ("dc", X509Name.DC); + mapping.Add ("uid", X509Name.UID); + mapping.Add ("surname", X509Name.Surname); + mapping.Add ("givenname", X509Name.GivenName); + mapping.Add ("initials", X509Name.Initials); + mapping.Add ("generation", X509Name.Generation); + mapping.Add ("unstructuredaddress", X509Name.UnstructuredAddress); + mapping.Add ("unstructuredname", X509Name.UnstructuredName); + mapping.Add ("uniqueidentifier", X509Name.UniqueIdentifier); + mapping.Add ("dn", X509Name.DnQualifier); + mapping.Add ("pseudonym", X509Name.Pseudonym); + mapping.Add ("nameofbirth", X509Name.NameAtBirth); + mapping.Add ("countryofcitizenship", X509Name.CountryOfCitizenship); + mapping.Add ("countryofresidence", X509Name.CountryOfResidence); + mapping.Add ("gender", X509Name.Gender); + mapping.Add ("placeofbirth", X509Name.PlaceOfBirth); + mapping.Add ("dateofbirth", X509Name.DateOfBirth); + mapping.Add ("businesscategory", X509Name.BusinessCategory); + mapping.Add ("telephonenumber", X509Name.TelephoneNumber); + return mapping; + } + } + + sealed class PrivateKeyOptions + { + public PrivateKeyOptions () + { + Algorithm = "RSA"; + BitLength = 2048; + } + + public string Algorithm { + get; set; + } + + public int BitLength { + get; set; + } + + public string FileName { + get; set; + } + } + + sealed class GeneratorOptions + { + public GeneratorOptions () + { + IssuerPassword = string.Empty; + Password = string.Empty; + } + + public string BasicConstraints { + get; set; + } + + public int DaysValid { + get; set; + } + + public string Issuer { + get; set; + } + + public string IssuerPassword { + get; set; + } + + public string KeyUsage { + get; set; + } + + public string Output { + get; set; + } + + public string Password { + get; set; + } + + public string SignatureAlgorithm { + get; set; + } + } +} diff --git a/UnitTests/TestData/smime/octet-stream-with-mixed-line-endings.dat b/UnitTests/TestData/smime/octet-stream-with-mixed-line-endings.dat new file mode 100644 index 0000000000..78df5f4c33 Binary files /dev/null and b/UnitTests/TestData/smime/octet-stream-with-mixed-line-endings.dat differ diff --git a/UnitTests/TestData/smime/smdh.pem b/UnitTests/TestData/smime/smdh.pem new file mode 100644 index 0000000000..f831b0713b --- /dev/null +++ b/UnitTests/TestData/smime/smdh.pem @@ -0,0 +1,33 @@ +-----BEGIN PRIVATE KEY----- +MIIBSgIBADCCASsGByqGSM4+AgEwggEeAoGBANQMSgwEcnEZ31kZxa9Ef8qOK/AJ +9dMlsXMWVYnf/QevGdN/0Aei/j9a8QHG+CvvTm0DOEKhN9QUtABKsYZag865CA7B +mSdHjQuFqILtzA25sDJ+3+jk9vbss+56ETRll/wasJVLGbmmHNkBMvc1fC1d/sGF +cEn4zJnQvvFaeMgDAoGAaQD9ZvL8FYsJuNxN6qp5VfnfRqYvyi2PWSqtRKPGGC+V +thYg49PRjwPOcXzvOsdEOQ7iH9jTiSvnUdwSSEwYTZkSBuQXAgOMJAWOpoXyaRvh +atziBDoBnWS+/kX5RBhxvS0+em9yfRqAQleuGG+R1mEDihyJc8dWQQPT+O1l4oUC +FQCJlKsQZ0VBrWPGcUCNa54ZW6TH9QQWAhRR2NMZrQSfWthXDO8Lj5WZ34zQrA== +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIID/zCCAuegAwIBAgIJANv1TSKgememMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA4MDIxNDQ5MjlaFw0yMzA2MTExNDQ5MjlaMEQx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU +ZXN0IFMvTUlNRSBFRSBESCAjMTCCAbYwggErBgcqhkjOPgIBMIIBHgKBgQDUDEoM +BHJxGd9ZGcWvRH/KjivwCfXTJbFzFlWJ3/0HrxnTf9AHov4/WvEBxvgr705tAzhC +oTfUFLQASrGGWoPOuQgOwZknR40LhaiC7cwNubAyft/o5Pb27LPuehE0ZZf8GrCV +Sxm5phzZATL3NXwtXf7BhXBJ+MyZ0L7xWnjIAwKBgGkA/Wby/BWLCbjcTeqqeVX5 +30amL8otj1kqrUSjxhgvlbYWIOPT0Y8DznF87zrHRDkO4h/Y04kr51HcEkhMGE2Z +EgbkFwIDjCQFjqaF8mkb4Wrc4gQ6AZ1kvv5F+UQYcb0tPnpvcn0agEJXrhhvkdZh +A4ociXPHVkED0/jtZeKFAhUAiZSrEGdFQa1jxnFAjWueGVukx/UDgYQAAoGAL1ve +cgI2awBeJH8ULBhSQpdL224VUDxFPiXzt8Vu5VLnxPv0pfA5En+8VByTuV7u6RSw +3/78NuTyr/sTyN8YlB1AuXHdTJynA1ICte1xgD4j2ijlq+dv8goOAFt9xkvXx7LD +umJ/cCignXETcNGfMi8+0s0bpMZyoHRdce8DQ26jYDBeMAwGA1UdEwEB/wQCMAAw +DgYDVR0PAQH/BAQDAgXgMB0GA1UdDgQWBBQLWk1ffSXH8p3Bqrdjgi/6jzLnwDAf +BgNVHSMEGDAWgBTffl6IBSQzCN0igQKXzJq3sTMnMDANBgkqhkiG9w0BAQUFAAOC +AQEAWvJj79MW1/Wq3RIANgAhonsI1jufYqxTH+1M0RU0ZXHulgem77Le2Ls1bizi +0SbvfpTiiFGkbKonKtO2wvfqwwuptSg3omMI5IjAGxYbyv2KBzIpp1O1LTDk9RbD +48JMMF01gByi2+NLUQ1MYF+5RqyoRqcyp5x2+Om1GeIM4Q/GRuI4p4dybWy8iC+d +LeXQfR7HXfh+tAum+WzjfLJwbnWbHmPhTbKB01U4lBp6+r8BGHAtNdPjEHqap4/z +vVZVXti9ThZ20EhM+VFU3y2wyapeQjhQvw/A2YRES0Ik7BSj3hHfWH/CTbLVQnhu +Uj6tw18ExOYxqoEGixNLPA5qsQ== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smdsa1.pem b/UnitTests/TestData/smime/smdsa1.pem new file mode 100644 index 0000000000..b424f6704e --- /dev/null +++ b/UnitTests/TestData/smime/smdsa1.pem @@ -0,0 +1,47 @@ +-----BEGIN PRIVATE KEY----- +MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQCQfLlNdehPnTrGIMhw4rk0uua6 +k1nCG3zcyfXli17BdB2k0HBPaTA3a3ZHfOt1Awy0Uu0wZ3gdPr9z0I64hnJXIGou +zIanZ7nYRImHtX5JMFbXeyxo1Owd2Zs3oEk9nQUoUsMxvmYC/ghPL5Zx1pPxcHCO +wzWxoG4yZMjimXOc1/W7zvK/4/g/Cz9fItD3zdcydfgM/hK0/CeYQ21xfhqf4mjK +v9plnCcWgToGI+7H8VK80MFbkO2QKRz3vP1/TjK6PRm9sEeB5b10+SvGv2j2w+CC +0fXL4s6n7PtBlm/bww8xL1/Az8kwejUcII1Dc8uNwwISwGbwaGBvl7IHpm21AiEA +rodZi+nCKZdTL8IgCjX3n0DuhPRkVQPjz/B6VweLW9MCggEAfimkUNwnsGFp7mKM +zJKhHoQkMB1qJzyIHjDzQ/J1xjfoF6i27afw1/WKboND5eseZhlhA2TO5ZJB6nGx +DOE9lVQxYVml++cQj6foHh1TVJAgGl4mWuveW/Rz+NEhpK4zVeEsfMrbkBypPByy +xzF1Z49t568xdIo+e8jLI8FjEdXOIUg4ehB3NY6SL8r4oJ49j/sJWfHcDoWH/LK9 +ZaBF8NpflJe3F40S8RDvM8j2HC+y2Q4QyKk1DXGiH+7yQLGWzr3M73kC3UBnnH0h +Hxb7ISDCT7dCw/lH1nCbVFBOM0ASI26SSsFSXQrvD2kryRcTZ0KkyyhhoPODWpU+ +TQMsxQQjAiEAkolGvb/76X3vm5Ov09ezqyBYt9cdj/FLH7DyMkxO7X0= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFkDCCBHigAwIBAgIJANk5lu6mSyBDMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzFaFw0yMzA1MjYxNzI4MzFaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBEU0EgIzEwggNGMIICOQYHKoZIzjgEATCCAiwCggEBAJB8 +uU116E+dOsYgyHDiuTS65rqTWcIbfNzJ9eWLXsF0HaTQcE9pMDdrdkd863UDDLRS +7TBneB0+v3PQjriGclcgai7MhqdnudhEiYe1fkkwVtd7LGjU7B3ZmzegST2dBShS +wzG+ZgL+CE8vlnHWk/FwcI7DNbGgbjJkyOKZc5zX9bvO8r/j+D8LP18i0PfN1zJ1 ++Az+ErT8J5hDbXF+Gp/iaMq/2mWcJxaBOgYj7sfxUrzQwVuQ7ZApHPe8/X9OMro9 +Gb2wR4HlvXT5K8a/aPbD4ILR9cvizqfs+0GWb9vDDzEvX8DPyTB6NRwgjUNzy43D +AhLAZvBoYG+XsgembbUCIQCuh1mL6cIpl1MvwiAKNfefQO6E9GRVA+PP8HpXB4tb +0wKCAQB+KaRQ3CewYWnuYozMkqEehCQwHWonPIgeMPND8nXGN+gXqLbtp/DX9Ypu +g0Pl6x5mGWEDZM7lkkHqcbEM4T2VVDFhWaX75xCPp+geHVNUkCAaXiZa695b9HP4 +0SGkrjNV4Sx8ytuQHKk8HLLHMXVnj23nrzF0ij57yMsjwWMR1c4hSDh6EHc1jpIv +yvignj2P+wlZ8dwOhYf8sr1loEXw2l+Ul7cXjRLxEO8zyPYcL7LZDhDIqTUNcaIf +7vJAsZbOvczveQLdQGecfSEfFvshIMJPt0LD+UfWcJtUUE4zQBIjbpJKwVJdCu8P +aSvJFxNnQqTLKGGg84NalT5NAyzFA4IBBQACggEAGXSQADbuRIZBjiQ6NikwZl+x +EDEffIE0RWbvwf1tfWxw4ZvanO/djyz5FePO0AIJDBCLUjr9D32nkmIG1Hu3dWgV +86knQsM6uFiMSzY9nkJGZOlH3w4NHLE78pk75xR1sg1MEZr4x/t+a/ea9Y4AXklE +DCcaHtpMGeAx3ZAqSKec+zQOOA73JWP1/gYHGdYyTQpQtwRTsh0Gi5mOOdpoJ0vp +O83xYbFCZ+ZZKX1RWOjJe2OQBRtw739q1nRga1VMLAT/LFSQsSE3IOp8hiWbjnit +1SE6q3II2a/aHZH/x4OzszfmtQfmerty3eQSq3bgajfxCsccnRjSbLeNiazRSKNg +MF4wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0OBBYEFNHQYTOO +xaZ/N68OpxqjHKuatw6sMB8GA1UdIwQYMBaAFMmRUwpjexZbi71E8HaIqSTm5bZs +MA0GCSqGSIb3DQEBBQUAA4IBAQAAiLociMMXcLkO/uKjAjCIQMrsghrOrxn4ZGBx +d/mCTeqPxhcrX2UorwxVCKI2+Dmz5dTC2xKprtvkiIadJamJmxYYzeF1pgRriFN3 +MkmMMkTbe/ekSvSeMtHQ2nHDCAJIaA/k9akWfA0+26Ec25/JKMrl3LttllsJMK1z +Xj7TcQpAIWORKWSNxY/ezM34+9ABHDZB2waubFqS+irlZsn38aZRuUI0K67fuuIt +17vMUBqQpe2hfNAjpZ8dIpEdAGjQ6izV2uwP1lXbiaK9U4dvUqmwyCIPniX7Hpaf +0VnX0mEViXMT6vWZTjLBUv0oKmO7xBkWHIaaX6oyF32pK5AO +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smdsa2.pem b/UnitTests/TestData/smime/smdsa2.pem new file mode 100644 index 0000000000..648447fc89 --- /dev/null +++ b/UnitTests/TestData/smime/smdsa2.pem @@ -0,0 +1,47 @@ +-----BEGIN PRIVATE KEY----- +MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQCQfLlNdehPnTrGIMhw4rk0uua6 +k1nCG3zcyfXli17BdB2k0HBPaTA3a3ZHfOt1Awy0Uu0wZ3gdPr9z0I64hnJXIGou +zIanZ7nYRImHtX5JMFbXeyxo1Owd2Zs3oEk9nQUoUsMxvmYC/ghPL5Zx1pPxcHCO +wzWxoG4yZMjimXOc1/W7zvK/4/g/Cz9fItD3zdcydfgM/hK0/CeYQ21xfhqf4mjK +v9plnCcWgToGI+7H8VK80MFbkO2QKRz3vP1/TjK6PRm9sEeB5b10+SvGv2j2w+CC +0fXL4s6n7PtBlm/bww8xL1/Az8kwejUcII1Dc8uNwwISwGbwaGBvl7IHpm21AiEA +rodZi+nCKZdTL8IgCjX3n0DuhPRkVQPjz/B6VweLW9MCggEAfimkUNwnsGFp7mKM +zJKhHoQkMB1qJzyIHjDzQ/J1xjfoF6i27afw1/WKboND5eseZhlhA2TO5ZJB6nGx +DOE9lVQxYVml++cQj6foHh1TVJAgGl4mWuveW/Rz+NEhpK4zVeEsfMrbkBypPByy +xzF1Z49t568xdIo+e8jLI8FjEdXOIUg4ehB3NY6SL8r4oJ49j/sJWfHcDoWH/LK9 +ZaBF8NpflJe3F40S8RDvM8j2HC+y2Q4QyKk1DXGiH+7yQLGWzr3M73kC3UBnnH0h +Hxb7ISDCT7dCw/lH1nCbVFBOM0ASI26SSsFSXQrvD2kryRcTZ0KkyyhhoPODWpU+ +TQMsxQQiAiAdCUJ5n2Q9hIynN8BMpnRcdfH696BKejGx+2Mr2kfnnA== +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFkDCCBHigAwIBAgIJANk5lu6mSyBEMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzFaFw0yMzA1MjYxNzI4MzFaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBEU0EgIzIwggNGMIICOQYHKoZIzjgEATCCAiwCggEBAJB8 +uU116E+dOsYgyHDiuTS65rqTWcIbfNzJ9eWLXsF0HaTQcE9pMDdrdkd863UDDLRS +7TBneB0+v3PQjriGclcgai7MhqdnudhEiYe1fkkwVtd7LGjU7B3ZmzegST2dBShS +wzG+ZgL+CE8vlnHWk/FwcI7DNbGgbjJkyOKZc5zX9bvO8r/j+D8LP18i0PfN1zJ1 ++Az+ErT8J5hDbXF+Gp/iaMq/2mWcJxaBOgYj7sfxUrzQwVuQ7ZApHPe8/X9OMro9 +Gb2wR4HlvXT5K8a/aPbD4ILR9cvizqfs+0GWb9vDDzEvX8DPyTB6NRwgjUNzy43D +AhLAZvBoYG+XsgembbUCIQCuh1mL6cIpl1MvwiAKNfefQO6E9GRVA+PP8HpXB4tb +0wKCAQB+KaRQ3CewYWnuYozMkqEehCQwHWonPIgeMPND8nXGN+gXqLbtp/DX9Ypu +g0Pl6x5mGWEDZM7lkkHqcbEM4T2VVDFhWaX75xCPp+geHVNUkCAaXiZa695b9HP4 +0SGkrjNV4Sx8ytuQHKk8HLLHMXVnj23nrzF0ij57yMsjwWMR1c4hSDh6EHc1jpIv +yvignj2P+wlZ8dwOhYf8sr1loEXw2l+Ul7cXjRLxEO8zyPYcL7LZDhDIqTUNcaIf +7vJAsZbOvczveQLdQGecfSEfFvshIMJPt0LD+UfWcJtUUE4zQBIjbpJKwVJdCu8P +aSvJFxNnQqTLKGGg84NalT5NAyzFA4IBBQACggEAItQlFu0t7Mw1HHROuuwKLS+E +h2WNNZP96MLQTygOVlqgaJY+1mJLzvl/51LLH6YezX0t89Z2Dm/3SOJEdNrdbIEt +tbu5rzymXxFhc8uaIYZFhST38oQwJOjM8wFitAQESe6/9HZjkexMqSqx/r5aEKTa +LBinqA1BJRI72So1/1dv8P99FavPADdj8V7fAccReKEQKnfnwA7mrnD+OlIqFKFn +3wCGk8Sw7tSJ9g6jgCI+zFwrKn2w+w+iot/Ogxl9yMAtKmAd689IAZr5GPPvV2y0 +KOogCiUYgSTSawZhr+rjyFavfI5dBWzMq4tKx/zAi6MJ+6hGJjJ8jHoT9JAPmaNg +MF4wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0OBBYEFGaxw04k +qpufeGZC+TTBq8oMnXyrMB8GA1UdIwQYMBaAFMmRUwpjexZbi71E8HaIqSTm5bZs +MA0GCSqGSIb3DQEBBQUAA4IBAQCk2Xob1ICsdHYx/YsBzY6E1eEwcI4RZbZ3hEXp +VA72/Mbz60gjv1OwE5Ay4j+xG7IpTio6y2A9ZNepGpzidYcsL/Lx9Sv1LlN0Ukzb +uk6Czd2sZJp+PFMTTrgCd5rXKnZs/0D84Vci611vGMA1hnUnbAnBBmgLXe9pDNRV +6mhmCLLjJ4GOr5Wxt/hhknr7V2e1VMx3Q47GZhc0o/gExfhxXA8+gicM0nEYNakD +2A1F0qDhQGakjuofANHhjdUDqKJ1sxurAy80fqb0ddzJt2el89iXKN+aXx/zEX96 +GI5ON7z/bkVwIi549lUOpWb2Mved61NBzCLKVP7HSuEIsC/I +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smdsa3.pem b/UnitTests/TestData/smime/smdsa3.pem new file mode 100644 index 0000000000..77acc5e46f --- /dev/null +++ b/UnitTests/TestData/smime/smdsa3.pem @@ -0,0 +1,47 @@ +-----BEGIN PRIVATE KEY----- +MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQCQfLlNdehPnTrGIMhw4rk0uua6 +k1nCG3zcyfXli17BdB2k0HBPaTA3a3ZHfOt1Awy0Uu0wZ3gdPr9z0I64hnJXIGou +zIanZ7nYRImHtX5JMFbXeyxo1Owd2Zs3oEk9nQUoUsMxvmYC/ghPL5Zx1pPxcHCO +wzWxoG4yZMjimXOc1/W7zvK/4/g/Cz9fItD3zdcydfgM/hK0/CeYQ21xfhqf4mjK +v9plnCcWgToGI+7H8VK80MFbkO2QKRz3vP1/TjK6PRm9sEeB5b10+SvGv2j2w+CC +0fXL4s6n7PtBlm/bww8xL1/Az8kwejUcII1Dc8uNwwISwGbwaGBvl7IHpm21AiEA +rodZi+nCKZdTL8IgCjX3n0DuhPRkVQPjz/B6VweLW9MCggEAfimkUNwnsGFp7mKM +zJKhHoQkMB1qJzyIHjDzQ/J1xjfoF6i27afw1/WKboND5eseZhlhA2TO5ZJB6nGx +DOE9lVQxYVml++cQj6foHh1TVJAgGl4mWuveW/Rz+NEhpK4zVeEsfMrbkBypPByy +xzF1Z49t568xdIo+e8jLI8FjEdXOIUg4ehB3NY6SL8r4oJ49j/sJWfHcDoWH/LK9 +ZaBF8NpflJe3F40S8RDvM8j2HC+y2Q4QyKk1DXGiH+7yQLGWzr3M73kC3UBnnH0h +Hxb7ISDCT7dCw/lH1nCbVFBOM0ASI26SSsFSXQrvD2kryRcTZ0KkyyhhoPODWpU+ +TQMsxQQjAiEArJr6p2zTbhRppQurHGTdmdYHqrDdZH4MCsD9tQCw1xY= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIFkDCCBHigAwIBAgIJANk5lu6mSyBFMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzFaFw0yMzA1MjYxNzI4MzFaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBEU0EgIzMwggNGMIICOQYHKoZIzjgEATCCAiwCggEBAJB8 +uU116E+dOsYgyHDiuTS65rqTWcIbfNzJ9eWLXsF0HaTQcE9pMDdrdkd863UDDLRS +7TBneB0+v3PQjriGclcgai7MhqdnudhEiYe1fkkwVtd7LGjU7B3ZmzegST2dBShS +wzG+ZgL+CE8vlnHWk/FwcI7DNbGgbjJkyOKZc5zX9bvO8r/j+D8LP18i0PfN1zJ1 ++Az+ErT8J5hDbXF+Gp/iaMq/2mWcJxaBOgYj7sfxUrzQwVuQ7ZApHPe8/X9OMro9 +Gb2wR4HlvXT5K8a/aPbD4ILR9cvizqfs+0GWb9vDDzEvX8DPyTB6NRwgjUNzy43D +AhLAZvBoYG+XsgembbUCIQCuh1mL6cIpl1MvwiAKNfefQO6E9GRVA+PP8HpXB4tb +0wKCAQB+KaRQ3CewYWnuYozMkqEehCQwHWonPIgeMPND8nXGN+gXqLbtp/DX9Ypu +g0Pl6x5mGWEDZM7lkkHqcbEM4T2VVDFhWaX75xCPp+geHVNUkCAaXiZa695b9HP4 +0SGkrjNV4Sx8ytuQHKk8HLLHMXVnj23nrzF0ij57yMsjwWMR1c4hSDh6EHc1jpIv +yvignj2P+wlZ8dwOhYf8sr1loEXw2l+Ul7cXjRLxEO8zyPYcL7LZDhDIqTUNcaIf +7vJAsZbOvczveQLdQGecfSEfFvshIMJPt0LD+UfWcJtUUE4zQBIjbpJKwVJdCu8P +aSvJFxNnQqTLKGGg84NalT5NAyzFA4IBBQACggEAcXvtfiJfIZ0wgGpN72ZeGrJ9 +msUXOxow7w3fDbP8r8nfVkBNbfha8rx0eY6fURFVZzIOd8EHGKypcH1gS6eZNucf +zgsH1g5r5cRahMZmgGXBEBsWrh2IaDG7VSKt+9ghz27EKgjAQCzyHQL5FCJgR2p7 +cv0V4SRqgiAGYlJ191k2WtLOsVd8kX//jj1l8TUgE7TqpuSEpaSyQ4nzJROpZWZp +N1RwFmCURReykABU/Nzin/+rZnvZrp8WoXSXEqxeB4mShRSaH57xFnJCpRwKJ4qS +2uhATzJaKH7vu63k3DjftbSBVh+32YXwtHc+BGjs8S2aDtCW3FtDA7Z6J8BIxaNg +MF4wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0OBBYEFMJxatDE +FCEFGl4uoiQQ1050Ju9RMB8GA1UdIwQYMBaAFMmRUwpjexZbi71E8HaIqSTm5bZs +MA0GCSqGSIb3DQEBBQUAA4IBAQBGZD1JnMep39KMOhD0iBTmyjhtcnRemckvRask +pS/CqPwo+M+lPNdxpLU2w9b0QhPnj0yAS/BS1yBjsLGY4DP156k4Q3QOhwsrTmrK +YOxg0w7DOpkv5g11YLJpHsjSOwg5uIMoefL8mjQK6XOFOmQXHJrUtGulu+fs6FlM +khGJcW4xYVPK0x/mHvTT8tQaTTkgTdVHObHF5Dyx/F9NMpB3RFguQPk2kT4lJc4i +Up8T9mLzaxz6xc4wwh8h70Zw81lkGYhX+LRk3sfd/REq9x4QXQNP9t9qU1CgrBzv +4orzt9cda4r+rleSg2XjWnXzMydE6DuwPVPZlqnLbSYUy660 +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smdsap.pem b/UnitTests/TestData/smime/smdsap.pem new file mode 100644 index 0000000000..249706c8c7 --- /dev/null +++ b/UnitTests/TestData/smime/smdsap.pem @@ -0,0 +1,9 @@ +-----BEGIN DSA PARAMETERS----- +MIIBHwKBgQDFJfsIPOIawMO5biw+AoYUhNVxReBOLQosU3Qv4B8krac0BNr3OjSG +Lh1wZxHqhlAE0QmasTaKojuk20nNWeFnczSz6vDl0IVJEhS8VYor5kt9gLqtGcoA +gsf4gRDIutJyQDaNn3IVY89uXUVIoexvQeLQDBCgQPC5O8rJdqBwtwIVAK2Jjt+d +qk07eQUE59koYUEKyNorAoGBAI4IEpusf8G14kCHmRtnHXM2tG5EWJDmW6Qtwjqv +Wp1GKUx5WFy1tVWR9nl5rL0Di+kNdENo+SkKj7h3uDulGOI6T0mQYbV2h1IK+FMO +GnOqvZ8eNTE2n4PGTo5puZ63LBm+QYrQsrNiUY4vakLFQ2rEK/SLwdsDFK4ZSJCB +Qw5z +-----END DSA PARAMETERS----- diff --git a/UnitTests/TestData/smime/smec1.pem b/UnitTests/TestData/smime/smec1.pem new file mode 100644 index 0000000000..75a862666b --- /dev/null +++ b/UnitTests/TestData/smime/smec1.pem @@ -0,0 +1,22 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgXzBRX9Z5Ib4LAVAS +DMlYvkj0SmLmYvWULe2LfyXRmpWhRANCAAS+SIj2FY2DouPRuNDp9WVpsqef58tV +3gIwV0EOV/xyYTzZhufZi/aBcXugWR1x758x4nHus2uEuEFi3Mr3K3+x +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICoDCCAYigAwIBAgIJANk5lu6mSyBGMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzFaFw0yMzA1MjYxNzI4MzFaMEQx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU +ZXN0IFMvTUlNRSBFRSBFQyAjMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABL5I +iPYVjYOi49G40On1ZWmyp5/ny1XeAjBXQQ5X/HJhPNmG59mL9oFxe6BZHXHvnzHi +ce6za4S4QWLcyvcrf7GjYDBeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXg +MB0GA1UdDgQWBBR/ybxC2DI+Jydhx1FMgPbMTmLzRzAfBgNVHSMEGDAWgBTJkVMK +Y3sWW4u9RPB2iKkk5uW2bDANBgkqhkiG9w0BAQUFAAOCAQEAdk9si83JjtgHHHGy +WcgWDfM0jzlWBsgFNQ9DwAuB7gJd/LG+5Ocajg5XdA5FXAdKkfwI6be3PdcVs3Bt +7f/fdKfBxfr9/SvFHnK7PVAX2x1wwS4HglX1lfoyq1boSvsiJOnAX3jsqXJ9TJiV +FlgRVnhnrw6zz3Xs/9ZDMTENUrqDHPNsDkKEi+9SqIsqDXpMCrGHP4ic+S8Rov1y +S+0XioMxVyXDp6XcL4PQ/NgHbw5/+UcS0me0atZ6pW68C0vi6xeU5vxojyuZxMI1 +DXXwMhOXWaKff7KNhXDUN0g58iWlnyaCz4XQwFsbbFs88TQ1+e/aj3bbwTxUeyN7 +qtcHJA== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smec2.pem b/UnitTests/TestData/smime/smec2.pem new file mode 100644 index 0000000000..457297a760 --- /dev/null +++ b/UnitTests/TestData/smime/smec2.pem @@ -0,0 +1,23 @@ +-----BEGIN PRIVATE KEY----- +MIGPAgEAMBAGByqGSM49AgEGBSuBBAAQBHgwdgIBAQQjhHaq507MOBznelrLG/pl +brnnJi/iEJUUp+Pm3PEiteXqckmhTANKAAQF2zs6vobmoT+M+P2+9LZ7asvFBNi7 +uCzLYF/8j1Scn/spczoC9vNzVhNw+Lg7dnjNL4EDIyYZLl7E0v69luzbvy+q44/8 +6bQ= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICpTCCAY2gAwIBAgIJANk5lu6mSyBHMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzFaFw0yMzA1MjYxNzI4MzFaMEQx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU +ZXN0IFMvTUlNRSBFRSBFQyAjMjBeMBAGByqGSM49AgEGBSuBBAAQA0oABAXbOzq+ +huahP4z4/b70tntqy8UE2Lu4LMtgX/yPVJyf+ylzOgL283NWE3D4uDt2eM0vgQMj +JhkuXsTS/r2W7Nu/L6rjj/zptKNgMF4wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8E +BAMCBeAwHQYDVR0OBBYEFGf+QSQlkN20PsNN7x+jmQIJBDcXMB8GA1UdIwQYMBaA +FMmRUwpjexZbi71E8HaIqSTm5bZsMA0GCSqGSIb3DQEBBQUAA4IBAQBaBBryl2Ez +ftBrGENXMKQP3bBEw4n9ely6HvYQi9IC7HyK0ktz7B2FcJ4z96q38JN3cLxV0DhK +xT/72pFmQwZVJngvRaol0k1B+bdmM03llxCw/uNNZejixDjHUI9gEfbigehd7QY0 +uYDu4k4O35/z/XPQ6O5Kzw+J2vdzU8GXlMBbWeZWAmEfLGbk3Ux0ouITnSz0ty5P +rkHTo0uprlFcZAsrsNY5v5iuomYT7ZXAR3sqGZL1zPOKBnyfXeNFUfnKsZW7Fnlq +IlYBQIjqR1HGxxgCSy66f1oplhxSch4PUpk5tqrs6LeOqc2+xROy1T5YrB3yjVs0 +4ZdCllHZkhop +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smec3.pem b/UnitTests/TestData/smime/smec3.pem new file mode 100644 index 0000000000..90eac867d0 --- /dev/null +++ b/UnitTests/TestData/smime/smec3.pem @@ -0,0 +1,22 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQga03Rl+2K38wgwVyJ +zSy+knGorGWZBGG5p//ke0WUSbqhRANCAARH8uHBHkuOfuyXgJj7V3lNqUEPiQNo +xG8ntGjVmKRHfywdUoQJ1PgfbkCEsBk334rRFmja1r+MYyqn/A9ARiGB +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICoDCCAYigAwIBAgIJAPaEOllWs/pjMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xNzA4MTAxNTQyMDhaFw0yNzA2MTkxNTQyMDhaMEQx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU +ZXN0IFMvTUlNRSBFRSBFQyAjMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEfy +4cEeS45+7JeAmPtXeU2pQQ+JA2jEbye0aNWYpEd/LB1ShAnU+B9uQISwGTffitEW +aNrWv4xjKqf8D0BGIYGjYDBeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXg +MB0GA1UdDgQWBBQLR+H9CmAY/KDyXWdVUM9FP766WzAfBgNVHSMEGDAWgBT3YQTy +KJTdSIrnOcPj3pm5oVNtazANBgkqhkiG9w0BAQsFAAOCAQEAmMRuf8Iz5fr9f0GA +HaNiOM5S7AIfZ6W7zzdeF63EF1j9HqP1DJsUW4y5b9azWmpp62kKuNaM4CGPUVvm +diLKJVlrDcc+6lW9oROpnBsskhjqFMTjTANPQSAKZeKiG2W3U8Q103VQpuYvE4Nj +OU9JT+5e4RZS7wxYk/IsvnyF/DkoF1FTMHo9/3Wiw4V4KRhpJIPnqojWNcfipmhM +UDpbw0Oyj5fE7x6wvaoOUr8GNJE5NudtV/5QDh9REkjyKUdVYsuUrWwKqn3NT8EI +OLl8wx3RqA8htRg/W+SoESx87rvW1saPGvfypBp4cl18B1IzTlC+FMbHFJvZqQn8 +Ci1l4Q== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smime.cfg b/UnitTests/TestData/smime/smime.cfg new file mode 100644 index 0000000000..22921d5737 --- /dev/null +++ b/UnitTests/TestData/smime/smime.cfg @@ -0,0 +1,21 @@ +[PrivateKey] +Algorithm = RSA +BitLength = 4096 +FileName = smime.key + +[Subject] +CountryName = US +StateOrProvinceName = Massachusetts +LocalityName = Boston +CommonName = MimeKit UnitTests +EmailAddress = mimekit@example.com + +[Generator] +BasicConstraints = critical, CA:false +DaysValid = 3650 +Issuer = intermediate2.pfx +IssuerPassword = no.secret +KeyUsage = critical, digitalSignature, keyEncipherment, nonRepudiation +SignatureAlgorithm = SHA256WithRSA +#Output = smime.pfx +Password = no.secret diff --git a/UnitTests/TestData/smime/smime.cnf b/UnitTests/TestData/smime/smime.cnf new file mode 100644 index 0000000000..e2a198b248 --- /dev/null +++ b/UnitTests/TestData/smime/smime.cnf @@ -0,0 +1,31 @@ +# https://serverfault.com/questions/581023/openssl-custom-extension + +[my_cert_extensions] +basicConstraints = CA:FALSE +keyUsage = critical, keyEncipherment, dataEncipherment +SMIME-CAPS = ASN1:SEQUENCE:smime_seq +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer + +[ smime_seq ] +SMIMECapability.0 = SEQWRAP,OID:sha1 +SMIMECapability.1 = SEQWRAP,OID:sha256 +SMIMECapability.2 = SEQWRAP,OID:sha1WithRSA +SMIMECapability.3 = SEQWRAP,OID:aes-256-ecb +SMIMECapability.4 = SEQWRAP,OID:aes-256-cbc +SMIMECapability.5 = SEQWRAP,OID:aes-256-ofb +SMIMECapability.6 = SEQWRAP,OID:aes-192-ecb +SMIMECapability.7 = SEQWRAP,OID:aes-192-cbc +SMIMECapability.8 = SEQWRAP,OID:aes-192-ofb +SMIMECapability.9 = SEQWRAP,OID:aes-128-ecb +SMIMECapability.10 = SEQWRAP,OID:aes-128-cbc +SMIMECapability.11 = SEQWRAP,OID:aes-128-ofb +SMIMECapability.12 = SEQWRAP,OID:camellia-256-cbc +SMIMECapability.13 = SEQWRAP,OID:camellia-192-cbc +SMIMECapability.14 = SEQWRAP,OID:camellia-128-cbc +SMIMECapability.15 = SEQWRAP,OID:des-ede3-cbc +SMIMECapability.16 = SEQUENCE:rsa_enc + +[ rsa_enc ] +capabilityID = OID:rsaEncryption +parameter = NULL diff --git a/UnitTests/TestData/smime/smime.crt b/UnitTests/TestData/smime/smime.crt deleted file mode 100644 index 503c436117..0000000000 --- a/UnitTests/TestData/smime/smime.crt +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN TRUSTED CERTIFICATE----- -MIIFgTCCA2kCAQEwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVTMRYwFAYD -VQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZCb3N0b24xHzAdBgNVBAoTFkV4 -YW1wbGUgQXV0aG9yaXR5IEluYy4xFDASBgNVBAMTC0JydWNlIFdheW5lMScwJQYJ -KoZIhvcNAQkBFhhpbnRlcm1lZGlhdGVAZXhhbXBsZS5jb20wHhcNMTcwNjMwMDEw -MzQyWhcNMTgwNjMwMDEwMzQyWjB2MQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFz -c2FjaHVzZXR0czEPMA0GA1UEBxMGQm9zdG9uMRowGAYDVQQDExFNaW1lS2l0IFVu -aXRUZXN0czEiMCAGCSqGSIb3DQEJARYTbWltZWtpdEBleGFtcGxlLmNvbTCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALktT8OGfHalWgPzIrECgGamORzE -CJMA2/MI8HD2PLhA8sFhwyW+M0jUf2U61BtU9u7uyt/GIWHrFF2eBXYWozxGLeGA -dxZaZ0RHESaU+u4iyDpWQ+GJtPJ+JLefh3Hwx1lde70xTBXvQj9ADo4FyClNoTs7 -tqTtM2vz0uctfNBMuKW7wKi/qbrwwZCOZfWEn/DxAVJE26LfgWFlBPkzbAlJ8xmq -3I3y1D1ZM/vf6B8/w4FJDqP2nIMrLttBttM9ctH1zUPrQx8hEhRHjSn20FFzJkyg -hKNkn8gbpT3XXKABlc1niTas+MGbGMIXqA0RqZz1H9yUlfq+soCd8vyNpq3YKypd -RRHIpHtJ/0Vp4TC4llE316k5CGMlnQrQYzKSuc4A2/3F5zRA1eXm7tYkpuSjPCCd -kZMIrGPPXiARS10FoXQ114Pb2G6ATwQZp47sk50lJmhY0Kk5rt2f8dpMHvz01DTd -J+PCLzGj8T78X+IU8EV5XdByUlwCMUV+e562f3y1pe28F7Bqm++VgeRG+RYKTRCZ -FFsu6sr0LzIH+yT5PFXcjW9F7dxk5DC4MGcaTh1Uw4qb19Mgv66U4367S8EA85Iz -qAO0vFUT+nuRW0fv5qj327KYj275bcVukq3i/sB7h4VSB6uxU0ElR6oYQy9g8GmN -pGawRajzIL2AU8SPAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACoBDq6kv0yNocp3 -MB43HQPQlgwhCHakqFKK3IzN03yKykq+CrQgT69sXq74DBCl1g19mZYSPxruuQPq -SpjM1D9Cah8lv0ydMFo4eYvUe5wOlcyAUmXYuAy5Te9oAaDF7O6370aFpfsJQ7x2 -WOI56/Z2inLHCsmXN4xS5ReNcnId2DSm+AElU72pN8yI13gfPT6jFX2MH9/TLHtn -eb3K2DZX4XEHNDIQfMa0/NHhoaZbftxgx5IZj2YoA8R5AsWQpK8zklMRudPWg2M7 -w3tl+m0V2my7dScpFdFmM/xdcY/rALeXehgiUdajU5pysEq/KHx/RHURhLXywbNx -xIkEIjWhGEkzaid4LVwNsTmDbFVSbG9dJJw19F/937oNeRmdZqoqzJaX1TsnwGpW -xJ7HTDZrMwR7AGuHGoQHPUIXPHyPOJCJQ8/OuevnyJyehnYZ5QUIRV2gkSNY1Dgm -KIrbDyL5L5EDOfa06y2A7bE47or51SrAFGTIEPlJm2Vzgde3js+8/YkWE3xpvp4V -pOICpW1toCnbHlXf4ZVZ/xkhVMqCMqyFKmHhlA8yzSa9NQ3KfNVteRuQSFsJmxE9 -2rW52VNsQUmmYZcREL1Yy3YoZWbmxrIkyCT6ZyehI2n38tO6gPj5rLa/0XXRQYRT -ZCP1jVE0nKn61O/O6ewmOz+ix6GIMDcwCgYIKwYBBQUHAwSgFAYIKwYBBQUHAwIG -CCsGAQUFBwMBDBNtaW1la2l0QGV4YW1wbGUuY29t ------END TRUSTED CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smime.csr b/UnitTests/TestData/smime/smime.csr deleted file mode 100644 index 2b6de09c20..0000000000 --- a/UnitTests/TestData/smime/smime.csr +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIEuzCCAqMCAQAwdjELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0 -dHMxDzANBgNVBAcTBkJvc3RvbjEaMBgGA1UEAxMRTWltZUtpdCBVbml0VGVzdHMx -IjAgBgkqhkiG9w0BCQEWE21pbWVraXRAZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3 -DQEBAQUAA4ICDwAwggIKAoICAQC5LU/Dhnx2pVoD8yKxAoBmpjkcxAiTANvzCPBw -9jy4QPLBYcMlvjNI1H9lOtQbVPbu7srfxiFh6xRdngV2FqM8Ri3hgHcWWmdERxEm -lPruIsg6VkPhibTyfiS3n4dx8MdZXXu9MUwV70I/QA6OBcgpTaE7O7ak7TNr89Ln -LXzQTLilu8Cov6m68MGQjmX1hJ/w8QFSRNui34FhZQT5M2wJSfMZqtyN8tQ9WTP7 -3+gfP8OBSQ6j9pyDKy7bQbbTPXLR9c1D60MfIRIUR40p9tBRcyZMoISjZJ/IG6U9 -11ygAZXNZ4k2rPjBmxjCF6gNEamc9R/clJX6vrKAnfL8jaat2CsqXUURyKR7Sf9F -aeEwuJZRN9epOQhjJZ0K0GMykrnOANv9xec0QNXl5u7WJKbkozwgnZGTCKxjz14g -EUtdBaF0NdeD29hugE8EGaeO7JOdJSZoWNCpOa7dn/HaTB789NQ03Sfjwi8xo/E+ -/F/iFPBFeV3QclJcAjFFfnuetn98taXtvBewapvvlYHkRvkWCk0QmRRbLurK9C8y -B/sk+TxV3I1vRe3cZOQwuDBnGk4dVMOKm9fTIL+ulON+u0vBAPOSM6gDtLxVE/p7 -kVtH7+ao99uymI9u+W3FbpKt4v7Ae4eFUgersVNBJUeqGEMvYPBpjaRmsEWo8yC9 -gFPEjwIDAQABoAAwDQYJKoZIhvcNAQEFBQADggIBAFfDpHAmjrlxpMLaGrs7/2gH -l1vEh5myf9DohL7xcSmzPgoQ+T/oUrPgunVSDL4mpUCDitg0l7vnT/UKQFmA9WZc -cLqATPLMIL9KZj+/jlneqWHrxMW+HRYyyAkaZlpvd4Ofd2876fkLwRpWtBT+NFfA -jQMMl+YqjZKZBEoVHZysWBgwOr03Zpa2tULO+qEK7OviWXd8P2L8ZT2rU5UcjOKY -M5U0oDO9w7xjIVXdmLABiPLGaj5aJH53xx34Axn0QOeWKTCy/HML+M74cSzybVqW -COFJu+xcmDCYb0qeQjogpgcr83tRSnAQ/hreATrtTEqf5FutgjSCbdrFoicOHZex -+hM4hTi1I+T+OWZ7sD6nA2w+qQUaJTkZSxK341rBeHdY1OP20WOk2+l2OiZBQN/j -IUjRwl+I0VyuFcPsYfP0gs4qSbutAUdR6nGeaxXvUFziKwb1ZBtvFMDRQMeFboay -oTtidkcUqTL7ZtxICB92Kr1+fWDTU7DsqAjU8PvnSJqbcGtn3BTfReTbj7GNvcX9 -2KXi8zgLM9s/tP7+ndSWGN3w3gOuoRCHS28jF9z0Mv2EZOWVhCSkWVWx2QJ4oPXq -cQZXsU3CKekNRIc2Ip9+8vIQ4+mfNJxGlGNOuKfoYltDGGNwSBqJIriAM016oRgS -0TJYb0Bdb32TnxzfFsi4 ------END CERTIFICATE REQUEST----- diff --git a/UnitTests/TestData/smime/smime.key b/UnitTests/TestData/smime/smime.key index d8b5f56c6c..612a10438d 100644 --- a/UnitTests/TestData/smime/smime.key +++ b/UnitTests/TestData/smime/smime.key @@ -1,54 +1,51 @@ -----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,940598E44C976B2F - -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 -----END RSA PRIVATE KEY----- diff --git a/UnitTests/TestData/smime/smime.p12 b/UnitTests/TestData/smime/smime.p12 index 3eca9711f7..4720672550 100644 Binary files a/UnitTests/TestData/smime/smime.p12 and b/UnitTests/TestData/smime/smime.p12 differ diff --git a/UnitTests/TestData/smime/smime.pfx b/UnitTests/TestData/smime/smime.pfx new file mode 100644 index 0000000000..7791bb7c7e Binary files /dev/null and b/UnitTests/TestData/smime/smime.pfx differ diff --git a/UnitTests/TestData/smime/smimev0.db b/UnitTests/TestData/smime/smimev0.db new file mode 100644 index 0000000000..a321425149 Binary files /dev/null and b/UnitTests/TestData/smime/smimev0.db differ diff --git a/UnitTests/TestData/smime/smroot.pem b/UnitTests/TestData/smime/smroot.pem new file mode 100644 index 0000000000..d1a253f409 --- /dev/null +++ b/UnitTests/TestData/smime/smroot.pem @@ -0,0 +1,49 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyyQXED5HyVWwq +nXyzmY317yMUJrIfsKvREG2C691dJNHgNg+oq5sjt/fzkyS84AvdOiicAsao4cYL +DulthaLpbC7msEBhvwAil0FNb5g3ERupe1KuTdUV1UuD/i6S2VoaNXUBBn1rD9Wc +BBc0lnx/4Wt92eQTI6925pt7ZHPQw2Olp7TQDElyi5qPxCem4uT0g3zbZsWqmmsI +MXbu+K3dEprzqA1ucKXbxUmZNkMwVs2XCmlLxrRUj8C3/zENtH17HWCznhR/IVcV +kgIuklkeiDsEhbWvUQumVXR7oPh/CPZAbjGqq5mVueHSHrp7brBVZKHZvoUka28Q +LWitq1W5AgMBAAECggEASkRnOMKfBeOmQy2Yl6K57eeg0sYgSDnDpd0FINWJ5x9c +b58FcjOXBodtYKlHIY6QXx3BsM0WaSEge4d+QBi7S+u8r+eXVwNYswXSArDQsk9R +Bl5MQkvisGciL3pvLmFLpIeASyS/BLJXMbAhU58PqK+jT2wr6idwxBuXivJ3ichu +ISdT1s2aMmnD86ulCD2DruZ4g0mmk5ffV+Cdj+WWkyvEaJW2GRYov2qdaqwSOxV4 +Yve9qStvEIWAf2cISQjbnw2Ww6Z5ebrqlOz9etkmwIly6DTbrIneBnoqJlFFWGlF +ghuzc5RE2w1GbcKSOt0qXH44MTf/j0r86dlu7UIxgQKBgQDq0pEaiZuXHi9OQAOp +PsDEIznCU1bcTDJewANHag5DPEnMKLltTNyLaBRulMypI+CrDbou0nDr29VOzfXx +mNvi/c7RttOBOx7kXKvu0JUFKe2oIWRsg0KsyMX7UFMVaHFgrW+8DhQc7HK7URiw +nitOnA7YwIHRF9BMmcWcLFEYBQKBgQDC6LPbXV8COKO0YCfGXPnE7EZGD/p0Q92Z +8CoSefphEScSdO1IpxFXG7fOZ4x2GQb9q7D3IvaeKAqNjUjkuyxdB30lIWDBwSWw +fFgsa2SZwD5P60G/ar50YJr6LiF333aUMDVmC9swFfZERAEmGUz2NTrPWQdIx/lu +PyDtUR75JQKBgHaoCCJ8vl5SJl1IA5GV4Bo8IoeLTSzsY9d09zMy6BoZcMD1Ix2T +5S2cXhayoegl9PT6bsYSGHVWFCdJ86ktMI826TcXRzDaCvYhzc9THroJQcnfdbtP +aHWezkv7fsAmkoPjn75K7ubeo+r7Q5qbkg6a1PW58N8TRXIvkackzaVxAoGBALAq +qh3U+AHG9dgbrPeyo6KkuCOtX39ks8/mbfCDRZYkbb9V5f5r2tVz3R93IlK/7jyr +yWimtmde46Lrl33922w+T5OW5qBZllo9GWkUrDn3s5qClcuQjJIdmxYTSfbSCJiK +NkmE39lHkG5FVRB9f71tgTlWS6ox7TYDYxx83NTtAoGAUJPAkGt4yGAN4Pdebv53 +bSEpAAULBHntiqDEOu3lVColHuZIucml/gbTpQDruE4ww4wE7dOhY8Q4wEBVYbRI +vHkSiWpJUvZCuKG8Foh5pm9hU0qb+rbQV7NhLJ02qn1AMGO3F/WKrHPPY8/b9YhQ +KfvPCYimQwBjVrEnSntLPR0= +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDbjCCAlagAwIBAgIJAMc+8VKBJ/S9MA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MjlaFw0yMzA3MTUxNzI4MjlaMEQx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU +ZXN0IFMvTUlNRSBSU0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALLJBcQPkfJVbCqdfLOZjfXvIxQmsh+wq9EQbYLr3V0k0eA2D6irmyO39/OT +JLzgC906KJwCxqjhxgsO6W2FoulsLuawQGG/ACKXQU1vmDcRG6l7Uq5N1RXVS4P+ +LpLZWho1dQEGfWsP1ZwEFzSWfH/ha33Z5BMjr3bmm3tkc9DDY6WntNAMSXKLmo/E +J6bi5PSDfNtmxaqaawgxdu74rd0SmvOoDW5wpdvFSZk2QzBWzZcKaUvGtFSPwLf/ +MQ20fXsdYLOeFH8hVxWSAi6SWR6IOwSFta9RC6ZVdHug+H8I9kBuMaqrmZW54dIe +untusFVkodm+hSRrbxAtaK2rVbkCAwEAAaNjMGEwHQYDVR0OBBYEFMmRUwpjexZb +i71E8HaIqSTm5bZsMB8GA1UdIwQYMBaAFMmRUwpjexZbi71E8HaIqSTm5bZsMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IB +AQAwpIVWQey2u/XoQSMSu0jd0EZvU+lhLaFrDy/AHQeG3yX1+SAOM6f6w+efPvyb +Op1NPI9UkMPb4PCg9YC7jgYokBkvAcI7J4FcuDKMVhyCD3cljp0ouuKruvEf4FBl +zyQ9pLqA97TuG8g1hLTl8G90NzTRcmKpmhs18BmCxiqHcTfoIpb3QvPkDX8R7LVt +9BUGgPY+8ELCgw868TuHh/Cnc67gBtRjBp0sCYVzGZmKsO5f1XdHrAZKYN5mEp0C +7/OqcDoFqORTquLeycg1At/9GqhDEgxNrqA+YEsPbLGAfsNuXUsXs2ubpGsOZxKt +Emsny2ah6fU2z7PztrUy/A80 +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smrsa1.pem b/UnitTests/TestData/smime/smrsa1.pem new file mode 100644 index 0000000000..d0d0b9e66b --- /dev/null +++ b/UnitTests/TestData/smime/smrsa1.pem @@ -0,0 +1,49 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDXr9uzB/20QXKC +xhkfNnJvl2xl1hzdOcrQmAqo+AAAcA/D49ImuJDVQRaK2bcj54XB26i1kXuOrxID +3/etUb8yudfx8OAVwh8G0xVA4zhr8uXW85W2tBr4v0Lt+W6lSd6Hmfrk4GmE9LTU +/vzl9HUPW6SZShN1G0nY6oeUXvLi0vasEUKv3a51T6JFYg4c7qt5RCk/w8kwrQ0D +orQwCdkOPEIiC4b+nPStF12SVm5bx8rbYzioxuY/PdSebvt0APeqgRxSpCxqYnHs +CoNeHzSrGXcP0COzFeUOz2tdrhmH09JLbGZs4nbojPxMkjpJSv3/ekDG2CHYxXSH +XxpJstxZAgMBAAECggEASY4xsJaTEPwY3zxLqPdag2/yibBBW7ivz/9p80HQTlXp +KnbxXj8nNXLjCytAZ8A3P2t316PrrTdLP4ML5lGwkM4MNPhek00GY79syhozTa0i +cPHVJt+5Kwee/aVI9JmCiGAczh0yHyOM3+6ttIZvvXMVaSl4BUHvJ0ikQBc5YdzL +s6VM2gCOR6K6n+39QHDI/T7WwO9FFSNnpWFOCHwAWtyBMlleVj+xeZX8OZ/aT+35 +27yjsGNBftWKku29VDineiQC+o+fZGJs6w4JZHoBSP8TfxP8fRCFVNA281G78Xak +cEnKXwZ54bpoSa3ThKl+56J6NHkkfRGb8Rgt/ipJYQKBgQD5DKb82mLw85iReqsT +8bkp408nPOBGz7KYnQsZqAVNGfehM02+dcN5z+w0jOj6GMPLPg5whlEo/O+rt9ze +j6c2+8/+B4Bt5oqCKoOCIndH68jl65+oUxFkcHYxa3zYKGC9Uvb+x2BtBmYgvDRG +ew6I2Q3Zyd2ThZhJygUZpsjsbQKBgQDdtNiGTkgWOm+WuqBI1LT5cQfoPfgI7/da +ZA+37NBUQRe0cM7ddEcNqx7E3uUa1JJOoOYv65VyGI33Ul+evI8h5WE5bupcCEFk +LolzbMc4YQUlsySY9eUXM8jQtfVtaWhuQaABt97l+9oADkrhA+YNdEu2yiz3T6W+ +msI5AnvkHQKBgDEjuPMdF/aY6dqSjJzjzfgg3KZOUaZHJuML4XvPdjRPUlfhKo7Q +55/qUZ3Qy8tFBaTderXjGrJurc+A+LiFOaYUq2ZhDosguOWUA9yydjyfnkUXZ6or +sbvSoM+BeOGhnezdKNT+e90nLRF6cQoTD7war6vwM6L+8hxlGvqDuRNFAoGAD4K8 +d0D4yB1Uez4ZQp8m/iCLRhM3zCBFtNw1QU/fD1Xye5w8zL96zRkAsRNLAgKHLdsR +355iuTXAkOIBcJCOjveGQsdgvAmT0Zdz5FBi663V91o+IDlryqDD1t40CnCKbtRG +hng/ruVczg4x7OYh7SUKuwIP/UlkNh6LogNreX0CgYBQF9troLex6X94VTi1V5hu +iCwzDT6AJj63cS3VRO2ait3ZiLdpKdSNNW2WrlZs8FZr/mVutGEcWho8BugGMWST +1iZkYwly9Xfjnpd0I00ZIlr2/B3+ZsK8w5cOW5Lpb7frol6+BkDnBjbNZI5kQndn +zQpuMJliRlrq/5JkIbH6SA== +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIJANk5lu6mSyBAMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzBaFw0yMzA1MjYxNzI4MzBaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBSU0EgIzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDXr9uzB/20QXKCxhkfNnJvl2xl1hzdOcrQmAqo+AAAcA/D49ImuJDVQRaK +2bcj54XB26i1kXuOrxID3/etUb8yudfx8OAVwh8G0xVA4zhr8uXW85W2tBr4v0Lt ++W6lSd6Hmfrk4GmE9LTU/vzl9HUPW6SZShN1G0nY6oeUXvLi0vasEUKv3a51T6JF +Yg4c7qt5RCk/w8kwrQ0DorQwCdkOPEIiC4b+nPStF12SVm5bx8rbYzioxuY/PdSe +bvt0APeqgRxSpCxqYnHsCoNeHzSrGXcP0COzFeUOz2tdrhmH09JLbGZs4nbojPxM +kjpJSv3/ekDG2CHYxXSHXxpJstxZAgMBAAGjYDBeMAwGA1UdEwEB/wQCMAAwDgYD +VR0PAQH/BAQDAgXgMB0GA1UdDgQWBBTmjc+lrTQuYx/VBOBGjMvufajvhDAfBgNV +HSMEGDAWgBTJkVMKY3sWW4u9RPB2iKkk5uW2bDANBgkqhkiG9w0BAQUFAAOCAQEA +dr2IRXcFtlF16kKWs1VTaFIHHNQrfSVHBkhKblPX3f/0s/i3eXgwKUu7Hnb6T3/o +E8L+e4ioQNhahTLt9ruJNHWA/QDwOfkqM3tshCs2xOD1Cpy7Bd3Dn0YBrHKyNXRK +WelGp+HetSXJGW4IZJP7iES7Um0DGktLabhZbe25EnthRDBjNnaAmcofHECWESZp +lEHczGZfS9tRbzOCofxvgLbF64H7wYSyjAe6R8aain0VRbIusiD4tCHX/lOMh9xT +GNBW8zTL+tV9H1unjPMORLnT0YQ3oAyEND0jCu0ACA1qGl+rzxhF6bQcTUNEbRMu +9Hjq6s316fk4Ne0EUF3PbA== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smrsa2.pem b/UnitTests/TestData/smime/smrsa2.pem new file mode 100644 index 0000000000..2f17cb2978 --- /dev/null +++ b/UnitTests/TestData/smime/smrsa2.pem @@ -0,0 +1,49 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcYC4tS2Uvn1Z2 +iDgtfkJA5tAqgbN6X4yK02RtVH5xekV9+6+eTt/9S+iFAzAnwqR/UB1R67ETrsWq +V8u9xLg5fHIwIkmu9/6P31UU9cghO7J1lcrhHvooHaFpcXepPWQacpuBq2VvcKRD +lDfVmdM5z6eS3dSZPTOMMP/xk4nhZB8mcw27qiccPieS0PZ9EZB63T1gmwaK1Rd5 +U94Pl0+zpDqhViuXmBfiIDWjjz0BzHnHSz5Rg4S3oXF1NcojhptIWyI0r7dgn5J3 +NxC4kgKdjzysxo6iWd0nLgz7h0jUdj79EOis4fg9G4f0EFWyQf7iDxGaA93Y9ePB +Jv5iFZVZAgMBAAECggEBAILIPX856EHb0KclbhlpfY4grFcdg9LS04grrcTISQW1 +J3p9nBpZ+snKe6I8Yx6lf5PiipPsSLlCliHiWpIzJZVQCkAQiSPiHttpEYgP2IYI +dH8dtznkdVbLRthZs0bnnPmpHCpW+iqpcYJ9eqkz0cvUNUGOjjWmwWmoRqwp/8CW +3S1qbkQiCh0Mk2fQeGar76R06kXQ9MKDEj14zyS3rJX+cokjEoMSlH8Sbmdh2mJz +XlNZcvqmeGJZwQWgbVVHOMUuZaKJiFa+lqvOdppbqSx0AsCRq6vjmjEYQEoOefYK +3IJM9IvqW5UNx0Cy4kQdjhZFFwMO/ALD3QyF21iP4gECgYEA+isQiaWdaY4UYxwK +Dg+pnSCKD7UGZUaCUIv9ds3CbntMOONFe0FxPsgcc4jRYQYj1rpQiFB8F11+qXGa +P/IHcnjr2+mTrNY4I9Bt1Lg+pHSS8QCgzeueFybYMLaSsXUo7tGwpvw6UUb6/YWI +LNCzZbrCLg1KZjGODhhxtvN45ZkCgYEA4YNSe+GMZlxgsvxbLs86WOm6DzJUPvxN +bWmni0+Oe0cbevgGEUjDVc895uMFnpvlgO49/C0AYJ+VVbStjIMgAeMnWj6OZoSX +q49rI8KmKUxKgORZiiaMqGWQ7Rxv68+4S8WANsjFxoUrE6dNV3uYDIUsiSLbZeI8 +38KVTcLohcECgYEAiOdyWHGq0G4xl/9rPUCzCMsa4velNV09yYiiwBZgVgfhsawm +hQpOSBZJA60XMGqkyEkT81VgY4UF4QLLcD0qeCnWoXWVHFvrQyY4RNZDacpl87/t +QGO2E2NtolL3umesa+2TJ/8Whw46Iu2llSjtVDm9NGiPk5eA7xPPf1iEi9kCgYAb +0EmVE91wJoaarLtGS7LDkpgrFacEWbPnAbfzW62UENIX2Y1OBm5pH/Vfi7J+vHWS +8E9e0eIRCL2vY2hgQy/oa67H151SkZnvQ/IP6Ar8Xvd1bDSK8HQ6tMQqKm63Y9g0 +KDjHCP4znOsSMnk8h/bZ3HcAtvbeWwftBR/LBnYNQQKBgA1leIXLLHRoX0VtS/7e +y7Xmn7gepj+gDbSuCs5wGtgw0RB/1z/S3QoS2TCbZzKPBo20+ivoRP7gcuFhduFR +hT8V87esr/QzLVpjLedQDW8Xb7GiO3BsU/gVC9VcngenbL7JObl3NgvdreIYo6+n +yrLyf+8hjm6H6zkjqiOkHAl+ +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIJANk5lu6mSyBBMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzBaFw0yMzA1MjYxNzI4MzBaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBSU0EgIzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQDcYC4tS2Uvn1Z2iDgtfkJA5tAqgbN6X4yK02RtVH5xekV9+6+eTt/9S+iF +AzAnwqR/UB1R67ETrsWqV8u9xLg5fHIwIkmu9/6P31UU9cghO7J1lcrhHvooHaFp +cXepPWQacpuBq2VvcKRDlDfVmdM5z6eS3dSZPTOMMP/xk4nhZB8mcw27qiccPieS +0PZ9EZB63T1gmwaK1Rd5U94Pl0+zpDqhViuXmBfiIDWjjz0BzHnHSz5Rg4S3oXF1 +NcojhptIWyI0r7dgn5J3NxC4kgKdjzysxo6iWd0nLgz7h0jUdj79EOis4fg9G4f0 +EFWyQf7iDxGaA93Y9ePBJv5iFZVZAgMBAAGjYDBeMAwGA1UdEwEB/wQCMAAwDgYD +VR0PAQH/BAQDAgXgMB0GA1UdDgQWBBT0arpyYMHXDPVL7MvzE+lx71L7sjAfBgNV +HSMEGDAWgBTJkVMKY3sWW4u9RPB2iKkk5uW2bDANBgkqhkiG9w0BAQUFAAOCAQEA +I8nM42am3aImkZyrw8iGkaGhKyi/dfajSWx6B9izBUh+3FleBnUxxOA+mn7M8C47 +Ne18iaaWK8vEux9KYTIY8BzXQZL1AuZ896cXEc6bGKsME37JSsocfuB5BIGWlYLv +/ON5/SJ0iVFj4fAp8z7Vn5qxRJj9BhZDxaO1Raa6cz6pm0imJy9v8y01TI6HsK8c +XJQLs7/U4Qb91K+IDNX/lgW3hzWjifNpIpT5JyY3DUgbkD595LFV5DDMZd0UOqcv +6cyN42zkX8a0TWr3i5wu7pw4k1oD19RbUyljyleEp0DBauIct4GARdBGgi5y1H2i +NzYzLAPBkHCMY0Is3KKIBw== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/smime/smrsa3.pem b/UnitTests/TestData/smime/smrsa3.pem new file mode 100644 index 0000000000..14c27f64aa --- /dev/null +++ b/UnitTests/TestData/smime/smrsa3.pem @@ -0,0 +1,49 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyK+BTAOJKJjji +OhY60NeZjzGGZxEBfCm62n0mwkzusW/V/e63uwj6uOVCFoVBz5doMf3M6QIS2jL3 +Aw6Qs5+vcuLA0gHrqIwjYQz1UZ5ETLKLKbQw6YOIVfsFSTxytUVpfcByrubWiLKX +63theG1/IVokDK/9/k52Kyt+wcCjuRb7AJQFj2OLDRuWm/gavozkK103gQ+dUq4H +XamZMtTq1EhQOfc0IUeCOEL6xz4jzlHHfzLdkvb7Enhav2sXDfOmZp/DYf9IqS7l +vFkkINPVbYFBTexaPZlFwmpGRjkmoyH/w+Jlcpzs+w6p1diWRpaSn62bbkRN49j6 +L2dVb+DfAgMBAAECggEAciwDl6zdVT6g/PbT/+SMA+7qgYHSN+1koEQaJpgjzGEP +lUUfj8TewCtzXaIoyj9IepBuXryBg6snNXpT/w3bqgYon/7zFBvxkUpDj4A5tvKf +BuY2fZFlpBvUu1Ju1eKrFCptBBBoA9mc+BUB/ze4ktrAdJFcxZoMlVScjqGB3GdR +OHw2x9BdWGCJBhiu9VHhAAb/LVWi6xgDumYSWZwN2yovg+7J91t5bsENeBRHycK+ +i5dNFh1umIK9N0SH6bpHPnLHrCRchrQ6ZRRxL4ZBKA9jFRDeI7OOsJuCvhGyJ1se +snsLjr/Ahg00aiHCcC1SPQ6pmXAVBCG7hf4AX82V4QKBgQDaFDE+Fcpv84mFo4s9 +wn4CZ8ymoNIaf5zPl/gpH7MGots4NT5+Ns+6zzJQ6TEpDjTPx+vDaabP7QGXwVZn +8NAHYvCQK37b+u9HrOt256YYRDOmnJFSbsJdmqzMEzpTNmQ8GuI37cZCS9CmSMv+ +ab/plcwuv0cJRSC83NN2AFyu1QKBgQDRJzKIBQlpprF9rA0D5ZjLVW4OH18A0Mmm +oanw7qVutBaM4taFN4M851WnNIROyYIlkk2fNgW57Y4M8LER4zLrjU5HY4lB0BMX +LQWDbyz4Y7L4lVnnEKfQxWFt9avNZwiCxCxEKy/n/icmVCzc91j9uwKcupdzrN6E +yzPd1s5y4wKBgQCkJvzmAdsOp9/Fg1RFWcgmIWHvrzBXl+U+ceLveZf1j9K5nYJ7 +2OBGer4iH1XM1I+2M4No5XcWHg3L4FEdDixY0wXHT6Y/CcThS+015Kqmq3fBmyrc +RNjzQoF9X5/QkSmkAIx1kvpgXtcgw70htRIrToGSUpKzDKDW6NYXhbA+PQKBgDJK +KH5IJ8E9kYPUMLT1Kc4KVpISvPcnPLVSPdhuqVx69MkfadFSTb4BKbkwiXegQCjk +isFzbeEM25EE9q6EYKP+sAm+RyyJ6W0zKBY4TynSXyAiWSGUAaXTL+AOqCaVVZiL +rtEdSUGQ/LzclIT0/HLV2oTw4KWxtTdc3LXEhpNdAoGBAM3LckiHENqtoeK2gVNw +IPeEuruEqoN4n+XltbEEv6Ymhxrs6T6HSKsEsLhqsUiIvIzH43KMm45SNYTn5eZh +yzYMXLmervN7c1jJe2Y2MYv6hE+Ypj1xGW4w7s8WNKmVzLv97beisD9AZrS7sXfF +RvOAi5wVkYylDxV4238MAZIq +-----END PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDbDCCAlSgAwIBAgIJANk5lu6mSyBCMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV +BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv +TUlNRSBSU0EgUm9vdDAeFw0xMzA3MTcxNzI4MzBaFw0yMzA1MjYxNzI4MzBaMEUx +CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR4wHAYDVQQDDBVU +ZXN0IFMvTUlNRSBFRSBSU0EgIzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCyK+BTAOJKJjjiOhY60NeZjzGGZxEBfCm62n0mwkzusW/V/e63uwj6uOVC +FoVBz5doMf3M6QIS2jL3Aw6Qs5+vcuLA0gHrqIwjYQz1UZ5ETLKLKbQw6YOIVfsF +STxytUVpfcByrubWiLKX63theG1/IVokDK/9/k52Kyt+wcCjuRb7AJQFj2OLDRuW +m/gavozkK103gQ+dUq4HXamZMtTq1EhQOfc0IUeCOEL6xz4jzlHHfzLdkvb7Enha +v2sXDfOmZp/DYf9IqS7lvFkkINPVbYFBTexaPZlFwmpGRjkmoyH/w+Jlcpzs+w6p +1diWRpaSn62bbkRN49j6L2dVb+DfAgMBAAGjYDBeMAwGA1UdEwEB/wQCMAAwDgYD +VR0PAQH/BAQDAgXgMB0GA1UdDgQWBBQ6CkW5sa6HrBsWvuPOvMjyL5AnsDAfBgNV +HSMEGDAWgBTJkVMKY3sWW4u9RPB2iKkk5uW2bDANBgkqhkiG9w0BAQUFAAOCAQEA +JhcrD7AKafVzlncA3cZ6epAruj1xwcfiE+EbuAaeWEGjoSltmevcjgoIxvijRVcp +sCbNmHJZ/siQlqzWjjf3yoERvLDqngJZZpQeocMIbLRQf4wgLAuiBcvT52wTE+sa +VexeETDy5J1OW3wE4A3rkdBp6hLaymlijFNnd5z/bP6w3AcIMWm45yPm0skM8RVr +O3UstEFYD/iy+p+Y/YZDoxYQSW5Vl+NkpGmc5bzet8gQz4JeXtH3z5zUGoDM4XK7 +tXP3yUi2eecCbyjh/wgaQiVdylr1Kv3mxXcTl+cFO22asDkh0R/y72nTCu5fSILY +CscFo2Z2pYROGtZDmYqhRw== +-----END CERTIFICATE----- diff --git a/UnitTests/TestData/text/homedepot-check-inside-now.html b/UnitTests/TestData/text/homedepot-check-inside-now.html new file mode 100644 index 0000000000..c43634ed73 --- /dev/null +++ b/UnitTests/TestData/text/homedepot-check-inside-now.html @@ -0,0 +1,1506 @@ + + + + + + + + + The Home Depot + + + + + + + + + + + +
+ FREE DELIVERY Appliance Purchases $396 or + More‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  + ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌  +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + +
+ + + + + +
+ FREE DELIVERY Appliance Purchases $396 or More  + View as a web page
+
+ + + + + + + + + + + +
+ + + + + +
+ + + + + + +
The Home Depot
+ + + + + + + + +
+ + + + Specials & Offers + + +
+ + +
+
+ + + + + + + + + + + + +
+ + + + + + + + + +
AppliancesBathFlooringLighting & FansToolsHoliday Decor
+
+ + + + + + + + + + +
+ + + + + + +
+ + + + + +
Display images to show real-time content
+ +
+ + + +
+ + + + + + + + + + + +
+ + +
Display images to show real-time content
+ + + + + + + + + + + + + +
+ + + + + + + +
Display images to show real-time content
Display images to show real-time content
+
+ + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
Display images to show real-time content Display images to show real-time contentDisplay images to show real-time content
+ + + + + + + +
+
+ + + + + + + + + + + + + +
+ + + + + +
Display images to show real-time content
+ +
+ + + + + +
Display images to show real-time content
+ + +
+ + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
Display images to show real-time contentDisplay images to show real-time content
+ + + + + +
Display images to show real-time content
+ + + + + +
+ + + + + +
Display images to show real-time content
+ +
+ + + + + + + +
Display images to show real-time contentDisplay images to show real-time content
+ + +
+ +
+ + + + + + + + + + + + + +
+ + Black Friday Savings 20 +
+ + + + + + + + + + + + + +
+ + + + + + + +
Black Friday Savings 22
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + + + +
Black Friday Savings 24
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + + + +
Black Friday Savings 26
+ +
+ + + +
+ + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + +
+ Black Friday Savings 12 + +
+ + + + + + + + +
Black Friday Savings 13
+ + + +
+ + +
+ + + + + + + + + + + + + +
+ + + + + + + +
Black Friday Savings 14Black Friday Savings 15Black Friday Savings 16
+
+ + + + + + + + + + + + + +
+ + + + + +
Black Friday Savings 28
+ +
+ + + +
+ + + + + + + + + + + +
+ + + + + + +
+ + + + + +
Display images to show real-time content
+ +
+ + + + + + + + +
+ + + + +
Display images to show real-time content
+ + + + +
Display images to show real-time content
+ + + + + + + +
Display images to show real-time content
+ + + + +
Display images to show real-time content
+ + + + +
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + +
 
TODAY'S SELECTIONS FOR YOU
+
+ + + + + +
+ + + + + + + +
+ + + + + +
Pressure WashersSnow Blowers
+
+ + + + + + + + + + + +
+ + + + + +
Paint PreparationExtension Cords
+ +
+ + + +
+
+ + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + +
Display images to show real-time content
+ + + + + + + + + + + + +
+ + + + + + + + +
+ + Display images to show real-time content +
+ + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + +
+ + + + + +
Mobile App
+
+ + + + + +
Local Ad
+
+
+
+ + + + +
+
+ + + + + + + + + + +
+ + + + + + +
+ + + + + +
Specials & Offers
+
+ + + + + +
Credit Center
+
+
+
+
+ + + + +
+
+ + + + +
+ + + + + + + + + +
Let's Connect:FBTWPYTInstagram
+
+
+ + + + + +
+ + + + +
+ + + + +
+ + + + + + +
Privacy & Security    Contact Us    Store Finder
+
+
+ + + + + + + + + + + +
+ Except as noted, prices valid through 12/18/2019. Prices may vary by store.

To unsubscribe from future emails, click here. + +

Licenses available here. + + +

†Subject to credit approval. Terms and conditions apply. + + +

NOTE: All offers may not be available in all areas. Prices are in U.S. dollars and are subject to change without notice. +

+ + 2455 Paces Ferry Road, N.W., Atlanta, GA 30339-4024, USA.
©2019 Home Depot Product Authority, LLC. All rights reserved. +
+ + + + +
+ + +
+
+ + +
+
+ + + +
+
+ +
+
+ + + + \ No newline at end of file diff --git a/UnitTests/TestData/text/lorem-ipsum.txt b/UnitTests/TestData/text/lorem-ipsum.txt new file mode 100644 index 0000000000..78b853cff8 --- /dev/null +++ b/UnitTests/TestData/text/lorem-ipsum.txt @@ -0,0 +1,40 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent volutpat, +velit vitae scelerisque sagittis, turpis lorem lobortis est, nec egestas lorem +justo ac libero. Proin sit amet augue mollis, suscipit neque sed, imperdiet +nulla. Ut vitae fermentum mi, a imperdiet augue. Morbi tincidunt nulla nunc, +at sollicitudin tortor viverra et. Mauris sit amet bibendum nibh, ut dapibus +metus. Nunc nec cursus nisi. Donec id porttitor velit. Curabitur pulvinar +augue nec metus finibus euismod. Cras vulputate diam nec mauris aliquam, a +tempus magna porta. Mauris sed risus rhoncus, tempor lacus nec, tristique mi. +Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere +cubilia curae; Phasellus pretium sollicitudin tincidunt. Donec pellentesque +leo nec nisl commodo, et accumsan nunc pharetra. + +Duis aliquam odio enim, sed molestie libero vulputate sed. Praesent eget nisl +varius, tristique odio sed, luctus augue. Pellentesque quis egestas libero, a +molestie augue. Curabitur lacus magna, commodo in facilisis id, tempus et +metus. Pellentesque id mi a magna tincidunt ultricies. Duis tempor vitae arcu +ut mattis. Mauris commodo ligula vitae ante dignissim, sed vehicula urna +ultrices. In vitae accumsan arcu. + +Fusce gravida sem ac velit ullamcorper cursus. Donec tincidunt facilisis diam, +vel molestie massa. Morbi in dictum enim. Vestibulum quis lectus elementum, +finibus magna eget, aliquet lectus. Pellentesque habitant morbi tristique +senectus et netus et malesuada fames ac turpis egestas. Nunc imperdiet eros +ligula, a vestibulum lacus tempus at. Quisque aliquet quam justo, vitae +vehicula tellus aliquam ac. Pellentesque sit amet fermentum leo. Duis aliquam +feugiat sem vel ornare. + +Suspendisse potenti. Aenean pellentesque diam id nunc placerat sagittis. Sed +lacus ipsum, scelerisque sit amet vulputate eu, elementum ut velit. Vivamus +non nibh quis tellus rhoncus ultrices. Suspendisse vel metus quis est +tristique commodo ac vel nisl. Fusce viverra justo vitae felis pellentesque, +ac bibendum sem tincidunt. Ut facilisis luctus facilisis. Fusce non +condimentum ligula. + +Vivamus faucibus elit dui, vitae vehicula turpis mattis sed. Aliquam erat +volutpat. Aliquam a enim nulla. Nullam elementum lacus sem, quis consequat +eros aliquam egestas. Fusce fringilla faucibus sapien, quis dignissim ex +venenatis faucibus. Sed congue nisi mi, id scelerisque eros facilisis vitae. +Ut tortor metus, sodales nec blandit a, molestie eu arcu. Sed dictum congue +tincidunt. Phasellus quis placerat nibh, sed rutrum metus. \ No newline at end of file diff --git a/UnitTests/TestData/text/mimekit.net.html b/UnitTests/TestData/text/mimekit.net.html new file mode 100644 index 0000000000..89b19726f8 --- /dev/null +++ b/UnitTests/TestData/text/mimekit.net.html @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + MimeKit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+

World-Class

+

Parse any message with MimeKit's powerful MIME parser. Properly handles any character encoding.

+

View details »

+
+
+

High Performance

+

MimeKit's parser is orders of magnitude faster than any other MIME parser for .NET. Parse gigabytes of mail in mere seconds rather than the 15 minutes or more that it takes with other .NET MIME parser libraries.

+

View details »

+
+
+

Security

+

MimeKit has full support for S/MIME v3.2, OpenPGP, and DKIM-Signatures.

+

View details »

+
+
+ +

+ +
+
+

Open Source

+

MimeKit and MailKit are open source and completely free for commercial use.

+

View details »

+
+
+

Run Anywhere

+

MimeKit and MailKit support Windows, Linux, Mac, iOS, Android, Windows Phone and more!

+
+
+

Easy To Use

+

MimeKit and MailKit make even the most complex tasks doable.

+
+
+ + + + +

+ +

Help

+ +
+
+

Documentation

+

The documentation portal is the first place to go for help. It has full API coverage and a growing number of source code examples.

+
+
+

Stack Overflow

+

Stack Overflow is a great place to ask questions about MimeKit and MailKit.

+
+
+

Issue Tracker

+

The GitHub Issue Trackers for MimeKit and MailKit are great places to go to file bug reports and make feature requests.

+
+
+ +

+ +

License

+ +

MimeKit is open source under the MIT license and is free for commercial use.

+ +

+ +

Donate

+ +

+ MimeKit and MailKit are personal open source projects that I have put thousands of hours into perfecting + by continuously improving the API based on feedback from developers like yourself, writing documentation, + and optimizing with the goal of making them not only the very best email framework for .NET, but the best + email framework for any programming language. I need your help to achieve this. +

+

If MimeKit and/or MailKit have been helpful to you, please consider donating. Your contributions will be appreciated.

+

+ + Click here to lend your support to MimeKit by making a donation! + +

+ +

+ + + + +
+ + + + + + + + + + + diff --git a/UnitTests/TestData/text/planet-fitness.html b/UnitTests/TestData/text/planet-fitness.html new file mode 100644 index 0000000000..a26309a6b9 --- /dev/null +++ b/UnitTests/TestData/text/planet-fitness.html @@ -0,0 +1,872 @@ + + + + + Planet Fitness + + + + + + + + + + + + + + + + +
Don’t miss our celebrity guest Monday evening
+ + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+                                           +
+ + diff --git a/UnitTests/TestData/text/planet-fitness.txt b/UnitTests/TestData/text/planet-fitness.txt new file mode 100644 index 0000000000..383f0eab62 --- /dev/null +++ b/UnitTests/TestData/text/planet-fitness.txt @@ -0,0 +1,111 @@ +Planet Fitness + + +https://view.email.planetfitness.com/?qs=9a098a031cabde68c0a4260051cd6fe473a2e997a53678ff26b4b199a711a9d2ad0536530d6f837c246b09f644d42016ecfb298f930b7af058e9e454b34f3d818ceb3052ae317b1ac4594aab28a2d788 +View web version. + + + + + + + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ab48e22f7d9e9447a24bee0d865e2726344dbb9445bfe9550309f3710c1455f171c23158086b024cfc6354b301deb2985 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4addbddbe9bb6f8638f98f7bb4a15c3f34a8667b9ea5202381ae63f383208ef093a2e198078d558a251d757d550b613652 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ab48e22f7d9e9447a24bee0d865e2726344dbb9445bfe9550309f3710c1455f171c23158086b024cfc6354b301deb2985 + + + + + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a8ba0ca93b2738893f382a915e100552dea93b7268c997e97f2bda6a942a8e550771190a598fb34b2df0728b183b797cf + + + +Work - In with Jerry O’Connell! + +Tune to to Facebook Live to follow along with celebrity guest Jerry O’Connell as he works out with his family, and you! + +Live-Streamed Monday, 4pm PT, 5pm MT, 6pm CT, 7pm ET + + +Did it! Week 1 of Home Work-Ins was a huge success thanks to all of you! It feels great to keep moving together and it’s getting even better. + + +We have an exciting week 2 of Home Work-Ins lined up with appearances by many celebrity guests including Actor, Director and Talk Show Host Jerry O’Connell, this Monday. + + +Jerry will be joined by a couple of work-in partners of his own - his family! So if you have a friend, roommate or family member nearby, encourage them to join you. + + +Daily Work-Ins are available for anyone and everyone so tune into Facebook Live Monday, March 23rd at 4pm PT, 5pm MT, 6pm CT and 7pm ET for a fun, family-friendly Work-In! +No Equipment Needed - classes 20 Minutes or less + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a8ba0ca93b2738893f382a915e100552dea93b7268c997e97f2bda6a942a8e550771190a598fb34b2df0728b183b797cf +FACEBOOK LIVE > + + +DOWNLOAD OUR FREE APP + +You can also find hundreds of workouts that you can do anywhere, anytime on the Planet Fitness App — which, as always, is completely FREE to everyone. + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ab68f547c9b18e75fbc7581a77f855a97d3cc035bcb44f2f932897021d489b956329d2e63ef426b81463acaac4ec0bf4d + + +If you have questions about the status of your club, visit https://click.email.planetfitness.com/?qs=fd2766e949040b4af2bd2a5e3f2a21ab10cba203117c5a96a5310ee3a0d25d22ffd396de347843f51ef096ebf1e73d07936394f1cf786f54 + + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ab48e22f7d9e9447a24bee0d865e2726344dbb9445bfe9550309f3710c1455f171c23158086b024cfc6354b301deb2985 + + + + + + + + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a8585b54b48d281f53598c4c29fae23fe7a009d3216f71cf84448c557baa18b3cb4c8a953e97f9a4bafeeeb720681efb1 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a6310a6acf8c804014580d5e1662b5a8206046685c970ff2770ff55f7078c4602046e8a96fae53d100e3373ecd7db5799 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a37b21d7bb4301e9e807cf7dc14ab2108c9247373f2a046763a0042f2bb102f55d5658f398dc77175ab6b42a5fb67a0f0 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4a9bc8d7a00cf29e8f017bf396e3f59178472177be72dfb62593e0d8acc24fe8ac609a9b48f3ec05aea93f6e074d05be53 + +https://click.email.planetfitness.com/?qs=fd2766e949040b4af2bd2a5e3f2a21ab10cba203117c5a96a5310ee3a0d25d22ffd396de347843f51ef096ebf1e73d07936394f1cf786f54 +Find a Club + +https://click.email.planetfitness.com/?qs=fd2766e949040b4acc4f4342183d37f6ae0e5e5c1b6a06d331affe132e477c75889922c4cf5cb6cd330a12e1e8988232c95a32d2ac133c58 +Community@PF + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ad196bb82b9436e98956338c61cf13ec8ce9b952d57cad393dcd84667a45d254980c712241061e5c435f09757a0a68302 +About Planet Fitness + +https://click.email.planetfitness.com/?qs=fd2766e949040b4aa5f82506f59dff039c2ae94395e3d9087e4670c1fa355caec85a7b295e3bbc2d85d5212e26cad91534e5b0c06e5f0c80 +Contact Us + + +My Club: Boston, MA + +https://click.email.planetfitness.com/?qs=fd2766e949040b4ab48e22f7d9e9447a24bee0d865e2726344dbb9445bfe9550309f3710c1455f171c23158086b024cfc6354b301deb2985 +planetfitness.com + + +Planet Fitness facilities are independently owned and operated. Offers are valid at participating locations and home club only. State and local taxes, annual membership fee and/or 12-month commitment may apply. There may be incentives offered for enrolling in other memberships. See home club for details. + + + + +https://click.email.planetfitness.com/profile_center.aspx?qs=268c8e2e8c9235dc6f85fdf897f0cab733bfea4c9c36a7f901b3c6827608a64762a095adceb0ea7e9ab59c794fdfdc8095243684b21125583bdaa852c8df792144bca9a725498f92 +Manage Subscription +https://click.email.planetfitness.com/unsub_center.aspx?qs=268c8e2e8c9235dcf6ad43b30405c3205973f0468ea88c55035a9ec86bca16b77bc7f95a7f72c685088d2762b8c4560b97c615d55ae29710f127416eff6a4b48d77d312b06e13365 +Unsubscribe + + +Planet Fitness + +4 Liberty Lane West, Hampton New Hampshire 03842 United States + +(c)2020 Planet Fitness, All rights reserved. diff --git a/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.doc b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.doc new file mode 100644 index 0000000000..10c2778778 Binary files /dev/null and b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.doc differ diff --git a/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.pdf b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.pdf new file mode 100644 index 0000000000..ef5e2b4ad5 Binary files /dev/null and b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_1402.pdf differ diff --git a/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_14021.htm b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_14021.htm new file mode 100644 index 0000000000..ee0d259a33 --- /dev/null +++ b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/VIA_Nytt_14021.htm @@ -0,0 +1,1914 @@ + + + + + + + + + + + + + + + + + + +
+ +

+VIA Nytt 14 - 2002 20 august

+ +

 

+ +

 

+ +

+ + + + + + + + + +
+ +
 

+ +

 

+ +
+ +

+ +


+
VIA Flyspesialisten nsker +den nye konkurransesituasjonen p norsk innenriks velkommen

+ +

Konkurranse skaper dynamikk +i markedet, kt fokus p produktutvikling, service, tilbud, hy motivasjon for + lykkes og ikke minst lavere priser. Hos alle VIA Flyspesialisten byrer +fr du n Norwegian billetter til fordelaktige priser.

+ +

 

+ +

Ny rute fra Stavanger til +Aberdeen, og Trondheim inn p KLMs norgesnett

+ +

25. 8 - to dager fr oljemessen pner i Stavanger - starter +KLM sin nye rute mellom Stavanger og Aberdeen i Skottland. KLM vil starte daglige flyvninger mellom Amsterdam og +Trondheim fra 30. mars neste r. Ruten blir opprettet p grunn av at +Trondheims-omrdet er det fjerde strste markedet i Norge, de fleste av +flypassasjerer fra dette markedet skal til ml utenfor Skandinavia. Ruten vil bli betjent med en 80-seters Fokker 70, og +det blir to rundreiser per dag.

+ +

 

+ +

KLM med lavere +priser

+ +

KLM har innfrt ny og +lavere prisstruktur p sine 66 europeiske destinasjoner. De reduserer ogs antallet +prisklasser kraftig. Prisen vil avhenge av bookingtidspunktet, og lavpriser +krever minimumsopphold p 3dg el. natt lrdag/sndag.

+ +

 

+ +

SAS senker prisene i Norge

+ +

SAS har senket prisene p +lavprisbilletter med 25 prosent, og ligger tett opptil Norwegians laveste +priser nr selskapet kommer p markedet 1. september. P flere ruter i +Sr-Norge koster Norwegian 490 kroner. SAS tilbyr reiser fra 690 kroner. Mens +Norwegian til Nord-Norge vil operere med under 1000 kroner en vei, vil SAS +legge seg p mellom 1.500 og 1.800 kroner. Konkurransetilsynet sier at de vil +flge nye med for se om SAS vil dumpe sine priser. (Dagsavisen)

+ +


+
British +Airways fortsetter sin priskrig mot lavprisselskapene

+ +

BA har kuttet prisene med 80% p sine flyvninger fra +England til destinasjoner i Tyskland, Sveits og sterrike. Prisene starter p 99 p 37 ruter. BA +tilbyr n full service til lavpriser p 108 europeiske ruter. De satte tidligere ned prisene p +britisk innenriks (noe som gav 15% flere reisende) og senket prisene med 80% og +fjernet lrdagsregelen p 42 andre europeiske ruter, deriblant til Norge, +Sverige og Danmark.

+ +

 

+ +

Finnair ker +til Beijing

+ +

Finnair ker 5. +september til Beijing med en ekstra ukentlig avgang ut torsdag og hjem til +Helsinki igjen fredag. Finnair flyver daglig til Bangkok og derfra videre til +hhv. Hong Kong og Singapore. Frem til 31. oktober tilbyr selskapet ca. +1/3 rabatt nr ektefelle/samboer reiser med til sten.

+ +

 

+ +

Sterling med nye +destinasjoner

+ +

Milano/Bergamo blir +fra 13. september ny Sterling- destinasjon fra Kbenhavn og Stockholm. I +tillegg fr Bergen og Stavanger ukentlige direkte ruter til Malaga og Alicante, +og Sterling begynner en ukentlig ruteflyvning til Tenerife.

+ +

 

+ +

Ny rute til +Dsseldorf
+Lufthansa, som nylig ble kret til det mest punktlige flyselskapet i Europa, +vil gjenoppta morgenruten mellom Oslo og Dsseldorf. Avgangen vil starte i +Dsseldorf kl. 0700 med ankomst Gardermoen kl. 0845, mens returen blir fra Oslo +kl. 0920 og ankomst Dsseldorf kl. 1145.

+ +

 

+ +

+ +

 

+ +

Oslo billigste hotell-by
+
Oslo er Skandinavias billigste +hotell-by - dyrest er Stockholm, fulgt av Kbenhavn. Det viser tall fra Horwath +Eurocity Survey, som boarding.no refererer. I oversikten er Oslo p 15. plassen over Europas +dyreste hotellhovedsteder. Dyrest er London med en gjennomsnittspris 150% +hyere end Oslo. Stockholm er p 6. plassen - 28% dyrere enn Oslo.

+ +

 

+ +

 

+ +

I perioder listet opp her forventes det vre vanskelig skaffe +hotellrom:

+ +

Stavanger 27. 30. august ONS +(Oljemessen)

+ +

Stockholm 3. 6. +september QuNordic +Road & Traffic + Elmia Waste & Recykling

+ +

Stockholm +8. 12. september Urology Congress

+ +

Stockholm 14. + 18. september ERS + Network Telecom + SecurIT

+ +

Kbenhavn 21. 25. september EU toppmte

+ +

VIA Flyspesialisten har til dels store romkvoter i vre strste +byer. Bestill derfor din overnatting hos oss.

+ +

 

+ +

Nye hoteller

+ +

30. august pner to nye hoteller i +Danmark: det nybygde Scandic i Kbenhavns Sydhavn og det like s nye Radisson +SAS Hotel i Silkeborg. I +august pnes ogs Hilton Malm City og Hilton Stockholm Infra City. 1. september pner Quality Hotel Aalborg med 168 nye +vrelser, og direkte adgang til Aalborg Kultur og Kongress Center.

+ +

 

+ +

+ +

 

+ +

Jentetur med Hurtigruten fra Bod til +Troms, inkludert spa og moteoppvisning 08-10. november

+ +

F tips og ideer til hud +og hr, med Hurtigrutens egne frisrer og terapeuter. Bli ny i MS Finnmarkens +egen velvreavdeling. Med frisrer, make-up og aromaterapi. Spr vr +fargekonsulent hvilke farger som kler deg best. Eller slapp av under pen +himmel i skipets to boblebad. Vi bor p Rica Ishavshotell og avslutter +lrdagskvelden med et gnistrende moteshow og pflgende middag. Pris fra kr. 3.290,- per person i dobbellugar/rom for hurtigruten inkl. fullpensjon og spennende +foredrag, overnatting lrdag-sndag p Rica Ishavshotell i Troms inkl. +halvpensjon og moteshow, og fly fra Troms til Bod. Tilslutningspriser fra +andre byer ordnes. Teknisk arrangr: Kystopplevelser.

+ +

 

+ +

SAS og Braathens med hyere PTA-avgift

+ +

Med virkning fra 1. oktober +kes PTA-avgiften i Skandinavia til DKK/SEK/NOK 350. Det er alts avgiften +flyselskapet tar for at du som reisebyrkunde skal kunne hente ut billetten p +deres flyplasskontor. I tillegg kommer reisebyrenes honorar. Reis heller +derfor billettlst der det er mulig, eller hent ut billettene for en mye +rimeligere penge p de flyplassene der VIA Flyspesialisten har kontor +(Gardermoen, Sola, Torp, Vrnes og Flesland).

+ +

 

+ +

Utrolige priser p fly og hotell i USA med VIA +Flyspesialisten og Prisma frem til 10. september

+ +

Orlando 4.435, -, New York 5.195, - Washington 5.005, - +Miami 5.050, - Los Angeles 5.545, -

+ +

Prisene +pr. person inkluderer flyreise fra Oslo med skatter og 2 netter p hotell i +delt dobbeltrom. Vi lner deg i tillegg +mobiltelefon som fungerer i USA, og spanderer oppgradering ved leie av +Hertzbil! Reiseperiode: 3/9 - 12/12 2002 (Orlando 23/9 - 12/12, +Los Angeles 25/8 - 10/12). Utreise fra Oslo. Begrenset antall plasser. +Spesielle betingelser.

+ +

 

+ +

Kampanjetilbud med Sterling til Milano

+ +

Sterling starter +flyvninger fra Gardermoen til Milano/Bergamo via Kbenhavn to ganger i uken, +med frste avreise 13. september, og vi tilbyr i den forbindelse knalltilbud: +Oslo Milano kr 998,- t/r. Sterling garanterer at denne prisen vil vre +tilgjengelig s lenge det finnes ledige plasser p flyet! Salgsperioden gjelder +ut august, og reisen m foretaes i september (seneste retur 4.oktober).

+ +

 

+ +

? VISSTE DU AT

+ +

..... Aurstad Parkering p +Gardermoen stenger 23.08.2002 og flytter virksomheten til parkeringsomrde P3, +som befinner seg p hyre side av motorveien inn mot Terminalbygget p Oslo +Lufthavn.

+ +

..Verdens strste pariserhjul - London +Eye ved bredden av Themsen - har ftt permanent tillatelse til bli stende.
+
Det 135 meter hye pariserhjulet, sponset av BA, er siden +pningen i r 2000 blitt beskt av flere enn 8 millioner.

+ +

. Walt +Disney Company vil pne sin tredje temapark i Fjerne sten, denne gang i +Shanghai. Det finnes allerede en i Tokyo og i 2005/6 fr Hong Kong ogs en.

+ +

. N skal de yensynlig ikke lenger +prutes om prisen p turer med tuk-tuk, de sm vognene som fungerer som taxier. +Bl.a. Phuket, Thailands strste y, har de thailandske myndigheder besluttet at +de n skal kjres etter faste priser.

+ +

 

+ +


+
Redaksjonen tar forbehold om +trykkfeil og eventuelle prisendringer i tilbudene som str beskrevet i VIA +Nytt.

+ +

 

+ +

nsker du bli slettet +fra distribusjonslisten for denne utsendelsen? Vennligst meld tilbake til +avsender.

+ +
+ + + + diff --git a/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/message.rtf b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/message.rtf new file mode 100644 index 0000000000..e3c5078f3e Binary files /dev/null and b/UnitTests/TestData/tnef/MAPI_ATTACH_DATA_OBJ/message.rtf differ diff --git a/UnitTests/TestData/tnef/MAPI_OBJECT/Untitled_Attachment b/UnitTests/TestData/tnef/MAPI_OBJECT/Untitled_Attachment new file mode 100644 index 0000000000..4b67570e91 Binary files /dev/null and b/UnitTests/TestData/tnef/MAPI_OBJECT/Untitled_Attachment differ diff --git a/UnitTests/TestData/tnef/MAPI_OBJECT/message.rtf b/UnitTests/TestData/tnef/MAPI_OBJECT/message.rtf new file mode 100644 index 0000000000..98c80bd4de Binary files /dev/null and b/UnitTests/TestData/tnef/MAPI_OBJECT/message.rtf differ diff --git a/UnitTests/TestData/tnef/attachments.list b/UnitTests/TestData/tnef/attachments.list new file mode 100644 index 0000000000..bf987c9469 --- /dev/null +++ b/UnitTests/TestData/tnef/attachments.list @@ -0,0 +1,3 @@ +bookmark.htm +zappa_av1.jpg +body.rtf \ No newline at end of file diff --git a/UnitTests/TestData/tnef/attachments.tnef b/UnitTests/TestData/tnef/attachments.tnef new file mode 100644 index 0000000000..b9f629502c Binary files /dev/null and b/UnitTests/TestData/tnef/attachments.tnef differ diff --git a/UnitTests/TestData/tnef/attachments/bookmark.htm b/UnitTests/TestData/tnef/attachments/bookmark.htm new file mode 100644 index 0000000000..a1cf7112cb --- /dev/null +++ b/UnitTests/TestData/tnef/attachments/bookmark.htm @@ -0,0 +1,578 @@ + + +Bookmarks +

Bookmarks

+

+

Adobe GoLive

+

+

GoLive Actions Resource +
GoLive Actions +
GoLive Headquarters News +
GoLiveHeaven A Hub for the GoLive Community +
http--216.246.51.202-forums-adobe_golive-index.htm +
More Adobe GoLive Actions page one +
OUTactions +

+

ASP Stuff

+

+

ASP - Application service providers +
CRMXchange Gateway to the Contact Center, CRM and Customer Care Community +
PeopleSoft Customer Relationship Management Home +

+

Daily

+

+

Astronomy Picture of the Day Archive +
Best of the Blogs +
Brill's Content +
CamWorld Thinking Outside the Box +
CHUD - Cinematic Happenings Under Development +
Daypop - a current events-weblog-news search engine +
Dotcom Scoop +
dotCULT.com +
drew##^# +
FARK Drew Curtis' FARK.com +
FEED Magazine +
IA EH. Eleganthack is a guide to Information Architecture, Interface Design, Usability, User Ce +
Ironminds +
memepool.com +
Metafilter Community Weblog +
mrbarrett.com +
Plastic +
Salon.com +
SHARPEWORLD america's no. 1 website +
Slashdot News for nerds, stuff that matters +
Suck.com Daily +
Talk Hard Online Forums +
The Morning News +
TheStandard.com homepage +
Wired News +

+

Dell

+

+

Dell Auction +
Dell +
Dellnet +
Gigabuys +
Support.Dell.com +

+

eZines

+

+

Association of Alternative Newsweeklies +
LOST AT SEA online +
MotherJones.com -- News and Resources for the Skeptical Citizen +
Shift.com +

+

Finances

+

+

Fidelity Asset Manager Growth +
Fool.com Finance and Folly -- Main Page +
Fool.com Is Your 401(k) Foolish -- How to Pick a Winner +
IAParticipant +
My Fidelity +
The Motley Fool -- My Fool +
Welcome to Maverick Investing with Doug Fabian! +

+

Fonts

+

+

04 extra bitmap +
1001 Fonts .com +
BLAMBOT Comic Fonts & Lettering +
CHANK FONTS! +
CheapskateFonts - Fonts +
Dr. Design's Definitive Design Links List +
Font Collections in Specialty Themes +
font-o-ville +
Fontmaker [PAGE 1] +
Fontosaurus Text +
Fonts & Things - the most unusual fonts online... +
Free Typewriter Fonts +
Larabie Fonts +
Orgdot open source pixel and led fonts for flash +
phantomphonts +
Small Fonts by Cal Henderson +
The Dog Hause Fonts +
Web Page Design for Designers - Pixel Fonts +
www.pizzadude.dk fonts.html +

+

Funnies

+

+

SatireWire dot.com.edy +
SNL MM (Saturday Night Live Multimedia - snl.jt.org) YOUR SOURCE FOR SNL MULTIMEDIA, saturday n +
The Dialectizer +
Welcome to SNL InfoMedia +

+

Grateful Dead

+

+

(4442) Garcia (Star) +
(4442) Garcia +
A Long, Staid Trip - How Deadheads ruined the Grateful Dead. By MarcWeingarten +
Access Place Grateful Dead - Lyrics, Pictures, MP3, Setlists.. +
BEAR'S ART PAGES +
Betty Board info +
Blair Jackson - Garcia +
Buffalo News Concert Review 7-17-90 +
Concert Posters +
db.etree.org - GD by Year +
Deadhook @ www.ezboard.com +
deadlegs.com mp3 and real audio library of grateful dead quality audio. Mp3 shows and Mp3 bootl +
Deadshow.com +
Did You Know +
Doug Irwins First Amended Petition under Probate Code section 9860 +
Dozin.com +
Eurodead.net - for Grateful Dead fans everywhere +
Eurodead.net Links Directory +
Garcia's Guitars Mac Video Game +
GD CD-R Covers +
Google Search grateful dead 1-20-79 +
Google Search rec.music.gdead +
Google Web Directory - Arts Music BandsandArtists G GratefulDead +
GRAMMY.com - Interview with Dennis McNally +
Grateful Day +
Grateful Dead Almanac +
GRATEFUL DEAD AT WINTERLAND, NEW YEAR'S 1972-73 +
Grateful Dead Family Discography +
Grateful Dead Frequently Asked Questions +
Grateful Dead Links +
GRATEFUL DEAD LIVE - www.gdlive.com +
Grateful Dead Lyric And Song Finder +
Guitar.com - Jerry Garcia The Acoustic Man's Dead +
How to 'Truck' the Brand Lessons from the Grateful Dead - Page 1 +
Jerry Garcias Guitars +
Lone Star Dead web space +
psilo.com - Dead Tickets, Passes, & Laminates +
Rock and Roll Hall of Fame and Museum Hall of Fame Inductee Detail +
RollingStone.com Artists The Grateful Dead +
SHN List for Grateful Dead +
Songs for the Dead +
Strings of gold - There was something special about Doug Irwin's guitars, and Jerry Garcia knew +
TBT Venues New York +
The Annotated Grateful Dead Lyrics, by David Dodd +
The DeadBoard Dead General Got something to talk about +
The Deadheads Newsletters 1972 -1974 +
The Grateful Dead - FBI Files +
The SetList Program +
The Smoking Gun Archive- Garcia's Assets +
TheStandard.com I'm With the Brand +
Uncle Sam and the Grateful Dead +
Wired.com - April 23, 2001 - Deadheads May Not Be Grateful +
www.gdlive.com - -shn- +

+

Indie Music Sites

+

+

--indietabs.net i can't freestyle. i'm a low budget ludacris. +
-30-music ... 30music.com +
3WK Underground Radio - Internet Only Alternative Radio! +
Aversion.com - Rock Punk Indie Music +
barsuk records +
CMJ New Music First +
Comes with a Smile +
Crud Magazine +
Delusions of Adequacy +
Dusted Magazine +
Emmie Magazine +
Epitonic.com Hi Quality Free MP3 Music +
http--www.basement-life.com- +
hybridmagazine.com +
In Music We Trust +
indieworkshop.com +
insound +
j u n k m e d i a music news, reviews & interviews +
L o s t A t S e a . o n l i n e +
Live Indie Rock Music +
mp3.palukaville.net +
P R O J E C T A T L A N T I S Z I N E +
Pitchforkmedia.com +
PopMatters +
Rocket Fuel Online Magazine +
SOUNDTHESIRENS.COM - Independent Online Magazine +
Splendid +
tonevendor.com . welcome +

+

Information Architecture

+

+

Argus Center for Information Architecture +

+

Jobs

+

+

BuffaloJobFinder.com +
GreatJobNetwork.com Jobs in Buffalo, New York +
HotJobs.com +
iambuffaloniagarajobs.com +
Western New York Jobs +

+

Lab

+

+

Black Lab Studios - Gallery Autumn +
Dog Links - E-commerce +
LUCKY LABRADOR BREWING COMPANY +

+

Links

+

+

3WK +
Admin +
BNews +
Board +
CDR +
Demon +
eBay +
Fark +
Google +
jay +
Lishost - Board +
M&T +
MindLeaders +
MSN +
MyFool +
MyUB +
NYT +
PHP +
PortalQA +
PP3 +
PP4 +
Setlist Corrections +
Slash +
TMD +

+

Media

+

+

Bloomberg +
Capitol Records +
CBS +
CNBC Dow Jones Business Video +
CNET Today - Technology News +
CNN Videoselect +
Disney +
ESPN Sports +
Fox News +
Fox Sports +
Hollywood Online +
Internet Radio Guide +
MSNBC +
MUSICVIDEOS.COM +
NBC VideoSeeker +
Sugarmegs Live Stream +
TV Guide Entertainment Network +
Universal Studios Online +
Warner Bros. Hip Clips +
What's On Now +
Windows Media Showcase +

+

Music

+

+

Digital Club Network (DCN) - The Live Music Source +
Epitonic.com Hi Quality Free MP3 Music +
Indie Live MP3s - mp3.palukaville.net +
Live Indie Rock Music +
Live365.com - Broadcast +
MP3.com Buffalo +
MusicToday +
Tim's Secret MP3 Stash +

+

Nice Sites

+

+

Art Technology Group +
Black Dog Interactive A New Breed +
Born Magazine Design and Literature Collaboration +
Brience.com +
Factiva, a Dow Jones Reuters Company +
FACTOR DESIGN +
Ford HEV +
fusionOne +
International Herald Tribune +
iSyndicate Syndication solutions built on our Intelligent Syndication Network +
oddcast +
siegelgale Launch +

+

PHP

+

+

codewalkers.com - main page - PHP Help +
EZwebdesign.com - PHP Resources +
HotScripts.com PHP +
http--www.phpinsider.com- +
Macromedia - PHP and Dreamweaver MX +
MySQL Documentation MySQL Commented MySQL Manual +
New York PHP - Linux Apache MySQL PHP +
PHP Hideout +
PHP Hypertext Preprocessor +
PHP Magazin - German +
PHP Manual date +
PHP WORLD - Free PHP Help , Resources and Scripts Consulting - MYSQL, Oracle database PHP Suppo +
PHP-Nuke +
PHPBuilder.com - The Resource For PHP Developers +
PHPCon East 2003 US Conference for PHP Developers. +
PHPDeveloper.org +
PHPkitchen - Come See What's Cookin' +
phpWizard - Building Dynamic Websites with PHP +
PX PHP Code Exchange +
Random CVS notes +
The PHP Resource Index +
WDVL PHP +
Web Design References PHP +
WebmasterBase - PHP and MySQL +

+

phpBB

+

+

Hacks.phpBB.Com +
phpBB 2 Index +
phpBB2 CVS snapshots +
phpBB2.de +
SourceForge Project Info - phpBB +

+

PhpNuke

+

+

PHP-Nuke +
Quebec Hardcore News +
Yahoo! Groups phpnuke Files +

+

References

+

+

AMG All Music Guide +
Bartleby.com Great Books Online +
CNNfyi.com - Student Mainpage +
Fast Facts Handbook +
homework help and educational resources at harcourt.com +
whatis.com +

+

Setlists

+

+

Allman Brothers Band Setlists +
Ben Harper Setlists +
Black Crows Setlists #1 +
Black Crows Setlists #2 +
Blues Traveler Setlists +
Blues Traveler Stage and Pre-show Setlists +
Bob Dylan Setlists +
Bob Marley Performances +
Bruce Hornsby Setlists +
Charlie Hunter Setlists +
Counting Crows Bootleg Guide +
Counting Crows Setlists - 2 +
Dark Star Orchestra Setlist +
Dave Matthews Band Setlists +
Derek Trucks Band +
Disco Biscuits Setlists +
Galactic Setlists +
Gov't Mule Setlists +
Grateful DeadLists +
Jane's Addiction - Boots +
Jazz Mandolin Project Setlists +
Jerry Garcia Setlists +
Jerry Joseph & the Jackmormons - Setlists +
Jimmy Buffet Setlists +
Karl Denson's Tiny Universe Setlists +
Led Zeppelin Setlists +
Leftover Salmon Setlists +
Modest Mouse Setlists +
Moe Setlists +
Other Ones Setlists +
Phil Lesh Setlists +
Pink Floyd Concert Appearances +
Pink Floyd ROIO +
Ratdog Setlists +
Rusted Root Setlists +
Samples Setlists +
Sector 9 Setlists +
Setlist.Com For all your setlist needs! +
Setlists - About.com +
Soulive Setlists +
Strangefolk Setlists +
String Cheese Setlists +
The Recipe Setlists +
U2 Setlist Archive +
Widespread Panic Setlists +

+

Shopping

+

+

Online DVD Deals and Coupons +
techbargains.com +

+

Steaming Tunes

+

+

3WK RealPlayer +
3WK Underground Radio +
Grateful Day +
Grateful Dead and Phriends- Streaming Real Audio Files +
Hip Boots - MP3 +
Hooked on Sonics Radio +
Listen +
musicneverstops.com +
OnShare GroupListing +
rip-off radio @ thebigripoff.com +
Sugarmegs- streams +
The Jam Zone! - Come in and groove with the Dead, Phish, Pink Floyd, Dave Matthews and many oth +

+

Trading

+

+

#tape_trade_central - Dalnet's Concert Trading Channel +
Bob Dylan Bootleg Artwork +
CD-R Trading Bootleg Cover Art Links +
CDR Covers - Yahoo! Photos - Thumbnails View +
CDR-Info, The Recording Authority +
CoverUniverse +
Etree.org +
etreenews.org +
Hip FTP +
http--www.u2-flom.de- +
i n h i d i n g . c o m +
Index of -etree +
Inlay Card Template +
Julian Fowler's CD Jewel Case Inserts +
NicksPicks.com +
Nothing's Shocking +
Paper CD Case +
Pink Floyd ROIO +
sativa.etree.org homepage +
Screech's Domain +
Shinburn - powered by XMB +
shntunes.org +
Tapers Revenge +
Templates CD-ROM Labels, CD Tray Cards, CD Inserts, and CD Mailers +
Welcome to Metropolis Noir - Your home for high quality Hip +

+

WAP-WML

+

+

allNetDevices -- The Wireless FAQ +
Nokia - WAP on Web +
Openwave Developer Program +
Openwave Systems Inc. +
Tag Reference - Wireless in a nutshell.com +
TagTag.com -+- FREE WAP site construction and hosting +
TTemulator - WAP emulator +
WAP (Wireless application protocol) - About.com +
WAP browser @ Gelon.net +
WAP Forum +
WAP Home - AnywhereYouGo.com +
WAP Usability Report Field Study Fall 2000 +
WAP.com - - Your guide to the wireless Internet, wap phones, wap services and PDAs +
WapTiger - WAP emulator +
Welcome to WAPDrive Free WAP sites WAP news WML tutorial WAP gateways +
Wireless Developer Network - Home +
Wireless in a nutshell.com - WAP, SMS, iMode, 3G, Bluetooth, VoxML, J2ME +
Wireless Industry - About.com +
WMLScript.com +
Yahoo! Mobile - Tours +
Yahoo! Mobile +

+

Web Design

+

+

404 Research Lab +
A List Apart For People Who Make Websites +
ASSEMBLER.ORG = Making Art With Machine Code; +
Bobby Validator +
Boxes and Arrows Because we can +
Chami.com - HTML-Kit, etc. +
CNET.com - Web Building - Stupid Web Tricks +
Color Schemer - Online Color Scheme Generator +
Contracts for every occasion - Web Building - CNET.com +
CSS Attributes Reference +
Doctor HTML v6 +
evolt.org Workers of the Web, Evolt! +
Flash 99% Good. First Aid Manual For Usable Flash Sites +
Frequent Questions Answered -- r937.com +
glish.com CSS layout techniques +
Graphic Design Resources Center - Graphic design tutorials, graphics tips, web design articles, +
Guide to Cascading Style Sheets +
GUIStuff.com - Free Graphical User Interfaces +
irt.org - JavaScript Windows FAQ Knowledge Base +
JavaScript Section - Homepage +
jjg.net information architecture resources +
Lighthouse latest +
LucDesk - Information Design . Web Usability . User Experience +
media inspiration +
more crayons colors for web designers +
my god...it's philippe starck... v-2 organisation +
Netscape - Developer +
O'Reilly Network Javascript and CSS DevCenter +
PDN's PIX - second site +
PDN's PIX - THE MAGAZINE FOR VISUAL CREATIVES +
Pirated Sites!! Aaarrgghh... +
Pirated Sites! +
Rabi's Dreamweaver Extensions +
Silicon Valley WebGuild Web Site Design Contest +
SimplytheBest Javascripts, JAVA Scripts +
SitePoint.com - Helping Business Grow Online! +
teamphotoshop.com +
The Web Standards Project Fighting for Standards in our Browsers +
Tomalak's Realm Daily Links to Strategic Web Design News +
Tutorials +
Usability.gov - Provided by the NCI National Cancer Institute +
Usable Web +
VisiBone Webmaster's Color Lab +
W3C HTML Validation Service +
W3Schools Online Web Tutorials +
Web Color Theory +
Web Design References +
Web Developer's Virtual Library Encyclopedia of Web Design Tutorials, Articles and Discussions +
Web Page Design for Designers - Home Page +
Web Pages That Suck +
Web Site Garage +
Web Tipes +
WebmasterBase - Helping Business Grow Online +
Webmonkey Reference Color Codes +
Webmonkey Reference Glossary +
Webmonkey Reference HTML Cheatsheet +
Webmonkey Reference Special Characters +
Webmonkey +
WebReview.com +
WebWord.com Hot Web Sites +
Welcome to SiteCritique.net - Helping You Create Better Designs Through Friendly Advice! +
Welcome to Web Resources - Where WebTechnology meets Simplicity +
ZDNet d e v e l o p e r Usability +

+

WNYMusic

+

+

Buffalo Music Online - Wnymusic.com +
Buffalo Music Online Message Board +
Ultimate Bulletin Board - Control Panel Frame +
WNYMusic - The List +

+

Zipzaps

+

+

Ebay - Items matching ( zipzap ) +
latencyproject.com - zip mods and racing +
Micro RC Cars Center +
Micro RC Cars Forum +
Radioshack.com - ZipZaps +
TinyRC.com - ZipZaps +
TinyRC.com +

+

.[DeskMod - Your Source for Desktop Modification]. +
ALT-PHP-FAQ - How do I turn newlines - returns into html breaks (br) +
BabyCentre Dads' stuff Diet for a healthy father-to-be +
BabyCentre Trying for a baby +
Business Week Online Salary Wizard +
Copyleft.net - Geek Chic! +
Coverall CD Audio Covers +
CVS--Concurrent Versions System - Table of Contents +
Dream Theater - Impaxx 5.18.93 - Dream Out Loud +
FastSubmit - Submit your website to search engines for FREE! +
Folding@home +
Free News Servers +
FreewarePalm +
History of Buffalo, New York +
internet beatles recording index main page +
irt.org - Dynamic HTML FAQ Knowledge Base +
irt.org - JavaScript Table FAQ Knowledge Base +
Keyboard Shortcuts for Windows +
Know Your Place! Shut Your Face! +
Lamb stuff! +
Misc. Space List +
MSN.com +
NASA's Visible Earth +
Opt-Out +
Portal Docs TOC +
Radio Station Guide +
Restoration Central Home, nurturing the passion for antiques and old homes with an Arts & Craft +
Rock and Roll Pumpkin Carving Patterns +
SternFanNetwork Home Page +
SWhois.net +
The Lawyers Who Get It Right - Jay Gerland +
ThinkGeek Stuff for Smart Masses +
US-NY-Buffalo-Web Developer +
WebMag Online - The No#1 Resource for Web Builders +
Welcome to the Happy Buffalo Slander Corner!!! +
Wxperience Forums - Forum Index +
[Real's JAVA JAVASCRIPT PB and WSH How-to] +

diff --git a/UnitTests/TestData/tnef/attachments/message.rtf b/UnitTests/TestData/tnef/attachments/message.rtf new file mode 100644 index 0000000000..cfbdbccd59 Binary files /dev/null and b/UnitTests/TestData/tnef/attachments/message.rtf differ diff --git a/UnitTests/TestData/tnef/attachments/zappa_av1.jpg b/UnitTests/TestData/tnef/attachments/zappa_av1.jpg new file mode 100644 index 0000000000..da46742cd6 Binary files /dev/null and b/UnitTests/TestData/tnef/attachments/zappa_av1.jpg differ diff --git a/UnitTests/TestData/tnef/body/message.html b/UnitTests/TestData/tnef/body/message.html new file mode 100644 index 0000000000..c54b6181cd --- /dev/null +++ b/UnitTests/TestData/tnef/body/message.html @@ -0,0 +1,95 @@ + + + + + +

+
THE BILL OF RIGHTS
Amendments 1-10 of the +Constitution
+
 
+
The Conventions of a number of the States having, +at the time of adopting the Constitution, expressed a desire, in order to +prevent misconstruction or abuse of its powers, that further declaratory and +restrictive clauses should be added, and as extending the ground of public +confidence in the Government will best insure the beneficent ends of its +institution;
Resolved, by the Senate and House of Representatives of the +United States of America, in Congress assembled, two-thirds of both Houses +concurring, that the following articles be proposed to the Legislatures of the +several States, as amendments to the Constitution of the United States; all or +any of which articles, when ratified by three-fourths of the said Legislatures, +to be valid to all intents and purposes as part of the said Constitution, +namely:
+
 
+
Amendment I
+
 
+
Congress shall make no law respecting an +establishment of religion, or prohibiting the free exercise thereof; or +abridging the freedom of speech, or of the press; or the right of the people +peaceably to assemble, and to petition the government for a redress of +grievances.
+
 
+
Amendment II
+
 
+
A well regulated militia, being necessary to the +security of a free state, the right of the people to keep and bear arms, shall +not be infringed.
+
 
+
Amendment III
+
 
+
No soldier shall, in time of peace be quartered in +any house, without the consent of the owner, nor in time of war, but in a manner +to be prescribed by law.
+
 
+
Amendment IV
+
 
+
The right of the people to be secure in their +persons, houses, papers, and effects, against unreasonable searches and +seizures, shall not be violated, and no warrants shall issue, but upon probable +cause, supported by oath or affirmation, and particularly describing the place +to be searched, and the persons or things to be seized.
+
 
+
Amendment V
+
 
+
No person shall be held to answer for a capital, or +otherwise infamous crime, unless on a presentment or indictment of a grand jury, +except in cases arising in the land or naval forces, or in the militia, when in +actual service in time of war or public danger; nor shall any person be subject +for the same offense to be twice put in jeopardy of life or limb; nor shall be +compelled in any criminal case to be a witness against himself, nor be deprived +of life, liberty, or property, without due process of law; nor shall private +property be taken for public use, without just compensation.
+
 
+
Amendment VI
+
 
+
In all criminal prosecutions, the accused shall +enjoy the right to a speedy and public trial, by an impartial jury of the state +and district wherein the crime shall have been committed, which district shall +have been previously ascertained by law, and to be informed of the nature and +cause of the accusation; to be confronted with the witnesses against him; to +have compulsory process for obtaining witnesses in his favor, and to have the +assistance of counsel for his defense.
+
 
+
Amendment VII
+
 
+
In suits at common law, where the value in +controversy shall exceed twenty dollars, the right of trial by jury shall be +preserved, and no fact tried by a jury, shall be otherwise reexamined in any +court of the United States, than according to the rules of the common law. +
+
 
+
Amendment VIII
+
 
+
Excessive bail shall not be required, nor excessive +fines imposed, nor cruel and unusual punishments inflicted.
+
 
+
Amendment IX
+
 
+
The enumeration in the Constitution, of certain +rights, shall not be construed to deny or disparage others retained by the +people.
+
 
+
Amendment X
+
 
+
The powers not delegated to the United States by +the Constitution, nor prohibited by it to the states, are reserved to the states +respectively, or to the people.
diff --git a/UnitTests/TestData/tnef/christmas.list b/UnitTests/TestData/tnef/christmas.list new file mode 100644 index 0000000000..77c480de77 --- /dev/null +++ b/UnitTests/TestData/tnef/christmas.list @@ -0,0 +1,6 @@ +kitten-playing-with-a-christmas-tree.jpg +Untitled Attachment +Untitled Attachment +Untitled Attachment +Untitled Attachment +body.rtf \ No newline at end of file diff --git a/UnitTests/TestData/tnef/christmas.tnef b/UnitTests/TestData/tnef/christmas.tnef new file mode 100644 index 0000000000..40a3f33c91 Binary files /dev/null and b/UnitTests/TestData/tnef/christmas.tnef differ diff --git a/UnitTests/TestData/tnef/christmas/Untitled Attachment.1 b/UnitTests/TestData/tnef/christmas/Untitled Attachment.1 new file mode 100644 index 0000000000..b2775ecb62 Binary files /dev/null and b/UnitTests/TestData/tnef/christmas/Untitled Attachment.1 differ diff --git a/UnitTests/TestData/tnef/christmas/Untitled Attachment.2 b/UnitTests/TestData/tnef/christmas/Untitled Attachment.2 new file mode 100644 index 0000000000..a34ac939bf Binary files /dev/null and b/UnitTests/TestData/tnef/christmas/Untitled Attachment.2 differ diff --git a/UnitTests/TestData/tnef/christmas/Untitled Attachment.3 b/UnitTests/TestData/tnef/christmas/Untitled Attachment.3 new file mode 100644 index 0000000000..b2775ecb62 Binary files /dev/null and b/UnitTests/TestData/tnef/christmas/Untitled Attachment.3 differ diff --git a/UnitTests/TestData/tnef/christmas/Untitled Attachment.4 b/UnitTests/TestData/tnef/christmas/Untitled Attachment.4 new file mode 100644 index 0000000000..655eb921e5 Binary files /dev/null and b/UnitTests/TestData/tnef/christmas/Untitled Attachment.4 differ diff --git a/UnitTests/TestData/tnef/christmas/kitten-playing-with-a-christmas-tree.jpg b/UnitTests/TestData/tnef/christmas/kitten-playing-with-a-christmas-tree.jpg new file mode 100644 index 0000000000..bb1a3f3ebf Binary files /dev/null and b/UnitTests/TestData/tnef/christmas/kitten-playing-with-a-christmas-tree.jpg differ diff --git a/UnitTests/TestData/tnef/christmas/message.rtf b/UnitTests/TestData/tnef/christmas/message.rtf new file mode 100644 index 0000000000..4dbeccbb9e --- /dev/null +++ b/UnitTests/TestData/tnef/christmas/message.rtf @@ -0,0 +1,55 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31506\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 00000000000000000000}Cambria Math;}{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f186\fbidi \froman\fcharset0\fprq2{\*\panose 0208090404030b020404}Cooper Black;}{\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f428\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f429\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f431\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f432\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f433\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f434\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f435\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f436\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f768\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f769\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f771\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f772\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f775\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f776\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f798\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f799\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f801\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f802\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f803\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f804\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f805\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f806\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}{\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\red5\green99\blue193;\red149\green79\blue114;\red255\green255\blue255;}{\*\defchp \f31506\fs22 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf19 \sbasedon10 \ssemihidden \sunhideused \styrsid1065446 Hyperlink;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf20 \sbasedon10 \ssemihidden \sunhideused \styrsid1065446 FollowedHyperlink;}{\s17\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs21\alang1025 \ltrch\fcs0 \f37\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext17 \slink18 \sunhideused \styrsid1065446 Plain Text;}{\*\cs18 \additive \rtlch\fcs1 \af0\afs21 \ltrch\fcs0 \f37\fs21 \sbasedon10 \slink17 \slocked \styrsid1065446 Plain Text Char;}{\*\cs19 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b \sbasedon10 \sqformat \spriority22 \styrsid1065446 Strong;}}{\*\revtbl {Unknown;}}{\*\rsidtbl \rsid1011802\rsid1065446}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect \widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin150\dgvorigin0\dghshow1\dgvshow1\jexpand\viewkind5\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0{\*\background {\shp{\*\shpinst\shpleft0\shptop0\shpright0\shpbottom0\shpfhdr0\shpbxmargin\shpbxignore\shpbymargin\shpbyignore\shpwr0\shpwrk0\shpfblwtxt1\shpz0\shplid1025{\sp{\sn shapeType}{\sv 1}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}{\sp{\sn fillType}{\sv 6}}{\sp{\sn fillColor}{\sv 255}}{\sp{\sn fillBackColor}{\sv 2315831}}{\sp{\sn fillFocus}{\sv 100}}{\sp{\sn fillToLeft}{\sv 32768}}{\sp{\sn fillToTop}{\sv 32768}}{\sp{\sn fillToRight}{\sv 32768}}{\sp{\sn fillToBottom}{\sv 32768}}{\sp{\sn fUseShapeAnchor}{\sv 0}}{\sp{\sn fFilled}{\sv 1}}{\sp{\sn lineWidth}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn bWMode}{\sv 9}}{\sp{\sn fBackground}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}}}}\ltrpar \sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1065446 \rtlch\fcs1 \af31507\afs21\alang1025 \ltrch\fcs0 \f37\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1065446 \rtlch\fcs1 \af31507\afs24\alang1025 \ltrch\fcs0 \f186\fs24\cf21\lang1033\langfe1033\cgrid\langnp1033\langfenp1033\insrsid1065446 {{\objattph {\rtlch\fcs1 \af31507\afs24 \ltrch\fcs0 \f186\fs24\cf21\insrsid1065446 }}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs24 \ltrch\fcs0 \f186\fs24\cf21\insrsid1065446 +\par +\par }{\rtlch\fcs1 \af31507\afs24 \ltrch\fcs0 \f186\fs24\cf21\insrsid1065446\charrsid1065446 You've made this a Christmas to remember +\par Springtime feeling's in the middle of December +\par Strangers meet and willingly surrender +\par Oh! What a Christmas to remember +\par Almost went to Aspen but something told me no +\par I considered Mammoth but there wasn't enough snow +\par And I even thought of Gatlinburg but seemed so far to go +\par So I headed up to Tahoe for a Christmas on the slopes +\par +\par And I had fantasized about Christmas in this way +\par Curled up by a fireplace in a Tahoe ski chalet +\par With a fast talking lover and some slow burning wood +\par But even in my wildest dreams it never got this good and +\par +\par You've made this a Christmas to remember +\par Springtime feeling's in the middle of December +\par Change the radio and I'll turn the lights down dimmer +\par Oh! What a Christmas to remember +\par +\par Strangers when we met, lovers as we leave +\par Christmas to remember, too good to believe +\par Don't know how or when, but I know we'll meet again +\par Blowin' back to somewhere like some wild restless winter's wind +\par +\par And you've made this a Christmas to remember +\par Springtime feeling's in the middle of December +\par 'Neath the mistletoe you kissed me warm and tender +\par Oh! What a Christmas to remember +\par +\par We loved and laughed and played and joked +\par Sang Christmas songs and talked to folks +\par Sleighed the fields and skied the slopes +\par Then to the lodge for dinner +\par Now it's time for us to go +\par As our hearts melt like chimney snow +\par There's just one thing I want to know +\par Can we do this next winter +\par Oh! What a Christmas to remember +\par +\par You've made this a Christmas to remember +\par Springtime feeling's in the middle of December +\par Though the fire is hot, we'll just have to let it simmer +\par Oh! What a Christmas to remember +\par +\par You've made this a Christmas to remember +\par Springtime feeling's in the middle of December +\par Though it's cold outside we'll just stroke the burning embers +\par Oh! What a Christmas to remember}{\rtlch\fcs1 \af31507\afs24 \ltrch\fcs0 \f186\fs24\cf21\insrsid1065446\charrsid1065446 +\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf0\insrsid1065446\charrsid1065446 +\par }{\pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1065446 \rtlch\fcs1 \af31507\afs21\alang1025 \ltrch\fcs0 \f37\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033\insrsid1065446 {{\objattph {\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf0\insrsid1065446 }}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\pard\plain \ltrpar\s17\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1065446 \rtlch\fcs1 \af31507\afs21\alang1025 \ltrch\fcs0 \f37\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033\insrsid1065446 {{\objattph {\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf0\insrsid1065446 }}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf0\insrsid1065446 +\par +\par }{\rtlch\fcs1 \af31507 \ltrch\fcs0 \cf0\insrsid1065446\charrsid1065446 +\par }} \ No newline at end of file diff --git a/UnitTests/TestData/tnef/data-before-name/AUTOEXEC.BAT b/UnitTests/TestData/tnef/data-before-name/AUTOEXEC.BAT new file mode 100644 index 0000000000..e69de29bb2 diff --git a/UnitTests/TestData/tnef/data-before-name/CONFIG.SYS b/UnitTests/TestData/tnef/data-before-name/CONFIG.SYS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/UnitTests/TestData/tnef/data-before-name/boot.ini b/UnitTests/TestData/tnef/data-before-name/boot.ini new file mode 100644 index 0000000000..2807aea440 --- /dev/null +++ b/UnitTests/TestData/tnef/data-before-name/boot.ini @@ -0,0 +1,6 @@ +[boot loader] +timeout=30 +default=multi(0)disk(0)rdisk(0)partition(1)\WINNT +[operating systems] +multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00" +multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00 [VGA mode]" /basevideo /sos diff --git a/UnitTests/TestData/tnef/data-before-name/message.rtf b/UnitTests/TestData/tnef/data-before-name/message.rtf new file mode 100644 index 0000000000..ba8283613c Binary files /dev/null and b/UnitTests/TestData/tnef/data-before-name/message.rtf differ diff --git a/UnitTests/TestData/tnef/long-filename/allproductsmar2000.dat b/UnitTests/TestData/tnef/long-filename/allproductsmar2000.dat new file mode 100644 index 0000000000..80cf2d28ad --- /dev/null +++ b/UnitTests/TestData/tnef/long-filename/allproductsmar2000.dat @@ -0,0 +1,11 @@ + +FEATURE QARun_Developer compuware 4.70 \ + 02-mar-2000 0 8CB7C0E22EA5D23F83E0 \ + VENDOR_STRING=10000;0;TRIAL HOSTID=DEMO \ + ck=237 + +FEATURE QARun_Regular_Runtime compuware 4.70 \ + 02-mar-2000 0 1C9750622766DB0B975F \ + VENDOR_STRING=10000;0;TRIAL HOSTID=DEMO \ + ck=30 + diff --git a/UnitTests/TestData/tnef/long-filename/message.rtf b/UnitTests/TestData/tnef/long-filename/message.rtf new file mode 100644 index 0000000000..5379e74451 --- /dev/null +++ b/UnitTests/TestData/tnef/long-filename/message.rtf @@ -0,0 +1,26 @@ +{\rtf1\ansi\ansicpg1252\fromtext \deff0{\fonttbl +{\f0\fswiss Arial;} +{\f1\fmodern Courier New;} +{\f2\fnil\fcharset2 Symbol;} +{\f3\fmodern\fcharset0 Courier New;}} +{\colortbl\red0\green0\blue0;\red0\green0\blue255;} +\uc1\pard\plain\deftab360 \f0\fs20\cf0 I've attached a temp. license for QARun 4.7. Do you need something more permanent? If so, give me your host id and host name of the machine you want to put it on and indicate whether you want a single user perm. license or a concurrent user perm. license.\par +\par +Heather\par +\par +\par +-----Original Message-----\par +From: Mark Simpson [mailto:msimpson@numega.com]\par +Sent: Wednesday, November 17, 1999 2:57 PM\par +To: Heather_Phillips@compuware.com\par +Subject: license file\par +\par +\par +\par +Who should i talk to about getting a valid license for qarun 4.7? I need\par +to install it and cannot.\par +\par +-- \par +Mark Simpson Software Engineer\par +Compuware Corporation msimpson@numega.com\par +} \ No newline at end of file diff --git a/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99-JAN00.doc b/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99-JAN00.doc new file mode 100644 index 0000000000..7f03c1a4ad Binary files /dev/null and b/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99-JAN00.doc differ diff --git a/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99.doc b/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99.doc new file mode 100644 index 0000000000..b765da80b6 Binary files /dev/null and b/UnitTests/TestData/tnef/missing-filenames/TechlibDEC99.doc differ diff --git a/UnitTests/TestData/tnef/missing-filenames/TechlibNOV99.doc b/UnitTests/TestData/tnef/missing-filenames/TechlibNOV99.doc new file mode 100644 index 0000000000..d86f42719f Binary files /dev/null and b/UnitTests/TestData/tnef/missing-filenames/TechlibNOV99.doc differ diff --git a/UnitTests/TestData/tnef/missing-filenames/generpts.src b/UnitTests/TestData/tnef/missing-filenames/generpts.src new file mode 100644 index 0000000000..69c16339c3 --- /dev/null +++ b/UnitTests/TestData/tnef/missing-filenames/generpts.src @@ -0,0 +1,1691 @@ +*PROC CIRREQ01 +*----------------------------------------------------------------------------- +* +* Title: Patron Request Report +* File: PATRQT01.PRC +* Author: Information Dimensions, Inc. (TD) +* +* Description: A list of patron requests +* +* Input Parameters: +* OUTPUT - may be 'REVIEW','PRINT'. Review displays report +* on screen, print outputs to file for printing. +* +* START_DATE/END_DATE - find where CIRC_REQUEST.ADD_DT +* is in range +* +* CIRC_SORT_KEY - option to sort by title, patron name, +* or patron id +* +* HOLD_SORT_KEY - option to sort by title, patron id, +* patron name, or call number. +* +* Other Selection Criteria: +* LIBR_KEY - Restrict to certain libraries. +* +* ALL - Boolean value; set true by Slang if no params entered +* +* Output File: patrqt01.rpt +* +* Record Types Referenced: +* TEMPLATE, COPY, CAT, CIRC_REQUEST +* Buffers: @A @B @C @D +* +* Report Name: Cairculation Requests +* +* Report No.: PATRQT01 +* +* Menu Access: CATALOG REPORTS +* +* Parameter +* Input Screen: CATRPT12 +* +* Templates: REPORT_HDR, BIB_PATRON, COPY_NOCIRC, COPY_NOCIRC_S, +* PATRON_REQUEST. +* +*------------------------------------------------------------------------------ +* +* Revision History: +* +* Date Revised By Description +* -------- ---------- ----------- +* 11/20/89 DeFrench Initial Version +* 03/28/91 Sandstrom Add LIBR_KEY to find commands. +* 04/25/91 Sandstrom Add MATERIAL_TYPE to FIND commands. +* 07/03/91 MChung Substitute tabs with 8 spaces and +* spelling checks +* +*------------------------------------------------------------------------------ +* +START: + ACQUIRE/PV MESSAGE 46707, C2=MSG + TELL MSG,$B + ON/BREAK BREAKERR + ON/EXCEPTION EXCEPTION + ON/SYNTAX SYNTAXERR + SET/DEFAULT RESULT = N + SET/PV PV_TODAY = $YYYYMMDD + SET/PV PRINTTOP = 1 + SET/PV RPTNM = 'PATRQT01' + SET/PV RPTTTL = 'Circulation/Holds report' + SET/PV PGNO = 0 +* Set up for desired output method + SELECT (OUTPUT) + CASE 'REVIEW' + SET/PV MAXLINES = 20 + SET/PV PV_FILEID = '' + CASE 'PRINT' + SET/PV MAXLINES = 60 + OPEN/F patrqt01.rpt, FID=A, INTENT=WRITE, + + CARRIAGE=YES, ERR=OPENERR + SET/PV PV_FILEID = ',FID=A' + END_SELECT +* + GET/VIEW [TEMPLATE_KEY = 'REPORT_HDR']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV HEADER = TEXT@A + GET/VIEW [TEMPLATE_KEY='REQ_HDR']TEMPLATE@A, ERR=VIEWERR + ASSIGN/PV REQ_HDR = TEXT@A + GET/VIEW [TEMPLATE_KEY = 'PATRON_REQUEST']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV RQTINFO = TEXT@A + GET/VIEW [TEMPLATE_KEY = 'BIB_PATRON']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV CATINFO = TEXT@A + GET/VIEW [TEMPLATE_KEY = 'COPY_NOCIRC']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV COPYINFO = TEXT@A + GET/VIEW [TEMPLATE_KEY = 'COPY_NOCIRC_S']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV SCOPYINFO = TEXT@A + SET/PV CALLOC = 'CATR' +* +* Begin construction of FIND command. +* + SET/PV PV_FINDCMD = 'FIND CIRC_REQUEST,CATR,COPY,material_type ' //+ + 'WHERE CIRC_REQUEST.CATNO:=CATR.CATNO ' //+ + 'AND CIRC_REQUEST.ITEMID:=COPY.ITEMID ' //+ + 'AND MATERIAL_TYPE.TYPE:=CATR.MTYPE '//+ + 'AND CIRC_REQUEST.REQUEST_TYPE=''C'' ' +* +* Add Library to find. +* + DELETE/GV OUTLC + DELETE/GV OUTSTR + DELETE/GV INSTR + SET/GV INSTR = LIBR_KEY + @/PL='$TLP_PROC/generpts' QTBLKS01, VFLDNM='COPY.LIBR_KEY' + SET/PV SAVE_OUTSTR = '(' //OUTSTR + SET/PV PV_FINDCMD = PV_FINDCMD // 'AND (' // OUTSTR //' ' +* + DELETE/GV OUTLC + DELETE/GV OUTSTR + DELETE/GV INSTR + SET/GV INSTR = LIBR_KEY + @/PL='$TLP_PROC/generpts' QTBLKS01, + + VFLDNM='CIRC_REQUEST.PLACED_LIBR_KEY' + SET/PV SAVE_OUTSTR = SAVE_OUTSTR// ' OR ' //OUTSTR //') ' + SET/PV PV_FINDCMD = PV_FINDCMD // 'OR ' // OUTSTR //') ' +* +* Add the date fields if they were passed. +* + IF (START_DATE <> '') + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' AND CIRC_REQUEST.ADD_DT = '//START_DATE//':'//END_DATE//' ' + END_IF +* +* Append FIND for sort options. +* + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' ORDER BY !CIRC_SORT_KEY!, CATR.TI,CATR.PUBL, COPY.YEAR, ' //+ + 'COPY.LIBR_KEY, COPY.ITEMID, COPY.COPY' +* +* If output option is equal to 'PRINT', then delete the records +* as they are printed. +* + IF OUTPUT = 'PRINT' + START/TRANS SW=CIRC_REQUEST + END_IF +* +* Execute Find and set up for report generation +* + !PV_FINDCMD! END REF=NO + ACQUIRE/PV MEMBERS, N1 = PV_NUMMEM + ACQUIRE/PV LASTSET, N1 = PV_FOUNDSET + JUMPIF (PV_NUMMEM = 0), DO_HOLDS +* +* Write initial header. +* + IF OUTPUT = 'REVIEW' + CLEAR/SCREEN + SET/PV LINE_CNT =2 + ELSE + TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + END_IF +* + SET/PV PGNO = PGNO + 1 + TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + TYPE !REQ_HDR!, $S2, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 8 +* +* Step through members of set, generating correct output for each. +* + FOR PV_Q = 1, PV_NUMMEM +* + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]CIRC_REQUEST@D, ERR = VIEWERR + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]CATR@B, ERR = VIEWERR + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]COPY@C, ERR = VIEWERR +* + ASSIGN/PV CATDOC = CATR.DOC@B + IF CATDOC = 'SER' + TYPE !CATINFO!,!SCOPYINFO!,!RQTINFO!,LABELS=NO, SKIP=1, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV LINE_CNT = LINE_CNT + 12 + ELSE + TYPE !CATINFO!,!COPYINFO!,!RQTINFO!,LABELS=NO, SKIP=1, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV LINE_CNT = LINE_CNT + 12 + END_IF + IF OUTPUT = 'PRINT' + DELETE [!PV_FOUNDSET!,!PV_Q!]CIRC_REQUEST + END_IF +* +* Check for a page break. +* + IF LINE_CNT > MAXLINES + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT =2 + ELSE + TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + END_IF +* + SET/PV PGNO = PGNO + 1 + TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 7 + END_IF +* + END_FOR +***************************************************** +***************************************************** +DO_HOLDS: +* +* Begin construction of the HOLDS FIND command. +* + SET/PV PV_FINDCMD = 'FIND CIRC_REQUEST,CATR,COPY,MATERIAL_TYPE ' //+ + 'WHERE CIRC_REQUEST.CATNO:=CATR.CATNO ' //+ + 'AND CIRC_REQUEST.ITEMID:=COPY.ITEMID ' //+ + 'AND MATERIAL_TYPE.TYPE:=CATR.MTYPE '//+ + 'AND CIRC_REQUEST.REQUEST_TYPE=''H'' '//+ + 'AND ' // SAVE_OUTSTR // ' ' +* +* Add the date fields if they were passed. +* + IF (START_DATE <> '') + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' AND CIRC_REQUEST.ADD_DT = '//START_DATE//':'//END_DATE//' ' + END_IF +* +* Append FIND for sort options. +* + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' ORDER BY !HOLD_SORT_KEY!, CATR.TI,CATR.PUBL, COPY.YEAR, ' //+ + 'COPY.LIBR_KEY, COPY.ITEMID, COPY.COPY' +* +* Execute Find and set up for report generation +* + !PV_FINDCMD! END REF=NO + ACQUIRE/PV MEMBERS, N1 = PV_NUMMEM + ACQUIRE/PV LASTSET, N1 = PV_FOUNDSET + JUMPIF (PV_NUMMEM = 0), CLEANUP +* +* Write initial header. +* + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT =2 + ELSE + TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + END_IF +* + SET/PV PGNO = PGNO + 1 + TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 7 +* +* Step through members of set, generating correct output for each. +* + FOR PV_Q = 1, PV_NUMMEM +* + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]CIRC_REQUEST@D, ERR = VIEWERR + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]CATR@B, ERR = VIEWERR + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]COPY@C, ERR = VIEWERR +* + ASSIGN/PV HOLDTYPE = CIRC_REQUEST.HOLD_TYPE@D + SET/PV RHOLDTYPE = $RAISE(HOLDTYPE) + IF RHOLDTYPE = 'COPY' + TYPE $S2, 'COPY level hold for:' + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + ELSE + TYPE $S2, 'CAT level hold for:' + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + END_IF +* +* Choose the serials copy info if item is a serial. +* + ASSIGN/PV CATDOC = CATR.DOC@B + IF CATDOC = 'SER' + TYPE !CATINFO!,!SCOPYINFO!,!RQTINFO!,LABELS=NO, SKIP=1, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV LINE_CNT = LINE_CNT + 12 + ELSE + TYPE !CATINFO!,!COPYINFO!,!RQTINFO!,LABELS=NO, SKIP=1, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV LINE_CNT = LINE_CNT + 12 + END_IF +* +* Delete the occurrence if print is selected +* + IF OUTPUT = 'PRINT' + DELETE [!PV_FOUNDSET!,!PV_Q!]CIRC_REQUEST + END_IF +* +* Check for a page break. +* + IF LINE_CNT > MAXLINES + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT =2 + ELSE + TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + END_IF +* + SET/PV PGNO = PGNO + 1 + TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 7 + END_IF +* + END_FOR +* +* Cleanup - close files and discard result sets. +* +CLEANUP: + ACQUIRE/PV MESSAGE 46708, C2=MSG + TELL MSG + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' +QUIT: ACQUIRE/PV LASTSET, N1 = PV_LASTSET + DISCARD !PV_FOUNDSET!:!PV_LASTSET! + SET/DEF RESULT = Y + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + FINISH/TRANS + END_IF +* +* DONE - successful report generation; return to caller +* +DONE: + RETURN_TO_SCREEN +* +* Error - inform user and close file, if necessary. +* +SYNTAXERR: +EXCEPTION: +OPENERR: +VIEWERR: + SHOW/MESSAGE !DMSTAT! + JUMP ERROR +BREAKERR: + SHOW/MESSAGE 46700 +ERROR: + SHOW/MESSAGE 46703 + IF (OUTPUT <> 'REVIEW') + CLOSE/FILE FID = A,ERR=$CONTINUE + ABORT/TRANSACTION, ERR=$CONTINUE + END_IF + SET/DEF RESULT = Y + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' + RETURN_TO_SCREEN +*PROC FILOPN01 +*----------------------------------------------------------------------------- +* +* Title: Generic File Open +* File: FILOPN01.PRC +* Author: Information Dimensions, Inc. (BPM) +* +* Description: This proc is designed as a subroutine that is called from +* other TLP procs to correctly open files in cases where the +* file may already exist. +* +* Input Parameters: +* FIL The file descriptor to be opened. +* ID The file ID to be assigned to this file. +* Called by: Any report that has an OPEN/FILE. +* Call: @/PL='$TLP_PROC/generpts' FILOPN01 FIL=!A!, ID=!B! +*------------------------------------------------------------------------------ +* Revision History +* +* Date Rev. Revised By Description +* --------- ---------- -------------------------------- +* 04/07/93 BMOORE Initial version +*----------------------------------------------------------------------------- +* +START: +* +* Open the file. +* +OPEN/FILE FD=!FIL! FID=!ID! INTENT=WRITE CARRIAGE=NO ERR=OPENERR +SET/GV FILE_STATUS = 'OK' +RETURN +* +* If error occurs, attempt to delete existing file and then open the file. +* +OPENERR: +* +DELETE/FILE !FIL! +OPEN/FILE FD=!FIL! FID=!ID! INTENT=WRITE CARRIAGE=NO ERR=OPENER2 +SET/GV FILE_STATUS = 'OK' +RETURN +* +* If still unable to open the file, display message and return. +* +OPENER2: +* +SET/GV FILE_STATUS = 'OPEN_ERROR' +TELL 'File cannot be opened. Contact your DBA' +RETURN +*PROC GENPRT01 +*----------------------------------------------------------------------------- +* +* Title: Generic Print Routine +* File: GENPRT01.PRC +* Author: Information Dimensions, Inc. (BPM) +* +* Description: This proc is designed as a subroutine that is called from +* other TLP procs to allow custom printing of reports. +* The proc uses the ROUTE/FILE command to route a file to the +* printer of chice. Consult the BASISplus Command Procedures +* manual for additional parameters. Optionally, you can use +* a SPAWN command to call local procedures for printing. +* +* Input Parameters: +* FIL The file descriptor to be sent to the printer. +* ERROR_FLG is 'Y' if called from within error branch of +* the calling proc. +* +* Called by: Any report that generates a printable file. +* +* Call: @/PL=TLP$PROC:GENERPTS.LIB GENPRT01 FIL=!A! ERROR_FLG='N' +*------------------------------------------------------------------------------ +* Revision History +* +* Date Rev. Revised By Description +* --------- ---------- -------------------------------- +* 04/08/93 BMOORE Initial version +*----------------------------------------------------------------------------- +* +ON/EXCEPTION $RETURN +START: +* +**** ROUTE/FILE FD=!FIL! +RETURN +*PROC MAROUT01 +*----------------------------------------------------------------------------- +* +* Title: Marc Output +* File: MAROUT01.PRC +* Author: Information Dimensions, Inc. (HB) +* +* Description: Create Marc Input file records that can be run using the Marc +* program +* +* Input Parameters: +* OUTPUT - may be 'REVIEW','PRINT'. Review displays report +* on screen, print outputs to file. +* +* FORMAT - may be set to OCLC, LC, or PC +* +* BLOCKSIZE - the length of each line in output file +* +* FIND_CAT - where part of find command for cat record +* +* FIND_COPY - where part of find command for copy record +* +* CATNO - a string of CATNO's to search on +* +* Valid Combinations: +* OUTPUT, FORMAT, and BLOCKSIZE are required. +* User may enter one of: FIND_CAT OR FIND_COPY OR CATNO +* +* Output File: marout01.rpt +* marout01.log +* +* Record Types Referenced: +* MARC +* Buffers: @A +* +* Report Name: MARC OUTPUT +* +* Report No.: MAROUT01 +* +* Menu Access: CATRPT01 +* +* Parameter +* Input Screen: MARRPT10 +* +* Templates: none +* +*------------------------------------------------------------------------------ +* +* Revision History: +* +* Date Revised By Description +* -------- ---------- ----------- +* 04/25/90 Berger Initial version +* 04/26/90 Sandstrom Added PC format code +* 05/10/90 Sandstrom Added LC format code +* 05/11/90 Berger Revisions to FIND_CAT and FIND_COPY +* 07/03/91 MChung Substitute tabs with 8 spaces and +* spelling checks +* 12/02/91 Sandstrom Changed log file open to handle +* error if log file already exists. +* +*------------------------------------------------------------------------------ +* +START: + ACQUIRE/PV MESSAGE 46707, C2=MSG + TELL MSG,$B + ON/BREAK BREAKERR + ON/EXCEPTION EXCEPTION + ON/SYNTAX SYNTAXERR + SET/DEFAULT RESULT = N + SET/PV LINE_CNT = 1 +* Check for bad blocksize + IF BLOCKSIZE < 80 + SET/PV BLOCKSIZE = 80 + ELSE_IF BLOCKSIZE > 2048 + SET/PV BLOCKSIZE = 2048 + END_IF +* Set up for desired output method + SELECT (OUTPUT) + CASE 'REVIEW' + SET/PV BLOCKSIZE = 80 + CASE 'PRINT' + OPEN/FILE marout01.rpt, FID=A, + + INTENT=WRITE,ERR=OPENERR, RECORDLC=!BLOCKSIZE! + SET/PV PV_FILEID = ',FID=A' + END_SELECT +* +* Construct find command for search on CAT record +* + IF FIND_CAT <> NULL + SET/PV PV_FINDCMD = 'FIND CAT,MARC ' //+ + 'WHERE CAT.CATNO:=MARC.CATNO AND ' + SET/PV FIND_CAT = $RAISE(FIND_CAT) +* +* Add CAT. to ambiguous fields in find command where it is not specified +* + SET/PV PV_ADD = $MATCH('ADD_DT',FIND_CAT) + SET/PV PV_EXISTS = $MATCH('.ADD_DT',FIND_CAT) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_CAT = FIND_CAT[1:(PV_ADD-1)] // 'CAT.' //+ + FIND_CAT[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('CATNO',FIND_CAT) + SET/PV PV_EXISTS = $MATCH('.CATNO',FIND_CAT) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_CAT = FIND_CAT[1:(PV_ADD-1)] // 'CAT.' //+ + FIND_CAT[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('REV_DT',FIND_CAT) + SET/PV PV_EXISTS = $MATCH('.REV_DT',FIND_CAT) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_CAT = FIND_CAT[1:(PV_ADD-1)] // 'CAT.' //+ + FIND_CAT[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('REV_UID',FIND_CAT) + SET/PV PV_EXISTS = $MATCH('.REV_UID',FIND_CAT) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_CAT = FIND_CAT[1:(PV_ADD-1)] // 'CAT.' //+ + FIND_CAT[PV_ADD:*] + END_IF +* Append restrictive condition to find command + SET/PV PV_FINDCMD = PV_FINDCMD // FIND_CAT +* +* Construct find command for search on COPY record +* + ELSE_IF FIND_COPY <> NULL + SET/PV PV_FINDCMD = 'FIND COPY,MARC ' //+ + 'WHERE COPY.CATNO:=MARC.CATNO AND ' + SET/PV FIND_COPY = $RAISE(FIND_COPY) +* +* Add COPY. to ambiguous fields in find command where it is not specified +* + SET/PV PV_ADD = $MATCH('ADD_DT',FIND_COPY) + SET/PV PV_EXISTS = $MATCH('.ADD_DT',FIND_COPY) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_COPY = FIND_COPY[1:(PV_ADD-1)] // 'COPY.' //+ + FIND_COPY[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('CATNO',FIND_COPY) + SET/PV PV_EXISTS = $MATCH('.CATNO',FIND_COPY) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_COPY = FIND_COPY[1:(PV_ADD-1)] // 'COPY.' //+ + FIND_COPY[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('REV_DT',FIND_COPY) + SET/PV PV_EXISTS = $MATCH('.REV_DT',FIND_COPY) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_COPY = FIND_COPY[1:(PV_ADD-1)] // 'COPY.' //+ + FIND_COPY[PV_ADD:*] + END_IF +* + SET/PV PV_ADD = $MATCH('REV_UID',FIND_COPY) + SET/PV PV_EXISTS = $MATCH('.REV_UID',FIND_COPY) + IF (PV_ADD > 0) AND (PV_EXISTS = 0) + SET/PV FIND_COPY = FIND_COPY[1:(PV_ADD-1)] // 'COPY.' //+ + FIND_COPY[PV_ADD:*] + END_IF +* Append restrictive condition to find command + SET/PV PV_FINDCMD = PV_FINDCMD // FIND_COPY +* +* Construct find command for search on selected CATNO's +* + ELSE_IF CATNO <> NULL + SET/PV PV_FINDCMD = 'FIND MARC WHERE MARC.CATNO =' //!CATNO! +* +* Construct default find command for no selected search criteria +* + ELSE + SET/PV PV_FINDCMD = 'FIND MARC' + END_IF +* +* Add sort to the find command +* + SET/PV PV_FINDCMD = PV_FINDCMD // ' ORDER BY MARC.CATNO END REF=NO' +* +* Write find command to log file +* +* OPEN/FILE marout01.log,FID=B,INTENT=WRITE,CREATE=YES, + +* CARRIAGE=YES, ERR=OPENERR +* smls19911202 changed error branch on log file open to $continue +* and added test for dmstat. + OPEN/FILE marout01.log,FID=B,INTENT=WRITE,CREATE=YES, + + ERR=$CONTINUE + IF DMSTAT <> 0 + OPEN/FILE marout01.log,FID=B,INTENT=UPDATE,ERR=OPENERR + END_IF + PUT/FILE ' Log File for MAROUT01',FID=B + PUT/FILE ' ---------------------',FID=B + PUT/FILE $S2,'FIND COMMAND',$B,'------------',FID=B + SET/PV PV_FINDLEN = $LC(PV_FINDCMD) + SET/PV PV_POINT = 1 + WHILE (PV_POINT <= PV_FINDLEN) + PUT/FILE PV_FINDCMD[PV_POINT:(PV_POINT+79)],FID=B + SET/PV PV_POINT = PV_POINT + 80 + END_WHILE +* +* Execute find, store members and set in variables +* + !PV_FINDCMD!,ERR=FNDERR + ACQUIRE/PV MEMBERS, N1 = PV_NUMMEM + ACQUIRE/PV LASTSET, N1 = PV_SET +* +* Write members to log file and close file +* + PUT/FILE $S2,'NUMBER OF MEMBERS = ',PV_NUMMEM,FID=B + CLOSE/FILE FID=B +* +* Check for no hits +* + IF (PV_NUMMEM <= 0) + SHOW/MESSAGE 46705 + JUMP CLEANUP + END_IF +* +* Type output for specified formats +* + SELECT (FORMAT) + CASE 'OCLC' +* +* Step through members of set, generating correct output for each. +* + FOR PV_MEM = 1, PV_NUMMEM + GET/VIEW[!PV_SET!,!PV_MEM!]MARC@A + ASSIGN/PV PV_OUTDATA = MARC_DATA@A + SET/PV PV_LENGTH = $LC(PV_OUTDATA) + SET/PV PV_POINT = 1 +****** Loop through printing one record at a time ****** + WHILE (PV_POINT <= PV_LENGTH) + IF OUTPUT = 'REVIEW' + SET/PV LINE_CNT = LINE_CNT + 1 +******* Check for page break ******** + IF LINE_CNT >= 20 + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 1 + END_IF + TELL PV_OUTDATA[PV_POINT:(PV_POINT+BLOCKSIZE-1)] + ELSE + PUT/F PV_OUTDATA[PV_POINT:(PV_POINT+BLOCKSIZE-1)] + + ,FID=A + END_IF + SET/PV PV_POINT = PV_POINT + BLOCKSIZE + END_WHILE + END_FOR +* + CASE 'PC' +* +* + SET/PV PV_MEM = 1 + SET/PV PV_POINT_OUT = 1 +GETPC: + WHILE PV_MEM LE PV_NUMMEM +* +* Get record +* + GET/VIEW[!PV_SET!,!PV_MEM!]MARC@A + ASSIGN/PV PV_MARCDATA = MARC_DATA@A + SET/PV PV_MARCDATA = $TRIM (PV_MARCDATA) + SET/PV PV_MEM = PV_MEM + 1 + SET/PV PV_LENGTH = PV_MARCDATA[1:5] + SET/PV PV_SEGLEN = PV_LENGTH + SET/PV PV_POINT_IN = 1 +* +* Loop to build and write buffer +* +BLDPC: +* +* Record will begin and end in this block.... + IF (PV_SEGLEN EQ PV_LENGTH) AND + + PV_SEGLEN LE (BLOCKSIZE - PV_POINT_OUT + 1) THEN + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT+PV_SEGLEN-1]=+ + PV_MARCDATA[1:PV_LENGTH] + SET/PV PV_POINT_OUT = PV_POINT_OUT + PV_SEGLEN + SET/PV PV_SEGLEN = 0 + IF PV_POINT_OUT GT BLOCKSIZE THEN + SET/PV PV_POINT_OUT = 1 + JUMP OUTPC + END_IF + JUMP GETPC + END_IF +* Record will begin but not end in this block.... + IF (PV_SEGLEN EQ PV_LENGTH) AND + + PV_SEGLEN GT (BLOCKSIZE - PV_POINT_OUT + 1) THEN + SET/PV PV_BUFFER[PV_POINT_OUT:BLOCKSIZE] = + + PV_MARCDATA[1:BLOCKSIZE-PV_POINT_OUT+1] + SET/PV PV_SEGLEN = PV_SEGLEN - (BLOCKSIZE-PV_POINT_OUT+1) + SET/PV PV_POINT_IN = PV_POINT_IN+BLOCKSIZE-PV_POINT_OUT+1 + SET/PV PV_POINT_OUT = 1 + JUMP OUTPC + END_IF +* Record will end but not begin in this block.... + IF (PV_SEGLEN NE PV_LENGTH) AND + + PV_SEGLEN LE (BLOCKSIZE - PV_POINT_OUT + 1) THEN + SET/PV PV_BUFFER[PV_POINT_OUT:*] = + + PV_MARCDATA[PV_POINT_IN:PV_POINT_IN+PV_SEGLEN-1] + SET/PV PV_POINT_OUT = PV_SEGLEN + 1 + IF PV_POINT_OUT GT BLOCKSIZE THEN + SET/PV PV_POINT_OUT = 1 + SET/PV PV_SEGLEN = 0 + JUMP OUTPC + END_IF + JUMP GETPC + END_IF +* Record will not begin or end in this block.... + IF (PV_SEGLEN NE PV_LENGTH) AND + + PV_SEGLEN GT (BLOCKSIZE - PV_POINT_OUT + 1) THEN + SET/PV PV_BUFFER[PV_POINT_OUT:BLOCKSIZE] = + + PV_MARCDATA[PV_POINT_IN:PV_POINT_IN+BLOCKSIZE-1] + SET/PV PV_SEGLEN = PV_SEGLEN - BLOCKSIZE + SET/PV PV_POINT_IN = PV_POINT_IN + BLOCKSIZE + JUMP OUTPC + END_IF +OUTPC: + IF OUTPUT = 'REVIEW' + SET/PV LINE_CNT = LINE_CNT + 1 +******* Check for page break ******** + IF LINE_CNT >= 20 + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 1 + END_IF + TELL PV_BUFFER[1:BLOCKSIZE] + ELSE + PUT/F PV_BUFFER[1:BLOCKSIZE] ,FID=A + END_IF +* + IF PV_SEGLEN EQ 0 THEN + JUMP GETPC + ELSE + JUMP BLDPC + END_IF + END_WHILE +* "Put" last line + IF OUTPUT = 'REVIEW' + TELL PV_BUFFER[1:BLOCKSIZE] + ELSE + PUT/F PV_BUFFER[1:BLOCKSIZE] ,FID=A + END_IF +* +* + CASE 'LC' +* + SET/PV PV_MEM = 1 + SET/PV PV_POINT_OUT = 1 +GETLC: + WHILE PV_MEM LE PV_NUMMEM +* +* Get record +* + GET/VIEW[!PV_SET!,!PV_MEM!]MARC@A + ASSIGN/PV PV_MARCDATA = MARC_DATA@A + SET/PV PV_MARCDATA = $TRIM (PV_MARCDATA) + SET/PV PV_MEM = PV_MEM + 1 + SET/PV PV_LENGTH = PV_MARCDATA[1:5] + SET/PV PV_SEGLEN = PV_LENGTH + SET/PV PV_POINT_IN = 1 +* +* Loop to build and write buffer +* +BLDLC: +* +* Record will begin and end in this block....0 + IF (PV_SEGLEN EQ PV_LENGTH) AND + + PV_SEGLEN LE (BLOCKSIZE - PV_POINT_OUT + 1 - 5) THEN +* Set segment control word + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT] = '0' + SET/PV PV_SCW_I = PV_SEGLEN + 5 + SET/PV PV_SCW_S[1:4] = $PADZ(PV_SCW_I,4) + SET/PV PV_BUFFER[PV_POINT_OUT+1:PV_POINT_OUT+4] = + + PV_SCW_S[1:4] +* Add record segment + SET/PV PV_POINT_OUT = PV_POINT_OUT + 5 + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT+PV_SEGLEN-1]=+ + PV_MARCDATA[1:PV_LENGTH] + SET/PV PV_POINT_OUT = PV_POINT_OUT + PV_SEGLEN + SET/PV PV_SEGLEN = 0 + IF PV_POINT_OUT GE (BLOCKSIZE-5) THEN + SET/PV PV_POINT_OUT = 1 + JUMP OUTLC + END_IF + JUMP GETLC + END_IF +* Record will begin but not end in this block....1 + IF (PV_SEGLEN EQ PV_LENGTH) AND + + PV_SEGLEN GT (BLOCKSIZE - PV_POINT_OUT + 1 - 5) THEN +* Set segment control word + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT] = '1' + SET/PV PV_SCW_I = BLOCKSIZE - PV_POINT_OUT + 1 + SET/PV PV_SCW_S[1:4] = $PADZ(PV_SCW_I,4) + SET/PV PV_BUFFER[PV_POINT_OUT+1:PV_POINT_OUT+4] = + + PV_SCW_S[1:4] +* Add record segment + SET/PV PV_POINT_OUT = PV_POINT_OUT + 5 + SET/PV PV_BUFFER[PV_POINT_OUT:BLOCKSIZE] = + + PV_MARCDATA[1:BLOCKSIZE-PV_POINT_OUT+1] + SET/PV PV_SEGLEN = PV_SEGLEN - (BLOCKSIZE-PV_POINT_OUT+1) + SET/PV PV_POINT_IN = PV_POINT_IN+BLOCKSIZE-PV_POINT_OUT+1 + SET/PV PV_POINT_OUT = 1 + JUMP OUTLC + END_IF +* Record will end but not begin in this block....3 + IF (PV_SEGLEN NE PV_LENGTH) AND + + PV_SEGLEN LE (BLOCKSIZE - PV_POINT_OUT + 1 - 5) THEN +* Set segment control word + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT] = '3' + SET/PV PV_SCW_I = PV_SEGLEN + 5 + SET/PV PV_SCW_S[1:4] = $PADZ(PV_SCW_I,4) + SET/PV PV_BUFFER[PV_POINT_OUT+1:PV_POINT_OUT+4] = + + PV_SCW_S[1:4] +* Add record segment + SET/PV PV_POINT_OUT = PV_POINT_OUT + 5 + SET/PV PV_BUFFER[PV_POINT_OUT:*] = + + PV_MARCDATA[PV_POINT_IN:PV_POINT_IN+PV_SEGLEN-1] + SET/PV PV_POINT_OUT = PV_SEGLEN + 1 + 5 + IF PV_POINT_OUT GE (BLOCKSIZE-5) THEN + SET/PV PV_POINT_OUT = 1 + SET/PV PV_SEGLEN = 0 + JUMP OUTLC + END_IF + JUMP GETLC + END_IF +* Record will not begin or end in this block....2 + IF (PV_SEGLEN NE PV_LENGTH) AND + + PV_SEGLEN GT (BLOCKSIZE - PV_POINT_OUT + 1 - 5) THEN +* Set segment control word + SET/PV PV_BUFFER[PV_POINT_OUT:PV_POINT_OUT] = '2' + SET/PV PV_SCW_I = BLOCKSIZE + SET/PV PV_SCW_S[1:4] = $PADZ(PV_SCW_I,4) + SET/PV PV_BUFFER[PV_POINT_OUT+1:PV_POINT_OUT+4] = + + PV_SCW_S[1:4] +* Add record segment + SET/PV PV_POINT_OUT = PV_POINT_OUT + 5 + SET/PV PV_BUFFER[PV_POINT_OUT:BLOCKSIZE] = + + PV_MARCDATA[PV_POINT_IN:PV_POINT_IN+BLOCKSIZE-6] + SET/PV PV_SEGLEN = PV_SEGLEN - (BLOCKSIZE - 5) + SET/PV PV_POINT_IN = PV_POINT_IN + (BLOCKSIZE - 5) + SET/PV PV_POINT_OUT = 1 + JUMP OUTLC + END_IF +OUTLC: + IF OUTPUT = 'REVIEW' + SET/PV LINE_CNT = LINE_CNT + 1 +******* Check for page break ******** + IF LINE_CNT >= 20 + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 1 + END_IF + TELL PV_BUFFER[1:BLOCKSIZE] + ELSE + PUT/F PV_BUFFER[1:BLOCKSIZE] ,FID=A + END_IF +* + IF PV_SEGLEN EQ 0 THEN + JUMP GETLC + ELSE + JUMP BLDLC + END_IF + END_WHILE +* "Put" last line + IF OUTPUT = 'REVIEW' + TELL PV_BUFFER[1:BLOCKSIZE] + ELSE + PUT/F PV_BUFFER[1:BLOCKSIZE] ,FID=A + END_IF +* + END_SELECT +* +* Cleanup - close files and discard result sets. +* +CLEANUP: + ACQUIRE/PV MESSAGE 46708, C2=MSG + TELL MSG + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' +QUIT: ACQUIRE/PV LASTSET, N1 = PV_LASTSET + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + END_IF + DISCARD !PV_SET!:!PV_LASTSET! + SET/DEF RESULT = Y +* +* DONE - successful report generation; return to caller +* +DONE: + RETURN_TO_SCREEN +* +* Error - inform user and close file, if necessary. +* +SYNTAXERR: +EXCEPTION: +OPENERR: +VIEWERR: + SHOW/MESSAGE !DMSTAT! + JUMP ERROR +FNDERR: + SHOW/MESSAGE 46702 + JUMP ERROR +BREAKERR: + SHOW/MESSAGE 46700 +ERROR: + SHOW/MESSAGE 46703 + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + CLOSE/F FID = B,ERR=$CONTINUE + END_IF + SET/DEF RESULT = Y + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' + RETURN_TO_SCREEN +*PROC MRT +tell 'TLP ENU 920430 L1F P004 TLPV3.3' +return +*PROC NWBLST01 +*----------------------------------------------------------------------------- +* +* Title: New Books List +* File: NWBLST01.PRC +* Author: Information Dimensions, Inc. (HB) +* +* Description: List of Titles newly received in the library +* +* Input Parameters: +* OUTPUT - may be 'REVIEW','PRINT'. Review displays report +* on screen, print outputs to file for printing. +* +* START_DT/END_DT - find where COPY.ADD_DT is in range +* +* SUBJECT - restrict to certain CAT.SUBJs +* +* SORT_KEY - option to sort by title or subject +* +* MONTH_YEAR - Inputted month and year for heading +* +* LOGIN_LIBR - User's login library +* +* Other Selection Criteria: +* LIBR_KEY - Restrict to certain libraries. +* +* ALL - Boolean value; set true by Slang if no params entered +* +* Valid Combinations: +* Presence or absence of SUBJECT. Subject must be present for +* sort_key = 'SUBJECT'. All other parameters are required to +* be inputted to the proc. +* +* Output File: nwblst01.rpt +* +* Record Types Referenced: +* TEMPLATE, LIBR, COPY, CATR, SUB +* Buffers: @A @B @C @D +* +* Report Name: New Books List +* +* Report No.: NWBLST01 +* +* Menu Access: ??? +* +* Parameter +* Input Screen: CATRPT10 +* +* Templates: REPORT_HDR, UNION_CAT, COPY_NEWBOOK +* +*------------------------------------------------------------------------------ +* +* Revision History: +* +* Date Revised By Description +* -------- ---------- ----------- +* 11/16/89 Berger Initial version +* 09/27/90 Berger Fix paging problem, problem with type +* 01/07/91 Sandstrom 20 libs fix +* 05/08/91 Sandstrom Moved file opens and template gets +* to be after the find command. +* 07/03/91 MChung Substitute tabs with 8 spaces and +* spelling check +* +*------------------------------------------------------------------------------ +* +START: + ACQUIRE/PV MESSAGE 46707, C2=MSG + TELL MSG,$B + ON/BREAK BREAKERR + ON/EXCEPTION EXCEPTION + ON/SYNTAX SYNTAXERR + SET/DEFAULT RESULT = N + SET/PV PV_TODAY = $YYYYMMDD + SET/PV PRINTTOP = 1 + SET/PV RPTNM = 'NWBLST01' + SET/PV RPTTTL = 'New Books list for '// MONTH_YEAR + SET/PV PGNO = 0 +* +*set/mode echoproc=yes +* Begin construction of FIND command. +* +* 910107smls added 20 libs fix + DELETE/GV OUTSTR + DELETE/GV OUTLC + DELETE/GV INSTR + SET/GV INSTR = LIBR_KEY + @/PL='$TLP_PROC/generpts' QTBLKS01, VFLDNM='COPY.LIBR_KEY' + SET/PV PV_FINDCMD = 'FIND SUB,RCAT,COPY,LIBR ' //+ + 'WHERE RCAT.CATNO:=>>SUB.CATNO ' //+ + 'AND RCAT.CATNO:=>>COPY.CATNO ' //+ + 'AND LIBR.LIBR_KEY:=COPY.LIBR_KEY ' //+ + ' AND ((RCAT.ADD_DT = '//START_DT//':'//END_DT// + + ' ) '// + + 'OR (SUB.ADD_DT = '//START_DT//':'//END_DT// + + ' AND DOC inc ''SER''* AND RNUM=0)) ' +* +* Append FIND command based on options. +* +* IF (SUBJECT <> '') +* SET/PV PV_FINDCMD = PV_FINDCMD //+ +* 'AND RCAT.SHELF INC ' // SUBJECT +* END_IF +* +* Append FIND for sort options. +* +* Removed copy.libr_key from order by +* SET/PV PV_FINDCMD = PV_FINDCMD //+ +* ' ORDER BY !SORT_KEY! RCAT.TI, RCAT.PUBL, ' //+ +* 'COPY.YEAR, COPY.ITEMID, COPY.COPY' + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' ORDER BY rcat.shelf' +* +* Execute Find and set up for report generation +* + !PV_FINDCMD! END REF=NO + ACQUIRE/PV MEMBERS, N1 = PV_NUMMEM + ACQUIRE/PV LASTSET, N1 = PV_FOUNDSET + IF (PV_NUMMEM <= 0) + SHOW/MESSAGE 46705 + JUMP CLEANUP + END_IF +* smls 910508 moved this to be after the FIND command. +* Set up for desired output method + SELECT (OUTPUT) + CASE 'REVIEW' + SET/PV MAXLINES = 20 + SET/PV PV_FILEID = '' + CASE 'PRINT' + SET/PV MAXLINES = 60 + spawn rm -f nwblst01.rpt + OPEN/F nwblst01.rpt, FID=A, INTENT=WRITE,ERR=OPENERR + put/f fid=a $t20,rptttl + SET/PV PV_FILEID = ',FID=A' + END_SELECT +* +* GET/VIEW [TEMPLATE_KEY = 'REPORT_HDR']TEMPLATE@A, ERR = VIEWERR +* ASSIGN/PV HEADER = TEXT@A + GET/VIEW [TEMPLATE_KEY = 'UNION_CAT']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV CATINFO = TEXT@A +* GET/VIEW [TEMPLATE_KEY = 'COPY_NEWBOOK']TEMPLATE@A, ERR = VIEWERR +* ASSIGN/PV COPYINFO = TEXT@A +* +* Step through members of set, generating correct output for each. + FOR PV_Q = 1, PV_NUMMEM +* + GET/VIEW [!PV_FOUNDSET!,!PV_Q!]LIBR@B, ERR = VIEWERR + ASSIGN/PV LIBR_NAME = LIBR_NAME@B + ASSIGN/PV LOC_NAME = LOC_NAME@B + ASSIGN/PV CALLOC = CALL_NUM_LOC@B + IF CALLOC = 'CAT' OR CALLOC = NULL THEN + SET/PV CALLOC = 'RCAT' + END_IF +* +* Generate report header, then data for each item +* +* IF LIBR_NAME <> PV_OLD_LIBR_NAME OR PV_Q = 1 + IF PV_Q = 1 + IF OUTPUT = 'REVIEW' + IF PV_Q <> 1 + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + END_IF + CLEAR/SCREEN + SET/PV LINE_CNT = 2 +* ELSE_IF PV_Q <> 1 +* TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + END_IF +* + SET/PV PGNO = 1 +* TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + +* SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 1 + END_IF + SET/PV PV_OLD_LIBR_NAME = LIBR_NAME +* +* Check for new Subject (if subject is entered) +* + IF SUBJECT <> '' + GET/VIEW [PV_FOUNDSET,PV_Q]RCAT@D,ERR=VIEWERR + ASSIGN/PV PV_CURSUBJ = SUBJ@D + IF PV_CURSUBJ <> PV_OLDSUBJ + SET/PV PV_OLDSUBJ = PV_CURSUBJ +* Check for page break + SET/PV LINE_CNT = LINE_CNT + 2 + IF LINE_CNT > MAXLINES + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 2 + ELSE +* TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + SET/PV PGNO = PGNO + 1 +* TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + +* SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT =1 + END_IF + END_IF +* TYPE $S2, RCAT.SUBJ, LABELS = N, SKIP = 0, + +* SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + END_IF + END_IF +* + GET/VIEW [PV_FOUNDSET,PV_Q]COPY@C, ERR = VIEWERR + ASSIGN/PV PV_CURCATNO = CATNO@C + IF PV_CURCATNO = NULL + GET/VIEW [PV_FOUNDSET,PV_Q]RCAT@D, ERR = VIEWERR + ASSIGN/PV PV_CURCATNO = CATNO@D + END_IF + ASSIGN/PV PV_CURITEMID = ITEMID@C +* If new catno, print catalog info + IF (PV_CURCATNO <> PV_LSTCATNO) + SET/PV LINE_CNT = LINE_CNT + 7 +* Check for page break + IF LINE_CNT > MAXLINES + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 2 + ELSE +* TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + SET/PV PGNO = PGNO + 1 +* TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + +* SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 1 + END_IF + END_IF + TYPE $S2, !CATINFO!, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV PV_LSTCATNO = PV_CURCATNO + set/pv line_cnt=line_cnt+dm_lines + END_IF +* Aviod duplicates from FIND command + IF (PV_CURITEMID <> PV_LSTITEMID) + SET/PV LINE_CNT = LINE_CNT + 1 +* Check for page break + IF LINE_CNT > MAXLINES + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + SET/PV LINE_CNT = 2 + ELSE +* TYPE $P, MEMBERS=1, SET=!PV_FOUNDSET! !PV_FILEID! + SET/PV PGNO = PGNO + 1 +* TYPE !HEADER!, $S2, LABELS = N, SKIP = 0, + +* SET = !PV_FOUNDSET!, MEMBERS = 1 !PV_FILEID! + SET/PV LINE_CNT = 1 + END_IF + END_IF + TYPE !COPYINFO!, LABELS = N, SKIP = 0, + + SET = !PV_FOUNDSET!, MEMBERS = !PV_Q! !PV_FILEID! + SET/PV PV_LSTITEMID = PV_CURITEMID + set/pv line_cnt=line_cnt+dm_lines + END_IF +* + END_FOR +* +* Cleanup - close files and discard result sets. +* +CLEANUP: + ACQUIRE/PV MESSAGE 46708, C2=MSG + TELL MSG + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' +QUIT: ACQUIRE/PV LASTSET, N1 = PV_LASTSET + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + END_IF + DISCARD !PV_FOUNDSET!:!PV_LASTSET! + SET/DEF RESULT = Y +* +* DONE - successful report generation; return to caller +* +DONE: + RETURN_TO_SCREEN +* +* Error - inform user and close file, if necessary. +* +SYNTAXERR: +EXCEPTION: +OPENERR: +VIEWERR: + SHOW/MESSAGE !DMSTAT! + JUMP ERROR +BREAKERR: + SHOW/MESSAGE 46700 +ERROR: + SHOW/MESSAGE 46703 + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + END_IF + SET/DEF RESULT = Y + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' + RETURN_TO_SCREEN +*PROC QTBLKS01 +*----------------------------------------------------------------------------- +* +* Title: Build Library Key String +* File: QTBLKS01 +* Author: Information Dimensions, Inc. (BB/SMLS) +* +* Description: This proc is called to build a string of library keys that +* can be used within a find command. This routine handles the +* >20 terms/field limit. +* +* Directions: +* +* Input: +* Passed as a global variable: +* INSTR[*] - Input character string that contains the list of +* library keys with single quotes around each key. +* Multiple keys are separated by commas. +* Passed on call: +* VFLDNM[*] - Contains the name of the view field with a source +* of the library key to be used in the find command. +* Output: +* The following global variables are set: +* OUTSTR[*] - The product of this routine, the field test. +* OUTLC - The length of the field test value. +* BSTAT - Return status....0=ok, -1=error. +* +*------------------------------------------------------------------------------ +* +* Revision History: +* +* Date Revised By Description +* -------- ---------- ----------- +* 12/20/90 Beaber Initial Version +* 01/03/91 Sandstrom Revisions +* 07/08/91 MChung Substitute tabs with 8 spaces & +* spelling checks +* +*------------------------------------------------------------------------------ +* +* +* Initialize variables. +* + SET/PV VFNSC = 1 + SET/PV VFNEC = $LC(VFLDNM) + SET/PV INEC = $LC(INSTR) + SET/PV INSC = 1 + SET/PV OUTSC = 1 + SET/PV SC = 1 + SET/PV SC20 = 1 + SET/PV COUNT = 0 + SET/GV BSTAT = 0 +* +* Begin building output string by adding on '(', field name, '='. +* + SET/GV OUTSTR[*] = '(' // VFLDNM[VFNSC:VFNEC] // '=' + SET/PV OUTSC = OUTSC + VFNEC - VFNSC + 4 +* +* Loop through input string searching for commas. +* + SET/PV COMMA = $MATCH(',',INSTR[SC:INEC]) + WHILE (COMMA NE 0) + SET/PV COUNT = COUNT + 1 +* +* Continue building the string as every 20th comma is found. +* + IF ($MOD(COUNT,20) EQ 0) THEN +* +* Add on "OR Field_name=", if necessary. +* + IF (OUTSTR[OUTSC-2] <> '=') THEN + SET/GV OUTSTR[OUTSC+1:OUTSC+VFNEC-VFNSC+7] = + + ' OR ' // VFLDNM[VFNSC:VFNEC] // '=' + SET/PV OUTSC = OUTSC + VFNEC - VFNSC + 7 + END_IF +* +* Add on next 20 keys. +* + IF SC20 = INSC THEN + SET/GV OUTSTR[OUTSC:OUTSC+SC+COMMA-SC20-2] = + + INSTR[SC20:SC+COMMA-2] + ELSE + SET/GV OUTSTR[OUTSC:OUTSC+SC+COMMA-SC20-2] = + + INSTR[SC20+1:SC+COMMA-2] + END_IF +* +* Increment index (SC) and continue looking for commas. +* + SET/PV OUTSC = OUTSC + SC + COMMA - SC20 - 2 + SET/PV SC20 = SC + COMMA + END_IF +* +* Increment index (SC) and continue looking for commas. +* + SET/PV SC = SC + COMMA + BREAK_IF (SC GT INEC) + SET/PV COMMA = $MATCH(',',INSTR[SC:INEC]) + END_WHILE +* +* Add on "OR Field_name=", if necessary. +* + IF (OUTSTR[OUTSC-2] <> '=') THEN + SET/GV OUTSTR[OUTSC+1:OUTSC+VFNEC-VFNSC+7] = + + ' OR ' // VFLDNM[VFNSC:VFNEC] // '=' + SET/PV OUTSC = OUTSC + VFNEC - VFNSC + 7 + END_IF +* +* Add on last set of characters. +* + SET/PV OUTEC = OUTSC + INEC - SC20 + 2 + SET/GV OUTSTR[OUTSC:OUTEC] = INSTR[SC20:INEC] // ')' +* + SET/GV OUTLC = OUTEC + RETURN +*PROC SPILAB01 +*----------------------------------------------------------------------------- +* +* Title: Spine Labels +* File: SPILAB01.PRC +* Author: Information Dimensions, Inc. (HB) +* +* Description: Spine labels for cataloged books +* +* Input Parameters: +* OUTPUT - may be 'REVIEW','PRINT'. Review displays report +* on screen, print outputs to file for printing. +* +* START_DT/END_DT - find where COPY.ADD_DT is in range +* +* CALL - restrict to certain CATR.CALLs +* +* ITEMID - restrict to certain COPY.ITEMIDs +* +* LOGIN_LIBR - User's login library +* +* Other Selection Criteria: +* LIBR_KEY - Restrict to certain libraries. +* +* ALL - Boolean value; set true by Slang if no params entered +* +* Valid Combinations: +* START AND END DT REQUIRED. CALL and ITEMID are optional. +* +* Output File: spilab01.rpt +* +* Record Types Referenced: +* TEMPLATE, LIBR, SYS_PARM, COPY, CATR, SUB +* Buffers: @A @C @B @E @D +* +* Report Name: Spine Labels +* +* Report No.: SPILAB01 +* +* Menu Access: ??? +* +* Parameter +* Input Screen: CATRPT11 +* +* Templates: +* +*------------------------------------------------------------------------------ +* +* Revision History: +* +* Date Revised By Description +* -------- ---------- ----------- +* 10/16/89 Berger Initial version +* 11/14/90 Berger Fixed bug in dewey form on the +* line counter +* 01/07/91 Sandstrom 20 libs fix +* 05/08/91 Sandstrom Moved file opens and template gets to +* after the find command. +* 07/03/91 MChung Substitute tabs with 8 spaces and +* spelling check +* 04/14/92 Sandstrom Fix for TLP-1291-7. Output for +* call number was not correct. +* +*------------------------------------------------------------------------------ +* +START: + ACQUIRE/PV MESSAGE 46707, C2=MSG + TELL MSG,$B + ON/BREAK BREAKERR + ON/EXCEPTION EXCEPTION + ON/SYNTAX SYNTAXERR + SET/DEFAULT RESULT = N + SET/PV PV_TODAY = $YYYYMMDD +* +* Begin construction of FIND command. +* +* 910107smls added 20 libs fix + DELETE/GV OUTSTR + DELETE/GV OUTLC + DELETE/GV INSTR + SET/GV INSTR = LIBR_KEY + @/PL='$TLP_PROC/generpts' QTBLKS01, VFLDNM='COPY.LIBR_KEY' + SET/PV PV_FINDCMD = 'FIND CATR,COPY,LIBR ' //+ + 'WHERE COPY.CATNO:=CATR.CATNO ' //+ + 'AND LIBR.LIBR_KEY:=COPY.LIBR_KEY AND ' //+ + OUTSTR[1:OUTLC]//' ' + IF START_DT <> '' THEN + SET/PV PV_FINDCMD = PV_FINDCMD//+ + 'AND COPY.ADD_DT = '//START_DT//':'//END_DT//' ' + END_IF +* + GET/VIEW [ID=1]SYS_PARM@B,ERR=VIEWERR + ASSIGN/PV RPT_MULT_ENT = RPT_MULT_ENTITY@B + ASSIGN/PV COPY_RPT_SORT = COPY_RPT_SORT@B + GET/VIEW[LIBR_KEY=!LOGIN_LIBR!]LIBR@C,ERR=VIEWERR + ASSIGN/PV CALLOC = CALL_NUM_LOC@C + IF CALLOC = 'CAT' OR CALLOC = NULL + SET/PV CALLOC = 'CATR' + END_IF +* +* Append FIND command based on options. +* + IF (ITEMID <> '') + SET/PV PV_FINDCMD = PV_FINDCMD //+ + 'AND COPY.ITEMID = ' // ITEMID + ELSE_IF (CALL <> '') + SET/PV PV_FINDCMD = PV_FINDCMD //+ + 'AND !CALLOC!.CALL = ' // CALL + END_IF +* +* Build sortkey to reflect correct call no. field, depending on +* SYS_PARM and LIBR flags +* + GET/VIEW [ID=1]SYS_PARM@B,ERR=VIEWERR + ASSIGN/PV RPT_MULT_ENT = RPT_MULT_ENTITY@B + ASSIGN/PV COPY_RPT_SORT = COPY_RPT_SORT@B + IF (RPT_MULT_ENTITY = 'N') + ASSIGN/PV CAT_LC = CAT_LC_FLG@B + IF (CAT_LC = 'Y') + SET/PV LCADD = '_LC_SORT' + ELSE + SET/PV CATRADD = '(1)' + END_IF + ELSE + GET/VIEW[LIBR_KEY=!LOGIN_LIBR!]LIBR@C,ERR=VIEWERR + ASSIGN/PV CAT_LC = CAT_LC_FLG@C + ASSIGN/PV COPY_LC = COPY_LC_FLG@C + IF (CALLOC = 'CATR') AND (CAT_LC = 'Y') + SET/PV LCADD = '_LC_SORT' + SET/PV CATRADD = '' + ELSE_IF (CALLOC = 'CATR') + SET/PV LCADD = '' + SET/PV CATRADD = '(1)' + ELSE_IF (CALLOC = 'COPY') AND (COPY_LC = 'Y') + SET/PV LCADD = '_LC_SORT' + SET/PV CATRADD = '' + ELSE + SET/PV LCADD = '' + SET/PV CATRADD = '' + END_IF + END_IF + SET/PV SORTKEY = '!CALLOC!.CALL!LCADD!' // '!CATRADD!' +* + SET/PV PV_FINDCMD = PV_FINDCMD //+ + ' ORDER BY COPY.LIBR_KEY, !SORTKEY! ' + IF (COPY_RPT_SORT <> '') + SET/PV PV_FINDCMD = PV_FINDCMD // ', !COPY_RPT_SORT! ' + END_IF +* +* Execute Find and set up for report generation +* + !PV_FINDCMD! END REF=NO + ACQUIRE/PV MEMBERS, N1 = PV_NUMMEM + ACQUIRE/PV LASTSET, N1 = PV_FOUNDSET + IF (PV_NUMMEM <= 0) + SHOW/MESSAGE 46705 + JUMP CLEANUP + END_IF +* smls moved file opens and template get. +* Set up for desired output method + SELECT (OUTPUT) + CASE 'REVIEW' + SET/PV PV_FILEID = '' + CASE 'PRINT' + OPEN/F spilab01.rpt, FID=A, INTENT=WRITE, + + CARRIAGE=YES, ERR=OPENERR + SET/PV PV_FILEID = ',FID=A' + END_SELECT +* + GET/VIEW [TEMPLATE_KEY = 'SPINE_LABEL']TEMPLATE@A, ERR = VIEWERR + ASSIGN/PV PV_SPINE_LABEL = TEXT@A +* Step through members of set, generating correct output for each. + FOR PV_Q = 1, PV_NUMMEM +* +* get calloc +* + GET/VIEW [PV_FOUNDSET,PV_Q]LIBR@C, ERR=VIEWERR + ASSIGN/PV CALLOC = CALL_NUM_LOC@C + IF CALLOC = 'CAT' OR CALLOC = NULL THEN + SET/PV CALLOC = 'CATR' + END_IF +* +* Parse the Call Number to print it in the template +* + IF CALLOC = 'CATR' + GET/VIEW [PV_FOUNDSET,PV_Q]CATR@D,ERR=VIEWERR + ASSIGN/PV PV_CALL = CALL@D + ELSE + GET/VIEW [PV_FOUNDSET,PV_Q]COPY@E,ERR=VIEWERR +* smls19920414 changed field name being assigned to PV_CALL +* from ASSIGN/PV PV_CALL = COPY@E to + ASSIGN/PV PV_CALL = CALL@E + END_IF + SET/PV LENGTH = $LC(PV_CALL) + SET/PV LINENUM = 1 +* Reset temp variables to give to template + FOR I = 1,9 + SET/PV LINE!I! = '' + END_FOR +* +* Parse LC call numbers +* +* smls19920414 added reference to COPY_LC. +* Old IF was: IF CAT_LC = 'Y' + IF (CALLOC = 'CATR' AND CAT_LC = 'Y') + + OR (CALLOC = 'COPY' AND COPY_LC = 'Y') THEN + FOR PV_P = 1,LENGTH + SET/PV PV_CHAR = PV_CALL[PV_P] + IF PV_P <> LENGTH + SET/PV PV_Z = PV_P + 1 + SET/PV PV_NEXT = PV_CALL[PV_Z] + ELSE + SET/PV PV_NEXT = ' ' + END_IF + SELECT LINENUM + CASE 1 +* Check for letter + IF $ABS(PV_CHAR) = 0 AND PV_CHAR <> '0' + SET/PV LINE1 = LINE1 // PV_CHAR + ELSE + SET/PV LINE2 = PV_CHAR + SET/PV LINENUM = 2 + END_IF + CASE 2 +* Check for period followed by a letter + IF PV_CHAR = '.' AND $ABS(PV_NEXT) = 0 AND + + PV_NEXT <> '0' + SET/PV LINENUM = 3 + ELSE + SET/PV LINE2 = LINE2 // PV_CHAR + END_IF + DEFAULT + SET/PV LINE!LINENUM! = LINE!LINENUM! // PV_CHAR +* Check for a space or next character to be a letter + IF ($ABS(PV_NEXT) = 0 AND PV_NEXT <> '0') + SET/PV LINENUM = LINENUM + 1 + END_IF + END_SELECT + END_FOR +* +* Parse Dewey call numbers +* + ELSE + FOR PV_P = 1,LENGTH + SET/PV PV_CHAR = PV_CALL[PV_P] + SELECT LINENUM + CASE 1 +* Break on period + IF PV_CHAR = '.' + SET/PV LINENUM = 2 + END_IF + SET/PV LINE!LINENUM! = LINE!LINENUM! // PV_CHAR + DEFAULT + SET/PV LINE!LINENUM! = LINE!LINENUM! // PV_CHAR +* Break on spaces + IF PV_CHAR = ' ' + SET/PV LINENUM = LINENUM + 1 + END_IF + END_SELECT + END_FOR + END_IF +* Type the Spine Label + TYPE !PV_SPINE_LABEL!, SKIP=0, + + SET=!PV_FOUNDSET!,MEMBERS=!PV_Q! !PV_FILEID! + IF OUTPUT = 'REVIEW' + ACQUIRE/PV MESSAGE 46710, C2=MSG + INQUIRE/PV PV_QUIT, '!MSG!' + JUMPIF PV_QUIT[1] = 'N' OR PV_QUIT[1] = 'n',QUIT + CLEAR/SCREEN + END_IF + + END_FOR +* +* Cleanup - close files and discard result sets. +* +CLEANUP: + ACQUIRE/PV MESSAGE 46708, C2=MSG + TELL MSG + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' +QUIT: ACQUIRE/PV LASTSET, N1 = PV_LASTSET + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + END_IF + DISCARD !PV_FOUNDSET!:!PV_LASTSET! + SET/DEF RESULT = Y +* +* DONE - successful report generation; return to caller +* +DONE: + RETURN_TO_SCREEN +* +* Error - inform user and close file, if necessary. +* +SYNTAXERR: +EXCEPTION: +OPENERR: +VIEWERR: + SHOW/MESSAGE !DMSTAT! + JUMP ERROR +BREAKERR: + SHOW/MESSAGE 46700 +ERROR: + SHOW/MESSAGE 46703 + IF (OUTPUT <> 'REVIEW') + CLOSE/F FID = A,ERR=$CONTINUE + END_IF + SET/DEF RESULT = Y + ACQUIRE/PV MESSAGE 46709, C2=MSG + INQUIRE/PV DUMMY, '!MSG!' + RETURN_TO_SCREEN diff --git a/UnitTests/TestData/tnef/missing-filenames/message.rtf b/UnitTests/TestData/tnef/missing-filenames/message.rtf new file mode 100644 index 0000000000..dc477b6fc0 --- /dev/null +++ b/UnitTests/TestData/tnef/missing-filenames/message.rtf @@ -0,0 +1,20 @@ +{\rtf1\ansi\ansicpg1252\fromtext\deff0{\fonttbl +{\f0\fswiss Arial;} +{\f1\fmodern Courier New;} +{\f2\fnil\fcharset2 Symbol;} +{\f3\fmodern\fcharset0 Courier New;}{\f4\fswiss\fcharset0 Arial;}} +{\colortbl\red0\green0\blue0;\red0\green0\blue255;} +\uc1\pard\plain\deftab360\f0\fs20\cf0 Hi Stephen,\par +\par +Sue has encountered a Date problem while running our' New Books List'. Can you please help us. Apparently it is having a hernia with the ADD_DT which I would have presumed was fixed with your patches.\par +\par +Attached is the PRC file : generpts.scr\par +\par +Attached are some screen dumps which record the error message (3 MS Word .doc files)\par +\par +I am in Vancouver for the next two weeks but it is really important we get this functionality resolved ASAP. Could you continue dialoguing with Sue and Ralph to see how we can fix this. \par +\par +cheers, Liedeke\par + +\pard\plain\f4\fs20 \par EOM \par\par NOTICE - This message contains information intended only for the use of the addressee named above. It may also be confidential and/or privileged. If you are not the intended recipient of this message you are hereby notified that you must not disseminate, copy or take any action in reliance on it. If you have received this message in error please notify postmaster@bhp.com.au.\par +\objattph \objattph \objattph \objattph } \ No newline at end of file diff --git a/UnitTests/TestData/tnef/multi-value-attribute.list b/UnitTests/TestData/tnef/multi-value-attribute.list new file mode 100644 index 0000000000..158799e55b --- /dev/null +++ b/UnitTests/TestData/tnef/multi-value-attribute.list @@ -0,0 +1,2 @@ +208225__5_seconds__Voice_Mail.mp3 +body.rtf diff --git a/UnitTests/TestData/tnef/multi-value-attribute.tnef b/UnitTests/TestData/tnef/multi-value-attribute.tnef new file mode 100644 index 0000000000..a8939b487b Binary files /dev/null and b/UnitTests/TestData/tnef/multi-value-attribute.tnef differ diff --git a/UnitTests/TestData/tnef/multi-value-attribute/208225__5_seconds__Voice_Mail.mp3 b/UnitTests/TestData/tnef/multi-value-attribute/208225__5_seconds__Voice_Mail.mp3 new file mode 100644 index 0000000000..91cd66c133 Binary files /dev/null and b/UnitTests/TestData/tnef/multi-value-attribute/208225__5_seconds__Voice_Mail.mp3 differ diff --git a/UnitTests/TestData/tnef/multi-value-attribute/message.rtf b/UnitTests/TestData/tnef/multi-value-attribute/message.rtf new file mode 100644 index 0000000000..60b7def291 --- /dev/null +++ b/UnitTests/TestData/tnef/multi-value-attribute/message.rtf @@ -0,0 +1,33 @@ +{\rtf1\ansi\ansicpg1252\fromhtml1 \fbidis \deff0{\fonttbl +{\f0\fswiss Arial;} +{\f1\fmodern Courier New;} +{\f2\fnil\fcharset2 Symbol;} +{\f3\fmodern\fcharset0 Courier New;}} +{\colortbl\red0\green0\blue0;\red0\green0\blue255;} +\uc1\pard\plain\deftab360 \f0\fs24 +{\*\htmltag19 } +{\*\htmltag34 } +{\*\htmltag1 \par } +{\*\htmltag241 } +{\*\htmltag41 } +{\*\htmltag50 } +{\*\htmltag240 } +{\*\htmltag96
}\htmlrtf {\htmlrtf0 +{\*\htmltag96
}\htmlrtf {\lang9 \htmlrtf0 +{\*\htmltag96
}\htmlrtf {\htmlrtf0 {\*\htmltag64}\htmlrtf {\htmlrtf0 You received a voice mail from Curie Conf Room at +{\*\htmltag84 }\htmlrtf {\field{\*\fldinst{HYPERLINK "tel:208225"}}{\fldrslt\cf1\ul \htmlrtf0 208225\htmlrtf }\htmlrtf0 \htmlrtf }\htmlrtf0 +{\*\htmltag92 }.{\*\htmltag72}\htmlrtf\par}\htmlrtf0 + +{\*\htmltag104
}\htmlrtf }\htmlrtf0 +{\*\htmltag112
}\htmlrtf \par +\htmlrtf0 +{\*\htmltag96 }\htmlrtf {\pard\plain \f0\fs24 \htmlrtf0 +{\*\htmltag104
}\htmlrtf }\htmlrtf0 +{\*\htmltag104
}\htmlrtf }\htmlrtf0 +{\*\htmltag104
}\htmlrtf }\htmlrtf0 +{\*\htmltag58 } +{\*\htmltag27 }} \ No newline at end of file diff --git a/UnitTests/TestData/tnef/one-file/AUTHORS b/UnitTests/TestData/tnef/one-file/AUTHORS new file mode 100644 index 0000000000..cdb2e018cd --- /dev/null +++ b/UnitTests/TestData/tnef/one-file/AUTHORS @@ -0,0 +1,8 @@ + + Authors of tnef + =============== + +* Mark Simpson damned@world.std.com + +Many thank go to the original author: Thomas Boll (tb@boll.ch). + diff --git a/UnitTests/TestData/tnef/panic.list b/UnitTests/TestData/tnef/panic.list new file mode 100644 index 0000000000..7c56258bc5 --- /dev/null +++ b/UnitTests/TestData/tnef/panic.list @@ -0,0 +1,4 @@ +image001.jpg +image002.jpg +image003.png +body.html \ No newline at end of file diff --git a/UnitTests/TestData/tnef/panic.tnef b/UnitTests/TestData/tnef/panic.tnef new file mode 100644 index 0000000000..741b6ab67e Binary files /dev/null and b/UnitTests/TestData/tnef/panic.tnef differ diff --git a/UnitTests/TestData/tnef/panic/image001.jpg b/UnitTests/TestData/tnef/panic/image001.jpg new file mode 100644 index 0000000000..0673017a5b Binary files /dev/null and b/UnitTests/TestData/tnef/panic/image001.jpg differ diff --git a/UnitTests/TestData/tnef/panic/image002.jpg b/UnitTests/TestData/tnef/panic/image002.jpg new file mode 100644 index 0000000000..6ef03f0c80 Binary files /dev/null and b/UnitTests/TestData/tnef/panic/image002.jpg differ diff --git a/UnitTests/TestData/tnef/panic/image003.png b/UnitTests/TestData/tnef/panic/image003.png new file mode 100644 index 0000000000..b6e71b808a Binary files /dev/null and b/UnitTests/TestData/tnef/panic/image003.png differ diff --git a/UnitTests/TestData/tnef/panic/message.html b/UnitTests/TestData/tnef/panic/message.html new file mode 100644 index 0000000000..70fbcfd40b --- /dev/null +++ b/UnitTests/TestData/tnef/panic/message.html @@ -0,0 +1,103 @@ + + + + + + +
+


+

+
+
+
+
+
From: Andreas Wallenberg
+Sent: Friday, December 18, 2015 2:38 PM
+To: Tech
+Cc: Ying Han; Johan Blom
+Subject: VIKTIGT: Vill att ngon av er gr fljande ndringar i https://baka.spiderads.eu/
+
 
+
+
+
+

+1.       Flytta ner fljande 3 orderIDs ner till fakturerad
+

+

+2.       Ta bort testkunderna, men skerstll att vr fiktiva kund i frsvinner i + +https://my.spiderads.eu/
+

+

+3.       Fljande kunder blir fakturerade idag
+Men nr Wglund r tillbaka vill jag att vi skapar en mailtrigger till +ekonomi@bifirm.com  & installerar epost + informerar Ekonomi (Danka & Ying) hur dom hanterar ordrar framver i Baka.
+
+----------------------------------------
+
+Hej Danka & Ying, hr kommer lite drygt 1,5 miljoner att fakturera.
+
+Fljande skriver ni p fakturan
+• Engngsfakturor: Tross = SpiderAds P0119 att Jessica Bohman & Fotografiska = SpiderAds – Decemberkampanj F-Concept (SpiderAds + Kampanjnamn som str i ordern)
+• Avtalsfakturor: Programmatisk annonsering SpiderAds + avtalsperiod & Startkostnad X sek (p egen rad)   +

+

+

+1.       Eksjhus offertnr 715: Fakturera 45.000 sek + moms omgende 17 dgr netto enligt offert (Engngsorder)

+

+2.       Tross offertnr 714: Fakturera 38.000 sek + moms omgende 17 dgr netto enligt offert (Engngsorder)

+

+3.       Fotografiska offertnr 725: 50.000 sek + moms omgende 30 dgr netto enligt offert (Engngsorder finns ingen korrekt offert, men fakturera)

+

+4.       Fotografiska offertnr 720: 225.000 sek kvartalsvis i frskott omgende 30 dgr netto med avtalsstart 1/12 2015 (Lpande avtal)

+

+5.       Djurnset offertnr 716: 150.000 sek kvartalsvis i frskott per den 1 jan 2016 30 dgr netto. Avtalsstart 1/1 2016 (Lpande avtal)

+

+6.       Hedins Bil offertnr 693: 125.000 sek kvartalsvis i frskott faktureras omgende 17 dgr netto (OBS frsta fakturan skall ha en startkostnad p 15.000 + sek). Avtalsstart 1/1 2016

+

+7.       Domaine Wines offertnr 695: 125.000 sek kvartalsvis i frskott faktureras per den 1 jan 2016 17 dgr netto (OBS frsta fakturan skall ha en startkostnad + p 15.000 sek). Avtalsstart 1/1 2016.

+

+8.       Eksjhus offertnr 687: 90.000 sek kvartalsvis i frskott omgende 17 dgr netto med avtalsstart 1/12 2015 (Lpande avtal)

+

+9.       Wine Team offertnr 723: 125.000 sek kvartalsvis i frskott faktureras omgende 30 dgr netto. Avtalsstart 18 jan 2016

+

+10.   Cycle Europe offertnr 692: 125.000 sek kvartalsvis i frskott faktureras per den 1 jan 2016 30 dgr netto. Avtalsstart 1 mars 2016

+

+11.   Hermansson & Co AB offertnr 696: 125.000 sek kvartalsvis i frskott faktureras omgende 17 dgr netto (OBS frsta fakturan skall ha en startkostnad + p 15.000 sek). Avtalsstart 1/1 2016

+

+12.   Vstkuststugan offertnr 682: 81.000 sek kvartalsvis i frskott faktureras omgende 17 dgr netto (OBS frsta fakturan skall ha en startkostnad p 15.000 + sek). Avtalsstart 1/1 2016

+

+13.   Borohus offertnr 681: 63.000 sek kvartalsvis i frskott faktureras omgende 17 dgr netto (OBS frsta fakturan skall ha en startkostnad p 15.000 sek). + Avtalsstart 1/1 2016

+

+14.   Cask Sweden AB offertnr 719: 125.000 sek kvartalsvis i frskott faktureras per den 1 feb 2016 30 dgr netto (OBS frsta fakturan skall ha en startkostnad + p 10.000 sek). Avtalsstart 1 mars 2016

+

+
+Dessutom r befintlig avtal fr Vitaminspecialisten (Backontrackshop & Magneticshop) verflyttat frn Eurovator till BI Firm och kommer faktureras kund direkt frn oss + att BT fakturerar oss och inte Eurovator dessa.

+

+

+Med vnliga hlsningar

+

+Andreas Wallenberg
+
+
SpiderAds-BI firm  Mail Signatur
+

+Rosenlundsgatan 54, 118 63 Stockholm 
+Tel: 08 – 650 71 00 | Mob: 0707 - 66 55 24 | www.bifirm.com – + +www.spiderads.eu

+

+
+
+
+
+ + diff --git a/UnitTests/TestData/tnef/rich-text.eml b/UnitTests/TestData/tnef/rich-text.eml new file mode 100644 index 0000000000..842e0ef68b --- /dev/null +++ b/UnitTests/TestData/tnef/rich-text.eml @@ -0,0 +1,14501 @@ +From: "Jeffrey Stedfast" +To: +Subject: Rich Text +Date: Sat, 15 Dec 2018 10:07:14 -0500 +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_0001_01D4945F.67C9A820" +X-Mailer: Microsoft Outlook 16.0 +Thread-Index: AQIGQYd8BwKQgsko1bnR3xjxAU5sOA== +Content-Language: en-us +x-ms-exchange-organization-originalclientipaddress: 76.124.193.35 +x-ms-exchange-organization-originalserveripaddress: 2603:10b6:3:a3::10 +msip_labels: MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Enabled=True; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SiteId=72f988bf-86f1-41af-91ab-2d7cd011db47; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Owner=jestedfa@microsoft.com; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_SetDate=2018-12-15T15:07:06.8221370Z; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Name=General; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Application=Microsoft Azure Information Protection; MSIP_Label_f42aa342-8706-4288-bd11-ebb85995028c_Extended_MSFT_Method=Automatic; Sensitivity=General +x-ms-exchange-organization-submissionquotaskipped: False +X-MS-TNEF-Correlator: +X-OlkEid: 00000000ECAE942DF45013449093835EEB7507F00700C3B68E10F77511CEB4CD00AA00BBB6E600000000000C0000CDA2140C59596247B6411A8D771D11090000000006030000A82A649F37B6A646AF283D18546521C5 +Content-Length: 1111863 + +This is a multipart message in MIME format. + +------=_NextPart_000_0001_01D4945F.67C9A820 +Content-Type: text/plain; + charset="us-ascii" +Content-Transfer-Encoding: 7bit + + + +You've made this a Christmas to remember +Springtime feeling's in the middle of December +Strangers meet and willingly surrender +Oh! What a Christmas to remember +Almost went to Aspen but something told me no +I considered Mammoth but there wasn't enough snow +And I even thought of Gatlinburg but seemed so far to go +So I headed up to Tahoe for a Christmas on the slopes + +And I had fantasized about Christmas in this way +Curled up by a fireplace in a Tahoe ski chalet +With a fast talking lover and some slow burning wood +But even in my wildest dreams it never got this good and + +You've made this a Christmas to remember +Springtime feeling's in the middle of December +Change the radio and I'll turn the lights down dimmer +Oh! What a Christmas to remember + +Strangers when we met, lovers as we leave +Christmas to remember, too good to believe +Don't know how or when, but I know we'll meet again +Blowin' back to somewhere like some wild restless winter's wind + +And you've made this a Christmas to remember +Springtime feeling's in the middle of December +'Neath the mistletoe you kissed me warm and tender +Oh! What a Christmas to remember + +We loved and laughed and played and joked +Sang Christmas songs and talked to folks +Sleighed the fields and skied the slopes +Then to the lodge for dinner +Now it's time for us to go +As our hearts melt like chimney snow +There's just one thing I want to know +Can we do this next winter +Oh! What a Christmas to remember + +You've made this a Christmas to remember +Springtime feeling's in the middle of December +Though the fire is hot, we'll just have to let it simmer +Oh! What a Christmas to remember + +You've made this a Christmas to remember +Springtime feeling's in the middle of December +Though it's cold outside we'll just stroke the burning embers +Oh! What a Christmas to remember + + + + + +------=_NextPart_000_0001_01D4945F.67C9A820 +Content-Type: application/ms-tnef; + name="winmail.dat" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="winmail.dat" + +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 +mh+bL5w/nU+eX59v/6B/oY+in6OvtS+2P7dP+V+fvA+9H74vi5+/t30AxUAAAwAWEAIAAAALABYw +AQAAAAMA3j+fTgAAAwDxPwkEAAAeAPo/AQAAABQAAABqc3RlZGZhc3RAeWFob28uY29tAAIB+z8B +AAAAnQAAAAAAAADcp0DIwEIQGrS5CAArL+GCAQAAAAAAAAAvTz1FWENIQU5HRUxBQlMvT1U9RVhD +SEFOR0UgQURNSU5JU1RSQVRJVkUgR1JPVVAgKEZZRElCT0hGMjNTUERMVCkvQ049UkVDSVBJRU5U +Uy9DTj0yMjdERUMzNkQwOTg0NDY2OUY3OEZDOTQ4OUVCMzFERC1KRUZGUkVZIFNURQAAAAADAP0/ +5AQAAB4AIkABAAAAAwAAAEVYAAAeACNAAQAAAIEAAAAvTz1FWENIQU5HRUxBQlMvT1U9RVhDSEFO +R0UgQURNSU5JU1RSQVRJVkUgR1JPVVAgKEZZRElCT0hGMjNTUERMVCkvQ049UkVDSVBJRU5UUy9D +Tj0yMjdERUMzNkQwOTg0NDY2OUY3OEZDOTQ4OUVCMzFERC1KRUZGUkVZIFNURQAAAAAeACRAAQAA +AAMAAABFWAAAHgAlQAEAAACBAAAAL089RVhDSEFOR0VMQUJTL09VPUVYQ0hBTkdFIEFETUlOSVNU +UkFUSVZFIEdST1VQIChGWURJQk9IRjIzU1BETFQpL0NOPVJFQ0lQSUVOVFMvQ049MjI3REVDMzZE +MDk4NDQ2NjlGNzhGQzk0ODlFQjMxREQtSkVGRlJFWSBTVEUAAAAAHgAwQAEAAAARAAAASmVmZnJl +eSBTdGVkZmFzdAAAAAAeADFAAQAAABEAAABKZWZmcmV5IFN0ZWRmYXN0AAAAAB4AOEABAAAAEQAA +AEplZmZyZXkgU3RlZGZhc3QAAAAAHgA5QAEAAAARAAAASmVmZnJleSBTdGVkZmFzdAAAAAADAFlA +AAAAAAMAWkAAAAAAAwACWQAAFgADAAlZAwAAAB4ACl0BAAAAFwAAAGplc3RlZGZhQG1pY3Jvc29m +dC5jb20AAB4AC10BAAAAFwAAAGplc3RlZGZhQG1pY3Jvc29mdC5jb20AAAMAAWgBAAAAAwAHaAAA +AAADAAho8P4MAAMACWgRAAAAHgAKaAEAAAABAAAAAAAAAAsAC2gBAAAAAwAMaAAAAAADABBoAAAA +AAMAAIAIIAYAAAAAAMAAAAAAAABGAAAAAHiFAAAAAAAAAwAQgFar8ylNVdARqXwAoMkR9QoAAAAA +AKAAAAEAAAADABiAU6vzKU1V0BGpfACgyRH1CgAAAABBoAAAAAAAAAMAGYAUIAYAAAAAAMAAAAAA +AABGAAAAAAWPAADw/gwAAwAagFOr8ylNVdARqXwAoMkR9QoAAAAAQ6AAABEAAAAeABuAU6vzKU1V +0BGpfACgyRH1CgAAAABEoAAAAQAAAAEAAAAAAAAACwAcgBQgBgAAAAAAwAAAAAAAAEYAAAAAB48A +AAEAAAADAB2ACCAGAAAAAADAAAAAAAAARgAAAABwhQAAAAAAAAMAKYAIIAYAAAAAAMAAAAAAAABG +AAAAANeFAAABAAAAAwArgAggBgAAAAAAwAAAAAAAAEYAAAAAEIUAAAABAAALADuACCAGAAAAAADA +AAAAAAAARgAAAAAUhQAAAAAAAAsAPoAIIAYAAAAAAMAAAAAAAABGAAAAAIKFAAABAAAAAwBCgAgg +BgAAAAAAwAAAAAAAAEYAAAAAAYUAAAAAAAALAEiACCAGAAAAAADAAAAAAAAARgAAAAAGhQAAAAAA +AAsATYAIIAYAAAAAAMAAAAAAAABGAAAAAA6FAAAAAAAAAwBOgAggBgAAAAAAwAAAAAAAAEYAAAAA +GIUAAAAAAAADAFOACCAGAAAAAADAAAAAAAAARgAAAADrhQAACQQAAAIBwIAIIAYAAAAAAMAAAAAA +AABGAAAAACCFAAABAAAALQIAAAIBBwAAAAAAAAAFUmVwbHkISVBNLk5vdGUHTWVzc2FnZQJSRQUA +AAAAAAAAAAEAAAAAAAAAAgAAAGYAAAACAAAAAQAAAAxSZXBseSB0byBBbGwISVBNLk5vdGUHTWVz +c2FnZQJSRQUAAAAAAAAAAAEAAAAAAAAAAgAAAGcAAAADAAAAAgAAAAdGb3J3YXJkCElQTS5Ob3Rl +B01lc3NhZ2UCRlcFAAAAAAAAAAABAAAAAAAAAAIAAABoAAAABAAAAAMAAAAPUmVwbHkgdG8gRm9s +ZGVyCElQTS5Qb3N0BFBvc3QABQAAAAAAAAAAAQAAAAAAAAACAAAAbAAAAAgAAAAEAAAAA1llcwhJ +UE0uTm90ZQADWWVzAAAAAAAAAAAAAQAAAAIAAAACAAAAAQAAAP////8EAAAAAk5vCElQTS5Ob3Rl +AAJObwAAAAAAAAAAAAEAAAACAAAAAgAAAAIAAAD/////BAAAAAVNYXliZQhJUE0uTm90ZQAFTWF5 +YmUAAAAAAAAAAAABAAAAAgAAAAIAAAADAAAA/////wQBBVIAZQBwAGwAeQACUgBFAAxSAGUAcABs +AHkAIAB0AG8AIABBAGwAbAACUgBFAAdGAG8AcgB3AGEAcgBkAAJGAFcAD1IAZQBwAGwAeQAgAHQA +bwAgAEYAbwBsAGQAZQByAAADWQBlAHMAA1kAZQBzAAJOAG8AAk4AbwAFTQBhAHkAYgBlAAVNAGEA +eQBiAGUAAAAAAgEFgQggBgAAAAAAwAAAAAAAAEYBAAAANgAAAEkAbgBUAHIAYQBuAHMAaQB0AE0A +ZQBzAHMAYQBnAGUAQwBvAHIAcgBlAGwAYQB0AG8AcgAAAAAAAQAAABAAAABrmOnR1mtfT4xQuYTZ +2hsOCwAVgQggBgAAAAAAwAAAAAAAAEYBAAAAMAAAAEUAbgB0AGkAdAB5AEUAeAB0AHIAYQBjAHQA +aQBvAG4AUwB1AGMAYwBlAHMAcwAAAAEAAAAeABaBCCAGAAAAAADAAAAAAAAARgEAAAAWAAAAVABl +AGUAVgBlAHIAcwBpAG8AbgAAAAAAAQAAAAwAAAAyMDE4MTIxMC4xMQAUABeBCCAGAAAAAADAAAAA +AAAARgEAAAAyAAAAUAByAG8AcABlAHIAdAB5AEUAeABpAHMAdABlAG4AYwBlAFQAcgBhAGMAawBl +AHIAAAAAAAAEAAAAAAAAAwAagQggBgAAAAAAwAAAAAAAAEYBAAAAMgAAAEUAeABjAGgAYQBuAGcA +ZQBBAHAAcABsAGkAYwBhAHQAaQBvAG4ARgBsAGEAZwBzAAAAAAAgAAAACwAbgROP8kH0gxRBpYTu +21prC/8BAAAAKAAAAEkAcwBRAHUAbwB0AGUAZABUAGUAeAB0AEMAaABhAG4AZwBlAGQAAAAAAAAA +AgEegROP8kH0gxRBpYTu21prC/8BAAAALgAAAEgAZQBhAGQAZQByAEIAbwBkAHkARgByAGEAZwBt +AGUAbgB0AEwAaQBzAHQAAAAAAAEAAAAiAAAAAQAKAAAABAAAAAAAAAAUAAAAAAAAAAAAAAD///// +AAAAAAAAHgAfgR+k6zOoei5Cvnt54amOVLMBAAAAOAAAAEMAbwBuAHYAZQByAHMAYQB0AGkAbwBu +AEkAbgBkAGUAeABUAHIAYQBjAGsAaQBuAGcARQB4AAAAAQAAAJcAAABJST1bQ0lEPWQ3YjhjNTFi +LTVhNDgtODk0Ni04Y2M5LTQ5ZTg3ZDQ3M2JlNDtJRFhIRUFEPUQ0OTQ4MkMzOTc7SURYQ09VTlQ9 +MV07VEZSPU5vdEZvcmtpbmc7VmVyc2lvbj1WZXJzaW9uIDE1LjIwIChCdWlsZCAxNDQ2LjApLCBT +dGFnZT1INDtVUD0xMDtEUD0xQzUAAB4AK4EIIAYAAAAAAMAAAAAAAABGAQAAAFIAAABFAG4AdABp +AHQAeQBFAHgAdAByAGEAYwB0AGkAbwBuAFMAZQByAHYAaQBjAGUARABpAGEAZwBuAG8AcwB0AGkA +YwBDAG8AbgB0AGUAeAB0AAAAAAABAAAAMgMAAFsiRXh0cmFjdGlvbklkIiwiYzYyNjI2YjQtZDIw +OC00Y2NhLWFkZjUtMDI4ODFlM2EzZTE0IiwiVGVlRW5naW5lVmVyc2lvbiIsIjUyLjAuMCIsIkJ1 +aWxkTnVtYmVyIiwiMjAxODEyMTAuMTEiLCJDaGFuZ2VzZXROdW1iZXIiLCIyMDE4MTIxMC4xMSIs +IkxvY2FsZSIsImVuLVVTIiwiTWVzc2FnZUlkIiwiXHUwMDNjRE01UFIyMU1CMDgyOERBMkI4Qzg4 +MDQ4QkMwM0VGRkE2Q0ZBMjBARE01UFIyMU1CMDgyOC5uYW1wcmQyMS5wcm9kLm91dGxvb2suY29t +XHUwMDNlIiwiUmVmZXJlbmNlVGltZSIsIjIwMTgtMTItMTVUMTU6MDc6MDAuMDAwMDAwMFoiLCJG +bGlnaHRzIiwiUWFzQjJGbGlnaHQ7VEVFUmVwbHlXaXRoU2hpcFdXO1RFRU0ySFBheWxvYWRFbmFi +bGVkRmxpZ2h0O1RFRUNvbXBsaWFudEluZmVyZW5jZXNTaG9ydGN1dDtURUVJbmZlcmVuY2VzRm9y +TTJIO1RFRUluZmVyZW5jZXNWMkZvck0ySDtURUVJbmZlcmVuY2VzRm9yU3Vic2NyaXB0aW9uO1RF +RUVuYWJsZVRlcm1GcmVxdWVuY3k7VEVFSW1wb3J0YW50TWFpbDtURUVIaWdobGlnaHRzQ0Y7dGVl +UmVxdWVzdHNQQU1vZGVsRmxpZ2h0O1RFRVJlcGx5V2l0aENvdmVyYWdlRmlsdGVyRmxpZ2h0O1RF +RVJlcGx5V2l0aENvbXBsaWFudE0yUTtURUVTbWFydFJlcGx5RW5hYmxlZEZsaWdodDtURUVTZXJ2 +aWNlQXBwb2ludG1lbnRPZmZCb3hFeHRyYWN0aW9uO1Fhc1Rlc3RDb21wbGlhbnRURUVGbGlnaHQ7 +UWFzVGVzdEtQRU9mZkJveEIyIiwiU3RhcnRUaW1lIiwiMjAxOC0xMi0xNVQxNTowNzoxOS43MTU1 +MTIxWiIsIkVuZFRpbWUiLCIyMDE4LTEyLTE1VDE1OjA3OjE5Ljc5MjU3NjZaIl0AAAALAC6BE4/y +QfSDFEGlhO7bWmsL/wEAAAAcAAAASABhAHMAUQB1AG8AdABlAGQAVABlAHgAdAAAAAAAAAAeADSB +CCAGAAAAAADAAAAAAAAARgEAAAAeAAAARQBuAHQAaQB0AHkARABvAGMAdQBtAGUAbgB0AAAAAAAB +AAAAvzsAAFt7DQogICJAY29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm9yZyIsDQogICJ0eXBlIjog +IkV4dHJhY3RMYW5ndWFnZSIsDQogICJlbnRpdGllcyI6IFsNCiAgew0KICAgICJAdHlwZSI6ICJF +eHRyYWN0TGFuZ3VhZ2UiLA0KICAgICJAY29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm1pY3Jvc29m +dC5jb20iLA0KICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJMYW5ndWFnZSI6IHsN +CiAgICAgICJAdHlwZSI6ICJMYW5ndWFnZSIsDQogICAgICAiTG9jYWxlIjogImVuLVVTIiwNCiAg +ICAgICJuYW1lIjogIkVuZ2xpc2ggKFVuaXRlZCBTdGF0ZXMpIg0KICAgIH0sDQogICAgIkBzb3Vy +Y2UiOiAiRXhjaGFuZ2UiLA0KICAgICJMYW5ndWFnZVNjb3JlcyI6IHsNCiAgICAgICJFbmdsaXNo +IjogOTkuMTM1NDQ0Ng0KICAgIH0sDQogICAgIkBFbnRpdHlJZCI6ICJlZjJhZTFmZS0zNTRlLTQw +MTMtYjEyYy1hNWE3ZDAwYjcwZmMiLA0KICAgICJAY29ycmVsYXRpb25UcmFpbCI6ICJBc3NldElk +PWI1MGY5ZDY3LTcwNWEtNGJjNy05YmNkLTYyZmJjYzg2MDRhMTtFeHRyYWN0aW9uSWQ9YzYyNjI2 +YjQtZDIwOC00Y2NhLWFkZjUtMDI4ODFlM2EzZTE0O0VudGl0eUlkPWVmMmFlMWZlLTM1NGUtNDAx +My1iMTJjLWE1YTdkMDBiNzBmYyIsDQogICAgIkBleHRyYWN0aW9uVGltZVV0YyI6ICIyMDE4LTEy +LTE1VDE1OjA3OjE5Ljc5MjU3NjZaIg0KICB9DQpdDQp9LHsNCiAgIkBjb250ZXh0IjogImh0dHA6 +Ly9zY2hlbWEub3JnIiwNCiAgInR5cGUiOiAiU2NoZWR1bGVBY3Rpb24iLA0KICAiZW50aXRpZXMi +OiBbDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmciLA0KICAgICJAb3V0 +cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6ICIyLjEiLA0KICAg +ICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAiVEVFLDUyLjAuMCwy +MDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Db21taXRtZW50VEZMVSw1Mi4wLjAsMjAxODEy +MDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFjdGlvblRydXN0TGV2ZWwiOiAi +VHJ1c3RlZCIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUiOiAiMC45ODg3IiwNCiAgICAi +ZGVzY3JpcHRpb24iOiAiQ2hhbmdlIHRoZSByYWRpbyBhbmQgSSdsbCB0dXJuIHRoZSBsaWdodHMg +ZG93biBkaW1tZXIiLA0KICAgICJkZXNjcmlwdGlvbi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiQ29t +bWl0bWVudCIsDQogICAgInNjaGVkdWxlZFRpbWUiOiAiIiwNCiAgICAic2NoZWR1bGVkVGltZS90 +aW1lem9uZSI6ICJFYXN0ZXJuIFN0YW5kYXJkIFRpbWUiLA0KICAgICJzY2hlZHVsZWRUaW1lL3Jl +bGF0aXZlIjogIiIsDQogICAgInNjaGVkdWxlZFRpbWUvaW1wcmVjaXNlRmxhZyI6ICIiLA0KICAg +ICJAYWJzb2x1dGVPZmZzZXRQbGFpblRleHQiOiAiMCIsDQogICAgIkBzcGFuIjogIjUzIiwNCiAg +ICAiQEVudGl0eUlkIjogIjYzOTljMDFiLWUzZjQtNGY4Ni1iYTMwLWY0OTA1NDFhZjE4YyIsDQog +ICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1YS00YmM3LTliY2Qt +NjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2EtYWRmNS0wMjg4MWUz +YTNlMTQ7RW50aXR5SWQ9NjM5OWMwMWItZTNmNC00Zjg2LWJhMzAtZjQ5MDU0MWFmMThjIiwNCiAg +ICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTkuNzkyNTc2NloiDQog +IH0NCl0NCn0sew0KICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmciLA0KICAidHlwZSI6 +ICJLZXlQaHJhc2VFeHRyYWN0aW9uIiwNCiAgImVudGl0aWVzIjogWw0KICB7DQogICAgIkBvdXRw +dXRWZXJzaW9uIjogIjIuMCIsDQogICAgIkBmb3JtYXR0ZXIiOiAiVGVlS3BlQm9uZENicEJhc2U2 +NCIsDQogICAgIkBzY2hlbWEiOiAiTWljcm9zb2Z0LkV4Y2hhbmdlLlJlbGV2YW5jZS5UZWVLcGVC +b25kUmVzcG9uc2UuVGVlS3BlLlRlZUtwZVJlc3BvbnNlIiwNCiAgICAia2V5UGhyYXNlcyI6ICJR +MElCQU0wVUVnb2JDWElBYVFCakFHZ0FJQUIwQUdVQWVBQjBBTWNLVWRSZ1FNMFVFQWNFQWdBQUFF +QU1BQUNBUHhBQUFJQS9EZ0FBQUVBQUNXTUFhQUJ5QUdrQWN3QjBBRzBBWVFCekFNY0tJS2dUdjgw +VUVBY2FNZ0FBSkVJQ0FBQ0FQeElBQUdCQkZxbEJKVDBVQUlDdFF4Z0FBSUEvR2dBQW9FQWNxQlJz +UEI0bHlUSkRJRW5tQXo4aUFBQUFRQ1JUM2J3N0p0czJKME1vczduMlBqUUFBR0JCTmt2VXJqNDgy +N2FoUVQ2YmJ2dytSQ1ZKbmtGR2hSVDNQaXdsU1lKQUxnQUFBRUF3dDIwYlFFcVNKR2xBVEFBQUFF +Qk90MjBiUUFBU2N3QndBSElBYVFCdUFHY0FkQUJwQUcwQVpRQWdBR1lBWlFCbEFHd0FhUUJ1QUdj +QXh3cUl0Z3BBelJRUUJ4d3lBQUFrUWdJQUFBQkFFZ0FBb0VBV3FCVHNQQlFBZ0sxREdBQUFBRDhh +QUFBQVFSeFQzYnc4SHMzTU9FTWdMRllJUHlJQUFNQkJKUCtsalQwbU16TWdReWcwWU93K05BQUFv +RUEya01INVBUZ0FBSUEvT2d6T3h6dzhNek9yUVQ2WW5nVS9RQUFBQUVCQ0RNNUhQVVROekpSQlJ1 +OUY2RDR1QUFEQVFEQUFBTUJBVEFBQXdFQk9BQURBUUFBSmN3QjBBSElBWVFCdUFHY0FaUUJ5QUhN +QXh3cXIyNzFBelJRUUJ4d3lBQUFrUWdJQUFJQS9FZ0FBQUVBV1U5MjhPeFFBZ0sxREdBQUFnRDhh +QUFDQVFSeFQzVHc5SGdBQW4wSWc3cHBxUGlJQUFFdERKSUhERlQ4bUFFQ0ZReWhubkVRL05BQUFB +RUEyRE01SFBUZ0FBQUJBT2d6T1J6MDhBQUFRUVQ3T3gyQStRQUFBd0VGQ2lkb1ZQMFFBQVBoQlJw +eVBRVDh1QUFDQVFEQUFBTEJBVEFBQWdFQk9BQUN3UUFBRllRQnpBSEFBWlFCdUFNY0tMa0Jwd00w +VUVBY2dNZ0FBSkVJQ0FBQ0FQeElBQUlBL0ZsUGRQRHNVQUlDdFF4Z0FBSUEvR2dBQThFRWNmZyt4 +UFI0QUFQQkJJSDRQc1QwaUFBQ2VReVF6SVdrL0pnQUFua01vTXlGcFB6UUFBSUEvTmd6T3h6dzRB +QUNBUURvTXpzYzlQQUFBZ0VBK0RNN0hQVUFBQUJCQ1FzN0hZRDlFQUFBUVFrYk94MkEvS2dBQVFF +QXNBQUJBUUM0QUFLQkFNQUFBb0VCSUFBQkFRRW9BQUVCQVRBQUFvRUJPQUFDZ1FBQUVjd0J1QUc4 +QWR3REhDbUh3YjhETkZCQUhHeklBQUNSQ0FnQUFnRDhTQUFBQVFCWlQzYnc3RkFDQXJVTWFBQUF3 +UWh3cDJBRStIZ0FBRmtNZ1hsUGRQaUlBQUxSQ0pKL0xoRDRtQUFCRVF5aDBtUkEvTkFBQUFFQTJE +TTVIUFRnQUFLQkFPcERCK1QwOEFBQ0lRVDd0U3RRK1FBQUFNRUZDcVYySlBrUUFBTGhCUmhtY0R6 +OHFBQURBUUN3QUFPQkFTQUFBd0VCS0FBRGdRQUFLWndCaEFIUUFiQUJwQUc0QVlnQjFBSElBWndE +SENzWjVhOERORkJBSElESUFBQ1JDQWdBQWdEOFNBQUNBUHhaVDNUdzdGQUNBclVNWUFBQ0FQeG9B +QUVoQ0hPbU1FejRlQUFCSVFpRHBqQk0rSWdBQWxFTWs2RjlhUHlZQUFKUkRLT2hmV2o4MEFBQ0FQ +ellNenNjOE9BQUF3RUE2aWRvVlBqd0FBTUJBUG9uYUZUNUFBQUFJUWtMdFNsUS9SQUFBQ0VKRzdV +cFVQeW9BQUtCQUxBQUFvRUF1QUFEQVFEQUFBTUJBU0FBQW9FQktBQUNnUUV3QUFNQkFUZ0FBd0VB +QUJuTUFiQUJ2QUhBQVpRQnpBTWNLUVBsUHdNMFVFQWNiTWdBQUpFSUNBQUNBUHhJQUFBQkFGbFBk +dkRzVUFJQ3RReG9BQUloQ0hDbXJTRDRlQUlBWFF5RDJpZDgrSWdBQTNrSWs3c2VqUGlZQWdFSkRL +Q2grRHo4MEFBQUFRRFlNemtjOU9BQUE0RUE2UzlRdVBqd0FBSVJCUG4wTXpqNUFBQUJnUVVKTDFL +NCtSQUFBdkVGR1Vic1NQeW9BQU1CQUxBQUFDRUZJQUFEQVFFb0FBQWhCQUFsbUFHa0FjZ0JsQUhB +QWJBQmhBR01BWlFESEN2SFhqTURORkJBSEh6SUFBQ1JDQWdBQWdEOFNBQUNBUHhaVDNUdzdGQUNB +clVNYUFBQ2tRaHlUKzNFK0hnQUFwRUlnay90eFBpSUFBSVJESkQ3RVFqOG1BQUNFUXlnK3hFSS9O +QUFBZ0Q4MkRNN0hQRGdBQUJCQk9zN0hZRDQ4QUFBUVFUN094MkErUUFBQStFRkNuSTlCUDBRQUFQ +aEJScHlQUVQ4cUFBQ0FRQ3dBQUlCQUxnQUFvRUF3QUFDZ1FFZ0FBSUJBU2dBQWdFQk1BQUNnUUU0 +QUFLQkFBQkIwQUdFQWFBQnZBR1VBSUFCekFHc0FhUUFnQUdNQWFBQmhBR3dBWlFCMEFNY0s3V3FW +d00wVUVBY2NNZ0FBSkVJQ0FBQkFRQklBQUlBL0Z2K2xEVHdVQUlDdFF4aXJxcW8rR2dBQXFrSWM4 +OVY2UGg0QUFLcENJUFBWZWo0aUFJQ0JReVRyRXo4L0pnQ0FnVU1vNnhNL1B6UUFBSUEvTmd6T3h6 +dzRBQUFRUVRyT3gyQStQQUFBRUVFK3pzZGdQa0FBQVBoQlFweVBRVDlFQUFENFFVYWNqMEUvS2dB +QTRFQXNBQURnUUVnQUFPQkFTZ0FBNEVBQUVtWUFZUUJ6QUhRQUlBQjBBR0VBYkFCckFHa0FiZ0Ju +QUNBQWJBQnZBSFlBWlFCeUFNY0tIVEdYd00wVUVBY2ZNZ0FBSkVJQ0FBQkFRQklBQUlBL0Z2K2xE +VHdVQUlDdFF4b0FBTFJDSEovTGhENGVBQUMwUWlDZnk0UStJZ0FBZmtNa21XTTdQeVlBQUg1REtK +bGpPejgwQUFDQVB6WU16c2M4T0FBQUlFRTZrTUY1UGp3QUFDQkJQcERCZVQ1QUFBRHdRVUlzVVRz +L1JBQUE4RUZHTEZFN1B5b0FBQUJBTEFBQUFFQXVBQUNnUURBQUFLQkFTQUFBQUVCS0FBQUFRRXdB +QUtCQVRnQUFvRUFBRVhNQWJBQnZBSGNBSUFCaUFIVUFjZ0J1QUdrQWJnQm5BQ0FBZHdCdkFHOEFa +QURIQ3UxcWxjRE5GQkFIR3pJQUFDUkNBZ0FBUUVBU0FBQ0FQeGIvcFEwOEZBQ0FyVU1hQUFDK1Fo +eEVMSXcrSGdBQXZrSWdSQ3lNUGlJQUFIbERKRWF6Tno4bUFBQjVReWhHc3pjL05BQUFnRDgyRE03 +SFBEZ0FBQ0JCT3BEQmVUNDhBQUFnUVQ2UXdYaytRQUFBOEVGQ0xGRTdQMFFBQVBCQlJpeFJPejhx +QUFEZ1FDd0FBT0JBU0FBQTRFQktBQURnUUFBT2R3QnBBR3dBWkFCbEFITUFkQUFnQUdRQWNnQmxB +R0VBYlFCekFNY0tyMkNLd00wVUVBY2ZNZ0FBSkVJQ0FBQUFRQklBQUlBL0ZsUGR2RHNVQUlDdFF4 +b0FBTXhDSEY2QWxqNGVBQURNUWlCZWdKWStJZ0FBYzBNa0ZrWXpQeVlBQUhOREtCWkdNejgwQUFD +QVB6WU16c2M4T0FBQU1FRTZxVjJKUGp3QUFEQkJQcWxkaVQ1QUFBRG9RVUs3RWpVL1JBQUE2RUZH +dXhJMVB5b0FBSUJBTEFBQWdFQXVBQURBUURBQUFNQkFTQUFBZ0VCS0FBQ0FRRXdBQU1CQVRnQUF3 +RUFBQlhJQVlRQmtBR2tBYndESENwVS9qOERORkJBSEh6SUFBQ1JDQWdBQWdEOFNBQUNBUHhaVDNU +dzdGQUNBclVNYUFBQUFReHhUM2J3K0hnQUFBRU1nVTkyOFBpSUFBRnBESkhuVUlEOG1BQUJhUXlo +NTFDQS9OQUFBZ0Q4MkRNN0hQRGdBQUdCQk9rdlVyajQ4QUFCZ1FUNUwxSzQrUUFBQTBFRkNhbGNp +UDBRQUFOQkJSbXBYSWo4cUFBQUFRQ3dBQUFCQUxnQUFBRUV3QUFBQVFVZ0FBQUJBU2dBQUFFQk1B +QUFBUVU0QUFBQkJBQVpzQUdrQVp3Qm9BSFFBY3dESEN0cGxnOERORkJBSEh6SUFBQ1JDQWdBQWdE +OFNBQUNBUHhaVDNUdzdGQUNBclVNYUFBQUdReHl6dDhVK0hnQUFCa01nczdmRlBpSUFBRlJESkVs +bkhEOG1BQUJVUXloSlp4dy9OQUFBZ0Q4MkRNN0hQRGdBQUdCQk9rdlVyajQ4QUFCZ1FUNUwxSzQr +UUFBQTBFRkNhbGNpUDBRQUFOQkJSbXBYSWo4cUFBQUFRU3dBQUFCQkxnQUFBRUF3QUFBQVFFZ0FB +QUJCU2dBQUFFRk1BQUFBUUU0QUFBQkFBQVpzQUc4QWRnQmxBSElBY3dESENpY2lhc0RORkJBSEh6 +SUFBQ1JDQWdBQWdEOFNBQUNBUHhaVDNUdzdGQUNBclVNYUFBQVRReHd1NXRnK0hnQUFFME1nTHVi +WVBpSUFBRWRESkF6UUVqOG1BQUJIUXlnTTBCSS9OQUFBZ0Q4MkRNN0hQRGdBQUlCQk9nek94ejQ4 +QUFDQVFUNE16c2MrUUFBQXdFRkNpZG9WUDBRQUFNQkJSb25hRlQ4cUFBQ0FRQ3dBQUlCQUxnQUFR +RUF3QUFCQVFFZ0FBSUJBU2dBQWdFQk1BQUJBUUU0QUFFQkFBQVppQUd3QWJ3QjNBR2tBYmdESENy +NHYzTURORkJBSEhESUFBQ1JDQWdBQWdEOFNBQUNBUHhaVDNUdzdGQUNBclVNWUFBQ0FQeG9BQUN0 +REhLMVAvRDRlQUFBclF5Q3RUL3crSWdBQUwwTWtUQnNCUHlZQUFDOURLRXdiQVQ4MEFBQ0FQellN +enNjOE9BQUFtRUU2cjBUdFBqd0FBSmhCUHE5RTdUNUFBQUNvUVVJNEh3TS9SQUFBcUVGR09COERQ +eTRBQUNCQk1BQUFJRUZNQUFBZ1FVNEFBQ0JCQUJSM0FHa0FiQUJrQUNBQWNnQmxBSE1BZEFCc0FH +VUFjd0J6QUNBQWR3QnBBRzRBZEFCbEFISUF4d3BkTWdMQnpSUVFCeDh5QUFBa1FnSUFBRUJBRWdB +QWdEOFcvNlVOUEJRQWdLMURHZ0FBTVVNY0I1VUNQeDRBQURGRElBZVZBajhpQUFBblF5VERhUFkr +SmdBQUowTW93MmoyUGpRQUFJQS9OZ3pPeHp3NEFBQ1lRVHF2Uk8wK1BBQUFtRUUrcjBUdFBrQUFB +S2hCUWpnZkF6OUVBQUNvUVVZNEh3TS9LZ0FBd0VBc0FBREFRQzRBQUFCQU1BQUFBRUJJQUFEQVFF +b0FBTUJBVEFBQUFFQk9BQUFBUUFBRmJnQmxBR0VBZEFCb0FNY0s4dS9ud00wVUVBY2NNZ0FBSkVJ +Q0FBQ0FQeElBQUlBL0ZsUGRQRHNVQUlDdFF4Z0FBSUEvR2dBQVIwTWNETkFTUHg0QUFFZERJQXpR +RWo4aUFBQVRReVF1NXRnK0pnQUFFME1vTHViWVBqUUFBSUEvTmd6T3h6dzRBQUN3UVRxcFhRay9Q +QUFBc0VFK3FWMEpQMEFBQUpCQlFzN0g0RDVFQUFDUVFVYk94K0ErTGdBQUFFRXdBQUFBUVV3QUFB +QkJUZ0FBQUVFQUNXMEFhUUJ6QUhRQWJBQmxBSFFBYndCbEFNY0tYblBXd00wVUVBY2ZNZ0FBSkVJ +Q0FBQ0FQeElBQUlBL0ZsUGRQRHNVQUlDdFF4b0FBRWxESE1aSkZEOGVBQUJKUXlER1NSUS9JZ0FB +RVVNa3VQTFZQaVlBQUJGREtMankxVDQwQUFDQVB6WU16c2M4T0FBQXNFRTZxVjBKUHp3QUFMQkJQ +cWxkQ1Q5QUFBQ1FRVUxPeCtBK1JBQUFrRUZHenNmZ1Bpb0FBQUJBTEFBQUFFQXVBQURBUURBQUFN +QkFTQUFBQUVCS0FBQUFRRXdBQU1CQVRnQUF3RUFBRkhNQVlRQnVBR2NBSUFCakFHZ0FjZ0JwQUhN +QWRBQnRBR0VBY3dBZ0FITUFid0J1QUdjQWN3REhDbEFyQThITkZCQUhIRElBQUNSQ0FnQUFRRUFT +QUFDQVB4Yi9wUTA4RkFDQXJVTVlxNm9xUHhvQUFGNURITzdISXo4ZUFBQmVReUR1eHlNL0lnQUE5 +RUlrOHdLMFBpWUFBUFJDS1BNQ3RENDBBQUNBUHpZTXpzYzhPQUFBeUVFNitoZ2NQendBQU1oQlB2 +b1lIRDlBQUFCd1FVSXNVYnMrUkFBQWNFRkdMRkc3UGk0QUFJQkFNQUFBZ0VCTUFBQ0FRRTRBQUlC +QUFBWm1BR2tBWlFCc0FHUUFjd0RIQ2lmUjFzRE5GQkFISHpJQUFDUkNBZ0FBZ0Q4U0FBQ0FQeFpU +M1R3N0ZBQ0FyVU1hQUFCblF4eTJheW8vSGdBQVowTWd0bXNxUHlJQUFPWkNKTm11cVQ0bUFBRG1R +aWpacnFrK05BQUFnRDgyRE03SFBEZ0FBTkJCT21wWElqODhBQURRUVQ1cVZ5SS9RQUFBWUVGQ1M5 +U3VQa1FBQUdCQlJrdlVyajRxQUFBQVFDd0FBQUJBTGdBQWdFQXdBQUNBUUVnQUFBQkFTZ0FBQUVC +TUFBQ0FRRTRBQUlCQUFBWm9BR1VBWVFCeUFIUUFjd0RIQ2lmUjFzRE5GQkFISHpJQUFDUkNBZ0FB +Z0Q4U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1hQUFCOFF4emU2VGsvSGdBQWZFTWczdWs1UHlJQUFMeENK +SW15aWo0bUFBQzhRaWlKc29vK05BQUFnRDgyRE03SFBEZ0FBT2hCT3JzU05UODhBQURvUVQ2N0Vq +VS9RQUFBTUVGQ3FWMkpQa1FBQURCQlJxbGRpVDRxQUFBQVFDd0FBQUJBTGdBQWdFQXdBQUNBUUVn +QUFBQkFTZ0FBQUVCTUFBQ0FRRTRBQUlCQUFBZGpBR2dBYVFCdEFHNEFaUUI1QU1jS3k0Zlp3TTBV +RUFjZk1nQUFKRUlDQUFDQVB4SUFBSUEvRmxQZFBEc1VBSUN0UXhvQUFIOURISFlnUEQ4ZUFBQi9R +eUIySUR3L0lnQUF0a0lrV1VXR1BpWUFBTFpDS0ZsRmhqNDBBQUNBUHpZTXpzYzhPQUFBNkVFNnV4 +STFQendBQU9oQlByc1NOVDlBQUFBd1FVS3BYWWsrUkFBQU1FRkdxVjJKUGlvQUFLQkFMQUFBb0VB +dUFBQ0FQekFBQUlBL1NBQUFvRUJLQUFDZ1FFd0FBSUEvVGdBQWdEOEFDMjRBWlFCNEFIUUFJQUIz +QUdrQWJnQjBBR1VBY2dESENyek85c0RORkJBSEd6SUFBQ1JDQWdBQUFFQVNBQUNBUHhaVDNidzdG +QUNBclVNYUFBQ0hReHh1TVVjL0hnQUFoME1nYmpGSFB5SUFBSlpDSkY1VFhUNG1BQUNXUWloZVUx +MCtOQUFBZ0Q4MkRNN0hQRGdBQVBoQk9weVBRVDg4QUFENFFUNmNqMEUvUUFBQUVFRkN6c2RnUGtR +QUFCQkJSczdIWUQ0cUFBQ0FRQ3dBQUlCQVNBQUFnRUJLQUFDQVFBQUVaZ0JwQUhJQVpRREhDcUJC +MzhETkZCQUhIeklBQUNSQ0FnQUFnRDhTQUFDQVB4WlQzVHc3RkFDQXJVTWFBQUNVUXh6b1gxby9I +Z0FBbEVNZzZGOWFQeUlBQUVoQ0pPbU1FejRtQUFCSVFpanBqQk0rTkFBQWdEODJETTdIUERnQUFB +eENPbDZKV2o4OEFBQU1RajVlaVZvL1FBQUFvRUJDa01INVBVUUFBS0JBUnBEQitUMHFBQUFBUUN3 +QUFBQkFMZ0FBSUVFd0FBQWdRVWdBQUFCQVNnQUFBRUJNQUFBZ1FVNEFBQ0JCQUE1aUFIVUFjZ0J1 +QUdrQWJnQm5BQ0FBWlFCdEFHSUFaUUJ5QUhNQXh3b0c4UVBCelJRUUJ4c3lBQUFrUWdJQUFBQkFF +Z0FBZ0Q4V1U5MjhPeFFBZ0sxREdnQ0FxVU1jRlJsNlB4NEFnS2xESUJVWmVqOGlBQURBUUNUL3BZ +MDhKZ0FBd0VBby82V05QRFFBQUlBL05nek94enc0QUFBY1Fqb2ZnM00vUEFBQUhFSStINE56UDBB +QUFJQS9RZ3pPeHp4RUFBQ0FQMFlNenNjOEtnQUFJRUVzQUFBZ1FVZ0FBQ0JCU2dBQUlFRUFBQT09 +IiwNCiAgICAiQHR5cGUiOiAiS2V5UGhyYXNlRXh0cmFjdGlvbiIsDQogICAgIkBjb250ZXh0Ijog +Imh0dHA6Ly9zY2hlbWEubWljcm9zb2Z0LmNvbSIsDQogICAgIkBFbnRpdHlJZCI6ICI1MDNiMDhi +Ny1hY2NlLTQwNDYtYjQ4OC1lYmUyOGM1ZDU2M2QiLA0KICAgICJAY29ycmVsYXRpb25UcmFpbCI6 +ICJBc3NldElkPWI1MGY5ZDY3LTcwNWEtNGJjNy05YmNkLTYyZmJjYzg2MDRhMTtFeHRyYWN0aW9u +SWQ9YzYyNjI2YjQtZDIwOC00Y2NhLWFkZjUtMDI4ODFlM2EzZTE0O0VudGl0eUlkPTUwM2IwOGI3 +LWFjY2UtNDA0Ni1iNDg4LWViZTI4YzVkNTYzZCIsDQogICAgIkBleHRyYWN0aW9uVGltZVV0YyI6 +ICIyMDE4LTEyLTE1VDE1OjA3OjE5Ljc5MjU3NjZaIg0KICB9DQpdDQp9LHsNCiAgIkBjb250ZXh0 +IjogImh0dHA6Ly9zY2hlbWEub3JnIiwNCiAgInR5cGUiOiAiRm9sbG93VXBTY2hlZHVsZVJlcGx5 +UmVxdWVzdCIsDQogICJlbnRpdGllcyI6IFsNCiAgew0KICAgICJAY29udGV4dCI6ICJodHRwOi8v +c2NoZW1hLm9yZyIsDQogICAgIkBvdXRwdXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkBzY2hlbWFP +cmdWZXJzaW9uIjogIjIuMSIsDQogICAgIkB0eXBlIjogIlNjaGVkdWxlQWN0aW9uIiwNCiAgICAi +QHNvdXJjZSI6ICJURUUsNTIuMC4wLDIwMTgxMjAzLjExLDIwMTgxMjAzLjExO2VuLVVTLkZvbGxv +d1VwRm9yUmVxdWVzdFJSLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMSIsDQogICAgIkBl +bnRpdHlFeHRyYWN0aW9uVHJ1c3RMZXZlbCI6ICJVbmtub3duIiwNCiAgICAiQHNvdXJjZUNvbmZp +ZGVuY2VTY29yZSI6ICIwLjUxMTM2MTY1ODg2NjIiLA0KICAgICJkZXNjcmlwdGlvbiI6ICJXaGF0 +IGEgQ2hyaXN0bWFzIHRvIHJlbWVtYmVyIiwNCiAgICAiZGVzY3JpcHRpb24vc2NoZWR1bGVBY3Rp +b25UeXBlIjogIkZvbGxvd1VwIiwNCiAgICAiQGFic29sdXRlT2Zmc2V0UGxhaW5UZXh0IjogIjEz +MSIsDQogICAgIkBzcGFuIjogIjQiLA0KICAgICJARW50aXR5SWQiOiAiNjZkZmExNzMtYTFiYi00 +YjllLTg4NmItZmM1ODI3Mzc4NjkyIiwNCiAgICAiQGNvcnJlbGF0aW9uVHJhaWwiOiAiQXNzZXRJ +ZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJjZC02MmZiY2M4NjA0YTE7RXh0cmFjdGlvbklkPWM2MjYy +NmI0LWQyMDgtNGNjYS1hZGY1LTAyODgxZTNhM2UxNDtFbnRpdHlJZD02NmRmYTE3My1hMWJiLTRi +OWUtODg2Yi1mYzU4MjczNzg2OTIiLA0KICAgICJAZXh0cmFjdGlvblRpbWVVdGMiOiAiMjAxOC0x +Mi0xNVQxNTowNzoxOS43OTI1NzY2WiINCiAgfSwNCiAgew0KICAgICJAY29udGV4dCI6ICJodHRw +Oi8vc2NoZW1hLm9yZyIsDQogICAgIkBvdXRwdXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkBzY2hl +bWFPcmdWZXJzaW9uIjogIjIuMSIsDQogICAgIkB0eXBlIjogIlNjaGVkdWxlQWN0aW9uIiwNCiAg +ICAiQHNvdXJjZSI6ICJURUUsNTIuMC4wLDIwMTgxMjAzLjExLDIwMTgxMjAzLjExO2VuLVVTLkZv +bGxvd1VwRm9yUmVxdWVzdFJSLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMSIsDQogICAg +IkBlbnRpdHlFeHRyYWN0aW9uVHJ1c3RMZXZlbCI6ICJVbmtub3duIiwNCiAgICAiQHNvdXJjZUNv +bmZpZGVuY2VTY29yZSI6ICIwLjUxMTM2MTY1ODg2NjIiLA0KICAgICJkZXNjcmlwdGlvbiI6ICJX +aGF0IGEgQ2hyaXN0bWFzIHRvIHJlbWVtYmVyIiwNCiAgICAiZGVzY3JpcHRpb24vc2NoZWR1bGVB +Y3Rpb25UeXBlIjogIkZvbGxvd1VwIiwNCiAgICAiQGFic29sdXRlT2Zmc2V0UGxhaW5UZXh0Ijog +IjcxOSIsDQogICAgIkBzcGFuIjogIjQiLA0KICAgICJARW50aXR5SWQiOiAiYWJhNmI4ZTYtZjFh +YS00MWM1LThmMTItNjI3YWU2NDljMTQyIiwNCiAgICAiQGNvcnJlbGF0aW9uVHJhaWwiOiAiQXNz +ZXRJZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJjZC02MmZiY2M4NjA0YTE7RXh0cmFjdGlvbklkPWM2 +MjYyNmI0LWQyMDgtNGNjYS1hZGY1LTAyODgxZTNhM2UxNDtFbnRpdHlJZD1hYmE2YjhlNi1mMWFh +LTQxYzUtOGYxMi02MjdhZTY0OWMxNDIiLA0KICAgICJAZXh0cmFjdGlvblRpbWVVdGMiOiAiMjAx +OC0xMi0xNVQxNTowNzoxOS43OTI1NzY2WiINCiAgfSwNCiAgew0KICAgICJAY29udGV4dCI6ICJo +dHRwOi8vc2NoZW1hLm9yZyIsDQogICAgIkBvdXRwdXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkBz +Y2hlbWFPcmdWZXJzaW9uIjogIjIuMSIsDQogICAgIkB0eXBlIjogIlNjaGVkdWxlQWN0aW9uIiwN +CiAgICAiQHNvdXJjZSI6ICJURUUsNTIuMC4wLDIwMTgxMjAzLjExLDIwMTgxMjAzLjExO2VuLVVT +LkZvbGxvd1VwRm9yUmVxdWVzdFJSLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMSIsDQog +ICAgIkBlbnRpdHlFeHRyYWN0aW9uVHJ1c3RMZXZlbCI6ICJVbmtub3duIiwNCiAgICAiQHNvdXJj +ZUNvbmZpZGVuY2VTY29yZSI6ICIwLjYzMDMzMjAzMjgxMzgiLA0KICAgICJkZXNjcmlwdGlvbiI6 +ICInTmVhdGggdGhlIG1pc3RsZXRvZSB5b3Uga2lzc2VkIG1lIHdhcm0gYW5kIHRlbmRlciIsDQog +ICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJGb2xsb3dVcCIsDQogICAgIkBh +YnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICIxMDQxIiwNCiAgICAiQHNwYW4iOiAiMSIsDQogICAg +IkBFbnRpdHlJZCI6ICIzNzkwMDhjYS0xMGE1LTRhMjUtOTgyMS1kNjU0Y2JiOTE5MGYiLA0KICAg +ICJAY29ycmVsYXRpb25UcmFpbCI6ICJBc3NldElkPWI1MGY5ZDY3LTcwNWEtNGJjNy05YmNkLTYy +ZmJjYzg2MDRhMTtFeHRyYWN0aW9uSWQ9YzYyNjI2YjQtZDIwOC00Y2NhLWFkZjUtMDI4ODFlM2Ez +ZTE0O0VudGl0eUlkPTM3OTAwOGNhLTEwYTUtNGEyNS05ODIxLWQ2NTRjYmI5MTkwZiIsDQogICAg +IkBleHRyYWN0aW9uVGltZVV0YyI6ICIyMDE4LTEyLTE1VDE1OjA3OjE5Ljc5MjU3NjZaIg0KICB9 +LA0KICB7DQogICAgIkBjb250ZXh0IjogImh0dHA6Ly9zY2hlbWEub3JnIiwNCiAgICAiQG91dHB1 +dFZlcnNpb24iOiAiMS4wIiwNCiAgICAiQHNjaGVtYU9yZ1ZlcnNpb24iOiAiMi4xIiwNCiAgICAi +QHR5cGUiOiAiU2NoZWR1bGVBY3Rpb24iLA0KICAgICJAc291cmNlIjogIlRFRSw1Mi4wLjAsMjAx +ODEyMDMuMTEsMjAxODEyMDMuMTE7ZW4tVVMuRm9sbG93VXBGb3JSZXF1ZXN0UlIsNTIuMC4wLDIw +MTgxMjAzLjExLDIwMTgxMjAzLjExIiwNCiAgICAiQGVudGl0eUV4dHJhY3Rpb25UcnVzdExldmVs +IjogIlVua25vd24iLA0KICAgICJAc291cmNlQ29uZmlkZW5jZVNjb3JlIjogIjAuNTExMzYxNjU4 +ODY2MiIsDQogICAgImRlc2NyaXB0aW9uIjogIldoYXQgYSBDaHJpc3RtYXMgdG8gcmVtZW1iZXIi +LA0KICAgICJkZXNjcmlwdGlvbi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiRm9sbG93VXAiLA0KICAg +ICJAYWJzb2x1dGVPZmZzZXRQbGFpblRleHQiOiAiMTA5NiIsDQogICAgIkBzcGFuIjogIjQiLA0K +ICAgICJARW50aXR5SWQiOiAiNGM3N2FkM2EtODg2ZC00OTRlLTk4MjAtMDk2N2YwMjRjNDUwIiwN +CiAgICAiQGNvcnJlbGF0aW9uVHJhaWwiOiAiQXNzZXRJZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJj +ZC02MmZiY2M4NjA0YTE7RXh0cmFjdGlvbklkPWM2MjYyNmI0LWQyMDgtNGNjYS1hZGY1LTAyODgx +ZTNhM2UxNDtFbnRpdHlJZD00Yzc3YWQzYS04ODZkLTQ5NGUtOTgyMC0wOTY3ZjAyNGM0NTAiLA0K +ICAgICJAZXh0cmFjdGlvblRpbWVVdGMiOiAiMjAxOC0xMi0xNVQxNTowNzoxOS43OTI1NzY2WiIN +CiAgfSwNCiAgew0KICAgICJAY29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm9yZyIsDQogICAgIkBv +dXRwdXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkBzY2hlbWFPcmdWZXJzaW9uIjogIjIuMSIsDQog +ICAgIkB0eXBlIjogIlNjaGVkdWxlQWN0aW9uIiwNCiAgICAiQHNvdXJjZSI6ICJURUUsNTIuMC4w +LDIwMTgxMjAzLjExLDIwMTgxMjAzLjExO2VuLVVTLkZvbGxvd1VwRm9yUmVxdWVzdFJSLDUyLjAu +MCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMSIsDQogICAgIkBlbnRpdHlFeHRyYWN0aW9uVHJ1c3RM +ZXZlbCI6ICJVbmtub3duIiwNCiAgICAiQHNvdXJjZUNvbmZpZGVuY2VTY29yZSI6ICIwLjk2MDIz +MTYzMTM3ODciLA0KICAgICJkZXNjcmlwdGlvbiI6ICJDYW4gd2UgZG8gdGhpcyBuZXh0IHdpbnRl +ciIsDQogICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJGb2xsb3dVcCIsDQog +ICAgIkBhYnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICIxMzgwIiwNCiAgICAiQHNwYW4iOiAiMyIs +DQogICAgIkBFbnRpdHlJZCI6ICIxZWJkMzRiOS04OThmLTRmZmQtOTAwYS1jNDM3ZjFiMDI2NDQi +LA0KICAgICJAY29ycmVsYXRpb25UcmFpbCI6ICJBc3NldElkPWI1MGY5ZDY3LTcwNWEtNGJjNy05 +YmNkLTYyZmJjYzg2MDRhMTtFeHRyYWN0aW9uSWQ9YzYyNjI2YjQtZDIwOC00Y2NhLWFkZjUtMDI4 +ODFlM2EzZTE0O0VudGl0eUlkPTFlYmQzNGI5LTg5OGYtNGZmZC05MDBhLWM0MzdmMWIwMjY0NCIs +DQogICAgIkBleHRyYWN0aW9uVGltZVV0YyI6ICIyMDE4LTEyLTE1VDE1OjA3OjE5Ljc5MjU3NjZa +Ig0KICB9LA0KICB7DQogICAgIkBjb250ZXh0IjogImh0dHA6Ly9zY2hlbWEub3JnIiwNCiAgICAi +QG91dHB1dFZlcnNpb24iOiAiMS4wIiwNCiAgICAiQHNjaGVtYU9yZ1ZlcnNpb24iOiAiMi4xIiwN +CiAgICAiQHR5cGUiOiAiU2NoZWR1bGVBY3Rpb24iLA0KICAgICJAc291cmNlIjogIlRFRSw1Mi4w +LjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTE7ZW4tVVMuRm9sbG93VXBGb3JSZXF1ZXN0UlIsNTIu +MC4wLDIwMTgxMjAzLjExLDIwMTgxMjAzLjExIiwNCiAgICAiQGVudGl0eUV4dHJhY3Rpb25UcnVz +dExldmVsIjogIlVua25vd24iLA0KICAgICJAc291cmNlQ29uZmlkZW5jZVNjb3JlIjogIjAuNTEx +MzYxNjU4ODY2MiIsDQogICAgImRlc2NyaXB0aW9uIjogIldoYXQgYSBDaHJpc3RtYXMgdG8gcmVt +ZW1iZXIiLA0KICAgICJkZXNjcmlwdGlvbi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiRm9sbG93VXAi +LA0KICAgICJAYWJzb2x1dGVPZmZzZXRQbGFpblRleHQiOiAiMTQxMSIsDQogICAgIkBzcGFuIjog +IjQiLA0KICAgICJARW50aXR5SWQiOiAiYTg5MzY1NmYtY2RlZC00ZGE5LTkyNzAtNGFiMjQ4YTc1 +NGJkIiwNCiAgICAiQGNvcnJlbGF0aW9uVHJhaWwiOiAiQXNzZXRJZD1iNTBmOWQ2Ny03MDVhLTRi +YzctOWJjZC02MmZiY2M4NjA0YTE7RXh0cmFjdGlvbklkPWM2MjYyNmI0LWQyMDgtNGNjYS1hZGY1 +LTAyODgxZTNhM2UxNDtFbnRpdHlJZD1hODkzNjU2Zi1jZGVkLTRkYTktOTI3MC00YWIyNDhhNzU0 +YmQiLA0KICAgICJAZXh0cmFjdGlvblRpbWVVdGMiOiAiMjAxOC0xMi0xNVQxNTowNzoxOS43OTI1 +NzY2WiINCiAgfSwNCiAgew0KICAgICJAY29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm9yZyIsDQog +ICAgIkBvdXRwdXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkBzY2hlbWFPcmdWZXJzaW9uIjogIjIu +MSIsDQogICAgIkB0eXBlIjogIlNjaGVkdWxlQWN0aW9uIiwNCiAgICAiQHNvdXJjZSI6ICJURUUs +NTIuMC4wLDIwMTgxMjAzLjExLDIwMTgxMjAzLjExO2VuLVVTLkZvbGxvd1VwRm9yUmVxdWVzdFJS +LDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMSIsDQogICAgIkBlbnRpdHlFeHRyYWN0aW9u +VHJ1c3RMZXZlbCI6ICJVbmtub3duIiwNCiAgICAiQHNvdXJjZUNvbmZpZGVuY2VTY29yZSI6ICIw +LjUxMTM2MTY1ODg2NjIiLA0KICAgICJkZXNjcmlwdGlvbiI6ICJXaGF0IGEgQ2hyaXN0bWFzIHRv +IHJlbWVtYmVyIiwNCiAgICAiZGVzY3JpcHRpb24vc2NoZWR1bGVBY3Rpb25UeXBlIjogIkZvbGxv +d1VwIiwNCiAgICAiQGFic29sdXRlT2Zmc2V0UGxhaW5UZXh0IjogIjE1ODkiLA0KICAgICJAc3Bh +biI6ICI0IiwNCiAgICAiQEVudGl0eUlkIjogIjM2NmQxMmQ0LTI0MjAtNDY3YS05MGNjLTk0ODE3 +YjhkMjQxMSIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1 +YS00YmM3LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2Et +YWRmNS0wMjg4MWUzYTNlMTQ7RW50aXR5SWQ9MzY2ZDEyZDQtMjQyMC00NjdhLTkwY2MtOTQ4MTdi +OGQyNDExIiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTku +NzkyNTc2NloiDQogIH0sDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmci +LA0KICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6 +ICIyLjEiLA0KICAgICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAi +VEVFLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJlcXVl +c3RSUiw1Mi4wLjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFj +dGlvblRydXN0TGV2ZWwiOiAiVW5rbm93biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUi +OiAiMC41MTEzNjE2NTg4NjYyIiwNCiAgICAiZGVzY3JpcHRpb24iOiAiV2hhdCBhIENocmlzdG1h +cyB0byByZW1lbWJlciIsDQogICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJG +b2xsb3dVcCIsDQogICAgIkBhYnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICIxNzcyIiwNCiAgICAi +QHNwYW4iOiAiNCIsDQogICAgIkBFbnRpdHlJZCI6ICJiMmNmN2Y1NS0wY2ZjLTQyMjYtYjhiMC04 +YWI2MWJiYmQyZDkiLA0KICAgICJAY29ycmVsYXRpb25UcmFpbCI6ICJBc3NldElkPWI1MGY5ZDY3 +LTcwNWEtNGJjNy05YmNkLTYyZmJjYzg2MDRhMTtFeHRyYWN0aW9uSWQ9YzYyNjI2YjQtZDIwOC00 +Y2NhLWFkZjUtMDI4ODFlM2EzZTE0O0VudGl0eUlkPWIyY2Y3ZjU1LTBjZmMtNDIyNi1iOGIwLThh +YjYxYmJiZDJkOSIsDQogICAgIkBleHRyYWN0aW9uVGltZVV0YyI6ICIyMDE4LTEyLTE1VDE1OjA3 +OjE5Ljc5MjU3NjZaIg0KICB9DQpdDQp9XQAAHhA1gQggBgAAAAAAwAAAAAAAAEYBAAAAGAAAAEUA +bgB0AGkAdAB5AE4AYQBtAGUAcwAAAAgAAAAQAAAARXh0cmFjdExhbmd1YWdlAA8AAABTY2hlZHVs +ZUFjdGlvbgAAFAAAAEtleVBocmFzZUV4dHJhY3Rpb24AHQAAAEZvbGxvd1VwU2NoZWR1bGVSZXBs +eVJlcXVlc3QAAAAAEwAAAEV4dHJhY3RMYW5ndWFnZTEuMAAAEgAAAFNjaGVkdWxlQWN0aW9uMS4w +AAAAFwAAAEtleVBocmFzZUV4dHJhY3Rpb24yLjAAACAAAABGb2xsb3dVcFNjaGVkdWxlUmVwbHlS +ZXF1ZXN0MS4wAB4AQ4G4WoAxkj7cEYecAAYbAxAEAQAAACIAAABHAHAAZwBPAEwAIABTAGkAZwAg +AFMAdABhAHQAdQBzAAAAAAABAAAAAgAAACMAAAAeAEWBhgMCAAAAAADAAAAAAAAARgEAAABmAAAA +eAAtAG0AcwAtAGUAeABjAGgAYQBuAGcAZQAtAG8AcgBnAGEAbgBpAHoAYQB0AGkAbwBuAC0AbwBy +AGkAZwBpAG4AYQBsAGMAbABpAGUAbgB0AGkAcABhAGQAZAByAGUAcwBzAAAAAAABAAAADgAAADc2 +LjEyNC4xOTMuMzUAAAAeAEaBhgMCAAAAAADAAAAAAAAARgEAAABmAAAAeAAtAG0AcwAtAGUAeABj +AGgAYQBuAGcAZQAtAG8AcgBnAGEAbgBpAHoAYQB0AGkAbwBuAC0AbwByAGkAZwBpAG4AYQBsAHMA +ZQByAHYAZQByAGkAcABhAGQAZAByAGUAcwBzAAAAAAABAAAAEwAAADI2MDM6MTBiNjozOmEzOjox +MAAAHgBPgROP8kH0gxRBpYTu21prC/8BAAAAFgAAAEMAbABpAGUAbgB0AEkAbgBmAG8AAAAAAAEA +AAAVAAAAQ2xpZW50PU1TRXhjaGFuZ2VSUEMAAAAAHgBZgYYDAgAAAAAAwAAAAAAAAEYBAAAAGAAA +AG0AcwBpAHAAXwBsAGEAYgBlAGwAcwAAAAEAAABFAgAATVNJUF9MYWJlbF9mNDJhYTM0Mi04NzA2 +LTQyODgtYmQxMS1lYmI4NTk5NTAyOGNfRW5hYmxlZD1UcnVlOyBNU0lQX0xhYmVsX2Y0MmFhMzQy +LTg3MDYtNDI4OC1iZDExLWViYjg1OTk1MDI4Y19TaXRlSWQ9NzJmOTg4YmYtODZmMS00MWFmLTkx +YWItMmQ3Y2QwMTFkYjQ3OyBNU0lQX0xhYmVsX2Y0MmFhMzQyLTg3MDYtNDI4OC1iZDExLWViYjg1 +OTk1MDI4Y19Pd25lcj1qZXN0ZWRmYUBtaWNyb3NvZnQuY29tOyBNU0lQX0xhYmVsX2Y0MmFhMzQy +LTg3MDYtNDI4OC1iZDExLWViYjg1OTk1MDI4Y19TZXREYXRlPTIwMTgtMTItMTVUMTU6MDc6MDYu +ODIyMTM3MFo7IE1TSVBfTGFiZWxfZjQyYWEzNDItODcwNi00Mjg4LWJkMTEtZWJiODU5OTUwMjhj +X05hbWU9R2VuZXJhbDsgTVNJUF9MYWJlbF9mNDJhYTM0Mi04NzA2LTQyODgtYmQxMS1lYmI4NTk5 +NTAyOGNfQXBwbGljYXRpb249TWljcm9zb2Z0IEF6dXJlIEluZm9ybWF0aW9uIFByb3RlY3Rpb247 +IE1TSVBfTGFiZWxfZjQyYWEzNDItODcwNi00Mjg4LWJkMTEtZWJiODU5OTUwMjhjX0V4dGVuZGVk +X01TRlRfTWV0aG9kPUF1dG9tYXRpYzsgU2Vuc2l0aXZpdHk9R2VuZXJhbAAAAAAeAHuBhgMCAAAA +AADAAAAAAAAARgEAAABkAAAAeAAtAG0AcwAtAGUAeABjAGgAYQBuAGcAZQAtAG8AcgBnAGEAbgBp +AHoAYQB0AGkAbwBuAC0AcwB1AGIAbQBpAHMAcwBpAG8AbgBxAHUAbwB0AGEAcwBrAGkAcABwAGUA +ZAAAAAEAAAAGAAAARmFsc2UAAAAeAHyBCCAGAAAAAADAAAAAAAAARgEAAABGAAAARQBuAHQAaQB0 +AHkARQB4AHQAcgBhAGMAdABpAG8AbgAvAFMAYwBoAGUAZAB1AGwAZQBBAGMAdABpAG8AbgAxAC4A +MAAAAAAAAQAAAM0DAABbDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmci +LA0KICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6 +ICIyLjEiLA0KICAgICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAi +VEVFLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Db21taXRtZW50VEZMVSw1 +Mi4wLjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFjdGlvblRy +dXN0TGV2ZWwiOiAiVHJ1c3RlZCIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUiOiAiMC45 +ODg3IiwNCiAgICAiZGVzY3JpcHRpb24iOiAiQ2hhbmdlIHRoZSByYWRpbyBhbmQgSSdsbCB0dXJu +IHRoZSBsaWdodHMgZG93biBkaW1tZXIiLA0KICAgICJkZXNjcmlwdGlvbi9zY2hlZHVsZUFjdGlv +blR5cGUiOiAiQ29tbWl0bWVudCIsDQogICAgInNjaGVkdWxlZFRpbWUiOiAiIiwNCiAgICAic2No +ZWR1bGVkVGltZS90aW1lem9uZSI6ICJFYXN0ZXJuIFN0YW5kYXJkIFRpbWUiLA0KICAgICJzY2hl +ZHVsZWRUaW1lL3JlbGF0aXZlIjogIiIsDQogICAgInNjaGVkdWxlZFRpbWUvaW1wcmVjaXNlRmxh +ZyI6ICIiLA0KICAgICJAYWJzb2x1dGVPZmZzZXRQbGFpblRleHQiOiAiMCIsDQogICAgIkBzcGFu +IjogIjUzIiwNCiAgICAiQEVudGl0eUlkIjogIjYzOTljMDFiLWUzZjQtNGY4Ni1iYTMwLWY0OTA1 +NDFhZjE4YyIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1 +YS00YmM3LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2Et +YWRmNS0wMjg4MWUzYTNlMTQ7RW50aXR5SWQ9NjM5OWMwMWItZTNmNC00Zjg2LWJhMzAtZjQ5MDU0 +MWFmMThjIiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTku +NzkyNTc2NloiDQogIH0NCl0AAAAAHgB9gQggBgAAAAAAwAAAAAAAAEYBAAAASAAAAEUAbgB0AGkA +dAB5AEUAeAB0AHIAYQBjAHQAaQBvAG4ALwBFAHgAdAByAGEAYwB0AEwAYQBuAGcAdQBhAGcAZQAx +AC4AMAAAAAEAAABwAgAAWw0KICB7DQogICAgIkB0eXBlIjogIkV4dHJhY3RMYW5ndWFnZSIsDQog +ICAgIkBjb250ZXh0IjogImh0dHA6Ly9zY2hlbWEubWljcm9zb2Z0LmNvbSIsDQogICAgIkBvdXRw +dXRWZXJzaW9uIjogIjEuMCIsDQogICAgIkxhbmd1YWdlIjogew0KICAgICAgIkB0eXBlIjogIkxh +bmd1YWdlIiwNCiAgICAgICJMb2NhbGUiOiAiZW4tVVMiLA0KICAgICAgIm5hbWUiOiAiRW5nbGlz +aCAoVW5pdGVkIFN0YXRlcykiDQogICAgfSwNCiAgICAiQHNvdXJjZSI6ICJFeGNoYW5nZSIsDQog +ICAgIkxhbmd1YWdlU2NvcmVzIjogew0KICAgICAgIkVuZ2xpc2giOiA5OS4xMzU0NDQ2DQogICAg +fSwNCiAgICAiQEVudGl0eUlkIjogImVmMmFlMWZlLTM1NGUtNDAxMy1iMTJjLWE1YTdkMDBiNzBm +YyIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1YS00YmM3 +LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2EtYWRmNS0w +Mjg4MWUzYTNlMTQ7RW50aXR5SWQ9ZWYyYWUxZmUtMzU0ZS00MDEzLWIxMmMtYTVhN2QwMGI3MGZj +IiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTkuNzkyNTc2 +NloiDQogIH0NCl0AHgB+gQggBgAAAAAAwAAAAAAAAEYBAAAAUAAAAEUAbgB0AGkAdAB5AEUAeAB0 +AHIAYQBjAHQAaQBvAG4ALwBLAGUAeQBQAGgAcgBhAHMAZQBFAHgAdAByAGEAYwB0AGkAbwBuADIA +LgAwAAAAAQAAAPIaAABbDQogIHsNCiAgICAiQG91dHB1dFZlcnNpb24iOiAiMi4wIiwNCiAgICAi +QGZvcm1hdHRlciI6ICJUZWVLcGVCb25kQ2JwQmFzZTY0IiwNCiAgICAiQHNjaGVtYSI6ICJNaWNy +b3NvZnQuRXhjaGFuZ2UuUmVsZXZhbmNlLlRlZUtwZUJvbmRSZXNwb25zZS5UZWVLcGUuVGVlS3Bl +UmVzcG9uc2UiLA0KICAgICJrZXlQaHJhc2VzIjogIlEwSUJBTTBVRWdvYkNYSUFhUUJqQUdnQUlB +QjBBR1VBZUFCMEFNY0tVZFJnUU0wVUVBY0VBZ0FBQUVBTUFBQ0FQeEFBQUlBL0RnQUFBRUFBQ1dN +QWFBQnlBR2tBY3dCMEFHMEFZUUJ6QU1jS0lLZ1R2ODBVRUFjYU1nQUFKRUlDQUFDQVB4SUFBR0JC +RnFsQkpUMFVBSUN0UXhnQUFJQS9HZ0FBb0VBY3FCUnNQQjRseVRKRElFbm1BejhpQUFBQVFDUlQz +Ync3SnRzMkowTW9zN24yUGpRQUFHQkJOa3ZVcmo0ODI3YWhRVDZiYnZ3K1JDVkpua0ZHaFJUM1Bp +d2xTWUpBTGdBQUFFQXd0MjBiUUVxU0pHbEFUQUFBQUVCT3QyMGJRQUFTY3dCd0FISUFhUUJ1QUdj +QWRBQnBBRzBBWlFBZ0FHWUFaUUJsQUd3QWFRQnVBR2NBeHdxSXRncEF6UlFRQnh3eUFBQWtRZ0lB +QUFCQUVnQUFvRUFXcUJUc1BCUUFnSzFER0FBQUFEOGFBQUFBUVJ4VDNidzhIczNNT0VNZ0xGWUlQ +eUlBQU1CQkpQK2xqVDBtTXpNZ1F5ZzBZT3crTkFBQW9FQTJrTUg1UFRnQUFJQS9PZ3pPeHp3OE16 +T3JRVDZZbmdVL1FBQUFBRUJDRE01SFBVVE56SlJCUnU5RjZENHVBQURBUURBQUFNQkFUQUFBd0VC +T0FBREFRQUFKY3dCMEFISUFZUUJ1QUdjQVpRQnlBSE1BeHdxcjI3MUF6UlFRQnh3eUFBQWtRZ0lB +QUlBL0VnQUFBRUFXVTkyOE94UUFnSzFER0FBQWdEOGFBQUNBUVJ4VDNUdzlIZ0FBbjBJZzdwcHFQ +aUlBQUV0REpJSERGVDhtQUVDRlF5aG5uRVEvTkFBQUFFQTJETTVIUFRnQUFBQkFPZ3pPUnowOEFB +QVFRVDdPeDJBK1FBQUF3RUZDaWRvVlAwUUFBUGhCUnB5UFFUOHVBQUNBUURBQUFMQkFUQUFBZ0VC +T0FBQ3dRQUFGWVFCekFIQUFaUUJ1QU1jS0xrQnB3TTBVRUFjZ01nQUFKRUlDQUFDQVB4SUFBSUEv +RmxQZFBEc1VBSUN0UXhnQUFJQS9HZ0FBOEVFY2ZnK3hQUjRBQVBCQklINFBzVDBpQUFDZVF5UXpJ +V2svSmdBQW5rTW9NeUZwUHpRQUFJQS9OZ3pPeHp3NEFBQ0FRRG9NenNjOVBBQUFnRUErRE03SFBV +QUFBQkJDUXM3SFlEOUVBQUFRUWtiT3gyQS9LZ0FBUUVBc0FBQkFRQzRBQUtCQU1BQUFvRUJJQUFC +QVFFb0FBRUJBVEFBQW9FQk9BQUNnUUFBRWN3QnVBRzhBZHdESENtSHdiOERORkJBSEd6SUFBQ1JD +QWdBQWdEOFNBQUFBUUJaVDNidzdGQUNBclVNYUFBQXdRaHdwMkFFK0hnQUFGa01nWGxQZFBpSUFB +TFJDSkovTGhENG1BQUJFUXloMG1SQS9OQUFBQUVBMkRNNUhQVGdBQUtCQU9wREIrVDA4QUFDSVFU +N3RTdFErUUFBQU1FRkNxVjJKUGtRQUFMaEJSaG1jRHo4cUFBREFRQ3dBQU9CQVNBQUF3RUJLQUFE +Z1FBQUtad0JoQUhRQWJBQnBBRzRBWWdCMUFISUFad0RIQ3NaNWE4RE5GQkFISURJQUFDUkNBZ0FB +Z0Q4U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1ZQUFDQVB4b0FBRWhDSE9tTUV6NGVBQUJJUWlEcGpCTStJ +Z0FBbEVNazZGOWFQeVlBQUpSREtPaGZXajgwQUFDQVB6WU16c2M4T0FBQXdFQTZpZG9WUGp3QUFN +QkFQb25hRlQ1QUFBQUlRa0x0U2xRL1JBQUFDRUpHN1VwVVB5b0FBS0JBTEFBQW9FQXVBQURBUURB +QUFNQkFTQUFBb0VCS0FBQ2dRRXdBQU1CQVRnQUF3RUFBQm5NQWJBQnZBSEFBWlFCekFNY0tRUGxQ +d00wVUVBY2JNZ0FBSkVJQ0FBQ0FQeElBQUFCQUZsUGR2RHNVQUlDdFF4b0FBSWhDSENtclNENGVB +SUFYUXlEMmlkOCtJZ0FBM2tJazdzZWpQaVlBZ0VKREtDaCtEejgwQUFBQVFEWU16a2M5T0FBQTRF +QTZTOVF1UGp3QUFJUkJQbjBNemo1QUFBQmdRVUpMMUs0K1JBQUF2RUZHVWJzU1B5b0FBTUJBTEFB +QUNFRklBQURBUUVvQUFBaEJBQWxtQUdrQWNnQmxBSEFBYkFCaEFHTUFaUURIQ3ZIWGpNRE5GQkFI +SHpJQUFDUkNBZ0FBZ0Q4U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1hQUFDa1FoeVQrM0UrSGdBQXBFSWdr +L3R4UGlJQUFJUkRKRDdFUWo4bUFBQ0VReWcreEVJL05BQUFnRDgyRE03SFBEZ0FBQkJCT3M3SFlE +NDhBQUFRUVQ3T3gyQStRQUFBK0VGQ25JOUJQMFFBQVBoQlJweVBRVDhxQUFDQVFDd0FBSUJBTGdB +QW9FQXdBQUNnUUVnQUFJQkFTZ0FBZ0VCTUFBQ2dRRTRBQUtCQUFCQjBBR0VBYUFCdkFHVUFJQUJ6 +QUdzQWFRQWdBR01BYUFCaEFHd0FaUUIwQU1jSzdXcVZ3TTBVRUFjY01nQUFKRUlDQUFCQVFCSUFB +SUEvRnYrbERUd1VBSUN0UXhpcnFxbytHZ0FBcWtJYzg5VjZQaDRBQUtwQ0lQUFZlajRpQUlDQlF5 +VHJFejgvSmdDQWdVTW82eE0vUHpRQUFJQS9OZ3pPeHp3NEFBQVFRVHJPeDJBK1BBQUFFRUUrenNk +Z1BrQUFBUGhCUXB5UFFUOUVBQUQ0UVVhY2owRS9LZ0FBNEVBc0FBRGdRRWdBQU9CQVNnQUE0RUFB +RW1ZQVlRQnpBSFFBSUFCMEFHRUFiQUJyQUdrQWJnQm5BQ0FBYkFCdkFIWUFaUUJ5QU1jS0hUR1h3 +TTBVRUFjZk1nQUFKRUlDQUFCQVFCSUFBSUEvRnYrbERUd1VBSUN0UXhvQUFMUkNISi9MaEQ0ZUFB +QzBRaUNmeTRRK0lnQUFma01rbVdNN1B5WUFBSDVES0psak96ODBBQUNBUHpZTXpzYzhPQUFBSUVF +NmtNRjVQandBQUNCQlBwREJlVDVBQUFEd1FVSXNVVHMvUkFBQThFRkdMRkU3UHlvQUFBQkFMQUFB +QUVBdUFBQ2dRREFBQUtCQVNBQUFBRUJLQUFBQVFFd0FBS0JBVGdBQW9FQUFFWE1BYkFCdkFIY0FJ +QUJpQUhVQWNnQnVBR2tBYmdCbkFDQUFkd0J2QUc4QVpBREhDdTFxbGNETkZCQUhHeklBQUNSQ0Fn +QUFRRUFTQUFDQVB4Yi9wUTA4RkFDQXJVTWFBQUMrUWh4RUxJdytIZ0FBdmtJZ1JDeU1QaUlBQUhs +REpFYXpOejhtQUFCNVF5aEdzemMvTkFBQWdEODJETTdIUERnQUFDQkJPcERCZVQ0OEFBQWdRVDZR +d1hrK1FBQUE4RUZDTEZFN1AwUUFBUEJCUml4Uk96OHFBQURnUUN3QUFPQkFTQUFBNEVCS0FBRGdR +QUFPZHdCcEFHd0FaQUJsQUhNQWRBQWdBR1FBY2dCbEFHRUFiUUJ6QU1jS3IyQ0t3TTBVRUFjZk1n +QUFKRUlDQUFBQVFCSUFBSUEvRmxQZHZEc1VBSUN0UXhvQUFNeENIRjZBbGo0ZUFBRE1RaUJlZ0pZ +K0lnQUFjME1rRmtZelB5WUFBSE5ES0JaR016ODBBQUNBUHpZTXpzYzhPQUFBTUVFNnFWMkpQandB +QURCQlBxbGRpVDVBQUFEb1FVSzdFalUvUkFBQTZFRkd1eEkxUHlvQUFJQkFMQUFBZ0VBdUFBREFR +REFBQU1CQVNBQUFnRUJLQUFDQVFFd0FBTUJBVGdBQXdFQUFCWElBWVFCa0FHa0Fid0RIQ3BVL2o4 +RE5GQkFISHpJQUFDUkNBZ0FBZ0Q4U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1hQUFBQVF4eFQzYncrSGdB +QUFFTWdVOTI4UGlJQUFGcERKSG5VSUQ4bUFBQmFReWg1MUNBL05BQUFnRDgyRE03SFBEZ0FBR0JC +T2t2VXJqNDhBQUJnUVQ1TDFLNCtRQUFBMEVGQ2FsY2lQMFFBQU5CQlJtcFhJajhxQUFBQVFDd0FB +QUJBTGdBQUFFRXdBQUFBUVVnQUFBQkFTZ0FBQUVCTUFBQUFRVTRBQUFCQkFBWnNBR2tBWndCb0FI +UUFjd0RIQ3RwbGc4RE5GQkFISHpJQUFDUkNBZ0FBZ0Q4U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1hQUFB +R1F4eXp0OFUrSGdBQUJrTWdzN2ZGUGlJQUFGUkRKRWxuSEQ4bUFBQlVReWhKWnh3L05BQUFnRDgy +RE03SFBEZ0FBR0JCT2t2VXJqNDhBQUJnUVQ1TDFLNCtRQUFBMEVGQ2FsY2lQMFFBQU5CQlJtcFhJ +ajhxQUFBQVFTd0FBQUJCTGdBQUFFQXdBQUFBUUVnQUFBQkJTZ0FBQUVGTUFBQUFRRTRBQUFCQUFB +WnNBRzhBZGdCbEFISUFjd0RIQ2ljaWFzRE5GQkFISHpJQUFDUkNBZ0FBZ0Q4U0FBQ0FQeFpUM1R3 +N0ZBQ0FyVU1hQUFBVFF4d3U1dGcrSGdBQUUwTWdMdWJZUGlJQUFFZERKQXpRRWo4bUFBQkhReWdN +MEJJL05BQUFnRDgyRE03SFBEZ0FBSUJCT2d6T3h6NDhBQUNBUVQ0TXpzYytRQUFBd0VGQ2lkb1ZQ +MFFBQU1CQlJvbmFGVDhxQUFDQVFDd0FBSUJBTGdBQVFFQXdBQUJBUUVnQUFJQkFTZ0FBZ0VCTUFB +QkFRRTRBQUVCQUFBWmlBR3dBYndCM0FHa0FiZ0RIQ3I0djNNRE5GQkFISERJQUFDUkNBZ0FBZ0Q4 +U0FBQ0FQeFpUM1R3N0ZBQ0FyVU1ZQUFDQVB4b0FBQ3RESEsxUC9ENGVBQUFyUXlDdFQvdytJZ0FB +TDBNa1RCc0JQeVlBQUM5REtFd2JBVDgwQUFDQVB6WU16c2M4T0FBQW1FRTZyMFR0UGp3QUFKaEJQ +cTlFN1Q1QUFBQ29RVUk0SHdNL1JBQUFxRUZHT0I4RFB5NEFBQ0JCTUFBQUlFRk1BQUFnUVU0QUFD +QkJBQlIzQUdrQWJBQmtBQ0FBY2dCbEFITUFkQUJzQUdVQWN3QnpBQ0FBZHdCcEFHNEFkQUJsQUhJ +QXh3cGRNZ0xCelJRUUJ4OHlBQUFrUWdJQUFFQkFFZ0FBZ0Q4Vy82VU5QQlFBZ0sxREdnQUFNVU1j +QjVVQ1B4NEFBREZESUFlVkFqOGlBQUFuUXlURGFQWStKZ0FBSjBNb3cyajJQalFBQUlBL05nek94 +enc0QUFDWVFUcXZSTzArUEFBQW1FRStyMFR0UGtBQUFLaEJRamdmQXo5RUFBQ29RVVk0SHdNL0tn +QUF3RUFzQUFEQVFDNEFBQUJBTUFBQUFFQklBQURBUUVvQUFNQkFUQUFBQUVCT0FBQUFRQUFGYmdC +bEFHRUFkQUJvQU1jSzh1L253TTBVRUFjY01nQUFKRUlDQUFDQVB4SUFBSUEvRmxQZFBEc1VBSUN0 +UXhnQUFJQS9HZ0FBUjBNY0ROQVNQeDRBQUVkRElBelFFajhpQUFBVFF5UXU1dGcrSmdBQUUwTW9M +dWJZUGpRQUFJQS9OZ3pPeHp3NEFBQ3dRVHFwWFFrL1BBQUFzRUUrcVYwSlAwQUFBSkJCUXM3SDRE +NUVBQUNRUVViT3grQStMZ0FBQUVFd0FBQUFRVXdBQUFCQlRnQUFBRUVBQ1cwQWFRQnpBSFFBYkFC +bEFIUUFid0JsQU1jS1huUFd3TTBVRUFjZk1nQUFKRUlDQUFDQVB4SUFBSUEvRmxQZFBEc1VBSUN0 +UXhvQUFFbERITVpKRkQ4ZUFBQkpReURHU1JRL0lnQUFFVU1rdVBMVlBpWUFBQkZES0xqeTFUNDBB +QUNBUHpZTXpzYzhPQUFBc0VFNnFWMEpQendBQUxCQlBxbGRDVDlBQUFDUVFVTE94K0ErUkFBQWtF +Rkd6c2ZnUGlvQUFBQkFMQUFBQUVBdUFBREFRREFBQU1CQVNBQUFBRUJLQUFBQVFFd0FBTUJBVGdB +QXdFQUFGSE1BWVFCdUFHY0FJQUJqQUdnQWNnQnBBSE1BZEFCdEFHRUFjd0FnQUhNQWJ3QnVBR2NB +Y3dESENsQXJBOEhORkJBSEhESUFBQ1JDQWdBQVFFQVNBQUNBUHhiL3BRMDhGQUNBclVNWXE2b3FQ +eG9BQUY1REhPN0hJejhlQUFCZVF5RHV4eU0vSWdBQTlFSWs4d0swUGlZQUFQUkNLUE1DdEQ0MEFB +Q0FQellNenNjOE9BQUF5RUU2K2hnY1B6d0FBTWhCUHZvWUhEOUFBQUJ3UVVJc1VicytSQUFBY0VG +R0xGRzdQaTRBQUlCQU1BQUFnRUJNQUFDQVFFNEFBSUJBQUFabUFHa0FaUUJzQUdRQWN3REhDaWZS +MXNETkZCQUhIeklBQUNSQ0FnQUFnRDhTQUFDQVB4WlQzVHc3RkFDQXJVTWFBQUJuUXh5MmF5by9I +Z0FBWjBNZ3Rtc3FQeUlBQU9aQ0pObXVxVDRtQUFEbVFpalpycWsrTkFBQWdEODJETTdIUERnQUFO +QkJPbXBYSWo4OEFBRFFRVDVxVnlJL1FBQUFZRUZDUzlTdVBrUUFBR0JCUmt2VXJqNHFBQUFBUUN3 +QUFBQkFMZ0FBZ0VBd0FBQ0FRRWdBQUFCQVNnQUFBRUJNQUFDQVFFNEFBSUJBQUFab0FHVUFZUUJ5 +QUhRQWN3REhDaWZSMXNETkZCQUhIeklBQUNSQ0FnQUFnRDhTQUFDQVB4WlQzVHc3RkFDQXJVTWFB +QUI4UXh6ZTZUay9IZ0FBZkVNZzN1azVQeUlBQUx4Q0pJbXlpajRtQUFDOFFpaUpzb28rTkFBQWdE +ODJETTdIUERnQUFPaEJPcnNTTlQ4OEFBRG9RVDY3RWpVL1FBQUFNRUZDcVYySlBrUUFBREJCUnFs +ZGlUNHFBQUFBUUN3QUFBQkFMZ0FBZ0VBd0FBQ0FRRWdBQUFCQVNnQUFBRUJNQUFDQVFFNEFBSUJB +QUFkakFHZ0FhUUJ0QUc0QVpRQjVBTWNLeTRmWndNMFVFQWNmTWdBQUpFSUNBQUNBUHhJQUFJQS9G +bFBkUERzVUFJQ3RReG9BQUg5REhIWWdQRDhlQUFCL1F5QjJJRHcvSWdBQXRrSWtXVVdHUGlZQUFM +WkNLRmxGaGo0MEFBQ0FQellNenNjOE9BQUE2RUU2dXhJMVB6d0FBT2hCUHJzU05UOUFBQUF3UVVL +cFhZaytSQUFBTUVGR3FWMkpQaW9BQUtCQUxBQUFvRUF1QUFDQVB6QUFBSUEvU0FBQW9FQktBQUNn +UUV3QUFJQS9UZ0FBZ0Q4QUMyNEFaUUI0QUhRQUlBQjNBR2tBYmdCMEFHVUFjZ0RIQ3J6TzlzRE5G +QkFIR3pJQUFDUkNBZ0FBQUVBU0FBQ0FQeFpUM2J3N0ZBQ0FyVU1hQUFDSFF4eHVNVWMvSGdBQWgw +TWdiakZIUHlJQUFKWkNKRjVUWFQ0bUFBQ1dRaWhlVTEwK05BQUFnRDgyRE03SFBEZ0FBUGhCT3B5 +UFFUODhBQUQ0UVQ2Y2owRS9RQUFBRUVGQ3pzZGdQa1FBQUJCQlJzN0hZRDRxQUFDQVFDd0FBSUJB +U0FBQWdFQktBQUNBUUFBRVpnQnBBSElBWlFESENxQkIzOERORkJBSEh6SUFBQ1JDQWdBQWdEOFNB +QUNBUHhaVDNUdzdGQUNBclVNYUFBQ1VReHpvWDFvL0hnQUFsRU1nNkY5YVB5SUFBRWhDSk9tTUV6 +NG1BQUJJUWlqcGpCTStOQUFBZ0Q4MkRNN0hQRGdBQUF4Q09sNkpXajg4QUFBTVFqNWVpVm8vUUFB +QW9FQkNrTUg1UFVRQUFLQkFScERCK1QwcUFBQUFRQ3dBQUFCQUxnQUFJRUV3QUFBZ1FVZ0FBQUJB +U2dBQUFFQk1BQUFnUVU0QUFDQkJBQTVpQUhVQWNnQnVBR2tBYmdCbkFDQUFaUUJ0QUdJQVpRQnlB +SE1BeHdvRzhRUEJ6UlFRQnhzeUFBQWtRZ0lBQUFCQUVnQUFnRDhXVTkyOE94UUFnSzFER2dDQXFV +TWNGUmw2UHg0QWdLbERJQlVaZWo4aUFBREFRQ1QvcFkwOEpnQUF3RUFvLzZXTlBEUUFBSUEvTmd6 +T3h6dzRBQUFjUWpvZmczTS9QQUFBSEVJK0g0TnpQMEFBQUlBL1Fnek94enhFQUFDQVAwWU16c2M4 +S2dBQUlFRXNBQUFnUVVnQUFDQkJTZ0FBSUVFQUFBPT0iLA0KICAgICJAdHlwZSI6ICJLZXlQaHJh +c2VFeHRyYWN0aW9uIiwNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5taWNyb3NvZnQu +Y29tIiwNCiAgICAiQEVudGl0eUlkIjogIjUwM2IwOGI3LWFjY2UtNDA0Ni1iNDg4LWViZTI4YzVk +NTYzZCIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1YS00 +YmM3LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2EtYWRm +NS0wMjg4MWUzYTNlMTQ7RW50aXR5SWQ9NTAzYjA4YjctYWNjZS00MDQ2LWI0ODgtZWJlMjhjNWQ1 +NjNkIiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTkuNzky +NTc2NloiDQogIH0NCl0AAAAeAH+BCCAGAAAAAADAAAAAAAAARgEAAABAAAAARQBuAHQAaQB0AHkA +RQB4AHQAcgBhAGMAdABpAG8AbgAvAEMAcgBlAGEAdABlAGQAVABhAHMAawAxAC4AMAAAAAEAAABF +AQAAW3siQGNvbnRleHQiOiJodHRwOi8vc2NoZW1hLm9yZyIsIkBvdXRwdXRWZXJzaW9uIjoiMS4w +IiwiQHR5cGUiOiJDcmVhdGVkVGFzayIsIkBzb3VyY2UiOiJUZWVJbmZlcmVuY2VzIiwiVGFza0lk +IjoiUmdBQUFBQzdfOHpqWWJzNVNJNXlXQ3BxdF9HVkJ3RHdhVm05a3h3clFKa2dPYmFrcFV1V0FB +Q0w2cEp1QUFEd2FWbTlreHdyUUprZ09iYWtwVXVXQUFEZFE5VXFBQUFBMCIsIlRhc2tTb3VyY2Ui +OiJjb20ubWljcm9zb2Z0Lm91dGxvb2suZW1haWwuY29tbWl0bWVudCIsIlNvdXJjZUVudGl0eUlk +IjoiNjM5OWMwMWItZTNmNC00Zjg2LWJhMzAtZjQ5MDU0MWFmMThjIn1dAAAAAB4AgIEIIAYAAAAA +AMAAAAAAAABGAQAAAGIAAABFAG4AdABpAHQAeQBFAHgAdAByAGEAYwB0AGkAbwBuAC8ARgBvAGwA +bABvAHcAVQBwAFMAYwBoAGUAZAB1AGwAZQBSAGUAcABsAHkAUgBlAHEAdQBlAHMAdAAxAC4AMAAA +AAAAAQAAACYZAABbDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmciLA0K +ICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6ICIy +LjEiLA0KICAgICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAiVEVF +LDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJlcXVlc3RS +Uiw1Mi4wLjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFjdGlv +blRydXN0TGV2ZWwiOiAiVW5rbm93biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUiOiAi +MC41MTEzNjE2NTg4NjYyIiwNCiAgICAiZGVzY3JpcHRpb24iOiAiV2hhdCBhIENocmlzdG1hcyB0 +byByZW1lbWJlciIsDQogICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJGb2xs +b3dVcCIsDQogICAgIkBhYnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICIxMzEiLA0KICAgICJAc3Bh +biI6ICI0IiwNCiAgICAiQEVudGl0eUlkIjogIjY2ZGZhMTczLWExYmItNGI5ZS04ODZiLWZjNTgy +NzM3ODY5MiIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1 +YS00YmM3LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2Et +YWRmNS0wMjg4MWUzYTNlMTQ7RW50aXR5SWQ9NjZkZmExNzMtYTFiYi00YjllLTg4NmItZmM1ODI3 +Mzc4NjkyIiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTku +NzkyNTc2NloiDQogIH0sDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmci +LA0KICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6 +ICIyLjEiLA0KICAgICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAi +VEVFLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJlcXVl +c3RSUiw1Mi4wLjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFj +dGlvblRydXN0TGV2ZWwiOiAiVW5rbm93biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUi +OiAiMC41MTEzNjE2NTg4NjYyIiwNCiAgICAiZGVzY3JpcHRpb24iOiAiV2hhdCBhIENocmlzdG1h +cyB0byByZW1lbWJlciIsDQogICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJG +b2xsb3dVcCIsDQogICAgIkBhYnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICI3MTkiLA0KICAgICJA +c3BhbiI6ICI0IiwNCiAgICAiQEVudGl0eUlkIjogImFiYTZiOGU2LWYxYWEtNDFjNS04ZjEyLTYy +N2FlNjQ5YzE0MiIsDQogICAgIkBjb3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjct +NzA1YS00YmM3LTliY2QtNjJmYmNjODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRj +Y2EtYWRmNS0wMjg4MWUzYTNlMTQ7RW50aXR5SWQ9YWJhNmI4ZTYtZjFhYS00MWM1LThmMTItNjI3 +YWU2NDljMTQyIiwNCiAgICAiQGV4dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6 +MTkuNzkyNTc2NloiDQogIH0sDQogIHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5v +cmciLA0KICAgICJAb3V0cHV0VmVyc2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lv +biI6ICIyLjEiLA0KICAgICJAdHlwZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2Ui +OiAiVEVFLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJl +cXVlc3RSUiw1Mi4wLjAsMjAxODEyMDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0 +cmFjdGlvblRydXN0TGV2ZWwiOiAiVW5rbm93biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2Nv +cmUiOiAiMC42MzAzMzIwMzI4MTM4IiwNCiAgICAiZGVzY3JpcHRpb24iOiAiJ05lYXRoIHRoZSBt +aXN0bGV0b2UgeW91IGtpc3NlZCBtZSB3YXJtIGFuZCB0ZW5kZXIiLA0KICAgICJkZXNjcmlwdGlv +bi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiRm9sbG93VXAiLA0KICAgICJAYWJzb2x1dGVPZmZzZXRQ +bGFpblRleHQiOiAiMTA0MSIsDQogICAgIkBzcGFuIjogIjEiLA0KICAgICJARW50aXR5SWQiOiAi +Mzc5MDA4Y2EtMTBhNS00YTI1LTk4MjEtZDY1NGNiYjkxOTBmIiwNCiAgICAiQGNvcnJlbGF0aW9u +VHJhaWwiOiAiQXNzZXRJZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJjZC02MmZiY2M4NjA0YTE7RXh0 +cmFjdGlvbklkPWM2MjYyNmI0LWQyMDgtNGNjYS1hZGY1LTAyODgxZTNhM2UxNDtFbnRpdHlJZD0z +NzkwMDhjYS0xMGE1LTRhMjUtOTgyMS1kNjU0Y2JiOTE5MGYiLA0KICAgICJAZXh0cmFjdGlvblRp +bWVVdGMiOiAiMjAxOC0xMi0xNVQxNTowNzoxOS43OTI1NzY2WiINCiAgfSwNCiAgew0KICAgICJA +Y29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm9yZyIsDQogICAgIkBvdXRwdXRWZXJzaW9uIjogIjEu +MCIsDQogICAgIkBzY2hlbWFPcmdWZXJzaW9uIjogIjIuMSIsDQogICAgIkB0eXBlIjogIlNjaGVk +dWxlQWN0aW9uIiwNCiAgICAiQHNvdXJjZSI6ICJURUUsNTIuMC4wLDIwMTgxMjAzLjExLDIwMTgx +MjAzLjExO2VuLVVTLkZvbGxvd1VwRm9yUmVxdWVzdFJSLDUyLjAuMCwyMDE4MTIwMy4xMSwyMDE4 +MTIwMy4xMSIsDQogICAgIkBlbnRpdHlFeHRyYWN0aW9uVHJ1c3RMZXZlbCI6ICJVbmtub3duIiwN +CiAgICAiQHNvdXJjZUNvbmZpZGVuY2VTY29yZSI6ICIwLjUxMTM2MTY1ODg2NjIiLA0KICAgICJk +ZXNjcmlwdGlvbiI6ICJXaGF0IGEgQ2hyaXN0bWFzIHRvIHJlbWVtYmVyIiwNCiAgICAiZGVzY3Jp +cHRpb24vc2NoZWR1bGVBY3Rpb25UeXBlIjogIkZvbGxvd1VwIiwNCiAgICAiQGFic29sdXRlT2Zm +c2V0UGxhaW5UZXh0IjogIjEwOTYiLA0KICAgICJAc3BhbiI6ICI0IiwNCiAgICAiQEVudGl0eUlk +IjogIjRjNzdhZDNhLTg4NmQtNDk0ZS05ODIwLTA5NjdmMDI0YzQ1MCIsDQogICAgIkBjb3JyZWxh +dGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1YS00YmM3LTliY2QtNjJmYmNjODYwNGEx +O0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2EtYWRmNS0wMjg4MWUzYTNlMTQ7RW50aXR5 +SWQ9NGM3N2FkM2EtODg2ZC00OTRlLTk4MjAtMDk2N2YwMjRjNDUwIiwNCiAgICAiQGV4dHJhY3Rp +b25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTkuNzkyNTc2NloiDQogIH0sDQogIHsNCiAg +ICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmciLA0KICAgICJAb3V0cHV0VmVyc2lvbiI6 +ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6ICIyLjEiLA0KICAgICJAdHlwZSI6ICJT +Y2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAiVEVFLDUyLjAuMCwyMDE4MTIwMy4xMSwy +MDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJlcXVlc3RSUiw1Mi4wLjAsMjAxODEyMDMuMTEs +MjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFjdGlvblRydXN0TGV2ZWwiOiAiVW5rbm93 +biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUiOiAiMC45NjAyMzE2MzEzNzg3IiwNCiAg +ICAiZGVzY3JpcHRpb24iOiAiQ2FuIHdlIGRvIHRoaXMgbmV4dCB3aW50ZXIiLA0KICAgICJkZXNj +cmlwdGlvbi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiRm9sbG93VXAiLA0KICAgICJAYWJzb2x1dGVP +ZmZzZXRQbGFpblRleHQiOiAiMTM4MCIsDQogICAgIkBzcGFuIjogIjMiLA0KICAgICJARW50aXR5 +SWQiOiAiMWViZDM0YjktODk4Zi00ZmZkLTkwMGEtYzQzN2YxYjAyNjQ0IiwNCiAgICAiQGNvcnJl +bGF0aW9uVHJhaWwiOiAiQXNzZXRJZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJjZC02MmZiY2M4NjA0 +YTE7RXh0cmFjdGlvbklkPWM2MjYyNmI0LWQyMDgtNGNjYS1hZGY1LTAyODgxZTNhM2UxNDtFbnRp +dHlJZD0xZWJkMzRiOS04OThmLTRmZmQtOTAwYS1jNDM3ZjFiMDI2NDQiLA0KICAgICJAZXh0cmFj +dGlvblRpbWVVdGMiOiAiMjAxOC0xMi0xNVQxNTowNzoxOS43OTI1NzY2WiINCiAgfSwNCiAgew0K +ICAgICJAY29udGV4dCI6ICJodHRwOi8vc2NoZW1hLm9yZyIsDQogICAgIkBvdXRwdXRWZXJzaW9u +IjogIjEuMCIsDQogICAgIkBzY2hlbWFPcmdWZXJzaW9uIjogIjIuMSIsDQogICAgIkB0eXBlIjog +IlNjaGVkdWxlQWN0aW9uIiwNCiAgICAiQHNvdXJjZSI6ICJURUUsNTIuMC4wLDIwMTgxMjAzLjEx +LDIwMTgxMjAzLjExO2VuLVVTLkZvbGxvd1VwRm9yUmVxdWVzdFJSLDUyLjAuMCwyMDE4MTIwMy4x +MSwyMDE4MTIwMy4xMSIsDQogICAgIkBlbnRpdHlFeHRyYWN0aW9uVHJ1c3RMZXZlbCI6ICJVbmtu +b3duIiwNCiAgICAiQHNvdXJjZUNvbmZpZGVuY2VTY29yZSI6ICIwLjUxMTM2MTY1ODg2NjIiLA0K +ICAgICJkZXNjcmlwdGlvbiI6ICJXaGF0IGEgQ2hyaXN0bWFzIHRvIHJlbWVtYmVyIiwNCiAgICAi +ZGVzY3JpcHRpb24vc2NoZWR1bGVBY3Rpb25UeXBlIjogIkZvbGxvd1VwIiwNCiAgICAiQGFic29s +dXRlT2Zmc2V0UGxhaW5UZXh0IjogIjE0MTEiLA0KICAgICJAc3BhbiI6ICI0IiwNCiAgICAiQEVu +dGl0eUlkIjogImE4OTM2NTZmLWNkZWQtNGRhOS05MjcwLTRhYjI0OGE3NTRiZCIsDQogICAgIkBj +b3JyZWxhdGlvblRyYWlsIjogIkFzc2V0SWQ9YjUwZjlkNjctNzA1YS00YmM3LTliY2QtNjJmYmNj +ODYwNGExO0V4dHJhY3Rpb25JZD1jNjI2MjZiNC1kMjA4LTRjY2EtYWRmNS0wMjg4MWUzYTNlMTQ7 +RW50aXR5SWQ9YTg5MzY1NmYtY2RlZC00ZGE5LTkyNzAtNGFiMjQ4YTc1NGJkIiwNCiAgICAiQGV4 +dHJhY3Rpb25UaW1lVXRjIjogIjIwMTgtMTItMTVUMTU6MDc6MTkuNzkyNTc2NloiDQogIH0sDQog +IHsNCiAgICAiQGNvbnRleHQiOiAiaHR0cDovL3NjaGVtYS5vcmciLA0KICAgICJAb3V0cHV0VmVy +c2lvbiI6ICIxLjAiLA0KICAgICJAc2NoZW1hT3JnVmVyc2lvbiI6ICIyLjEiLA0KICAgICJAdHlw +ZSI6ICJTY2hlZHVsZUFjdGlvbiIsDQogICAgIkBzb3VyY2UiOiAiVEVFLDUyLjAuMCwyMDE4MTIw +My4xMSwyMDE4MTIwMy4xMTtlbi1VUy5Gb2xsb3dVcEZvclJlcXVlc3RSUiw1Mi4wLjAsMjAxODEy +MDMuMTEsMjAxODEyMDMuMTEiLA0KICAgICJAZW50aXR5RXh0cmFjdGlvblRydXN0TGV2ZWwiOiAi +VW5rbm93biIsDQogICAgIkBzb3VyY2VDb25maWRlbmNlU2NvcmUiOiAiMC41MTEzNjE2NTg4NjYy +IiwNCiAgICAiZGVzY3JpcHRpb24iOiAiV2hhdCBhIENocmlzdG1hcyB0byByZW1lbWJlciIsDQog +ICAgImRlc2NyaXB0aW9uL3NjaGVkdWxlQWN0aW9uVHlwZSI6ICJGb2xsb3dVcCIsDQogICAgIkBh +YnNvbHV0ZU9mZnNldFBsYWluVGV4dCI6ICIxNTg5IiwNCiAgICAiQHNwYW4iOiAiNCIsDQogICAg +IkBFbnRpdHlJZCI6ICIzNjZkMTJkNC0yNDIwLTQ2N2EtOTBjYy05NDgxN2I4ZDI0MTEiLA0KICAg +ICJAY29ycmVsYXRpb25UcmFpbCI6ICJBc3NldElkPWI1MGY5ZDY3LTcwNWEtNGJjNy05YmNkLTYy +ZmJjYzg2MDRhMTtFeHRyYWN0aW9uSWQ9YzYyNjI2YjQtZDIwOC00Y2NhLWFkZjUtMDI4ODFlM2Ez +ZTE0O0VudGl0eUlkPTM2NmQxMmQ0LTI0MjAtNDY3YS05MGNjLTk0ODE3YjhkMjQxMSIsDQogICAg +IkBleHRyYWN0aW9uVGltZVV0YyI6ICIyMDE4LTEyLTE1VDE1OjA3OjE5Ljc5MjU3NjZaIg0KICB9 +LA0KICB7DQogICAgIkBjb250ZXh0IjogImh0dHA6Ly9zY2hlbWEub3JnIiwNCiAgICAiQG91dHB1 +dFZlcnNpb24iOiAiMS4wIiwNCiAgICAiQHNjaGVtYU9yZ1ZlcnNpb24iOiAiMi4xIiwNCiAgICAi +QHR5cGUiOiAiU2NoZWR1bGVBY3Rpb24iLA0KICAgICJAc291cmNlIjogIlRFRSw1Mi4wLjAsMjAx +ODEyMDMuMTEsMjAxODEyMDMuMTE7ZW4tVVMuRm9sbG93VXBGb3JSZXF1ZXN0UlIsNTIuMC4wLDIw +MTgxMjAzLjExLDIwMTgxMjAzLjExIiwNCiAgICAiQGVudGl0eUV4dHJhY3Rpb25UcnVzdExldmVs +IjogIlVua25vd24iLA0KICAgICJAc291cmNlQ29uZmlkZW5jZVNjb3JlIjogIjAuNTExMzYxNjU4 +ODY2MiIsDQogICAgImRlc2NyaXB0aW9uIjogIldoYXQgYSBDaHJpc3RtYXMgdG8gcmVtZW1iZXIi +LA0KICAgICJkZXNjcmlwdGlvbi9zY2hlZHVsZUFjdGlvblR5cGUiOiAiRm9sbG93VXAiLA0KICAg +ICJAYWJzb2x1dGVPZmZzZXRQbGFpblRleHQiOiAiMTc3MiIsDQogICAgIkBzcGFuIjogIjQiLA0K +ICAgICJARW50aXR5SWQiOiAiYjJjZjdmNTUtMGNmYy00MjI2LWI4YjAtOGFiNjFiYmJkMmQ5IiwN +CiAgICAiQGNvcnJlbGF0aW9uVHJhaWwiOiAiQXNzZXRJZD1iNTBmOWQ2Ny03MDVhLTRiYzctOWJj +ZC02MmZiY2M4NjA0YTE7RXh0cmFjdGlvbklkPWM2MjYyNmI0LWQyMDgtNGNjYS1hZGY1LTAyODgx +ZTNhM2UxNDtFbnRpdHlJZD1iMmNmN2Y1NS0wY2ZjLTQyMjYtYjhiMC04YWI2MWJiYmQyZDkiLA0K +ICAgICJAZXh0cmFjdGlvblRpbWVVdGMiOiAiMjAxOC0xMi0xNVQxNTowNzoxOS43OTI1NzY2WiIN +CiAgfQ0KXQAAAAsAHw4BAAAAAgH4DwEAAAAQAAAAFwCIYmVcL0K+j6gSY6LNKgIB+g8BAAAAEAAA +AOyulC30UBNEkJODXut1B/ADAP4PBQAAAAMADTT9P60OAwAPNP0/rQ4CARQ0AQAAABAAAADpL+t1 +llBEhoO4feUiqklIAgHiZQEAAAAUAAAA9kFwYR5q1kOITwPBjPt/YwAB/DICAeNlAQAAABUAAAAU +9kFwYR5q1kOITwPBjPt/YwAB/DIAAAACAX8AAQAAAFEAAAA8RE01UFIyMU1CMDgyOERBMkI4Qzg4 +MDQ4QkMwM0VGRkE2Q0ZBMjBARE01UFIyMU1CMDgyOC5uYW1wcmQyMS5wcm9kLm91dGxvb2suY29t +PgAAAAADAAYQYQv/igMABxCmBQAAAwAQEAAAAAADABEQAAAAAB4ACBABAAAAZQAAAFlPVVZFTUFE +RVRISVNBQ0hSSVNUTUFTVE9SRU1FTUJFUlNQUklOR1RJTUVGRUVMSU5HU0lOVEhFTUlERExFT0ZE +RUNFTUJFUlNUUkFOR0VSU01FRVRBTkRXSUxMSU5HTFlTVVIAAAAAGqACApAGAA4AAAABAAAAAAAg +ACAAAAAAAEEAAhOAAwAOAAAA4gcMAA8ACgADACAABgA3AQIPgAYAKbkFAP/Y/+AAEEpGSUYAAQIB +AEgASAAA/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsLDQ4SEA0OEQ4LCxAW +EBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQU +FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8IAEQgDpwV6AwEiAAIRAQMRAf/EAB0AAAAH +AQEBAAAAAAAAAAAAAAABAgMEBQYHCAn/xAAbAQADAQEBAQEAAAAAAAAAAAAAAQIDBAUGB//aAAwD +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 +6H6lqFNi1NfHOjo6XQ4tPRt1aTyZu47P0Dyrua8/09P530m8w8SmhybrOWCPs0GmaQTR+LfXXB0c +2xXZMoliYurygKbcAiSZgSXFg0TqkGl5mZU+UdkhiQUxGdJZoao6Wn1IVM7XV8m06v2H5T6lz7c7 +rEy02KldM4F2ce3ycmns3eNtfJrj2JQ5DlaXUchyPr3NPoVSF9e5mRsBkgRuoUNSkGxRpMHgAAMg +MECAEEoSYAEZADIEBkCAAEgAEASZMMA0gYMAYUBGDGQBgDBACAQAAwEnnUzd8w7Hbw+YWsynRiOF +9Cw/l83R+m+V+pdS5gnUZGW1BnwE5bESVrbaF11t9+vf0LKXWlhPU+1cS0s92w2mNmRvfIaYTmrF +S1cFFhsuJWaW1r5eLstI0Ss5YhZFVwB2Ofcr8NbaFCRltdFTlNXEaO2nZ07kUc6Vm5uOtmhlFRMV +WNaw7TyK0bNDOqNIhxnI6Vi7WHplKy0RpenX1Ojv338+LS1W3HGi2bzmlPV595Q9tkWdvK9n7755 ++hr5fQxKFQgKICjSsoiRYYyMHFWcx2iVxvHda5lRDI1zLRvKQwlxmmqfXvSnUiVENxJkV063KgDk +uRpDzDMqKI3G3Yt9yJdS6iPoq646fpOJ6hadVYoc5Z1Pd2flpnWuOYyTOLqJ2qzXRbvm3Sl0bTXY +aT11peeZLp0Tt2YNppazIUKOungo0KE+YAyAIYBAAhaUEAAIlECSMgACUKIEBggwAGAMzQRmGgYN +MjMwIzAJIwBAMIZm8mhRj2Hyj1aownAenvH1+suq6rzrNW8LXYt+M3ML1DA8+kbNXMK5ZWiDq50R ++ttWXRuV7fTOsrunY6KzUKRHra469y63vTpeh5jouLt6JJp7iNBIrXmmGJMBUdXa0uetkwiAnYy6 +6zqXXILgWEquSIQmaLHovYdKmdLN+vgKtFdY29CUxXQk9PIzxovDrEaZ29G5XaTFor2n0zpkqrKz +n51lS9lcdXZDv4/pOoefTW8opnRjXOdKqtTze3e8Y67lto4LA12X6/iYQkRunw+8emvnX6t04+zh +YqM75v7EUz53z/tHxbGe59XeGPST0oePdo81aDK2VSiDa25SGzhJAcaduKfSYTQtFOohzIM5iYk6 +ucyUxrQK4OSlaLOFLiV0txYCpHorujftM06EuEuxWbVqLKX0zVcvodNKvZ453njszHB+866d35cr +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 +Fyes0Z//2dpmAhCAAQANAAAAS0lUVEVOfjEuSlBHAI0DAhGABgC4DQAAAQAJAAAD3AYAAAAAIQYA +AAAABQAAAAkCAAAAAAUAAAABAv///wClAAAAQQvGAIgAIAAgAAAAAAAgACAAAAAAACgAAAAgAAAA +QAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAhBgAAQQtGAGYAIAAgAAAAAAAgACAAAAAAACgAAAAgAAAAIAAAAAEAGAAAAAAA +AAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACR +kI+Qj46Pjo2OjoyNjYuNjIuMi4qLiomKioiKiYeJiIaIh4aHhoWGhoSGhYOFhIKEg4GDgoGDgoCC +gX2BgHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRkZD7+/r7+/r7+/r7+/r7+/r7 ++/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/r7+/qCgX0AAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAACSkpD7+/r39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX3 +9vX39vX39vX39vX39vX39vX39vX7+/qDgoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AACTkpH7+/v39/b39vb39vb39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX3 +9vX7+/qDgoEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUk5L8+/v49/b49/b49/b4 +9/b49/b39/b39vb39vX39vX39vX39vX39vX39vX39vX39vX39vX39vX7+/qEg4EAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUlJP8+/v49/b49/b49/b49/b49/b49/b49/b49/b39vb3 +9vX39vX39vX39vX39vX39vX39vX39vX7+/qFhIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAACVlZT8+/v49/bXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDX +dgD39vX7+/qGhYMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWlZX8+/v49/fXdgDX +dgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgD39vX7+/qGhoQAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXlpX8/Pv5+PfXdgDXdgDXdgDXdgDXdgDXdgDXdgDX +dgDXdgDXdgDXdgDXdgDXdgDXdgDXdgD39vX7+/qHhoUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAACXl5b8/Pv5+PfXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDfmDzXdgDX +dgDXdgD39vX7+/qIh4YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYmJf8/Pv5+PfX +dgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDmq17ZgA3XdgDXdgDXdgD39vX7+/qJiIYAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZmZj8/Pz5+PjXdgDXdgDXdgDXdgDXdgDXdgDX +dgDXdgDXdgDhmj7rvIDXdgDXdgDhoEvXdgD39vb7+/qKiYcAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAACamZn8/Pz5+fjXdgDkqFvXdgDXdgDXdgDXdgDXdgDXdgDciR767t/ZgA3XdgDZ +gA327+fXdgD49/b7+/qKiogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbmpr9/Pz6 ++fjXdgD38ejdkCzXdgDXdgDXdgDXdgDXdgD45s/osm3XdgDXdgDuz6n49/bXdgD49/b7+/uLiokA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbm5r8/Pz5+fjXdgD6+fjz4crZgA7XdgDX +dgDXdgDwzJ/7+vnsyJrXdgDmsGr49/f49/bXdgD49/b8+/uMi4oAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAACcnJv9/Pz6+fjXdgD6+fj5+PjsyJvXdgDXdgDgmDz5+Pj5+Pj5+Pfu0Kr3 +8Oj4+Pf49/fXdgD49/b8+/uNjIsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACdnZz9 +/fz6+fnXdgD6+fj6+fj6+fjkqFvbiB338ej5+fj5+Pj5+Pj5+Pf5+Pf5+Pf4+PfXdgD49/b8+/uN +jYsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACenZ39/Pz6+fnXdgD6+fn6+vn6+fj4 +8en16dr6+fj6+fj5+fj5+Pj5+Pj5+Pf5+Pf4+PfXdgD49/b8+/uOjowAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAACenp79/fz7+vnXdgD6+fn6+fn6+fn6+vn6+fj5+fj6+fj5+fj5+fj5 ++Pj5+Pf5+Pf5+PfXdgD49/b8+/uPjo0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACf +n5/9/fz6+vnXdgD6+vn7+vn6+fn6+fn6+fj6+fj5+Pj6+fj5+fj5+Pj5+Pj5+Pf5+PfXdgD49/f8 ++/uQj44AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgoKD9/f37+vrXdgDXdgDXdgDX +dgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgDXdgD49/f8+/uRkI8AAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAChoaD9/f37+vr7+vr7+vr6+vn6+vn7+vn6+fn6+vn6+fj5+Pj6 ++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 +AAAAIAAAACAAAAABABgAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////// +////////////////////////////////////////////////////////////gICAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////////////////////////////// +////////////////////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAgICA//////////////////////////////////////////////////////////////////// +////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////// +////////wMDAwMDAwMDA////////////////////////////////////////////gICAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////////////wMDAAACAAACAwMDAwMDA +////////////////////////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAgICA////////////////wMDAAACAAACAAACAAACAwMDAwMDA//////////////////// +////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////// +wMDAAACAAACAAACAAACAAACAAACAwMDA////////////////////////////////////gICAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////wMDAAACAAACAAACAAACAAACAAACA +AACAgICAwMDA////////////////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAgICA////////AACAAACAAACAAACA////gICAAACAAACAAACAwMDAwMDA//////// +////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////// +AACAAACAAACA////////////wMDAAACAAACAAACAwMDAwMDA////////////////////////gICA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////AACA//////////////// +////wMDAAACAAACAgICAwMDA////////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAgICA////////////////////////////////////////wMDAAACAAACAgICA +wMDA////////////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//// +////////////////////////////////////////////AACAAACAwMDAwMDA//////////////// +gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////////////// +////////////////////////AACAAACAwMDAwMDA////////////gICAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAgICA//////////////////////////////////////////////////// +////AACAAACAwMDAwMDA////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA +////////////////////////////////////////////////////////////AACAAACAwMDA//// +////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////////// +////////////////////////////////////////AACAAACA////////gICAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////////////////////////////////// +////////////////////AACAwMDA////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +gICA//////////////////////////////////////////////////////////////////////// +AACA////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA//////////////////// +////////////////////////////////////////////////////////////gICAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////////////AAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAwMDA////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAgICA////////////////////gICAgICAgICAgICAgICAgICAgICAgICAgICAwMDAAAAAwMDA +////////////gICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAgICAgICAgICA +gICAgICA////gICAgICAgICAgICAgICAgICAgICAwMDAAAAAgICAgICAgICAgICAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////wMDAwMDAwMDA +wMDAwMDAwMDAgICAwMDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICA////////////////////////gICAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAgICAgICAgICAgICAgICAgICAgICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAApE8CBZAGAGgaAAATAAAAAwAg +DgEkAAAeAAEwAQAAABQAAABCdWlsZCBhIHRyYWluIHRhYmxlAA0AATcBAAAAfBkAAAcDAgAAAAAA +wAAAAAAAAEZ4nz4iJg8BBpAIAAQAAAAAAAEAAQABB5AGAAgAAADkBAAAAAAAAOgAAQiABwAJAAAA +SVBNLlRhc2sApwIBDYAEAAIAAAABAAEAAQSAAQAUAAAAQnVpbGQgYSB0cmFpbiB0YWJsZQDXBgEF +gAMADgAAAOIHDAAPAAkAJQAfAAYAVwEBAIAAAKYAAAAEAKYAEgCEAEplZmZyZXkgU3RlZGZhc3QA +AEVYOi9vPUV4Y2hhbmdlTGFicy9vdT1FeGNoYW5nZSBBZG1pbmlzdHJhdGl2ZSBHcm91cCAoRllE +SUJPSEYyM1NQRExUKS9jbj1SZWNpcGllbnRzL2NuPTIyN2RlYzM2ZDA5ODQ0NjY5Zjc4ZmM5NDg5 +ZWIzMWRkLUplZmZyZXkgU3RlAAAAAAAAAAAAcTIBBoADAA4AAADiBwwADwAJACUAHwAGAFcBAQeA +BgABAAAAISEAASCAAwAOAAAA4gcMAA8ACQAlADYABgBuAQEJgAEAIQAAADlDQUVERDAyM0ZGODlF +NEFBNUZFNjk4NkE5ODM4RUY1AJEHAQyAAgA6AAAAQnVpbGQgbXkgbmVwaGV3IGFuIEhPLXNjYWxl +IHRyYWluIHRhYmxlIGZvciBDaHJpc3RtYXMuDQoNCm8TAQOQBgCAFwAAUAAAAAsAAgABAAAACwAj +AAAAAAADACYAAQAAAAsAKQAAAAAAAwA2AAAAAABAADkAoAPMtYOU1AECATsAAQAAAIQAAABFWDov +Tz1FWENIQU5HRUxBQlMvT1U9RVhDSEFOR0UgQURNSU5JU1RSQVRJVkUgR1JPVVAgKEZZRElCT0hG +MjNTUERMVCkvQ049UkVDSVBJRU5UUy9DTj0yMjdERUMzNkQwOTg0NDY2OUY3OEZDOTQ4OUVCMzFE +RC1KRUZGUkVZIFNURQACAUEAAQAAAJ0AAAAAAAAA3KdAyMBCEBq0uQgAKy/hggEAAAAAAAAAL289 +RXhjaGFuZ2VMYWJzL291PUV4Y2hhbmdlIEFkbWluaXN0cmF0aXZlIEdyb3VwIChGWURJQk9IRjIz +U1BETFQpL2NuPVJlY2lwaWVudHMvY249MjI3ZGVjMzZkMDk4NDQ2NjlmNzhmYzk0ODllYjMxZGQt +SmVmZnJleSBTdGUAAAAAHgBCAAEAAAARAAAASmVmZnJleSBTdGVkZmFzdAAAAAAeAGQAAQAAAAMA +AABFWAAAHgBlAAEAAACBAAAAL289RXhjaGFuZ2VMYWJzL291PUV4Y2hhbmdlIEFkbWluaXN0cmF0 +aXZlIEdyb3VwIChGWURJQk9IRjIzU1BETFQpL2NuPVJlY2lwaWVudHMvY249MjI3ZGVjMzZkMDk4 +NDQ2NjlmNzhmYzk0ODllYjMxZGQtSmVmZnJleSBTdGUAAAAAHgBwAAEAAAAZAAAAU2FtcGxlIE91 +dGxvb2sgMjAxNiBUYXNrAAAAAAIBcQABAAAAFgAAAAHUlINYxPFA1BPXQU74u8KjFPCQAk0AAB4A +GgwBAAAAEQAAAEplZmZyZXkgU3RlZGZhc3QAAAAAAgEdDAEAAACEAAAARVg6L089RVhDSEFOR0VM +QUJTL09VPUVYQ0hBTkdFIEFETUlOSVNUUkFUSVZFIEdST1VQIChGWURJQk9IRjIzU1BETFQpL0NO +PVJFQ0lQSUVOVFMvQ049MjI3REVDMzZEMDk4NDQ2NjlGNzhGQzk0ODlFQjMxREQtSkVGRlJFWSBT +VEUAHgAeDAEAAAADAAAARVgAAB4AHwwBAAAAgQAAAC9vPUV4Y2hhbmdlTGFicy9vdT1FeGNoYW5n +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 +1AEDAEKACCAGAAAAAADAAAAAAAAARgAAAAABhQAAAAAAAEAAQ4AIIAYAAAAAAMAAAAAAAABGAAAA +AGCFAAAASFO+UZzUAQsASIAIIAYAAAAAAMAAAAAAAABGAAAAAAaFAAAAAAAAQABLgAggBgAAAAAA +wAAAAAAAAEYAAAAAFoUAAACIDggzlNQBQABMgAggBgAAAAAAwAAAAAAAAEYAAAAAF4UAAAAIMLAO +nNQBCwBNgAggBgAAAAAAwAAAAAAAAEYAAAAADoUAAAAAAAADAE6ACCAGAAAAAADAAAAAAAAARgAA +AAAYhQAAAAAAAAMAU4AIIAYAAAAAAMAAAAAAAABGAAAAAOuFAAAJBAAAAwB4gAMgBgAAAAAAwAAA +AAAAAEYAAAAAAYEAAAEAAAALAHmAAyAGAAAAAADAAAAAAAAARgAAAAAcgQAAAAAAAAUAeoADIAYA +AAAAAMAAAAAAAABGAAAAAAKBAACamZmZmZmpPwMAhYAIIAYAAAAAAMAAAAAAAABGAAAAAFKFAAAV +lRgAQACGgAMgBgAAAAAAwAAAAAAAAEYAAAAABYEAAAAAWsfkm9QBQACHgAMgBgAAAAAAwAAAAAAA +AEYAAAAABIEAAACAOB8JlNQBAwCKgAMgBgAAAAAAwAAAAAAAAEYAAAAAE4EAAAEAAAADAJOAAyAG +AAAAAADAAAAAAAAARgAAAAAQgQAAAAAAAAMAlIADIAYAAAAAAMAAAAAAAABGAAAAABGBAAAAAAAA +CwCbgAMgBgAAAAAAwAAAAAAAAEYAAAAAJIEAAAAAAAALAJyAAyAGAAAAAADAAAAAAAAARgAAAAAs +gQAAAAAAAAMAnYADIAYAAAAAAMAAAAAAAABGAAAAACmBAAAAAAAAAwCegAMgBgAAAAAAwAAAAAAA +AEYAAAAAKoEAAAAAAAAeAKOAAyAGAAAAAADAAAAAAAAARgAAAAAngQAAAQAAAAEAAAAAAAAAAwCo +gAMgBgAAAAAAwAAAAAAAAEYAAAAAOYEAAAAAAAADAKuAAyAGAAAAAADAAAAAAAAARgAAAAASgQAA +AgAAAB4Ar4ADIAYAAAAAAMAAAAAAAABGAAAAACGBAAABAAAAAQAAAAAAAAAeALCAAyAGAAAAAADA +AAAAAAAARgAAAAAfgQAAAQAAABEAAABKZWZmcmV5IFN0ZWRmYXN0AAAAAAsAsoADIAYAAAAAAMAA +AAAAAABGAAAAAAOBAAAAAAAAAwCzgAMgBgAAAAAAwAAAAAAAAEYAAAAAI4EAABj8//8LALSAAyAG +AAAAAADAAAAAAAAARgAAAAAmgQAAAAAAAB4At4AIIAYAAAAAAMAAAAAAAABGAAAAAFSFAAABAAAA +BQAAADE2LjAAAAAAQADagAggBgAAAAAAwAAAAAAAAEYAAAAAoIUAAIC1y7WDlNQBHgDbgAggBgAA +AAAAwAAAAAAAAEYAAAAAoYUAAAEAAAAIAAAANTU1NTU1NQBAAOmACCAGAAAAAADAAAAAAAAARgAA +AAC/hQAAYGfLtYOU1AECAQWBCCAGAAAAAADAAAAAAAAARgEAAAA2AAAASQBuAFQAcgBhAG4AcwBp +AHQATQBlAHMAcwBhAGcAZQBDAG8AcgByAGUAbABhAHQAbwByAAAAAAABAAAAEAAAAPT6V+pQU7hF +mUOTsi5l9OIeAD0AAQAAAAEAAAAAAAAAHgACDgEAAAABAAAAAAAAAB4AAw4BAAAAAQAAAAAAAAAe +AAQOAQAAAAEAAAAAAAAACwAbDgAAAAAeAB0OAQAAABQAAABCdWlsZCBhIHRyYWluIHRhYmxlAAsA +Hw4BAAAAAwD0DwIAAAADAPcPAAAAAAIB+A8BAAAAEAAAABcAiGJlXC9Cvo+oEmOizSoCAfoPAQAA +ABAAAADsrpQt9FATRJCTg17rdQfwAwD+DwUAAAADAA00/T+tDgMADzT9P60OAgEUNAEAAAAQAAAA +6S/rdZZQRIaDuH3lIqpJSJ46AgECNwEAAAAAAAAAAwAFNwUAAAADAAs3MgcAAAMAFDcAAAAAAwD6 +fwAAAABAAPt/AEDdo1dFswxAAPx/AEDdo1dFswwDAP1/AAAAAAsA/n8AAAAACwD/fwAAAAADACEO +ZTICAAIB+A8BAAAAEAAAABcAiGJlXC9Cvo+oEmOizSoCAfoPAQAAABAAAADsrpQt9FATRJCTg17r +dQfwAwD+DwcAAAADAA00/T+tDgMADzT9P60OoNkCApAGAA4AAAABAFAHAAAgACAAAAAAAJgAAhCA +AQAUAAAAVW50aXRsZWQgQXR0YWNobWVudAByBwITgAMADgAAAOIHDAAPAAoAEQAmAAYASwECD4AG +AFkAAABUaGlzIGF0dGFjaG1lbnQgaXMgYSBNQVBJIDEuMCBlbWJlZGRlZCBtZXNzYWdlIGFuZCBp +cyBub3Qgc3VwcG9ydGVkIGJ5IHRoaXMgbWFpbCBzeXN0ZW0uAPIeAhGABgC4DQAAAQAJAAAD3AYA +AAAAIQYAAAAABQAAAAkCAAAAAAUAAAABAv///wClAAAAQQvGAIgAIAAgAAAAAAAgACAAAAAAACgA +AAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAA/////////////////////+AAAAfgAAAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAAH4AAAB+AA +AAfgAAAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAAH4AAAB+AAAAfgAAAH4AAA +B+AAAAf///////////////8hBgAAQQtGAGYAIAAgAAAAAAAgACAAAAAAACgAAAAgAAAAIAAAAAEA +GAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD/ +///////////AwMD////////////AwMD////////////AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA +wMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD////////////AwMD///////// +///AwMD////////////AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAA +AAAAAACAgID////////////AwMD////////////AwMD////////////AwMD////////////AwMDA +wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgIDAwMDAwMDAwMDA +wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA +wMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD////////////AwMD///// +///////AwMD////////////AwMD////////////AwMD////////////AwMAAAAAAAAAAAAAAAAAA +AAAAAAAAAACAgID////////////AwMD////////////AwMD////////////AwMD////////////A +wMD////////////AwMD////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID///////// +///AwMD////////////AwMD////////////AwMD////////////AwMD////////////AwMD///// +///////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA +wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAA +AAAAAAAAAAAAAACAgID////////////AwMD////////////AwMD////////////AwMD///////// +///AwMD////////////AwMD////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID///// +///////AwMD////////////AwMD////////////AwMD////////////AwMD////////////AwMD/ +///////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD////////////A +wMD////////////AwMD////////////AwMD////////////AwMD////////////AwMAAAAAAAAAA +AAAAAAAAAAAAAAAAAACAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA +wMDAwMDAwMAAAIAAAIAAAIDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID/ +///////////AwMD////////////AwMD////////////AwMD///////////8AAIDAwMD////AwMAA +AID////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD///////// +///AwMD////////////AwMD///////////8AAID///////////8AAID////////////AwMAAAAAA +AAAAAAAAAAAAAAAAAAAAAACAgID////////////AwMD////////////AwMD////////////AwMD/ +//////////8AAIDAwMD////AwMAAAID////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACA +gIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAIAAAIAA +AIDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgIDAwMDAwMDAwMDAwMDAwMDA +wMDAwMDAwMDAwMDAwMDAwMDAwMD////////////AwMD////////////AwMD////////////AwMAA +AAAAAAAAAAAAAAAAAAAAAAAAAACAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA +wMD////////////AwMD////////////AwMD////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAA +AACAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////////AwMD///// +///////AwMD////////////AwMAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gIAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACA +AACAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAA +AAAAAACAgICAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAAACAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAACAgICAgICAgICAgICA +gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA +gICAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAA9jwIFkAYAGOIFABMAAAADACAOfekFAB4AATABAAAA +FwAAAENocmlzdG1hcyBDZWxlYnJhdGlvbiEAAA0AATcBAAAAJeEFAAcDAgAAAAAAwAAAAAAAAEZ4 +nz4iJg8BBpAIAAQAAAAAAAEAAQABB5AGAAgAAADkBAAAAAAAAOgAAQiABwAQAAAASVBNLkFwcG9p +bnRtZW50AKMFAQ2ABAACAAAAAgACAAEEgAEAFwAAAENocmlzdG1hcyBDZWxlYnJhdGlvbiEAVwgB +BYADAA4AAADiBwwADwAJADEAFwAGAFsBAQkABAACAAAAAQABAAEAgAAApgAAAAQApgASAIQASmVm +ZnJleSBTdGVkZmFzdAAARVg6L289RXhjaGFuZ2VMYWJzL291PUV4Y2hhbmdlIEFkbWluaXN0cmF0 +aXZlIEdyb3VwIChGWURJQk9IRjIzU1BETFQpL2NuPVJlY2lwaWVudHMvY249MjI3ZGVjMzZkMDk4 +NDQ2NjlmNzhmYzk0ODllYjMxZGQtSmVmZnJleSBTdGUAAAAAAAAAAABxMgEGgAMADgAAAOIHDAAP +AAkAMQAXAAYAWwEBB4AGAAEAAAChoQABDIACADsAAABJdCdzIHRpbWUgZm9yIGV2ZXJ5b25lIHRv +IG9wZW4gdGhlaXIgQ2hyaXN0bWFzIHByZXNlbnRzIQ0KAMUUASCAAwAOAAAA4gcMAA8ACQAxAAQA +BgBIAQEJgAEAIQAAAENFODM4ODkwRTBFOEE2NERCNEVBM0MxOTk1ODQ2NTdGAEsHAQOQBgDkFQAA +cAAAAAsAAgABAAAACwAjAAAAAAADACYAAAAAAAsAKQAAAAAACwArAAAAAAADADYAAAAAAEAAOQBg +R0tehZTUAQIBOwABAAAAhAAAAEVYOi9PPUVYQ0hBTkdFTEFCUy9PVT1FWENIQU5HRSBBRE1JTklT +VFJBVElWRSBHUk9VUCAoRllESUJPSEYyM1NQRExUKS9DTj1SRUNJUElFTlRTL0NOPTIyN0RFQzM2 +RDA5ODQ0NjY5Rjc4RkM5NDg5RUIzMURELUpFRkZSRVkgU1RFAAIBQQABAAAAnQAAAAAAAADcp0DI +wEIQGrS5CAArL+GCAQAAAAAAAAAvbz1FeGNoYW5nZUxhYnMvb3U9RXhjaGFuZ2UgQWRtaW5pc3Ry +YXRpdmUgR3JvdXAgKEZZRElCT0hGMjNTUERMVCkvY249UmVjaXBpZW50cy9jbj0yMjdkZWMzNmQw +OTg0NDY2OWY3OGZjOTQ4OWViMzFkZC1KZWZmcmV5IFN0ZQAAAAAeAEIAAQAAABEAAABKZWZmcmV5 +IFN0ZWRmYXN0AAAAAB4AZAABAAAAAwAAAEVYAAAeAGUAAQAAAIEAAAAvbz1FeGNoYW5nZUxhYnMv +b3U9RXhjaGFuZ2UgQWRtaW5pc3RyYXRpdmUgR3JvdXAgKEZZRElCT0hGMjNTUERMVCkvY249UmVj +aXBpZW50cy9jbj0yMjdkZWMzNmQwOTg0NDY2OWY3OGZjOTQ4OWViMzFkZC1KZWZmcmV5IFN0ZQAA +AAAeAHAAAQAAABcAAABDaHJpc3RtYXMgQ2VsZWJyYXRpb24hAAACAXEAAQAAABYAAAAB1JSFROpB +O5YoiQNPfonY8L01ZCUyAAALABcMAQAAAB4AGgwBAAAAEQAAAEplZmZyZXkgU3RlZGZhc3QAAAAA +AgEdDAEAAACEAAAARVg6L089RVhDSEFOR0VMQUJTL09VPUVYQ0hBTkdFIEFETUlOSVNUUkFUSVZF +IEdST1VQIChGWURJQk9IRjIzU1BETFQpL0NOPVJFQ0lQSUVOVFMvQ049MjI3REVDMzZEMDk4NDQ2 +NjlGNzhGQzk0ODlFQjMxREQtSkVGRlJFWSBTVEUAHgAeDAEAAAADAAAARVgAAB4AHwwBAAAAgQAA +AC9vPUV4Y2hhbmdlTGFicy9vdT1FeGNoYW5nZSBBZG1pbmlzdHJhdGl2ZSBHcm91cCAoRllESUJP +SEYyM1NQRExUKS9jbj1SZWNpcGllbnRzL2NuPTIyN2RlYzM2ZDA5ODQ0NjY5Zjc4ZmM5NDg5ZWIz +MWRkLUplZmZyZXkgU3RlAAAAAAsAAQ4AAAAAQAAGDsDASV6FlNQBAwAIDm/bBQADABcOAAAAABQA +Gg4CAAAAAAAAAAMAgBABBAAAAwAFMAAAAABAAAcwMB4FMIWU1AFAAAgwACcYU4WU1AELABYwAQAA +AAMACzYAAAAAAwDeP69vAAADAPE/CQQAAB4A+j8BAAAAFAAAAGpzdGVkZmFzdEB5YWhvby5jb20A +AwABgAIgBgAAAAAAwAAAAAAAAEYAAAAABYIAAAIAAAALAAKAAiAGAAAAAADAAAAAAAAARgAAAAAj +ggAAAQAAAAMAA4ACIAYAAAAAAMAAAAAAAABGAAAAADGCAAAEAAAAAgEEgAIgBgAAAAAAwAAAAAAA +AEYAAAAAFoIAAAEAAABQAAAABDAEMA0gAgAAAMBWBwAMAAAAAAAAABkAAAAjIAAACgAAAAAAAAAA +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 +AAEAAAALAHWBAiAGAAAAAADAAAAAAAAARgAAAAA6ggAAAAAAAB4AdoHu/8AAEREREb7vAKq7zN3u +AAAAAAWQAAABAAAAIwAAADQ0NDctMDdFMjBDMEYtMDE5Ri0wRTMxLUZGMTctMDA3MzkAAAIBd4Hu +/8AAEREREb7vAKq7zN3uAAAAAAGQAAABAAAA0gIAAEJFR0lOOlZDQUxFTkRBUg0KVkVSU0lPTjoy +LjANClBST0RJRDotLy9BcHBsZSBJbmMuLy9BcHBsZSBXZWJEQVYgT3V0bG9vayBTdG9yZSA0Ljku +MTAvL0VODQpDQUxTQ0FMRTpHUkVHT1JJQU4NCkJFR0lOOlZFVkVOVA0KWC1BUFBMRS1PTC1NQVBQ +SU5HLUlORk86MQ0KU0VRVUVOQ0U6MA0KQ1JFQVRFRDoyMDE4MTIxNVQxNDQ5MjNaDQpEVFNUQU1Q +OjIwMTgxMjE1VDE0NDkwNFoNClVJRDo0NDQ3LTA3RTIwQzBGLTAxOUYtMEUzMS1GRjE3LTAwNzM5 +DQpMT0NBVElPTjpIb21lDQpTVU1NQVJZOkNocmlzdG1hcyBDZWxlYnJhdGlvbiENCkRFU0NSSVBU +SU9OOkl0J3MgdGltZSBmb3IgZXZlcnlvbmUgdG8gb3BlbiB0aGVpciBDaHJpc3RtYXMgcHJlc2Vu +dHMhDQpEVFNUQVJUOjIwMTgxMjI1VDEyMDAwMFoNCkRURU5EOjIwMTgxMjI1VDE0MDAwMFoNCkJF +R0lOOlZBTEFSTQ0KWC1XUi1BTEFSTVVJRDpHRUVQLTA3RTIwQzBGLTAxOUYtMEUzMS1GRjE3LTAw +NzM5DQpVSUQ6R0VFUC0wN0UyMEMwRi0wMTlGLTBFMzEtRkYxNy0wMDczOQ0KVFJJR0dFUjotUFQx +ME0NCkFDVElPTjpESVNQTEFZDQpERVNDUklQVElPTjpUaGlzIGlzIGFuIGV2ZW50IHJlbWluZGVy +Lg0KRU5EOlZBTEFSTQ0KUlJVTEU6RlJFUT1ZRUFSTFk7QllNT05USD0xMjtCWU1PTlRIREFZPTI1 +O1dLU1Q9U1UNCkxBU1QtTU9ESUZJRUQ6MjAxODEyMTVUMTQ0OTA0Wg0KRU5EOlZFVkVOVA0KRU5E +OlZDQUxFTkRBUg0KAAAeAHiB7v/AABERERG+7wCqu8zd7gAAAAACkAAAAQAAAC8AAAAiQz0xMTFA +VT0zZDBiZWFjMS03YmFlLTRmOWUtODY0My05ZTk5ZWMxM2NkOGUiAAAeAHmB7v/AABERERG+7wCq +u8zd7gAAAAAXkAAAAQAAACMAAABHRUVQLTA3RTIwQzBGLTAxOUYtMEUzMS1GRjE3LTAwNzM5AAAe +AHqB7v/AABERERG+7wCqu8zd7gAAAAADkAAAAQAAAB0AAAB0ZXh0L2NhbGVuZGFyOyBjaGFyc2V0 +PXV0Zi04AAAAAB4APQABAAAAAQAAAAAAAAAeAAIOAQAAAAEAAAAAAAAAHgADDgEAAAABAAAAAAAA +AB4ABA4BAAAAAQAAAAAAAAALABsOAQAAAB4AHQ4BAAAAFwAAAENocmlzdG1hcyBDZWxlYnJhdGlv +biEAAAsAHw4AAAAAAwD0DwIAAAADAPcPAAAAAAIB+A8BAAAAEAAAABcAiGJlXC9Cvo+oEmOizSoC +AfoPAQAAABAAAADsrpQt9FATRJCTg17rdQfwAwD+DwUAAAACAQkQAQAAANQAAADQAAAAUQEAAExa +RnUrm9DrAwAKAHJjcGcxMjUiMgNDdGV4BUJiaf5kBAADMAEDAfcKgAKkA+T/BxMCgBBzAFAEVghV +B7IRpScOUQMBAgBjaArAc2XcdDIGAAbDEaUzBEYUN94wEqwRswjvCfc7GJ8OMHY1EaIMYGMAUAsJ +AWQzDjYW0AumAzBvYmphgQJAcGggSXQnBCCadAdxIAIQBcBldgSQBnkCIB6QdG8gb3AjCfAeUGhl +aQXAQ2jZBRBzdADABCBwGKAUkFkCMHMhCqIKgH0iAAMADTT9P60OAwAPNP0/rQ4CARQ0AQAAABAA +AADpL+t1llBEhoO4feUiqklISusCApAGAA4AAAABAAAAAAAgACAAAAAAAEEAAhKAAwAOAAAA4gcM +AA8ACQAtADYABgB2AQITgAMADgAAAOIHDAAPAAkAMQAXAAYAWwECD4AGACm5BQD/2P/gABBKRklG +AAECAQBIAEgAAP/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEO +CwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQU +FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/CABEIA6cFegMBIgACEQEDEQH/xAAd +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 +CJMSgVdutaUqL41dW7NiLOQzVyJLFVc5N2MWMkHKxjO47WLUxvn2jvkY48a1j3FdX2cFlM05T3Ca +t+OSw+h+pahTYtTXxzo6Ol0OLT0bdWk8mbuOz9A8q7mvP9PT+d9JvMPEpocm6zlgj7NBpmkE0fi3 +11wdHNsV2TKJYmLq8oCm3AIkmYElxYNE6pBpeZmVPlHZIYkFMRnSWaGqOlp9SFTO11fJtOr9h+U+ +pc+3O6xMtNipXTOBdnHt8nJp7N3jbXya49iUOQ5Wl1HIcj69zT6FUhfXuZkbAZIEbqFDUpBsUaTB +4AADIDBAgBBKEmABGQAyBAZAgABIABAEmTDANIGDAGFARgxkAYAwQAgEAAMBJ51M3fMOx28PmFrM +p0YjhfQsP5fN0fpvlfqXUuYJ1GRltQZ8BOWxEla22hddbffr39Cyl1pYT1PtXEtLPdsNpjZkb3yG +mE5qxUtXBRYbLiVmlta+Xi7LSNErOWIWRVcAdjn3K/DW2hQkZbXRU5TVxGjtp2dO5FHOlZubjrZo +ZRUTFVjWsO08itGzQzqjSIcZyOlYu1h6ZSstEaXp19To799/Pi0tVtxxotm85pT1efeUPbZFnbyv +Z+++efoa+X0MShUICiAo0rKIkWGMjBxVnMdolcbx3WuZUQyNcy0bykMJcZpqn170p1IlRDcSZFdO +tyoA5LkaQ8wzKiiNxt2LfciXUuoj6KuuOn6TieoWnVWKHOWdT3dn5aZ1rjmMkzi6idqs10W75t0p +dG012Gk9daXnmS6dE7dmDaaWsyFCjrp4KNChPmAMgCGAQAIWlBAACJRAkjIAAlCiBAYIMABgDM0E +ZhoGDTIzMCMwCSMAQDCGZvJoUY9h8o9WqMJwHp7x9frLquq86zVvC12LfjNzC9QwPPpGzVzCuWVo +g6udEfrbVl0ble30zrK7p2Ois1CkR62uOvcut706XoeY6Li7eiSae4jQSK15phiTAVHV2tLnrZMI +gJ2Muus6l1yC4FhKrkiEJmix6L2HSpnSzfr4CrRXWNvQlMV0JPTyM8aLw6xGmdvRuV2kxaK9p9M6 +ZKqys5+dZUvZXHV2Q7+P6TqHn01vKKZ0Y1znSqrU83t3vGOu5baOCwNdl+v4mEJEbp8PvHpr51+r +dOPs4WKjO+b+xFM+d8/7R8WxnufV3hj0k9KHj3aPNWgytlUog2tuUhs4SQHGnbin0mE0LRTqIcyD +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 +ma3EaSO66cgFh9LaHVFn3WpU7YtAig2mePe+r+YfQnkfNX/iP2Ngu7HOcA9j+deP0Oe0qq/6HjjH +YPTnVu2kqNUWVC9GctxV3vzZSB0l7p5+RsdijwuRDrFilxZvv0lnna07rAT5DVd/WlwIegJA/OLf +pM9Dzw16HZzPPB+hWGcHR25qFzJjrkJLiI7Szscja6vGlc7u9XYKcxVdQzMZc7g9vY16eMabcrF2 ++r3Tfk+pyU9pmeTvyzDFnO2dI2aItZPp98tBVN2qcOP6a5918nP9hg+ucV4i41vJtdtC7htp09Gh +e52UxcU7VBr7uhYoW71vGKVt8tvHrbauBvc9v6Lt8/42qvSkfj8Pgz3qU+jfx7V+zMma+e8t6Ymq +fLML1hEqvNth2fkmPPZVlOmikF407gC4Im1RQwZdtApr3S6odDVnlzuRu2wy7epQlCiTK5j8SLDu +rV9FZUtRVah757UsZ+CdGfTRWp1M2XEjS3IWeha6DbpZNiyyrsVW0LON3s8MI5sHLMoeldc5pe2p +B5pN43VJiW7smXj75ZXP7q7eJgQNwys+eJ6fcXpxhPcXHXCGvQTg/Ow9DJl+fld+UjiT/bllcQV3 +F1nDl9yrpOTjqrlb8aRqMrHehmKzUybKhOcOu+j+DeiPmeqwrsRRXl2XnkYtTBo6RI+i4uXu9SeD +l0zpb4+fT94+LFStk7U5J7WLFlndObWbXpDazq9CGqBd4bKJV2QqU7gBUHaGFUdoTVWLMDqytSFW +CzAVhWoFUlbqCka0BhQO3RhUOWZsqk3BMfYOLnomA5BiuV8q9NweDs843Xa2qOQZH0Sma87XHb3G +YVW8V0c3PldAooed511jIef15J+2h9+eao9bS1tWCcq9a9NxMFmn9lq3lS92wF9fLtl5qz0xtnmb +Eht6XJagu2DzVOu5UlXKsDZV0+sOTJv6UkZGBvAjk9H3MI5E91YBySh7wA8gr9djHn8juetBT8mJ +9aJT8nyPVJ1fk4/WJUcGuewCXw4+4FL4i52oN8Vk9gS1y1fTUW8E/tCp5R7SE1nE6QgzkDYFLyND +0skcsmdHJLn1vqjp5NOuOjFxt6E+cROpGjl03opDw0jYhrJO6twMorWqZk16wwyy9QYZY9QGZlOp +MMgztgPBRujEnzCv6+E+DUfpVM35KgexRNeKKj3YJXgY/fIR4h656CRx7eerft54VyY+su+rzcvn +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 +uq6Loui6LxrxrxMvEy8ArwCvAK9MK9MK9OK9OK9LG69BXdeigZeliQ1YhLoy0tLS0tLS0tLS0tLS +0tLS0tLX01/PpaWlpaXVaWvrr66WlpaWl1WlpaXVdV0XReNeNeNeJeBl4F6demZelFekFejBeijX +5fEvy6JflkC/LYV+Wwr8vhXoYk1SNl6cF4RXjZdGXRdV1XVdV1WlpaWlpaWlpaWlr/raWl1XVdV0 +XReNeNeNeNeJl4mXiZeJl4mXiZeNl42XRl0ZdGXVl0ZdGXRl42XRl0ZdF1XVdV1WlpaWlpa/k0tL +X/b1/Pv+zpaWlpaWlplpab/oa/7GvppaWlpaWlpaWlpdV1Wl1XVdV1XVaXVaXVdVpaWlpa/n0tfT +X10tLS0tLX9/2XsvZey9l7L2/wBDtbW1tbW1tbW/5tLX8+lpaWlpaWlpaWlr/pdmZ+4p303lBf47 +Mm911WlpaWvppa+mlpaXYWXlBMQutLyDvS1/0PIO/wC7v67W1tbW1tbW1tbW1tbXuvde69/ppaWl +paWlpaWlr+fS19NLS1/29LS0tLS0tLS19Nf6d/Zpb8cajyMZuQBK0xlBO4AcczlDNodWIjK1HEMI +f23bs08ARxUv6i3NT0MVt5a+NEZ2+rv1aCXzN/a2pj6xUGGxLtZK29c43LxbW/7OlpaWlpa/k0tL +X8mv+ttbW1tbW/rv+xpaWlpaWlpaWv8Aoa/k0tLS0tLS0tLS0tLX/auyERtqvI8pHZqu8FjKwrGT +eSteZ5Vjp/JVhLRgUltU5ye2dsxs2r7i0s0jV4rrlBRuvJN55bD0rxyyhcIbdi+YLfttW3/Qxf8A +9hIXWOD3lpT+GvRtlJZs2nEp3sVVJM89bFMcjTWSKSaSem/qmeCPyWgp2DKWK47TndMZp7BPLcM6 +itzFELWpJY4LXnipS+AattyuXZZa6af+m7WLAY+288v+h2t/T3Xv/LpaWlr/AHulpaWlpaWlpaWl +paWlpa+mlpaWkfwyIy+nyISib/vyU8Xliry+lMa+6Veb0r2meCrWmCPH473yV0e9uSqEpXf+HDxt +45YBq1aTkcUMIVgeNpcnmvdm/arf/Bjmd7skFmZHWGrTxAN1p/8A2nbpk7rM8FNv/bsR/wDFrn1y +WRZngbbYwJwGljP/AJkEbS5I4BaWhILWspI0jZD/AIMa/XGwNu7ihYrAf/b5b9kxax9EmemzCK2t +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 +m5fmxaMI+Divg+q04wSlEhq8UR13eTTdrkNi3/QyL4q0VSpF44o6GvbxHKPku1grBaE2Ldyycj+h +91s8CXk6OVf55SUFbI6sJdM5U87amt6T4oX1ji6miGrFyflMlCnyXRJZL/4kLzYsifgmk0LCyVy7 +Kr8Rjoa2s72ookiMcnFIW1WUWLLKJtKWDn8Uejqy/wBiOlx8k4av+jP+qlFU1k1NSWo7ltB5NP8A +CjyPvG1qJbfRWCVXRYvjaUm3gUPDK+N+i3taQ6Yq2js87dmF/lldYNPVlozyfU60XBV5M3g0ZazW +GT19XSdIjLmPSbZCXA8EmxdUXYirZdke7Fs0JeGSGVYt2VZRJGV2WRkUmOJBZJYZKkiLhq+2XZ6W +po5gyH1i/wBkf9Vp1ZqarnKxtyKNHT5ZFtbRzTFbLd0TeKQlxR/Qo0TZVC2eSKUfsSaw97Irzvli +HH/LranpQ5HH2+pLyNuyEHKSHJaePBa1JEtFJ2cU+j003kgkdyHk4kSWMmChWuzveUaGvvcqE7ON +npji0QY0JElkmdEfqHVDdu/t0Y0t8WY6G3eBHFicmRReaOXJ/wBEVeRtGPJaORf2NbUJbJFroop/ +dFqStDfE5e/j9v1SvTNTUv2+DjZo/wDa9xN4cn2aM6lbFqfJf/EqxYL91lllo8ER5Mp0dbscRx+6 +TSIveiuLFkTGrR6fInofA0VQlbHpSeELR4xyacOUjTTSyW7pjOxY2fQysHJdIn8sjnb9fZR+jrvb +syt1RZ5++X/cfFdHRLof5xZJXg0tRx/7cjlHlwsm+KJ60aHp+CuI26yY6ZHTSZFYERzk6IdlJIlj +KFl0PBXkfglGzLWRbUUNDW62kl2y0uj1SOopbMSOORFFD01LwPQQtLiyMl0Ti5OiEVHGzyL9dlfJ +jeuTMiwNcnkSS62p+BNrs738jrboZe1mfg7IO19s9bi+NEr0Y+1WepFq0equmLMXEU0+yd82zTS9 +TlM1HdGorolp8hwfkl0aWlB5kamnn2kI3GvJFs6R/ZwVCvyP4I4JvAx9rayjJZyW726Q8jRxZlFJ +5IlFFfZW9Eva+RLKx2RfJGVs3yiJt5JN1e7ihRvplUJRfk4/sS/e/wCxvdNLscol/IrfRHvO1iIF +7P8AZfyaqm3zFqPwMlFxOeLFJvI5D9wsf0R+GdD1HLBOGckJcXkdiZV5I4Zd9FtCdjRhEmnGhfbf +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 +vqVK+ivoqVKlSpUqVKlSpUqVKlSpX0qVKiDaYF5AyOKWc0lg4GdCxKHwZzdBknnh6wO0w1kdx9/8 +mY+adq1knrj3mUfq5F8/KOebk1cBP6yy/lz4lur7c4uUrW4MQ4ah9jUu4pOhs5ExgwtsYq0dwUxf +Fy4VzpUW9PaaQSsTqMwo+SmJa3FYK8H9wjkPlKlNzrIgvVekEDwBR6fRG50sMuzy8lZG8eIaBNJM +kqTypQyOKCc05BsjnhroYqj2lJpWWuo9v9l4xE/biAdZlJ4sK+ZjF4RiKlx8jqvMD81bHRviVHIB +KeltVCHa5h28QGYnKHXvNP8A2V/1BiAFoTlo7Cgcji0FgxSVuKn018x2i2s132qG8EMypyNeiXiJ +uq0Ka066xl3L3X3hM7oaBohxDbwLKcH9yjYfS+0KJAAaNeZZo36MVG13Sj0I2WFySggyOEKc0lg2 +fzAr6KJUogCW06GzkTFhhbYxVpUqVKlSpUqVKlSo6UZlZBBkcAs5pLBslSpX0qV9a+lQdJpMbORM +WGFtjFWlSpUr6VKlSvpUqOlmdWQQZEoFOaSwbJUqVKlSpUqVKlQVLadDZyJiwwtsYq0qV9KlSpUq +VKjiVHSwuaUEGRwCnNJYNn0r+FfxqCILTobORMWGFtjFWkqV9alSpUqVKj5YXqyCDI4BTmksGyVK +lSpX1qV9Qktp0NnImLDC2xirT+VS/wCFRI1wwh0pae4Pb6WIuXLhSX9Fy5f0uXL+mfpmUypVlTrs +yvKzPWKsE8HL1/8AIAePmvMYxUNJnZRSuvJ73KlSpUZlahgFha4ylSpUqVKlV/CvrUr61/8APUqV +9KlSvpUqVKlSvpX/AIV9a+lfSv4VK/jUr619a+lfSpUr6VKlfWpX0r66/jX/AIVKlfSvpUqV9a+l +SpX0V9FfUqVKlSpUqVKlSpUqH0V9a+tfxvYB1sIvY/m/L/yEQJQDAfU+mDYa/A5jALBpQ+n8K/jU +qVKlfxqVK+lfWpUr+NfSv/4upX0qV/6V9agfx//aAAwDAQACAAMAAAAQlvHp6iiGW+47CHL2CCTH +HWD/AB16s6+3xwx6ErFn3rzr5oITRTYhQRgtjQrTPe8ZxfwO3DzhCweaQUgOl/HbPzwUyQ+zVpF+ +4vwls9gzTChZutrzlDSLlgiwN4XEt4taAs7eswZUu3N1cOJLTtpw3BXl3nAIOKmvpbzXWxhgl4d0 +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 +/wDAV7yMAMS//iE/8n/6AT/+fMmIOAOshbiUcIzTEh6/8mJJ9/8AnOSc5MiYkMCzxh6YnOsTGjI3 ++snjAhcnrNGf/9naZgIQgAEADQAAAEtJVFRFTn4xLkpQRwCNAwIRgAYAuA0AAAEACQAAA9wGAAAA +ACEGAAAAAAUAAAAJAgAAAAAFAAAAAQL///8ApQAAAEELxgCIACAAIAAAAAAAIAAgAAAAAAAoAAAA +IAAAAEAAAAABAAEAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAIQYAAEELRgBmACAAIAAAAAAAIAAgAAAAAAAoAAAAIAAAACAAAAABABgA +AAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAkZCPkI+Oj46Njo6MjY2LjYyLjIuKi4qJioqIiomHiYiGiIeGh4aFhoaEhoWDhYSChIOBg4KB +g4KAgoF9gYB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkZGQ+/v6+/v6+/v6+/v6 ++/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6+/v6goF9AAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkpKQ+/v69/b19/b19/b19/b19/b19/b19/b19/b19/b1 +9/b19/b19/b19/b19/b19/b19/b19/b1+/v6g4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAk5KR+/v79/f29/b29/b29/b19/b19/b19/b19/b19/b19/b19/b19/b19/b19/b19/b1 +9/b19/b1+/v6g4KBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlJOS/Pv7+Pf2+Pf2 ++Pf2+Pf2+Pf29/f29/b29/b19/b19/b19/b19/b19/b19/b19/b19/b19/b1+/v6hIOBAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlJST/Pv7+Pf2+Pf2+Pf2+Pf2+Pf2+Pf2+Pf2+Pf2 +9/b29/b19/b19/b19/b19/b19/b19/b19/b1+/v6hYSCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAlZWU/Pv7+Pf213YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA +13YA13YA9/b1+/v6hoWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlpWV/Pv7+Pf3 +13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA9/b1+/v6hoaEAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl5aV/Pz7+fj313YA13YA13YA13YA13YA13YA +13YA13YA13YA13YA13YA13YA13YA13YA13YA9/b1+/v6h4aFAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAl5eW/Pz7+fj313YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA35g8 +13YA13YA13YA9/b1+/v6iIeGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmJiX/Pz7 ++fj313YA13YA13YA13YA13YA13YA13YA13YA13YA13YA5qte2YAN13YA13YA13YA9/b1+/v6iYiG +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmZmY/Pz8+fj413YA13YA13YA13YA13YA +13YA13YA13YA13YA4Zo+67yA13YA13YA4aBL13YA9/b2+/v6iomHAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAmpmZ/Pz8+fn413YA5Khb13YA13YA13YA13YA13YA13YA3Ike+u7f2YAN +13YA2YAN9u/n13YA+Pf2+/v6ioqIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAm5qa +/fz8+vn413YA9/Ho3ZAs13YA13YA13YA13YA13YA+ObP6LJt13YA13YA7s+p+Pf213YA+Pf2+/v7 +i4qJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAm5ua/Pz8+fn413YA+vn48+HK2YAO +13YA13YA13YA8Myf+/r57Mia13YA5rBq+Pf3+Pf213YA+Pf2/Pv7jIuKAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAnJyb/fz8+vn413YA+vn4+fj47Mib13YA13YA4Jg8+fj4+fj4+fj3 +7tCq9/Do+Pj3+Pf313YA+Pf2/Pv7jYyLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +nZ2c/f38+vn513YA+vn4+vn4+vn45Khb24gd9/Ho+fn4+fj4+fj4+fj3+fj3+fj3+Pj313YA+Pf2 +/Pv7jY2LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnp2d/fz8+vn513YA+vn5+vr5 ++vn4+PHp9ena+vn4+vn4+fn4+fj4+fj4+fj3+fj3+Pj313YA+Pf2/Pv7jo6MAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAnp6e/f38+/r513YA+vn5+vn5+vn5+vr5+vn4+fn4+vn4+fn4 ++fn4+fj4+fj3+fj3+fj313YA+Pf2/Pv7j46NAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAn5+f/f38+vr513YA+vr5+/r5+vn5+vn5+vn4+vn4+fj4+vn4+fn4+fj4+fj4+fj3+fj313YA ++Pf3/Pv7kI+OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoKCg/f39+/r613YA13YA +13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA13YA+Pf3/Pv7kZCPAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoaGg/f39+/r6+/r6+/r6+vr5+vr5+/r5+vn5+vr5+vn4 ++fj4+vn4+fn4+fj46eno6ejn6ejn6Ojn7OvrkZGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAoqGh/f39+/v6+/r6+/r6+vr6+vr5+vr5+vn5+vn5+vn4+fn4+vn4+fn4/Pz8pqamjIyM +jIyMjIyMjIyMkpKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoqKi/f39+/v6+/v6 ++/r6+/r6+vr5+vr5+vn5+vn5+vn4+vn4+vn4+fn4/Pz8pqam6+vr6enp5eXl09PTjIuLAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo6Oj/f39+/v7+/v6+/r6+/r6+vr5+vr5+/r5+vn5 ++vr5+vn4+vn4+fn4/Pz8pqam7+/v7Ozs2dnYjo2MGhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAApKSk/f39+/v7+/v6+/r6+/r6+vr6+vr5+vr5+vn5+vr5+vn4+vn4+fn4/Pz8pqam +8vLy3t3dj4+OGhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApaWl/f39/f39 +/f39/f39/f39/f38/f38/f38/fz8/fz8/fz8/fz8/Pz8/v7+pqam4ODgkZGQGhoaAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApaWlpaWlpKSko6OjoqKioqGhoaGgoKCgn5+f +np6enp2dnZ2cnJybm5uam5qampmZk5OSGhoaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAWjcCBZAGAMgBAAAZAAAAAwAgDtvHBQAeAAEwAQAAACkA +AABraXR0ZW4tcGxheWluZy13aXRoLWEtY2hyaXN0bWFzLXRyZWUuanBnAAAAAEAABzCg6d3hhJTU +AUAACDBA+UpehZTUAQIBAjcBAAAAAAAAAB4AAzcBAAAABQAAAC5qcGcAAAAAAwAFNwEAAAAeAAc3 +AQAAACkAAABraXR0ZW4tcGxheWluZy13aXRoLWEtY2hyaXN0bWFzLXRyZWUuanBnAAAAAAMACzcA +AAAAAwAUNwAAAAADAPp/AAAAAEAA+38AQN2jV0WzDEAA/H8AQN2jV0WzDAMA/X8AAAAACwD+fwAA +AAALAP9/AAAAAB4AC4F/fzWW4VnQR5mnRlFcGDtUAQAAACwAAABBAHQAdABhAGMAaABtAGUAbgB0 +AE8AcgBpAGcAaQBuAGEAbABVAHIAbAAAAAEAAAABAAAAAAAAAAMAIQ6lMgIAAwD3DwAAAAACAfgP +AQAAABAAAAAXAIhiZVwvQr6PqBJjos0qAgH5DwEAAAAEAAAApTICAAIB+g8BAAAAEAAAAOyulC30 +UBNEkJODXut1B/ADAP4PBwAAAAMADTT9P60OAwAPNP0/rQ7baAAAAAIBAjcBAAAAAAAAAAMABTcF +AAAAAwALN1AHAAADABQ3AAAAAAMA+n8AAAAAQAD7fwBA3aNXRbMMQAD8fwBA3aNXRbMMAwD9fwAA +AAALAP5/AAAAAAsA/38AAAAAAwAhDoUyAgACAfgPAQAAABAAAAAXAIhiZVwvQr6PqBJjos0qAgH6 +DwEAAAAQAAAA7K6ULfRQE0SQk4Ne63UH8AMA/g8HAAAAAwANNP0/rQ4DAA80/T+tDsSt + +------=_NextPart_000_0001_01D4945F.67C9A820-- diff --git a/UnitTests/TestData/tnef/rtf/message.rtf b/UnitTests/TestData/tnef/rtf/message.rtf new file mode 100644 index 0000000000..8581bd8c96 Binary files /dev/null and b/UnitTests/TestData/tnef/rtf/message.rtf differ diff --git a/UnitTests/TestData/tnef/triples/message.rtf b/UnitTests/TestData/tnef/triples/message.rtf new file mode 100644 index 0000000000..9ff27f0135 Binary files /dev/null and b/UnitTests/TestData/tnef/triples/message.rtf differ diff --git a/UnitTests/TestData/tnef/triples/message.txt b/UnitTests/TestData/tnef/triples/message.txt new file mode 100644 index 0000000000..2dcec2378a --- /dev/null +++ b/UnitTests/TestData/tnef/triples/message.txt @@ -0,0 +1 @@ +Sample description diff --git a/UnitTests/TestData/tnef/two-files/AUTHORS b/UnitTests/TestData/tnef/two-files/AUTHORS new file mode 100644 index 0000000000..cdb2e018cd --- /dev/null +++ b/UnitTests/TestData/tnef/two-files/AUTHORS @@ -0,0 +1,8 @@ + + Authors of tnef + =============== + +* Mark Simpson damned@world.std.com + +Many thank go to the original author: Thomas Boll (tb@boll.ch). + diff --git a/UnitTests/TestData/tnef/two-files/README b/UnitTests/TestData/tnef/two-files/README new file mode 100644 index 0000000000..c5c0805bf1 --- /dev/null +++ b/UnitTests/TestData/tnef/two-files/README @@ -0,0 +1,31 @@ + + TNEF + ==== + +TNEF is a program for unpacking MIME attachments of type +"application/ms-tnef". This is a Microsoft only attachment. + +Due to the proliferation of Microsoft Outlook and Exchange mail servers, +more and more mail is encapsulated into this format. + +The TNEF program allows one to unapck the attachments which were +encapsulated into teh TNEF attachment. Thus alleviating the need to use +Microsoft Outlook to view the attachment. + +TNEF is mainly testsed and used on GNU/Linux and CYGWIN systems. It +'should' work on other UNIX and UNIX-like systems. + +See the file COPYING for copyright and warranty information. + +See the file INSTALL for instructions on installing TNEF. The short form +for installation is the standard: + + tar xzvf tnef-x.y.tar.gz + cd tnef-x.y + ./configure + make + make install + + + + diff --git a/UnitTests/TestData/tnef/ukr.eml b/UnitTests/TestData/tnef/ukr.eml old mode 100755 new mode 100644 diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name.list b/UnitTests/TestData/tnef/unicode-mapi-attr-name.list new file mode 100644 index 0000000000..d133fb0f20 --- /dev/null +++ b/UnitTests/TestData/tnef/unicode-mapi-attr-name.list @@ -0,0 +1,4 @@ +spaconsole2.cfg +image001.png +image002.png +image003.png \ No newline at end of file diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name.tnef b/UnitTests/TestData/tnef/unicode-mapi-attr-name.tnef new file mode 100644 index 0000000000..583675eb6f Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr-name.tnef differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name/image001.png b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image001.png new file mode 100644 index 0000000000..dcacee578a Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image001.png differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name/image002.png b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image002.png new file mode 100644 index 0000000000..ebf45654f1 Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image002.png differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name/image003.png b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image003.png new file mode 100644 index 0000000000..4f714a34d3 Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr-name/image003.png differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name/message.html b/UnitTests/TestData/tnef/unicode-mapi-attr-name/message.html new file mode 100644 index 0000000000..691a9bed6c --- /dev/null +++ b/UnitTests/TestData/tnef/unicode-mapi-attr-name/message.html @@ -0,0 +1,69 @@ +

Przesyłam poprawiony plik

Proszę o wrzucenie J

 

Proszę o aktualizacje tych paneli na telefonach

2215

MAC „E05FB9821FD6”

2286

MAC „E05FB98221EA”

 

 

 

+

Marcin Jabłonkowski
Specjalista ds. IT

+

Tel.   +48 22 250 55 06
Fax   +48 22 448 72 +68
Kom. +48 508 686 161
E-mail M.Jablonkowski@promedica24.pl


From: serwis@thulium.pl [mailto:serwis@thulium.pl]
Sent: Friday, June 20, 2014 11:37 AM
To: Marcin Jabłonkowski
Subject: [ZGLOSZENIE] THU#29044 Aktualizacja numerów w dodatkowych panelach

 

W załączniku plik.
W razie problemów, proszę podesłać numery to będziemy aktualizować.
--
Marek Solarski

Serwis Thulium: 12 397 53 01


Oceń obsługę klikając w odpowiednią buźkę

\ No newline at end of file diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr-name/spaconsole2.cfg b/UnitTests/TestData/tnef/unicode-mapi-attr-name/spaconsole2.cfg new file mode 100644 index 0000000000..e407c4a96f --- /dev/null +++ b/UnitTests/TestData/tnef/unicode-mapi-attr-name/spaconsole2.cfg @@ -0,0 +1,145 @@ + +Yes +1 +Yes +Asterisk +No +*98 + +No + + + + + + + + + + + + +fnc=blf+sd;sub=5602@10.34.39.104;name=5602 + +fnc=blf+sd;sub=2221@10.34.39.104;name=2221 +fnc=blf+sd;sub=2249@10.34.39.104;name=2249 +fnc=blf+sd;sub=5634@10.34.39.104;name=5634 +fnc=blf+sd;sub=5536@10.34.39.104;name=5536 + +fnc=blf+sd;sub=5542@10.34.39.104;name=5542 +fnc=blf+sd;sub=5587@10.34.39.104;name=5587 + +fnc=blf+sd;sub=2296@10.34.39.104;name=2296 + +fnc=blf+sd;sub=5538@10.34.39.104;name=5538 + +fnc=blf+sd;sub=5694@10.34.39.104;name=5694 + +fnc=blf+sd;sub=2248@10.34.39.104;name=2248 +fnc=blf+sd;sub=5534@10.34.39.104;name=5534 + +fnc=blf+sd;sub=5675@10.34.39.104;name=5675 + +fnc=blf+sd;sub=2275@10.34.39.104;name=2275 + +fnc=blf+sd;sub=5584@10.34.39.104;name=5584 + +fnc=blf+sd;sub=5549@10.34.39.104;name=5549 + +fnc=blf+sd;sub=5655@10.34.39.104;name=5655 + +fnc=blf+sd;sub=5624@10.34.39.104;name=5624 + +fnc=blf+sd;sub=2286@10.34.39.104;name=2286 + +fnc=blf+sd;sub=2256@10.34.39.104;name=2256 + +fnc=blf+sd;sub=5530@10.34.39.104;name=5530 + +fnc=blf+sd;sub=5554@10.34.39.104;name=5554 + +fnc=blf+sd;sub=2220@10.34.39.104;name=2220 + +fnc=blf+sd;sub=2293@10.34.39.104;name=2293 + +fnc=blf+sd;sub=5593@10.34.39.104;name=5593 + +fnc=blf+sd;sub=2218@10.34.39.104;name=2218 + +fnc=blf+sd;sub=2206@10.34.39.104;name=2206 + +fnc=blf+sd;sub=2245@10.34.39.104;name=2245 + +fnc=blf+sd;sub=2213@10.34.39.104;name=2213 + +fnc=blf+sd;sub=5561@10.34.39.104;name=5561 + +fnc=blf+sd;sub=5526@10.34.39.104;name=5526 + +fnc=blf+sd;sub=2255@10.34.39.104;name=2255 + +fnc=blf+sd;sub=5568@10.34.39.104;name=5568 + +fnc=blf+sd;sub=5678@10.34.39.104;name=5678 + +fnc=blf+sd;sub=2211@10.34.39.104;name=2211 + +fnc=blf+sd;sub=5553@10.34.39.104;name=5553 + +fnc=blf+sd;sub=2223@10.34.39.104;name=2223 + +fnc=blf+sd;sub=5649@10.34.39.104;name=5649 + +fnc=blf+sd;sub=2246@10.34.39.104;name=2246 + +fnc=blf+sd;sub=5529@10.34.39.104;name=5529 + +fnc=blf+sd;sub=5562@10.34.39.104;name=5562 + +fnc=blf+sd;sub=2274@10.34.39.104;name=2274 + +fnc=blf+sd;sub=5661@10.34.39.104;name=5661 + +fnc=blf+sd;sub=2297@10.34.39.104;name=2297 + +fnc=blf+sd;sub=2215@10.34.39.104;name=2215 + +fnc=blf+sd;sub=2282@10.34.39.104;name=2282 + +fnc=blf+sd;sub=5520@10.34.39.104;name=5520 + +fnc=blf+sd;sub=2219@10.34.39.104;name=2219 + +fnc=blf+sd;sub=2240@10.34.39.104;name=2240 + +fnc=blf+sd;sub=2294@10.34.39.104;name=2294 + +fnc=blf+sd;sub=5667@10.34.39.104;name=5667 + +fnc=blf+sd;sub=2281@10.34.39.104;name=2281 + +fnc=blf+sd;sub=5546@10.34.39.104;name=5546 + +fnc=blf+sd;sub=5563@10.34.39.104;name=5563 + +fnc=blf+sd;sub=5594@10.34.39.104;name=5594 + +fnc=blf+sd;sub=5545@10.34.39.104;name=5545 + +fnc=blf+sd;sub=5633@10.34.39.104;name=5633 + +fnc=blf+sd;sub=2217@10.34.39.104;name=2217 + +fnc=blf+sd;sub=2266@10.34.39.104;name=2266 + +fnc=blf+sd;sub=5559@10.34.39.104;name=5559 + +fnc=blf+sd;sub=5514@10.34.39.104;name=5514 + +fnc=blf+sd;sub=5591@10.34.39.104;name=5591 + +fnc=blf+sd;sub=2273@10.34.39.104;name=2273 + +fnc=blf+sd;sub=5503@10.34.39.104;name=5503 + + diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr.list b/UnitTests/TestData/tnef/unicode-mapi-attr.list new file mode 100644 index 0000000000..e85b45dd75 --- /dev/null +++ b/UnitTests/TestData/tnef/unicode-mapi-attr.list @@ -0,0 +1 @@ +example.dat \ No newline at end of file diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr.tnef b/UnitTests/TestData/tnef/unicode-mapi-attr.tnef new file mode 100644 index 0000000000..d093384058 Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr.tnef differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr/example.dat b/UnitTests/TestData/tnef/unicode-mapi-attr/example.dat new file mode 100644 index 0000000000..74f24e204a Binary files /dev/null and b/UnitTests/TestData/tnef/unicode-mapi-attr/example.dat differ diff --git a/UnitTests/TestData/tnef/unicode-mapi-attr/message.html b/UnitTests/TestData/tnef/unicode-mapi-attr/message.html new file mode 100644 index 0000000000..bcaef30635 --- /dev/null +++ b/UnitTests/TestData/tnef/unicode-mapi-attr/message.html @@ -0,0 +1,12 @@ + + + + + + +
+

​hello world
+

+
+ + diff --git a/UnitTests/TestData/tnef/winmail.tnef b/UnitTests/TestData/tnef/winmail.tnef old mode 100755 new mode 100644 diff --git a/UnitTests/TestData/tnef/winmail/Untitled Attachment.1 b/UnitTests/TestData/tnef/winmail/Untitled Attachment.1 new file mode 100644 index 0000000000..5cd5541236 Binary files /dev/null and b/UnitTests/TestData/tnef/winmail/Untitled Attachment.1 differ diff --git a/UnitTests/TestData/tnef/winmail/Untitled Attachment.2 b/UnitTests/TestData/tnef/winmail/Untitled Attachment.2 new file mode 100644 index 0000000000..8992120eb2 Binary files /dev/null and b/UnitTests/TestData/tnef/winmail/Untitled Attachment.2 differ diff --git a/UnitTests/TestData/tnef/winmail/message.rtf b/UnitTests/TestData/tnef/winmail/message.rtf new file mode 100644 index 0000000000..62e2acac46 --- /dev/null +++ b/UnitTests/TestData/tnef/winmail/message.rtf @@ -0,0 +1,65 @@ +{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;} +{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};} +{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\f38\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'cb\'ce\'cc\'e5;}{\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\f31501\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;} +{\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\f31505\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} +{\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f60\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f61\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;} +{\f63\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f64\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f65\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f66\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);} +{\f67\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f68\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f172\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};} +{\f172\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f410\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f411\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f413\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;} +{\f414\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f417\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f418\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f422\fbidi \fnil\fcharset0\fprq2 @\'cb\'ce\'cc\'e5 Western;} +{\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31520\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;} +{\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}{\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\f31536\fbidi \froman\fcharset163\fprq2 Cambria (Vietnamese);} +{\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\f31560\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;} +{\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\f40\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f41\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f43\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f44\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\f45\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f46\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f47\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\f48\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0; +\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue255;\red128\green0\blue128;} +{\*\defchp \fs21\kerning2\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{ +\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 +\snext0 \sqformat \spriority0 Normal;} +{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;} +{\*\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 +\snext11 \ssemihidden \sunhideused Normal Table;} +{\*\cs15 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf17 \sbasedon10 \ssemihidden \sunhideused \styrsid8806070 Hyperlink;} +{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf18 \sbasedon10 \ssemihidden \sunhideused \styrsid8806070 FollowedHyperlink;}{\s17\ql \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 +\af2\afs21\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f37\hich\af2\dbch\af13\cgrid\langnp1033\langfenp2052 \sbasedon0 \snext17 \slink18 \sunhideused \styrsid8806070 Plain Text;} +{\*\cs18 \additive \rtlch\fcs1 \af2\afs21 \ltrch\fcs0 \fs21\loch\f37\hich\af2\dbch\af13 \sbasedon10 \slink17 \slocked \styrsid8806070 \'b4\'bf\'ce\'c4\'b1\'be Char;}{ +\s19\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs18\alang1025 \ltrch\fcs0 \fs18\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052 +\sbasedon0 \snext19 \slink20 \ssemihidden \sunhideused \styrsid8806070 Balloon Text;} +{\*\cs20 \additive \rtlch\fcs1 \af0\afs18 \ltrch\fcs0 \fs18 \sbasedon10 \slink19 \slocked \ssemihidden \styrsid8806070 \'c5\'fa\'d7\'a2\'bf\'f2\'ce\'c4\'b1\'be Char;}}{\*\revtbl {Unknown;}}{\*\rsidtbl \rsid8073230\rsid8806070\rsid11085733}{\mmathPr\mmathFont34\mbrkBin0 +\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw12240\paperh15840\margl1800\margr1800\margt1440\margb1440\gutter0\ltrsect +\deftab420\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\formshade\horzdoc\dgmargin\dghspace180\dgvspace156 +\dghorigin136\dgvorigin0\dghshow0\dgvshow2\jcompress\viewkind5\viewscale110\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot8073230 +\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0{\*\wgrffmtfilter 2450} +\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl3 +\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang +{\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang +{\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s17\ql \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid8806070 \rtlch\fcs1 \af2\afs21\alang1025 \ltrch\fcs0 +\fs21\lang1033\langfe2052\kerning2\loch\af37\hich\af2\dbch\af13\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\insrsid8806070 \hich\af2\dbch\af13\loch\f37 111111111111111111111111111111111111111111111 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\lang1024\langfe1024\noproof\insrsid8073230\charrsid10250154 \objattph }{\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\insrsid8806070 +\par }\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}} +{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7 +\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}} +\pard\plain \ltrpar\s17\ql \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid8806070 \rtlch\fcs1 \af2\afs21\alang1025 \ltrch\fcs0 +\fs21\lang1033\langfe2052\kerning2\loch\af37\hich\af2\dbch\af13\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\insrsid8806070 \hich\af2\dbch\af13\loch\f37 222222222222222222222222222222 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\lang1024\langfe1024\noproof\insrsid8073230\charrsid10250154 \objattph }{\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\insrsid8806070 +\par }\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}} +{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7 +\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}} +\pard\plain \ltrpar\s17\ql \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid8806070 \rtlch\fcs1 \af2\afs21\alang1025 \ltrch\fcs0 +\fs21\lang1033\langfe2052\kerning2\loch\af37\hich\af2\dbch\af13\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af2 \ltrch\fcs0 \cf0\insrsid8806070 \hich\af2\dbch\af13\loch\f37 3333333333333333333}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\cf0\insrsid8806070\charrsid8806070 +\par }} \ No newline at end of file diff --git a/UnitTests/TestHelper.cs b/UnitTests/TestHelper.cs new file mode 100644 index 0000000000..676225af16 --- /dev/null +++ b/UnitTests/TestHelper.cs @@ -0,0 +1,56 @@ +// +// TestHelper.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +namespace UnitTests { + static class TestHelper + { + public static readonly string ProjectDir; + + static TestHelper () + { + var codeBase = typeof (TestHelper).Assembly.CodeBase; + if (codeBase.StartsWith ("file://", StringComparison.OrdinalIgnoreCase)) + codeBase = codeBase.Substring ("file://".Length); + + if (Path.DirectorySeparatorChar == '\\') { + if (codeBase[0] == '/') + codeBase = codeBase.Substring (1); + + codeBase = codeBase.Replace ('/', '\\'); + } + + var dir = Path.GetDirectoryName (codeBase); + + while (Path.GetFileName (dir) != "UnitTests") + dir = Path.GetFullPath (Path.Combine (dir, "..")); + + ProjectDir = Path.GetFullPath (dir); + } + } +} diff --git a/UnitTests/Text/FlowedToHtmlTests.cs b/UnitTests/Text/FlowedToHtmlTests.cs new file mode 100644 index 0000000000..ddd2a0b91b --- /dev/null +++ b/UnitTests/Text/FlowedToHtmlTests.cs @@ -0,0 +1,236 @@ +// +// FlowedToHtmlTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class FlowedToHtmlTests + { + [Test] + public void TestArgumentExceptions () + { + var converter = new FlowedToHtml (); + var reader = new StringReader (""); + var writer = new StringWriter (); + + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, writer)); + Assert.Throws (() => converter.Convert (reader, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new FlowedToHtml (); + + Assert.IsFalse (converter.DeleteSpace, "DeleteSpace"); + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.FooterFormat, "FooterFormat"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.HeaderFormat, "HeaderFormat"); + Assert.IsNull (converter.HtmlTagCallback, "HtmlTagCallback"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Flowed, converter.InputFormat, "InputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Html, converter.OutputFormat, "OutputFormat"); + Assert.IsFalse (converter.OutputHtmlFragment, "OutputHtmlFragment"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); + } + + [Test] + public void TestSimpleFlowedToHtml () + { + string expected = "

This is some sample text that has been formatted " + + "according to the format=flowed rules defined in rfc3676. " + + "This text, once converted, should all be on a single line.

" + Environment.NewLine + + "
" + Environment.NewLine + + "
" + Environment.NewLine + + "
" + Environment.NewLine + + "
" + Environment.NewLine + + "

And this line of text should be separate by 4 blank lines.

" + Environment.NewLine; + string text = "This is some sample text that has been formatted " + Environment.NewLine + + "according to the format=flowed rules defined in rfc3676. " + Environment.NewLine + + "This text, once converted, should all be on a single line." + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + Environment.NewLine + + "And this line of text should be separate by 4 blank lines." + Environment.NewLine; + var converter = new FlowedToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestIncreasingQuoteLevels () + { + string expected = "

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + + "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + + "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + + "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + + "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + + "

Any complaints?

" + Environment.NewLine + + "
"; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + "> reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>> unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>>> enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">>>>> styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new FlowedToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestDecreasingQuoteLevels () + { + string expected = "

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + + "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + + "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + + "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + + "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + + "

Any complaints?

" + Environment.NewLine + + "
"; + string text = ">>>>>> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + ">>>>>> reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">>>>> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">>>>> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>>> unmuzzled ratsbane!" + Environment.NewLine + + ">>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>> enforced, including the use of only upper case." + Environment.NewLine + + ">> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">> styles, of late." + Environment.NewLine + + "> Any complaints?" + Environment.NewLine; + var converter = new FlowedToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestBrokenlyQuotedText () + { + // Note: this is the brokenly quoted sample from rfc3676 at the end of section 4.5 + string expected = "

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + + "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + + "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + + "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + + "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + + "

Any complaints?

" + Environment.NewLine + + "
"; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + "> reeky elf-skinned pigeon-egg! " + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>> unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>>> enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">>>>> styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new FlowedToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestTextHeaderAndFooter () + { + string expected = "On <date>, so-and-so said:

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + + "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + + "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + + "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + + "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + + "

Any complaints?

" + Environment.NewLine + + "
Tha-tha-tha-tha that's all, folks!
"; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + "> reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>> unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>>> enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">>>>> styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new FlowedToHtml { + Header = "On , so-and-so said:" + Environment.NewLine, + HeaderFormat = HeaderFooterFormat.Text, + Footer = "Tha-tha-tha-tha that's all, folks!" + Environment.NewLine, + FooterFormat = HeaderFooterFormat.Text, + HtmlTagCallback = null + }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestSimpleFlowedWithUrlsToHtml () + { + string expected = "

Check out http://www.xamarin.com - it's amazing!

" + Environment.NewLine; + string text = "Check out http://www.xamarin.com - it's amazing!" + Environment.NewLine; + var converter = new FlowedToHtml { Header = null, Footer = null, OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + } +} diff --git a/UnitTests/Text/FlowedToTextTests.cs b/UnitTests/Text/FlowedToTextTests.cs new file mode 100644 index 0000000000..708b2ec684 --- /dev/null +++ b/UnitTests/Text/FlowedToTextTests.cs @@ -0,0 +1,149 @@ +// +// FlowedToTextTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class FlowedToTextTests + { + [Test] + public void TestArgumentExceptions () + { + var converter = new FlowedToText (); + var reader = new StringReader (""); + var writer = new StringWriter (); + + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, writer)); + Assert.Throws (() => converter.Convert (reader, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new FlowedToText (); + + Assert.IsFalse (converter.DeleteSpace, "DeleteSpace"); + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Flowed, converter.InputFormat, "InputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Text, converter.OutputFormat, "OutputFormat"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); + } + + [Test] + public void TestSimpleFlowedToText () + { + string expected = "This is some sample text that has been formatted " + + "according to the format=flowed rules defined in rfc3676. " + + "This text, once converted, should all be on a single line." + Environment.NewLine; + string text = "This is some sample text that has been formatted " + Environment.NewLine + + "according to the format=flowed rules defined in rfc3676. " + Environment.NewLine + + "This text, once converted, should all be on a single line." + Environment.NewLine; + var converter = new FlowedToText { Header = null, Footer = null }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestQuotedFlowedToText () + { + string expected = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + "> reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>> unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>>> enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">>>>> styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new FlowedToText { Header = null, Footer = null }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestBrokenQuotedFlowedToText () + { + // Note: this is the brokenly quoted sample from rfc3676 at the end of section 4.5 + string expected = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg! " + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + + "> reeky elf-skinned pigeon-egg! " + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + + ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + + ">>> unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + + ">>>> enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + + ">>>>> styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new FlowedToText { Header = null, Footer = null }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + } +} diff --git a/UnitTests/Text/HtmlAttributeTests.cs b/UnitTests/Text/HtmlAttributeTests.cs index b714e10846..fa3b207673 100644 --- a/UnitTests/Text/HtmlAttributeTests.cs +++ b/UnitTests/Text/HtmlAttributeTests.cs @@ -1,9 +1,9 @@ -// +// // HtmlAttributeTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Text/HtmlEntityDecoderTests.cs b/UnitTests/Text/HtmlEntityDecoderTests.cs index 11c64b5b10..d14239fae9 100644 --- a/UnitTests/Text/HtmlEntityDecoderTests.cs +++ b/UnitTests/Text/HtmlEntityDecoderTests.cs @@ -1,9 +1,9 @@ -// +// // HtmlEntityDecoderTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,6 @@ // THE SOFTWARE. // -using System; using System.IO; using NUnit.Framework; @@ -39,7 +38,7 @@ public class HtmlEntityDecoderTests [Test] public void TestDecodeNamedEntities () { - var path = Path.Combine ("..", "..", "TestData", "html", "HtmlEntities.json"); + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "html", "HtmlEntities.json"); var decoder = new HtmlEntityDecoder (); using (var json = new JsonTextReader (new StreamReader (path))) { @@ -79,7 +78,7 @@ public void TestDecodeNamedEntities () if (!json.Read () || json.TokenType != JsonToken.EndObject) break; - for (int i = 0; i < name.Length && name[i] != ';'; i++) + for (int i = 0; i < name.Length; i++) Assert.IsTrue (decoder.Push (name[i]), "Failed to push char #{0} of \"{1}\".", i, name); Assert.AreEqual (value, decoder.GetValue (), "Decoded entity did not match for \"{0}\".", name); @@ -102,44 +101,44 @@ static void TestDecodeNumericEntity (string text, string expected) [Test] public void TestDecodeNumericEntities () { - TestDecodeNumericEntity ("�", "\uFFFD"); // REPLACEMENT CHARACTER - TestDecodeNumericEntity ("€", "\u20AC"); // EURO SIGN (€) - TestDecodeNumericEntity ("‚", "\u201A"); // SINGLE LOW-9 QUOTATION MARK (‚) - TestDecodeNumericEntity ("ƒ", "\u0192"); // LATIN SMALL LETTER F WITH HOOK (ƒ) - TestDecodeNumericEntity ("„", "\u201E"); // DOUBLE LOW-9 QUOTATION MARK („) - TestDecodeNumericEntity ("…", "\u2026"); // HORIZONTAL ELLIPSIS (…) - TestDecodeNumericEntity ("†", "\u2020"); // DAGGER (†) - TestDecodeNumericEntity ("‡", "\u2021"); // DOUBLE DAGGER (‡) - TestDecodeNumericEntity ("ˆ", "\u02C6"); // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) - TestDecodeNumericEntity ("‰", "\u2030"); // PER MILLE SIGN (‰) - TestDecodeNumericEntity ("Š", "\u0160"); // LATIN CAPITAL LETTER S WITH CARON (Š) - TestDecodeNumericEntity ("‹", "\u2039"); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) - TestDecodeNumericEntity ("Œ", "\u0152"); // LATIN CAPITAL LIGATURE OE (Œ) - TestDecodeNumericEntity ("Ž", "\u017D"); // LATIN CAPITAL LETTER Z WITH CARON (Ž) - TestDecodeNumericEntity ("‘", "\u2018"); // LEFT SINGLE QUOTATION MARK (‘) - TestDecodeNumericEntity ("’", "\u2019"); // RIGHT SINGLE QUOTATION MARK (’) - TestDecodeNumericEntity ("“", "\u201C"); // LEFT DOUBLE QUOTATION MARK (“) - TestDecodeNumericEntity ("”", "\u201D"); // RIGHT DOUBLE QUOTATION MARK (”) - TestDecodeNumericEntity ("•", "\u2022"); // BULLET (•) - TestDecodeNumericEntity ("–", "\u2013"); // EN DASH (–) - TestDecodeNumericEntity ("—", "\u2014"); // EM DASH (—) - TestDecodeNumericEntity ("˜", "\u02DC"); // SMALL TILDE (˜) - TestDecodeNumericEntity ("™", "\u2122"); // TRADE MARK SIGN (™) - TestDecodeNumericEntity ("š", "\u0161"); // LATIN SMALL LETTER S WITH CARON (š) - TestDecodeNumericEntity ("›", "\u203A"); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) - TestDecodeNumericEntity ("œ", "\u0153"); // LATIN SMALL LIGATURE OE (œ) - TestDecodeNumericEntity ("ž", "\u017E"); // LATIN SMALL LETTER Z WITH CARON (ž) - TestDecodeNumericEntity ("Ÿ", "\u0178"); // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + TestDecodeNumericEntity ("�", "\uFFFD"); // REPLACEMENT CHARACTER + TestDecodeNumericEntity ("€", "\u20AC"); // EURO SIGN (€) + TestDecodeNumericEntity ("‚", "\u201A"); // SINGLE LOW-9 QUOTATION MARK (‚) + TestDecodeNumericEntity ("ƒ", "\u0192"); // LATIN SMALL LETTER F WITH HOOK (ƒ) + TestDecodeNumericEntity ("„", "\u201E"); // DOUBLE LOW-9 QUOTATION MARK („) + TestDecodeNumericEntity ("…", "\u2026"); // HORIZONTAL ELLIPSIS (…) + TestDecodeNumericEntity ("†", "\u2020"); // DAGGER (†) + TestDecodeNumericEntity ("‡", "\u2021"); // DOUBLE DAGGER (‡) + TestDecodeNumericEntity ("ˆ", "\u02C6"); // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + TestDecodeNumericEntity ("‰", "\u2030"); // PER MILLE SIGN (‰) + TestDecodeNumericEntity ("Š", "\u0160"); // LATIN CAPITAL LETTER S WITH CARON (Š) + TestDecodeNumericEntity ("‹", "\u2039"); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + TestDecodeNumericEntity ("Œ", "\u0152"); // LATIN CAPITAL LIGATURE OE (Œ) + TestDecodeNumericEntity ("Ž", "\u017D"); // LATIN CAPITAL LETTER Z WITH CARON (Ž) + TestDecodeNumericEntity ("‘", "\u2018"); // LEFT SINGLE QUOTATION MARK (‘) + TestDecodeNumericEntity ("’", "\u2019"); // RIGHT SINGLE QUOTATION MARK (’) + TestDecodeNumericEntity ("“", "\u201C"); // LEFT DOUBLE QUOTATION MARK (“) + TestDecodeNumericEntity ("”", "\u201D"); // RIGHT DOUBLE QUOTATION MARK (”) + TestDecodeNumericEntity ("•", "\u2022"); // BULLET (•) + TestDecodeNumericEntity ("–", "\u2013"); // EN DASH (–) + TestDecodeNumericEntity ("—", "\u2014"); // EM DASH (—) + TestDecodeNumericEntity ("˜", "\u02DC"); // SMALL TILDE (˜) + TestDecodeNumericEntity ("™", "\u2122"); // TRADE MARK SIGN (™) + TestDecodeNumericEntity ("š", "\u0161"); // LATIN SMALL LETTER S WITH CARON (š) + TestDecodeNumericEntity ("›", "\u203A"); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + TestDecodeNumericEntity ("œ", "\u0153"); // LATIN SMALL LIGATURE OE (œ) + TestDecodeNumericEntity ("ž", "\u017E"); // LATIN SMALL LETTER Z WITH CARON (ž) + TestDecodeNumericEntity ("Ÿ", "\u0178"); // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) // parse error - TestDecodeNumericEntity ("􏿿", "􏿿"); + TestDecodeNumericEntity ("􏿿", "􏿿"); - TestDecodeNumericEntity ("�", "\uFFFD"); + TestDecodeNumericEntity ("�", "\uFFFD"); - TestDecodeNumericEntity ("", ""); + TestDecodeNumericEntity ("", ""); - TestDecodeNumericEntity (" ", " "); - TestDecodeNumericEntity ("z", "z"); + TestDecodeNumericEntity (" ", " "); + TestDecodeNumericEntity ("z", "z"); } } } diff --git a/UnitTests/Text/HtmlTagIdTests.cs b/UnitTests/Text/HtmlTagIdTests.cs new file mode 100644 index 0000000000..581278e671 --- /dev/null +++ b/UnitTests/Text/HtmlTagIdTests.cs @@ -0,0 +1,62 @@ +// +// HtmlTagIdTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class HtmlTagIdTests + { + [Test] + public void TestToHtmlTagId () + { + Assert.AreEqual (HtmlTagId.Unknown, "".ToHtmlTagId (), "string.Empty"); + Assert.AreEqual (HtmlTagId.Comment, "!".ToHtmlTagId (), "!"); + Assert.AreEqual (HtmlTagId.Comment, "!blah".ToHtmlTagId (), "!blah"); + Assert.AreEqual (HtmlTagId.A, "a".ToHtmlTagId (), "a"); + Assert.AreEqual (HtmlTagId.A, "A".ToHtmlTagId (), "A"); + Assert.AreEqual (HtmlTagId.Font, "font".ToHtmlTagId (), "font"); + Assert.AreEqual (HtmlTagId.Font, "FONT".ToHtmlTagId (), "FONT"); + Assert.AreEqual (HtmlTagId.Font, "FoNt".ToHtmlTagId (), "FoNt"); + } + + [Test] + public void TestIsFormattingElement () + { + var formattingElements = new[] { "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" }; + + foreach (var element in formattingElements) { + var tag = element.ToHtmlTagId (); + + Assert.IsTrue (tag.IsFormattingElement (), element); + } + + Assert.IsFalse ("body".ToHtmlTagId ().IsFormattingElement (), "body"); + } + } +} diff --git a/UnitTests/Text/HtmlTextPreviewerTests.cs b/UnitTests/Text/HtmlTextPreviewerTests.cs new file mode 100644 index 0000000000..21d5e38c50 --- /dev/null +++ b/UnitTests/Text/HtmlTextPreviewerTests.cs @@ -0,0 +1,158 @@ +// +// HtmlTextPreviewerTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit; +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class HtmlTextPreviewerTests + { + [Test] + public void TestArgumentExceptions () + { + var previewer = new HtmlTextPreviewer (); + + Assert.Throws (() => previewer.MaximumPreviewLength = 0); + Assert.Throws (() => previewer.MaximumPreviewLength = 1025); + + Assert.Throws (() => previewer.GetPreviewText ((string) null)); + Assert.Throws (() => previewer.GetPreviewText ((TextReader) null)); + Assert.Throws (() => previewer.GetPreviewText ((Stream) null, "charset")); + Assert.Throws (() => previewer.GetPreviewText (Stream.Null, (string) null)); + Assert.Throws (() => previewer.GetPreviewText ((Stream) null, Encoding.ASCII)); + Assert.Throws (() => previewer.GetPreviewText (Stream.Null, (Encoding) null)); + } + + [Test] + public void TestEmptyText () + { + var previewer = new HtmlTextPreviewer (); + + Assert.AreEqual (string.Empty, previewer.GetPreviewText (string.Empty), "string"); + + using (var reader = new StringReader (string.Empty)) + Assert.AreEqual (string.Empty, previewer.GetPreviewText (reader), "TextReader"); + + using (var stream = new MemoryStream (new byte[0], false)) { + Assert.AreEqual (string.Empty, previewer.GetPreviewText (stream, "x-unknown"), "Stream, string"); + Assert.AreEqual (string.Empty, previewer.GetPreviewText (stream, Encoding.UTF8), "Stream, Encoding"); + } + } + + void AssertPreviewText (string path, string expected, int maxPreviewLen) + { + var previewer = new HtmlTextPreviewer { MaximumPreviewLength = maxPreviewLen }; + var buffer = new byte[16 * 1024]; + string actual; + int nread; + + Assert.AreEqual (TextFormat.Html, previewer.InputFormat); + + using (var stream = File.OpenRead (path)) + nread = stream.Read (buffer, 0, buffer.Length); + + var text = Encoding.UTF8.GetString (buffer, 0, nread); + actual = previewer.GetPreviewText (text); + Assert.AreEqual (expected, actual, "GetPreviewText(string)"); + + using (var stream = new MemoryStream (buffer, 0, nread, false)) { + actual = previewer.GetPreviewText (stream, "utf-8"); + Assert.AreEqual (expected, actual, "GetPreviewText(Stream, string)"); + + stream.Position = 0; + actual = previewer.GetPreviewText (stream, Encoding.UTF8); + Assert.AreEqual (expected, actual, "GetPreviewText(Stream, Encoding)"); + + stream.Position = 0; + using (var reader = new StreamReader (stream, Encoding.UTF8, false, 4096, true)) { + actual = previewer.GetPreviewText (stream, Encoding.UTF8); + Assert.AreEqual (expected, actual, "GetPreviewText(TextReader)"); + } + } + } + + [Test] + public void TestHomeDepot110 () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "homedepot-check-inside-now.html"); + const string expected = "FREE DELIVERY Appliance Purchases $396 or More"; + + AssertPreviewText (path, expected, 110); + } + + [Test] + public void TestHomeDepot230 () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "homedepot-check-inside-now.html"); + const string expected = "FREE DELIVERY Appliance Purchases $396 or More"; + + AssertPreviewText (path, expected, 230); + } + + [Test] + public void TestMimeKitHomepage110 () + { + string expected = "Toggle navigation MimeKit Home About Help Documentation Donate \u00D7 Install with NuGet (recommended) NuGet PM> I\u2026"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "mimekit.net.html"); + + AssertPreviewText (path, expected, 110); + } + + [Test] + public void TestMimeKitHomepage230 () + { + string expected = "Toggle navigation MimeKit Home About Help Documentation Donate \u00D7 Install with NuGet (recommended) NuGet PM> Install-Package MimeKit PM> Install-Package MailKit or Install via VS Package Management window. Direct Download ZIP fil\u2026"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "mimekit.net.html"); + + AssertPreviewText (path, expected, 230); + } + + [Test] + public void TestPlanetFitness110 () + { + string expected = "Don’t miss our celebrity guest Monday evening"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "planet-fitness.html"); + + AssertPreviewText (path, expected, 110); + } + + [Test] + public void TestPlanetFitness230 () + { + string expected = "Don’t miss our celebrity guest Monday evening"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "planet-fitness.html"); + + AssertPreviewText (path, expected, 230); + } + } +} diff --git a/UnitTests/Text/HtmlToHtmlTests.cs b/UnitTests/Text/HtmlToHtmlTests.cs index cf6388ad15..0759200431 100644 --- a/UnitTests/Text/HtmlToHtmlTests.cs +++ b/UnitTests/Text/HtmlToHtmlTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -43,18 +43,78 @@ public void TestArgumentExceptions () var reader = new StringReader (""); var writer = new StringWriter (); - Assert.AreEqual (TextFormat.Html, converter.InputFormat); - Assert.AreEqual (TextFormat.Html, converter.OutputFormat); - Assert.IsFalse (converter.DetectEncodingFromByteOrderMark); - Assert.IsFalse (converter.FilterComments); - Assert.IsFalse (converter.FilterHtml); - Assert.IsNull (converter.Footer); - Assert.IsNull (converter.Header); - Assert.AreEqual (HeaderFooterFormat.Text, converter.FooterFormat); - Assert.AreEqual (HeaderFooterFormat.Text, converter.HeaderFormat); + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); Assert.Throws (() => converter.Convert ((TextReader) null, writer)); Assert.Throws (() => converter.Convert (reader, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new HtmlToHtml (); + + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsFalse (converter.FilterComments, "FilterComments"); + Assert.IsFalse (converter.FilterHtml, "FilterHtml"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.FooterFormat, "FooterFormat"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.HeaderFormat, "HeaderFormat"); + Assert.IsNull (converter.HtmlTagCallback, "HtmlTagCallback"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Html, converter.InputFormat, "InputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Html, converter.OutputFormat, "OutputFormat"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); + } + + void ReplaceUrlsWithFileNames (HtmlTagContext ctx, HtmlWriter htmlWriter) + { + if (ctx.TagId == HtmlTagId.Image) { + htmlWriter.WriteEmptyElementTag (ctx.TagName); + ctx.DeleteEndTag = true; + + for (int i = 0; i < ctx.Attributes.Count; i++) { + var attr = ctx.Attributes[i]; + + if (attr.Id == HtmlAttributeId.Src) { + var fileName = Path.GetFileName (attr.Value); + htmlWriter.WriteAttributeName (attr.Name); + htmlWriter.WriteAttributeValue (fileName); + } else { + htmlWriter.WriteAttribute (attr); + } + } + } else { + ctx.WriteTag (htmlWriter, true); + } + } + + [Test] + public void TestSimpleHtmlToHtml () + { + string expected = File.ReadAllText (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "xamarin3.xhtml")); + string text = File.ReadAllText (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "xamarin3.html")); + var converter = new HtmlToHtml { Header = null, Footer = null, HtmlTagCallback = ReplaceUrlsWithFileNames }; + var result = converter.Convert (text); + + Assert.AreEqual (TextFormat.Html, converter.InputFormat, "InputFormat"); + Assert.AreEqual (TextFormat.Html, converter.OutputFormat, "OutputFormat"); + Assert.AreEqual (expected, result); } void SupressInnerContentCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) @@ -141,5 +201,22 @@ public void TestHeaderFooter () Assert.AreEqual (expected, result); } + + [Test] + public void TestTextHeaderFooter () + { + const string input = "Here is the body content which seems fine so far"; + const string expected = "<html><head></head>
Here is the body content which seems fine so far</html>
"; + var converter = new HtmlToHtml { + HeaderFormat = HeaderFooterFormat.Text, + Header = "", + FooterFormat = HeaderFooterFormat.Text, + Footer = "" + }; + + var result = converter.Convert (input); + + Assert.AreEqual (expected, result); + } } } diff --git a/UnitTests/Text/HtmlTokenTests.cs b/UnitTests/Text/HtmlTokenTests.cs index 5db3a5f592..f69430e855 100644 --- a/UnitTests/Text/HtmlTokenTests.cs +++ b/UnitTests/Text/HtmlTokenTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Text/HtmlTokenizerTests.cs b/UnitTests/Text/HtmlTokenizerTests.cs index f21a01cbeb..92488444c9 100644 --- a/UnitTests/Text/HtmlTokenizerTests.cs +++ b/UnitTests/Text/HtmlTokenizerTests.cs @@ -1,9 +1,9 @@ -// +// // HtmlTokenizerTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -158,55 +158,55 @@ static void VerifyHtmlTokenizerOutput (string path) [Test] public void TestGoogleSignInAttemptBlocked () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "blocked.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "blocked.html")); } [Test] public void TestXamarin3SampleHtml () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "xamarin3.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "xamarin3.html")); } [Test] public void TestPapercut () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "papercut.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "papercut.html")); } [Test] public void TestPapercut44 () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "papercut-4.4.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "papercut-4.4.html")); } [Test] public void TestScriptData () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "script-data.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "script-data.html")); } [Test] public void TestCData () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "cdata.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "cdata.html")); } [Test] public void TestTokenizer () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "test.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "test.html")); } [Test] public void TestPlainText () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "plaintext.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "plaintext.html")); } [Test] public void TestBadlyQuotedAttribute () { - VerifyHtmlTokenizerOutput (Path.Combine ("..", "..", "TestData", "html", "badly-quoted-attr.html")); + VerifyHtmlTokenizerOutput (Path.Combine (TestHelper.ProjectDir, "TestData", "html", "badly-quoted-attr.html")); } // Note: The following tests are borrowed from AngleSharp @@ -1028,6 +1028,11 @@ public void TestTruncatedCDATA () Assert.IsTrue (tokenizer.ReadNextToken (out HtmlToken token)); Assert.AreEqual (HtmlTokenKind.Data, token.Kind); Assert.AreEqual (" // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Text/HtmlWriterTests.cs b/UnitTests/Text/HtmlWriterTests.cs index 523a4835b8..8af7abae77 100644 --- a/UnitTests/Text/HtmlWriterTests.cs +++ b/UnitTests/Text/HtmlWriterTests.cs @@ -1,9 +1,9 @@ -// +// // HtmlWriterTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Text/PlainTextPreviewerTests.cs b/UnitTests/Text/PlainTextPreviewerTests.cs new file mode 100644 index 0000000000..e3c79ac0ea --- /dev/null +++ b/UnitTests/Text/PlainTextPreviewerTests.cs @@ -0,0 +1,113 @@ +// +// PlainTextPreviewerTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit; +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class PlainTextPreviewerTests + { + [Test] + public void TestArgumentExceptions () + { + var previewer = new PlainTextPreviewer (); + + Assert.Throws (() => previewer.MaximumPreviewLength = 0); + Assert.Throws (() => previewer.MaximumPreviewLength = 1025); + + Assert.Throws (() => previewer.GetPreviewText ((string) null)); + Assert.Throws (() => previewer.GetPreviewText ((TextReader) null)); + Assert.Throws (() => previewer.GetPreviewText ((Stream) null, "charset")); + Assert.Throws (() => previewer.GetPreviewText (Stream.Null, (string) null)); + Assert.Throws (() => previewer.GetPreviewText ((Stream) null, Encoding.ASCII)); + Assert.Throws (() => previewer.GetPreviewText (Stream.Null, (Encoding) null)); + } + + [Test] + public void TestEmptyText () + { + var previewer = new PlainTextPreviewer (); + + Assert.AreEqual (string.Empty, previewer.GetPreviewText (string.Empty), "string"); + + using (var reader = new StringReader (string.Empty)) + Assert.AreEqual (string.Empty, previewer.GetPreviewText (reader), "TextReader"); + + using (var stream = new MemoryStream (new byte[0], false)) { + Assert.AreEqual (string.Empty, previewer.GetPreviewText (stream, "x-unknown"), "Stream, string"); + Assert.AreEqual (string.Empty, previewer.GetPreviewText (stream, Encoding.UTF8), "Stream, Encoding"); + } + } + + void AssertPreviewText (string path, string expected) + { + var previewer = new PlainTextPreviewer (); + var buffer = new byte[16 * 1024]; + string actual; + int nread; + + Assert.AreEqual (TextFormat.Plain, previewer.InputFormat); + + using (var stream = File.OpenRead (path)) + nread = stream.Read (buffer, 0, buffer.Length); + + var text = Encoding.UTF8.GetString (buffer, 0, nread); + actual = previewer.GetPreviewText (text); + Assert.AreEqual (expected, actual, "GetPreviewText(string)"); + + using (var stream = new MemoryStream (buffer, 0, nread, false)) { + actual = previewer.GetPreviewText (stream, "utf-8"); + Assert.AreEqual (expected, actual, "GetPreviewText(Stream, string)"); + + stream.Position = 0; + actual = previewer.GetPreviewText (stream, Encoding.UTF8); + Assert.AreEqual (expected, actual, "GetPreviewText(Stream, Encoding)"); + + stream.Position = 0; + using (var reader = new StreamReader (stream, Encoding.UTF8, false, 4096, true)) { + actual = previewer.GetPreviewText (stream, Encoding.UTF8); + Assert.AreEqual (expected, actual, "GetPreviewText(TextReader)"); + } + } + } + + [Test] + public void TestPlanetFitness () + { + const string expected = "Planet Fitness https://view.email.planetfitness.com/?qs=9a098a031cabde68c0a4260051cd6fe473a2e997a53678ff26b4b199a711a9d2ad0536530d6f837c246b09f644d42016ecfb298f930b7af058e9e454b34f3d818ceb3052ae317b1ac4594aab28a2d788 View web ver…"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "planet-fitness.txt"); + + AssertPreviewText (path, expected); + } + } +} diff --git a/UnitTests/Text/RtfCompressedToRtfTests.cs b/UnitTests/Text/RtfCompressedToRtfTests.cs index 478a6a36b1..6316b3d8c7 100644 --- a/UnitTests/Text/RtfCompressedToRtfTests.cs +++ b/UnitTests/Text/RtfCompressedToRtfTests.cs @@ -1,9 +1,9 @@ -// +// // RtfCompressedToRtfTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Text/TextConverterTests.cs b/UnitTests/Text/TextConverterTests.cs index b5aec502e4..ceb2b54bcc 100644 --- a/UnitTests/Text/TextConverterTests.cs +++ b/UnitTests/Text/TextConverterTests.cs @@ -1,9 +1,9 @@ -// +// // TextConverterTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -37,286 +37,86 @@ namespace UnitTests.Text { public class TextConverterTests { [Test] - public void TestArgumentExceptions () + public void TestPropertySetters () { + var latin1 = Encoding.GetEncoding ("iso-8859-1"); + var utf16 = Encoding.Unicode; var converter = new TextToText (); - Assert.Throws (() => converter.InputEncoding = null); - Assert.Throws (() => converter.OutputEncoding = null); - - Assert.Throws (() => converter.InputStreamBufferSize = -1); - Assert.Throws (() => converter.OutputStreamBufferSize = -1); - - Assert.Throws (() => converter.Convert (null)); - Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); - Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); - Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); - Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); - Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); - Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); - Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); - Assert.Throws (() => converter.Convert ((TextReader) null, new StreamWriter (Stream.Null))); - } - - [Test] - public void TestSimpleFlowedToText () - { - string expected = "This is some sample text that has been formatted " + - "according to the format=flowed rules defined in rfc3676. " + - "This text, once converted, should all be on a single line." + Environment.NewLine; - string text = "This is some sample text that has been formatted " + Environment.NewLine + - "according to the format=flowed rules defined in rfc3676. " + Environment.NewLine + - "This text, once converted, should all be on a single line." + Environment.NewLine; - var converter = new FlowedToText (); - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } - - [Test] - public void TestQuotedFlowedToText () - { - string expected = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + - "> reeky elf-skinned pigeon-egg!" + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + - ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + - ">>> unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + - ">>>> enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + - ">>>>> styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - var converter = new FlowedToText (); - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } - - [Test] - public void TestBrokenQuotedFlowedToText () - { - // Note: this is the brokenly quoted sample from rfc3676 at the end of section 4.5 - string expected = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg! " + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + - "> reeky elf-skinned pigeon-egg! " + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + - ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + - ">>> unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + - ">>>> enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + - ">>>>> styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - var converter = new FlowedToText (); - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } - - [Test] - public void TestSimpleFlowedToHtml () - { - string expected = "

This is some sample text that has been formatted " + - "according to the format=flowed rules defined in rfc3676. " + - "This text, once converted, should all be on a single line.

" + Environment.NewLine + - "
" + Environment.NewLine + - "
" + Environment.NewLine + - "
" + Environment.NewLine + - "
" + Environment.NewLine + - "

And this line of text should be separate by 4 blank lines.

" + Environment.NewLine; - string text = "This is some sample text that has been formatted " + Environment.NewLine + - "according to the format=flowed rules defined in rfc3676. " + Environment.NewLine + - "This text, once converted, should all be on a single line." + Environment.NewLine + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine + - Environment.NewLine + - "And this line of text should be separate by 4 blank lines." + Environment.NewLine; - var converter = new FlowedToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } + converter.InputEncoding = latin1; + Assert.AreEqual (latin1, converter.InputEncoding, "InputEncoding"); - [Test] - public void TestQuotedFlowedToHtml () - { - string expected = "

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + - "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + - "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + - "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + - "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + - "

Any complaints?

" + Environment.NewLine + - "
"; - string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + - "> reeky elf-skinned pigeon-egg!" + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + - ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + - ">>> unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + - ">>>> enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + - ">>>>> styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - var converter = new FlowedToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); + converter.InputStreamBufferSize = 5000; + Assert.AreEqual (5000, converter.InputStreamBufferSize, "InputStreamBufferSize"); - Assert.AreEqual (expected, result); - } + converter.OutputEncoding = utf16; + Assert.AreEqual (utf16, converter.OutputEncoding, "OutputEncoding"); - [Test] - public void TestBrokenQuotedFlowedToHtml () - { - // Note: this is the brokenly quoted sample from rfc3676 at the end of section 4.5 - string expected = "

Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!

" + Environment.NewLine + - "

Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!

" + Environment.NewLine + - "

Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!

" + Environment.NewLine + - "

Henceforth, the coding style is to be strictly enforced, including the use of only upper case.

" + Environment.NewLine + - "

I've noticed a lack of adherence to the coding styles, of late.

" + Environment.NewLine + - "

Any complaints?

" + Environment.NewLine + - "
"; - string text = "> Thou villainous ill-breeding spongy dizzy-eyed " + Environment.NewLine + - "> reeky elf-skinned pigeon-egg! " + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered " + Environment.NewLine + - ">> dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe " + Environment.NewLine + - ">>> unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly " + Environment.NewLine + - ">>>> enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding " + Environment.NewLine + - ">>>>> styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - var converter = new FlowedToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); + converter.OutputStreamBufferSize = 6000; + Assert.AreEqual (6000, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); - Assert.AreEqual (expected, result); + converter.DetectEncodingFromByteOrderMark = true; + Assert.IsTrue (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); } [Test] - public void TestSimpleFlowedWithUrlsToHtml () + public void TestConvertFromReaderToStream () { - string expected = "

Check out http://www.xamarin.com - it's amazing!

" + Environment.NewLine; - string text = "Check out http://www.xamarin.com - it's amazing!" + Environment.NewLine; - var converter = new FlowedToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); + const string input = "This is some text..."; + var converter = new TextToText { + DetectEncodingFromByteOrderMark = false, + InputEncoding = Encoding.ASCII, + OutputEncoding = Encoding.ASCII + }; - Assert.AreEqual (expected, result); - } + using (var output = new MemoryStream ()) { + using (var reader = new StringReader (input)) + converter.Convert (reader, output); - [Test] - public void TestSimpleTextToText () - { - string expected = "This is some sample text. This is line #1." + Environment.NewLine + - "This is line #2." + Environment.NewLine + - "And this is line #3." + Environment.NewLine; - string text = "This is some sample text. This is line #1." + Environment.NewLine + - "This is line #2." + Environment.NewLine + - "And this is line #3." + Environment.NewLine; - var converter = new TextToText (); - var result = converter.Convert (text); + var result = Encoding.ASCII.GetString (output.GetBuffer (), 0, (int) output.Length); - Assert.AreEqual (expected, result); + Assert.AreEqual (input, result); + } } [Test] - public void TestSimpleTextToFlowed () + public void TestConvertFromStreamToStream () { - string expected = "> Thou art a villainous ill-breeding spongy dizzy-eyed reeky elf-skinned " + Environment.NewLine + - "> pigeon-egg!" + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly enforced, including " + Environment.NewLine + - ">>>> the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - string text = "> Thou art a villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + - ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + - ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + - ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + - ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + - ">>>>>> Any complaints?" + Environment.NewLine; - TextConverter converter = new TextToFlowed (); - string result = converter.Convert (text); - - Assert.AreEqual (expected, result); - - converter = new FlowedToText { DeleteSpace = true }; - result = converter.Convert (expected); + const string input = "This is some text..."; + var converter = new TextToText { + DetectEncodingFromByteOrderMark = false, + InputEncoding = Encoding.ASCII, + OutputEncoding = Encoding.ASCII + }; - Assert.AreEqual (text, result); - } + using (var output = new MemoryStream ()) { + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input))) + converter.Convert (stream, output); - [Test] - public void TestSimpleTextToHtml () - { - const string expected = "This is some sample text. This is line #1.
" + - "This is line #2.
" + - "And this is line #3.
"; - string text = "This is some sample text. This is line #1." + Environment.NewLine + - "This is line #2." + Environment.NewLine + - "And this is line #3." + Environment.NewLine; - var converter = new TextToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); + var result = Encoding.ASCII.GetString (output.GetBuffer (), 0, (int) output.Length); - Assert.AreEqual (expected, result); + Assert.AreEqual (input, result); + } } [Test] - public void TestSimpleTextWithUrlsToHtml () + public void TestConvertFromStreamToWriter () { - const string expected = "Check out http://www.xamarin.com - it's amazing!
"; - string text = "Check out http://www.xamarin.com - it's amazing!" + Environment.NewLine; - var converter = new TextToHtml { OutputHtmlFragment = true }; - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } + const string input = "This is some text..."; + var converter = new TextToText { + DetectEncodingFromByteOrderMark = false, + InputEncoding = Encoding.ASCII, + OutputEncoding = Encoding.ASCII + }; - void ReplaceUrlsWithFileNames (HtmlTagContext ctx, HtmlWriter htmlWriter) - { - if (ctx.TagId == HtmlTagId.Image) { - htmlWriter.WriteEmptyElementTag (ctx.TagName); - ctx.DeleteEndTag = true; + using (var writer = new StringWriter ()) { + using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (input))) + converter.Convert (stream, writer); - for (int i = 0; i < ctx.Attributes.Count; i++) { - var attr = ctx.Attributes[i]; + var result = writer.ToString (); - if (attr.Id == HtmlAttributeId.Src) { - var fileName = Path.GetFileName (attr.Value); - htmlWriter.WriteAttributeName (attr.Name); - htmlWriter.WriteAttributeValue (fileName); - } else { - htmlWriter.WriteAttribute (attr); - } - } - } else { - ctx.WriteTag (htmlWriter, true); + Assert.AreEqual (input, result); } } - - [Test] - public void TestSimpleHtmlToHtml () - { - string expected = File.ReadAllText ("../../TestData/html/xamarin3.xhtml"); - string text = File.ReadAllText ("../../TestData/html/xamarin3.html"); - var converter = new HtmlToHtml { HtmlTagCallback = ReplaceUrlsWithFileNames }; - var result = converter.Convert (text); - - Assert.AreEqual (expected, result); - } } } diff --git a/UnitTests/Text/TextPreviewerTests.cs b/UnitTests/Text/TextPreviewerTests.cs new file mode 100644 index 0000000000..79a28d345c --- /dev/null +++ b/UnitTests/Text/TextPreviewerTests.cs @@ -0,0 +1,153 @@ +// +// TextPreviewerTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit; +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class TextPreviewerTests + { + [Test] + public void TestArgumentExceptions () + { + Assert.Throws (() => TextPreviewer.GetPreviewText ((TextPart) null)); + } + + static TextPart CreateTextPart (string path, TextFormat format) + { + var text = File.ReadAllText (path); + + return new TextPart (format) { Text = text }; + } + + void AssertPreviewText (string path, TextFormat format, string expected) + { + var body = CreateTextPart (path, format); + string actual; + + actual = TextPreviewer.GetPreviewText (body); + Assert.AreEqual (expected, actual); + } + + [Test] + public void TestHomeDepotCheckInsideNOW () + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "homedepot-check-inside-now.html"); + const string expected = "FREE DELIVERY Appliance Purchases $396 or More"; + + AssertPreviewText (path, TextFormat.Html, expected); + } + + [Test] + public void TestMimeKitHomepage () + { + string expected = "Toggle navigation MimeKit Home About Help Documentation Donate \u00D7 Install with NuGet (recommended) NuGet PM> Install-Package MimeKit PM> Install-Package MailKit or Install via VS Package Management window. Direct Download ZIP fil\u2026"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "mimekit.net.html"); + + AssertPreviewText (path, TextFormat.Html, expected); + } + + [Test] + public void TestPlanetFitness () + { + string expected = "Don’t miss our celebrity guest Monday evening"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "planet-fitness.html"); + + AssertPreviewText (path, TextFormat.Html, expected); + } + + [Test] + public void TestPlanetFitnessPlain () + { + const string expected = "Planet Fitness https://view.email.planetfitness.com/?qs=9a098a031cabde68c0a4260051cd6fe473a2e997a53678ff26b4b199a711a9d2ad0536530d6f837c246b09f644d42016ecfb298f930b7af058e9e454b34f3d818ceb3052ae317b1ac4594aab28a2d788 View web ver…"; + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "text", "planet-fitness.txt"); + + AssertPreviewText (path, TextFormat.Plain, expected); + } + + [Test] + public void TestGetPreviewTextUnknownCharset () + { + var encoding = Encoding.GetEncoding ("big5"); + var builder = new StringBuilder (); + + using (var memory = new MemoryStream ()) { + var bytes = encoding.GetBytes ("日月星辰"); + string preview; + + memory.Write (bytes, 0, bytes.Length); + memory.Position = 0; + + var body = new TextPart ("plain") { + Content = new MimeContent (memory, ContentEncoding.Default) + }; + body.ContentType.Charset = "x-unknown"; + + preview = TextPreviewer.GetPreviewText (body); + Assert.AreEqual ("¤é¤ë¬P¨°", preview, "chinese text x-unknown -> UTF-8 -> iso-8859-1"); + } + + using (var memory = new MemoryStream ()) { + var bytes = Encoding.UTF8.GetBytes ("日月星辰"); + string preview; + + memory.Write (bytes, 0, bytes.Length); + memory.Position = 0; + + var body = new TextPart ("plain") { + Content = new MimeContent (memory, ContentEncoding.Default) + }; + body.ContentType.Charset = "x-unknown"; + + preview = TextPreviewer.GetPreviewText (body); + Assert.AreEqual ("日月星辰", preview, "x-unknown -> UTF-8"); + } + + using (var memory = new MemoryStream ()) { + var bytes = Encoding.GetEncoding (28591).GetBytes ("L'encyclopédie libre"); + string preview; + + memory.Write (bytes, 0, bytes.Length); + memory.Position = 0; + + var body = new TextPart ("plain") { + Content = new MimeContent (memory, ContentEncoding.Default) + }; + body.ContentType.Charset = "x-unknown"; + + preview = TextPreviewer.GetPreviewText (body); + Assert.AreEqual ("L'encyclopédie libre", preview, "french text x-unknown -> UTF-8 -> iso-8859-1"); + } + } + } +} diff --git a/UnitTests/Text/TextToFlowedTests.cs b/UnitTests/Text/TextToFlowedTests.cs new file mode 100644 index 0000000000..0d53f5ed22 --- /dev/null +++ b/UnitTests/Text/TextToFlowedTests.cs @@ -0,0 +1,260 @@ +// +// TextToFlowedTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class TextToFlowedTests + { + [Test] + public void TestArgumentExceptions () + { + var converter = new TextToFlowed (); + var reader = new StringReader (""); + var writer = new StringWriter (); + + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, writer)); + Assert.Throws (() => converter.Convert (reader, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new TextToFlowed (); + + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Text, converter.InputFormat, "InputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Flowed, converter.OutputFormat, "OutputFormat"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); + } + + [Test] + public void TestSimpleTextToFlowed () + { + string expected = "> Thou art a villainous ill-breeding spongy dizzy-eyed reeky elf-skinned " + Environment.NewLine + + "> pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the " + Environment.NewLine + + ">>>> use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + string text = "> Thou art a villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + TextConverter converter = new TextToFlowed { Header = null, Footer = null }; + string result = converter.Convert (text); + + Assert.AreEqual (expected, result); + + converter = new FlowedToText { DeleteSpace = true }; + result = converter.Convert (expected); + + Assert.AreEqual (text, result); + } + + [Test] + public void TestSpaceStuffingFromLine () + { + string expected = "My favorite James Bond movie is" + Environment.NewLine + + " From Russia with love." + Environment.NewLine; + string text = "My favorite James Bond movie is" + Environment.NewLine + + "From Russia with love." + Environment.NewLine; + TextConverter converter = new TextToFlowed (); + string result = converter.Convert (text); + + Assert.AreEqual (expected, result); + + converter = new FlowedToText (); + result = converter.Convert (expected); + + Assert.AreEqual (text, result); + } + + [Test] + public void TestSpaceStuffingLinesStartingWithSpace () + { + string expected = "This is a regular line." + Environment.NewLine + + " This line starts with a space." + Environment.NewLine; + string text = "This is a regular line." + Environment.NewLine + + " This line starts with a space." + Environment.NewLine; + TextConverter converter = new TextToFlowed (); + string result = converter.Convert (text); + + Assert.AreEqual (expected, result); + + converter = new FlowedToText (); + result = converter.Convert (expected); + + Assert.AreEqual (text, result); + } + + [Test] + public void TestFlowingLongLines () + { + const string text = "But, soft! what light through yonder window breaks? " + + "It is the east, and Juliet is the sun. " + + "Arise, fair sun, and kill the envious moon, " + + "Who is already sick and pale with grief, " + + "That thou her maid art far more fair than she: " + + "Be not her maid, since she is envious; " + + "Her vestal livery is but sick and green " + + "And none but fools do wear it; cast it off. " + + "It is my lady, O, it is my love! " + + "O, that she knew she were! " + + "She speaks yet she says nothing: what of that? " + + "Her eye discourses; I will answer it. " + + "I am too bold, 'tis not to me she speaks: " + + "Two of the fairest stars in all the heaven, " + + "Having some business, do entreat her eyes " + + "To twinkle in their spheres till they return. " + + "What if her eyes were there, they in her head? " + + "The brightness of her cheek would shame those stars, " + + "As daylight doth a lamp; her eyes in heaven " + + "Would through the airy region stream so bright " + + "That birds would sing and think it were not night. " + + "See, how she leans her cheek upon her hand! " + + "O, that I were a glove upon that hand, " + + "That I might touch that cheek!\n"; + string expected = @"But, soft! what light through yonder window breaks? It is the east, and +Juliet is the sun. Arise, fair sun, and kill the envious moon, Who is +already sick and pale with grief, That thou her maid art far more fair than +she: Be not her maid, since she is envious; Her vestal livery is but sick +and green And none but fools do wear it; cast it off. It is my lady, O, it +is my love! O, that she knew she were! She speaks yet she says nothing: what +of that? Her eye discourses; I will answer it. I am too bold, 'tis not to me +she speaks: Two of the fairest stars in all the heaven, Having some +business, do entreat her eyes To twinkle in their spheres till they return. +What if her eyes were there, they in her head? The brightness of her cheek +would shame those stars, As daylight doth a lamp; her eyes in heaven Would +through the airy region stream so bright That birds would sing and think it +were not night. See, how she leans her cheek upon her hand! O, that I were a +glove upon that hand, That I might touch that cheek! +".Replace ("\r\n", "\n"); + TextConverter converter = new TextToFlowed (); + string result = converter.Convert (text).Replace ("\r\n", "\n"); + + Assert.AreEqual (expected, result); + + converter = new FlowedToText () { DeleteSpace = true }; + result = converter.Convert (expected).Replace ("\r\n", "\n"); + + Assert.AreEqual (text, result); + } + + [Test] + public void TestFlowingLongQuotedLines () + { + const string text = "A passage from Shakespear's Romeo + Juliet:\n" + + "> Begin quote\n" + + ">> But, soft! what light through yonder window breaks? " + + "It is the east, and Juliet is the sun. " + + "Arise, fair sun, and kill the envious moon, " + + "Who is already sick and pale with grief, " + + "That thou her maid art far more fair than she: " + + "Be not her maid, since she is envious; " + + "Her vestal livery is but sick and green " + + "And none but fools do wear it; cast it off. " + + "It is my lady, O, it is my love! " + + "O, that she knew she were! " + + "She speaks yet she says nothing: what of that? " + + "Her eye discourses; I will answer it. " + + "I am too bold, 'tis not to me she speaks: " + + "Two of the fairest stars in all the heaven, " + + "Having some business, do entreat her eyes " + + "To twinkle in their spheres till they return. " + + "What if her eyes were there, they in her head? " + + "The brightness of her cheek would shame those stars, " + + "As daylight doth a lamp; her eyes in heaven " + + "Would through the airy region stream so bright " + + "That birds would sing and think it were not night. " + + "See, how she leans her cheek upon her hand! " + + "O, that I were a glove upon that hand, " + + "That I might touch that cheek!\n" + + "> End quote\n\n" + + "Did that flow correctly?\n"; + string expected = @"A passage from Shakespear's Romeo + Juliet: +> Begin quote +>> But, soft! what light through yonder window breaks? It is the east, and +>> Juliet is the sun. Arise, fair sun, and kill the envious moon, Who is +>> already sick and pale with grief, That thou her maid art far more fair +>> than she: Be not her maid, since she is envious; Her vestal livery is but +>> sick and green And none but fools do wear it; cast it off. It is my lady, +>> O, it is my love! O, that she knew she were! She speaks yet she says +>> nothing: what of that? Her eye discourses; I will answer it. I am too +>> bold, 'tis not to me she speaks: Two of the fairest stars in all the +>> heaven, Having some business, do entreat her eyes To twinkle in their +>> spheres till they return. What if her eyes were there, they in her head? +>> The brightness of her cheek would shame those stars, As daylight doth a +>> lamp; her eyes in heaven Would through the airy region stream so bright +>> That birds would sing and think it were not night. See, how she leans her +>> cheek upon her hand! O, that I were a glove upon that hand, That I might +>> touch that cheek! +> End quote + +Did that flow correctly? +".Replace ("\r\n", "\n"); + TextConverter converter = new TextToFlowed (); + string result = converter.Convert (text).Replace ("\r\n", "\n"); + + Assert.AreEqual (expected, result); + + converter = new FlowedToText () { DeleteSpace = true }; + result = converter.Convert (expected).Replace ("\r\n", "\n"); + + Assert.AreEqual (text, result); + } + } +} diff --git a/UnitTests/Text/TextToHtmlTests.cs b/UnitTests/Text/TextToHtmlTests.cs index 80b5c4c091..e1c72b9004 100644 --- a/UnitTests/Text/TextToHtmlTests.cs +++ b/UnitTests/Text/TextToHtmlTests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,6 +28,7 @@ using System.IO; using System.Text; +using MimeKit.Encodings; using MimeKit.Text; using NUnit.Framework; @@ -43,17 +44,42 @@ public void TestArgumentExceptions () var reader = new StringReader (""); var writer = new StringWriter (); - Assert.AreEqual (TextFormat.Plain, converter.InputFormat); - Assert.AreEqual (TextFormat.Html, converter.OutputFormat); - Assert.IsFalse (converter.DetectEncodingFromByteOrderMark); - Assert.IsFalse (converter.OutputHtmlFragment); - Assert.IsNull (converter.Footer); - Assert.IsNull (converter.Header); - Assert.AreEqual (HeaderFooterFormat.Text, converter.FooterFormat); - Assert.AreEqual (HeaderFooterFormat.Text, converter.HeaderFormat); + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); Assert.Throws (() => converter.Convert ((TextReader) null, writer)); Assert.Throws (() => converter.Convert (reader, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new TextToHtml (); + + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.FooterFormat, "FooterFormat"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (HeaderFooterFormat.Text, converter.HeaderFormat, "HeaderFormat"); + Assert.IsNull (converter.HtmlTagCallback, "HtmlTagCallback"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Text, converter.InputFormat, "InputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Html, converter.OutputFormat, "OutputFormat"); + Assert.IsFalse (converter.OutputHtmlFragment, "OutputHtmlFragment"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); } [Test] @@ -90,5 +116,113 @@ public void TestHeaderFooter () var result = converter.Convert (input); Assert.AreEqual (expected, result); } + + [Test] + public void TestEmoji () + { + var expected = "😱
"; + var buffer = Encoding.ASCII.GetBytes ("=F0=9F=98=B1"); + var decoder = new QuotedPrintableDecoder (); + var length = decoder.EstimateOutputLength (buffer.Length); + var decoded = new byte[length]; + var n = decoder.Decode (buffer, 0, buffer.Length, decoded); + var emoji = Encoding.UTF8.GetString (decoded, 0, n); + var converter = new TextToHtml (); + var result = converter.Convert (emoji); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestIncreasingQuoteLevels () + { + string expected = "
Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!
" + + "
Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!
" + + "
Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!
" + + "
Henceforth, the coding style is to be strictly enforced, including the use of only upper case.
" + + "
I've noticed a lack of adherence to the coding styles, of late.
" + + "
Any complaints?
" + + "
"; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?" + Environment.NewLine; + var converter = new TextToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestIncreasingQuoteLevelsNoNewLineAtEndOfText () + { + string expected = "
Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!
" + + "
Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!
" + + "
Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!
" + + "
Henceforth, the coding style is to be strictly enforced, including the use of only upper case.
" + + "
I've noticed a lack of adherence to the coding styles, of late.
" + + "
Any complaints?
" + + "
"; + string text = "> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">>>>> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + ">>>>>> Any complaints?"; + var converter = new TextToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestDecreasingQuoteLevels () + { + string expected = "
Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!
" + + "
Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!
" + + "
Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!
" + + "
Henceforth, the coding style is to be strictly enforced, including the use of only upper case.
" + + "
I've noticed a lack of adherence to the coding styles, of late.
" + + "
Any complaints?
" + + "
"; + string text = ">>>>>> Thou villainous ill-breeding spongy dizzy-eyed reeky elf-skinned pigeon-egg!" + Environment.NewLine + + ">>>>> Thou artless swag-bellied milk-livered dismal-dreaming idle-headed scut!" + Environment.NewLine + + ">>>> Thou errant folly-fallen spleeny reeling-ripe unmuzzled ratsbane!" + Environment.NewLine + + ">>> Henceforth, the coding style is to be strictly enforced, including the use of only upper case." + Environment.NewLine + + ">> I've noticed a lack of adherence to the coding styles, of late." + Environment.NewLine + + "> Any complaints?" + Environment.NewLine; + var converter = new TextToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestSimpleTextToHtml () + { + const string expected = "This is some sample text. This is line #1.
" + + "This is line #2.
" + + "And this is line #3.
"; + string text = "This is some sample text. This is line #1." + Environment.NewLine + + "This is line #2." + Environment.NewLine + + "And this is line #3." + Environment.NewLine; + var converter = new TextToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestSimpleTextWithUrlsToHtml () + { + const string expected = "Check out http://www.xamarin.com - it's amazing!
"; + string text = "Check out http://www.xamarin.com - it's amazing!" + Environment.NewLine; + var converter = new TextToHtml { OutputHtmlFragment = true }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } } } diff --git a/UnitTests/Text/TextToTextTests.cs b/UnitTests/Text/TextToTextTests.cs new file mode 100644 index 0000000000..6b9f2f737a --- /dev/null +++ b/UnitTests/Text/TextToTextTests.cs @@ -0,0 +1,103 @@ +// +// TextToTextTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using MimeKit.Text; + +using NUnit.Framework; + +namespace UnitTests.Text { + [TestFixture] + public class TextToTextTests + { + [Test] + public void TestArgumentExceptions () + { + var converter = new TextToText (); + + Assert.Throws (() => converter.InputEncoding = null); + Assert.Throws (() => converter.OutputEncoding = null); + + Assert.Throws (() => converter.InputStreamBufferSize = -1); + Assert.Throws (() => converter.OutputStreamBufferSize = -1); + + Assert.Throws (() => converter.Convert (null)); + Assert.Throws (() => converter.Convert ((Stream) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (Stream) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, Stream.Null)); + Assert.Throws (() => converter.Convert (Stream.Null, (TextWriter) null)); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (Stream) null)); + Assert.Throws (() => converter.Convert ((Stream) null, new StreamWriter (Stream.Null))); + Assert.Throws (() => converter.Convert (new StreamReader (Stream.Null), (TextWriter) null)); + Assert.Throws (() => converter.Convert ((TextReader) null, new StreamWriter (Stream.Null))); + } + + [Test] + public void TestDefaultPropertyValues () + { + var converter = new TextToText (); + + Assert.IsFalse (converter.DetectEncodingFromByteOrderMark, "DetectEncodingFromByteOrderMark"); + Assert.IsNull (converter.Footer, "Footer"); + Assert.IsNull (converter.Header, "Header"); + Assert.AreEqual (Encoding.UTF8, converter.InputEncoding, "InputEncoding"); + Assert.AreEqual (TextFormat.Text, converter.InputFormat, "InputFormat"); + Assert.AreEqual (Encoding.UTF8, converter.OutputEncoding, "OutputEncoding"); + Assert.AreEqual (TextFormat.Text, converter.OutputFormat, "OutputFormat"); + Assert.AreEqual (4096, converter.InputStreamBufferSize, "InputStreamBufferSize"); + Assert.AreEqual (4096, converter.OutputStreamBufferSize, "OutputStreamBufferSize"); + } + + [Test] + public void TestHeaderAndFooter () + { + string expected = "Header,Footer"; + string text = ","; + var converter = new TextToText { Header = "Header", Footer = "Footer" }; + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + + [Test] + public void TestSimpleTextToText () + { + string expected = "This is some sample text. This is line #1." + Environment.NewLine + + "This is line #2." + Environment.NewLine + + "And this is line #3." + Environment.NewLine; + string text = "This is some sample text. This is line #1." + Environment.NewLine + + "This is line #2." + Environment.NewLine + + "And this is line #3." + Environment.NewLine; + var converter = new TextToText (); + var result = converter.Convert (text); + + Assert.AreEqual (expected, result); + } + } +} diff --git a/UnitTests/Text/TrieTests.cs b/UnitTests/Text/TrieTests.cs index 030457f6e1..98f43849d7 100644 --- a/UnitTests/Text/TrieTests.cs +++ b/UnitTests/Text/TrieTests.cs @@ -1,9 +1,9 @@ -// +// // TrieTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -56,6 +56,28 @@ public class TrieTests "I've attached a file (file:///cvs/gmime/gmime/gtrie.c)", }; + [Test] + public void TestArgumentExceptions () + { + var text = TestCases[0].ToCharArray (); + var trie = new Trie (); + string pattern; + + Assert.Throws (() => trie.Add (null)); + Assert.Throws (() => trie.Add (string.Empty)); + + for (int i = 0; i < TriePatterns.Length; i++) + trie.Add (TriePatterns[i]); + + Assert.Throws (() => trie.Search (null, out pattern)); + Assert.Throws (() => trie.Search (null, 0, out pattern)); + Assert.Throws (() => trie.Search (null, 0, 0, out pattern)); + + Assert.Throws (() => trie.Search (text, -1, out pattern)); + Assert.Throws (() => trie.Search (text, -1, text.Length, out pattern)); + Assert.Throws (() => trie.Search (text, 0, -1, out pattern)); + } + [Test] public void TestTrie () { diff --git a/UnitTests/Text/UrlScannerTests.cs b/UnitTests/Text/UrlScannerTests.cs index b5ea6ff8e5..93d2f89575 100644 --- a/UnitTests/Text/UrlScannerTests.cs +++ b/UnitTests/Text/UrlScannerTests.cs @@ -1,9 +1,9 @@ -// +// // UrlScannerTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -177,6 +177,36 @@ public void TestSimpleWebUrlWithPath () TestUrlScanner ("This is some text with an http://www.xamarin.com/logo.png url in it...", "http://www.xamarin.com/logo.png"); } + [Test] + public void TestSimpleWebUrlWithPathEnclosedInParens () + { + TestUrlScanner ("This is some text with an (http://www.xamarin.com/logo.png) url in it...", "http://www.xamarin.com/logo.png"); + } + + [Test] + public void TestSimpleWebUrlWithPathEnclosedInCurlyBraces () + { + TestUrlScanner ("This is some text with an {http://www.xamarin.com/logo.png} url in it...", "http://www.xamarin.com/logo.png"); + } + + [Test] + public void TestSimpleWebUrlWithPathEnclosedInAngleBrackets () + { + TestUrlScanner ("This is some text with an url in it...", "http://www.xamarin.com/logo.png"); + } + + [Test] + public void TestSimpleWebUrlWithPathEnclosedInSquareBrackets () + { + TestUrlScanner ("This is some text with an [http://www.xamarin.com/logo.png] url in it...", "http://www.xamarin.com/logo.png"); + } + + [Test] + public void TestSimpleWebUrlWithPathEnclosedInPipes () + { + TestUrlScanner ("This is some text with an |http://www.xamarin.com/logo.png| url in it...", "http://www.xamarin.com/logo.png"); + } + [Test] public void TestSimpleWebUrlWithPort () { diff --git a/UnitTests/TextPartTests.cs b/UnitTests/TextPartTests.cs index aab9893bc2..4d10c0ff60 100644 --- a/UnitTests/TextPartTests.cs +++ b/UnitTests/TextPartTests.cs @@ -1,9 +1,9 @@ -// +// // TextPartTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Jeffrey Stedfast +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ // using System; +using System.IO; using System.Text; using NUnit.Framework; @@ -66,25 +67,182 @@ public void TestFormat () Assert.IsTrue (text.IsHtml, "IsHtml"); Assert.IsFalse (text.IsPlain, "IsPlain"); Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsFalse (text.IsEnriched, "IsEnriched"); Assert.IsFalse (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.Html, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.Html), "IsFormat"); text = new TextPart (TextFormat.Plain); Assert.IsFalse (text.IsHtml, "IsHtml"); Assert.IsTrue (text.IsPlain, "IsPlain"); Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsFalse (text.IsEnriched, "IsEnriched"); Assert.IsFalse (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.Plain, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.Plain), "IsFormat"); text = new TextPart (TextFormat.Flowed); Assert.IsFalse (text.IsHtml, "IsHtml"); - Assert.IsTrue (text.IsPlain, "IsPlain"); + Assert.IsTrue (text.IsPlain, "IsPlain"); // special: Flowed is both Plain *and* Flowed Assert.IsTrue (text.IsFlowed, "IsFlowed"); + Assert.IsFalse (text.IsEnriched, "IsEnriched"); Assert.IsFalse (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.Flowed, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.Plain), "IsFormat"); // special: Flowed is both Plain *and* Flowed + Assert.IsTrue (text.IsFormat (TextFormat.Flowed), "IsFormat"); text = new TextPart (TextFormat.RichText); Assert.IsFalse (text.IsHtml, "IsHtml"); Assert.IsFalse (text.IsPlain, "IsPlain"); Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsFalse (text.IsEnriched, "IsEnriched"); Assert.IsTrue (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.RichText, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.RichText), "IsFormat"); + + text = new TextPart (new ContentType ("application", "rtf")); + Assert.IsFalse (text.IsHtml, "IsHtml"); + Assert.IsFalse (text.IsPlain, "IsPlain"); + Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsFalse (text.IsEnriched, "IsEnriched"); + Assert.IsTrue (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.RichText, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.RichText), "IsFormat"); + Assert.IsFalse (text.IsFormat (TextFormat.CompressedRichText), "CompressedRichText"); + + text = new TextPart (TextFormat.Enriched); + Assert.IsFalse (text.IsHtml, "IsHtml"); + Assert.IsFalse (text.IsPlain, "IsPlain"); + Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsTrue (text.IsEnriched, "IsEnriched"); + Assert.IsFalse (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.Enriched, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.Enriched), "IsFormat"); + + text = new TextPart ("richtext"); + Assert.IsFalse (text.IsHtml, "IsHtml"); + Assert.IsFalse (text.IsPlain, "IsPlain"); + Assert.IsFalse (text.IsFlowed, "IsFlowed"); + Assert.IsTrue (text.IsEnriched, "IsEnriched"); + Assert.IsFalse (text.IsRichText, "IsRichText"); + Assert.AreEqual (TextFormat.Enriched, text.Format, "Format"); + Assert.IsTrue (text.IsFormat (TextFormat.Enriched), "IsFormat"); + } + + [Test] + public void TestGetText () + { + const string text = "This is some Låtín1 text."; + + var encoding = Encoding.GetEncoding ("iso-8859-1"); + var part = new TextPart ("plain"); + + part.SetText ("iso-8859-1", text); + + Assert.AreEqual (text, part.GetText ("iso-8859-1"), "charset"); + Assert.AreEqual (text, part.GetText (encoding), "encoding"); + } + + [Test] + public void TestInvalidCharset () + { + const string text = "This is some Låtín1 text."; + + var latin1 = Encoding.GetEncoding ("iso-8859-1"); + var part = new TextPart ("plain"); + + part.SetText ("iso-8859-1", text); + part.ContentType.Charset = "flubber"; + + Assert.AreEqual (text, part.Text); + + var actual = part.GetText (out Encoding encoding); + + Assert.AreEqual (text, actual, "GetText(out Encoding)"); + Assert.AreEqual (latin1.CodePage, encoding.CodePage, "Encoding"); + } + + [Test] + public void TestNullContentIsAscii () + { + var part = new TextPart ("plain"); + + Assert.AreEqual (string.Empty, part.Text, "Text"); + Assert.AreEqual (string.Empty, part.GetText (Encoding.ASCII), "GetText"); + + var actual = part.GetText (out Encoding encoding); + + Assert.AreEqual (string.Empty, actual, "GetText(out Encoding)"); + Assert.AreEqual (Encoding.ASCII.CodePage, encoding.CodePage, "Encoding"); + } + + [Test] + public void TestLatin1 () + { + const string text = "This is some Låtín1 text."; + + var latin1 = Encoding.GetEncoding ("iso-8859-1"); + var memory = new MemoryStream (); + var buffer = latin1.GetBytes (text); + memory.Write (buffer, 0, buffer.Length); + memory.Position = 0; + + var part = new TextPart ("plain") { Content = new MimeContent (memory) }; + + Assert.AreEqual (text, part.Text); + + var actual = part.GetText (out Encoding encoding); + + Assert.AreEqual (text, actual, "GetText(out Encoding)"); + Assert.AreEqual (latin1.CodePage, encoding.CodePage, "Encoding"); + } + + [Test] + public void TestUTF16BE () + { + const string text = "This is some UTF-16BE text.\r\nThis is line #2."; + var expected = text.Replace ("\r\n", Environment.NewLine); + + var memory = new MemoryStream (); + memory.WriteByte (0xfe); + memory.WriteByte (0xff); + + var buffer = Encoding.BigEndianUnicode.GetBytes (text); + memory.Write (buffer, 0, buffer.Length); + memory.Position = 0; + + var part = new TextPart ("plain") { Content = new MimeContent (memory) }; + + Assert.AreEqual (expected, part.Text.Substring (1)); + + var actual = part.GetText (out Encoding encoding); + + Assert.AreEqual (expected, actual.Substring (1), "GetText(out Encoding)"); + Assert.AreEqual (Encoding.BigEndianUnicode.CodePage, encoding.CodePage, "Encoding"); + } + + [Test] + public void TestUTF16LE () + { + const string text = "This is some UTF-16LE text.\r\nThis is line #2."; + var expected = text.Replace ("\r\n", Environment.NewLine); + + var memory = new MemoryStream (); + memory.WriteByte (0xff); + memory.WriteByte (0xfe); + + var buffer = Encoding.Unicode.GetBytes (text); + memory.Write (buffer, 0, buffer.Length); + memory.Position = 0; + + var part = new TextPart ("plain") { Content = new MimeContent (memory) }; + + Assert.AreEqual (expected, part.Text.Substring (1)); + + var actual = part.GetText (out Encoding encoding); + + Assert.AreEqual (expected, actual.Substring (1), "GetText(out Encoding)"); + Assert.AreEqual (Encoding.Unicode.CodePage, encoding.CodePage, "Encoding"); } } } diff --git a/UnitTests/TextRfc822HeadersTests.cs b/UnitTests/TextRfc822HeadersTests.cs new file mode 100644 index 0000000000..b09a0b0597 --- /dev/null +++ b/UnitTests/TextRfc822HeadersTests.cs @@ -0,0 +1,90 @@ +// +// TextRfc822HeadersTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using NUnit.Framework; + +using MimeKit; + +namespace UnitTests +{ + [TestFixture] + public class TextRfc822HeadersTests + { + [Test] + public void TestArgumentExceptions () + { + var entity = new TextRfc822Headers (); + + Assert.Throws (() => new TextRfc822Headers ("unknown-parameter")); + Assert.Throws (() => new TextRfc822Headers (new MimeMessage (), new MimeMessage ())); + + Assert.Throws (() => entity.Accept (null)); + } + + class TextRfc822HeadersVisitor : MimeVisitor + { + public TextRfc822Headers Rfc822Headers; + + protected internal override void VisitTextRfc822Headers (TextRfc822Headers entity) + { + Rfc822Headers = entity; + } + } + + [Test] + public void TestSerializationAndDeserialization () + { + var message = new MimeMessage (); + message.From.Add (new MailboxAddress ("Sender Name", "sender@example.com")); + message.To.Add (new MailboxAddress ("Recipient Name", "recipient@example.com")); + message.Subject = "Content of a text/rfc822-headers part"; + + var rfc822headers = new TextRfc822Headers (new Header (HeaderId.ContentId, ""), message); + + message = new MimeMessage (); + message.From.Add (new MailboxAddress ("Postmaster", "postmaster@example.com")); + message.To.Add (new MailboxAddress ("Sender Name", "sender@example.com.com")); + message.Subject = "Sorry, but your message bounced"; + message.Body = rfc822headers; + + using (var stream = new MemoryStream ()) { + message.WriteTo (stream); + stream.Position = 0; + + message = MimeMessage.Load (stream); + + var visitor = new TextRfc822HeadersVisitor (); + visitor.Visit (message); + + Assert.IsNotNull (visitor.Rfc822Headers, "Rfc822Headers"); + Assert.AreEqual ("id@localhost", visitor.Rfc822Headers.ContentId, "ContentId"); + } + } + } +} diff --git a/UnitTests/Tnef/RtfCompressedToRtfTests.cs b/UnitTests/Tnef/RtfCompressedToRtfTests.cs new file mode 100644 index 0000000000..f2243a7430 --- /dev/null +++ b/UnitTests/Tnef/RtfCompressedToRtfTests.cs @@ -0,0 +1,173 @@ +// +// RtfCompressedToRtfTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; +using System.Text; + +using NUnit.Framework; + +using MimeKit.Tnef; + +namespace UnitTests.Tnef { + [TestFixture] + public class RtfCompressedToRtfTests + { + [Test] + public void TestRtfCompressedToRtfUnknownCompressionType () + { + var input = new byte[] { 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', 0xff, 0xff, 0xff, 0xff }; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + output = filter.Flush (input, 0, input.Length, out outputIndex, out outputLength); + + Assert.AreEqual (16, outputIndex, "outputIndex"); + Assert.AreEqual (0, outputLength, "outputLength"); + Assert.IsFalse (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual ((RtfCompressionMode) 1145258561, filter.CompressionMode, "ComnpressionMode"); + } + + [Test] + public void TestRtfCompressedToRtfInvalidCrc () + { + var input = new byte[] { 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, (byte) 'L', (byte) 'Z', (byte) 'F', (byte) 'u', 0xff, 0xff, 0xff, 0xff }; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + output = filter.Flush (input, 0, input.Length, out outputIndex, out outputLength); + + Assert.AreEqual (0, outputIndex, "outputIndex"); + Assert.AreEqual (0, outputLength, "outputLength"); + Assert.IsFalse (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual (RtfCompressionMode.Compressed, filter.CompressionMode, "ComnpressionMode"); + } + + [Test] + public void TestRtfCompressedToRtf () + { + var input = new byte[] { (byte) '-', 0x00, 0x00, 0x00, (byte) '+', 0x00, 0x00, 0x00, (byte) 'L', (byte) 'Z', (byte) 'F', (byte) 'u', 0xf1, 0xc5, 0xc7, 0xa7, 0x03, 0x00, (byte) '\n', 0x00, (byte) 'r', (byte) 'c', (byte) 'p', (byte) 'g', (byte) '1', (byte) '2', (byte) '5', (byte) 'B', (byte) '2', (byte) '\n', 0xf3, (byte) ' ', (byte) 'h', (byte) 'e', (byte) 'l', (byte) '\t', 0x00, (byte) ' ', (byte) 'b', (byte) 'w', 0x05, 0xb0, (byte) 'l', (byte) 'd', (byte) '}', (byte) '\n', 0x80, 0x0f, 0xa0 }; + const string expected = "{\\rtf1\\ansi\\ansicpg1252\\pard hello world}\r\n"; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + output = filter.Flush (input, 0, input.Length, out outputIndex, out outputLength); + + Assert.AreEqual (0, outputIndex, "outputIndex"); + Assert.AreEqual (43, outputLength, "outputLength"); + Assert.IsTrue (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual (RtfCompressionMode.Compressed, filter.CompressionMode, "ComnpressionMode"); + + var text = Encoding.ASCII.GetString (output, outputIndex, outputLength); + + Assert.AreEqual (expected, text); + } + + [Test] + public void TestRtfCompressedToRtfByteByByte () + { + var input = new byte[] { (byte) '-', 0x00, 0x00, 0x00, (byte) '+', 0x00, 0x00, 0x00, (byte) 'L', (byte) 'Z', (byte) 'F', (byte) 'u', 0xf1, 0xc5, 0xc7, 0xa7, 0x03, 0x00, (byte) '\n', 0x00, (byte) 'r', (byte) 'c', (byte) 'p', (byte) 'g', (byte) '1', (byte) '2', (byte) '5', (byte) 'B', (byte) '2', (byte) '\n', 0xf3, (byte) ' ', (byte) 'h', (byte) 'e', (byte) 'l', (byte) '\t', 0x00, (byte) ' ', (byte) 'b', (byte) 'w', 0x05, 0xb0, (byte) 'l', (byte) 'd', (byte) '}', (byte) '\n', 0x80, 0x0f, 0xa0 }; + const string expected = "{\\rtf1\\ansi\\ansicpg1252\\pard hello world}\r\n"; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + using (var memory = new MemoryStream ()) { + for (int i = 0; i < input.Length; i++) { + output = filter.Filter (input, i, 1, out outputIndex, out outputLength); + memory.Write (output, outputIndex, outputLength); + } + + output = filter.Flush (input, 0, 0, out outputIndex, out outputLength); + memory.Write (output, outputIndex, outputLength); + + output = memory.ToArray (); + } + + Assert.AreEqual (43, output.Length, "outputLength"); + Assert.IsTrue (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual (RtfCompressionMode.Compressed, filter.CompressionMode, "ComnpressionMode"); + + var text = Encoding.ASCII.GetString (output); + + Assert.AreEqual (expected, text); + } + + [Test] + public void TestRtfCompressedToRtfRaw () + { + var input = new byte[] { (byte) '.', 0x00, 0x00, 0x00, (byte) '\"', 0x00, 0x00, 0x00, (byte) 'M', (byte) 'E', (byte) 'L', (byte) 'A', (byte) ' ', 0xdf, 0x12, 0xce, (byte) '{', (byte) '\\', (byte) 'r', (byte) 't', (byte) 'f', (byte) '1', (byte) '\\', (byte) 'a', (byte) 'n', (byte) 's', (byte) 'i', (byte) '\\', (byte) 'a', (byte) 'n', (byte) 's', (byte) 'i', (byte) 'c', (byte) 'p', (byte) 'g', (byte) '1', (byte) '2', (byte) '5', (byte) '2', (byte) '\\', (byte) 'p', (byte) 'a', (byte) 'r', (byte) 'd', (byte) ' ', (byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) '}' }; + const string expected = "{\\rtf1\\ansi\\ansicpg1252\\pard test}"; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + output = filter.Flush (input, 0, input.Length, out outputIndex, out outputLength); + + Assert.AreEqual (16, outputIndex, "outputIndex"); + Assert.AreEqual (34, outputLength, "outputLength"); + Assert.IsTrue (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual (RtfCompressionMode.Uncompressed, filter.CompressionMode, "ComnpressionMode"); + + var text = Encoding.ASCII.GetString (output, outputIndex, outputLength); + + Assert.AreEqual (expected, text); + } + + [Test] + public void TestRtfCompressedToRtfRawByteByByte () + { + var input = new byte[] { (byte) '.', 0x00, 0x00, 0x00, (byte) '\"', 0x00, 0x00, 0x00, (byte) 'M', (byte) 'E', (byte) 'L', (byte) 'A', (byte) ' ', 0xdf, 0x12, 0xce, (byte) '{', (byte) '\\', (byte) 'r', (byte) 't', (byte) 'f', (byte) '1', (byte) '\\', (byte) 'a', (byte) 'n', (byte) 's', (byte) 'i', (byte) '\\', (byte) 'a', (byte) 'n', (byte) 's', (byte) 'i', (byte) 'c', (byte) 'p', (byte) 'g', (byte) '1', (byte) '2', (byte) '5', (byte) '2', (byte) '\\', (byte) 'p', (byte) 'a', (byte) 'r', (byte) 'd', (byte) ' ', (byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) '}' }; + const string expected = "{\\rtf1\\ansi\\ansicpg1252\\pard test}"; + var filter = new RtfCompressedToRtf (); + int outputIndex, outputLength; + byte[] output; + + using (var memory = new MemoryStream ()) { + for (int i = 0; i < input.Length; i++) { + output = filter.Filter (input, i, 1, out outputIndex, out outputLength); + memory.Write (output, outputIndex, outputLength); + } + + output = filter.Flush (input, 0, 0, out outputIndex, out outputLength); + memory.Write (output, outputIndex, outputLength); + + output = memory.ToArray (); + } + + Assert.AreEqual (34, output.Length, "outputLength"); + Assert.IsTrue (filter.IsValidCrc32, "IsValidCrc32"); + Assert.AreEqual (RtfCompressionMode.Uncompressed, filter.CompressionMode, "ComnpressionMode"); + + var text = Encoding.ASCII.GetString (output); + + Assert.AreEqual (expected, text); + } + } +} diff --git a/UnitTests/Tnef/TnefReaderStreamTests.cs b/UnitTests/Tnef/TnefReaderStreamTests.cs new file mode 100644 index 0000000000..d0ef6c9d9b --- /dev/null +++ b/UnitTests/Tnef/TnefReaderStreamTests.cs @@ -0,0 +1,70 @@ +// +// TnefReaderStreamTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using NUnit.Framework; + +using MimeKit.Tnef; + +namespace UnitTests.Tnef { + [TestFixture] + public class TnefReaderStreamTests + { + static readonly string DataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "tnef"); + + [Test] + public void TestTnefReaderStream () + { + using (var stream = File.OpenRead (Path.Combine (DataDir, "winmail.tnef"))) { + using (var reader = new TnefReader (stream)) { + var buffer = new byte[1024]; + + using (var tnef = new TnefReaderStream (reader, 0, 0)) { + Assert.IsTrue (tnef.CanRead); + Assert.IsFalse (tnef.CanWrite); + Assert.IsFalse (tnef.CanSeek); + Assert.IsFalse (tnef.CanTimeout); + + Assert.Throws (() => tnef.Read (null, 0, buffer.Length)); + Assert.Throws (() => tnef.Read (buffer, -1, buffer.Length)); + Assert.Throws (() => tnef.Read (buffer, 0, -1)); + + Assert.Throws (() => tnef.Write (buffer, 0, buffer.Length)); + Assert.Throws (() => tnef.Seek (0, SeekOrigin.End)); + Assert.Throws (() => tnef.Flush ()); + Assert.Throws (() => tnef.SetLength (1024)); + + Assert.Throws (() => { var x = tnef.Position; }); + Assert.Throws (() => { tnef.Position = 0; }); + Assert.Throws (() => { var x = tnef.Length; }); + } + } + } + } + } +} diff --git a/UnitTests/Tnef/TnefReaderTests.cs b/UnitTests/Tnef/TnefReaderTests.cs new file mode 100644 index 0000000000..73a0e9c0d5 --- /dev/null +++ b/UnitTests/Tnef/TnefReaderTests.cs @@ -0,0 +1,526 @@ +// +// TnefReaderTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.IO; + +using NUnit.Framework; + +using MimeKit.Tnef; + +namespace UnitTests.Tnef { + [TestFixture] + public class TnefReaderTests + { + static readonly string DataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "tnef"); + + [Test] + public void TestArgumentExceptions () + { + using (var stream = File.OpenRead (Path.Combine (DataDir, "winmail.tnef"))) { + Assert.Throws (() => new TnefReader (null, 0, TnefComplianceMode.Strict)); + Assert.Throws (() => new TnefReader (stream, -1, TnefComplianceMode.Strict)); + + using (var reader = new TnefReader (stream, 1252, TnefComplianceMode.Strict)) { + var buffer = new byte[16]; + + Assert.Throws (() => reader.ReadAttributeRawValue (null, 0, buffer.Length)); + Assert.Throws (() => reader.ReadAttributeRawValue (buffer, -1, buffer.Length)); + Assert.Throws (() => reader.ReadAttributeRawValue (buffer, 0, -1)); + } + } + } + + [Test] + public void TestSetComplianceError () + { + using (var stream = File.OpenRead (Path.Combine (DataDir, "winmail.tnef"))) { + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + foreach (TnefComplianceStatus error in Enum.GetValues (typeof (TnefComplianceStatus))) { + if (error == TnefComplianceStatus.Compliant) { + Assert.DoesNotThrow (() => reader.SetComplianceError (error)); + } else { + Assert.Throws (() => reader.SetComplianceError (error)); + } + } + } + } + } + + [Test] + public void TestTruncatedHeader () + { + using (var stream = new MemoryStream ()) { + Assert.Throws (() => new TnefReader (stream, 0, TnefComplianceMode.Strict)); + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, reader.ComplianceStatus); + + reader.ResetComplianceStatus (); + Assert.AreEqual (TnefComplianceStatus.Compliant, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestTruncatedHeaderAfterSignature () + { + using (var stream = new MemoryStream ()) { + var invalidSignature = BitConverter.GetBytes (0x223e9f78); + + stream.Write (invalidSignature, 0, invalidSignature.Length); + stream.WriteByte (0); + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestInvalidSignatureLoose () + { + using (var stream = new MemoryStream ()) { + var invalidSignature = BitConverter.GetBytes (0x223e9f79); + + stream.Write (invalidSignature, 0, invalidSignature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.AreEqual (TnefComplianceStatus.InvalidTnefSignature, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestInvalidSignatureStrict () + { + using (var stream = new MemoryStream ()) { + var invalidSignature = BitConverter.GetBytes (0x223e9f79); + TnefReader reader; + + stream.Write (invalidSignature, 0, invalidSignature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + stream.Position = 0; + + try { + reader = new TnefReader (stream, 0, TnefComplianceMode.Strict); + Assert.Fail ("new TnefReader should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.InvalidTnefSignature, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("new TnefReader should have thrown TnefException, not {0}", ex); + } + } + } + + [Test] + public void TestInvalidOemCodepageLoose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (1), 0, 4); + + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.IsTrue (reader.ReadNextAttribute (), "ReadNextAttribute"); + Assert.AreEqual (TnefAttributeTag.OemCodepage, reader.AttributeTag, "AttributeTag"); + Assert.AreEqual (TnefComplianceStatus.InvalidMessageCodepage, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestInvalidOemCodepageStrict () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (1), 0, 4); + + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + try { + reader.ReadNextAttribute (); + Assert.Fail ("ReadNextAttribute should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.InvalidMessageCodepage, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("ReadNextAttribute should have thrown TnefException, not {0}", ex); + } + } + } + } + + [Test] + public void TestInvalidTnefVersionLoose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (1), 0, 4); + + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.IsTrue (reader.ReadNextAttribute (), "ReadNextAttribute"); + Assert.AreEqual (TnefAttributeTag.TnefVersion, reader.AttributeTag, "AttributeTag"); + reader.TnefPropertyReader.ReadValueAsInt32 (); + Assert.AreEqual (1, reader.TnefVersion, "TnefVersion"); + Assert.AreEqual (TnefComplianceStatus.InvalidTnefVersion, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestInvalidTnefVersionStrict () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (1), 0, 4); + + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + try { + reader.ReadNextAttribute (); + Assert.Fail ("ReadNextAttribute should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.InvalidTnefVersion, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("ReadNextAttribute should have thrown TnefException, not {0}", ex); + } + } + } + } + + [Test] + public void TestNegativeAttributeRawValueLengthLoose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (-4), 0, 4); + stream.Write (BitConverter.GetBytes (65536), 0, 4); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (28591), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.IsFalse (reader.ReadNextAttribute (), "ReadNextAttribute"); + Assert.AreEqual (TnefAttributeTag.TnefVersion, reader.AttributeTag, "AttributeTag"); + Assert.AreEqual (TnefComplianceStatus.InvalidAttributeLength, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestNegativeAttributeRawValueLengthStrict () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (-4), 0, 4); + stream.Write (BitConverter.GetBytes (65536), 0, 4); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (28591), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + try { + reader.ReadNextAttribute (); + Assert.Fail ("ReadNextAttribute should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.InvalidAttributeLength, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("ReadNextAttribute should have thrown TnefException, not {0}", ex); + } + } + } + } + + [Test] + public void TestReadAfterClose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (28), 0, 4); + stream.Write (BitConverter.GetBytes (65536), 0, 4); + stream.Position = 0; + + var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose); + reader.Close (); + + Assert.Throws (() => reader.ReadNextAttribute ()); + } + } + + [Test] + public void TestReadAttributeRawValueTruncatedLoose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.MessageId), 0, 4); + stream.Write (BitConverter.GetBytes (28), 0, 4); + stream.Write (BitConverter.GetBytes (0xFFFFFFFF), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.IsTrue (reader.ReadNextAttribute (), "ReadNextAttribute"); + Assert.AreEqual (TnefAttributeTag.MessageId, reader.AttributeTag, "AttributeTag"); + + var buffer = new byte[28]; + int nread, n = 0; + + do { + if ((nread = reader.ReadAttributeRawValue (buffer, n, buffer.Length - n)) == 0) + break; + + n += nread; + } while (n < 28); + + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestReadAttributeRawValueTruncatedStrict () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.MessageId), 0, 4); + stream.Write (BitConverter.GetBytes (28), 0, 4); + stream.Write (BitConverter.GetBytes (0xFFFFFFFF), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + Assert.IsTrue (reader.ReadNextAttribute (), "ReadNextAttribute"); + Assert.AreEqual (TnefAttributeTag.MessageId, reader.AttributeTag, "AttributeTag"); + + var buffer = new byte[28]; + int n; + + n = reader.ReadAttributeRawValue (buffer, 0, buffer.Length); + + try { + reader.ReadAttributeRawValue (buffer, n, buffer.Length - n); + Assert.Fail ("ReadAttributeRawValue should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("ReadAttributeRawValue should have thrown TnefException, not {0}", ex); + } + } + } + } + + [Test] + public void TestReadInt32 () + { + using (var stream = new MemoryStream ()) { + var signature = BitConverter.GetBytes (0x223e9f78); + + stream.Write (signature, 0, signature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + + var buffer = BitConverter.GetBytes (1060); + stream.Write (buffer, 0, buffer.Length); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + var value = reader.ReadInt32 (); + + Assert.AreEqual (1060, value); + } + } + } + + [Test] + public void TestReadInt64 () + { + using (var stream = new MemoryStream ()) { + var signature = BitConverter.GetBytes (0x223e9f78); + + stream.Write (signature, 0, signature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + + var buffer = BitConverter.GetBytes ((long) 1060); + stream.Write (buffer, 0, buffer.Length); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + var value = reader.ReadInt64 (); + + Assert.AreEqual (1060, value); + } + } + } + + [Test] + public void TestReadDouble () + { + using (var stream = new MemoryStream ()) { + var signature = BitConverter.GetBytes (0x223e9f78); + + stream.Write (signature, 0, signature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + + var buffer = BitConverter.GetBytes (1024.1024); + stream.Write (buffer, 0, buffer.Length); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + var value = reader.ReadDouble (); + + Assert.AreEqual (1024.1024, value); + } + } + } + + [Test] + public void TestReadSingle () + { + using (var stream = new MemoryStream ()) { + var signature = BitConverter.GetBytes (0x223e9f78); + + stream.Write (signature, 0, signature.Length); + stream.WriteByte (0); + stream.WriteByte (0); + + var buffer = BitConverter.GetBytes ((float) 1024.1024); + stream.Write (buffer, 0, buffer.Length); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + var value = reader.ReadSingle (); + + Assert.AreEqual ((float) 1024.1024, value); + } + } + } + + [Test] + public void TestSeekTruncatedLoose () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (65536), 0, 4); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (28591), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Loose)) { + Assert.IsFalse (reader.Seek (64), "Seek"); + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, reader.ComplianceStatus); + } + } + } + + [Test] + public void TestSeekTruncatedStrict () + { + using (var stream = new MemoryStream ()) { + stream.Write (BitConverter.GetBytes (0x223e9f78), 0, 4); + stream.WriteByte (0); + stream.WriteByte (0); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.TnefVersion), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (65536), 0, 4); + stream.WriteByte ((byte) TnefAttributeLevel.Message); + stream.Write (BitConverter.GetBytes ((int) TnefAttributeTag.OemCodepage), 0, 4); + stream.Write (BitConverter.GetBytes (4), 0, 4); + stream.Write (BitConverter.GetBytes (28591), 0, 4); + stream.Position = 0; + + using (var reader = new TnefReader (stream, 0, TnefComplianceMode.Strict)) { + try { + reader.Seek (64); + Assert.Fail ("Seek should have thrown TnefException"); + } catch (TnefException ex) { + Assert.AreEqual (TnefComplianceStatus.StreamTruncated, ex.Error, "Error"); + } catch (Exception ex) { + Assert.Fail ("Seek should have thrown TnefException, not {0}", ex); + } + } + } + } + } +} diff --git a/UnitTests/Tnef/TnefTests.cs b/UnitTests/Tnef/TnefTests.cs index 3a7766968e..825537f8bf 100644 --- a/UnitTests/Tnef/TnefTests.cs +++ b/UnitTests/Tnef/TnefTests.cs @@ -1,9 +1,9 @@ -// +// // TnefTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,12 @@ using System.IO; using System.Text; using System.Linq; +using System.Globalization; using MimeKit; using MimeKit.IO; using MimeKit.Tnef; +using MimeKit.Utils; using MimeKit.IO.Filters; using NUnit.Framework; @@ -40,6 +42,14 @@ namespace UnitTests.Tnef { [TestFixture] public class TnefTests { + [Test] + public void TestArgumentExceptions () + { + var tnef = new TnefPart (); + + Assert.Throws (() => tnef.Accept (null)); + } + static void ExtractRecipientTable (TnefReader reader, MimeMessage message) { var prop = reader.TnefPropertyReader; @@ -157,6 +167,7 @@ static void ExtractRecipientTable (TnefReader reader, MimeMessage message) static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyBuilder builder) { + string normalizedSubject = null, subjectPrefix = null; var prop = reader.TnefPropertyReader; var chars = new char[1024]; var buf = new byte[1024]; @@ -192,6 +203,8 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB rtf.ContentType.Name = "body.rtf"; var converter = new RtfCompressedToRtf (); + converter.Reset (); + var content = new MemoryStream (); using (var filtered = new FilteredStream (content)) { @@ -269,7 +282,7 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB break; case TnefPropertyId.SubjectPrefix: Assert.AreEqual (typeof (string), type); - value = prop.ReadValueAsString (); + subjectPrefix = prop.ReadValueAsString (); break; case TnefPropertyId.MessageSubmissionId: Assert.AreEqual (typeof (byte[]), type); @@ -287,10 +300,22 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB Assert.AreEqual (typeof (string), type); value = prop.ReadValueAsString (); break; - case TnefPropertyId.NormalizedSubject: + case TnefPropertyId.SenderEmailAddress: + Assert.AreEqual (typeof (string), type); + value = prop.ReadValueAsString (); + break; + case TnefPropertyId.SenderAddrtype: Assert.AreEqual (typeof (string), type); value = prop.ReadValueAsString (); break; + case TnefPropertyId.SenderSearchKey: + Assert.AreEqual (typeof (byte[]), type); + value = prop.ReadValueAsString (); + break; + case TnefPropertyId.NormalizedSubject: + Assert.AreEqual (typeof (string), type); + normalizedSubject = prop.ReadValueAsString (); + break; case TnefPropertyId.CreationTime: Assert.AreEqual (typeof (DateTime), type); value = prop.ReadValueAsDateTime (); @@ -323,10 +348,6 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB Assert.AreEqual (typeof (byte[]), type); value = prop.ReadValueAsString (); break; - case TnefPropertyId.SenderSearchKey: - Assert.AreEqual (typeof (byte[]), type); - value = prop.ReadValueAsString (); - break; case TnefPropertyId.DeleteAfterSubmit: Assert.AreEqual (typeof (bool), type); value = prop.ReadValueAsBoolean (); @@ -389,6 +410,13 @@ static void ExtractMapiProperties (TnefReader reader, MimeMessage message, BodyB break; } } + + if (string.IsNullOrEmpty (message.Subject) && !string.IsNullOrEmpty (normalizedSubject)) { + if (!string.IsNullOrEmpty (subjectPrefix)) + message.Subject = subjectPrefix + normalizedSubject; + else + message.Subject = normalizedSubject; + } } static void ExtractAttachments (TnefReader reader, BodyBuilder builder) @@ -401,14 +429,17 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) TnefAttachFlags flags; string[] mimeType; byte[] attachData; + byte[] buffer; DateTime time; string text; //Console.WriteLine ("Extracting attachments..."); do { - if (reader.AttributeLevel != TnefAttributeLevel.Attachment) - Assert.Fail ("Expected attachment attribute level: {0}", reader.AttributeLevel); + if (reader.AttributeLevel != TnefAttributeLevel.Attachment) { + //Assert.Fail ("Expected attachment attribute level: {0}", reader.AttributeLevel); + break; + } switch (reader.AttributeTag) { case TnefAttributeTag.AttachRenderData: @@ -450,15 +481,19 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) //Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachContentId: - attachment.ContentId = prop.ReadValueAsString (); + text = prop.ReadValueAsString (); + + buffer = CharsetUtils.UTF8.GetBytes (text); + int index = 0; + + if (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out string msgid)) + attachment.ContentId = msgid; //Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, attachment.ContentId); break; case TnefPropertyId.AttachDisposition: text = prop.ReadValueAsString (); - if (attachment.ContentDisposition == null) - attachment.ContentDisposition = new ContentDisposition (text); - else - attachment.ContentDisposition.Disposition = text; + if (ContentDisposition.TryParse (text, out ContentDisposition disposition)) + attachment.ContentDisposition = disposition; //Console.WriteLine ("Attachment Property: {0} = {1}", prop.PropertyTag.Id, text); break; case TnefPropertyId.AttachMethod: @@ -487,7 +522,6 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) case TnefPropertyId.AttachData: var stream = prop.GetRawValueReadStream (); var content = new MemoryStream (); - var guid = new byte[16]; if (attachMethod == TnefAttachMethod.EmbeddedMessage) { var tnef = new TnefPart (); @@ -501,11 +535,9 @@ static void ExtractAttachments (TnefReader reader, BodyBuilder builder) attachment = tnef; } - stream.Read (guid, 0, 16); - stream.CopyTo (content, 4096); - var buffer = content.GetBuffer (); + buffer = content.GetBuffer (); filter.Flush (buffer, 0, (int) content.Length, out outIndex, out outLength); attachment.ContentTransferEncoding = filter.GetBestEncoding (EncodingConstraint.SevenBit); attachment.Content = new MimeContent (content); @@ -594,6 +626,8 @@ static MimeMessage ExtractTnefMessage (TnefReader reader) var builder = new BodyBuilder (); var message = new MimeMessage (); + message.Headers.Remove (HeaderId.Date); + while (reader.ReadNextAttribute ()) { if (reader.AttributeLevel == TnefAttributeLevel.Attachment) break; @@ -620,6 +654,9 @@ static MimeMessage ExtractTnefMessage (TnefReader reader) break; case TnefAttributeTag.TnefVersion: //Console.WriteLine ("Message Attribute: {0} = {1}", reader.AttributeTag, prop.ReadValueAsInt32 ()); + var version = prop.ReadValueAsInt32 (); + Assert.AreEqual (65536, version, "version"); + Assert.AreEqual (65536, reader.TnefVersion, "TnefVersion"); break; case TnefAttributeTag.OemCodepage: int codepage = prop.ReadValueAsInt32 (); @@ -658,9 +695,25 @@ static MimeMessage ParseTnefMessage (string path, TnefComplianceStatus expected) } } - static void TestTnefParser (string path, TnefComplianceStatus expected = TnefComplianceStatus.Compliant) + static byte[] ReadAllBytes (Stream stream, bool text) { + using (var memory = new MemoryStream ()) { + using (var filtered = new FilteredStream (memory)) { + if (text) + filtered.Add (new Dos2UnixFilter (true)); + stream.CopyTo (filtered, 4096); + filtered.Flush (); + + return memory.ToArray (); + } + } + } + + static void TestTnefParser (string baseFileName, TnefComplianceStatus expected = TnefComplianceStatus.Compliant) + { + var path = Path.Combine (TestHelper.ProjectDir, "TestData", "tnef", baseFileName); var message = ParseTnefMessage (path + ".tnef", expected); + var tnefName = Path.GetFileName (path + ".tnef"); var names = File.ReadAllLines (path + ".list"); foreach (var name in names) { @@ -682,11 +735,27 @@ static void TestTnefParser (string path, TnefComplianceStatus expected = TnefCom var tnef = new TnefPart { Content = new MimeContent (content) }; var attachments = tnef.ExtractAttachments ().ToList (); + // Step 1: make sure we've extracted the body and all of the attachments foreach (var name in names) { bool found = false; foreach (var part in attachments.OfType ()) { - if (part.FileName == name) { + if (part is TextPart && string.IsNullOrEmpty (part.FileName)) { + var basename = Path.GetFileNameWithoutExtension (name); + var extension = Path.GetExtension (name); + string subtype; + + switch (extension) { + case ".html": subtype = "html"; break; + case ".rtf": subtype = "rtf"; break; + default: subtype = "plain"; break; + } + + if (basename == "body" && part.ContentType.IsMimeType ("text", subtype)) { + found = true; + break; + } + } else if (part.FileName == name) { found = true; break; } @@ -695,19 +764,91 @@ static void TestTnefParser (string path, TnefComplianceStatus expected = TnefCom if (!found) Assert.Fail ("Failed to locate attachment in TnefPart: {0}", name); } + + // Step 2: verify that the content of the extracted attachments matches up with the expected content + byte[] expectedData, actualData; + int untitled = 1; + + foreach (var part in attachments.OfType ()) { + var isText = false; + string fileName; + + if (part is TextPart text && string.IsNullOrEmpty (part.FileName)) { + if (text.IsHtml) + fileName = "message.html"; + else if (text.IsRichText) + fileName = "message.rtf"; + else + fileName = "message.txt"; + + isText = true; + } else if (part.FileName == "Untitled Attachment") { + // special case for winmail.tnef and christmas.tnef + fileName = string.Format (CultureInfo.InvariantCulture, "Untitled Attachment.{0}", untitled++); + } else { + var extension = Path.GetExtension (part.FileName); + + switch (extension) { + case ".cfg": + case ".dat": + case ".htm": + case ".ini": + case ".src": + isText = true; + break; + case "": + isText = part.FileName == "AUTHORS" || part.FileName == "README"; + break; + } + + fileName = part.FileName; + } + + var file = Path.Combine (path, fileName); + + if (!File.Exists (file)) { + //using (var stream = part.Content.Open ()) { + // actualData = ReadAllBytes (stream, isText); + // File.WriteAllBytes (file, actualData); + //} + continue; + } + + using (var stream = File.OpenRead (file)) + expectedData = ReadAllBytes (stream, isText); + + using (var stream = part.Content.Open ()) + actualData = ReadAllBytes (stream, isText); + + Assert.AreEqual (expectedData.Length, actualData.Length, $"{tnefName}: {fileName} content length does not match"); + for (int i = 0; i < expectedData.Length; i++) + Assert.AreEqual (expectedData[i], actualData[i], $"{tnefName}: {fileName} content differs at index {i}"); + } } } + [Test] + public void TestAttachments () + { + TestTnefParser ("attachments"); + } + [Test] public void TestBody () { - TestTnefParser ("../../TestData/tnef/body"); + TestTnefParser ("body"); + } + + [Test] + public void TestChristmas () + { + TestTnefParser ("christmas", TnefComplianceStatus.UnsupportedPropertyType); } [Test] public void TestDataBeforeName () { - TestTnefParser ("../../TestData/tnef/data-before-name"); + TestTnefParser ("data-before-name"); } [Test] @@ -715,93 +856,208 @@ public void TestGarbageAtEnd () { const TnefComplianceStatus errors = TnefComplianceStatus.InvalidAttributeLevel | TnefComplianceStatus.StreamTruncated; - TestTnefParser ("../../TestData/tnef/garbage-at-end", errors); + TestTnefParser ("garbage-at-end", errors); } [Test] public void TestLongFileName () { - TestTnefParser ("../../TestData/tnef/long-filename"); + TestTnefParser ("long-filename"); } [Test] public void TestMapiAttachDataObj () { - TestTnefParser ("../../TestData/tnef/MAPI_ATTACH_DATA_OBJ"); + TestTnefParser ("MAPI_ATTACH_DATA_OBJ"); } [Test] public void TestMapiObject () { - TestTnefParser ("../../TestData/tnef/MAPI_OBJECT"); + TestTnefParser ("MAPI_OBJECT"); } [Test] public void TestMissingFileNames () { - TestTnefParser ("../../TestData/tnef/missing-filenames"); + TestTnefParser ("missing-filenames"); } [Test] public void TestMultiNameProperty () { - TestTnefParser ("../../TestData/tnef/multi-name-property"); + TestTnefParser ("multi-name-property"); + } + + [Test] + public void TestMultiValueAttribute () + { + TestTnefParser ("multi-value-attribute"); } [Test] public void TestOneFile () { - TestTnefParser ("../../TestData/tnef/one-file"); + TestTnefParser ("one-file"); + } + + [Test] + public void TestPanic () + { + TestTnefParser ("panic", TnefComplianceStatus.InvalidAttribute | TnefComplianceStatus.InvalidAttributeLevel); } [Test] public void TestRtf () { - TestTnefParser ("../../TestData/tnef/rtf"); + TestTnefParser ("rtf"); } [Test] public void TestTriples () { - TestTnefParser ("../../TestData/tnef/triples"); + TestTnefParser ("triples"); } [Test] public void TestTwoFiles () { - TestTnefParser ("../../TestData/tnef/two-files"); + TestTnefParser ("two-files"); + } + + [Test] + public void TestUnicodeMapiAttrName () + { + TestTnefParser ("unicode-mapi-attr-name"); + } + + [Test] + public void TestUnicodeMapiAttr () + { + TestTnefParser ("unicode-mapi-attr"); } [Test] public void TestWinMail () { - TestTnefParser ("../../TestData/tnef/winmail"); + TestTnefParser ("winmail"); } [Test] public void TestExtractedCharset () { const string expected = "\r\n\r\n\r\n\r\n\r\n\r\n
\r\n

ЫПУФЙК

\r\n


\r\n

\r\n

{EMAILSIGNATURE}

\r\n


\r\n

\r\n

\r\n
\r\nRR Test 1\r\n
\r\n

 

\r\n
\r\n
\r\n\r\n\r\n"; - var message = MimeMessage.Load ("../../TestData/tnef/ukr.eml"); + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "tnef", "ukr.eml")); var tnef = message.BodyParts.OfType ().FirstOrDefault (); message = tnef.ConvertToMessage (); - Assert.IsInstanceOf (typeof (Multipart), message.Body); - - var mixed = (Multipart) message.Body; + Assert.IsInstanceOf (typeof (TextPart), message.Body); - Assert.AreEqual (1, mixed.Count); - Assert.IsInstanceOf (typeof (TextPart), mixed[0]); - - var text = (TextPart) mixed[0]; + var text = (TextPart) message.Body; Assert.IsTrue (text.IsHtml); var html = text.Text; Assert.AreEqual ("windows-1251", text.ContentType.Charset); - Assert.AreEqual (expected, html); + Assert.AreEqual (expected.Replace ("\r\n", Environment.NewLine), html); + } + + [Test] + public void TestRichTextEml () + { + var message = MimeMessage.Load (Path.Combine (TestHelper.ProjectDir, "TestData", "tnef", "rich-text.eml")); + var tnef = message.BodyParts.OfType ().FirstOrDefault (); + var mtime = new DateTimeOffset (new DateTime (2018, 12, 15, 10, 17, 38)); + + message = tnef.ConvertToMessage (); + + Assert.IsEmpty (message.Subject, "Subject"); + Assert.AreEqual (DateTimeOffset.MinValue, message.Date, "Date"); + Assert.AreEqual ("DM5PR21MB0828DA2B8C88048BC03EFFA6CFA20@DM5PR21MB0828.namprd21.prod.outlook.com", message.MessageId, "Message-Id"); + + Assert.IsInstanceOf (typeof (Multipart), message.Body); + var multipart = (Multipart) message.Body; + + Assert.AreEqual (6, multipart.Count); + + Assert.IsInstanceOf (typeof (TextPart), multipart[0]); + Assert.IsInstanceOf (typeof (MimePart), multipart[1]); + Assert.IsInstanceOf (typeof (MimePart), multipart[2]); + Assert.IsInstanceOf (typeof (MimePart), multipart[3]); + Assert.IsInstanceOf (typeof (MimePart), multipart[4]); + Assert.IsInstanceOf (typeof (MimePart), multipart[5]); + + var rtf = (TextPart) multipart[0]; + Assert.AreEqual ("text/rtf", rtf.ContentType.MimeType, "MimeType"); + + var kitten = (MimePart) multipart[1]; + Assert.AreEqual ("application/octet-stream", kitten.ContentType.MimeType, "MimeType"); + Assert.AreEqual ("kitten-playing-with-a-christmas-tree.jpg", kitten.FileName, "FileName"); + + // Note: For some reason, each task and appointment got duplicated. The first copy is attached as a + // TnefAttribute.AttachData and the second is a TnefPropertyId.AttachData. + var task1 = (MimePart) multipart[2]; + Assert.AreEqual ("application/octet-stream", task1.ContentType.MimeType, "MimeType"); + Assert.AreEqual ("Build a train table", task1.ContentType.Name, "Name"); + Assert.AreEqual ("attachment", task1.ContentDisposition.Disposition, "Disposition"); + Assert.AreEqual ("Untitled Attachment", task1.ContentDisposition.FileName, "FileName"); + Assert.AreEqual (mtime, task1.ContentDisposition.ModificationDate, "ModificationDate"); + Assert.AreEqual (9217, task1.ContentDisposition.Size, "Size"); + + var task2 = (MimePart) multipart[3]; + Assert.AreEqual ("application/vnd.ms-tnef", task2.ContentType.MimeType, "MimeType"); + Assert.AreEqual ("Build a train table", task2.ContentType.Name, "Name"); + Assert.AreEqual ("attachment", task2.ContentDisposition.Disposition, "Disposition"); + Assert.AreEqual ("Untitled Attachment", task2.ContentDisposition.FileName, "FileName"); + Assert.AreEqual (mtime, task2.ContentDisposition.ModificationDate, "ModificationDate"); + Assert.AreEqual (9217, task2.ContentDisposition.Size, "Size"); + + var appointment1 = (MimePart) multipart[4]; + Assert.AreEqual ("application/octet-stream", appointment1.ContentType.MimeType, "MimeType"); + Assert.AreEqual ("Christmas Celebration!", appointment1.ContentType.Name, "Name"); + Assert.AreEqual ("attachment", appointment1.ContentDisposition.Disposition, "Disposition"); + Assert.AreEqual ("Untitled Attachment", appointment1.ContentDisposition.FileName, "FileName"); + Assert.AreEqual (mtime, appointment1.ContentDisposition.ModificationDate, "ModificationDate"); + Assert.AreEqual (387453, appointment1.ContentDisposition.Size, "Size"); + + var appointment2 = (MimePart) multipart[5]; + Assert.AreEqual ("application/vnd.ms-tnef", appointment2.ContentType.MimeType, "MimeType"); + Assert.AreEqual ("Christmas Celebration!", appointment2.ContentType.Name, "Name"); + Assert.AreEqual ("attachment", appointment2.ContentDisposition.Disposition, "Disposition"); + Assert.AreEqual ("Untitled Attachment", appointment2.ContentDisposition.FileName, "FileName"); + Assert.AreEqual (mtime, appointment2.ContentDisposition.ModificationDate, "ModificationDate"); + Assert.AreEqual (387453, appointment2.ContentDisposition.Size, "Size"); + } + + [Test] + public void TestTnefNameId () + { + var guid = Guid.NewGuid (); + var tnef1 = new TnefNameId (guid, 17); + var tnef2 = new TnefNameId (guid, 17); + + Assert.AreEqual (TnefNameIdKind.Id, tnef1.Kind, "Kind Id"); + Assert.AreEqual (guid, tnef1.PropertySetGuid, "PropertySetGuid Id"); + Assert.AreEqual (17, tnef1.Id, "Id"); + + Assert.AreEqual (tnef1.GetHashCode (), tnef2.GetHashCode (), "GetHashCode Id"); + Assert.AreEqual (tnef1, tnef2, "Equal Id"); + + tnef1 = new TnefNameId (guid, "name"); + Assert.AreEqual (TnefNameIdKind.Name, tnef1.Kind, "Kind Name"); + Assert.AreEqual (guid, tnef1.PropertySetGuid, "PropertySetGuid"); + Assert.AreEqual ("name", tnef1.Name, "Name"); + + Assert.AreNotEqual (tnef1.GetHashCode (), tnef2.GetHashCode (), "GetHashCode Name vs Id"); + Assert.AreNotEqual (tnef1, tnef2, "Equal Name vs Id"); + + tnef2 = new TnefNameId (guid, "name"); + Assert.AreEqual (tnef1.GetHashCode (), tnef2.GetHashCode (), "GetHashCode Name"); + Assert.AreEqual (tnef1, tnef2, "Equal Name"); + + Assert.IsFalse (tnef1.Equals (new object ()), "Equals (object)"); } } } diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 220f18becc..8c04335117 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -1,85 +1,68 @@ - - + + - Debug - AnyCPU - {0225FDB7-CF63-4402-BB30-9B149AC06C2E} - v4.5 - Library - UnitTests + net48 UnitTests - 8.0.30703 - 2.0 - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - 612 - - - full - true - bin\Release - prompt - 4 - false - - + Full true - - + $(DefineConstants);MONO ..\MimeKit\mimekit.snk + false + false + - - - - - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll - - - ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - - ..\packages\System.Data.SQLite.Core.1.0.106.0\lib\net45\System.Data.SQLite.dll - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + - - {D5F54A4F-D84B-430F-9271-F7861E285B3E} - MimeKit.Net45 - - - {F26434C1-BA3D-41FB-B560-C009CB72B1B6} - Mono.Data.Sqlite - + + + + + + + + + + - + + + + + @@ -92,24 +75,37 @@ + + + + + + + + + + + + + @@ -119,6 +115,7 @@ + @@ -130,18 +127,22 @@ + + + + @@ -152,9 +153,13 @@ + + + + @@ -176,6 +181,8 @@ + + @@ -197,6 +204,7 @@ + @@ -207,44 +215,114 @@ - - - + + + + + + + + + + + + + - - PreserveNewest - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -252,8 +330,6 @@ - - - + diff --git a/UnitTests/Utils/CharsetUtilsTests.cs b/UnitTests/Utils/CharsetUtilsTests.cs index 38f63e3429..a711afebe8 100644 --- a/UnitTests/Utils/CharsetUtilsTests.cs +++ b/UnitTests/Utils/CharsetUtilsTests.cs @@ -1,9 +1,9 @@ -// +// // CharsetUtilsTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,6 @@ using System; using System.Text; -using System.Security.Cryptography; using NUnit.Framework; @@ -97,9 +96,11 @@ public void TestParseCodePage () Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-8859")); Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-BB59")); + Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-8859-")); Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-8859-A")); Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-2022-US")); Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-4999-1")); + Assert.AreEqual (-1, CharsetUtils.ParseCodePage ("iso-abcd-1")); } [Test] diff --git a/UnitTests/Utils/DateParserTests.cs b/UnitTests/Utils/DateParserTests.cs index a558a2bd21..5061b4258b 100644 --- a/UnitTests/Utils/DateParserTests.cs +++ b/UnitTests/Utils/DateParserTests.cs @@ -1,9 +1,9 @@ -// +// // DateParserTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Utils/MimeUtilsTests.cs b/UnitTests/Utils/MimeUtilsTests.cs index c43b09a7dc..0001e57700 100644 --- a/UnitTests/Utils/MimeUtilsTests.cs +++ b/UnitTests/Utils/MimeUtilsTests.cs @@ -1,9 +1,9 @@ -// +// // MimeUtilsTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -66,6 +66,7 @@ public void TestArgumentExceptions () "", "local-part@domain1@domain2", "", "local-part@", "", "local-part", + "<:invalid-local-part;@domain.com>", ":invalid-local-part;@domain.com", }; [Test] @@ -82,30 +83,63 @@ public void TestParseGoodReferences () } } - static readonly string[] BadReferences = { + static readonly string[] BrokenReferences = { " (this is an unterminated comment...", "(this is just a comment)", "<", - "<:invalid-local-part;@domain.com>", " +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; + +using NUnit.Framework; + +using MimeKit.Utils; + +namespace UnitTests.Utils { + [TestFixture] + public class PackedByteArrayTests + { + [Test] + public void TestArgumentExceptions () + { + var packed = new PackedByteArray (); + + Assert.Throws (() => packed.CopyTo (null, 0)); + Assert.Throws (() => packed.CopyTo (new byte[16], -1)); + } + + [Test] + public void TestBasicFunctionality () + { + var packed = new PackedByteArray (); + var expected = new byte[1024]; + var buffer = new byte[1024]; + int index = 0; + + for (int i = 0; i < 257; i++) { + expected[index++] = (byte) 'A'; + packed.Add ((byte) 'A'); + } + + for (int i = 1; i < 26; i++) { + expected[index++] = (byte) ('A' + i); + packed.Add ((byte) ('A' + i)); + } + + for (int i = 0; i < 128; i++) { + expected[index++] = (byte) 'B'; + packed.Add ((byte) 'B'); + } + + Assert.AreEqual (index, packed.Count, "Count"); + + packed.CopyTo (buffer, 0); + + for (int i = 0; i < index; i++) + Assert.AreEqual (expected[i], buffer[i], "buffer[{0}]", i); + } + } +} diff --git a/UnitTests/Utils/ParseUtilsTests.cs b/UnitTests/Utils/ParseUtilsTests.cs index c91ef5b41b..54fe288e28 100644 --- a/UnitTests/Utils/ParseUtilsTests.cs +++ b/UnitTests/Utils/ParseUtilsTests.cs @@ -1,9 +1,9 @@ -// +// // ParseUtilsTests.cs // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -134,5 +134,226 @@ public void TestTryParseBadDomains () Assert.AreEqual (BadDomainErrorIndexes[i], ex.ErrorIndex, "Unexpected error index."); } } + + static readonly string[] MsgIdInputs = { + " ", + " Messe_Bauma_rz(1)_ae284449-6bdc-488f-8ec3-5be5e5b09efb.jpg", + }; + static readonly string[] MsgIdOutputs = { + "Messe_Bauma_rz(1)_ae284449-6bdc-488f-8ec3-5be5e5b09efb.jpg", + "Messe_Bauma_rz(1)_ae284449-6bdc-488f-8ec3-5be5e5b09efb.jpg", + }; + + [Test] + public void TestTryParseMsgIdTokens () + { + for (int i = 0; i < MsgIdInputs.Length; i++) { + var buffer = Encoding.ASCII.GetBytes (MsgIdInputs[i]); + int endIndex = buffer.Length; + int index = 0; + string msgid; + + Assert.IsTrue (ParseUtils.TryParseMsgId (buffer, ref index, endIndex, false, false, out msgid), "TryParseMsgId"); + Assert.AreEqual (MsgIdOutputs[i], msgid, "MsgIdOutputs[{0}]", i); + } + } + + [Test] + public void TestTryParseMsgIdEmptyString () + { + var buffer = Encoding.ASCII.GetBytes (" "); + int index = 0; + string msgid; + + Assert.IsFalse (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + + try { + index = 0; + ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, true, out msgid); + Assert.Fail ("throwOnError"); + } catch (ParseException ex) { + Assert.AreEqual (1, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (1, ex.ErrorIndex, "ErrorIndex"); + } + } + + [Test] + public void TestTryParseMsgIdLessThan () + { + var buffer = Encoding.ASCII.GetBytes (" <"); + int index = 0; + string msgid; + + Assert.IsFalse (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + + try { + index = 0; + ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, true, out msgid); + Assert.Fail ("throwOnError"); + } catch (ParseException ex) { + Assert.AreEqual (1, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (2, ex.ErrorIndex, "ErrorIndex"); + } + } + + [Test] + public void TestTryParseMsgIdLessThanLocalPart () + { + var buffer = Encoding.ASCII.GetBytes (" "); + int index = 0; + string msgid; + + Assert.IsTrue (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + Assert.AreEqual ("local-part@", msgid); + } + + [Test] + public void TestTryParseMsgIdLessThanLocalPartAtDomainMissingGreaterThan () + { + var buffer = Encoding.ASCII.GetBytes (" "); + int index = 0; + string msgid; + + Assert.IsFalse (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + + try { + index = 0; + ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, true, out msgid); + Assert.Fail ("throwOnError"); + } catch (ParseException ex) { + Assert.AreEqual (2, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (24, ex.ErrorIndex, "ErrorIndex"); + } + } + + [Test] + public void TestTryParseMsgIdInvalidInternationalLocalPart () + { + var buffer = Encoding.GetEncoding ("iso-8859-1").GetBytes (" <æøå@domain>"); + int index = 0; + string msgid; + + Assert.IsFalse (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + + try { + index = 0; + ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, true, out msgid); + Assert.Fail ("throwOnError"); + } catch (ParseException ex) { + Assert.AreEqual (2, ex.TokenIndex, "TokenIndex"); + Assert.AreEqual (2, ex.ErrorIndex, "ErrorIndex"); + } + } + + [Test] + public void TestTryParseMsgIdWithIdnDomain () + { + var buffer = Encoding.ASCII.GetBytes (" "); + const string expected = "id@名がドメイン.com"; + int index = 0; + string msgid; + + Assert.IsTrue (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, false, out msgid), "TryParseMsgId"); + Assert.AreEqual (expected, msgid, "msgid"); + + index = 0; + Assert.IsTrue (ParseUtils.TryParseMsgId (buffer, ref index, buffer.Length, false, true, out msgid), "TryParseMsgId+thowOnError"); + Assert.AreEqual (expected, msgid, "msgid"); + } } } diff --git a/UnitTests/Utils/Rfc2047Tests.cs b/UnitTests/Utils/Rfc2047Tests.cs index 345bfdb759..11feb0816f 100644 --- a/UnitTests/Utils/Rfc2047Tests.cs +++ b/UnitTests/Utils/Rfc2047Tests.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2013-2017 Xamarin Inc. (www.xamarin.com) +// Copyright (c) 2013-2020 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/UnitTests/Utils/StringBuilderExtensionTests.cs b/UnitTests/Utils/StringBuilderExtensionTests.cs new file mode 100644 index 0000000000..273de4cd1a --- /dev/null +++ b/UnitTests/Utils/StringBuilderExtensionTests.cs @@ -0,0 +1,111 @@ +// +// StringBuilderExtensionTests.cs +// +// Author: Jeffrey Stedfast +// +// Copyright (c) 2013-2020 .NET Foundation and Contributors +// +// 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. +// + +using System; +using System.Text; +using System.Collections.Generic; + +using NUnit.Framework; + +using MimeKit; +using MimeKit.Utils; + +namespace UnitTests.Utils { + [TestFixture] + public class StringBuilderExtensionTests + { + [Test] + public void TestLineWrap () + { + var builder = new StringBuilder ("This is supposed to be a really long string of text that is about to be folded "); + const string expected1 = "This is supposed to be a really long string of text that is about to be folded\n "; + const string expected2 = "This is supposed to be a really long string of text that is about to be folded\n\t"; + var format = FormatOptions.Default.Clone (); + + format.NewLineFormat = NewLineFormat.Unix; + + builder.LineWrap (format); + + Assert.AreEqual (expected1, builder.ToString (), "#1"); + + builder.Length -= 2; + + builder.LineWrap (format); + + Assert.AreEqual (expected2, builder.ToString (), "#2"); + } + + [Test] + public void TestAppendTokens () + { + var builder = new StringBuilder ("Authentication-Results:"); + var format = FormatOptions.Default.Clone (); + var tokens = new List (); + int lineLength = builder.Length; + + format.NewLineFormat = NewLineFormat.Unix; + + tokens.Add (" "); + tokens.Add ("this-is-a-really-long-parameter-name"); + tokens.Add ("="); + tokens.Add ("this-is-a-really-long-parameter-value"); + + builder.AppendTokens (format, ref lineLength, tokens); + + Assert.AreEqual ("Authentication-Results: this-is-a-really-long-parameter-name=\n\tthis-is-a-really-long-parameter-value", builder.ToString ()); + } + + [Test] + public void TestAppendFoldedWithQuotedString () + { + const string expected = "This is about to get a quoted string appended to it:\n \"and this is a \\\"quoted string\\\" that must not get broken up!\" Got it? Good.\n There should be another wrap in here..."; + var builder = new StringBuilder ("This is about to get a quoted string appended "); + var format = FormatOptions.Default.Clone (); + int lineLength = builder.Length; + + format.NewLineFormat = NewLineFormat.Unix; + + builder.AppendFolded (format, false, "to it: \"and this is a \\\"quoted string\\\" that must not get broken up!\" Got it? Good. There should be another wrap in here...", ref lineLength); + + Assert.AreEqual (expected, builder.ToString ()); + Assert.AreEqual (40, lineLength); + } + +#if DEBUG + [Test] + public void TestAppendCStringByte () + { + const string expected = "\\0\\x01\\x02\\x03\\x04\\x05\\x06\\a\\b\\t\\n\\v\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f "; + var builder = new StringBuilder (); + + for (byte i = 0; i < 0x21; i++) + builder.AppendCStringByte (i); + + Assert.AreEqual (expected, builder.ToString ()); + } +#endif + } +} diff --git a/UnitTests/packages.config b/UnitTests/packages.config deleted file mode 100644 index 33eec2a2ea..0000000000 --- a/UnitTests/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 83d99fc8f4..0286bafcbf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ -version: 2.0.1.1.{build} -os: Visual Studio 2017 +version: 2.10.1.1.{build} +os: Visual Studio 2019 configuration: Debug platform: Any CPU @@ -14,54 +14,34 @@ environment: secure: bY3HMQXJsuuHTqtDx878B8dh+vRw8Sr+ffu+i2ycNlnvN3NUsGXVCj/SUBlbsNdL install: - - cmd: git submodule update --init --recursive - - cmd: nuget restore MimeKit.Net45.sln +- cmd: git submodule update --init --recursive +- cmd: dotnet restore MimeKit.sln build: - project: MimeKit.Net45.sln + project: MimeKit.sln verbosity: minimal + parallel: true test_script: - ps: >- - $testDir = ".\UnitTests\bin\Debug\" + $NUnitConsoleRunner = Join-Path $Home ".nuget\packages\nunit.consolerunner\3.11.1\tools\nunit3-console.exe" - $tests = @("$testdir\UnitTests.dll") + $Coveralls = Join-Path $Home ".nuget\packages\coveralls.net\0.7.0\tools\csmacnz.Coveralls.exe" - foreach ($elem in $tests) { - .\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe ` - -register:user ` - -target:.\packages\NUnit.Runners.2.6.4\tools\nunit-console.exe ` - "-targetargs: ""$elem"" /framework:net-4.5 /noshadow" ` - "-filter:+[MimeKit]* -[UnitTests]* -[submodules]* -[Mono.Data.Sqlite]*" ` - -output:opencover.xml ` - } + $OpenCoverDir = Join-Path $Home ".nuget\packages\opencover\4.6.519\tools" - $revision = git rev-parse HEAD + $OpenCoverProfiler32 = Join-Path $OpenCoverDir "x86\OpenCover.Profiler.dll" - $branch = git rev-parse --abbrev-ref HEAD + $OpenCoverProfiler64 = Join-Path $OpenCoverDir "x64\OpenCover.Profiler.dll" - $commitAuthor = git show --quiet --format="%aN" $revision + $OpenCover = Join-Path $OpenCoverDir "OpenCover.Console.exe" - $commitEmail = git show --quiet --format="%aE" $revision + $OutputDir = "UnitTests\bin\Debug\net48" - $commitMessage = git show --quiet --format="%s" $revision + & regsvr32 $OpenCoverProfiler32 - .\packages\coveralls.net.0.7.0\tools\csmacnz.Coveralls.exe ` + & regsvr32 $OpenCoverProfiler64 - --opencover -i opencover.xml ` + & $OpenCover -filter:"+[MimeKit]* -[UnitTests]*" -target:"$NUnitConsoleRunner" -targetdir:"$OutputDir" -targetargs:"--domain:single UnitTests.dll" -output:opencover.xml - --repoToken $Env:COVERALLS_REPO_TOKEN ` - - --commitId $revision ` - - --commitBranch $branch ` - - --commitAuthor $commitAuthor ` - - --commitEmail $commitEmail ` - - --commitMessage $commitMessage ` - - --useRelativePaths ` - - --basePath .\UnitTests\bin\Debug + & $Coveralls --opencover -i opencover.xml --repoToken $Env:COVERALLS_REPO_TOKEN --useRelativePaths --basePath $OutputDir --commitId $Env:APPVEYOR_REPO_COMMIT --commitBranch $Env:APPVEYOR_REPO_BRANCH --commitAuthor $Env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $Env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $Env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $Env:APPVEYOR_BUILD_NUMBER --serviceName appveyor diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000000..49b1fa10c3 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,69 @@ +# .NET Desktop +# Build and run tests for .NET Desktop or Windows classic desktop solutions. +# Add steps that publish symbols, save build artifacts, and more: +# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net + +trigger: +- master + +pool: + vmImage: 'windows-2019' + +name: 2.10.1$(Rev:.r) + +variables: + solution: 'MimeKit.sln' + buildPlatform: 'Any CPU' + buildConfiguration: 'Release' + +steps: +- script: git submodule update --init --recursive + +- task: NuGetToolInstaller@0 + displayName: 'Install NuGet 5.8.0' + inputs: + versionSpec: 5.8.0 + +- task: NuGetCommand@2 + displayName: 'Restore NuGet Package Dependencies' + inputs: + restoreSolution: '$(solution)' + +- task: VSBuild@1 + displayName: 'Build $(solution) for $(buildConfiguration)|$(buildPlatform)' + inputs: + solution: '$(solution)' + platform: '$(buildPlatform)' + configuration: '$(buildConfiguration)' + +- task: PowerShell@2 + displayName: 'Run Unit Tests' + inputs: + targetType: 'filePath' + filePath: 'azure-test-runner.ps1' + +- task: PublishTestResults@2 + displayName: 'Publish Unit Test Results' + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: 'TestResult.xml' + +- task: NuGetCommand@2 + displayName: 'Package MimeKit-$(Build.BuildNumber)' + inputs: + command: pack + packagesToPack: nuget/MimeKit.nuspec + versioningScheme: byBuildNumber + +- task: NuGetCommand@2 + displayName: 'Publish MimeKit NuGet package to MyGet Feed' + inputs: + command: push + nuGetFeedType: external + publishFeedCredentials: 'MyGet' + packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg' + +- task: PublishBuildArtifacts@1 + displayName: 'Publish MimeKit NuGet package' + inputs: + ArtifactName: 'MimeKit-$(Build.BuildNumber)' diff --git a/azure-test-runner.ps1 b/azure-test-runner.ps1 new file mode 100644 index 0000000000..0754bbac75 --- /dev/null +++ b/azure-test-runner.ps1 @@ -0,0 +1,3 @@ +$NUnitConsoleRunner = Join-Path $Home ".nuget\packages\nunit.consolerunner\3.11.1\tools\nunit3-console.exe" + +& $NUnitConsoleRunner --domain:single "UnitTests\bin\Release\net48\UnitTests.dll" diff --git a/component/Details.md b/component/Details.md deleted file mode 100644 index 271acfd04a..0000000000 --- a/component/Details.md +++ /dev/null @@ -1,18 +0,0 @@ -MimeKit is an Open Source library for creating and parsing MIME, S/MIME and PGP -messages on desktop platforms (e.g. Windows, Mac, and Linux) as well as mobile -platforms (e.g. iOS and Android). It also supports parsing of Unix mbox files. - -Unlike any other .NET MIME parser, MimeKit's parser does not need to parse -string input nor does it use a TextReader. Instead, it parses raw byte streams, -thus allowing it to better support undeclared 8bit text in headers as well as -message bodies. It also means that MimeKit's parser is significantly faster -than other .NET MIME parsers. - -MimeKit's parser also uses a real tokenizer when parsing the headers rather -than regex or string.Split() like most other .NET MIME parsers. This means that -MimeKit is much more RFC-compliant than any other .NET MIME parser out there, -including the commercial implementations. - -In addition to having a far superior parser implementation, MimeKit's object -tree is not a derivative of System.Net.Mail objects and thus does not suffer -from System.Net.Mail's massive limitations or bugs. diff --git a/component/Makefile b/component/Makefile deleted file mode 100644 index fd869b43ea..0000000000 --- a/component/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -all: - -#build: -# xbuild /property:Configuration=Release /target:Rebuild ../MimeKit.Mobile.sln - -package: ./tools/ - mono ./tools/xamarin-component.exe package - -validate: ./tools/ - mono ./tools/xamarin-component.exe validate - -upload: ./tools/ - mono ./tools/xamarin-component.exe upload - -./tools/: - rm -rf ./tools/ - mkdir ./tools/ - cd ./tools/ && curl -silent -L https://components.xamarin.com/submit/xpkg > tools.zip - -cd ./tools/ && unzip tools.zip - rm ./tools/tools.zip - -clean: - rm -rf ./tools/ diff --git a/component/component.yaml b/component/component.yaml deleted file mode 100644 index aff2177c1b..0000000000 --- a/component/component.yaml +++ /dev/null @@ -1,24 +0,0 @@ -id: mimekit -name: MimeKit -version: 2.0.0 -publisher: Jeffrey Stedfast -publisher-url: https://github.com/jstedfast/MimeKit -getting-started: GettingStarted.md -details: Details.md -license: ../License.md -summary: A complete MIME email library with support for S/MIME, OpenPGP, and DKIM. -icons: - - mimekit_512x512.png - - mimekit_128x128.png -packages: - ios-unified: - - MimeKit, Version=2.0.0 - android: - - MimeKit, Version=2.0.0 -samples: - - name: "Android Sample" - path: ../samples/MessageReader.Android/MessageReader.Android.sln - - name: "iOS Sample" - path: ../samples/MessageReader.iOS/MessageReader.iOS.sln -no_build: true -is_shell: true diff --git a/cov-build.bat b/cov-build.bat index a9e19388f1..203444d9ee 100755 --- a/cov-build.bat +++ b/cov-build.bat @@ -1 +1 @@ -..\cov-analysis\bin\cov-build.exe --dir cov-int "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe" /t:Rebuild MimeKit.Coverity.sln +..\cov-analysis\bin\cov-build.exe --dir cov-int "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe" /t:Rebuild MimeKit.Coverity.sln diff --git a/component/GettingStarted.md b/nuget/GettingStarted.md similarity index 79% rename from component/GettingStarted.md rename to nuget/GettingStarted.md index 7335742906..98cc8d8628 100644 --- a/component/GettingStarted.md +++ b/nuget/GettingStarted.md @@ -55,7 +55,7 @@ to be interpreted as attachments. The `Content-Disposition` header will generally have one of two values: `inline` or `attachment`. -The meaning of these value should be fairly obvious. If the value is `attachment`, then the content +The meaning of these values should be fairly obvious. If the value is `attachment`, then the content of said MIME part is meant to be presented as a file attachment separate from the core message. However, if the value is `inline`, then the content of that MIME part is meant to be displayed inline within the mail client's rendering of the core message body. If the `Content-Disposition` header does @@ -180,15 +180,15 @@ save the decoded content to a file: var fileName = part.FileName; using (var stream = File.Create (fileName)) { - part.ContentObject.DecodeTo (stream); + part.Content.DecodeTo (stream); } ``` -You can also get access to the original raw content by "opening" the `ContentObject`. This might be useful +You can also get access to the original raw content by "opening" the `Content`. This might be useful if you want to pass the content off to a UI control that can do its own loading from a stream. ```csharp -using (var stream = part.ContentObject.Open ()) { +using (var stream = part.Content.Open ()) { // At this point, you can now read from the stream as if it were the original, // raw content. Assuming you have an image UI control that could load from a // stream, you could do something like this: @@ -261,7 +261,7 @@ Will you be my +1? // create an image attachment for the file located at path var attachment = new MimePart ("image", "gif") { - ContentObject = new ContentObject (File.OpenRead (path), ContentEncoding.Default), + Content = new MimeContent (File.OpenRead (path), ContentEncoding.Default), ContentDisposition = new ContentDisposition (ContentDisposition.Attachment), ContentTransferEncoding = ContentEncoding.Base64, FileName = Path.GetFileName (path) @@ -361,12 +361,17 @@ If you are targetting any of the Xamarin platforms (or Linux), you won't need to anything (although you certainly can if you want to) because, by default, I've configured MimeKit to use the Mono.Data.Sqlite binding to SQLite. -If you are, however, on any of the Windows platforms, you'll need to pick a System.Data -provider such as [System.Data.SQLite](https://www.nuget.org/packages/System.Data.SQLite). -Once you've made your choice and installed it (via NuGet or however), you'll need to -implement your own `SecureMimeContext` subclass. Luckily, it's very simple to do. Assuming -you've chosen System.Data.SQLite, here's how you'd implement your own `SecureMimeContext` -class: +If you are on any of the Windows platforms, however, you'll need to decide on whether +to use one of the conveniently available backends such as the `WindowsSecureMimeContext` +backend or the `TemporarySecureMimeContext` backend or else you'll need to pick a +System.Data provider such as +[System.Data.SQLite](https://www.nuget.org/packages/System.Data.SQLite) to use with +the `DefaultSecureMimeContext` base class. + +If you opt for using the `DefaultSecureMimeContext` backend, you'll need to implement +your own `DefaultSecureMimeContext` subclass. Luckily, it's very simple to do. +Assuming you've chosen System.Data.SQLite, here's how you'd implement your own +`DefaultSecureMimeContext` class: ```csharp using System.Data.SQLite; @@ -405,6 +410,9 @@ CryptographyContext.Register (typeof (MySecureMimeContext)); Now you are ready to encrypt, decrypt, sign and verify S/MIME messages! +Note: If you choose to use the `WindowsSecureMimeContext` or `TemporarySecureMimeContext` backend, +you should register that class instead. + ### Preparing to use MimeKit's PGP/MIME support Like with S/MIME support, you also need to register your own `OpenPgpContext`. Unlike S/MIME, however, @@ -572,7 +580,7 @@ would use an OpenPGP cryptography context. For example, you might use a subclass use `GnuPGContext` directly because it has no way of prompting the user for their passphrase). For the sake of this example, let's pretend that you've written a minimal subclass of -`MimeKit.Cryptography.GnuPGContext` that simply overrides the `GetPassword()` method and +`MimeKit.Cryptography.GnuPGContext` that only overrides the `GetPassword()` method and that this subclass is called `MyGnuPGContext`. ```csharp @@ -688,31 +696,211 @@ As you can see, it's fairly straight forward. Verifying DKIM signatures is slightly more involved than creating them because you'll need to write a custom implementation of the `IDkimPublicKeyLocator` interface. Typically, this custom class will need to download -the DKIM public keys as they are requested by MimeKit during verification of DKIM signature headers. +the DKIM public keys via your chosen DNS library as they are requested by MimeKit during verification of +DKIM signature headers. -Once you've implemented a custom `IDkimPublicKeyLocator`, verifying signatures is fairly trivial: +Once you've implemented a custom `IDkimPublicKeyLocator`, verifying signatures is fairly trivial. Most of the work +needed will be in the `IDkimPublicKeyLocator` implementation. As an example of how to implement this interface, +here is one possible implementation using the [Heijden.DNS](http://www.nuget.org/packages/Heijden.Dns/) library: ```csharp -var dkim = message.Headers[HeaderId.DkimSignature]; +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Collections.Generic; + +using Heijden.DNS; + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.OpenSsl; -if (message.Verify (dkim, locator)) { - // the DKIM-Signature header is valid! -} else { - // the DKIM-Signature is invalid +using MimeKit; +using MimeKit.Cryptography; + +namespace DkimVerifier +{ + class DkimPublicKeyLocator : IDkimPublicKeyLocator + { + readonly Dictionary cache; + readonly Resolver resolver; + + public DkimPublicKeyLocator () + { + cache = new Dictionary (); + + resolver = new Resolver ("8.8.8.8") { + TransportType = TransportType.Udp, + UseCache = true, + Retries = 3 + }; + } + + AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationToken cancellationToken) + { + var query = selector + "._domainkey." + domain; + AsymmetricKeyParameter pubkey; + + // checked if we've already fetched this key + if (cache.TryGetValue (query, out pubkey)) + return pubkey; + + // make a DNS query + var response = resolver.Query (query, QType.TXT); + var builder = new StringBuilder (); + + // combine the TXT records into 1 string buffer + foreach (var record in response.RecordsTXT) { + foreach (var text in record.TXT) + builder.Append (text); + } + + var txt = builder.ToString (); + string k = null, p = null; + int index = 0; + + // parse the response (will look something like: "k=rsa; p=") + while (index < txt.Length) { + while (index < txt.Length && char.IsWhiteSpace (txt[index])) + index++; + + if (index == txt.Length) + break; + + // find the end of the key + int startIndex = index; + while (index < txt.Length && txt[index] != '=') + index++; + + if (index == txt.Length) + break; + + var key = txt.Substring (startIndex, index - startIndex); + + // skip over the '=' + index++; + + // find the end of the value + startIndex = index; + while (index < txt.Length && txt[index] != ';') + index++; + + var value = txt.Substring (startIndex, index - startIndex); + + switch (key) { + case "k": k = value; break; + case "p": p = value; break; + } + + // skip over the ';' + index++; + } + + if (k != null && p != null) { + var data = "-----BEGIN PUBLIC KEY-----\r\n" + p + "\r\n-----END PUBLIC KEY-----\r\n"; + var rawData = Encoding.ASCII.GetBytes (data); + + using (var stream = new MemoryStream (rawData, false)) { + using (var reader = new StreamReader (stream)) { + var pem = new PemReader (reader); + + pubkey = pem.ReadObject () as AsymmetricKeyParameter; + + if (pubkey != null) { + cache.Add (query, pubkey); + + return pubkey; + } + } + } + } + + throw new Exception (string.Format ("Failed to look up public key for: {0}", domain)); + } + + public AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + { + var methodList = methods.Split (new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < methodList.Length; i++) { + if (methodList[i] == "dns/txt") + return DnsLookup (domain, selector, cancellationToken); + } + + throw new NotSupportedException (string.Format ("{0} does not include any suported lookup methods.", methods)); + } + } + + class Program + { + public static void Main (string[] args) + { + if (args.Length == 0) { + Help (); + return; + } + + for (int i = 0; i < args.Length; i++) { + if (args[i] == "--help") { + Help (); + return; + } + } + + var locator = new DkimPublicKeyLocator (); + + for (int i = 0; i < args.Length; i++) { + if (!File.Exists (args[i])) { + Console.Error.WriteLine ("{0}: No such file.", args[i]); + continue; + } + + Console.Write ("{0} -> ", args[i]); + + var message = MimeMessage.Load (args[i]); + var index = message.Headers.IndexOf (HeaderId.DkimSignature); + + if (index == -1) { + Console.WriteLine ("NO SIGNATURE"); + continue; + } + + var dkim = message.Headers[index]; + + if (message.Verify (dkim, locator)) { + // the DKIM-Signature header is valid! + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine ("VALID"); + Console.ResetColor (); + } else { + // the DKIM-Signature is invalid! + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine ("INVALID"); + Console.ResetColor (); + } + } + } + + static void Help () + { + Console.WriteLine ("Usage is: DkimVerifier [options] [messages]"); + Console.WriteLine (); + Console.WriteLine ("Options:"); + Console.WriteLine (" --help This help menu."); + } + } } ``` ## Donate MimeKit is a personal open source project that I have put thousands of hours into perfecting with the -goal of making it not only the very best MIME parser framework for .NET, but the best MIME parser -framework for any programming language. I need your help to achieve this. - - - Click here to lend your support to MimeKit and MailKit by making a donation via pledgie.com! - +goal of making it the very best MIME parser framework for .NET. I need your help to achieve this. + +Donating helps pay for things such as web hosting, domain registration and licenses for developer tools +such as a performance profiler, memory profiler, a static code analysis tool, and more. It also helps +motivate me to continue working on the project. + +Click here to lend your support to MimeKit by making a donation! ## Reporting Bugs diff --git a/nuget/MimeKit.nuspec b/nuget/MimeKit.nuspec index c2fc9da5f8..c54adfb3e2 100644 --- a/nuget/MimeKit.nuspec +++ b/nuget/MimeKit.nuspec @@ -2,22 +2,23 @@ MimeKit - 2.0.1.1 + 2.10.1.1 MimeKit Jeffrey Stedfast Jeffrey Stedfast - http://opensource.org/licenses/MIT - http://github.com/jstedfast/MimeKit - https://raw.github.com/jstedfast/MimeKit/master/nuget/mimekit-50.png + MIT + http://www.mimekit.net + + icons\mimekit-50.png false MimeKit is an Open Source library for creating and parsing MIME, S/MIME and PGP messages on desktop and mobile platforms. It also supports parsing of Unix mbox files. - Unlike any other .NET MIME parser, MimeKit's parser does not need to parse string input nor does it use a TextReader. Instead, it parses raw byte streams, thus allowing it to better support undeclared 8bit text in headers as well as message bodies. It also means that MimeKit's parser is significantly faster than other .NET MIME parsers (more than 25x faster than OpenPOP.NET and over 100x faster than AE.Net.Mail and MailSystem.NET). + Unlike any other .NET MIME parser, MimeKit's parser does not need to parse string input nor does it use a TextReader. Instead, it parses raw byte streams, thus allowing it to better support undeclared 8bit text in headers as well as message bodies. It also means that MimeKit's parser is significantly faster than other .NET MIME parsers. MimeKit's parser also uses a real tokenizer when parsing the headers rather than regex or string.Split() like most other .NET MIME parsers. This means that MimeKit is much more RFC-compliant than any other .NET MIME parser out there, including the commercial implementations. - In addition to having a far superior parser implementation, MimeKit's object tree is not a derivative of System.Net.Mail objects and thus does not suffer from System.Net.Mail's massive limitations or bugs. + In addition to having a far superior parser implementation, MimeKit's object tree is not a derivative of System.Net.Mail objects and thus does not suffer from System.Net.Mail's limitations. API documentation can be found on the web at http://www.mimekit.net/docs @@ -25,101 +26,92 @@ An Open Source library for creating and parsing MIME, S/MIME and PGP messages on desktop and mobile platforms. -* Improved the HTML parser logic to better handle a number of edge cases. -* MimeKit will now automatically download CRLs based on the CRL Distribution Point certificate extension if any HTTP URLs are defined (LDAP and FTP are not yet supported) when verifying S/MIME digital signatures using a derivative of the BouncyCastleSecureMimeContext backend (the WindowsSecureMimeContext gets this for free from System.Security's CMS implementation). -* Fixed OpenPgpContext.RetrievePublicKeyRingAsync() to use the filtered stream. -* Added support for using the Blowfish encryption algorithm with S/MIME (only supported in the BouncyCastle backends). -* Added support for using the SEED encryption algorithm with S/MIME (also only supported in the BouncyCastle backends). -* Added an optional 'algorithm' argument to OpenPgpContext.GenerateKeyPair() to allow specifying the symmetric key algorithm to use in generating the key pair. This defaults to AES-256, which is the same value used in older versions of MimeKit. +* Treat message/disposition-notification and message/delivery-status the same as text/* when preparing for signing. (issue #626) +* Always set Content-Disposition: inline for BodyBuilder.LinkedResources. This fixes a regression introduced in 2.10.0. (issue #627) +* Fixed NuGet package references to System.Data.DataSetExtensions for netstandard2.1 and net4x. - Xamarin Inc. + .NET Foundation and Contributors en-US - mime encryption dkim security smime s/mime openpgp pgp mbox mail email parser tnef net45 netstandard netstandard1.3 netstandard1.6 netstandard2.0 xamarin android ios monodroid monoandroid win8 wp81 + mime encryption arc dkim security smime s/mime openpgp pgp mbox mail email parser tnef net45 net46 net47 net48 netstandard netstandard2.0 + - - - - - - - - + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - - - - - - - - - - + + + - - + + + + + + + - - + + + + + + - - - - + - - - - - - + + + + - - - - - - + + + + + + + + + + diff --git a/nuget/MimeKitLite.nuspec b/nuget/MimeKitLite.nuspec index e6d6e3d0c3..9e070c9c57 100644 --- a/nuget/MimeKitLite.nuspec +++ b/nuget/MimeKitLite.nuspec @@ -2,22 +2,23 @@ MimeKitLite - 2.0.1.1 + 2.10.1.1 MimeKit Lite Jeffrey Stedfast Jeffrey Stedfast - http://opensource.org/licenses/MIT - http://github.com/jstedfast/MimeKit - https://raw.github.com/jstedfast/MimeKit/master/nuget/mimekit-50.png + MIT + http://www.mimekit.net + + icons\mimekit-50.png false MimeKit is an Open Source library for creating and parsing MIME messages. It also supports parsing of Unix mbox files. - Unlike any other .NET MIME parser, MimeKit's parser does not need to parse string input nor does it use a TextReader. Instead, it parses raw byte streams, thus allowing it to better support undeclared 8bit text in headers as well as message bodies. It also means that MimeKit's parser is significantly faster than other .NET MIME parsers (more than 25x faster than OpenPOP.NET and over 100x faster than AE.Net.Mail and MailSystem.NET). + Unlike any other .NET MIME parser, MimeKit's parser does not need to parse string input nor does it use a TextReader. Instead, it parses raw byte streams, thus allowing it to better support undeclared 8bit text in headers as well as message bodies. It also means that MimeKit's parser is significantly faster than other .NET MIME parsers. MimeKit's parser also uses a real tokenizer when parsing the headers rather than regex or string.Split() like most other .NET MIME parsers. This means that MimeKit is much more RFC-compliant than any other .NET MIME parser out there, including the commercial implementations. - In addition to having a far superior parser implementation, MimeKit's object tree is not a derivative of System.Net.Mail objects and thus does not suffer from System.Net.Mail's massive limitations or bugs. + In addition to having a far superior parser implementation, MimeKit's object tree is not a derivative of System.Net.Mail objects and thus does not suffer from System.Net.Mail's limitations. API documentation can be found on the web at http://www.mimekit.net/docs @@ -25,73 +26,62 @@ An Open Source library for creating and parsing MIME messages. -* Improved the HTML parser logic to better handle a number of edge cases. +* Treat message/disposition-notification and message/delivery-status the same as text/* when preparing for signing. (issue #626) +* Always set Content-Disposition: inline for BodyBuilder.LinkedResources. This fixes a regression introduced in 2.10.0. (issue #627) - Xamarin Inc. + .NET Foundation and Contributors en-US - mime mbox mail email parser tnef net45 netstandard netstandard1.3 netstandard1.6 netstandard2.0 xamarin android ios monodroid monoandroid win8 wp81 + mime mbox mail email parser tnef net45 net46 net47 net48 netstandard netstandard2.0 - - - - + + + + + + + + + - - - - - - - - - - - + + - - - - - - - - + + + + + + + + - - - - - - - + + + - - - - - - + - - - - + - - - - - - + + + + + + + + + + diff --git a/component/mimekit_128x128.png b/nuget/mimekit_128x128.png similarity index 100% rename from component/mimekit_128x128.png rename to nuget/mimekit_128x128.png diff --git a/component/mimekit_512x512.png b/nuget/mimekit_512x512.png similarity index 100% rename from component/mimekit_512x512.png rename to nuget/mimekit_512x512.png diff --git a/release.bat b/release.bat deleted file mode 100755 index 8da48cef26..0000000000 --- a/release.bat +++ /dev/null @@ -1,2 +0,0 @@ -"%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" /p:Configuration=Release /p:Platform="Any CPU" /t:Rebuild MimeKitLite.sln -"%WinDir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" /p:Configuration=Release /p:Platform="Any CPU" /t:Rebuild MimeKit.sln diff --git a/rfc/draft-ietf-dmarc-arc-protocol-23.txt b/rfc/draft-ietf-dmarc-arc-protocol-23.txt new file mode 100644 index 0000000000..085309e59c --- /dev/null +++ b/rfc/draft-ietf-dmarc-arc-protocol-23.txt @@ -0,0 +1,2240 @@ + + + + +DMARC Working Group K. Andersen +Internet-Draft LinkedIn +Intended status: Experimental B. Long, Ed. +Expires: June 21, 2019 Google + S. Blank, Ed. + Valimail + M. Kucherawy, Ed. + TDP + December 18, 2018 + + + Authenticated Received Chain (ARC) Protocol + draft-ietf-dmarc-arc-protocol-23 + +Abstract + + The Authenticated Received Chain (ARC) protocol provides an + authenticated "chain of custody" for a message, allowing each entity + that handles the message to see what entities handled it before, and + to see what the message's authentication assessment was at each step + in the handling. + + ARC allows Internet Mail Handlers to attach assertions of message + authentication assessment to individual messages. As messages + traverse ARC-enabled Internet Mail Handlers, additional ARC + assertions can be attached to messages to form ordered sets of ARC + assertions that represent the authentication assessment at each step + of message handling paths. + + ARC-enabled Internet Mail Handlers can process sets of ARC assertions + to inform message disposition decisions, to identify Internet Mail + Handlers that might break existing authentication mechanisms, and to + convey original authentication assessments across trust boundaries. + +Status of This Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at https://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + + +Andersen, et al. Expires June 21, 2019 [Page 1] + +Internet-Draft ARC-Protocol December 2018 + + + This Internet-Draft will expire on June 21, 2019. + +Copyright Notice + + Copyright (c) 2018 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 + 2. General Concepts . . . . . . . . . . . . . . . . . . . . . . 5 + 2.1. Evidence . . . . . . . . . . . . . . . . . . . . . . . . 5 + 2.2. Custody . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 2.3. Chain of Custody . . . . . . . . . . . . . . . . . . . . 5 + 2.4. Validation of Chain of Custody . . . . . . . . . . . . . 5 + 3. Terminology and Definitions . . . . . . . . . . . . . . . . . 6 + 3.1. ARC Set . . . . . . . . . . . . . . . . . . . . . . . . . 6 + 3.2. Authenticated Received Chain (ARC) . . . . . . . . . . . 7 + 3.3. Internet Mail Handlers / Intermediaries . . . . . . . . . 7 + 3.4. Authentication Assessment . . . . . . . . . . . . . . . . 7 + 3.5. Signing vs Sealing . . . . . . . . . . . . . . . . . . . 7 + 3.6. Sealer . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 3.7. Validator . . . . . . . . . . . . . . . . . . . . . . . . 8 + 3.8. Imported ABNF Tokens . . . . . . . . . . . . . . . . . . 8 + 3.9. Common ABNF Tokens . . . . . . . . . . . . . . . . . . . 8 + 4. Protocol Elements . . . . . . . . . . . . . . . . . . . . . . 8 + 4.1. ARC Header Fields . . . . . . . . . . . . . . . . . . . . 8 + 4.1.1. ARC-Authentication-Results (AAR) . . . . . . . . . . 9 + 4.1.2. ARC-Message-Signature (AMS) . . . . . . . . . . . . . 9 + 4.1.3. ARC-Seal (AS) . . . . . . . . . . . . . . . . . . . . 10 + 4.1.4. Internationalized Email (EAI) . . . . . . . . . . . . 11 + 4.2. ARC Set . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 4.2.1. Instance Tags . . . . . . . . . . . . . . . . . . . . 12 + 4.3. Authenticated Received Chain . . . . . . . . . . . . . . 12 + 4.4. Chain Validation Status . . . . . . . . . . . . . . . . . 13 + 5. Protocol Actions . . . . . . . . . . . . . . . . . . . . . . 13 + 5.1. Sealer Actions . . . . . . . . . . . . . . . . . . . . . 14 + 5.1.1. Header Fields To Include In ARC-Seal Signatures . . . 15 + + + +Andersen, et al. Expires June 21, 2019 [Page 2] + +Internet-Draft ARC-Protocol December 2018 + + + 5.1.2. Marking and Sealing "cv=fail" (Invalid) Chains . . . 15 + 5.1.3. Only One Authenticated Received Chain Per Message . . 15 + 5.1.4. Broad Ability to Seal . . . . . . . . . . . . . . . . 16 + 5.1.5. Sealing is Always Safe . . . . . . . . . . . . . . . 16 + 5.2. Validator Actions . . . . . . . . . . . . . . . . . . . . 16 + 5.2.1. All Failures Are Permanent . . . . . . . . . . . . . 18 + 5.2.2. Responding to ARC Validation Failures During the SMTP + Transaction . . . . . . . . . . . . . . . . . . . . . 18 + 6. Communication of Validation Results . . . . . . . . . . . . . 18 + 7. Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . . 19 + 7.1. Communicate Authentication Assessment Across Trust + Boundaries . . . . . . . . . . . . . . . . . . . . . . . 19 + 7.1.1. Message Scanning Services . . . . . . . . . . . . . . 19 + 7.1.2. Multi-tier MTA Processing . . . . . . . . . . . . . . 19 + 7.1.3. Mailing Lists . . . . . . . . . . . . . . . . . . . . 20 + 7.2. Inform Message Disposition Decisions . . . . . . . . . . 20 + 7.2.1. DMARC Local Policy Overrides . . . . . . . . . . . . 20 + 7.2.2. DMARC Reporting . . . . . . . . . . . . . . . . . . . 21 + 8. Privacy Considerations . . . . . . . . . . . . . . . . . . . 22 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 22 + 9.1. Increased Header Field Size . . . . . . . . . . . . . . . 22 + 9.2. DNS Operations . . . . . . . . . . . . . . . . . . . . . 22 + 9.3. Message Content Suspicion . . . . . . . . . . . . . . . . 23 + 9.4. Message Sealer Suspicion . . . . . . . . . . . . . . . . 23 + 9.5. Replay Attacks . . . . . . . . . . . . . . . . . . . . . 23 + 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 23 + 10.1. Email Authentication Results Names Registry Update . . . 24 + 10.2. Email Authentication Methods Registry Update . . . . . . 24 + 10.3. Definitions of the ARC header fields . . . . . . . . . . 24 + 10.4. New Enhanced Status Code - ARC Validation . . . . . . . 25 + 11. Experimental Considerations . . . . . . . . . . . . . . . . . 25 + 11.1. Success Consideration . . . . . . . . . . . . . . . . . 25 + 11.2. Failure Considerations . . . . . . . . . . . . . . . . . 26 + 11.3. Open Questions . . . . . . . . . . . . . . . . . . . . . 26 + 11.3.1. Value of the ARC-Seal (AS) Header Field . . . . . . 26 + 11.3.2. Usage and/or signals from multiple selectors and/or + domains in ARC sets . . . . . . . . . . . . . . . . 26 + 11.3.3. DNS Overhead . . . . . . . . . . . . . . . . . . . . 26 + 11.3.4. What Trace Information is Valuable . . . . . . . . . 27 + 12. Implementation Status . . . . . . . . . . . . . . . . . . . . 27 + 12.1. GMail test reflector and incoming validation . . . . . . 28 + 12.2. AOL test reflector and internal tagging . . . . . . . . 28 + 12.3. dkimpy . . . . . . . . . . . . . . . . . . . . . . . . . 29 + 12.4. OpenARC . . . . . . . . . . . . . . . . . . . . . . . . 29 + 12.5. Mailman 3.x patch . . . . . . . . . . . . . . . . . . . 29 + 12.6. Copernica/MailerQ web-based validation . . . . . . . . . 30 + 12.7. Rspamd . . . . . . . . . . . . . . . . . . . . . . . . . 30 + 12.8. PERL MAIL::DKIM module . . . . . . . . . . . . . . . . . 31 + + + +Andersen, et al. Expires June 21, 2019 [Page 3] + +Internet-Draft ARC-Protocol December 2018 + + + 12.9. PERL Mail::Milter::Authentication module . . . . . . . . 31 + 12.10. Sympa List Manager . . . . . . . . . . . . . . . . . . . 32 + 12.11. Oracle Messaging Server . . . . . . . . . . . . . . . . 32 + 12.12. MessageSystems Momentum and PowerMTA platforms . . . . . 32 + 12.13. Exim . . . . . . . . . . . . . . . . . . . . . . . . . . 33 + 12.14. Halon MTA . . . . . . . . . . . . . . . . . . . . . . . 33 + 12.15. IIJ . . . . . . . . . . . . . . . . . . . . . . . . . . 33 + 13. References . . . . . . . . . . . . . . . . . . . . . . . . . 33 + 13.1. Normative References . . . . . . . . . . . . . . . . . . 33 + 13.2. Informative References . . . . . . . . . . . . . . . . . 35 + 13.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 36 + Appendix A. Design Requirements . . . . . . . . . . . . . . . . 36 + A.1. Primary Design Criteria . . . . . . . . . . . . . . . . . 36 + A.2. Out of Scope . . . . . . . . . . . . . . . . . . . . . . 37 + Appendix B. Example Usage . . . . . . . . . . . . . . . . . . . 37 + Appendix C. Acknowledgements . . . . . . . . . . . . . . . . . . 39 + Appendix D. Comments and Feedback . . . . . . . . . . . . . . . 39 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 39 + +1. Introduction + + The utility of widely deployed email authentication technologies such + as Sender Policy Framework (SPF) [RFC7208] and DomainKeys Identified + Mail (DKIM) [RFC6376] is impacted by the processing of Internet Mail + by intermediate handlers. This impact is thoroughly documented in + the defining documents for SPF and DKIM and further discussed in + [RFC6377] and [RFC7960]. + + DMARC [RFC7489] also relies upon SPF and DKIM authentication + mechanisms. Failures of authentication caused by the actions of + intermediate handlers can cause legitimate mail to be incorrectly + rejected or misdirected. + + Authenticated Received Chain (ARC) creates a mechanism for individual + Internet Mail Handlers to add their authentication assessment to a + message's ordered set of handling results. ARC encapsulates the + authentication assessment in a DKIM signature derivative to grant + other handlers the ability to verify the authenticity of the + individual assessment assertion as well as the aggregate set and + sequence of results. + + Ordered sets of authentication assessments can be used by ARC-enabled + Internet Mail Handlers to inform message handling disposition, to + identify where alteration of message content might have occurred, and + to provide additional trace information for use in understanding + message handling paths. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 4] + +Internet-Draft ARC-Protocol December 2018 + + +2. General Concepts + + ARC is loosely based on concepts from evidence collection. Evidence + is usually collected, labeled, stored, and transported in specific + ways to preserve the state of evidence and to document all processing + steps. + +2.1. Evidence + + In ARC's situation, the "evidence" is a message's authentication + assessment at any point along the delivery path between origination + and final delivery. Determination of message authentication can be + affected when intermediate handlers modify message content (header + fields and/or body content), route messages through unforeseen paths, + or change envelope information. + + The authentication assessment for a message is determined upon + receipt of a message and documented in the Authentication-Results + header field(s). ARC extends this mechanism to survive transit + through intermediary ADMDs. + + Because the first-hand determination of an authentication assessment + can never be reproduced by other handlers, the assertion of the + authentication assessment is more akin to testimony by a verifiable + party than hard evidence which can be independently evaluated. + +2.2. Custody + + "Custody" refers to when an Internet Mail Handler processes a + message. When a handler takes custody of a message, the handler + becomes a custodian and attaches their own evidence (authentication + assessment upon receipt) to the message if they are ARC-enabled. + Evidence is added in such a way so that future handlers can verify + the authenticity of both evidence and custody. + +2.3. Chain of Custody + + The "chain of custody" of ARC is the entire set of evidence and + custody that travels with a message. + +2.4. Validation of Chain of Custody + + Any ARC-enabled Internet Mail Handler can validate the entire set of + custody and the authentication assessments asserted by each party to + yield a valid Chain of Custody. If the evidence-supplying custodians + can be trusted, then the validated Chain of Custody describes the + (possibly changing) authentication assessment as the message traveled + through various custodians. + + + +Andersen, et al. Expires June 21, 2019 [Page 5] + +Internet-Draft ARC-Protocol December 2018 + + + Even though a message's authentication assessment might have changed, + the validated chain of custody can be used to determine if the + changes (and the custodians responsible for the changes) can be + tolerated. + +3. Terminology and Definitions + + This section defines terms used in the rest of the document. + + Readers should to be familiar with the contents, core concepts, and + definitions found in [RFC5598]. The potential roles of transit + services in the delivery of email are directly relevant. + + Language, syntax (including some ABNF constructs), and concepts are + imported from DKIM [RFC6376]. Specific references to DKIM are made + throughout this document. The following terms are imported from + [RFC5598]: + + o ADministrative Management Domain (ADMD), Section 2.3 + + o Message Transfer Agents (MTA), Section 4.3.2 + + o Message Submission Agent (MSA), Section 4.3.1 + + o Message Delivery Agent (MDA), Section 4.3.3 + + Syntax descriptions use Augmented BNF (ABNF) [RFC5234] and [RFC7405]. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. These words may also appear in this + document in lower case as plain English words, absent their normative + meanings. + +3.1. ARC Set + + Section 4.1 introduces three (3) ARC header fields which are added to + a message by an ARC-enabled internet mail handler. Together, these + three header fields compose a single "ARC Set". An ARC Set provides + the means for an Internet Mail Handler to attach an authentication + assessment to a message in a manner that can be verified by future + handlers. A single message can contain multiple ARC Sets. + + In general concept terms, an ARC Set represents Evidence and Custody. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 6] + +Internet-Draft ARC-Protocol December 2018 + + +3.2. Authenticated Received Chain (ARC) + + The sequence of ARC Sets attached to a message at a given time is + called the Authenticated Received Chain. An Authenticated Received + Chain is the record of individual authentication assessments as a + message traverses through ARC-participating ADMDs. + + The first attachment of an ARC Set to a message causes an + Authenticated Received Chain to be created. Additional attachments + of ARC Sets cause the Authenticated Received Chain to be extended. + + In General concept terms, an Authenticated Received Chain represents + Chain of Custody. + +3.3. Internet Mail Handlers / Intermediaries + + Internet Mail Handlers process and deliver messages across the + Internet and include MSAs, MTAs, MDAs, gateways, and mailing lists as + defined in [RFC5598]. + + Throughout this document the term "intermediaries" refers to the both + regular MTAs as well as delivery/reposting agents such as mailing + lists covered within the scope of [RFC5598]'s transit services. + + "Intermediaries" and "Internet Mail Handlers" are used synonymously + throughout this document. + +3.4. Authentication Assessment + + The Authentication Assessment which is affixed to a message as part + of each ARC Set consists of the "authres-payload" [I-D-7601bis]. For + the integrity of an ARC Set, the Authentication Assessment only needs + to be properly encapsulated within the ARC Set as defined below + Section 4.1. The accuracy or syntax of the authres-payload field + does not affect the validity of the ARC chain itself. + +3.5. Signing vs Sealing + + Signing is the process of affixing a digital signature to a message + as a header field, such as when a DKIM-Signature (as in [RFC6376] + section 2.1), or an AMS or AS is added. Sealing is when an ADMD + affixes a complete and valid ARC Set to a message creating or + continuing an Authenticated Received Chain. + + + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 7] + +Internet-Draft ARC-Protocol December 2018 + + +3.6. Sealer + + A Sealer is an Internet Mail Handler that attaches a complete and + valid ARC Set to a message. + + In general concept terms, a Sealer adds its testimony (assertion of + authentication assessment) and proof of custody to the Chain of + Custody. + +3.7. Validator + + A Validator is an ARC-enabled Internet Mail Handler that evaluates an + Authenticated Received Chain for validity and content. The process + of evaluation of the individual ARC Sets that compose an + Authenticated Received Chain is described in Section 5.2. + + In general concept terms, a Validator inspects the Chain of Custody + to determine the content and validity of individual Evidence supplied + by custodians. + +3.8. Imported ABNF Tokens + + The following ABNF tokens are imported: + + o tag-list ([RFC6376] section 3.2) + + o authres-payload ([I-D-7601bis] section 2.2) + + o cfws ([RFC5322] section 3.2.2) + +3.9. Common ABNF Tokens + + The following ABNF tokens are used elsewhere in this document: + + position = 1*2DIGIT ; 1 - 50 + instance = [CFWS] %s"i" [CFWS] "=" + [CFWS] position + chain-status = ("none" / "fail" / "pass") + seal-cv-tag = %s"cv" [CFWS] "=" + [CFWS] chain-status + +4. Protocol Elements + +4.1. ARC Header Fields + + ARC introduces three new header fields. Syntax for new header fields + adapts existing specifications. This document only describes where + + + + +Andersen, et al. Expires June 21, 2019 [Page 8] + +Internet-Draft ARC-Protocol December 2018 + + + ARC-specific changes in syntax and semantics differ from existing + specifications. + +4.1.1. ARC-Authentication-Results (AAR) + + The ARC-Authentication-Results (AAR) header field records the message + authentication assessment as processed by an ARC-participating ADMD + at message arrival time. + + In general concept terms, the AAR header field is where Evidence is + recorded by a custodian. + + The AAR header field is similar in syntax and semantics to an + Authentication-Results field [I-D-7601bis], with two (2) differences: + + o the name of the header field itself; + + o the presence of the "instance tag". Additional information on the + "instance tag" can be found in Section 4.2.1. + + The formal ABNF for the AAR header field is: + + arc-info = instance [CFWS] ";" authres-payload + arc-authres-header = "ARC-Authentication-Results:" [CFWS] arc-info + + Because there is only one AAR allowed per ARC set, the AAR MUST + contain the combined authres-payload with all of the authentication + results from within the participating ADMD, regardless of how many + Authentication-Results header fields are attached to the message. + +4.1.2. ARC-Message-Signature (AMS) + + The ARC-Message-Signature (AMS) header field allows an ARC- + participating ADMD to convey some responsibility (custodianship) for + a message and possible message modifications to future ARC- + participating custodians. + + In general concept terms, the AMS header field identifies a + custodian. + + The AMS header field has the same syntax and semantics as the DKIM- + Signature field [RFC6376], with three (3) differences: + + o the name of the header field itself; + + o no version tag ("v") is defined for the AMS header field. As + required for undefined tags (in [RFC6376]), if seen, a version tag + MUST be ignored; + + + +Andersen, et al. Expires June 21, 2019 [Page 9] + +Internet-Draft ARC-Protocol December 2018 + + + o the "i" (AUID) tag is not imported from DKIM; instead, this tag is + replaced by the "instance tag" as defined in Section 4.2.1; + + ARC places no requirements on the selectors and/or domains used for + the AMS header field signatures. + + The formal ABNF for the AMS header field is: + + arc-ams-info = instance [CFWS] ";" tag-list + arc-message-signature = "ARC-Message-Signature:" [CFWS] arc-ams-info + + To reduce the chances of accidental invalidation of AMS signatures: + + o AMS header fields are added by ARC-participating ADMDs as messages + exit the ADMD. AMS header fields SHOULD be attached so that any + modifications made by the ADMD are included in the signature of + the AMS header field. + + o Authentication-Results header fields MUST NOT be included in AMS + signatures as they are likely to be deleted by downstream ADMDs + (per [I-D-7601bis] Section 5). + + o ARC-related header fields (ARC-Authentication-Results, ARC- + Message-Signature, ARC-Seal) MUST NOT be included in the list of + header fields covered by the signature of the AMS header field. + + To preserve the ability to verify the integrity of a message, the + signature of the AMS header field SHOULD include any DKIM-Signature + header fields already present in the message. + +4.1.3. ARC-Seal (AS) + + The ARC-Seal (AS) header field permits ARC-participating ADMDs to + verify the integrity of AAR header fields and corresponding AMS + header fields. + + In general concept terms, the AS header field is how custodians bind + their authentication assessments (testimonial) into a Chain of + Custody so that Validators can inspect individual evidence and + custodians. + + The AS header field is similar in syntax and semantics to DKIM- + Signatures [RFC6376], with the following differences: + + o the "i" (AUID) tag is not imported from DKIM; instead, this tag is + replaced by the "instance tag" as defined in Section 4.2.1; + + + + + +Andersen, et al. Expires June 21, 2019 [Page 10] + +Internet-Draft ARC-Protocol December 2018 + + + o the signature of the AS header field does not cover the body of + the message and therefore there is no 'bh' tag. The signature of + the AS header field only covers specific header fields as defined + in Section 5.1.1; + + o no body canonicalization is performed as the AS signature does not + cover the body of a message; + + o only "relaxed" header field canonicalization ([RFC6376] section + 3.4.2) is used; + + o the only supported tags are "i" (from Section 4.2.1 of this + document), and "a", "b", "d, "s", "t" from [RFC6376] Section 3.5. + Note especially that the DKIM "h" tag is NOT allowed and if found, + MUST result in a cv status of "fail" (for more information see + Section 5.1.1); + + o an additional tag, "cv" ("seal-cv-tag" in the ARC-Seal ABNF + definition) is used to communicate Chain Validation Status to + subsequent ADMDs. + + ARC places no requirements on the selectors and/or domains used for + the AS header field signatures. + + The formal ABNF for the AS header field is: + + arc-as-info = instance [CFWS] ";" tag-list + arc-seal = "ARC-Seal:" [CFWS] arc-as-info + +4.1.4. Internationalized Email (EAI) + + In internationalized messages [RFC6532] many header fields can + contain UTF-8 as well as ASCII text. The changes for EAI are all + inherited from DKIM as updated by [draft-levine-eaiauth] and + Authentication-Results as updated in [I-D-7601bis], but are called + out here for emphasis. + + In all ARC header fields, the d= s= tags can contain U-labels. In + all tags, non-ASCII characters need not be quoted in dkim-quoted- + printable. + + The AAR header allows UTF-8 in the same places that A-R does, as + described in [I-D-7601bis]. + + + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 11] + +Internet-Draft ARC-Protocol December 2018 + + +4.2. ARC Set + + An "ARC Set" is a single collection of three ARC header fields (AAR, + AMS, and AS). ARC header fields of an ARC Set share the same + "instance" value. + + By adding all ARC header fields to a message, an ARC Sealer adds an + ARC Set to a message. A description of how Sealers add an ARC Set to + a message is found in Section 5.1. + +4.2.1. Instance Tags + + Instance tags describe which ARC header fields belong to an ARC Set. + Each ARC header field of an ARC Set shares the same instance tag + value. + + Instance tag values are integers that begin at 1 and are incremented + by each addition of an ARC Set. Through the incremental values of + instance tags, an ARC Validator can determine the order in which ARC + Sets were added to a message. + + Instance tag values can range from 1-50 (inclusive). + + _INFORMATIONAL:_ The upper limit of 50 was picked based on some + initial observations reported by early working group members. The + value was chosen so as to balance the risk of excessive header field + growth Section 9.1 against expert opinion regarding the probability + of long-tail but non-looping multiple-intermediary mail flows. + Longer ARC chains will also impose load on validators and DNS to + support additional verification steps. Observed quantities of + "Received" header fields was also considered in establishing this as + an experimental initial value. + + Valid ARC Sets MUST have exactly one instance of each ARC header + field (AAR, AMS, and AS) for a given instance value and signing + algorithm. + + For handling multiple signing algorithms, see [ARC-MULTI]. + +4.3. Authenticated Received Chain + + An Authenticated Received Chain is an ordered collection of ARC Sets. + As ARC Sets are enumerated sets of ARC header fields, an + Authenticated Received Chain represents the output of message + authentication assessments along the handling path of ARC-enabled + processors. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 12] + +Internet-Draft ARC-Protocol December 2018 + + + Authentication Assessments determined at each step of the ARC-enabled + handling path is present in an Authenticated Received Chain in the + form of AAR header fields. The ability to verify the identity of + message handlers and the integrity of message content is provided by + AMS header fields. AS header fields allow messages handlers to + validate the assertions, order and sequence of the Authenticated + Received Chain itself. + + In general concept terms, an Authenticated Received Chain represents + a message's Chain of Custody. Validators can consult a message's + Chain of Custody to gain insight regarding each custodian of a + message and the Evidence collected by each custodian. + +4.4. Chain Validation Status + + The state of the Authenticated Received Chain at a specific + processing step is called the "Chain Validation Status". Chain + Validation Status information is communicated in several ways: + + o the AS header field in the "cv" tag, and + + o as part of Authentication-Results and AAR header field(s). + + Chain Validation Status has one of three possible values: + + o none: There was no Authenticated Received Chain on the message + when it arrived for validation. Typically, this occurs when a + message is received directly from a message's original Message + Transfer Agent (MTA) or Message Submission Agent (MSA), or from an + upstream Internet Mail Handler that is not participating in ARC + handling. + + o fail: The message contains an Authenticated Received Chain whose + validation failed. + + o pass: The message contains an Authenticated Received Chain whose + validation succeeded. + +5. Protocol Actions + + ARC-enabled Internet Mail Handlers generally act as both ARC + Validators (when receiving messages) and ARC Sealers (when sending + messages onward, not originated locally). + + An Authenticated Received Chain with a Chain Validation Status of + "pass" (or "none") allows Internet Mail Handlers to ascertain: + + + + + +Andersen, et al. Expires June 21, 2019 [Page 13] + +Internet-Draft ARC-Protocol December 2018 + + + o all ARC-participating ADMDs that claim responsibility for handling + (and possibly modifying) the message in transit; + + o the authentication assessments of the message as determined by + each ADMD (from AAR header fields). + + With this information, Internet Mail Handlers MAY inform local policy + decisions regarding disposition of messages that experience + authentication failure due to intermediate processing. + +5.1. Sealer Actions + + To "seal" a message, an ARC Sealer adds an ARC Set (the three ARC + header fields AAR, AMS, and AS) to a message. All ARC header fields + in an ARC Set share the same instance tag value. + + To perform Sealing (aka to build and attach a new ARC Set), the + following actions must be taken by an ARC Sealer when presented with + a message: + + 1. All message modifications (including adding DKIM-Signature header + field(s)) MUST be performed before Sealing. + + 2. If the message already contains an Authenticated Received Chain + with the most recent AS reporting "cv=fail", then there is no + need to proceed and the algorithm stops here. + + 3. Calculate the instance value: if the message already contains an + Authenticated Received Chain, the instance value is 1 more than + the highest instance number found in the Authenticated Received + Chain. If no Authenticated Received Chain exists, the instance + value is 1. + + 4. Using the calculated instance value, generate and attach a + complete ARC set to the message as follows: + + 1. Generate and attach an ARC-Authentication-Results header + field as defined in Section 4.1.1. + + 2. Generate and attach an ARC-Message-Signature header field as + defined in Section 4.1.2. + + 3. Generate and attach an ARC-Seal header field using the AS + definition found in Section 4.1.3, the prescribed headers + defined in Section 5.1.1, and the Chain Validation Status as + determined during ARC Validation. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 14] + +Internet-Draft ARC-Protocol December 2018 + + +5.1.1. Header Fields To Include In ARC-Seal Signatures + + The ARC-Seal is generated in a manner similar to how DKIM-Signatures + are added to messages ([RFC6376], section 3.7), with explicit + requirements on the header fields and ordering of those fields. + + The signature of an AS header field signs a canonicalized form of the + ARC Set header field values. The ARC set header field values are + supplied to the hash function in increasing instance order, starting + at 1, and include the ARC Set being added at the time of Sealing the + message. + + Within an ARC Set, header fields are supplied to the hash function in + the following order: + + 1. ARC-Authentication-Results + + 2. ARC-Message-Signature + + 3. ARC-Seal + + Note that when an Authenticated Received Chain has failed validation, + the signing scope for the ARC-Seal is modified as specified in + Section 5.1.2. + +5.1.2. Marking and Sealing "cv=fail" (Invalid) Chains + + In the case of a failed Authenticated Received Chain, the header + fields included in the signature scope of the AS header field b= + value MUST only include the ARC Set header fields created by the MTA + which detected the malformed chain, as if this newest ARC Set was the + only set present. + + _INFORMATIONAL_: This approach is mandated to handle the case of a + malformed or otherwise invalid Authenticated Received Chain. There + is no way to generate a deterministic set of AS header fields + (Section 5.1.1) in most cases of invalid chains. + +5.1.3. Only One Authenticated Received Chain Per Message + + A message can have only one Authenticated Received Chain on it at a + time. Once broken, the chain cannot be continued, as the chain of + custody is no longer valid and responsibility for the message has + been lost. For further discussion of this topic and the design + restriction which prevents chain continuation or re-establishment, + see [ARC-USAGE]. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 15] + +Internet-Draft ARC-Protocol December 2018 + + +5.1.4. Broad Ability to Seal + + ARC is not solely intended for perimeter MTAs. Any Internet Mail + Handler MAY seal a message by adding a complete ARC set, whether or + not they have modified or are aware of having modified the message. + For additional information, see Section 7.1. + +5.1.5. Sealing is Always Safe + + The utility of an Authenticated Received Chain is limited to very + specific cases. Authenticated Received Chains are designed to + provide additional information to an Internet Mail Handler when + evaluating messages for delivery in the context of authentication + failures. Specifically: + + o Properly adding an ARC Set to a message does not damage or + invalidate an existing Authenticated Received Chain. + + o Sealing an Authenticated Received Chain when a message has not + been modified does not negatively affect the chain. + + o Validating a message exposes no new threat vectors (see + Section 9). + + o An ADMD may choose to Seal all inbound messages whether or not a + message has been modified or will be retransmitted. + +5.2. Validator Actions + + A validator performs the following steps, in sequence, to process an + Authenticated Received Chain. Canonicalization, hash functions, and + signature validation methods are imported from [RFC6376] section 5. + + 1. Collect all ARC Sets currently attached to the message. + + * If there are none, the Chain Validation Status is "none" and + the algorithm stops here. + + * The maximum number of ARC Sets that can be attached to a + message is 50. If more than the maximum number exist the + Chain Validation Status is "fail" and the algorithm stops + here. + + * In the following algorithm, the maximum discovered ARC + instance value is referred to as "N". + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 16] + +Internet-Draft ARC-Protocol December 2018 + + + 2. If the Chain Validation Status of the highest instance value ARC + Set is "fail", then the Chain Validation status is "fail" and the + algorithm stops here. + + 3. Validate the structure of the Authenticated Received Chain. A + valid ARC has the following conditions: + + 1. Each ARC Set MUST contain exactly one each of the three ARC + header fields (AAR, AMS, and AS). + + 2. The instance values of the ARC Sets MUST form a continuous + sequence from 1..N with no gaps or repetition. + + 3. The "cv" value for all ARC-Seal header fields MUST NOT be + "fail". For ARC Sets with instance values > 1, the values + MUST be "pass". For the ARC Set with instance value = 1, the + value MUST be "none". + + * If any of these conditions are not met, the Chain Validation + Status is "fail" and the algorithm stops here. + + 4. Validate the AMS with the greatest instance value (most recent). + If validation fails, then the Chain Validation Status is "fail" + and the algorithm stops here. + + 5. _OPTIONAL:_ Determine the "oldest-pass" value from the ARC Set by + validating each prior AMS beginning with the N-1 and proceeding + in decreasing order to the AMS with the instance value of 1: + + 1. If an AMS fails to validate (for instance value "M"), then + set the oldest-pass value to the lowest AMS instance value + which passed (M+1) and go to the next step (there is no need + to check any other (older) AMS header fields). This does not + affect the validity of the Authenticated Received Chain. + + 2. If all AMS header fields verify, set the oldest-pass value to + zero (0). + + 6. Validate each AS beginning with the greatest instance value and + proceeding in decreasing order to the AS with the instance value + of 1. If any AS fails to validate, the Chain Validation Status + is "fail" and the algorithm stops here. + + 7. If the algorithm reaches this step, then the Chain Validation + Status is "pass", and the algorithm is complete. + + The end result of this Validation algorithm SHOULD be included within + the Authentication-Results header field for the ADMD. + + + +Andersen, et al. Expires June 21, 2019 [Page 17] + +Internet-Draft ARC-Protocol December 2018 + + + As with a DKIM signature ([RFC6376] section 6.3) which fails + verification, a message with an Authenticated Received Chain with a + Chain Validation status of "fail" MUST be treated the same as a + message with no Authenticated Received Chain. + + _INFORMATIONAL_: Recipients of an invalid or failing Authenticated + Received Chain can use that information as part of a wider handling + context. ARC adoption cannot be assumed by intermediaries; many + intermediaries will continue to modify messages without adding ARC + Seals. + +5.2.1. All Failures Are Permanent + + Authenticated Received Chains represent the traversal of messages + through one or more intermediaries. All errors, including DNS + failures, become unrecoverable and are considered permanent. + + Any error validating an Authenticated Received Chain results in a + Chain Validation Status of "fail". For further discussion of this + topic and the design restriction which prevents chain continuation or + re-establishment, see [ARC-USAGE]. + +5.2.2. Responding to ARC Validation Failures During the SMTP + Transaction + + If an ARC Validator determines that the incoming message fails ARC + validation, the Validator MAY signal the breakage through the + extended SMTP response code 5.7.29 "ARC validation failure" and + corresponding SMTP basic response code. Because ARC failures are + likely only to be detected in the context of other underlying + authentication mechanism failures, validators MAY use the more + general 5.7.26 "Multiple authentication checks failed" instead of the + ARC-specific code. + +6. Communication of Validation Results + + Chain Validation Status (described in Section 4.4) is communicated + via Authentication-Results (and AAR) header fields using the auth + method "arc". This auth method is described in Section 10.1. + + If necessary data is available, the ptypes and properties defined in + Section 10.2 SHOULD be recorded in an Authentication-Results header + field: + + o smtp.remote-ip - The address of the connection-initiating SMTP + server, from which the message is being relayed. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 18] + +Internet-Draft ARC-Protocol December 2018 + + + o header.oldest-pass - The instance number of the oldest AMS that + still validates, or 0 if all pass. + +7. Use Cases + + This section explores several messaging handling use cases that are + addressed by ARC. + +7.1. Communicate Authentication Assessment Across Trust Boundaries + + When an intermediary ADMD adds an ARC Set to a message's + Authenticated Received Chain (or creates the initial ARC Set), the + ADMD communicates its authentication assessment to the next ARC- + participating ADMD in the message handling path. + + If ARC-enabled ADMDs are trusted, Authenticated Received Chains can + be used to bridge administrative boundaries. + +7.1.1. Message Scanning Services + + Message services are available to perform anti-spam, anti-malware, + and anti-phishing scanning. Such services typically remove malicious + content, replace HTTP links in messages with sanitized links, and/or + attach footers to messages advertising the abilities of the message + scanning service. These modifications almost always break signature- + based authentication (such as DKIM). + + Scanning services typically require clients to point MX records of an + Internet domain to the scanning service. Messages destined for the + Internet domain are initially delivered to the scanning service. + Once scanning is performed, messages are then routed to the client's + own mail handling infrastructure. Re-routing messages in this way + almost always breaks path-based authentication (such as SPF). + + Message scanning services can attach Authenticated Received Chains to + messages to communicate authentication assessment into client ADMDs. + Clients can then benefit from the message scanning service while + processing messages as if the client's infrastructure were the + original destination of the Internet domain's MX record. + +7.1.2. Multi-tier MTA Processing + + Large message processing infrastructure is often divided into several + processing tiers that can break authentication information between + tiers. For example, a large site may maintain a cluster of MTAs + dedicated to connection handling and enforcement of IP-based + reputation filtering. A secondary cluster of MTAs may be dedicated + and optimized for content-based processing of messages. + + + +Andersen, et al. Expires June 21, 2019 [Page 19] + +Internet-Draft ARC-Protocol December 2018 + + + Authenticated Received Chains can be used to communicate + authentication assessment between processing tiers. + +7.1.3. Mailing Lists + + Mailing lists take delivery of messages and re-post them to + subscribers. A full description of authentication-related mailing + list issues can be found in [RFC7960] Section 3.2.3. + + Mailing list services can implement ARC to convey the authentication + assessment of posted messages sent to the list's subscriber base. + The ADMDs of the mailing list subscribers can then use the + Authenticated Received Chain to determine the authentication + assessment of the original message before mailing list handling. + +7.2. Inform Message Disposition Decisions + + Intermediaries often break authentication through content + modification, interfere with path-based authentication (such as SPF), + and strip authentication results (if an MTA removes Authentication- + Results header fields). + + Authenticated Received Chains allow ARC Validators to: + + 1. identify ARC-enabled ADMDs that break authentication while + processing messages; + + 2. gain extended visibility into the authentication-preserving + abilities of ADMDs that relay messages into ARC-enabled ADMDs. + + Through the collection of ARC-related data, an ADMD can identify + handling paths that have broken authentication. + + An Authenticated Received Chain allows an Internet Mail Handler to + potentially base decisions of message disposition on authentication + assessments provided by different ADMDs. + +7.2.1. DMARC Local Policy Overrides + + DMARC introduces a policy model where Domain Owners can request email + receivers to reject or quarantine messages that fail DMARC alignment. + Interoperability issues between DMARC and indirect email flows are + documented in [RFC7960]. + + Authenticated Received Chains allow DMARC processors to consider + authentication assessments provided by other ADMDs. As a matter of + local policy, a DMARC processor MAY choose to accept the + + + + +Andersen, et al. Expires June 21, 2019 [Page 20] + +Internet-Draft ARC-Protocol December 2018 + + + authentication assessments provided by an Authenticated Received + Chain when determining if a message is DMARC compliant. + + When an Authenticated Received Chain is used to determine message + disposition, the DMARC processor can communicate this local policy + decision to Domain Owners as described in Section 7.2.2. + +7.2.2. DMARC Reporting + + DMARC-enabled receivers indicate when ARC Validation influences + DMARC-related local policy decisions. When an ARC-enabled handler + generates a DMARC report, it MAY indicate the influence of ARC on + their local policy decision(s) by adding a reason of "local_policy" + with a comment string (per [RFC7489] Appendix C) containing a list of + data discovered during ARC Validation, which at a minimum includes: + + o the Chain Validation Status, + + o the domain and selector for each AS, + + o the originating IP address from the first ARC Set: + + EXAMPLE: + + + none + fail + fail + + local_policy + arc=pass as[2].d=d2.example as[2].s=s2 + as[1].d=d1.example as[1].s=s3 + remote-ip[1]=2001:DB8::1A + + + + In the above example DMARC XML reporting fragment, data relating to + specific validated ARC Sets are enumerated using array syntax (eg, + "as[2]" means AS header field with instance value of 2). d2.example + is the Sealing domain for ARC Set #2 (i=2) and d1.example is the + Sealing domain for ARC Set #1 (i=1). + + Depending on the reporting practices of intermediate message + handlers, Domain Owners may receive multiple DMARC reports for a + single message. Receivers of DMARC reports should be aware of this + behaviour and make the necessary accommodations. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 21] + +Internet-Draft ARC-Protocol December 2018 + + +8. Privacy Considerations + + The Authenticated Received Chain provides a verifiable record of the + handlers for a message. This record may include Personally + Identifiable Information such as IP address(es) and domain names. + Such information is also included in existing non-ARC related header + fields such as the "Received" header fields. + +9. Security Considerations + + The Security Considerations of [RFC6376] and [I-D-7601bis] apply + directly to this specification. + + As with other domain authentication technologies (such as SPF, DKIM, + and DMARC), ARC makes no claims about the semantic content of + messages. + A received message with an ARC chain provides evidence (at instance + N) that: The sealing domain (ARC-Seal d=) processed a message with + this body, determined the authentication assessment reported in the + ARC-Authentication-Results, and the ARC chain 1..N-1 (with the + validation status as reported in the cv field). + +9.1. Increased Header Field Size + + Inclusion of Authenticated Received Chains into messages may cause + issues for older or constrained MTAs due to increased total header + field size. Large header field blocks, in general, may cause + failures to deliver or other outage scenarios for such MTAs. ARC + itself would not cause problems. + +9.2. DNS Operations + + The validation of an Authenticated Received Chain composed of N ARC + Sets can require up to 2*N DNS queries (not including any DNS + redirection mechanisms which can increase the total number of + queries). This leads to two considerations: + + 1. An attacker can send a message to an ARC participant with a + concocted sequence of ARC Sets bearing the domains of intended + victims, and all of them will be queried by the participant until + a failure is discovered. DNS caching and the difficulty of + forging the signature values should limit the extent of this load + to domains under control of the attacker. Query traffic pattern + analysis may expose information about downstream validating ADMD + infrastructure. + + 2. DKIM only performs one DNS query per signature, while ARC can + introduce many (per chain). Absent caching, slow DNS responses + + + +Andersen, et al. Expires June 21, 2019 [Page 22] + +Internet-Draft ARC-Protocol December 2018 + + + can cause SMTP timeouts; and backlogged delivery queues on + Validating systems. This could be exploited as a DoS attack. + +9.3. Message Content Suspicion + + Recipients are cautioned to treat messages bearing Authenticated + Received Chains with the same suspicion applied to all other + messages. This includes appropriate content scanning and other + checks for potentially malicious content. + + ARC authenticates the identity of some email handling actors. It + does not make any assessment of their trustworthiness. + + Just as passing message authentication is not an indication of + message safety, forwarding that information through the mechanism of + ARC is also not an indication of message safety. Even if all ARC- + enabled ADMDs are trusted, ADMDs may have become compromised, may + miss unsafe content, or may not properly authenticate messages. + +9.4. Message Sealer Suspicion + + Recipients are cautioned to treat every Sealer of the ARC Chain with + suspicion. Just as with a validated DKIM signature, responsibility + for message handling is attributed to the Sealing domain, but whether + or not that Sealer is a malicious actor is out of scope of the + authentication mechanism. Since ARC aids message delivery in the + event of an authentication failure, ARC Sealers should be treated + with suspicion, so that a malicious actor cannot Seal spam or other + fraudulent messages to aid their delivery, too. + +9.5. Replay Attacks + + Since ARC inherits heavily from DKIM, it has similar attack vectors. + In particular, the Replay Attack described in [RFC6376] section 8.6 + is potentially amplified by ARC's chained statuses. In an ARC replay + attack, a malicious actor would take an intact and passing ARC Chain, + and then resend it to many recipients without making any + modifications that invalidate the latest AMS or AS. The impact to a + receiver would be more DNS lookups and signature evaluations. This + scope of this attack can be limited by caching DNS queries and + following the same signing scope guidance from [RFC6376] section + 5.4.1. + +10. IANA Considerations + + [[ *Note to the RFC Editors:* "dkim - header - s" is defined in + [I-D-7601bis]. Please adjust the list below as appropriate. ]] + + + + +Andersen, et al. Expires June 21, 2019 [Page 23] + +Internet-Draft ARC-Protocol December 2018 + + + This draft introduces three new headers fields and updates the Email + Authentication Parameters registry with one new authentication method + and several status codes. + +10.1. Email Authentication Results Names Registry Update + + This draft adds one Auth Method with three Codes to the IANA "Email + Authentication Result Names" registry: + + o Auth Method : arc + Code: "none", "pass", "fail" + Specification: this document 2.2 + Status: active + +10.2. Email Authentication Methods Registry Update + + This draft adds several new items to the Email Authentication Methods + registry, most recently defined in [I-D-7601bis]: + + o Method: arc + Definition: this document section 6 + ptype: smtp + Property: remote-ip + Value: IP address (v4 or v6) of originating SMTP connection + Status: active + Version: 1 + + o Method: arc + Definition: this document section 6 + ptype: header + Property: oldest-pass + Value: The instance id of the oldest validating AMS, or 0 if they + all pass (see Section 5.2) + Status: active + Version: 1 + +10.3. Definitions of the ARC header fields + + This specification adds three new header fields to the "Permanent + Message Header Field Registry", as follows: + + o Header field name: ARC-Seal + Applicable protocol: mail + Status: Experimental + Author/Change controller: IETF + Specification document(s): this document + Related information: [RFC6376] + + + + +Andersen, et al. Expires June 21, 2019 [Page 24] + +Internet-Draft ARC-Protocol December 2018 + + + o Header field name: ARC-Message-Signature + Applicable protocol: mail + Status: Experimental + Author/Change controller: IETF + Specification document(s): this document + Related information: [RFC6376] + + o Header field name: ARC-Authentication-Results + Applicable protocol: mail + Status: Experimental + Author/Change controller: IETF + Specification document(s): this document + Related information: [I-D-7601bis] + +10.4. New Enhanced Status Code - ARC Validation + + The following value should be added to the [ENHANCED-STATUS] + registry, as follows: + + o Code: X.7.29 + Sample Text: ARC validation failure + Associated basic status code: 550 + Description: This status code may be returned when a message fails + ARC validation + Reference: this document + Submitter: K. Andersen + Change controller: IESG + +11. Experimental Considerations + + The ARC protocol is designed to address common interoperability + issues introduced by intermediate message handlers. Interoperability + issues are described in [RFC6377] and [RFC7960]. + + As the ARC protocol is implemented by Internet Mail Handlers over + time, the following should be evaluated in order to determine the + success of the protocol in accomplishing the intended benefits. + +11.1. Success Consideration + + In an attempt to deliver legitimate messages that users desire, many + receivers use heuristic-based methods to identify messages that + arrive via indirect delivery paths. + + ARC will be a success if the presence of Authenticated Received + Chains allows for improved decision making when processing legitimate + messages, specifically resulting in equal or better delivery rates + than achieve through the use of heuristic approaches. + + + +Andersen, et al. Expires June 21, 2019 [Page 25] + +Internet-Draft ARC-Protocol December 2018 + + +11.2. Failure Considerations + + ARC should function without introducing significant new vectors for + abuse (see Section 9). If unforeseen vectors are enabled by ARC, + then this protocol will be a failure. Note that weaknesses inherent + in the mail protocols ARC is built upon (such as DKIM replay attacks + and other known issues) are not new vectors which can be attributed + to this specification. + +11.3. Open Questions + + The following open questions are academic and have no clear answer at + the time of the development of the protocol. However, additional + deployments should be able to gather the necessary data to answer + some or all of them. + +11.3.1. Value of the ARC-Seal (AS) Header Field + + Data should be collected to show if the ARC-Seal (AS) provides value + beyond the ARC Message Signature (AMS) for either making delivery + decisions or catching malicious actors trying to craft or replay + malicious chains. + +11.3.2. Usage and/or signals from multiple selectors and/or domains in + ARC sets + + Any selectors and/or (sub)domains (under the control of the sealing + ADMD) may be used for ARC header field signatures. + + While implementers may choose to use various selectors and/or domains + for ARC set header fields, no compelling argument for or against such + usage has been made within the working group. As such we have chosen + to allow maximum freedom for the experimental definition of this + protocol. + + Wider deployment experience and higher volumes of traffic may show + whether this is useful. + +11.3.3. DNS Overhead + + Longer Authenticated Received Chains will require more queries to + retrieve the keys for validating the chain. While this is not + believed to be a security issue (see Section 9.2), it is unclear how + much overhead will truly be added. This is similar to some of the + initial processing and query load concerns which were debated at the + time of the DKIM specification development. + + + + + +Andersen, et al. Expires June 21, 2019 [Page 26] + +Internet-Draft ARC-Protocol December 2018 + + + Data should be collected to better understand usable length and + distribution of lengths found in valid Authenticated Received Chains + along with the DNS impact of processing Authenticated Received + Chains. + + An effective operational maximum will have to be developed through + deployment experience in the field. + +11.3.4. What Trace Information is Valuable + + There are several edge cases where the information in the AAR can + make the difference between message delivery or rejection. For + example, if there is a well known mailing list that seals with ARC + but doesn't do its own initial DMARC enforcement, an Internet Mail + Handler with this knowledge could make a delivery decision based upon + the authentication information it sees in the corresponding AAR + header field. + + Certain trace information in the AAR is useful/necessary in the + construction of DMARC reports. + + Further, certain receivers believe the entire set of trace + information would be valuable to feed into machine learning systems + to identify fraud and/or provide other signals related to message + delivery. + + At this point, however, it is unclear what trace information will be + valuable for all receivers, regardless of size. + + Data should be collected on what trace information receivers are + using that provides useful signals that affect deliverability, and + what portions of the trace data are left untouched or provide no + useful information. + + Since many such systems are intentionally proprietary or confidential + to prevent gaming by abusers, it may not be viable to reliably answer + this particular question. The evolving nature of attacks can also + shift the landscape of "useful" information over time. + +12. Implementation Status + + [[ Note to the RFC Editor: Please remove this section before + publication along with the reference to [RFC7942]. ]] + + This section records the status of known implementations of the + protocol defined by this specification at the time of posting of this + Internet-Draft, and is based on a proposal described in [RFC7942]. + The description of implementations in this section is intended to + + + +Andersen, et al. Expires June 21, 2019 [Page 27] + +Internet-Draft ARC-Protocol December 2018 + + + assist the IETF in its decision processes in progressing drafts to + RFCs. Please note that the listing of any individual implementation + here does not imply endorsement by the IETF. Furthermore, no effort + has been spent to verify the information presented here that was + supplied by IETF contributors. This is not intended as, and must not + be construed to be, a catalog of available implementations or their + features. Readers are advised to note that other implementations may + exist. + + This information is known to be correct as of the eighth + interoperability test event which was held on 2018-03-17 at IETF101. + + For a few of the implementations, later status information was + available as of August 2018. + +12.1. GMail test reflector and incoming validation + + Organization: Google + Description: Internal production implementation with both debug + analysis and validating + sealing pass-through function + Status of Operation: Production - Incoming Validation + Coverage: Full spec implemented as of this document + Licensing: Internal only + Implementation Notes: + + o Full functionality was demonstrated during the interop testing on + 2018-03-17 and 2018-10-12. All traffic going into GSuite, Google + Groups, or GMail mailboxes will have ARC validation and sealing. + + Contact Info: arc-discuss@dmarc.org [1] + +12.2. AOL test reflector and internal tagging + + Organization: AOL + Description: Internal prototype implementation with both debug + analysis and validating + sealing pass-through function + Status of Operation: Beta + Coverage: ARC Chain validity status checking is operational, but only + applied to email addresses enrolled in the test program. This system + conforms to [ARC-DRAFT-05] + Licensing: Proprietary - Internal only + Implementation Notes: + + o 2017-07-15: Full functionality verified during the interop + testing. + + o 2018-06: Partially retired but still accessible by special request + due to the in process evolution of the AOL mail infrastructure to + + + +Andersen, et al. Expires June 21, 2019 [Page 28] + +Internet-Draft ARC-Protocol December 2018 + + + the integrated OATH environment. The implementation was based on + the Apache James DKIM code base. + + o 2018-10: No longer available due to infrastucture changes at AOL/ + Yahoo!/Oath. + + Contact Info: arc-discuss@dmarc.org [2] + +12.3. dkimpy + + Organization: dkimpy developers/Scott Kitterman + Description: Python DKIM package + Status of Operation: Production + Coverage: Full spec implemented as of this document + + o 2017-07-15: The internal test suite is incomplete, but the command + line developmental version of validator was demonstrated to + interoperate with the Google and AOL implementations during the + interop on 2017-07-15 and the released version passes the tests in + [ARC-TEST] arc_test_suite [3] with both python and python3. + + o 2018-10: Re-validated in the interop + + Licensing: Open/Other (same as dkimpy package = BCD version 2) + Contact Info: https://launchpad.net/dkimpy + +12.4. OpenARC + + Organization: TDP/Murray Kucherawy + Description: Implementation of milter functionality related to the + OpenDKIM and OpenDMARC packages + Status of Operation: Beta + Coverage: Built to support this document + Licensing: Open/Other (same as OpenDKIM and OpenDMARC packages) + Implementation Notes: + + o 2018-10: Validated with one bug discovered during interop + + o 2018-11: Known issues have been resolved with release 1.0.0-Beta2 + + Contact Info: arc-discuss@dmarc.org [4], openarc-users@openarc.org + [5] + +12.5. Mailman 3.x patch + + Organization: Mailman development team + Description: Integrated ARC capabilities within the Mailman 3.2 + package + + + +Andersen, et al. Expires June 21, 2019 [Page 29] + +Internet-Draft ARC-Protocol December 2018 + + + Status of Operation: Patch submitted + Coverage: Based on OpenARC + Licensing: Same as mailman package - GPL + Implementation Notes: + + o Appears to work properly in at least one beta deployment, but + waiting on acceptance of the pull request into the mainline of + mailman development + + o Discussions continuing with Mailman team to get this integrated + + Contact Info: https://www.gnu.org/software/mailman/contact.html + +12.6. Copernica/MailerQ web-based validation + + Organization: Copernica + Description: Web-based validation of ARC-signed messages + Status of Operation: Beta + Coverage: Built to support [ARC-DRAFT-05] + Licensing: On-line usage only + Implementation Notes: + + o Released 2016-10-24 + + o Requires full message content to be pasted into a web form found + at http://arc.mailerq.com/ (warning - https is not supported). + + o An additional instance of an ARC signature can be added if one is + willing to paste a private key into an unsecured web form. + + o 2017-07-15: Testing shows that results match the other + implementations listed in this section. + + o 2018-10: not tested during interop + + Contact Info: https://www.copernica.com/ + +12.7. Rspamd + + Organization: Rspamd community + Description: ARC signing and verification module + Status of Operation: Production, though deployment usage is unknown + Coverage: Built to support [ARC-DRAFT-14] + Licensing: Open source + Implementation Notes: + + o 2017-06-12: Released with version 1.6.0 + + + + +Andersen, et al. Expires June 21, 2019 [Page 30] + +Internet-Draft ARC-Protocol December 2018 + + + o 2017-07-15: Testing during the interop showed that the validation + functionality interoperated with the Google, AOL, dkimpy and + MailerQ implementations + + o 2018-10: Re-validated during the interop + + Contact Info: https://rspamd.com/doc/modules/arc.html and + https://github.com/vstakhov/rspamd + +12.8. PERL MAIL::DKIM module + + Organization: FastMail + Description: Email domain authentication (sign and/or verify) module, + previously included SPF / DKIM / DMARC, now has ARC added + Status of Operation: Production, deployment usage unknown + Coverage: Built to support [ARC-DRAFT-10] + Licensing: Open Source + Implementation Notes: + + o 2017-12-15: v0.50 released with full test set passing for ARC + + o 2018-10: Revalidated during the interop and used for the creation + of the Appendix B example + + Contact Info: http://search.cpan.org/~mbradshaw/Mail-DKIM-0.50/ + +12.9. PERL Mail::Milter::Authentication module + + Organization: FastMail + Description: Email domain authentication milter, uses MAIL::DKIM (see + above) + Status of Operation: Initial validation completed during IETF99 + hackathon with some follow-on work during the week + Coverage: Built to support [ARC-DRAFT-14] + Licensing: Open Source + Implementation Notes: + + o 2017-07-15: Validation functionality which interoperates with + Gmail, AOL, dkimpy was demonstrated; later in the week of IETF99, + the signing functionality was reported to be working + + o 2017-07-20: ARC functionality has not yet been pushed back to the + github repo but should be showing up soon + + o 2018-10: Revalidated during the interop + + Contact Info: https://github.com/fastmail/authentication_milter + + + + +Andersen, et al. Expires June 21, 2019 [Page 31] + +Internet-Draft ARC-Protocol December 2018 + + +12.10. Sympa List Manager + + Organization: Sympa Dev Community + Description: Beta released Status of Operation: Beta released + Coverage: Built to support this document, based on Mail::DKIM module + Licensing: open source + Implementation Notes: + + o 2018-01-05: Tracked as https://github.com/sympa-community/sympa/ + issues/153 + + o 2018-12-08: Sympa 6.2.37 beta 3 incorporates ARC support, + scheduled for stable release 6.2.38 on 2018-12-21 + + Contact Info: https://github.com/sympa-community + +12.11. Oracle Messaging Server + + Organization: Oracle + Description: + Status of Operation: Initial development work during IETF99 + hackathon. Framework code is complete, crypto functionality requires + integration with libsodium + Coverage: Work in progress + Licensing: Unknown + Implementation Notes: + + o 2018-03: Protocol handling components are completed, but crypto is + not yet functional. + + Contact Info: Chris Newman, Oracle + +12.12. MessageSystems Momentum and PowerMTA platforms + + Organization: MessageSystems/SparkPost + Description: OpenARC integration into the LUA-enabled Momentum + processing space + Status of Operation: Beta + Coverage: Same as OpenARC + Licensing: Unknown + Implementation Notes: + + o 2018-10: Beta version in private evaluation, not tested during + interop. + + Contact Info: TBD + + + + + +Andersen, et al. Expires June 21, 2019 [Page 32] + +Internet-Draft ARC-Protocol December 2018 + + +12.13. Exim + + Organization: Exim developers + Status of Operation: Operational; requires specific enabling for + compile. + Coverage: Full spec implemented as of [ARC-DRAFT-13] + Licensing: GPL + Contact Info: exim-users@exim.org + Implementation notes: + + o Implemented as of Exim 4.91 + +12.14. Halon MTA + + Organization: Halon + Status of Operation: Operational as of May 2018 + Coverage: Full spec implemented as of this document Licensing: + Commercial, trial version available for download + Contact Info: https://halon.io + Implementation notes: + + o GPL'd library with ARC capabilities: https://github.com/halon/ + libdkimpp + + o 2018-10: Validated during interop + +12.15. IIJ + + Organization: Internet Initiative Japan (IIJ) Status of Operation: + Operational as of October 2018 + Coverage: Full spec implemented as of this document + Licensing: Internal + Contact Info: https://www.iij.ad.jp/en/ + Implementation notes: + + o 2018-10: Internal MTA implementation validated during the ARC + interop + +13. References + +13.1. Normative References + + [draft-levine-eaiauth] + Levine, J., "E-mail Authentication for Internationalized + Mail", August 2018, . + + + + + +Andersen, et al. Expires June 21, 2019 [Page 33] + +Internet-Draft ARC-Protocol December 2018 + + + [I-D-7601bis] + Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", February 2018, + . + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, + DOI 10.17487/RFC5234, January 2008, + . + + [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, + DOI 10.17487/RFC5322, October 2008, + . + + [RFC5598] Crocker, D., "Internet Mail Architecture", RFC 5598, + DOI 10.17487/RFC5598, July 2009, + . + + [RFC6376] Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed., + "DomainKeys Identified Mail (DKIM) Signatures", STD 76, + RFC 6376, DOI 10.17487/RFC6376, September 2011, + . + + [RFC6377] Kucherawy, M., "DomainKeys Identified Mail (DKIM) and + Mailing Lists", BCP 167, RFC 6377, DOI 10.17487/RFC6377, + September 2011, . + + [RFC6532] Yang, A., Steele, S., and N. Freed, "Internationalized + Email Headers", RFC 6532, DOI 10.17487/RFC6532, February + 2012, . + + [RFC7208] Kitterman, S., "Sender Policy Framework (SPF) for + Authorizing Use of Domains in Email, Version 1", RFC 7208, + DOI 10.17487/RFC7208, April 2014, + . + + [RFC7405] Kyzivat, P., "Case-Sensitive String Support in ABNF", + RFC 7405, DOI 10.17487/RFC7405, December 2014, + . + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 34] + +Internet-Draft ARC-Protocol December 2018 + + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + +13.2. Informative References + + [ARC-DRAFT-05] + Andersen, K., "Authenticated Received Chain (ARC) Protocol + (I-D-05)", n.d., . + + [ARC-DRAFT-10] + Andersen, K., "Authenticated Received Chain (ARC) Protocol + (I-D-10)", n.d., . + + [ARC-DRAFT-13] + Andersen, K., "Authenticated Received Chain (ARC) Protocol + (I-D-13)", n.d., . + + [ARC-DRAFT-14] + Andersen, K., "Authenticated Received Chain (ARC) Protocol + (I-D-14)", n.d., . + + [ARC-MULTI] + Andersen, K., "Using Multiple Signing Algorithms with + ARC", June 2018, . + + [ARC-TEST] + Blank, S., "ARC Test Suite", January 2017, + . + + [ARC-USAGE] + Jones, S., Adams, T., Rae-Grant, J., and K. Andersen, + "Recommended Usage of the ARC Headers", April 2018, + . + + [ENHANCED-STATUS] + "IANA SMTP Enhanced Status Codes", n.d., + . + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 35] + +Internet-Draft ARC-Protocol December 2018 + + + [RFC7489] Kucherawy, M., Ed. and E. Zwicky, Ed., "Domain-based + Message Authentication, Reporting, and Conformance + (DMARC)", RFC 7489, DOI 10.17487/RFC7489, March 2015, + . + + [RFC7942] Sheffer, Y. and A. Farrel, "Improving Awareness of Running + Code: The Implementation Status Section", BCP 205, + RFC 7942, DOI 10.17487/RFC7942, July 2016, + . + + [RFC7960] Martin, F., Ed., Lear, E., Ed., Draegen. Ed., T., Zwicky, + E., Ed., and K. Andersen, Ed., "Interoperability Issues + between Domain-based Message Authentication, Reporting, + and Conformance (DMARC) and Indirect Email Flows", + RFC 7960, DOI 10.17487/RFC7960, September 2016, + . + +13.3. URIs + + [1] mailto:arc-discuss@dmarc.org + + [2] mailto:arc-discuss@dmarc.org + + [3] https://github.com/Valimail/arc_test_suite + + [4] mailto:arc-discuss@dmarc.org + + [5] mailto:openarc-users@openarc.org + + [6] mailto:dmarc@ietf.org + + [7] mailto:arc-discuss@dmarc.org + + [8] mailto:arc-interop@dmarc.org + + [9] https://arc-spec.org + +Appendix A. Design Requirements + + The specification of the ARC framework is driven by the following + high-level goals, security considerations, and practical operational + requirements. + +A.1. Primary Design Criteria + + o Provide a verifiable "chain of custody" for email messages; + + o Not require changes for originators of email; + + + +Andersen, et al. Expires June 21, 2019 [Page 36] + +Internet-Draft ARC-Protocol December 2018 + + + o Support the verification of the ARC header field set by each hop + in the handling chain; + + o Work at Internet scale; and + + o Provide a trustable mechanism for the communication of + Authentication-Results across trust boundaries. + +A.2. Out of Scope + + ARC is not a trust framework. Users of the ARC header fields are + cautioned against making unsubstantiated conclusions when + encountering a "broken" ARC sequence. + +Appendix B. Example Usage + + The following message is an example of one which has passed through + several intermediary handlers, some of which have modified the + message and others which have not: + +Return-Path: +Received: from example.org (example.org [208.69.40.157]) + by gmail.example with ESMTP id d200mr22663000ykb.93.1421363207 + for ; Thu, 14 Jan 2015 15:02:40 -0800 (PST) +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from [2001:DB8::1A] (w-x-y-z.dsl.static.isp.example [w.x.y.z]) + (authenticated bits=0) + by segv.d1.example with ESMTP id t0FN4a8O084569; + Thu, 14 Jan 2015 15:00:01 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from mail-ob0-f188.google.example + (mail-ob0-f188.google.example [208.69.40.157]) by + clochette.example.org with ESMTP id d200mr22663000ykb.93.1421363268 + for ; Thu, 14 Jan 2015 15:03:15 -0800 (PST) +ARC-Seal: i=3; a=rsa-sha256; cv=pass; d=clochette.example.org; s= + clochette; t=12345; b=CU87XzXlNlk5X/yW4l73UvPUcP9ivwYWxyBWcVrRs7 + +HPx3K05nJhny2fvymbReAmOA9GTH/y+k9kEc59hAKVg== +ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d= + clochette.example.org; h=message-id:date:from:to:subject; s= + clochette; t=12345; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZY + LQ=; b=o71vwyLsK+Wm4cOSlirXoRwzEvi0vqIjd/2/GkYFYlSd/GGfKzkAgPqxf + K7ccBMP7Zjb/mpeggswHjEMS8x5NQ== +ARC-Authentication-Results: i=3; clochette.example.org; spf=fail + smtp.from=jqd@d1.example; dkim=fail (512-bit key) + header.i=@d1.example; dmarc=fail; arc=pass (as.2.gmail.example=pass, + + + +Andersen, et al. Expires June 21, 2019 [Page 37] + +Internet-Draft ARC-Protocol December 2018 + + + ams.2.gmail.example=pass, as.1.lists.example.org=pass, + ams.1.lists.example.org=fail (message has been altered)) +Authentication-Results: clochette.example.org; spf=fail + smtp.from=jqd@d1.example; dkim=fail (512-bit key) + header.i=@d1.example; dmarc=fail; arc=pass (as.2.gmail.example=pass, + ams.2.gmail.example=pass, as.1.lists.example.org=pass, + ams.1.lists.example.org=fail (message has been altered)) +ARC-Seal: i=2; a=rsa-sha256; cv=pass; d=gmail.example; s=20120806; t= + 12345; b=Zpukh/kJL4Q7Kv391FKwTepgS56dgHIcdhhJZjsalhqkFIQQAJ4T9BE + 8jjLXWpRNuh81yqnT1/jHn086RwezGw== +ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d= + gmail.example; h=message-id:date:from:to:subject; s=20120806; t= + 12345; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b=CVoG44 + cVZvoSs2mMig2wwqPaJ4OZS5XGMCegWqQs1wvRZJS894tJM0xO1RJLgCPsBOxdA5 + 9WSqI9s9DfyKDfWg== +ARC-Authentication-Results: i=2; gmail.example; spf=fail + smtp.from=jqd@d1.example; dkim=fail (512-bit key) + header.i=@example.org; dmarc=fail; arc=pass + (as.1.lists.example.org=pass, ams.1.lists.example.org=pass) +ARC-Seal: i=1; a=rsa-sha256; cv=none; d=lists.example.org; s=dk-lists; + t=12345; b=TlCCKzgk3TrAa+G77gYYO8Fxk4q/Ml0biqduZJeOYh6+0zhwQ8u/ + lHxLi21pxu347isLSuNtvIagIvAQna9a5A== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d= + lists.example.org; h=message-id:date:from:to:subject; s= + dk-lists; t=12345; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYL + Q=; b=DsoD3n3hiwlrN1ma8IZQFgZx8EDO7Wah3hUjIEsYKuShRKYB4LwGUiKD5Y + yHgcIwGHhSc/4+ewYqHMWDnuFxiQ== +ARC-Authentication-Results: i=1; lists.example.org; spf=pass + smtp.mfrom=jqd@d1.example; dkim=pass (512-bit key) + header.i=@d1.example; dmarc=pass +DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=d1.example; h= + message-id:date:from:to:subject; s=origin2015; bh=bIxxaeIQvmOBdT + AitYfSNFgzPP4=; b=qKjd5fYibKXWWIcMKCgRYuo1vJ2fD+IAQPjX+uamXIGY2Q + 0HjQ+Lq3/yHzG3JHJp6780/nKQPOWt2UDJQrJkEA== +Message-ID: <54B84785.1060301@d1.example> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.example +Subject: [List 2] Example 1 + +Hey gang, +This is a test message. +--J. + + + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 38] + +Internet-Draft ARC-Protocol December 2018 + + +Appendix C. Acknowledgements + + This draft originated with the work of OAR-Dev Group. + + The authors thank all of the OAR-Dev and the subsequent DMARC-WG + group for the ongoing help and though-provoking discussions from all + the participants, especially: Alex Brotman, Brandon Long, Dave + Crocker, Elizabeth Zwicky, Franck Martin, Greg Colburn, J. Trent + Adams, John Rae-Grant, Mike Hammer, Mike Jones, Steve Jones, Terry + Zink, Tim Draegen, Gene Shuman, Scott Kitterman, Bron Gondwana. + + Grateful appreciation is extended to the people who provided feedback + through the discuss mailing list. + +Appendix D. Comments and Feedback + + Please address all comments, discussions, and questions to + dmarc@ietf.org [6]. Earlier discussions can be found at arc- + discuss@dmarc.org [7]. Interop discussions planning can be found at + arc-interop@dmarc.org [8]. + + Some introductory material for less technical people can be found at + https://arc-spec.org [9]. + +Authors' Addresses + + Kurt Andersen + LinkedIn + 1000 West Maude Ave + Sunnyvale, California 94085 + USA + + Email: kurt+ietf@drkurt.com + + + Brandon Long (editor) + Google + + Email: blong@google.com + + + Seth Blank (editor) + Valimail + + Email: seth@valimail.com + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 39] + +Internet-Draft ARC-Protocol December 2018 + + + Murray Kucherawy (editor) + TDP + + Email: superuser@gmail.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Andersen, et al. Expires June 21, 2019 [Page 40] diff --git a/rfc/rfc2369.txt b/rfc/rfc2369.txt new file mode 100644 index 0000000000..77a1f68f59 --- /dev/null +++ b/rfc/rfc2369.txt @@ -0,0 +1,843 @@ + + + + + + +Network Working Group G. Neufeld +Request for Comments: 2369 Nisto +Category: Standards Track J. Baer + SkyWeyr Technologies + July 1998 + + + The Use of URLs as Meta-Syntax for Core Mail List Commands + and their Transport through Message Header Fields + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (1998). All Rights Reserved. + +Abstract + + The mailing list command specification header fields are a set of + structured fields to be added to email messages sent by email + distribution lists. Each field typically contains a URL (usually + mailto [RFC2368]) locating the relevant information or performing the + command directly. The three core header fields described in this + document are List-Help, List-Subscribe, and List-Unsubscribe. + + There are three other header fields described here which, although + not as widely applicable, will have utility for a sufficient number + of mailing lists to justify their formalization here. These are + List-Post, List-Owner and List-Archive. + + By including these header fields, list servers can make it possible + for mail clients to provide automated tools for users to perform list + functions. This could take the form of a menu item, push button, or + other user interface element. The intent is to simplify the user + experience, providing a common interface to the often cryptic and + varied mailing list manager commands. + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. + + + + + +Neufeld & Baer Standards Track [Page 1] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +1. Introduction + + This is a proposal for additional header fields to be added to email + messages sent by email distribution lists. The content of each new + field is typically a URL - usually mailto [RFC2368] - which locates + the relevant information or performs the command directly. MTAs + generating the header fields SHOULD usually include a mailto based + command, in addition to any other protocols used, in order to support + users who do not have access to non-mail-based protocols. + + Implementing these fields will be optional. Significant functionality + and convenience can be gained by including them, however. Many list + managers, especially as the proposal first gains acceptance, MAY + choose to implement only one or two of the fields. The List-Help + field is the most useful individual field since it provides an access + point to detailed user support information, and accommodates almost + all existing list managers command sets. The List-Subscribe and + List-Unsubscribe fields are also very useful, but cannot describe + some list manager syntaxes at this time (those which require variable + substitution). See appendix A.5 for an explanation. + + The description of command syntax provided by the fields can be used + by mail client applications to provide simplified and consistent user + access to email distribution list functions. This could take the form + of menu items, push buttons, or other user interface elements. The + intent is to simplify the user experience, providing a common + interface to the often cryptic and varied mailing list manager + commands. + + Consideration has been given to avoiding the creation of too many + fields, while at the same time avoiding the overloading of individual + fields and keeping the syntax clear and simple. + + The use of these fields does not remove the requirement to support + the -Request command address for mailing lists [RFC2142]. + +2. The Command Syntax + + The list header fields are subject to the encoding and character + restrictions for mail headers as described in [RFC822]. Additionally, + the URL content is further restricted to the set of URL safe + characters [RFC1738]. + + The contents of the list header fields mostly consist of angle- + bracket ('<', '>') enclosed URLs, with internal whitespace being + ignored. MTAs MUST NOT insert whitespace within the brackets, but + client applications should treat any whitespace, that might be + inserted by poorly behaved MTAs, as characters to ignore. + + + +Neufeld & Baer Standards Track [Page 2] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + A list of multiple, alternate, URLs MAY be specified by a comma- + separated list of angle-bracket enclosed URLs. The URLs have order of + preference from left to right. The client application should use the + left most protocol that it supports, or knows how to access by a + separate application. By this mechanism, protocols like http may be + specified while still providing the basic mailto support for those + clients who do not have access to non-mail protocols. The client + should only use one of the available URLs for a command, using + another only if the first one used failed. + + The use of URLs allows for the use of the syntax with existing URL + supporting applications. As the standard for URLs is extended, the + list header fields will gain the benefit of those extensions. + Additionally, the use of URLs provides access to multiple transport + protocols (such as ftp and http) although it is expected that the + "mailto" protocol [RFC2368] will be the focus of most use of the list + header fields. Use of non-mailto protocols should be considered in + light of those users who do not have access to the specified + mechanism (those who only have email - with no web access). + + Command syntaxes requiring variable fields to be set by the client + (such as including the user's email address within a command) are not + supported by this implementation. However, systems using such + syntaxes SHOULD still take advantage of the List-Help field to + provide the user with detailed instructions as needed or - perhaps + more usefully - provide access to some form of structured command + interface such as an HTML-based form. + + The additional complications of supporting variable fields within the + command syntax was determined to be too difficult to support by this + protocol and would compromise the likelihood of implementation by + software authors. + + To allow for future extension, client applications MUST follow the + following guidelines for handling the contents of the header fields + described in this document: + + 1) Except where noted for specific fields, if the content of the + field (following any leading whitespace, including comments) + begins with any character other than the opening angle bracket + '<', the field SHOULD be ignored. + + 2) Any characters following an angle bracket enclosed URL SHOULD be + ignored, unless a comma is the first non-whitespace/comment + character after the closing angle bracket. + + + + + + +Neufeld & Baer Standards Track [Page 3] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + 3) If a sub-item (comma-separated item) within the field is not an + angle-bracket enclosed URL, the remainder of the field (the + current, and all subsequent, sub-items) SHOULD be ignored. + +3. The List Header Fields + + This document presents header fields which will provide the + command syntax description for the 'core' and key secondary + functions of most email distribution lists. The fields implemented + on a given list SHOULD be included on all messages distributed by + the list (including command responses to individual users), and on + other messages where the message clearly applies to one distinct + list. There MUST be no more than one of each field present in any + given message. + + These fields MUST only be generated by mailing lists, not end + users. + +3.1. List-Help + + The List-Help field is the most important of the header fields + described in this document. It would be acceptable for a list + manager to include only this field, since by definition it SHOULD + direct the user to complete instructions for all other commands. + Typically, the URL specified would request the help file, perhaps + incorporating an HTML form for list commands, for the list, and + alternatively provide access to an instructive website. + + Examples: + + List-Help: (List Instructions) + List-Help: + List-Help: (Info about the list) + List-Help: , + List-Help: (FTP), + + +3.2. List-Unsubscribe + + The List-Unsubscribe field describes the command (preferably using + mail) to directly unsubscribe the user (removing them from the list). + + Examples: + + List-Unsubscribe: + List-Unsubscribe: (Use this command to get off the list) + + List-Unsubscribe: + + + +Neufeld & Baer Standards Track [Page 4] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + List-Unsubscribe: , + + +3.3. List-Subscribe + + The List-Subscribe field describes the command (preferably using + mail) to directly subscribe the user (request addition to the list). + + Examples: + + List-Subscribe: + List-Subscribe: + List-Subscribe: (Use this command to join the list) + + List-Subscribe: + List-Subscribe: , + + +3.4. List-Post + + The List-Post field describes the method for posting to the list. + This is typically the address of the list, but MAY be a moderator, or + potentially some other form of submission. For the special case of a + list that does not allow posting (e.g., an announcements list), the + List-Post field may contain the special value "NO". + + Examples: + + List-Post: + List-Post: (Postings are Moderated) + List-Post: + List-Post: NO (posting not allowed on this list) + +3.5. List-Owner + + The List-Owner field identifies the path to contact a human + administrator for the list. The URL MAY contain the address of a + administrator for the list, the mail system administrator, or any + other person who can handle user contact for the list. There is no + need to specify List-Owner if it is the same person as the mail + system administrator (postmaster). + + Examples: + + List-Owner: (Contact Person for Help) + List-Owner: (Grant Neufeld) + List-Owner: + + + + +Neufeld & Baer Standards Track [Page 5] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +3.6. List-Archive + + The List-Archive field describes how to access archives for the list. + + Examples: + + List-Archive: + List-Archive: + List-Archive: (Web Archive) + +4. Supporting Nested Lists + + A list that is a sublist for another list in a nested mailing list + hierarchy will need to modify some of the List- header fields, while + leaving others as the parent list set them. + + Sublists SHOULD remove the parent list's List-Help, List-Subscribe, + List-Unsubscribe and List-Owner fields, and SHOULD insert their own + versions of those fields. + + If the sublist provides its own archive, it SHOULD replace the List- + Archive with its own. Otherwise, it MUST leave the List-Archive field + untouched. + + Dependant on how postings to the list are handled, the sublist MAY + replace the List-Post field. The appropriateness of whether to + replace List-Post is left to the determination of the individual list + managers. If the intention is that postings should be distributed to + all members of the primary list, List-Post should not be changed by a + sublist in such a way that postings will be distributed only to + members of the sublist. + +5. Security Considerations + + There are very few new security concerns generated with this + proposal. Message headers are an existing standard, designed to + easily accommodate new types. There may be concern with multiple + fields being inserted or headers being forged, but these are problems + inherent in Internet email, not specific to the protocol described in + this document. Further, the implications are relatively harmless. + + Mail list processors should not allow any user-originated list header + fields to pass through to their lists, lest they confuse the user and + have the potential to create security problems. + + On the client side, there may be some concern with posts or commands + being sent in error. It is required that the user have a chance to + confirm any action before it is executed. In the case of mailto, it + + + +Neufeld & Baer Standards Track [Page 6] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + may be appropriate to create the correctly formatted message without + sending it, allowing the user to see exactly what is happening and + giving the user the opportunity to approve or discard the message + before it is sent. + + All security considerations for the use of URLs [RFC1738] apply + equally to this protocol. Mail client applications should not support + list header field URLs which could compromise the security of the + user's system. This includes the "file://" URL type which could + potentially be used to trigger the execution of a local application + on some user systems. + +6. Acknowledgements + + The numerous participants of the List-Header [5], ListMom-Talk [6], + List-Managers and MIDA-Mail mailing lists contributed much to the + formation and structure of this document. + + Keith Moore and Christopher Allen + provided guidance on the standards + process. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Neufeld & Baer Standards Track [Page 7] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +A. Background Discussion + + This proposal arose from discussions started on the ListMom-Talk + Discussion List [6]. When the discussion reached a sufficient level, + a separate list was formed for discussing this proposal, the List + Headers Mail List [5] for deeper discussion. We have included + summaries of key issues raised, in order to show some of the + alternatives examined and reasons for our decisions. + +A.1. Multiple header fields vs. a single header field + + Use of a single header field for transporting command meta-syntax was + rejected for a number of reasons. + + Such a field would require the creation of a new meta-syntax in order + to describe the list commands (as opposed to the use of the widely + deployed URL syntax which was chosen for this implementation). Every + additional layer of complexity and newness reduces the likelihood of + actual implementation because it will require additional work to + support. Also, by using the existing URL syntax, we can profit from + the end users' knowledge of that syntax and ability to use it even if + their client applications do not support the list header fields. + + Restricting the transport of meta-syntax to the use of a single + header field also introduces complications with header field size + limitations. Most individual commands can easily be described in a + single line, but describing a multitude of commands can take up many + lines in the field and runs a greater risk of being modified by an + existing server on route. + + The client implementation is also easier with multiple fields, since + each command can be supported and implemented individually, + completely independent of the others. Thus, some list managers or + mail clients can choose to implement a subset of the fields based on + the specific needs of their individual lists. + + Finally, the format described in this document is simple and well + recognized, which reduces the chances of errors in implementation and + parsing. + +A.2. URLs vs. parameter lists + + URLs are already an established syntax which is flexible, well- + defined, and in wide spread use. As its definition matures and + expands, the abilities of the list fields will grow as well, without + requiring modification of this proposal. URLs are well prepared to + handle future protocols and developments, and can easily describe the + different existing access protocols such as mailto, http and ftp. + + + +Neufeld & Baer Standards Track [Page 8] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + Many clients already have functionality for recognizing, parsing, and + evaluating URLs, either internally or by passing the request to a + helper application. This makes implementation easier and more + realistic. As an example, this existing support for URL parsing + allowed us to add prototype list header functionality to existing + mail clients (Eudora and Emailer for the Macintosh) without modifying + their source code. + +A.3. Why not just create a standard command language? + + A standard command language, supported by all email list services, + would go a long way to reducing the problems of list access that + currently plague existing services. It would reduce the amount of + learning required by end users and allow for a number of common + support tools to be developed. + + However, such standardization does pose problems in the areas of + multi-lingual support and the custom needs of individual mailing + lists. The development of such a standard is also expected to be met + with a slow adoption rate by software developers and list service + providers. + + These points do not preclude the development of such a standard (in + fact, it would suggest that we should start sooner rather than + later), but we do need a solution that can be widely supported by the + current list services. + + We can support most existing list manager command syntaxes without a + standard command language. By using URLs, we allow alternate access + methods a standard command language probably wouldn't enable, such as + web based control. + + Finally, client support for a standard command language is not at all + clear or necessarily simple to implement. The variety and large + number of commands existing today would require complicated user + interfaces which could be confusing and difficult to implement. By + restricting this proposal to the core functions, the client + + implementation is much simpler, which significantly increases the + likelihood of implementation (as evidenced by the support already + announced by a number of client and server application authors). + +A.4. Internationalization + + Multilingual support is up to the URL standard. If URLs support it, + then the List- header fields support it. This is another advantage of + using URLs as the building blocks for the list header fields. + + + + +Neufeld & Baer Standards Track [Page 9] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +A.5. Variable Substitution + + Variables would allow the List- header fields to accommodate nearly + every existing list manager. However, it would immeasurably increase + the complexity of the entire proposal, and possibly involve + redefining the URL standard, or force us to use something more + complicated (and hence more difficult to implement) than URLs to + describe the command syntax. + + Parameters would either have to be mandatory (i.e. the user agent + doesn't submit the message if it doesn't know what text to + substitute) or you need a way to say "if you know this parameter, add + its text here; otherwise, do this" where "this" is either: (a) + substitute a constant string, or (b) fail. + + The reason you would want a facility like this is because some list + server applications insist on having certain parameters like users' + names, which the user agent might or might not know. e.g. listserv + insists on having a first name and a last name if you supply either + one. + + Which could lead to something like the UNIX shell syntax, where + ${foo-bar} means substitute the value of parameter "foo" if "foo" is + defined, else substitute the string "bar". Perhaps $foo would mean + "substitute the value of parameter foo if it is defined, else + substitute the empty string" + + This all seems far too complicated for the gains involved, especially + since the use of variables can often be avoided. + + The use of variables in the command syntaxes of list services appears + to be lessening and does not, in any case, apply to all commands. + While the unsubscribe and subscribe command header fields may not be + usable by those systems which require the use of variables, the help + field will still provide end users with a consistent point of access + through which they can get support for their use of the list. + +A.6. Why not use a specialized MIME part instead of header fields? + + MIME parts were considered, but because most mail clients currently + either don't support MIME or are not equipped to handle such + specialized parts - such an implementation would result in problems + for end users. It is also not as easy for many list servers to + implement MIME as it is to implement new header fields. + + However, we are looking at the design of a MIME part to more fully + describe list command syntax, as well as trying to find ways to get + it supported by the applicable software. + + + +Neufeld & Baer Standards Track [Page 10] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +A.7. Why include a Subscribe command? + + Subscribe and Unsubscribe are the key commands needed by almost every + list. Other commands, such as digest mode, are not as widely + supported. + + Additionally, users who have unsubscribed (before going on vacation, + or for whatever other reason) may want to resubscribe to a list. Or, + a message may be forwarded/bounced from a subscriber to a non- + subscriber. Or, the user may change addresses and want to subscribe + from their new address. Having the List-Subscribe field available + could certainly help in all these cases. + +A.8. The Dangers of Header Bloat + + At what point are there just too many header fields? It really + varies on a list by list basis. On some lists, the majority of users + will never be aware of a field unless the client software provides + some alternative user interface to it (akin to the Reply-To field). + On others, the users will often see the header fields of messages and + would be able to recognize the function of the URLs contained within. + + The flexibility afforded by the protocol described in this document + (in that the header fields may be individually implemented as deemed + appropriate) provides list administrators with sufficient 'room to + maneuver' to meet their individual needs. + + + + + + + + + + + + + + + + + + + + + + + + + +Neufeld & Baer Standards Track [Page 11] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +B. Client Implementation + +B.1. Guidelines + + For 'mailto' URL based commands, mail client applications may choose + to provide specialized feedback (such as presenting a dialog or + alert), instead of the actual command email message, asking for + command confirmation from the user. The feedback should identify the + message destination and command within a more descriptive + explanation. For example: + + "Do you want to send the unsubscription command 'unsubscribe + somelist' to 'somelist-request@some.host.com'? Sending the command + will result in your removal from the associated list." + + If the user has multiple email addresses supported by the mail + client, the client application should prompt the user for which + address to use when subscribing or performing some other action where + the address to use cannot be specifically determined. When + unsubscribing or such, the address that is subscribed should be used, + unless that is not known by the application and cannot be determined + from the message headers. + +B.2. Implementation Options + + The following implementation possibilities are suggested here to give + some idea as to why these new header fields will be useful, and how + they could be supported. + + In most cases, it may be helpful to disable the interface for the + commands when not applicable to the currently selected message. + +B.2.1. Key combinations and command lines + + On text based systems which utilize command lines or key + combinations, each field could be implemented as a separate command. + Thus one combination would subscribe the user, another would + unsubscribe, a third request help, etc. The commands would only be + available on messages containing the list header fields. + +B.2.2. Menu items + + On graphical systems which have menus, these commands could take the + form of a menu or sub-menu of items. For example, a "Lists" menu + might appear when viewing messages containing the header fields, with + items named "Subscribe", "Unsubscribe", "Get Help", "Post Message to + + + + + +Neufeld & Baer Standards Track [Page 12] + +RFC 2369 URLs as Meta-Syntax July 1998 + + + List", "Contact List Owner" and "Access List Archive". This menu + could be disabled when not applicable to the current message or + disappear entirely. + +B.2.3. Push Buttons and Pallettes + + On graphical window systems, buttons could be placed in the window of + the message, a toolbar, or in a floating pallette of their own. Each + button could correspond to a command, with names "Subscribe", + "Unsubscribe", "Get Help", "Post to List", "List Owner" and + "Archive". These buttons or pallettes could be disabled when not + applicable to the current message or disappear entirely. + +B.2.4 Feedback to the User + + If using a dialog interface (or other feedback element) the client + application MUST include an option for the user to review (and + possibly modify) the message before it is sent. The application may + also find it useful to provide a link to more detailed context- + sensitive assistance about mail list access in general. + +References + + [RFC822] Crocker, D., "Standard for the Format of ARPA + Internet Text Messages", STD 11, RFC 822, August 1982. + + [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, + "Uniform Resource Locators (URL)" RFC 1738, December 1994. + + [RFC2142] Crocker, D., "Mailbox Names for Common Services, Roles and + Functions", RFC 2142, May 1997. + + [RFC2368] Hoffman, P., Masinter, L., and J. Zawinski, "The mailto URL + scheme", RFC 2368, July 1998. + + [5] "List-Header" Mail list. list-header@list.nisto.com + + + + [6] "ListMom-Talk" Mail list. listmom-talk@skyweyr.com + + + + + + + + + + + +Neufeld & Baer Standards Track [Page 13] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +Editors' Addresses + + Joshua D. Baer + Box 273 + 4902 Forbes Avenue + Pittsburgh, PA 15213-3799 + USA + + EMail: josh@skyweyr.com + + + Grant Neufeld + Calgary, Alberta + Canada + + EMail: grant@acm.org + Web: http://www.nisto.com/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Neufeld & Baer Standards Track [Page 14] + +RFC 2369 URLs as Meta-Syntax July 1998 + + +Full Copyright Statement + + Copyright (C) The Internet Society (1998). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + + + + + + + + + + + + + + + + + + + + + + + +Neufeld & Baer Standards Track [Page 15] + diff --git a/rfc/rfc5451.txt b/rfc/rfc5451.txt new file mode 100644 index 0000000000..6dcaa5b9ac --- /dev/null +++ b/rfc/rfc5451.txt @@ -0,0 +1,2411 @@ + + + + + + +Network Working Group M. Kucherawy +Request for Comments: 5451 Sendmail, Inc. +Category: Standards Track April 2009 + + + Message Header Field for Indicating Message Authentication Status + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (c) 2009 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents in effect on the date of + publication of this document (http://trustee.ietf.org/license-info). + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. + +Abstract + + This memo defines a new header field for use with electronic mail + messages to indicate the results of message authentication efforts. + Any receiver-side software, such as mail filters or Mail User Agents + (MUAs), may use this message header field to relay that information + in a convenient way to users or to make sorting and filtering + decisions. + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 1] + +RFC 5451 Authentication-Results Header Field April 2009 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1. Purpose . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.2. Trust Boundary . . . . . . . . . . . . . . . . . . . . . . 4 + 1.3. Processing Scope . . . . . . . . . . . . . . . . . . . . . 5 + 1.4. Requirements . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.5. Definitions . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.5.1. General . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.5.2. Security . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.5.3. Email Architecture . . . . . . . . . . . . . . . . . . 6 + 1.6. Trust Environment . . . . . . . . . . . . . . . . . . . . 7 + 2. Definition and Format of the Header Field . . . . . . . . . . 8 + 2.1. General Description . . . . . . . . . . . . . . . . . . . 8 + 2.2. Formal Definition . . . . . . . . . . . . . . . . . . . . 8 + 2.3. Authentication Identifier Field . . . . . . . . . . . . . 10 + 2.4. Result Values . . . . . . . . . . . . . . . . . . . . . . 12 + 2.4.1. DKIM and DomainKeys Results . . . . . . . . . . . . . 12 + 2.4.2. SPF and Sender-ID Results . . . . . . . . . . . . . . 13 + 2.4.3. "iprev" Results . . . . . . . . . . . . . . . . . . . 14 + 2.4.4. SMTP AUTH Results . . . . . . . . . . . . . . . . . . 14 + 2.4.5. Extension Result Codes . . . . . . . . . . . . . . . . 15 + 2.5. Authentication Methods . . . . . . . . . . . . . . . . . . 15 + 2.5.1. Definition of Initial Methods . . . . . . . . . . . . 16 + 2.5.2. Extension Methods . . . . . . . . . . . . . . . . . . 16 + 3. The "iprev" Authentication Method . . . . . . . . . . . . . . 17 + 4. Adding the Header Field to A Message . . . . . . . . . . . . . 18 + 4.1. Header Field Position and Interpretation . . . . . . . . . 19 + 4.2. Local Policy Enforcement . . . . . . . . . . . . . . . . . 20 + 5. Removing the Header Field . . . . . . . . . . . . . . . . . . 20 + 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 22 + 6.1. The Authentication-Results Header Field . . . . . . . . . 22 + 6.2. Email Authentication Method Name Registry . . . . . . . . 22 + 6.3. Email Authentication Result Name Registry . . . . . . . . 24 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 26 + 7.1. Forged Header Fields . . . . . . . . . . . . . . . . . . . 26 + 7.2. Misleading Results . . . . . . . . . . . . . . . . . . . . 27 + 7.3. Header Field Position . . . . . . . . . . . . . . . . . . 28 + 7.4. Reverse IP Query Denial-of-Service Attacks . . . . . . . . 28 + 7.5. Mitigation of Backscatter . . . . . . . . . . . . . . . . 28 + 7.6. Internal MTA Lists . . . . . . . . . . . . . . . . . . . . 28 + 7.7. Attacks against Authentication Methods . . . . . . . . . . 28 + 7.8. Intentionally Malformed Header Fields . . . . . . . . . . 29 + 7.9. Compromised Internal Hosts . . . . . . . . . . . . . . . . 29 + 7.10. Encapsulated Instances . . . . . . . . . . . . . . . . . . 29 + 7.11. Reverse Mapping . . . . . . . . . . . . . . . . . . . . . 29 + + + + + +Kucherawy Standards Track [Page 2] + +RFC 5451 Authentication-Results Header Field April 2009 + + + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 30 + 8.1. Normative References . . . . . . . . . . . . . . . . . . . 30 + 8.2. Informative References . . . . . . . . . . . . . . . . . . 30 + Appendix A. Legacy MUAs . . . . . . . . . . . . . . . . . . . . . 32 + Appendix B. Authentication-Results Examples . . . . . . . . . . . 33 + B.1. Trivial Case; Header Field Not Present . . . . . . . . . . 33 + B.2. Nearly Trivial Case; Service Provided, But No + Authentication Done . . . . . . . . . . . . . . . . . . . 34 + B.3. Service Provided, Authentication Done . . . . . . . . . . 35 + B.4. Service Provided, Several Authentications Done, Single + MTA . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 + B.5. Service Provided, Several Authentications Done, + Different MTAs . . . . . . . . . . . . . . . . . . . . . . 37 + B.6. Service Provided, Multi-Tiered Authentication Done . . . . 39 + Appendix C. Operational Considerations about Message + Authentication . . . . . . . . . . . . . . . . . . . 41 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . 43 + +1. Introduction + + This memo defines a new header field for electronic mail messages + that presents the results of a message authentication effort in a + machine-readable format. The intent is to create a place to collect + such data when message authentication mechanisms are in use so that a + Mail User Agent (MUA) and downstream filters can make filtering + decisions and/or provide a recommendation to the user as to the + validity of the message's origin and possibly the integrity of its + content. + + End users are not expected to be direct consumers of this header + field. This header field is intended for consumption by programs + that will then use or render such data in a human-usable form. + + This memo defines both the format of this new header field and + discusses the implications of its presence or absence. However, it + does not discuss how the data contained in the header field should be + used (i.e. what filtering decisions are appropriate, or how an MUA + might render these results) as these are local policy and/or user + interface design questions that are not appropriate for this memo. + + At the time of publication of this memo, [AUTH], [DKIM], + [DOMAINKEYS], [SENDERID], and [SPF] are published DNS domain-level + email authentication methods in common use. This proposal is not + intended to be restricted to domain-based authentication, but this + has proven to be a good starting point for implementations. As + various methods emerge, it is necessary to prepare for their + appearance and encourage convergence in the area of interfacing + verifiers to filters and MUAs. + + + +Kucherawy Standards Track [Page 3] + +RFC 5451 Authentication-Results Header Field April 2009 + + + Although [SPF] defined a header field called Received-SPF and + [DOMAINKEYS] defined one called DomainKey-Status for this purpose, + those header fields are specific to the conveyance of their + respective results only and thus are insufficient to satisfy the + requirements enumerated below. + +1.1. Purpose + + The header field defined in this memo is expected to serve several + purposes: + + 1. Convey the results of various message authentication checks being + applied by upstream filters and Mail Transfer Agents (MTAs) to + MUAs and downstream filters within the same "trust domain", as + such agents may wish to render those results to end users or use + that data to apply more or less stringent content checks based on + authentication results; + + 2. Provide a common location within a message for this data; + + 3. Create an extensible framework for reporting new authentication + methods as they emerge. + + In particular, the mere presence of this header field should not be + construed as meaning that its data is valid, but rather that it is + asserting validity based on one or more authentication schemes + somewhere upstream. For an MUA or downstream filter to treat the + assertions as actually valid, there must be an assessment of the + trust relationship between such agents and the validating MTA. + +1.2. Trust Boundary + + This document makes several references to the "trust boundary" of an + administrative management domain (ADMD). Given the diversity among + existing mail environments, a precise definition of this term isn't + possible. + + Simply put, a transfer from the creator of the header field to the + consumer must occur within a context of trust that the creator's + information is correct. How this trust is obtained is outside the + scope of this document. It is entirely a local matter. + + Thus, this document defines a "trust boundary" as the delineation + between "external" and "internal" entities; "external" here includes + all hosts that do not deliberately provide some kind of messaging + service for the receiving ADMD's users, and "internal" includes those + hosts that do. By this definition, the hosts within a "trust + boundary" may lie entirely within a receiving ADMD's direct control, + + + +Kucherawy Standards Track [Page 4] + +RFC 5451 Authentication-Results Header Field April 2009 + + + or they can include hosts managed by another ADMD (such as an ISP or + commercial filtering service) but that also provide services for the + former. + +1.3. Processing Scope + + This proposal is intended to address the needs of authenticating + messages or properties of messages during their actual transport. It + is not meant to address the security of messages that might be + encapsulated within other messages, such as a message/rfc822 [MIME] + part within a message. + +1.4. Requirements + + This memo establishes no new requirements on existing protocols or + servers. + + In particular, this memo establishes no requirement on MTAs to reject + or filter arriving messages that do not pass authentication checks. + The data conveyed by the defined header field's contents are for the + information of MUAs and filters and should be used at their + discretion. + +1.5. Definitions + + This section defines various terms used throughout this document. + +1.5.1. General + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + +1.5.2. Security + + [SECURITY] discusses authentication and authorization and the + conflation of the two concepts. The use of those terms within the + context of recent message-security work has given rise to slightly + different definitions, and this document reflects those current + usages, as follows: + + o "Authorization" is the establishment of permission to use a + resource or represent an identity. In this context, authorization + indicates that a message from a particular ADMD arrived via a + route the ADMD has explicitly approved. + + + + + + +Kucherawy Standards Track [Page 5] + +RFC 5451 Authentication-Results Header Field April 2009 + + + o "Authentication" is the assertion of validity of a piece of data + about a message (such as the sender's identity) or the message in + its entirety. + + As examples: [SPF] and [SENDERID] are authorization mechanisms in + that they express a result that shows whether or not the ADMD that + apparently sent the message has explicitly authorized the connecting + [SMTP] client to relay messages on its behalf but do not actually + validate any property of the message itself. By contrast, [DKIM] is + agnostic as to the routing of a message but uses cryptographic + signatures to authenticate agents claiming responsibility for the + message (which implies authorization) and ensure it was not modified + in transit. Since the signatures are not tied to SMTP connections, + they can be added by either the ADMD of origin, intermediate ADMDs + (such as a mailing list server), or both. + + Rather than create a separate header field for each class of + solution, this proposal groups them both into a single header field. + +1.5.3. Email Architecture + + o A "border MTA" is an MTA that acts as a gateway between the + general Internet and the users within an organizational boundary. + (See also Section 1.2.) + + o A "delivery MTA" (or Mail Delivery Agent or MDA) is an MTA that + actually enacts delivery of a message to a user's inbox or other + final delivery. + + o An "intermediate MTA" is an MTA that handles messages after a + border MTA and before a delivery MTA. + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 6] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The following diagram illustrates the flow of mail among these + defined components: + + +-----+ +-----+ +------------+ + | MUA |-->| MSA |-->| Border MTA | + +-----+ +-----+ +------------+ + | + | + V + +----------+ + | Internet | + +----------+ + | + | + V + +-----+ +-----+ +------------------+ +------------+ + | MUA |<--| MDA |<--| Intermediate MTA |<--| Border MTA | + +-----+ +-----+ +------------------+ +------------+ + + Generally, it is assumed that the work of applying message + authentication schemes takes place at a border MTA or a delivery MTA. + This specification is written with that assumption in mind. However, + there are some sites at which the entire mail infrastructure consists + of a single host. In such cases, such terms as "border MTA" and + "delivery MTA" may well apply to the same machine or even the very + same agent. It is also possible that some message authentication + tests could take place on an intermediate MTA. Although this + document doesn't specifically describe such cases, they are not meant + to be excluded from this specification. + + See [EMAIL-ARCH] for further discussion on general email system + architecture, and Appendix C of this memo for discussion about the + common aspects of email authentication in current environments. + +1.6. Trust Environment + + This new header field permits one or more message validation + mechanisms to communicate its output to one or more separate + assessment mechanisms. These mechanisms operate within a unified + trust boundary that defines an Administrative Management Domain + (ADMD). An ADMD contains one or more entities that perform + validation and generate the header field, and one or more that + consume it for some type of assessment. The field contains no + integrity or validation mechanism of its own, so its presence must be + trusted implicitly. Hence, use of the header field depends upon + ensuring that mail entering the ADMD has instances of the header + field claiming to be valid within its boundaries removed, so that + occurrences of such header fields can be used safely by consumers. + + + +Kucherawy Standards Track [Page 7] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The "authserv-id" token defined in Section 2.2 can be used to label + an entire ADMD or a specific validation engine within an ADMD. + Although the labeling scheme is left as an operational choice, some + guidance for selecting a token is provided within this proposal. + +2. Definition and Format of the Header Field + + This section gives a general overview of the format of the header + field being defined, and then provides more formal specification. + +2.1. General Description + + The new header field being defined here is called "Authentication- + Results". It is a Structured Header Field as defined in [MAIL] and + thus all of the related definitions in that document apply. + + This new header field SHOULD be added at the top of the message as it + transits MTAs that do authentication checks so some idea of how far + away the checks were done can be inferred. It therefore should be + treated as a Trace Field as defined in [MAIL], and thus all of the + related definitions in that document apply. + + The value of the header field (after removing [MAIL] comments) + consists of an authentication identifier, an optional version, and + then a series of "method=result" statements indicating which + authentication method(s) were applied and their respective results, + and then, for each applied method, an optional "reason" string plus + optional "property=value" statements indicating which message + properties were evaluated to reach that conclusion. + + The header field MAY appear more than once in a single message, or + more than one result MAY be represented in a single header field, or + a combination of these MAY be applied. + +2.2. Formal Definition + + Formally, the header field is specified as follows using [ABNF]: + + authres-header = "Authentication-Results:" [CFWS] authserv-id + [ CFWS version ] + ( [CFWS] ";" [CFWS] "none" / 1*resinfo ) [CFWS] CRLF + ; the special case of "none" is used to indicate that no + ; message authentication is performed + + authserv-id = dot-atom + ; see below for a description of this element + + + + + +Kucherawy Standards Track [Page 8] + +RFC 5451 Authentication-Results Header Field April 2009 + + + version = 1*DIGIT [CFWS] + ; indicates which version of this specification is in use; + ; this specification is version "1"; the absence of a + ; version implies this version of the specification + + resinfo = [CFWS] ";" methodspec [ CFWS reasonspec ] + *( CFWS propspec ) + + methodspec = [CFWS] method [CFWS] "=" [CFWS] result + ; indicates which authentication method was evaluated + + reasonspec = "reason" [CFWS] "=" [CFWS] value + ; a free-form comment on the reason the given result + ; was returned + + propspec = ptype [CFWS] "." [CFWS] property [CFWS] "=" pvalue + ; an indication of which properties of the message + ; were evaluated by the authentication scheme being + ; applied to yield the reported result and would be + ; useful to reveal to end users as authenticated + + method = dot-atom [ [CFWS] "/" [CFWS] version ] + ; a method indicates which method's result is + ; represented by "result", and is one of the methods + ; explicitly defined as valid in this document + ; or is an extension method as defined below + + result = dot-atom + ; indicates the results of the attempt to authenticate + ; the message; see below for details + + ptype = "smtp" / "header" / "body" / "policy" + ; indicates whether the property being evaluated was + ; a parameter to an [SMTP] command, or was a value taken + ; from a message header field, or was some property of + ; the message body, or some other property evaluated by + ; the receiving MTA + + property = dot-atom + ; if "ptype" is "smtp", this indicates which [SMTP] + ; command provided the value that was evaluated by the + ; authentication scheme being applied; if "ptype" is + ; "header", this indicates from which header field the + ; value being evaluated was extracted; if "ptype" is + ; "body", this indicates the offset into the body at which + ; content of interest was detected; if "ptype" is "policy" + ; then this indicates the name of the policy that caused + ; this header field to be added (see below) + + + +Kucherawy Standards Track [Page 9] + +RFC 5451 Authentication-Results Header Field April 2009 + + + pvalue = [CFWS] ( value / [ [ local-part ] "@" ] domain-name ) + [CFWS] + ; the value extracted from the message property defined + ; by the "ptype.property" construction; if the value + ; identifies something intended to be an e-mail identity, + ; then it MUST use the right hand portion of this ABNF + ; definition + + The "local-part" is as defined in Section 3.4.1, and "dot-atom" is + defined in Section 3.2.3, of [MAIL]. + + The "value" is as defined in Section 5.1 of [MIME]. + + The "domain-name" is as defined in Section 3.5 of [DKIM]. + + The "dot-atom" used in a "result" above is further constrained by the + necessity of being enumerated in Section 2.4 or an amendment to it. + + See Section 2.3 for a description of the "authserv-id" element. + + The list of commands eligible for use with the "smtp" ptype can be + found in [SMTP] and subsequent amendments. + + "CFWS" is as defined in Section 3.2.2 of [MAIL]. + + The "propspec" may be omitted if, for example, the method was unable + to extract any properties to do its evaluation yet has a result to + report. + + The "ptype" and "property" values used by each authentication method + should be defined in the specification for that method (or its + amendments). + + The "ptype" and "property" are case-insensitive. + + A "ptype" value of "policy" indicates a policy decision about the + message not specific to a property of the message that could be + extracted. For example, if a method would normally report a + "ptype.property" of "header.From" and no From: header field was + present, the method can use "policy" to indicate that no conclusion + about the authenticity of the message could be reached. + +2.3. Authentication Identifier Field + + Every Authentication-Results header field has an authentication + identifier field ("authserv-id" above). This is similar in syntax to + a fully-qualified domain name. + + + + +Kucherawy Standards Track [Page 10] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The authentication identifier field provides a unique identifier that + refers to the authenticating service within a given ADMD. The + uniqueness of the identifier MUST be guaranteed by the ADMD that + generates it and must pertain to exactly that one ADMD. This + identifier is intended to be machine-readable and not necessarily + meaningful to users. MUAs or downstream filters SHOULD use this + identifier to determine whether or not the data contained in an + Authentication-Results header field should be used. + + For simplicity and scalability, the authentication identifier SHOULD + be a common token used throughout the ADMD, such as the DNS domain + name used by or within that ADMD. + + For tracing and debugging purposes, the authentication identifier MAY + instead be the hostname of the MTA performing the authentication + check whose result is being reported. This is also useful for + another purpose, as described in Section 4. Moreover, some + implementations have considered appending a delimiter such as "/" and + following it with useful transport tracing data such as the [SMTP] + queue ID or a timestamp. + + It should be noted, however, that using a local, relative identifier + like a single hostname, rather than a hierarchical and globally + unique ADMD identifier like a DNS domain name, makes configuration + more difficult for large sites. The hierarchical identifier permits + aggregating related, trusted systems together under a single, parent + identifier, which in turn permits assessing the trust relationship + with a single reference. The alternative is a flat namespace + requiring individually listing each trusted system. Since consumers + must use the identifier to determine whether to use the contents of + the header field: + + o Changes to the identifier impose a large, centralized + administrative burden. + + o Ongoing administrative changes require constantly updating this + centralized table, making it difficult to ensure that an MUA or + downstream filter will have access to accurate information for + assessing the usability of the header field's content. In + particular, consumers of the header field will need to know not + only the current identifier(s) in use, but previous ones as well + to account for delivery latency or later re-assessment of the + header field's contents. + + Examples of valid authentication identifiers are "example.com", + "mail.example.org", "ms1.newyork.example.com", and "example-auth". + + + + + +Kucherawy Standards Track [Page 11] + +RFC 5451 Authentication-Results Header Field April 2009 + + +2.4. Result Values + + Each individual authentication method returns one of a set of + specific result values. The subsections below define these results + for the authentication methods specifically supported by this memo, + and verifiers SHOULD use these values as described below. New + methods not specified in this document intended to be supported by + the header field defined in this memo MUST include a similar result + table either in its defining memo or in a supplementary one. + +2.4.1. DKIM and DomainKeys Results + + The result values used by [DKIM] and [DOMAINKEYS] are as follows: + + none: The message was not signed. + + pass: The message was signed, the signature or signatures were + acceptable to the verifier, and the signature(s) passed + verification tests. + + fail: The message was signed and the signature or signatures were + acceptable to the verifier, but they failed the verification + test(s). + + policy: The message was signed but the signature or signatures were + not acceptable to the verifier. + + neutral: The message was signed but the signature or signatures + contained syntax errors or were not otherwise able to be + processed. This result SHOULD also be used for other failures not + covered elsewhere in this list. + + temperror: The message could not be verified due to some error that + is likely transient in nature, such as a temporary inability to + retrieve a public key. A later attempt may produce a final + result. + + permerror: The message could not be verified due to some error that + is unrecoverable, such as a required header field being absent. A + later attempt is unlikely to produce a final result. + + A signature is "acceptable to the verifier" if it passes local policy + checks (or there are no specific local policy checks). For example, + a verifier might require that the signature(s) on the message be + added using the DNS domain present in the From: header field of the + message, thus making third-party signatures unacceptable. + + + + + +Kucherawy Standards Track [Page 12] + +RFC 5451 Authentication-Results Header Field April 2009 + + + [DKIM] advises that if a message fails verification, it should be + treated as an unsigned message. A report of "fail" here permits the + receiver of the report to decide how to handle the failure. A report + of "neutral" or "none" preempts that choice, ensuring the message + will be treated as if it had not been signed. + +2.4.2. SPF and Sender-ID Results + + The result values are used by [SPF] and [SENDERID] as follows: + + none: No policy records were published at the sender's DNS domain. + + neutral: The sender's ADMD has asserted that it cannot or does not + want to assert whether or not the sending IP address is authorized + to send mail using the sender's DNS domain. + + pass: The client is authorized by the sender's ADMD to inject or + relay mail on behalf of the sender's DNS domain. + + policy: The client is authorized to inject or relay mail on behalf + of the sender's DNS domain according to the authentication + method's algorithm, but local policy dictates that the result is + unacceptable. + + hardfail: This client is explicitly not authorized to inject or + relay mail using the sender's DNS domain. + + softfail: The sender's ADMD believes the client was not authorized + to inject or relay mail using the sender's DNS domain, but is + unwilling to make a strong assertion to that effect. + + temperror: The message could not be verified due to some error that + is likely transient in nature, such as a temporary inability to + retrieve a policy record from DNS. A later attempt may produce a + final result. + + permerror: The message could not be verified due to some error that + is unrecoverable, such as a required header field being absent or + a syntax error in a retrieved DNS TXT record. A later attempt is + unlikely to produce a final result. + + The distinction between and interpretation of "none" and "neutral" + under these methods is discussed further in [SPF]. + + The "policy" result would be returned if, for example, [SPF] returned + as "pass" result, but a local policy check matches the sending DNS + domain to one found in an explicit list of unacceptable DNS domains + (e.g., spammers). + + + +Kucherawy Standards Track [Page 13] + +RFC 5451 Authentication-Results Header Field April 2009 + + + If the retrieved sender policies used to evaluate [SPF] and + [SENDERID] do not contain explicit provisions for authenticating the + local-part (see Section 3.4.1 of [MAIL]) of an address, the "pvalue" + reported along with results for these mechanisms SHOULD NOT include + the local-part. + +2.4.3. "iprev" Results + + The result values are used by the "iprev" method, defined in + Section 3, are as follows: + + pass: The DNS evaluation succeeded, i.e., the "reverse" and + "forward" lookup results were returned and were in agreement. + + fail: The DNS evaluation failed. In particular, the "reverse" and + "forward" lookups each produced results but they were not in + agreement, or the "forward" query completed but produced no + result, e.g., a DNS RCODE of 3, commonly known as NXDOMAIN, or an + RCODE of 0 (NOERROR) in a reply containing no answers, was + returned. + + temperror: The DNS evaluation could not be completed due to some + error that is likely transient in nature, such as a temporary DNS + error, e.g., a DNS RCODE of 2, commonly known as SERVFAIL, or + other error condition resulted. A later attempt may produce a + final result. + + permerror: The DNS evaluation could not be completed because no PTR + data are published for the connecting IP address, e.g., a DNS + RCODE of 3, commonly known as NXDOMAIN, or an RCODE of 0 (NOERROR) + in a reply containing no answers, was returned. This prevented + completion of the evaluation. + + There is no "none" for this method since any TCP connection + delivering email has an IP address associated with it, so some kind + of evaluation will always be possible. + + For discussion of the format of DNS replies, see [DNS]. + +2.4.4. SMTP AUTH Results + + The result values are used by the [AUTH] method are as follows: + + none: SMTP authentication was not attempted. + + pass: The SMTP client had authenticated to the server reporting the + result using the protocol described in [AUTH]. + + + + +Kucherawy Standards Track [Page 14] + +RFC 5451 Authentication-Results Header Field April 2009 + + + fail: The SMTP client had attempted to authenticate to the server + using the protocol described in [AUTH] but was not successful, yet + continued to send the message about which a result is being + reported. + + temperror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error which is likely transient in nature, + such as a temporary Lightweight Directory Access Protocol (LDAP) + lookup error. A later attempt may produce a final result. + + permerror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error that is likely not transient in nature, + such as a permanent LDAP lookup error. A later attempt is not + likely produce a final result. + + Note that an agent making use of the data provided by this header + field SHOULD consider "fail" and "temperror" to be the synonymous in + terms of message authentication, i.e., the client did not + authenticate. + +2.4.5. Extension Result Codes + + Additional result codes (extension results) might be defined in the + future by later revisions or extensions to this specification. + Extension results beginning with "x-" will never be defined as + standard fields; such names are reserved for experimental use. + Result codes not beginning with "x-" MUST be registered with the + Internet Assigned Numbers Authority (IANA) and published in an RFC. + See Section 6 for further details. + + Implementations reporting new result codes MUST use the "x-" prefix + until such time as the new method is registered by IANA. + + Extension results MUST only be used within ADMDs that have explicitly + consented to use them. These results and the parameters associated + with them are not documented in RFCs. Therefore, they are subject to + change at any time and not suitable for production use. Any MTA, MUA + or downstream filter intended for production use SHOULD ignore or + delete any Authentication-Results header field that includes an + extension result. + +2.5. Authentication Methods + + This section defines the supported authentication methods and + discusses the proper means for applying experimental and other + extension methods. + + + +Kucherawy Standards Track [Page 15] + +RFC 5451 Authentication-Results Header Field April 2009 + + +2.5.1. Definition of Initial Methods + + As they are currently existing specifications for message + authentication, it is appropriate to define an authentication method + identifier for each of [AUTH], [DKIM], [DOMAINKEYS], [SENDERID], and + [SPF]. Therefore, the authentication method identifiers "auth", + "dkim", "domainkeys", "sender-id", and "spf", respectively are hereby + defined for MTAs applying those specifications for email message + authentication. + + Furthermore, method "iprev" is defined in Section 3. + + See Section 6 for details. + +2.5.2. Extension Methods + + Additional authentication method identifiers (extension methods) may + be defined in the future by later revisions or extensions to this + specification. Extension methods beginning with "x-" will never be + defined as standard fields; such names are reserved for experimental + use. Method identifiers not beginning with "x-" MUST be registered + with the Internet Assigned Numbers Authority (IANA) and published in + an RFC. See Section 6 for further details. + + Extension methods may be defined for the following reasons: + + 1. To allow additional information from new authentication systems + to be communicated to MUAs or downstream filters. The names of + such identifiers should reflect the name of the method being + defined, but should not be needlessly long. + + 2. To allow the creation of "sub-identifiers" that indicate + different levels of authentication and differentiate between + their relative strengths, e.g., "auth1-weak" and "auth1-strong". + + Implementations of new methods MUST use the "x-" prefix until such + time as the new method is registered by IANA. + + Authentication method implementors are encouraged to provide adequate + information, via [MAIL] comments if necessary, to allow an MUA + developer to understand or relay ancillary details of authentication + results. For example, if it might be of interest to relay what data + was used to perform an evaluation, such information could be relayed + as a comment in the header field, such as: + + Authentication-Results: example.com; + foo=pass bar.baz=blob (2 of 3 tests OK) + + + + +Kucherawy Standards Track [Page 16] + +RFC 5451 Authentication-Results Header Field April 2009 + + + Experimental method identifiers MUST only be used within ADMDs that + have explicitly consented to use them. These method identifiers and + the parameters associated with them are not documented in RFCs. + Therefore, they are subject to change at any time and not suitable + for production use. Any MTA, MUA, or downstream filter intended for + production use SHOULD ignore or delete any Authentication-Results + header field that includes an experimental method identifier. + +3. The "iprev" Authentication Method + + This section defines an additional authentication method called + "iprev". + + In general, "iprev" is an attempt to verify that a client appears to + be valid based on some DNS queries. Upon receiving a session + initiation of some kind from a client, the IP address of the client + peer is queried for matching names (i.e., a number-to-name + translation, also known as a "reverse lookup" or a "PTR" record + query). Once that result is acquired, a lookup of each of the names + (i.e., a name-to-number translation, or an "A" or "AAAA" record + query) thus retrieved is done. The response to this second check + should result in at least one mapping back to the client's IP + address. + + More algorithmically: if the client peer's IP address is I, the list + of names to which I maps (after a "PTR" query) is the set N, and the + union of IP addresses to which each member of N maps (after + corresponding "A" and "AAAA" queries) is L, then this test is + successful if I is an element of L. + + The response to a PTR query could contain multiple names. To prevent + heavy DNS loads, agents performing these queries MUST be implemented + such that the number of names evaluated by generation of + corresponding A or AAAA queries is finite, though it MAY be + configurable by an administrator. As an example, Section 5.5 of + [SPF] chose a limit of 10 for its implementation of this algorithm. + + [DNS-IP6] discusses the query formats for the IPv6 case. + + A successful test using this algorithm constitutes a result of "pass" + since the ADMD in which the client's PTR claims it belongs has + confirmed that claim by including corresponding data in its DNS + domain. A failure to match constitutes a "fail". There is no case + in which a "neutral" result can be returned. The remaining + "temperror" and "permerror" cases refer, respectively, to temporary + and permanent DNS query errors. + + + + + +Kucherawy Standards Track [Page 17] + +RFC 5451 Authentication-Results Header Field April 2009 + + + There is some contention regarding the wisdom and reliability of this + test. For example, in some regions it can be difficult for this test + ever to pass because the practice of arranging to match the forward + and reverse DNS is infrequently observed. Therefore, the actual + implementation details of how a verifier performs an "iprev" test are + not specified here. The verifier MAY report a successful or failed + "iprev" test at its discretion having done some kind of check of the + validity of the connection's identity using DNS. It is incumbent + upon an agent making use of the reported "iprev" result to understand + what exactly that particular verifier is attempting to report. + + Extensive discussion of reverse DNS mapping and its implications can + be found in [DNSOP-REVERSE]. In particular, it recommends that + applications avoid using this test as a means of authentication or + security. Its presence in this memo is not an endorsement, but is + merely acknowledgement that the method remains common and provides + the means to relay the results of that test. + +4. Adding the Header Field to A Message + + This specification makes no attempt to evaluate the relative + strengths of various message authentication methods that may become + available. As such, the order of the presented authentication + methods and results MUST NOT be used either to imply or infer the + importance or strength of any given method over another. Instead, + the MUA or downstream filter consuming this header field must + interpret the result of each method based on its own knowledge of + what that method evaluates. + + Each "method" MUST refer to an authentication method declared in the + IANA registry, or an extension method as defined in Section 2.5.2, + and each "result" MUST refer to a result code declared in the IANA + registry, or an extension result code as defined in Section 2.4.5. + See Section 6 for further information about the registered methods + and result codes. + + An MTA compliant with this specification MUST add this header field + (after performing one or more message authentication tests) to + indicate which MTA or ADMD performed the test, which test got applied + and what the result was. If an MTA applies more than one such test, + it MUST add this header field either once per test, or once + indicating all of the results. An MTA MUST NOT add a result to an + existing header field. + + An MTA MAY add this header field containing only the authentication + identifier portion to indicate explicitly that no message + authentication schemes were applied prior to delivery of this + message. + + + +Kucherawy Standards Track [Page 18] + +RFC 5451 Authentication-Results Header Field April 2009 + + + An MTA adding this header field must take steps to identify it as + legitimate to the MUAs or downstream filters that will ultimately + consume its content. One required process to do so is described in + Section 5. Further measures may be required in some environments. + Some possible solutions are enumerated in Section 7.1. This memo + does not mandate any specific solution to this issue as each + environment has its own facilities and limitations. + + For MTAs that add this header field, adding header fields in order + (at the top), per Section 3.6 of [MAIL], is particularly important. + Moreover, this header field SHOULD be inserted above any other trace + header fields such MTAs might prepend. This allows easy detection of + header fields that can be trusted. + + End users making direct use of this header field may inadvertently + trust information that has not been properly vetted. If, for + example, a basic [SPF] result were to be relayed that claims an + authenticated addr-spec, the local-part of that addr-spec has + actually not been authenticated. Thus, an MTA adding this header + field SHOULD NOT include any data that has not been authenticated by + the method(s) being applied. Moreover, MUAs SHOULD NOT render to + users such information if it is presented by a method known not to + authenticate it. + +4.1. Header Field Position and Interpretation + + In order to ensure non-ambiguous results and avoid the impact of + false header fields, MUAs and downstream filters SHOULD NOT interpret + this header field unless specifically instructed to do so by the user + or administrator. That is, this interpretation should not be "on by + default". Naturally then, users or administrators should not + activate such a feature unless they are certain the header field will + be added by the border MTA that accepts the mail that is ultimately + read by the MUA, and instances of the header field appearing to be + from within the ADMD but actually added by foreign MTAs will be + removed before delivery. + + Furthermore, MUAs and downstream filters SHOULD NOT interpret this + header field unless the authentication identifier it bears appears to + be one used within its own ADMD as configured by the user or + administrator. + + MUAs and downstream filters MUST ignore any result reported using a + "result" not specified in the result code registry, or a "ptype" not + listed in the corresponding registry for such values as defined in + Section 6. Moreover, such agents MUST ignore a result indicated for + any "method" they do not specifically support. + + + + +Kucherawy Standards Track [Page 19] + +RFC 5451 Authentication-Results Header Field April 2009 + + + An MUA SHOULD NOT reveal these results to end users unless the + results are accompanied by, at a minimum, some associated reputation + data about the authenticated origin identifiers within the message. + For example, an attacker could register examp1e.com (note the digit + "one") and send signed mail to intended victims; a verifier would + detect that the signature was valid and report a "pass" even though + it's clear the DNS domain name was intended to mislead. See + Section 7.2 for further discussion. + + As stated in Section 2.1, this header field SHOULD be treated as + though it were a trace header field as defined in Section 3.6.7 of + [MAIL], and hence MUST NOT be reordered and MUST be prepended to the + message, so that there is generally some indication upon delivery of + where in the chain of handling MTAs the message authentication was + done. + + MUAs SHOULD ignore instances of this header field discovered within + message/rfc822 [MIME] attachments. + + Further discussion of this can be found in Section 7 below. + +4.2. Local Policy Enforcement + + If a site's local policy is to consider a non-recoverable failure + result (e.g., "fail" for DKIM, "hardfail" for SPF) for any particular + authentication method as justification to reject the message + completely, the border MTA SHOULD issue an [SMTP] rejection response + to the message rather than adding this header field with the failure + result and allowing it to proceed toward delivery. This is more + desirable than allowing the message to reach an internal host's MTA + or spam filter, thus possibly generating a local rejection such as a + [DSN] to a forged originator. + + The same MAY also be done for local policy decisions overriding the + results of the authentication methods (e.g., the "policy" result + codes described in Section 2.4). + + Such rejections at the SMTP protocol level are not possible if local + policy is enforced at the MUA and not the MTA. Unfortunately, this + may be a common scenario. + +5. Removing the Header Field + + For security reasons, any MTA conforming to this specification MUST + delete any discovered instance of this header field that claims to + have been added within its trust boundary and that did not come from + another trusted MTA. For example, an MTA (border or otherwise) for + example.com receiving a message MUST delete any instance of this + + + +Kucherawy Standards Track [Page 20] + +RFC 5451 Authentication-Results Header Field April 2009 + + + header field bearing an authentication identifier indicating the + header field was added within example.com prior to adding its own + header fields. This may mean each MTA will have to be equipped with + a list of internal MTAs known to be compliant (and hence + trustworthy). + + For simplicity and maximum security, a border MTA MAY remove all + instances of this header field on mail crossing into its trust + boundary. However, this may conflict with the desire to access + authentication results performed by trusted external service + providers. It may also invalidate signed messages whose signatures + cover external instances of this header field. A more robust border + MTA could allow a specific list of authenticating MTAs whose + information should be let in, removing all others. + + As stated in Section 1.2, a formal definition of "trust boundary" is + deliberately not made here. It is entirely possible that a border + MTA for example.com might explicitly trust authentication results + asserted by upstream host example.net even though they exist in + completely disjoint administrative boundaries. In that case, the + border MTA MAY elect not to delete those results; moreover, the + upstream host doing some authentication work could apply a signing + technology such as [DKIM] on its own results to assure downstream + hosts of their authenticity. An example of this is provided in + Appendix B. + + Similarly, in the case of messages signed using [DKIM] or other + message signing methods that sign header fields, this may invalidate + one or more signatures on the message if they covered the header + field to be removed at the time of signing. This behavior can be + desirable since there's little value in validating the signature on a + message with forged headers. However, signing agents MAY therefore + elect to omit these header fields from signing to avoid this + situation. + + An MTA SHOULD remove any instance of this header field bearing a + version (express or implied) that it does not support. However, an + MTA MUST remove such a header if the [SMTP] connection relaying the + message is not from a trusted internal MTA. + + + + + + + + + + + + +Kucherawy Standards Track [Page 21] + +RFC 5451 Authentication-Results Header Field April 2009 + + +6. IANA Considerations + + IANA has registered a new header field and created two new tables as + described below. + +6.1. The Authentication-Results Header Field + + Per [IANA-HEADERS], the "Authentication-Results" header field has + been added to the IANA Permanent Message Header Field Registry. The + following is the registration template: + + Header field name: Authentication-Results + Applicable protocol: mail ([MAIL]) + Status: Standard + Author/Change controller: IETF + Specification document(s): RFC 5451 + Related information: + Requesting review of any proposed changes and additions to + this field is recommended. + +6.2. Email Authentication Method Name Registry + + Names of message authentication methods supported by this + specification must be registered with IANA, with the exception of + experimental names as described in Section 2.5.2. + + New entries are assigned only for values that have been documented in + a published RFC that has had IETF Review, per [IANA-CONSIDERATIONS]. + Each method must register a name, the specification that defines it, + one or more "ptype" values appropriate for use with that method, + which "property" value(s) should be reported by that method, and a + description of the "value" to be used with each. + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 22] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The initial set of entries in this registry is as follows: + ++------------+----------+--------+----------------+--------------------+ +| Method | Defined | ptype | property | value | ++------------+----------+--------+----------------+--------------------+ +| auth | RFC4954 | smtp | auth | AUTH parameter of | +| | | | | the SMTP MAIL | +| | | | | command | ++------------+----------+--------+----------------+--------------------+ +| dkim | RFC4871 | header | d | value of | +| | | | | signature "d" tag | +| | | +----------------+--------------------+ +| | | | i | value of | +| | | | | signature "i" tag | ++------------+----------+--------+----------------+--------------------+ +| domainkeys | RFC4870 | header | d | value of | +| | | | | signature "d" tag | +| | | +----------------+--------------------+ +| | | | from | value of From | +| | | | | header field after | +| | | | | removing comments | +| | | | | and local-part if | +| | | | | not authenticated | +| | | +----------------+--------------------+ +| | | | sender | value of Sender | +| | | | | header field after | +| | | | | removing comments | +| | | | | and local-part if | +| | | | | not authenticated | ++------------+----------+--------+----------------+--------------------+ +| iprev | this | policy | iprev | client IP address | +| | document | | | | ++------------+----------+--------+----------------+--------------------+ +| sender-id | RFC4406 | header | name of header | value of header | +| | | | field used by | field used by PRA | +| | | | the Purported | after removing | +| | | | Responsible | comments and parts | +| | | | Address (PRA) | not authenticated | ++------------+----------+--------+----------------+--------------------+ +| spf | RFC4408 | smtp | mailfrom | envelope sender | +| | | | | after removing | +| | | | | parts not | +| | | | | authenticated | +| | +--------+----------------+--------------------+ +| | | smtp | helo | HELO/EHLO value | ++------------+----------+--------+----------------+--------------------+ + + + + + +Kucherawy Standards Track [Page 23] + +RFC 5451 Authentication-Results Header Field April 2009 + + +6.3. Email Authentication Result Name Registry + + Names of message authentication result codes supported by this + specification must be registered with IANA, with the exception of + experimental codes as described in Section 2.4.5. + + New entries are assigned only for result codes that have been + documented in a published RFC that has had IETF Review, per + [IANA-CONSIDERATIONS]. Each code must register a name, the document + that establishes the registration, the authentication method(s) that + uses it, and either a definition of the semantics of its use or a + reference to the place where those semantics are defined. + + The initial set of entries in this registry is as follows: + ++-----------+----------+----------------+------------------------------+ +| Code | Defined | Auth Method(s) | Meaning | ++-----------+----------+----------------+------------------------------+ +| none | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | +| | +----------------+------------------------------+ +| | | auth | section 2.4.4 | ++-----------+----------+----------------+------------------------------+ +| pass | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | +| | +----------------+------------------------------+ +| | | iprev | section 2.4.3 | +| | +----------------+------------------------------+ +| | | auth | section 2.4.4 | ++-----------+----------+----------------+------------------------------+ +| fail | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | iprev | section 2.4.3 | +| | +----------------+------------------------------+ +| | | auth | section 2.4.4 | ++-----------+----------+----------------+------------------------------+ + + + + + + + + +Kucherawy Standards Track [Page 24] + +RFC 5451 Authentication-Results Header Field April 2009 + + +| policy | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | ++-----------+----------+----------------+------------------------------+ +| neutral | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | ++-----------+----------+----------------+------------------------------+ +| temperror | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | +| | +----------------+------------------------------+ +| | | iprev | section 2.4.3 | +| | +----------------+------------------------------+ +| | | auth | section 2.4.4 | ++-----------+----------+----------------+------------------------------+ +| permerror | this | dkim | section 2.4.1 | +| | document | domainkeys | | +| | +----------------+------------------------------+ +| | | spf | section 2.4.2 | +| | | sender-id | | +| | +----------------+------------------------------+ +| | | iprev | section 2.4.3 | +| | +----------------+------------------------------+ +| | | auth | section 2.4.4 | ++-----------+----------+----------------+------------------------------+ +| hardfail | this | spf | section 2.4.2 | +| | document | sender-id | | ++-----------+----------+----------------+------------------------------+ +| softfail | this | spf | section 2.4.2 | +| | document | sender-id | | ++-----------+----------+----------------+------------------------------+ + + + + + + + + + + + + + +Kucherawy Standards Track [Page 25] + +RFC 5451 Authentication-Results Header Field April 2009 + + +7. Security Considerations + + The following security considerations apply when adding or processing + the "Authentication-Results" header field: + +7.1. Forged Header Fields + + An MUA or filter that accesses a mailbox whose mail is handled by a + non-conformant MTA, and understands Authentication-Results header + fields, could potentially make false conclusions based on forged + header fields. A malicious user or agent could forge a header field + using the DNS domain of a receiving ADMD as the authserv-id token in + the value of the header field, and with the rest of the value claim + that the message was properly authenticated. The non-conformant MTA + would fail to strip the forged header field, and the MUA could + inappropriately trust it. + + It is for this reason an MUA should not have processing of the + "Authentication-Results" header field enabled by default; instead it + should be ignored, at least for the purposes of enacting filtering + decisions, unless specifically enabled by the user or administrator + after verifying that the border MTA is compliant. It is acceptable + to have an MUA aware of this specification, but have an explicit list + of hostnames whose "Authentication-Results" header fields are + trustworthy; however, this list should initially be empty. + + Proposed alternate solutions to this problem are nascent: + + 1. Possibly the simplest is a digital signature protecting the + header field, such as using [DKIM], that can be verified by an + MUA by using a posted public key. Although one of the main + purposes of this memo is to relieve the burden of doing message + authentication work at the MUA, this only requires that the MUA + learn a single authentication scheme even if a number of them are + in use at the border MTA. Note that [DKIM] requires that the + From header field be signed, although in this application, the + signing agent (a trusted MTA) likely cannot authenticate that + value, so the fact that it is signed should be ignored. + + 2. Another would be a means to interrogate the MTA that added the + header field to see if it is actually providing any message + authentication services and saw the message in question, but this + isn't especially palatable given the work required to craft and + implement such a scheme. + + 3. Yet another might be a method to interrogate the internal MTAs + that apparently handled the message (based on Received: header + + + + +Kucherawy Standards Track [Page 26] + +RFC 5451 Authentication-Results Header Field April 2009 + + + fields) to determine whether any of them conform to Section 5 of + this memo. This, too, has potentially high barriers-to-entry. + + 4. Extensions to [IMAP], [SMTP], and [POP3] could be defined to + allow an MUA or filtering agent to acquire the "authserv-id" in + use within an ADMD, thus allowing it to identify which + Authentication-Results header fields it can trust. + + 5. On the presumption that internal MTAs are fully compliant with + Section 3.6 of [MAIL], and the compliant internal MTAs are using + their own host names or the ADMD's DNS domain name as the + "authserv-id" token, the header field proposed here should always + appear above a Received: header added by a trusted MTA. This can + be used as a test for header field validity. + + Support for some of these is planned for future work. + + In any case, a mechanism needs to exist for an MUA or filter to + verify that the host that appears to have added the header field (a) + actually did so, and (b) is legitimately adding that header field for + this delivery. Given the variety of messaging environments deployed + today, consensus appears to be that specifying a particular mechanism + for doing so is not appropriate for this memo. + + Mitigation of the forged header field attack can also be accomplished + by moving the authentication results data into meta-data associated + with the message. In particular, an [SMTP] extension could be + established which is used to communicate authentication results from + the border MTA to intermediate and delivery MTAs; the latter of these + could arrange to store the authentication results as meta-data + retrieved and rendered along with the message by an [IMAP] client + aware of a similar extension in that protocol. The delivery MTA + would be told to trust data via this extension only from MTAs it + trusts, and border MTAs would not accept data via this extension from + any source. There is no vector in such an arrangement for forgery of + authentication data by an outside agent. + +7.2. Misleading Results + + Until some form of service for querying the reputation of a sending + agent is widely deployed, the existence of this header field + indicating a "pass" does not render the message trustworthy. It is + possible for an arriving piece of spam or other undesirable mail to + pass checks by several of the methods enumerated above (e.g., a piece + of spam signed using [DKIM] by the originator of the spam, which + might be a spammer or a compromised system). In particular, this + issue is not resolved by forged header field removal discussed above. + + + + +Kucherawy Standards Track [Page 27] + +RFC 5451 Authentication-Results Header Field April 2009 + + + Hence, MUAs and downstream filters must take some care with use of + this header even after possibly malicious headers are scrubbed. + +7.3. Header Field Position + + Despite the requirements of [MAIL], header fields can sometimes be + reordered enroute by intermediate MTAs. The goal of requiring header + field addition only at the top of a message is an acknowledgement + that some MTAs do reorder header fields, but most do not. Thus, in + the general case, there will be some indication of which MTAs (if + any) handled the message after the addition of the header field + defined here. + +7.4. Reverse IP Query Denial-of-Service Attacks + + Section 5.5 of [SPF] describes a DNS-based denial-of-service attack + for verifiers that attempt DNS-based identity verification of + arriving client connections. A verifier wishing to do this check and + report this information SHOULD take care not to go to unbounded + lengths to resolve "A" and "PTR" queries. MUAs or other filters + making use of an "iprev" result specified by this memo SHOULD be + aware of the algorithm used by the verifier reporting the result and + thus be aware of its limitations. + +7.5. Mitigation of Backscatter + + Failing to follow the instructions of Section 4.2 can result in a + denial-of-service attack caused by the generation of [DSN] messages + (or equivalent) to addresses that did not send the messages being + rejected. + +7.6. Internal MTA Lists + + Section 5 describes a procedure for scrubbing headers that may + contain forged authentication results about a message. A compliant + installation will have to include, at each MTA, a list of other MTAs + known to be compliant and trustworthy. Failing to keep this list + current as internal infrastructure changes may expose an ADMD to + attack. + +7.7. Attacks against Authentication Methods + + If an attack becomes known against an authentication method, clearly + then the agent verifying that method can be fooled into thinking an + inauthentic message is authentic, and thus the value of this header + field can be misleading. It follows that any attack against the + authentication methods supported by this document (and later + amendments to it) is also a security consideration here. + + + +Kucherawy Standards Track [Page 28] + +RFC 5451 Authentication-Results Header Field April 2009 + + +7.8. Intentionally Malformed Header Fields + + It is possible for an attacker to add an Authentication-Results + header field that is extraordinarily large or otherwise malformed in + an attempt to discover or exploit weaknesses in header field parsing + code. Implementors must thoroughly verify all such header fields + received from MTAs and be robust against intentionally as well as + unintentionally malformed header fields. + +7.9. Compromised Internal Hosts + + An internal MUA or MTA that has been compromised could generate mail + with a forged From header field and a forged Authentication-Results + header field that endorses it. Although it is clearly a larger + concern to have compromised internal machines than it is to prove the + value of this header field, this risk can be mitigated by arranging + that internal MTAs will remove this header field if it claims to have + been added by a trusted border MTA (as described above), yet the + [SMTP] connection is not coming from an internal machine known to be + running an authorized MTA. However, in such a configuration, + legitimate MTAs will have to add this header field when legitimate + internal-only messages are generated. This is also covered in + Section 5. + +7.10. Encapsulated Instances + + [MIME] messages may contain attachments of type "message/rfc822", + which contain other [MAIL] messages. Such an encapsulated message + may also contain an Authentication-Results header field. Although + the processing of these is outside of the intended scope of this + document (see Section 1.3), some early guidance to MUA developers is + appropriate here. + + Since MTAs are unlikely to strip Authentication-Results header fields + after mailbox delivery, MUAs are advised in Section 4.1 to ignore + such instances within [MIME] attachments. Moreover, when extracting + a message digest to separate mail store messages or other media, such + header fields should be removed so that they will never be + interpreted improperly by MUAs that might later consume them. + +7.11. Reverse Mapping + + Although Section 3 of this memo includes explicit support for the + "iprev" method, its value as an authentication mechanism is limited. + Implementors of both this proposal and agents that use the data it + relays are encouraged to become familiar with the issues raised by + [DNSOP-REVERSE] when deciding whether or not to include support for + "iprev". + + + +Kucherawy Standards Track [Page 29] + +RFC 5451 Authentication-Results Header Field April 2009 + + +8. References + +8.1. Normative References + + [ABNF] Crocker, D. and P. Overell, "Augmented BNF for + Syntax Specifications: ABNF", STD 68, + RFC 5234, January 2008. + + [IANA-HEADERS] Klyne, G., Nottingham, M., and J. Mogul, + "Registration Procedures for Message Header + Fields", BCP 90, RFC 3864, September 2004. + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to + Indicate Requirement Levels", BCP 14, + RFC 2119, March 1997. + + [MAIL] Resnick, P., Ed., "Internet Message Format", + RFC 5322, October 2008. + + [MIME] Freed, N. and N. Borenstein, "Multipurpose + Internet Mail Extensions (MIME) Part One: + Format of Internet Message Bodies", RFC 2045, + November 1996. + +8.2. Informative References + + [AUTH] Siemborski, R. and A. Melnikov, "SMTP Service + Extension for Authentication", RFC 4954, + July 2007. + + [DKIM] Allman, E., Callas, J., Delany, M., Libbey, + M., Fenton, J., and M. Thomas, "DomainKeys + Identified Mail (DKIM) Signatures", RFC 4871, + May 2007. + + [DNS] Mockapetris, P., "Domain names - + implementation and specification", STD 13, + RFC 1035, November 1987. + + [DNS-IP6] Thomson, S., Huitema, C., Ksinant, V., and M. + Souissi, "DNS Extensions to Support IP Version + 6", RFC 3596, October 2003. + + [DNSOP-REVERSE] Senie, D. and A. Sullivan, "Considerations for + the use of DNS Reverse Mapping", Work + in Progress, March 2008. + + + + + +Kucherawy Standards Track [Page 30] + +RFC 5451 Authentication-Results Header Field April 2009 + + + [DOMAINKEYS] Delany, M., "Domain-Based Email Authentication + Using Public Keys Advertised in the DNS + (DomainKeys)", RFC 4870, May 2007. + + [DSN] Moore, K. and G. Vaudreuil, "An Extensible + Message Format for Delivery Status + Notifications", RFC 3464, January 2003. + + [EMAIL-ARCH] Crocker, D., "Internet Mail Architecture", + Work in Progress, October 2008. + + [IANA-CONSIDERATIONS] Narten, T. and H. Alvestrand, "Guidelines for + Writing an IANA Considerations Section in + RFCs", BCP 26, RFC 5226, May 2008. + + [IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL + - VERSION 4rev1", RFC 3501, March 2003. + + [POP3] Myers, J. and M. Rose, "Post Office Protocol - + Version 3", STD 53, RFC 1939, May 1996. + + [SECURITY] Rescorla, E. and B. Korver, "Guidelines for + Writing RFC Text on Security Considerations", + BCP 72, RFC 3552, July 2003. + + [SENDERID] Lyon, J. and M. Wong, "Sender ID: + Authenticating E-Mail", RFC 4406, April 2006. + + [SMTP] Klensin, J., "Simple Mail Transfer Protocol", + RFC 5321, October 2008. + + [SPF] Wong, M. and W. Schlitt, "Sender Policy + Framework (SPF) for Authorizing Use of Domains + in E-Mail, Version 1", RFC 4408, April 2006. + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 31] + +RFC 5451 Authentication-Results Header Field April 2009 + + +Appendix A. Legacy MUAs + + Implementors of this proposal should be aware that many MUAs are + unlikely to be retrofitted to support the new header field and its + semantics. In the interests of convenience and quicker adoption, a + delivery MTA might want to consider adding things that are processed + by existing MUAs in addition to the Authentication-Results header + field. One suggestion is to include a Priority header field, on + messages that don't already have such a header field, containing a + value that reflects the strength of the authentication that was + accomplished, e.g., "low" for weak or no authentication, "normal" or + "high" for good or strong authentication. + + Some modern MUAs can already filter based on the content of this + header field. However, there is keen interest in having MUAs make + some kind of graphical representation of this header field's meaning + to end users. Until this capability is added, other interim means of + conveying authentication results may be necessary while this proposal + and its successors are adopted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 32] + +RFC 5451 Authentication-Results Header Field April 2009 + + +Appendix B. Authentication-Results Examples + + This section presents some examples of the use of this header field + to indicate authentication results. + +B.1. Trivial Case; Header Field Not Present + + The trivial case: + + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 1: Trivial case + + The "Authentication-Results" header field is completely absent. The + MUA may make no conclusion about the validity of the message. This + could be the case because the message authentication services were + not available at the time of delivery, or no service is provided, or + the MTA is not in compliance with this specification. + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 33] + +RFC 5451 Authentication-Results Header Field April 2009 + + +B.2. Nearly Trivial Case; Service Provided, But No Authentication Done + + A message that was delivered by an MTA that conforms to this + specification but provides no actual message authentication service: + + Authentication-Results: example.org; none + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 2: Header present but no authentication done + + The "Authentication-Results" header field is present, showing that + the delivering MTA conforms to this specification. It used its DNS + domain name as the authserv-id. The presence of "none" (and the + absence of any method and result tokens) indicates that no message + authentication was done. + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 34] + +RFC 5451 Authentication-Results Header Field April 2009 + + +B.3. Service Provided, Authentication Done + + A message that was delivered by an MTA that conforms to this + specification and applied some message authentication: + + Authentication-Results: example.com; + spf=pass smtp.mailfrom=example.net + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.net + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.net> + Subject: here's a sample + + Hello! Goodbye! + + Example 3: Header reporting results + + The "Authentication-Results" header field is present, indicating that + the border MTA conforms to this specification. The authserv-id is + once again the DNS domain name. Furthermore, the message was + authenticated by that MTA via the method specified in [SPF]. Note + that since that method cannot authenticate the local-part, it has + been omitted from the result's value. The MUA could extract and + relay this extra information if desired. + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 35] + +RFC 5451 Authentication-Results Header Field April 2009 + + +B.4. Service Provided, Several Authentications Done, Single MTA + + A message that was relayed inbound via a single MTA that conforms to + this specification and applied three different message authentication + checks: + + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.com; + spf=pass smtp.mailfrom=example.com + Authentication-Results: example.com; + sender-id=pass header.from=example.com + Received: from dialup-1-2-3-4.example.net (8.11.6/8.11.6) + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.net + From: sender@example.com + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 4: Headers reporting results from one MTA + + The "Authentication-Results" header field is present, indicating the + delivering MTA conforms to this specification. Once again, the + receiving DNS domain name is used as the authserv-id. Furthermore, + the sender authenticated herself/himself to the MTA via a method + specified in [AUTH], and both [SPF] and [SENDERID] checks were done + and passed. The MUA could extract and relay this extra information + if desired. + + Two "Authentication-Results" header fields are not required since the + same host did all of the checking. The authenticating agent could + have consolidated all the results into one header field. + + This example illustrates a scenario in which a remote user on a + dialup connection (example.net) sends mail to a border MTA + (example.com) using SMTP authentication to prove identity. The + dialup provider has been explicitly authorized to relay mail as + "example.com" resulting in passes by the SPF and SenderID checks. + + + + + + + + +Kucherawy Standards Track [Page 36] + +RFC 5451 Authentication-Results Header Field April 2009 + + +B.5. Service Provided, Several Authentications Done, Different MTAs + + A message that was relayed inbound by two different MTAs that conform + to this specification and applied multiple message authentication + checks: + + Authentication-Results: example.com; + sender-id=hardfail header.from=example.com; + dkim=pass (good signature) header.i=sender@example.com + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by auth-checker.example.com (8.11.6/8.11.6) + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.com; + spf=hardfail smtp.mailfrom=example.com + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; d=example.com; + i=sender@example.com; t=1188964191; c=simple/simple; + h=From:Date:To:Message-Id:Subject; + bh=sEuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m70; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 5: Headers reporting results from multiple MTAs + + The "Authentication-Results" header field is present, indicating + conformance to this specification. Once again, the authserv-id used + is the recipient's DNS domain name. The header field is present + twice because two different MTAs in the chain of delivery did + authentication tests. The first, "mail-router.example.com" reports + that [AUTH] and [SPF] were both used, and [AUTH] passed but [SPF] + failed. In the [AUTH] case, additional data is provided in the + comment field, which the MUA can choose to render if desired. + + + + + + +Kucherawy Standards Track [Page 37] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The second MTA, "auth-checker.example.com", reports that it did a + [SENDERID] test (which failed) and a [DKIM] test (which passed). + Again, additional data about one of the tests is provided as a + comment, which the MUA may choose to render. + + Since different hosts did the two sets of authentication checks, the + header fields cannot be consolidated in this example. + + This example illustrates more typical transmission of mail into + "example.com" from a user on a dialup connection "example.net". The + user appears to be legitimate as he/she had a valid password allowing + authentication at the border MTA using [AUTH]. The [SPF] and + [SENDERID] tests failed since "example.com" has not granted + "example.net" authority to relay mail on its behalf. However, the + [DKIM] test passed because the sending user had a private key + matching one of "example.com"'s published public keys and used it to + sign the message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 38] + +RFC 5451 Authentication-Results Header Field April 2009 + + +B.6. Service Provided, Multi-Tiered Authentication Done + + A message that had authentication done at various stages, one of + which was outside the receiving ADMD: + + Authentication-Results: example.com; + dkim=pass (good signature) header.i=@mail-router.example.net; + dkim=fail (bad signature) header.i=@newyork.example.com + Received: from mail-router.example.net + (mail-router.example.net [192.0.2.250]) + by chicago.example.com (8.11.6/8.11.6) + for + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=furble; + d=mail-router.example.net; t=1188964198; c=relaxed/simple; + h=From:Date:To:Message-Id:Subject:Authentication-Results; + bh=ftA9J6GtX8OpwUECzHnCkRzKw1uk6FNiLfJl5Nmv49E=; + b=oINEO8hgn/gnunsg ... 9n9ODSNFSDij3= + Authentication-Results: example.net; + dkim=pass (good signature) header.i=@newyork.example.com + Received: from smtp.newyork.example.com + (smtp.newyork.example.com [192.0.2.220]) + by mail-router.example.net (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; d=newyork.example.com; + t=1188964191; c=simple/simple; + h=From:Date:To:Message-Id:Subject; + bh=sEu28nfs9fuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m7=; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + From: sender@newyork.example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: meetings@example.net + Message-Id: <12345.abc@newyork.example.com> + Subject: here's a sample + + Example 6: Headers reporting results from multiple MTAs in different + ADMDs + + In this example we see multi-tiered authentication with an extended + trust boundary. + + The message was sent from someone at example.com's New York office + (newyork.example.com) to a mailing list managed at an intermediary. + The message was signed at the origin using [DKIM]. + + + + + +Kucherawy Standards Track [Page 39] + +RFC 5451 Authentication-Results Header Field April 2009 + + + The message was sent to a mailing list service provider called + example.net, which is used by example.com. There, + meetings@example.net is expanded to a long list of recipients, one of + that is at the Chicago office. In this example, we will assume that + the trust boundary for chicago.example.com includes the mailing list + server at example.net. + + The mailing list server there first authenticated the message and + affixed an Authentication-Results header field indicating such using + its DNS domain name for the authserv-id. It then altered the message + by affixing some footer text to the body, including some + administrivia such as unsubscription instructions. Finally, the + mailing list server affixes a second [DKIM] signature and begins + distribution of the message. + + The border MTA for chicago.example.com explicitly trusts results from + mail-router.example.net so that header field is not removed. It + performs evaluation of both signatures and determines that the first + (most recent) is a "pass" but, because of the aforementioned + modifications, the second is a "fail". However, the first signature + included the Authentication-Results header added at mail- + router.example.net that validated the second signature. Thus, + indirectly, it can be determined that the authentications claimed by + both signatures are indeed valid. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 40] + +RFC 5451 Authentication-Results Header Field April 2009 + + +Appendix C. Operational Considerations about Message Authentication + + This proposal is predicated on the idea that authentication (and + presumably in the future, reputation) work is typically done by + border MTAs rather than MUAs or intermediate MTAs; the latter merely + make use of the results determined by the former. Certainly this is + not mandatory for participation in electronic mail or message + authentication, but the work of this proposal and its deployment to + date is based on that model. The assumption satisfies several common + ADMD requirements: + + 1. Service operators prefer to resolve the handling of problem + messages as close to the border of the ADMD as possible. This + enables, for example, rejections of messages at the SMTP level + rather than generating a DSN internally. Thus, doing any of the + authentication or reputation work exclusively at the MUA or + intermediate MTA renders this desire unattainable. + + 2. Border MTAs are more likely to have direct access to external + sources of authentication or reputation information since modern + MUAs are more likely to be heavily firewalled. Thus, some MUAs + might not even be able to complete the task of performing + authentication or reputation evaluations without complex proxy + configurations or similar burdens. + + 3. MUAs rely upon the upstream MTAs within their trust boundaries to + make correct (as much as that is possible) evaluations about the + message's envelope, header and content. Thus, MUAs don't need to + know how to do the work that upstream MTAs do; they only need the + results of that work. + + 4. Evaluations about the quality of a message, from simple token + matching (e.g., a list of preferred DNS domains) to cryptanalysis + (e.g., public/private key work), are at least a little bit + expensive and thus should be minimized. To that end, performing + those tests at the border MTA is far preferred to doing that work + at each MUA that handles a message. If an ADMD's environment + adheres to common messaging protocols, a reputation query or an + authentication check performed by a border MTA would return the + same result as the same query performed by an MUA. By contrast, + in an environment where the MUA does the work, a message arriving + for multiple recipients would thus cause authentication or + reputation evaluation to be done more than once for the same + message (i.e., at each MUA) causing needless amplification of + resource use and creating a possible denial-of-service attack + vector. + + + + + +Kucherawy Standards Track [Page 41] + +RFC 5451 Authentication-Results Header Field April 2009 + + + 5. Minimizing change is good. As new authentication and reputation + methods emerge, the list of methods supported by this header + field would presumably be extended. If MUAs simply consume the + contents of this header field rather than actually attempting to + do authentication and/or reputation work, then MUAs only need to + learn to parse this header field once; emergence of new methods + requires only a configuration change at the MUAs and software + changes at the MTAs (which are presumably fewer in number). When + choosing to implement these functions in MTAs vs MUAs, the issues + of individual flexibility, infrastructure inertia and scale of + effort must be considered. It is typically easier to change a + single MUA than an MTA because the modification affects fewer + users and can be pursued with less care. However, changing many + MUAs is more effort than changing a smaller number of MTAs. + + 6. For decisions affecting message delivery and display, assessment + based on authentication and reputation is best performed close to + the time of message transit, as a message makes its journey + toward a user's inbox, not afterwards. DKIM keys and IP address + reputations, etc., can change over time or even become invalid, + and users can take a long time to read a message once delivered. + The value of this work thus degrades, perhaps quickly, once the + delivery process has completed. This seriously diminishes the + value of this work when done other than at MTAs. + + Many operational choices are possible within an ADMD, including the + venue for performing authentication and/or reputation assessment. + The current specification does not dictate any of those choices. + Rather, it facilitates those cases in which information produced by + one stage of analysis needs to be transported with the message to the + next stage. + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 42] + +RFC 5451 Authentication-Results Header Field April 2009 + + +Acknowledgements + + The author wishes to acknowledge the following for their review and + constructive criticism of this proposal: Eric Allman, Mark Delany, + Victor Duchovni, Frank Ellermann, Jim Fenton, Philip Guenther, Tony + Hansen, Paul Hoffman, Scott Kitterman, Eliot Lear, John Levine, Miles + Libbey, Charles Lindsey, Alexey Melnikov, Douglas Otis, Juan Altmayer + Pizzorno, Michael Thomas, and Kazu Yamamoto. + + Special thanks to Dave Crocker and S. Moonesamy for their logistical + support, and feedback on and contributions to the numerous proposed + edits throughout the lifetime of this work. + +Author's Address + + Murray S. Kucherawy + Sendmail, Inc. + 6475 Christie Ave., Suite 350 + Emeryville, CA 94608 + US + + Phone: +1 510 594 5400 + EMail: msk+ietf@sendmail.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 43] + diff --git a/rfc/rfc6533.txt b/rfc/rfc6533.txt new file mode 100644 index 0000000000..a350c1711b --- /dev/null +++ b/rfc/rfc6533.txt @@ -0,0 +1,1067 @@ + + + + + + +Internet Engineering Task Force (IETF) T. Hansen, Ed. +Request for Comments: 6533 AT&T Laboratories +Obsoletes: 5337 C. Newman +Updates: 3461, 3464, 3798, 6522 Oracle +Category: Standards Track A. Melnikov +ISSN: 2070-1721 Isode Ltd + February 2012 + + + Internationalized Delivery Status and Disposition Notifications + +Abstract + + Delivery status notifications (DSNs) are critical to the correct + operation of an email system. However, the existing Draft Standards + (RFC 3461, RFC 3464, RFC 6522) are presently limited to ASCII text in + the machine-readable portions of the protocol. This specification + adds a new address type for international email addresses so an + original recipient address with non-ASCII characters can be correctly + preserved even after downgrading. This also provides updated content + return media types for delivery status notifications and message + disposition notifications to support use of the new address type. + + This document extends RFC 3461, RFC 3464, RFC 3798, and RFC 6522. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6533. + + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 1] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 3 + 3. UTF-8 Address Type . . . . . . . . . . . . . . . . . . . . . . 3 + 4. UTF-8 Delivery Status Notifications . . . . . . . . . . . . . 6 + 4.1. The message/global-delivery-status Media Type . . . . . . 6 + 4.2. The message/global Media Type . . . . . . . . . . . . . . 8 + 4.3. The message/global-headers Media Type . . . . . . . . . . 8 + 4.4. Using These Media Types with multipart/report . . . . . . 8 + 4.5. Additional Requirements on SMTP Servers . . . . . . . . . 9 + 5. UTF-8 Message Disposition Notifications . . . . . . . . . . . 9 + 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 10 + 6.1. UTF-8 Mail Address Type Registration . . . . . . . . . . . 10 + 6.2. Update to 'smtp' Diagnostic Type Registration . . . . . . 11 + 6.3. message/global-headers . . . . . . . . . . . . . . . . . . 11 + 6.4. message/global-delivery-status . . . . . . . . . . . . . . 12 + 6.5. message/global-disposition-notification . . . . . . . . . 14 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 15 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . . 16 + 8.1. Normative References . . . . . . . . . . . . . . . . . . . 16 + 8.2. Informative References . . . . . . . . . . . . . . . . . . 17 + Appendix A. Changes since RFC 5337 . . . . . . . . . . . . . . . 18 + Appendix B. Acknowledgements . . . . . . . . . . . . . . . . . . 18 + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 2] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +1. Introduction + + When an email message is transmitted using the SMTPUTF8 [RFC6531] + extension and Internationalized Email Headers [RFC6532], it is + sometimes necessary to return that message or generate a Message + Disposition Notification (MDN) [RFC3798]. As a message sent to + multiple recipients can generate a status and disposition + notification for each recipient, it is helpful if a client can + correlate these notifications based on the recipient address it + provided; thus, preservation of the original recipient is important. + This specification describes how to preserve the original recipient + and updates the MDN and DSN formats to support the new address types. + + NOTE: While this specification updates the experimental versions of + this protocol by removing certain constructs (e.g., the ">" address syntax is no longer permitted), the name of the + Address Type "UTF-8" and the media type names message/global, + message/global-delivery-status, and message/global-headers have not + been changed. + + This specification is a revision of and replacement for [RFC5337]. + Section 6 of [RFC6530] describes the change in approach between this + specification and the previous version. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + The formal syntax uses the Augmented Backus-Naur Form (ABNF) + [RFC5234] notation including the core rules defined in Appendix B of + [RFC5234] and the UTF-8 syntax rules in Section 4 of [RFC3629]. + +3. UTF-8 Address Type + + "An Extensible Message Format for Delivery Status Notifications" + [RFC3464] defines the concept of an address type. The address format + introduced in "Internationalized Email Headers" [RFC6532] is a new + address type. The syntax for the new address type in the context of + status notifications is specified at the end of this section. + + An SMTP [RFC5321] server that advertises both the SMTPUTF8 extension + [RFC6531] and the DSN extension [RFC3461] MUST accept a UTF-8 address + type in the ORCPT parameter including 8-bit UTF-8 characters. This + address type also includes a 7-bit encoding suitable for use in a + message/delivery-status body part or an ORCPT parameter sent to an + SMTP server that does not advertise SMTPUTF8. + + + +Hansen, et al. Standards Track [Page 3] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + This address type has 3 forms: utf-8-addr-xtext, utf-8-addr-unitext, + and utf-8-address. Only the first form is 7-bit safe (only uses + ASCII characters [ASCII]). + + The utf-8-address form is only suitable for use in newly defined + protocols capable of native representation of 8-bit characters. That + is, the utf-8-address form MUST NOT be used: + + 1. in the ORCPT parameter when the SMTP server doesn't advertise + support for SMTPUTF8 (utf-8-addr-xtext MUST be used instead); or + + 2. if the SMTP server supports SMTPUTF8, but the address contains + ASCII characters not permitted in the ORCPT parameter (e.g., the + ORCPT parameter forbids unencoded SP and the '=' character), + (either utf-8-addr-unitext or utf-8-addr-xtext MUST be used + instead); or + + 3. in a 7-bit transport environment including a message/ + delivery-status "Original-Recipient:" or "Final-Recipient:" + field, (utf-8-addr-xtext MUST be used instead). + + The utf-8-address form MAY be used in the ORCPT parameter when the + SMTP server also advertises support for SMTPUTF8 and the address + doesn't contain any ASCII characters not permitted in the ORCPT + parameter. It SHOULD be used in a message/global-delivery-status + "Original-Recipient:" or "Final-Recipient:" DSN field, or in an + "Original-Recipient:" header field [RFC3798] if the message is a + SMTPUTF8 message. + + In addition, the utf-8-addr-unitext form can be used anywhere where + the utf-8-address form is allowed. + + When used in the ORCPT parameter, the UTF-8 address type requires + that ASCII CTLs, SP, '\', '+', and '=' be encoded using 'unitext' + encoding (see below). This is described by the utf-8-addr-xtext and + utf-8-addr-unitext forms in the ABNF below. The 'unitext' encoding + uses "\x{HEXPOINT}" syntax (EmbeddedUnicodeChar in the ABNF below) + for encoding any Unicode character outside of ASCII range, as well as + for encoding CTLs, SP, '\', '+', and '='. HEXPOINT is 2 to 6 + hexadecimal digits. This encoding avoids the need to use the xtext + encoding described in [RFC3461], as any ASCII characters that need to + be escaped using xtext encoding never appear in any unitext-encoded + string. When sending data to a SMTPUTF8-capable server, native UTF-8 + characters SHOULD be used instead of the EmbeddedUnicodeChar syntax + described below. When sending data to an SMTP server that does not + advertise SMTPUTF8, then the EmbeddedUnicodeChar syntax MUST be used + instead of UTF-8. + + + + +Hansen, et al. Standards Track [Page 4] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + When the ORCPT parameter is placed in a message/ + global-delivery-status "Original-Recipient:" field, the + utf-8-addr-xtext form of the UTF-8 address type SHOULD be converted + to the utf-8-address form (see the ABNF below) by removing the + unitext encoding. However, if an address is labeled with the UTF-8 + address type but does not conform to utf-8 syntax, then it MUST be + copied into the message/global-delivery-status field without + alteration. + + The ability to encode characters with the EmbeddedUnicodeChar + encodings should be viewed as a transitional mechanism and avoided + when possible. It is hoped that as systems lacking support for + SMTPUTF8 become less common over time, these encodings can eventually + be phased out. + + In the ABNF below, all productions not defined in this document are + defined in Appendix B of [RFC5234], in Section 4 of [RFC3629], or in + [RFC3464]. + + utf-8-type-addr = "utf-8;" utf-8-enc-addr + + utf-8-address = Mailbox + ; Mailbox as defined in [RFC6531]. + + utf-8-enc-addr = utf-8-addr-xtext / + utf-8-addr-unitext / + utf-8-address + + utf-8-addr-xtext = 1*(QCHAR / EmbeddedUnicodeChar) + ; 7bit form of utf-8-addr-unitext. + ; Safe for use in the ORCPT [RFC3461] + ; parameter even when SMTPUTF8 SMTP + ; extension is not advertised. + + utf-8-addr-unitext = 1*(QUCHAR / EmbeddedUnicodeChar) + ; MUST follow utf-8-address ABNF when + ; dequoted. + ; Safe for using in the ORCPT [RFC3461] + ; parameter when SMTPUTF8 SMTP extension + ; is also advertised. + + QCHAR = %x21-2a / %x2c-3c / %x3e-5b / %x5d-7e + ; ASCII printable characters except + ; CTLs, SP, '\', '+', '='. + + + + + + + +Hansen, et al. Standards Track [Page 5] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + QUCHAR = QCHAR / UTF8-2 / UTF8-3 / UTF8-4 + ; ASCII printable characters except + ; CTLs, SP, '\', '+' and '=', plus + ; other Unicode characters encoded in UTF-8 + + EmbeddedUnicodeChar = %x5C.78 "{" HEXPOINT "}" + ; starts with "\x" + + HEXPOINT = ( ( "0"/"1" ) %x31-39 ) / "10" / "20" / + "2B" / "3D" / "7F" / ; all xtext-specials + "5C" / (HEXDIG8 HEXDIG) / ; 2-digit forms + ( NZHEXDIG 2(HEXDIG) ) / ; 3-digit forms + ( NZDHEXDIG 3(HEXDIG) ) / ; 4-digit forms excluding + ( "D" %x30-37 2(HEXDIG) ) / ; ... surrogate + ( NZHEXDIG 4(HEXDIG) ) / ; 5-digit forms + ( "10" 4*HEXDIG ) ; 6-digit forms + ; represents either "\" or a Unicode code point outside + ; the ASCII repertoire + + HEXDIG8 = %x38-39 / "A" / "B" / "C" / "D" / "E" / "F" + ; HEXDIG excluding 0-7 + NZHEXDIG = %x31-39 / "A" / "B" / "C" / "D" / "E" / "F" + ; HEXDIG excluding "0" + NZDHEXDIG = %x31-39 / "A" / "B" / "C" / "E" / "F" + ; HEXDIG excluding "0" and "D" + +4. UTF-8 Delivery Status Notifications + + A traditional delivery status notification [RFC3464] comes in a + three-part multipart/report [RFC6522] container, where the first part + is human-readable text describing the error, the second part is a + 7-bit-only message/delivery-status, and the optional third part is + used for content (message/rfc822) or header (text/rfc822-headers) + return. As the present standard DSN format does not permit the + return of undeliverable SMTPUTF8 messages, three new media types have + been defined. ([RFC5337] introduced experimental versions of these + media types.) + +4.1. The message/global-delivery-status Media Type + + The first type, message/global-delivery-status, has the syntax of + message/delivery-status with three modifications. First, the charset + for message/global-delivery-status is UTF-8, and thus any field MAY + contain UTF-8 characters when appropriate (see the ABNF below). In + particular, the "Diagnostic-Code:" field MAY contain UTF-8 as + described in SMTPUTF8 [RFC6531]; the "Diagnostic-Code:" field SHOULD + be in i-default language [RFC2277]. Second, systems generating a + message/global-delivery-status body part SHOULD use the utf-8-address + + + +Hansen, et al. Standards Track [Page 6] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + form of the UTF-8 address type for all addresses containing + characters outside the ASCII repertoire. These systems SHOULD up- + convert the utf-8-addr-xtext or the utf-8-addr-unitext form of a + UTF-8 address type in the ORCPT parameter to the utf-8-address form + of a UTF-8 address type in the "Original-Recipient:" field. Third, + an optional field called "Localized-Diagnostic:" is added. Each + instance includes a language tag [RFC5646] and contains text in the + specified language. This is equivalent to the text part of the + "Diagnostic-Code:" field. All instances of "Localized-Diagnostic:" + MUST use different language tags. The ABNF for message/ + global-delivery-status is specified below. + + In the ABNF below, all productions not defined in this document are + defined in Appendix B of [RFC5234], in Section 4 of [RFC3629], or in + [RFC3464]. Note that is the same as from + [RFC5322], but without . If or when RFC 5322 is updated to + disallow , should become just . Also, + if or when RFC 5322 is updated to disallow control characters in + , should become a reference to that update + instead. + + utf-8-delivery-status-content = per-message-fields + 1*( CRLF utf-8-per-recipient-fields ) + ; "per-message-fields" remains unchanged from the definition + ; in RFC 3464, except for the "extension-field", + ; which is updated below. + + utf-8-per-recipient-fields = + [ original-recipient-field CRLF ] + final-recipient-field CRLF + action-field CRLF + status-field CRLF + [ remote-mta-field CRLF ] + [ diagnostic-code-field CRLF + *(localized-diagnostic-text-field CRLF) ] + [ last-attempt-date-field CRLF ] + [ final-log-id-field CRLF ] + [ will-retry-until-field CRLF ] + *( extension-field CRLF ) + ; All fields except for "original-recipient-field", + ; "final-recipient-field", "diagnostic-code-field", + ; and "extension-field" remain unchanged from + ; the definition in RFC 3464. + + + + + + + + +Hansen, et al. Standards Track [Page 7] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + generic-address =/ utf-8-enc-addr + ; Only allowed with the "utf-8" address-type. + ; Updates Section 3.2.3 of RFC 3798. + ; + ; This indirectly updates "original-recipient-field" + ; and "final-recipient-field". + + diagnostic-code-field = + "Diagnostic-Code" ":" diagnostic-type ";" *text-fixed + + localized-diagnostic-text-field = + "Localized-Diagnostic" ":" Language-Tag ";" *utf8-text + ; "Language-Tag" is a language tag as defined in [RFC5646]. + + extension-field =/ extension-field-name ":" *utf8-text + ; Updates Section 7 of RFC3798 + + text-fixed = %d1-9 / ; Any ASCII character except for NUL, + %d11 / ; CR, and LF. + %d12 / ; See note above about + %d14-127 + + utf8-text = text-fixed / UTF8-non-ascii + + UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4 + +4.2. The message/global Media Type + + The second type, used for returning the content, is message/global, + which is similar to message/rfc822, except it contains a message with + UTF-8 headers. This media type is described in [RFC6532]. + +4.3. The message/global-headers Media Type + + The third type, used for returning the headers, is message/ + global-headers and contains only the UTF-8 header fields of a message + (all lines prior to the first blank line in a SMTPUTF8 message). + Unlike message/global, this body part provides no difficulties for + the present infrastructure. + +4.4. Using These Media Types with multipart/report + + Note that as far as a multipart/report [RFC6522] container is + concerned, message/global-delivery-status, message/global, and + message/global-headers MUST be treated as equivalent to message/ + delivery-status, message/rfc822, and text/rfc822-headers. That is, + + + + + +Hansen, et al. Standards Track [Page 8] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + implementations processing multipart/report MUST expect any + combinations of the 6 media types mentioned above inside a multipart/ + report media type. + + All three new types will typically use the "8bit" Content-Transfer- + Encoding. (In the event all content is 7-bit, the equivalent + traditional types for delivery status notifications MAY be used. For + example, if information in a message/global-delivery-status part can + be represented without any loss of information as message/ + delivery-status, then the message/delivery-status body part may be + used.) Note that [RFC6532] relaxed a restriction from MIME [RFC2046] + regarding the use of Content-Transfer-Encoding in new "message" + subtypes. This specification explicitly allows the use of Content- + Transfer-Encoding in message/global-headers and message/ + global-delivery-status. This is not believed to be problematic as + these new media types are intended primarily for use by newer systems + with full support for 8-bit MIME and UTF-8 headers. + +4.5. Additional Requirements on SMTP Servers + + If an SMTP server that advertises both SMTPUTF8 and DSN needs to + return an undeliverable SMTPUTF8 message, then it has two choices for + encapsulating the SMTPUTF8 message when generating the corresponding + multipart/report: + + If the return-path SMTP server does not support SMTPUTF8, then the + undeliverable body part and headers MUST be encoded using a 7-bit + Content-Transfer-Encoding such as "base64" or "quoted-printable" + [RFC2045], as detailed in Section 4. + + Otherwise, "8bit" Content-Transfer-Encoding can be used. + +5. UTF-8 Message Disposition Notifications + + Message Disposition Notifications [RFC3798] have a similar design and + structure to DSNs. As a result, they use the same basic return + format. When generating an MDN for a UTF-8 header message, the third + part of the multipart/report contains the returned content (message/ + global) or header (message/global-headers), same as for DSNs. The + second part of the multipart/report uses a new media type, message/ + global-disposition-notification, which has the syntax of message/ + disposition-notification with two modifications. First, the charset + for message/global-disposition-notification is UTF-8, and thus any + field MAY contain UTF-8 characters when appropriate (see the ABNF + below). (In particular, the failure-field, the error-field, and the + warning-field MAY contain UTF-8. These fields SHOULD be in i-default + + + + + +Hansen, et al. Standards Track [Page 9] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + language [RFC2277].) Second, systems generating a message/ + global-disposition-notification body part (typically a mail user + agent) SHOULD use the UTF-8 address type for all addresses containing + characters outside the ASCII repertoire. + + The MDN specification also defines the "Original-Recipient:" header + field, which is added with a copy of the contents of ORCPT at + delivery time. When generating an "Original-Recipient:" header + field, a delivery agent writing a UTF-8 header message in native + format SHOULD convert the utf-8-addr-xtext or the utf-8-addr-unitext + form of a UTF-8 address type in the ORCPT parameter to the + corresponding utf-8-address form. + + The MDN specification also defines the "Disposition-Notification-To:" + header field, which is an address header field and thus follows the + same 8-bit rules as other address header fields such as "From:" and + "To:" when used in a UTF-8 header message. + + ; ABNF for "original-recipient-header", "original-recipient-field", + ; and "final-recipient-field" from RFC 3798 is implicitly updated + ; as they use the updated "generic-address" as defined in + ; Section 4 of this document. + + failure-field = "Failure" ":" *utf8-text + ; "utf8-text" is defined in Section 4 of this document. + + error-field = "Error" ":" *utf8-text + ; "utf8-text" is defined in Section 4 of this document. + + warning-field = "Warning" ":" *utf8-text + ; "utf8-text" is defined in Section 4 of this document. + +6. IANA Considerations + + This specification does not create any new IANA registries. However, + the following items have been registered as a result of this + document. + +6.1. UTF-8 Mail Address Type Registration + + The mail address type registry was created by [RFC3464]. The + registration template response follows: + + (a) The address-type name. + + UTF-8 + + + + + +Hansen, et al. Standards Track [Page 10] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + (b) The syntax for mailbox addresses of this type, specified using + BNF, regular expressions, ASN.1, or other non-ambiguous language. + + See Section 3. + + (c) If addresses of this type are not composed entirely of graphic + characters from the ASCII repertoire, a specification for how + they are to be encoded as graphic ASCII characters in an + "Original-Recipient:" or "Final-Recipient:" DSN field. + + This address type has 3 forms (as defined in Section 3): + utf-8-addr-xtext, utf-8-addr-unitext, and utf-8-address. Only + the first form is 7-bit safe. + +6.2. Update to 'smtp' Diagnostic Type Registration + + The mail diagnostic type registry was created by [RFC3464] and + updated by [RFC5337]. This specification replaces [RFC5337]. The + registration for the 'smtp' diagnostic type has been updated to + reference RFC 6533 in addition to [RFC3464] and to remove the + reference to [RFC5337]. + + When the 'smtp' diagnostic type is used in the context of a message/ + delivery-status body part, it remains as presently defined. When the + 'smtp' diagnostic type is used in the context of a message/ + global-delivery-status body part, the codes remain the same, but the + text portion MAY contain UTF-8 characters. + +6.3. message/global-headers + + Type name: message + + Subtype name: global-headers + + Required parameters: none + + Optional parameters: none + + Encoding considerations: This media type contains Internationalized + Email Headers [RFC6532] with no message body. Whenever possible, + the 8-bit content transfer encoding SHOULD be used. When this + media type passes through a 7-bit-only SMTP infrastructure, it MAY + be encoded with the base64 or quoted-printable content transfer + encoding. + + Security considerations: See Section 7. + + + + + +Hansen, et al. Standards Track [Page 11] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + Interoperability considerations: It is important that this media + type is not converted to a charset other than UTF-8. As a result, + implementations MUST NOT include a charset parameter with this + media type. Although it might be possible to down-convert this + media type to the text/rfc822-header media type, such conversion + is discouraged as it loses information. + + Published specification: RFC 6533 + + Applications that use this media type: SMTPUTF8 servers and email + clients that support multipart/report generation or parsing. + + Additional information: + + Magic number(s): none + + File extension(s): In the event this is saved to a file, the + extension ".u8hdr" is suggested. + + Macintosh file type code(s): The 'TEXT' type code is suggested as + files of this type are typically used for diagnostic purposes + and suitable for analysis in a UTF-8-aware text editor. A + uniform type identifier (UTI) of + "public.utf8-email-message-header" is suggested. This type + conforms to "public.utf8-plain-text" and "public.plain-text". + + Person & email address to contact for further information: See the + Authors' Addresses section of this document. + + Intended usage: COMMON + + Restrictions on usage: This media type contains textual data in the + UTF-8 charset. It typically contains octets with the 8th bit set. + As a result, a transfer encoding is required when a 7-bit + transport is used. + + Author: See the Authors' Addresses section of this document. + + Change controller: IETF Standards Process + +6.4. message/global-delivery-status + + Type name: message + + Subtype name: global-delivery-status + + Required parameters: none + + + + +Hansen, et al. Standards Track [Page 12] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + Optional parameters: none + + Encoding considerations: This media type contains delivery status + notification attributes in the UTF-8 charset. The 8-bit content + transfer encoding MUST be used with this content-type, unless it + is sent over a 7-bit transport environment, in which case quoted- + printable or base64 may be necessary. + + Security considerations: See Section 7 + + Interoperability considerations: This media type provides + functionality similar to the message/delivery-status content-type + for email message return information. Clients of the previous + format will need to be upgraded to interpret the new format; + however, the new media type makes it simple to identify the + difference. + + Published specification: RFC 6533 + + Applications that use this media type: SMTP servers and email + clients that support delivery status notification generation or + parsing. + + Additional information: + + Magic number(s): none + + File extension(s): The extension ".u8dsn" is suggested. + + Macintosh file type code(s): A uniform type identifier (UTI) of + "public.utf8-email-message-delivery-status" is suggested. This + type conforms to "public.utf8-plain-text". + + Person & email address to contact for further information: See the + Authors' Addresses section of this document. + + Intended usage: COMMON + + Restrictions on usage: This is expected to be the second part of a + multipart/report. + + Author: See the Authors' Addresses section of this document. + + Change controller: IETF Standards Process + + + + + + + +Hansen, et al. Standards Track [Page 13] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +6.5. message/global-disposition-notification + + Type name: message + + Subtype name: global-disposition-notification + + Required parameters: none + + Optional parameters: none + + Encoding considerations: This media type contains disposition + notification attributes in the UTF-8 charset. The 8-bit content + transfer encoding MUST be used with this content-type, unless it + is sent over a 7-bit transport environment, in which case quoted- + printable or base64 may be necessary. + + Security considerations: See Section 7. + + Interoperability considerations: This media type provides + functionality similar to the message/disposition-notification + content-type for email message disposition information. Clients + of the previous format will need to be upgraded to interpret the + new format; however, the new media type makes it simple to + identify the difference. + + Published specification: RFC 6533 + + Applications that use this media type: Email clients or servers that + support message disposition notification generation or parsing. + + Additional information: + + Magic number(s): none + + File extension(s): The extension ".u8mdn" is suggested. + + Macintosh file type code(s): A uniform type identifier (UTI) of + "public.utf8-email-message-disposition-notification" is + suggested. This type conforms to "public.utf8-plain-text". + + Person & email address to contact for further information: See the + Authors' Addresses section of this document. + + Intended usage: COMMON + + Restrictions on usage: This is expected to be the second part of a + multipart/report. + + + + +Hansen, et al. Standards Track [Page 14] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + Author: See the Authors' Addresses section of this document. + + Change controller: IETF Standards Process + +7. Security Considerations + + Automated use of report types without authentication presents several + security issues. Forging negative reports presents the opportunity + for denial-of-service attacks when the reports are used for automated + maintenance of directories or mailing lists. Forging positive + reports may cause the sender to incorrectly believe a message was + delivered when it was not. + + Malicious users can generate report structures designed to trigger + coding flaws in report parsers. Report parsers need to use secure + coding techniques to avoid the risk of buffer overflow or denial-of- + service attacks against parser coding mistakes. Code reviews of such + parsers are also recommended. + + Malicious users of the email system regularly send messages with + forged envelope return paths, and these messages trigger delivery + status reports that result in a large amount of unwanted traffic on + the Internet. Many users choose to ignore delivery status + notifications because they are usually the result of "blowback" from + forged messages and thus never notice when messages they sent go + undelivered. As a result, support for correlation of delivery status + and message disposition notification messages with sent messages has + become a critical feature of mail clients and possibly mail stores, + if the email infrastructure is to remain reliable. In the short + term, simply correlating Message-IDs may be sufficient to distinguish + true status notifications from those resulting from forged originator + addresses. But in the longer term, including cryptographic signature + material that can securely associate the status notification with the + original message is advisable. + + As this specification permits UTF-8 in additional fields, the + security considerations of UTF-8 [RFC3629] apply. + + + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 15] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +8. References + +8.1. Normative References + + [ASCII] American National Standards Institute (formerly United + States of America Standards Institute), "USA Code for + Information Interchange", ANSI X3.4-1968, 1968. + + ANSI X3.4-1968 has been replaced by newer versions with + slight modifications, but the 1968 version remains + definitive for the Internet. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2277] Alvestrand, H., "IETF Policy on Character Sets and + Languages", BCP 18, RFC 2277, January 1998. + + [RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service + Extension for Delivery Status Notifications (DSNs)", + RFC 3461, January 2003. + + [RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format + for Delivery Status Notifications", RFC 3464, + January 2003. + + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [RFC3798] Hansen, T. and G. Vaudreuil, "Message Disposition + Notification", RFC 3798, May 2004. + + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008. + + [RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, + October 2008. + + [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, + October 2008. + + [RFC5646] Phillips, A. and M. Davis, "Tags for Identifying + Languages", BCP 47, RFC 5646, September 2009. + + [RFC6522] Kucherawy, M., Ed., "The Multipart/Report Media Type for + the Reporting of Mail System Administrative Messages", STD + 73, RFC 6522, January 2012. + + + + +Hansen, et al. Standards Track [Page 16] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + + [RFC6530] Klensin, J. and Y. Ko, "Overview and Framework for + Internationalized Email", RFC 6530, February 2012. + + [RFC6531] Yao, J. and W. Mao, "SMTP Extension for Internationalized + Email", RFC 6531, February 2012. + + [RFC6532] Yang, A., Steele, S., and N. Freed, "Internationalized + Email Headers", RFC 6532, February 2012. + +8.2. Informative References + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types", RFC 2046, + November 1996. + + [RFC5337] Newman, C. and A. Melnikov, "Internationalized Delivery + Status and Disposition Notifications", RFC 5337, + September 2008. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 17] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +Appendix A. Changes since RFC 5337 + + Changes were made to move from Experimental to Standards Track. The + most significant was the removal of an embedded alternative ASCII + address within a utf-8-address, and the reflections of the ABNF + changes in [RFC6531]. + + Fixed description of utf-8-addr-xtext and utf-8-addr-unitext. + + References to Downgrade and uMailbox removed/fixed. + + ABNF changes and fixed errata submitted by Alfred Hoenes. + + Minor changes to MIME type references. + + Other minor corrections. + +Appendix B. Acknowledgements + + Many thanks for input provided by Pete Resnick, James Galvin, Ned + Freed, John Klensin, Harald Alvestrand, Frank Ellermann, SM, Alfred + Hoenes, Kazunori Fujiwara, and members of the EAI working group to + help solidify this proposal. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 18] + +RFC 6533 Internationalized DSN and MDNs February 2012 + + +Authors' Addresses + + Tony Hansen (editor) + AT&T Laboratories + 200 Laurel Ave. + Middletown, NJ 07748 + US + + EMail: tony+eaidsn@maillennium.att.com + + + Chris Newman + Oracle + 800 Royal Oaks + Monrovia, CA 91016-6347 + US + + EMail: chris.newman@oracle.com + + + Alexey Melnikov + Isode Ltd + 5 Castle Business Village + 36 Station Road + Hampton, Middlesex TW12 2BX + UK + + EMail: Alexey.Melnikov@isode.com + + + + + + + + + + + + + + + + + + + + + + + +Hansen, et al. Standards Track [Page 19] + diff --git a/rfc/rfc6577.txt b/rfc/rfc6577.txt new file mode 100644 index 0000000000..2c39c84da4 --- /dev/null +++ b/rfc/rfc6577.txt @@ -0,0 +1,283 @@ + + + + + + +Internet Engineering Task Force (IETF) M. Kucherawy +Request for Comments: 6577 Cloudmark, Inc. +Updates: 5451 March 2012 +Category: Standards Track +ISSN: 2070-1721 + + + Authentication-Results Registration Update for + Sender Policy Framework (SPF) Results + +Abstract + + This memo updates the registry of authentication method results in + Authentication-Results: message header fields, correcting a + discontinuity between the original registry creation and the Sender + Policy Framework (SPF) specification. + + This memo updates RFC 5451. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6577. + +Copyright Notice + + Copyright (c) 2012 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + +Kucherawy Standards Track [Page 1] + +RFC 6577 Auth-Results SPF Erratum March 2012 + + +Table of Contents + + 1. Introduction ....................................................2 + 2. Keywords ........................................................2 + 3. New 'fail' Definition ...........................................2 + 4. IANA Considerations .............................................2 + 4.1. Addition of 'Status' Columns ...............................3 + 4.2. Update to Result Names .....................................3 + 5. Security Considerations .........................................3 + 6. References ......................................................4 + 6.1. Normative References .......................................4 + 6.2. Informative References .....................................4 + Appendix A. Examples in RFC 5451 ...................................5 + Appendix B. Acknowledgements .......................................5 + +1. Introduction + + [AUTHRES] defined a new header field for electronic mail messages + that presents the results of a message authentication effort in a + machine-readable format. That Request for Comments created a + registry of results for a few message authentication mechanisms, one + of which was the Sender Policy Framework [SPF]. The registry + contains one entry that is inconsistent with the latter + specification, which was noted in an erratum [ERR2617] filed with the + RFC Editor. This memo updates the IANA registries accordingly. + +2. Keywords + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + +3. New 'fail' Definition + + The new "fail" result, replacing the existing "hardfail" result for + [SPF] (and thus also for [SENDER-ID]) has the same definition for + "hardfail" that was used in Section 2.4.2 of [AUTHRES], namely: + + This client is explicitly not authorized to inject or relay mail + using the sender's DNS domain. + +4. IANA Considerations + + This section enumerates requested actions of IANA, per [IANA]. + + + + + + + +Kucherawy Standards Track [Page 2] + +RFC 6577 Auth-Results SPF Erratum March 2012 + + +4.1. Addition of 'Status' Columns + + IANA has amended the Email Authentication Methods and Email + Authentication Result Names registries, both in the Email + Authentication Parameters group, by adding to each a column called + "Status" that will indicate for each entry its current status. Legal + values for these columns are as follows: + + active: The entry is in current use. + + deprecated: The entry is no longer in current use. + + New registrations to either table MUST specify one of these values. + + All existing entries, except as specified below, are to be noted as + "active" as of publication of this memo. + +4.2. Update to Result Names + + [AUTHRES] listed "hardfail" as the result to be used when a message + fails an [SPF] evaluation. However, this latter specification used + the string "fail" to denote such failures. + + Therefore, IANA has marked "hardfail" in the Email Authentication + Result Names registry as "deprecated" and amended the "fail" entry as + follows: + + Code: fail + + Defined: [AUTHRES] + + Auth Method: spf, sender-id + + Meaning: [this memo] Section 3 + + Status: active + +5. Security Considerations + + This memo corrects a registry error. It is possible that older + implementations will not recognize or use the corrected entry. Thus, + implementers are advised to support both result strings for some + period of time. However, it is known that some implementations are + already using the SPF-defined result string. + + + + + + + +Kucherawy Standards Track [Page 3] + +RFC 6577 Auth-Results SPF Erratum March 2012 + + +6. References + +6.1. Normative References + + [AUTHRES] Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", RFC 5451, April 2009. + + [ERR2617] "RFC Errata", Errata ID 2617, RFC 5451, + . + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +6.2. Informative References + + [ERR2818] "RFC Errata", Errata ID 2818, RFC 5451, + . + + [IANA] Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 5226, + May 2008. + + [SENDER-ID] Lyon, J. and M. Wong, "Sender ID: Authenticating + E-Mail", RFC 4406, April 2006. + + [SPF] Wong, M. and W. Schlitt, "Sender Policy Framework (SPF) + for Authorizing Use of Domains in E-Mail, Version 1", + RFC 4408, April 2006. + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 4] + +RFC 6577 Auth-Results SPF Erratum March 2012 + + +Appendix A. Examples in RFC 5451 + + It should be noted that this update also applies to the examples in + [AUTHRES], specifically the one in Appendix B.5. The error there + [ERR2818] is not corrected by this update, which only deals with the + normative portions of that specification and the related IANA + registrations. However, it is assumed one could easily see what + needs to be corrected there. + + Corrected examples will be included in a full update to [AUTHRES] at + some future time. + +Appendix B. Acknowledgements + + The author wishes to acknowledge the following for their review and + constructive criticism of this proposal: S. Moonesamy, Scott + Kitterman. + +Author's Address + + Murray S. Kucherawy + Cloudmark, Inc. + 128 King St., 2nd Floor + San Francisco, CA 94107 + US + + Phone: +1 415 946 3800 + EMail: msk@cloudmark.com + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 5] + diff --git a/rfc/rfc7001.txt b/rfc/rfc7001.txt new file mode 100644 index 0000000000..522f8fff03 --- /dev/null +++ b/rfc/rfc7001.txt @@ -0,0 +1,2411 @@ + + + + + + +Internet Engineering Task Force (IETF) M. Kucherawy +Request for Comments: 7001 September 2013 +Obsoletes: 5451, 6577 +Category: Standards Track +ISSN: 2070-1721 + + + Message Header Field for Indicating Message Authentication Status + +Abstract + + This document specifies a message header field called Authentication- + Results for use with electronic mail messages to indicate the results + of message authentication efforts. Any receiver-side software, such + as mail filters or Mail User Agents (MUAs), can use this header field + to relay that information in a convenient and meaningful way to users + or to make sorting and filtering decisions. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc7001. + +Copyright Notice + + Copyright (c) 2013 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + +Kucherawy Standards Track [Page 1] + +RFC 7001 Authentication-Results Header Field September 2013 + + +Table of Contents + + 1. Introduction ....................................................3 + 1.1. Purpose ....................................................4 + 1.2. Trust Boundary .............................................5 + 1.3. Processing Scope ...........................................6 + 1.4. Requirements ...............................................6 + 1.5. Definitions ................................................6 + 1.5.1. Key Words ...........................................6 + 1.5.2. Security ............................................6 + 1.5.3. Email Architecture ..................................7 + 1.5.4. Other Terms .........................................8 + 1.6. Trust Environment ..........................................8 + 2. Definition and Format of the Header Field .......................9 + 2.1. General Description ........................................9 + 2.2. Formal Definition ..........................................9 + 2.3. The "policy" ptype ........................................12 + 2.4. Authentication Identifier Field ...........................13 + 2.5. Version Tokens ............................................14 + 2.6. Defined Methods and Result Values .........................14 + 2.6.1. DKIM and DomainKeys ................................14 + 2.6.2. SPF and Sender ID ..................................15 + 2.6.3. "iprev" ............................................17 + 2.6.4. SMTP AUTH ..........................................17 + 2.6.5. Other Registered Codes .............................18 + 2.6.6. Extension Methods ..................................18 + 2.6.7. Extension Result Codes .............................19 + 3. The "iprev" Authentication Method ..............................19 + 4. Adding the Header Field to a Message ...........................20 + 4.1. Header Field Position and Interpretation ..................22 + 4.2. Local Policy Enforcement ..................................23 + 5. Removing Existing Header Fields ................................23 + 6. IANA Considerations ............................................24 + 6.1. The Authentication-Results Header Field ...................25 + 6.2. "Email Authentication Methods" Registry ...................25 + 6.3. "Email Authentication Result Names" Registry ..............26 + 7. Security Considerations ........................................26 + 7.1. Forged Header Fields ......................................26 + 7.2. Misleading Results ........................................28 + 7.3. Header Field Position .....................................28 + 7.4. Reverse IP Query Denial-of-Service Attacks ................28 + 7.5. Mitigation of Backscatter .................................29 + 7.6. Internal MTA Lists ........................................29 + 7.7. Attacks against Authentication Methods ....................29 + 7.8. Intentionally Malformed Header Fields .....................29 + 7.9. Compromised Internal Hosts ................................29 + 7.10. Encapsulated Instances ...................................30 + 7.11. Reverse Mapping ..........................................30 + + + +Kucherawy Standards Track [Page 2] + +RFC 7001 Authentication-Results Header Field September 2013 + + + 8. References .....................................................30 + 8.1. Normative References ......................................30 + 8.2. Informative References ....................................31 + Appendix A. Acknowledgements .....................................33 + Appendix B. Legacy MUAs ..........................................33 + Appendix C. Authentication-Results Examples ......................33 + C.1. Trivial Case; Header Field Not Present ....................34 + C.2. Nearly Trivial Case; Service Provided, but No + Authentication Done .......................................34 + C.3. Service Provided, Authentication Done .....................35 + C.4. Service Provided, Several Authentications Done, Single + MTA .......................................................36 + C.5. Service Provided, Several Authentications Done, + Different MTAs ............................................37 + C.6. Service Provided, Multi-Tiered Authentication Done ........38 + C.7. Comment-Heavy Example .....................................40 + Appendix D. Operational Considerations about Message + Authentication .......................................40 + Appendix E. Changes since RFC 5451 ...............................42 + +1. Introduction + + This document describes a header field called Authentication-Results + for electronic mail messages that presents the results of a message + authentication effort in a machine-readable format. The intent of + the header field is to create a place to collect such data when + message authentication mechanisms are in use so that a Mail User + Agent (MUA) and downstream filters can make filtering decisions + and/or provide a recommendation to the user as to the validity of the + message's origin and possibly the safety and integrity of its + content. + + This document revises the original definition found in [RFC5451] + based upon various authentication protocols in current use and + incorporates errata logged since the publication of the original + specification. + + End users are not expected to be direct consumers of this header + field. This header field is intended for consumption by programs + that will then use such data or render it in a human-usable form. + + This document specifies the format of this header field and discusses + the implications of its presence or absence. However, it does not + discuss how the data contained in the header field ought to be used, + such as what filtering decisions are appropriate or how an MUA might + render those results, as these are local policy and/or user interface + design questions that are not appropriate for this document. + + + + +Kucherawy Standards Track [Page 3] + +RFC 7001 Authentication-Results Header Field September 2013 + + + At the time of publication of this document, the following are + published, domain-level email authentication methods in common use: + + o Author Domain Signing Practices ([ADSP]) + + o SMTP Service Extension for Authentication ([AUTH]) + + o DomainKeys Identified Mail Signatures ([DKIM]) + + o Sender Policy Framework ([SPF]) + + o Vouch By Reference ([VBR]) + + o reverse IP address name validation ("iprev", defined in Section 3) + + In addition, the following are non-standard methods recognized by + this specification that are no longer common: + + o DomainKeys ([DOMAINKEYS]) (Historic) + + o Sender ID ([SENDERID]) (Experimental) + + This specification is not intended to be restricted to domain-based + authentication schemes, but the existing schemes in that family have + proven to be a good starting point for implementations. The goal is + to give current and future authentication schemes a common framework + within which to deliver their results to downstream agents and + discourage the creation of unique header fields for each. + + Although SPF defined a header field called "Received-SPF" and the + historic DomainKeys defined one called "DomainKey-Status" for this + purpose, those header fields are specific to the conveyance of their + respective results only and thus are insufficient to satisfy the + requirements enumerated below. In addition, many SPF implementations + have adopted the header field specified here at least as an option, + and DomainKeys has been obsoleted by DKIM. + +1.1. Purpose + + The header field defined in this document is expected to serve + several purposes: + + 1. Convey the results of various message authentication checks, + which are applied by upstream filters and Mail Transfer Agents + (MTAs) and then passed to MUAs and downstream filters within the + same "trust domain". Such agents might wish to render those + results to end users or to use those data to apply more or less + stringent content checks based on authentication results; + + + +Kucherawy Standards Track [Page 4] + +RFC 7001 Authentication-Results Header Field September 2013 + + + 2. Provide a common location within a message for this data; + + 3. Create an extensible framework for reporting new authentication + methods as they emerge. + + In particular, the mere presence of this header field does not mean + its contents are valid. Rather, the header field is reporting + assertions made by one or more authentication schemes (supposedly) + applied somewhere upstream. For an MUA or downstream filter to treat + the assertions as actually valid, there must be an assessment of the + trust relationship among such agents, the validating MTA, and the + mechanism for conveying the information. + +1.2. Trust Boundary + + This document makes several references to the "trust boundary" of an + administrative management domain (ADMD). Given the diversity among + existing mail environments, a precise definition of this term isn't + possible. + + Simply put, a transfer from the producer of the header field to the + consumer must occur within a context that permits the consumer to + treat assertions by the producer as being reliable and accurate + (trustworthy). How this trust is obtained is outside the scope of + this document. It is entirely a local matter. + + Thus, this document defines a "trust boundary" as the delineation + between "external" and "internal" entities. Services that are + internal -- within the trust boundary -- are provided by the ADMD's + infrastructure for its users. Those that are external are outside of + the authority of the ADMD. By this definition, hosts that are within + a trust boundary are subject to the ADMD's authority and policies, + independent of their physical placement or their physical operation. + For example, a host within a trust boundary might actually be + operated by a remote service provider and reside physically within + its data center. + + It is possible for a message to be evaluated inside a trust boundary + but then depart and re-enter the trust boundary. An example might be + a forwarded message such as a message/rfc822 attachment (see + Multipurpose Internet Mail Extensions [MIME]) or one that is part of + a multipart/digest. The details reported by this field cannot be + trusted in that case. Thus, this field found within one of those + media types is typically ignored. + + + + + + + +Kucherawy Standards Track [Page 5] + +RFC 7001 Authentication-Results Header Field September 2013 + + +1.3. Processing Scope + + The content of this header field is meant to convey to message + consumers that authentication work on the message was already done + within its trust boundary, and those results are being presented. It + is not intended to provide message parameters to consumers so that + they can perform authentication protocols on their own. + +1.4. Requirements + + This document establishes no new requirements on existing protocols + or servers. + + In particular, this document establishes no requirement on MTAs to + reject or filter arriving messages that do not pass authentication + checks. The data conveyed by the specified header field's contents + are for the information of MUAs and filters and are to be used at + their discretion. + +1.5. Definitions + + This section defines various terms used throughout this document. + +1.5.1. Key Words + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + +1.5.2. Security + + "Guidelines for Writing RFC Text on Security Considerations" + ([SECURITY]) discusses authentication and authorization and the + conflation of the two concepts. The use of those terms within the + context of recent message security work has given rise to slightly + different definitions, and this document reflects those current + usages, as follows: + + o "Authorization" is the establishment of permission to use a + resource or represent an identity. In this context, authorization + indicates that a message from a particular ADMD arrived via a + route the ADMD has explicitly approved. + + o "Authentication" is the assertion of validity of a piece of data + about a message (such as the sender's identity) or the message in + its entirety. + + + + + +Kucherawy Standards Track [Page 6] + +RFC 7001 Authentication-Results Header Field September 2013 + + + As examples: SPF and Sender ID are authorization mechanisms in that + they express a result that shows whether or not the ADMD that + apparently sent the message has explicitly authorized the connecting + Simple Mail Transfer Protocol ([SMTP]) client to relay messages on + its behalf, but they do not actually validate any other property of + the message itself. By contrast, DKIM is agnostic as to the routing + of a message but uses cryptographic signatures to authenticate + agents, assign (some) responsibility for the message (which implies + authorization), and ensure that the listed portions of the message + were not modified in transit. Since the signatures are not tied to + SMTP connections, they can be added by either the ADMD of origin, + intermediate ADMDs (such as a mailing list server), other handling + agents, or any combination. + + Rather than create a separate header field for each class of + solution, this proposal groups them both into a single header field. + +1.5.3. Email Architecture + + o A "border MTA" is an MTA that acts as a gateway between the + general Internet and the users within an organizational boundary. + (See also Section 1.2.) + + o A "delivery MTA" (or Mail Delivery Agent or MDA) is an MTA that + actually enacts delivery of a message to a user's inbox or other + final delivery. + + o An "intermediate MTA" is any MTA that is not a delivery MTA and is + also not the first MTA to handle the message. + + The following diagram illustrates the flow of mail among these + defined components. See Internet Mail Architecture [EMAIL-ARCH] for + further discussion on general email system architecture, which + includes detailed descriptions of these components, and Appendix D of + this document for discussion about the common aspects of email + authentication in current environments. + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 7] + +RFC 7001 Authentication-Results Header Field September 2013 + + + +-----+ +-----+ +------------+ + | MUA |-->| MSA |-->| Border MTA | + +-----+ +-----+ +------------+ + | + | + V + +----------+ + | Internet | + +----------+ + | + | + V + +-----+ +-----+ +------------------+ +------------+ + | MUA |<--| MDA |<--| Intermediate MTA |<--| Border MTA | + +-----+ +-----+ +------------------+ +------------+ + + Generally, it is assumed that the work of applying message + authentication schemes takes place at a border MTA or a delivery MTA. + This specification is written with that assumption in mind. However, + there are some sites at which the entire mail infrastructure consists + of a single host. In such cases, such terms as "border MTA" and + "delivery MTA" might well apply to the same machine or even the very + same agent. It is also possible that some message authentication + tests could take place on an intermediate MTA. Although this + document doesn't specifically describe such cases, they are not meant + to be excluded. + +1.5.4. Other Terms + + In this document, the term "producer" refers to any component that + adds this header field to messages it is handling, and "consumer" + refers to any component that identifies, extracts, and parses the + header field to use as part of a handling decision. + +1.6. Trust Environment + + This header field permits one or more message validation mechanisms + to communicate output to one or more separate assessment mechanisms. + These mechanisms operate within a unified trust boundary that defines + an Administrative Management Domain (ADMD). An ADMD contains one or + more entities that perform validation and generate the header field + and one or more that consume it for some type of assessment. The + field often contains no integrity or validation mechanism of its own, + so its presence must be trusted implicitly. Hence, valid use of the + header field requires removing any occurrences of it that are present + when the message enters the ADMD. This ensures that later + occurrences have been added within the trust boundary of the ADMD. + + + + +Kucherawy Standards Track [Page 8] + +RFC 7001 Authentication-Results Header Field September 2013 + + + The authserv-id token defined in Section 2.2 can be used to reference + an entire ADMD or a specific validation engine within an ADMD. + Although the labeling scheme is left as an operational choice, some + guidance for selecting a token is provided in later sections of this + document. + +2. Definition and Format of the Header Field + + This section gives a general overview of the format of the header + field being defined and then provides more formal specification. + +2.1. General Description + + The header field specified here is called Authentication-Results. It + is a Structured Header Field as defined in Internet Message Format + ([MAIL]), and thus all of the related definitions in that document + apply. + + This header field is added at the top of the message as it transits + MTAs that do authentication checks, so some idea of how far away the + checks were done can be inferred. It is therefore considered to be a + trace field as defined in [MAIL], and thus all of the related + definitions in that document apply. + + The value of the header field (after removing comments) consists of + an authentication identifier, an optional version, and then a series + of statements and supporting data. The statements are of the form + "method=result" and indicate which authentication method(s) were + applied and their respective results. For each such statement, the + supporting data can include a "reason" string and one or more + "property=value" statements indicating which message properties were + evaluated to reach that conclusion. + + The header field can appear more than once in a single message, more + than one result can be represented in a single header field, or a + combination of these can be applied. + +2.2. Formal Definition + + Formally, the header field is specified as follows using Augmented + Backus-Naur Form ([ABNF]): + + authres-header = "Authentication-Results:" [CFWS] authserv-id + [ CFWS authres-version ] + ( no-result / 1*resinfo ) [CFWS] CRLF + + authserv-id = value + ; see below for a description of this element + + + +Kucherawy Standards Track [Page 9] + +RFC 7001 Authentication-Results Header Field September 2013 + + + authres-version = 1*DIGIT [CFWS] + ; indicates which version of this specification is in use; + ; this specification is version "1", and the absence of a + ; version implies this version of the specification + + no-result = [CFWS] ";" [CFWS] "none" + ; the special case of "none" is used to indicate that no + ; message authentication was performed + + resinfo = [CFWS] ";" methodspec [ CFWS reasonspec ] + *( CFWS propspec ) + + methodspec = [CFWS] method [CFWS] "=" [CFWS] result + ; indicates which authentication method was evaluated + ; and what its output was + + reasonspec = "reason" [CFWS] "=" [CFWS] value + ; a free-form comment on the reason the given result + ; was returned + + propspec = ptype [CFWS] "." [CFWS] property [CFWS] "=" pvalue + ; an indication of which properties of the message + ; were evaluated by the authentication scheme being + ; applied to yield the reported result + + method = Keyword [ [CFWS] "/" [CFWS] method-version ] + ; a method indicates which method's result is + ; represented by "result", and is one of the methods + ; explicitly defined as valid in this document + ; or is an extension method as defined below + + method-version = 1*DIGIT [CFWS] + ; indicates which version of the method specification is + ; in use, corresponding to the matching entry in the IANA + ; "Email Authentication Methods" registry; a value of "1" + ; is assumed if this version string is absent + + result = Keyword + ; indicates the results of the attempt to authenticate + ; the message; see below for details + + ptype = "smtp" / "header" / "body" / "policy" + ; indicates whether the property being evaluated was + ; a parameter to an [SMTP] command, was a value taken + ; from a message header field, was some property of + ; the message body, or was some other property evaluated by + ; the receiving MTA + + + + +Kucherawy Standards Track [Page 10] + +RFC 7001 Authentication-Results Header Field September 2013 + + + property = special-smtp-verb / Keyword + ; if "ptype" is "smtp", this indicates which [SMTP] + ; command provided the value that was evaluated by the + ; authentication scheme being applied; if "ptype" is + ; "header", this indicates from which header field the + ; value being evaluated was extracted; if "ptype" is + ; "body", this indicates where in the message body + ; a value being evaluated can be found (e.g., a specific + ; offset into the message or a reference to a MIME part); + ; if "ptype" is "policy", then this indicates the name + ; of the policy that caused this header field to be + ; added (see below) + + special-smtp-verb = "mailfrom" / "rcptto" + ; special cases of [SMTP] commands that are made up + ; of multiple words + + pvalue = [CFWS] ( value / [ [ local-part ] "@" ] domain-name ) + [CFWS] + ; the value extracted from the message property defined + ; by the "ptype.property" construction + + "local-part" is defined in Section 3.4.1 of [MAIL], and "CFWS" is + defined in Section 3.2.2 of [MAIL]. + + "Keyword" is defined in Section 4.1.2 of [SMTP]. + + The "value" is as defined in Section 5.1 of [MIME]. + + The "domain-name" is as defined in Section 3.5 of [DKIM]. + + The "Keyword" used in "result" above is further constrained by the + necessity of being enumerated in Section 2.6. + + See Section 2.4 for a description of the authserv-id element. + + If the value portion of a "pvalue" construction identifies something + intended to be an e-mail identity, then it MUST use the right hand + portion of that ABNF definition. + + The list of commands eligible for use with the "smtp" ptype can be + found in Section 4.1 of [SMTP]. + + The "propspec" may be omitted if, for example, the method was unable + to extract any properties to do its evaluation yet has a result to + report. + + + + + +Kucherawy Standards Track [Page 11] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Where an SMTP command name is being reported as a "property", the + agent generating the header field represents that command by + converting it to lowercase and dropping any spaces (e.g., "MAIL FROM" + becomes "mailfrom", "RCPT TO" becomes "rcptto", etc.). + + A "ptype" value of "policy" indicates a policy decision about the + message not specific to a property of the message that could be + extracted. See Section 2.3 for details. + + Examples of complete messages using this header field can be found in + Appendix C. + +2.3. The "policy" ptype + + A special ptype value of "policy" is defined. This ptype is provided + to indicate that some local policy mechanism was applied that + augments or even replaces (i.e., overrides) the result returned by + the authentication mechanism. The property and value in this case + identify the local policy that was applied and the result it + returned. + + For example, a DKIM signature is not required to include the Subject + header field in the set of fields that are signed. An ADMD receiving + such a message might decide that such a signature is unacceptable, + even if it passes, because the content of the Subject header field + could be altered post-signing without invalidating the signature. + Such an ADMD could replace the DKIM "pass" result with a "policy" + result and then also include the following in the corresponding + Authentication-Result field: + + ... dkim=fail policy.dkim-rules=unsigned-subject ... + + In this case, the property is "dkim-rules", indicating some local + check by that name took place and that check returned a result of + "unsigned-subject". These are arbitrary names selected by (and + presumably used within) the ADMD making use of them, so they are not + normally registered with IANA or otherwise specified apart from + setting syntax restrictions that allow for easy parsing within the + rest of the header field. + + This ptype existed in the original specification for this header + field, but without a complete description or example of intended use. + As a result, it has not seen any practical use to date that matches + its intended purpose. These added details are provided to guide + implementers toward proper use. + + + + + + +Kucherawy Standards Track [Page 12] + +RFC 7001 Authentication-Results Header Field September 2013 + + +2.4. Authentication Identifier Field + + Every Authentication-Results header field has an authentication + service identifier field (authserv-id above). Specifically, this is + any string intended to identify the authentication service within the + ADMD that conducted authentication checks on the message. This + identifier is intended to be machine-readable and not necessarily + meaningful to users. + + Since agents consuming this field will use this identifier to + determine whether its contents are of interest (and are safe to use), + the uniqueness of the identifier MUST be guaranteed by the ADMD that + generates it and MUST pertain to that ADMD. MUAs or downstream + filters SHOULD use this identifier to determine whether or not the + data contained in an Authentication-Results header field ought to be + used or ignored. + + For simplicity and scalability, the authentication service identifier + SHOULD be a common token used throughout the ADMD. Common practice + is to use the DNS domain name used by or within that ADMD, sometimes + called the "organizational domain", but this is not strictly + necessary. + + For tracing and debugging purposes, the authentication identifier can + instead be the specific hostname of the MTA performing the + authentication check whose result is being reported. Moreover, some + implementations define a substructure to the identifier; these are + outside of the scope of this specification. + + Note, however, that using a local, relative identifier like a flat + hostname, rather than a hierarchical and globally unique ADMD + identifier like a DNS domain name, makes configuration more difficult + for large sites. The hierarchical identifier permits aggregating + related, trusted systems together under a single, parent identifier, + which in turn permits assessing the trust relationship with a single + reference. The alternative is a flat namespace requiring + individually listing each trusted system. Since consumers will use + the identifier to determine whether to use the contents of the header + field: + + o Changes to the identifier impose a large, centralized + administrative burden. + + o Ongoing administrative changes require constantly updating this + centralized table, making it difficult to ensure that an MUA or + downstream filter will have access to accurate information for + assessing the usability of the header field's content. In + particular, consumers of the header field will need to know not + + + +Kucherawy Standards Track [Page 13] + +RFC 7001 Authentication-Results Header Field September 2013 + + + only the current identifier(s) in use but previous ones as well to + account for delivery latency or later re-assessment of the header + field's contents. + + Examples of valid authentication identifiers are "example.com", + "mail.example.org", "ms1.newyork.example.com", and "example-auth". + +2.5. Version Tokens + + The grammar above provides for the optional inclusion of versions on + both the header field itself (attached to the authserv-id token) and + on each of the methods being reported. The method version refers to + the method itself, which is specified in the documents describing + those methods, while the authserv-id version refers to this document + and thus the syntax of this header field. + + The purpose of including these is to avoid misinterpretation of the + results. That is, if a parser finds a version after an authserv-id + that it does not explicitly know, it can immediately discontinue + trying to parse since what follows might not be in an expected + format. For a method version, the parser SHOULD ignore a method + result if the version is not supported in case the semantics of the + result have a different meaning than what is expected. For example, + if a hypothetical DKIM version 2 yielded a "pass" result for + different reasons than version 1 does, a consumer of this field might + not want to use the altered semantics. Allowing versions in the + syntax is a way to indicate this and let the consumer of the header + field decide. + +2.6. Defined Methods and Result Values + + Each individual authentication method returns one of a set of + specific result values. The subsections below provide references to + the documents defining the authentication methods specifically + supported by this document, and their corresponding result values. + Verifiers SHOULD use these values as described below. New methods + not specified in this document, but intended to be supported by the + header field defined here, MUST include a similar result table either + in their defining documents or in supplementary ones. + +2.6.1. DKIM and DomainKeys + + DKIM is represented by the "dkim" method and is defined in [DKIM]. + DomainKeys is defined in [DOMAINKEYS] and is represented by the + "domainkeys" method. + + + + + + +Kucherawy Standards Track [Page 14] + +RFC 7001 Authentication-Results Header Field September 2013 + + + A signature is "acceptable to the ADMD" if it passes local policy + checks (or there are no specific local policy checks). For example, + an ADMD policy might require that the signature(s) on the message be + added using the DNS domain present in the From header field of the + message, thus making third-party signatures unacceptable even if they + verify. + + Both DKIM and DomainKeys use the same result set, as follows: + + none: The message was not signed. + + pass: The message was signed, the signature or signatures were + acceptable to the ADMD, and the signature(s) passed verification + tests. + + fail: The message was signed and the signature or signatures were + acceptable to the ADMD, but they failed the verification test(s). + + policy: The message was signed, but some aspect of the signature or + signatures was not acceptable to the ADMD. + + neutral: The message was signed, but the signature or signatures + contained syntax errors or were not otherwise able to be + processed. This result is also used for other failures not + covered elsewhere in this list. + + temperror: The message could not be verified due to some error that + is likely transient in nature, such as a temporary inability to + retrieve a public key. A later attempt may produce a final + result. + + permerror: The message could not be verified due to some error that + is unrecoverable, such as a required header field being absent. A + later attempt is unlikely to produce a final result. + + [DKIM] advises that if a message fails verification, it is to be + treated as an unsigned message. A report of "fail" here permits the + receiver of the report to decide how to handle the failure. A report + of "neutral" or "none" preempts that choice, ensuring the message + will be treated as if it had not been signed. + +2.6.2. SPF and Sender ID + + SPF and Sender ID use the "spf" and "sender-id" method names, + respectively. The result values for SPF are defined in Section 2.5 + of [SPF], and those definitions are included here by reference: + + + + + +Kucherawy Standards Track [Page 15] + +RFC 7001 Authentication-Results Header Field September 2013 + + + +-----------+----------------------------+ + | Code | Meaning | + +-----------+----------------------------+ + | none | [SPF], Section 2.5.1 | + +-----------+----------------------------+ + | pass | [SPF], Section 2.5.3 | + +-----------+----------------------------+ + | fail | [SPF], Section 2.5.4 | + +-----------+----------------------------+ + | softfail | [SPF], Section 2.5.5 | + +-----------+----------------------------+ + | policy | [RFC7001], Section 2.6.2 | + +-----------+----------------------------+ + | neutral | [SPF], Section 2.5.2 | + +-----------+----------------------------+ + | temperror | [SPF], Section 2.5.6 | + +-----------+----------------------------+ + | permerror | [SPF], Section 2.5.7 | + +-----------+----------------------------+ + + These result codes are used in the context of this specification to + reflect the result returned by the component conducting SPF + evaluation. + + Similarly, the results for Sender ID are listed and described in + Section 4.2 of [SENDERID], which in turn uses the SPF definitions. + + Note that both of those documents specify result codes that use mixed + case, but they are typically used all lowercase in this context. + + In both cases, an additional result of "policy" is defined, which + means the client was authorized to inject or relay mail on behalf of + the sender's DNS domain according to the authentication method's + algorithm, but local policy dictates that the result is unacceptable. + For example, "policy" might be used if SPF returns a "pass" result, + but a local policy check matches the sending DNS domain to one found + in an explicit list of unacceptable DNS domains (e.g., spammers). + + If the retrieved sender policies used to evaluate SPF and Sender ID + do not contain explicit provisions for authenticating the local-part + (see Section 3.4.1 of [MAIL]) of an address, the "pvalue" reported + along with results for these mechanisms SHOULD NOT include the local- + part. + + + + + + + + +Kucherawy Standards Track [Page 16] + +RFC 7001 Authentication-Results Header Field September 2013 + + +2.6.3. "iprev" + + The result values used by the "iprev" method, defined in Section 3, + are as follows: + + pass: The DNS evaluation succeeded, i.e., the "reverse" and + "forward" lookup results were returned and were in agreement. + + fail: The DNS evaluation failed. In particular, the "reverse" and + "forward" lookups each produced results, but they were not in + agreement, or the "forward" query completed but produced no + result, e.g., a DNS RCODE of 3, commonly known as NXDOMAIN, or an + RCODE of 0 (NOERROR) in a reply containing no answers, was + returned. + + temperror: The DNS evaluation could not be completed due to some + error that is likely transient in nature, such as a temporary DNS + error, e.g., a DNS RCODE of 2, commonly known as SERVFAIL, or + other error condition resulted. A later attempt may produce a + final result. + + permerror: The DNS evaluation could not be completed because no PTR + data are published for the connecting IP address, e.g., a DNS + RCODE of 3, commonly known as NXDOMAIN, or an RCODE of 0 (NOERROR) + in a reply containing no answers, was returned. This prevented + completion of the evaluation. A later attempt is unlikely to + produce a final result. + + There is no "none" for this method since any TCP connection + delivering email has an IP address associated with it, so some kind + of evaluation will always be possible. + + For discussion of the format of DNS replies, see "Domain Names - + Implementation and Specification" ([DNS]). + +2.6.4. SMTP AUTH + + SMTP AUTH (defined in [AUTH]) is represented by the "auth" method, + and its result values are as follows: + + none: SMTP authentication was not attempted. + + pass: The SMTP client authenticated to the server reporting the + result using the protocol described in [AUTH]. + + + + + + + +Kucherawy Standards Track [Page 17] + +RFC 7001 Authentication-Results Header Field September 2013 + + + fail: The SMTP client attempted to authenticate to the server using + the protocol described in [AUTH] but was not successful, yet + continued to send the message about which a result is being + reported. + + temperror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error that is likely transient in nature, such + as a temporary directory service lookup error. A later attempt + may produce a final result. + + permerror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error that is likely not transient in nature, + such as a permanent directory service lookup error. A later + attempt is not likely to produce a final result. + + An agent making use of the data provided by this header field SHOULD + consider "fail" and "temperror" to be synonymous in terms of message + authentication, i.e., the client did not authenticate in either case. + +2.6.5. Other Registered Codes + + Result codes were also registered in other RFCs for Vouch By + Reference (in [AR-VBR], represented by "vbr"), Authorized Third-Party + Signatures (in [ATPS], represented by "dkim-atps"), and the DKIM- + related Author Domain Signing Practices (in [ADSP], represented by + "dkim-adsp"). + +2.6.6. Extension Methods + + Additional authentication method identifiers (extension methods) may + be defined in the future by later revisions or extensions to this + specification. These method identifiers are registered with the + Internet Assigned Numbers Authority (IANA) and, preferably, published + in an RFC. See Section 6 for further details. + + Extension methods can be defined for the following reasons: + + 1. To allow additional information from new authentication systems + to be communicated to MUAs or downstream filters. The names of + such identifiers ought to reflect the name of the method being + defined but ought not be needlessly long. + + 2. To allow the creation of "sub-identifiers" that indicate + different levels of authentication and differentiate between + their relative strengths, e.g., "auth1-weak" and "auth1-strong". + + + + +Kucherawy Standards Track [Page 18] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Authentication method implementers are encouraged to provide adequate + information, via message header field comments if necessary, to allow + an MUA developer to understand or relay ancillary details of + authentication results. For example, if it might be of interest to + relay what data was used to perform an evaluation, such information + could be relayed as a comment in the header field, such as: + + Authentication-Results: example.com; + foo=pass bar.baz=blob (2 of 3 tests OK) + + Experimental method identifiers MUST only be used within ADMDs that + have explicitly consented to use them. These method identifiers and + the parameters associated with them are not documented in RFCs. + Therefore, they are subject to change at any time and not suitable + for production use. Any MTA, MUA, or downstream filter intended for + production use SHOULD ignore or delete any Authentication-Results + header field that includes an experimental (unknown) method + identifier. + +2.6.7. Extension Result Codes + + Additional result codes (extension results) might be defined in the + future by later revisions or extensions to this specification. + Result codes MUST be registered with the Internet Assigned Numbers + Authority (IANA) and preferably published in an RFC. See Section 6 + for further details. + + Extension results MUST only be used within ADMDs that have explicitly + consented to use them. These results and the parameters associated + with them are not formally documented. Therefore, they are subject + to change at any time and not suitable for production use. Any MTA, + MUA, or downstream filter intended for production use SHOULD ignore + or delete any Authentication-Results header field that includes an + extension result. + +3. The "iprev" Authentication Method + + This section defines an additional authentication method called + "iprev". + + "iprev" is an attempt to verify that a client appears to be valid + based on some DNS queries, which is to say that the IP address is + explicitly associated with a domain name. Upon receiving a session + initiation of some kind from a client, the IP address of the client + peer is queried for matching names (i.e., a number-to-name + translation, also known as a "reverse lookup" or a "PTR" record + query). Once that result is acquired, a lookup of each of the names + (i.e., a name-to-number translation, or an "A" or "AAAA" record + + + +Kucherawy Standards Track [Page 19] + +RFC 7001 Authentication-Results Header Field September 2013 + + + query) thus retrieved is done. The response to this second check + will typically result in at least one mapping back to the client's IP + address. + + Expressed as an algorithm: If the client peer's IP address is I, the + list of names to which I maps (after a "PTR" query) is the set N, and + the union of IP addresses to which each member of N maps (after + corresponding "A" and "AAAA" queries) is L, then this test is + successful if I is an element of L. + + The response to a PTR query could contain multiple names. To prevent + heavy DNS loads, agents performing these queries MUST be implemented + such that the number of names evaluated by generation of + corresponding A or AAAA queries is limited so as not to be unduly + taxing to the DNS infrastructure, though it MAY be configurable by an + administrator. As an example, Section 5.5 of [SPF] chose a limit of + 10 for its implementation of this algorithm. + + "DNS Extensions to Support IP Version 6" ([DNS-IP6]) discusses the + query formats for the IPv6 case. + + There is some contention regarding the wisdom and reliability of this + test. For example, in some regions, it can be difficult for this + test ever to pass because the practice of arranging to match the + forward and reverse DNS is infrequently observed. Therefore, the + precise implementation details of how a verifier performs an "iprev" + test are not specified here. The verifier MAY report a successful or + failed "iprev" test at its discretion having done some kind of check + of the validity of the connection's identity using DNS. It is + incumbent upon an agent making use of the reported "iprev" result to + understand what exactly that particular verifier is attempting to + report. + + Extensive discussion of reverse DNS mapping and its implications can + be found in "Considerations for the use of DNS Reverse Mapping" + ([DNSOP-REVERSE]). In particular, it recommends that applications + avoid using this test as a means of authentication or security. Its + presence in this document is not an endorsement but is merely + acknowledgement that the method remains common and provides the means + to relay the results of that test. + +4. Adding the Header Field to a Message + + This specification makes no attempt to evaluate the relative + strengths of various message authentication methods that may become + available. The methods listed are an order-independent set; their + sequence does not indicate relative strength or importance of one + + + + +Kucherawy Standards Track [Page 20] + +RFC 7001 Authentication-Results Header Field September 2013 + + + method over another. Instead, the MUA or downstream filter consuming + this header field is to interpret the result of each method based on + its own knowledge of what that method evaluates. + + Each "method" MUST refer to an authentication method declared in the + IANA registry or an extension method as described in Section 2.6.6, + and each "result" MUST refer to a result code declared in the IANA + registry or an extension result code as defined in Section 2.6.7. + See Section 6 for further information about the registered methods + and result codes. + + An MTA compliant with this specification adds this header field + (after performing one or more message authentication tests) to + indicate which MTA or ADMD performed the test, which test got + applied, and what the result was. If an MTA applies more than one + such test, it adds this header field either once per test or once + indicating all of the results. An MTA MUST NOT add a result to an + existing header field. + + An MTA MAY add this header field containing only the authentication + identifier portion and the "none" token (see Section 2.2) to indicate + explicitly that no message authentication schemes were applied prior + to delivery of this message. + + An MTA adding this header field has to take steps to identify it as + legitimate to the MUAs or downstream filters that will ultimately + consume its content. One process to do so is described in Section 5. + Further measures may be necessary in some environments. Some + possible solutions are enumerated in Section 7.1. This document does + not mandate any specific solution to this issue as each environment + has its own facilities and limitations. + + Most known message authentication methods focus on a particular + identifier to evaluate. SPF and Sender ID differ in that they can + yield a result based on more than one identifier; specifically, SPF + can evaluate the RFC5321.HELO parameter or the RFC5321.MailFrom + parameter, and Sender ID can evaluate the RFC5321.MailFrom parameter + or the Purported Responsible Address (PRA) identity. When generating + this field to report those results, only the parameter that yielded + the result is included. + + For MTAs that add this header field, adding header fields in order + (at the top), per Section 3.6 of [MAIL], is particularly important. + Moreover, this header field SHOULD be inserted above any other trace + header fields such MTAs might prepend. This placement allows easy + detection of header fields that can be trusted. + + + + + +Kucherawy Standards Track [Page 21] + +RFC 7001 Authentication-Results Header Field September 2013 + + + End users making direct use of this header field might inadvertently + trust information that has not been properly vetted. If, for + example, a basic SPF result were to be relayed that claims an + authenticated addr-spec, the local-part of that addr-spec has + actually not been authenticated. Thus, an MTA adding this header + field SHOULD NOT include any data that has not been authenticated by + the method(s) being applied. Moreover, MUAs SHOULD NOT render to + users such information if it is presented by a method known not to + authenticate it. + +4.1. Header Field Position and Interpretation + + In order to ensure non-ambiguous results and avoid the impact of + false header fields, MUAs and downstream filters SHOULD NOT interpret + this header field unless specifically configured to do so by the user + or administrator. That is, this interpretation should not be "on by + default". Naturally then, users or administrators ought not activate + such a feature unless they are certain the header field will be + validly added by an agent within the ADMD that accepts the mail that + is ultimately read by the MUA, and instances of the header field + appearing to originate within the ADMD but are actually added by + foreign MTAs will be removed before delivery. + + Furthermore, MUAs and downstream filters SHOULD NOT interpret this + header field unless the authentication service identifier it bears + appears to be one used within its own ADMD as configured by the user + or administrator. + + MUAs and downstream filters MUST ignore any result reported using a + "result" not specified in the IANA "Result Code" registry or a + "ptype" not listed in the corresponding registry for such values as + defined in Section 6. Moreover, such agents MUST ignore a result + indicated for any "method" they do not specifically support. + + An MUA SHOULD NOT reveal these results to end users, absent careful + human factors design considerations and testing, for the presentation + of trust-related materials. For example, an attacker could register + examp1e.com (note the digit "one") and send signed mail to intended + victims; a verifier would detect that the signature was valid and + report a "pass" even though it's clear the DNS domain name was + intended to mislead. See Section 7.2 for further discussion. + + As stated in Section 2.1, this header field MUST be treated as though + it were a trace header field as defined in Section 3.6.7 of [MAIL] + and hence MUST NOT be reordered and MUST be prepended to the message, + so that there is generally some indication upon delivery of where in + the chain of handling MTAs the message authentication was done. + + + + +Kucherawy Standards Track [Page 22] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Note that there are a few message handlers that are only capable of + appending new header fields to a message. Strictly speaking, these + handlers are not compliant with this specification. They can still + add the header field to carry authentication details, but any signal + about where in the handling chain the work was done may be lost. + Consumers SHOULD be designed such that this can be tolerated, + especially from a producer known to have this limitation. + + MUAs SHOULD ignore instances of this header field discovered within + message/rfc822 MIME attachments. + + Further discussion of these topics can be found in Section 7 below. + +4.2. Local Policy Enforcement + + Some sites have a local policy that considers any particular + authentication policy's non-recoverable failure results (typically + "fail" or similar) as justification for rejecting the message. In + such cases, the border MTA SHOULD issue an SMTP rejection response to + the message, rather than adding this header field and allowing the + message to proceed toward delivery. This is more desirable than + allowing the message to reach an internal host's MTA or spam filter, + thus possibly generating a local rejection such as a Delivery Status + Notification (DSN) [DSN] to a forged originator. Such generated + rejections are colloquially known as "backscatter". + + The same MAY also be done for local policy decisions overriding the + results of the authentication methods (e.g., the "policy" result + codes described in Section 2.6). + + Such rejections at the SMTP protocol level are not possible if local + policy is enforced at the MUA and not the MTA. + +5. Removing Existing Header Fields + + For security reasons, any MTA conforming to this specification MUST + delete any discovered instance of this header field that claims, by + virtue of its authentication service identifier, to have been added + within its trust boundary but that did not come directly from another + trusted MTA. For example, an MTA for example.com receiving a message + MUST delete or otherwise obscure any instance of this header field + bearing an authentication service identifier indicating that the + header field was added within example.com prior to adding its own + header fields. This could mean each MTA will have to be equipped + with a list of internal MTAs known to be compliant (and hence + trustworthy). + + + + + +Kucherawy Standards Track [Page 23] + +RFC 7001 Authentication-Results Header Field September 2013 + + + For simplicity and maximum security, a border MTA could remove all + instances of this header field on mail crossing into its trust + boundary. However, this may conflict with the desire to access + authentication results performed by trusted external service + providers. It may also invalidate signed messages whose signatures + cover external instances of this header field. A more robust border + MTA could allow a specific list of authenticating MTAs whose + information is to be admitted, removing the header field originating + from all others. + + As stated in Section 1.2, a formal definition of "trust boundary" is + deliberately not made here. It is entirely possible that a border + MTA for example.com will explicitly trust authentication results + asserted by upstream host example.net even though they exist in + completely disjoint administrative boundaries. In that case, the + border MTA MAY elect not to delete those results; moreover, the + upstream host doing some authentication work could apply a signing + technology such as [DKIM] on its own results to assure downstream + hosts of their authenticity. An example of this is provided in + Appendix C. + + Similarly, in the case of messages signed using [DKIM] or other + message-signing methods that sign header fields, this removal action + could invalidate one or more signatures on the message if they + covered the header field to be removed. This behavior can be + desirable since there's little value in validating the signature on a + message with forged header fields. However, signing agents MAY + therefore elect to omit these header fields from signing to avoid + this situation. + + An MTA SHOULD remove any instance of this header field bearing a + version (express or implied) that it does not support. However, an + MTA MUST remove such a header field if the [SMTP] connection relaying + the message is not from a trusted internal MTA. This means the MTA + needs to be able to understand versions of this header field at least + as late as the ones understood by the MUAs or other consumers within + its ADMD. + +6. IANA Considerations + + IANA has registered the defined header field and created two tables + as described below. These registry actions were originally defined + by [RFC5451] and are repeated here to provide a single, current + reference. + + + + + + + +Kucherawy Standards Track [Page 24] + +RFC 7001 Authentication-Results Header Field September 2013 + + +6.1. The Authentication-Results Header Field + + [RFC5451] added the Authentication-Results header field to the IANA + "Permanent Message Header Field Names" registry, per the procedure + found in [IANA-HEADERS]. That entry has been updated to reference + this document. The following is the registration template: + + Header field name: Authentication-Results + Applicable protocol: mail ([MAIL]) + Status: Standard + Author/Change controller: IETF + Specification document(s): RFC 7001 + Related information: + Requesting review of any proposed changes and additions to + this field is recommended. + +6.2. "Email Authentication Methods" Registry + + Names of message authentication methods supported by this + specification are to be registered with IANA, with the exception of + experimental names as described in Section 2.6.6. A registry was + created by [RFC5451] for this purpose. This document changes the + rules governing that registry. + + New entries are assigned only for values that have received Expert + Review, per [IANA-CONSIDERATIONS]. The designated expert shall be + appointed by the IESG. The designated expert has discretion to + request that a publication be referenced if a clear, concise + definition of the authentication method cannot be provided such that + interoperability is assured. Registrations should otherwise be + permitted. The designated expert can also handle requests to mark + any current registration as "deprecated". + + Each method must register a name, the specification that defines it, + a version number associated with the method being registered + (preferably starting at "1"), zero or more "ptype" values appropriate + for use with that method, which "property" value(s) should be + reported by that method, and a description of the "value" to be used + with each. + + All existing registry entries that reference [RFC5451] have been + updated to reference this document, except where entries have already + been deprecated. + + IANA has also added a "version" field to all existing registry + entries. All current methods are recorded as version "1". + + + + + +Kucherawy Standards Track [Page 25] + +RFC 7001 Authentication-Results Header Field September 2013 + + +6.3. "Email Authentication Result Names" Registry + + Names of message authentication result codes supported by this + specification must be registered with IANA, with the exception of + experimental codes as described in Section 2.6.7. A registry was + created by [RFC5451] for this purpose. This document changes the + rules governing that registry. + + New entries are assigned only for values that have received Expert + Review, per [IANA-CONSIDERATIONS]. The designated expert shall be + appointed by the IESG. The designated expert has discretion to + request that a publication be referenced if a clear, concise + definition of the authentication result cannot be provided such that + interoperability is assured. Registrations should otherwise be + permitted. The designated expert can also handle requests to mark + any current registration as "deprecated". + + All existing registry entries that reference [RFC5451] have been + updated to reference this document. + + The definitions for the SPF and Sender ID authentication methods are + updated using the references found in Section 2.6.2. + +7. Security Considerations + + The following security considerations apply when adding or processing + the Authentication-Results header field: + +7.1. Forged Header Fields + + An MUA or filter that accesses a mailbox whose messages are handled + by a non-conformant MTA, and understands Authentication-Results + header fields, could potentially make false conclusions based on + forged header fields. A malicious user or agent could forge a header + field using the DNS domain of a receiving ADMD as the authserv-id + token in the value of the header field and, with the rest of the + value, claim that the message was properly authenticated. The non- + conformant MTA would fail to strip the forged header field, and the + MUA could inappropriately trust it. + + For this reason, it is best not to have processing of the + Authentication-Results header field enabled by default; instead, it + should be ignored, at least for the purposes of enacting filtering + decisions, unless specifically enabled by the user or administrator + after verifying that the border MTA is compliant. It is acceptable + to have an MUA aware of this specification but have an explicit list + of hostnames whose Authentication-Results header fields are + trustworthy; however, this list should initially be empty. + + + +Kucherawy Standards Track [Page 26] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Proposed alternative solutions to this problem were made some time + ago and are listed below. To date, they have not been developed due + to lack of demand but are documented here should the information be + useful at some point in the future: + + 1. Possibly the simplest is a digital signature protecting the + header field, such as using [DKIM], that can be verified by an + MUA by using a posted public key. Although one of the main + purposes of this document is to relieve the burden of doing + message authentication work at the MUA, this only requires that + the MUA learn a single authentication scheme even if a number of + them are in use at the border MTA. Note that [DKIM] requires + that the From header field be signed, although in this + application, the signing agent (a trusted MTA) likely cannot + authenticate that value, so the fact that it is signed should be + ignored. Where the authserv-id is the ADMD's domain name, the + authserv-id matching this valid internal signature's "d=" DKIM + value is sufficient. + + 2. Another would be a means to interrogate the MTA that added the + header field to see if it is actually providing any message + authentication services and saw the message in question, but this + isn't especially palatable given the work required to craft and + implement such a scheme. + + 3. Yet another might be a method to interrogate the internal MTAs + that apparently handled the message (based on Received header + fields) to determine whether any of them conform to Section 5 of + this memo. This, too, has potentially high barriers to entry. + + 4. Extensions to [IMAP], [SMTP], and [POP3] could be defined to + allow an MUA or filtering agent to acquire the authserv-id in use + within an ADMD, thus allowing it to identify which + Authentication-Results header fields it can trust. + + 5. On the presumption that internal MTAs are fully compliant with + Section 3.6 of [MAIL] and the compliant internal MTAs are using + their own hostnames or the ADMD's DNS domain name as the + authserv-id token, the header field proposed here should always + appear above a Received header added by a trusted MTA. This can + be used as a test for header field validity. + + Support for some of these is being considered for future work. + + In any case, a mechanism needs to exist for an MUA or filter to + verify that the host that appears to have added the header field (a) + actually did so and (b) is legitimately adding that header field for + + + + +Kucherawy Standards Track [Page 27] + +RFC 7001 Authentication-Results Header Field September 2013 + + + this delivery. Given the variety of messaging environments deployed + today, consensus appears to be that specifying a particular mechanism + for doing so is not appropriate for this document. + + Mitigation of the forged header field attack can also be accomplished + by moving the authentication results data into metadata associated + with the message. In particular, an [SMTP] extension could be + established to communicate authentication results from the border MTA + to intermediate and delivery MTAs; the latter of these could arrange + to store the authentication results as metadata retrieved and + rendered along with the message by an [IMAP] client aware of a + similar extension in that protocol. The delivery MTA would be told + to trust data via this extension only from MTAs it trusts, and border + MTAs would not accept data via this extension from any source. There + is no vector in such an arrangement for forgery of authentication + data by an outside agent. + +7.2. Misleading Results + + Until some form of service for querying the reputation of a sending + agent is widely deployed, the existence of this header field + indicating a "pass" does not render the message trustworthy. It is + possible for an arriving piece of spam or other undesirable mail to + pass checks by several of the methods enumerated above (e.g., a piece + of spam signed using [DKIM] by the originator of the spam, which + might be a spammer or a compromised system). In particular, this + issue is not resolved by forged header field removal discussed above. + + Hence, MUAs and downstream filters must take some care with use of + this header even after possibly malicious headers are scrubbed. + +7.3. Header Field Position + + Despite the requirements of [MAIL], header fields can sometimes be + reordered en route by intermediate MTAs. The goal of requiring + header field addition only at the top of a message is an + acknowledgement that some MTAs do reorder header fields, but most do + not. Thus, in the general case, there will be some indication of + which MTAs (if any) handled the message after the addition of the + header field defined here. + +7.4. Reverse IP Query Denial-of-Service Attacks + + Section 5.5 of [SPF] describes a DNS-based denial-of-service attack + for verifiers that attempt DNS-based identity verification of + arriving client connections. A verifier wishing to do this check and + report this information needs to take care not to go to unbounded + lengths to resolve "A" and "PTR" queries. MUAs or other filters + + + +Kucherawy Standards Track [Page 28] + +RFC 7001 Authentication-Results Header Field September 2013 + + + making use of an "iprev" result specified by this document need to be + aware of the algorithm used by the verifier reporting the result and, + especially, its limitations. + +7.5. Mitigation of Backscatter + + Failing to follow the instructions of Section 4.2 can result in a + denial-of-service attack caused by the generation of [DSN] messages + (or equivalent) to addresses that did not send the messages being + rejected. + +7.6. Internal MTA Lists + + Section 5 describes a procedure for scrubbing header fields that may + contain forged authentication results about a message. A compliant + installation will have to include, at each MTA, a list of other MTAs + known to be compliant and trustworthy. Failing to keep this list + current as internal infrastructure changes may expose an ADMD to + attack. + +7.7. Attacks against Authentication Methods + + If an attack becomes known against an authentication method, clearly + then the agent verifying that method can be fooled into thinking an + inauthentic message is authentic, and thus the value of this header + field can be misleading. It follows that any attack against the + authentication methods supported by this document is also a security + consideration here. + +7.8. Intentionally Malformed Header Fields + + It is possible for an attacker to add an Authentication-Results + header field that is extraordinarily large or otherwise malformed in + an attempt to discover or exploit weaknesses in header field parsing + code. Implementers must thoroughly verify all such header fields + received from MTAs and be robust against intentionally as well as + unintentionally malformed header fields. + +7.9. Compromised Internal Hosts + + An internal MUA or MTA that has been compromised could generate mail + with a forged From header field and a forged Authentication-Results + header field that endorses it. Although it is clearly a larger + concern to have compromised internal machines than it is to prove the + value of this header field, this risk can be mitigated by arranging + that internal MTAs will remove this header field if it claims to have + been added by a trusted border MTA (as described above), yet the + [SMTP] connection is not coming from an internal machine known to be + + + +Kucherawy Standards Track [Page 29] + +RFC 7001 Authentication-Results Header Field September 2013 + + + running an authorized MTA. However, in such a configuration, + legitimate MTAs will have to add this header field when legitimate + internal-only messages are generated. This is also covered in + Section 5. + +7.10. Encapsulated Instances + + MIME messages can contain attachments of type "message/rfc822", which + contain other messages. Such an encapsulated message can also + contain an Authentication-Results header field. Although the + processing of these is outside of the intended scope of this document + (see Section 1.3), some early guidance to MUA developers is + appropriate here. + + Since MTAs are unlikely to strip Authentication-Results header fields + after mailbox delivery, MUAs are advised in Section 4.1 to ignore + such instances within MIME attachments. Moreover, when extracting a + message digest to separate mail store messages or other media, such + header fields should be removed so that they will never be + interpreted improperly by MUAs that might later consume them. + +7.11. Reverse Mapping + + Although Section 3 of this memo includes explicit support for the + "iprev" method, its value as an authentication mechanism is limited. + Implementers of both this proposal and agents that use the data it + relays are encouraged to become familiar with the issues raised by + [DNSOP-REVERSE] when deciding whether or not to include support for + "iprev". + +8. References + +8.1. Normative References + + [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008. + + [IANA-HEADERS] + Klyne, G., Nottingham, M., and J. Mogul, "Registration + Procedures for Message Header Fields", BCP 90, RFC 3864, + September 2004. + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [MAIL] Resnick, P., Ed., "Internet Message Format", RFC 5322, + October 2008. + + + + +Kucherawy Standards Track [Page 30] + +RFC 7001 Authentication-Results Header Field September 2013 + + + [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, November 1996. + + [SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, + October 2008. + +8.2. Informative References + + [ADSP] Allman, E., Fenton, J., Delany, M., and J. Levine, + "DomainKeys Identified Mail (DKIM) Author Domain Signing + Practices (ADSP)", RFC 5617, August 2009. + + [AR-VBR] Kucherawy, M., "Authentication-Results Registration for + Vouch by Reference Results", RFC 6212, April 2011. + + [ATPS] Kucherawy, M., "DomainKeys Identified Mail (DKIM) + Authorized Third-Party Signatures", RFC 6541, + February 2012. + + [AUTH] Siemborski, R. and A. Melnikov, "SMTP Service Extension + for Authentication", RFC 4954, July 2007. + + [DKIM] Crocker, D., Hansen, T., and M. Kucherawy, "DomainKeys + Identified Mail (DKIM) Signatures", STD 76, RFC 6376, + September 2011. + + [DNS] Mockapetris, P., "Domain names - implementation and + specification", STD 13, RFC 1035, November 1987. + + [DNS-IP6] Thomson, S., Huitema, C., Ksinant, V., and M. Souissi, + "DNS Extensions to Support IP Version 6", RFC 3596, + October 2003. + + [DNSOP-REVERSE] + Senie, D. and A. Sullivan, "Considerations for the use of + DNS Reverse Mapping", Work in Progress, March 2008. + + [DOMAINKEYS] + Delany, M., "Domain-Based Email Authentication Using + Public Keys Advertised in the DNS (DomainKeys)", RFC 4870, + May 2007. + + [DSN] Moore, K. and G. Vaudreuil, "An Extensible Message Format + for Delivery Status Notifications", RFC 3464, + January 2003. + + + + + +Kucherawy Standards Track [Page 31] + +RFC 7001 Authentication-Results Header Field September 2013 + + + [EMAIL-ARCH] + Crocker, D., "Internet Mail Architecture", RFC 5598, + July 2009. + + [IANA-CONSIDERATIONS] + Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 5226, + May 2008. + + [IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION + 4rev1", RFC 3501, March 2003. + + [POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", + STD 53, RFC 1939, May 1996. + + [RFC5451] Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", RFC 5451, April 2009. + + [SECURITY] Rescorla, E. and B. Korver, "Guidelines for Writing RFC + Text on Security Considerations", BCP 72, RFC 3552, + July 2003. + + [SENDERID] Lyon, J. and M. Wong, "Sender ID: Authenticating E-Mail", + RFC 4406, April 2006. + + [SPF] Wong, M. and W. Schlitt, "Sender Policy Framework (SPF) + for Authorizing Use of Domains in E-Mail, Version 1", + RFC 4408, April 2006. + + [VBR] Hoffman, P., Levine, J., and A. Hathcock, "Vouch By + Reference", RFC 5518, April 2009. + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 32] + +RFC 7001 Authentication-Results Header Field September 2013 + + +Appendix A. Acknowledgements + + The author wishes to acknowledge the following individuals for their + review and constructive criticism of this document: Dave Cridland, + Dave Crocker, Bjoern Hoehrmann, Scott Kitterman, John Levine, Alexey + Melnikov, S. Moonesamy, and Alessandro Vesely. + +Appendix B. Legacy MUAs + + Implementers of this protocol should be aware that many MUAs are + unlikely to be retrofitted to support the new header field and its + semantics. In the interests of convenience and quicker adoption, a + delivery MTA might want to consider adding things that are processed + by existing MUAs in addition to the Authentication-Results header + field. One suggestion is to include a Priority header field, on + messages that don't already have such a header field, containing a + value that reflects the strength of the authentication that was + accomplished, e.g., "low" for weak or no authentication, "normal" or + "high" for good or strong authentication. + + Some modern MUAs can already filter based on the content of this + header field. However, there is keen interest in having MUAs make + some kind of graphical representation of this header field's meaning + to end users. Until this capability is added, other interim means of + conveying authentication results may be necessary while this proposal + and its successors are adopted. + +Appendix C. Authentication-Results Examples + + This section presents some examples of the use of this header field + to indicate authentication results. + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 33] + +RFC 7001 Authentication-Results Header Field September 2013 + + +C.1. Trivial Case; Header Field Not Present + + The trivial case: + + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 1: Trivial Case + + The Authentication-Results header field is completely absent. The + MUA may make no conclusion about the validity of the message. This + could be the case because the message authentication services were + not available at the time of delivery, or no service is provided, or + the MTA is not in compliance with this specification. + +C.2. Nearly Trivial Case; Service Provided, but No Authentication Done + + A message that was delivered by an MTA that conforms to this + specification but provides no actual message authentication service: + + Authentication-Results: example.org 1; none + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 2: Header Present but No Authentication Done + + + + + + +Kucherawy Standards Track [Page 34] + +RFC 7001 Authentication-Results Header Field September 2013 + + + The Authentication-Results header field is present, showing that the + delivering MTA conforms to this specification. It used its DNS + domain name as the authserv-id. The presence of "none" (and the + absence of any method and result tokens) indicates that no message + authentication was done. The version number of the specification to + which the field's content conforms is explicitly provided. + +C.3. Service Provided, Authentication Done + + A message that was delivered by an MTA that conforms to this + specification and applied some message authentication: + + Authentication-Results: example.com; + spf=pass smtp.mailfrom=example.net + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.net + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.net> + Subject: here's a sample + + Hello! Goodbye! + + Example 3: Header Reporting Results + + The Authentication-Results header field is present, indicating that + the border MTA conforms to this specification. The authserv-id is + once again the DNS domain name. Furthermore, the message was + authenticated by that MTA via the method specified in [SPF]. Note + that since that method cannot authenticate the local-part, it has + been omitted from the result's value. The MUA could extract and + relay this extra information if desired. + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 35] + +RFC 7001 Authentication-Results Header Field September 2013 + + +C.4. Service Provided, Several Authentications Done, Single MTA + + A message that was relayed inbound via a single MTA that conforms to + this specification and applied three different message authentication + checks: + + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.net; + spf=pass smtp.mailfrom=example.net + Authentication-Results: example.com; + sender-id=pass header.from=example.net + Received: from dialup-1-2-3-4.example.net (8.11.6/8.11.6) + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + From: sender@example.net + Message-Id: <12345.abc@example.net> + Subject: here's a sample + + Hello! Goodbye! + + Example 4: Headers Reporting Results from One MTA + + The Authentication-Results header field is present, indicating that + the delivering MTA conforms to this specification. Once again, the + receiving DNS domain name is used as the authserv-id. Furthermore, + the sender authenticated herself/himself to the MTA via a method + specified in [AUTH], and both SPF and Sender ID checks were done and + passed. The MUA could extract and relay this extra information if + desired. + + Two Authentication-Results header fields are not required since the + same host did all of the checking. The authenticating agent could + have consolidated all the results into one header field. + + This example illustrates a scenario in which a remote user on a + dialup connection (example.net) sends mail to a border MTA + (example.com) using SMTP authentication to prove identity. The + dialup provider has been explicitly authorized to relay mail as + example.com resulting in passes by the SPF and Sender ID checks. + + + + + + + + +Kucherawy Standards Track [Page 36] + +RFC 7001 Authentication-Results Header Field September 2013 + + +C.5. Service Provided, Several Authentications Done, Different MTAs + + A message that was relayed inbound by two different MTAs that conform + to this specification and applied multiple message authentication + checks: + + Authentication-Results: example.com; + sender-id=fail header.from=example.com; + dkim=pass (good signature) header.d=example.com + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by auth-checker.example.com (8.11.6/8.11.6) + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; d=example.com; + t=1188964191; c=simple/simple; h=From:Date:To:Subject: + Message-Id:Authentication-Results; + bh=sEuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m70; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.com; + spf=fail smtp.mailfrom=example.com + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 5: Headers Reporting Results from Multiple MTAs + + The Authentication-Results header field is present, indicating + conformance to this specification. Once again, the authserv-id used + is the recipient's DNS domain name. The header field is present + twice because two different MTAs in the chain of delivery did + authentication tests. The first MTA, mail-router.example.com, + reports that SMTP AUTH and SPF were both used and that the former + passed while the latter failed. In the SMTP AUTH case, additional + information is provided in the comment field, which the MUA can + choose to render if desired. + + + + + +Kucherawy Standards Track [Page 37] + +RFC 7001 Authentication-Results Header Field September 2013 + + + The second MTA, auth-checker.example.com, reports that it did a + Sender ID test (which failed) and a DKIM test (which passed). Again, + additional data about one of the tests is provided as a comment, + which the MUA may choose to render. Also noteworthy here is the fact + that there is a DKIM signature added by example.com that assured the + integrity of the lower Authentication-Results field. + + Since different hosts did the two sets of authentication checks, the + header fields cannot be consolidated in this example. + + This example illustrates more typical transmission of mail into + example.com from a user on a dialup connection example.net. The user + appears to be legitimate as he/she had a valid password allowing + authentication at the border MTA using SMTP AUTH. The SPF and Sender + ID tests failed since example.com has not granted example.net + authority to relay mail on its behalf. However, the DKIM test passed + because the sending user had a private key matching one of + example.com's published public keys and used it to sign the message. + +C.6. Service Provided, Multi-Tiered Authentication Done + + A message that had authentication done at various stages, one of + which was outside the receiving ADMD: + + Authentication-Results: example.com; + dkim=pass reason="good signature" + header.i=@mail-router.example.net; + dkim=fail reason="bad signature" + header.i=@newyork.example.com + Received: from mail-router.example.net + (mail-router.example.net [192.0.2.250]) + by chicago.example.com (8.11.6/8.11.6) + for + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=furble; + d=mail-router.example.net; t=1188964198; c=relaxed/simple; + h=From:Date:To:Message-Id:Subject:Authentication-Results; + bh=ftA9J6GtX8OpwUECzHnCkRzKw1uk6FNiLfJl5Nmv49E=; + b=oINEO8hgn/gnunsg ... 9n9ODSNFSDij3= + Authentication-Results: example.net; + dkim=pass (good signature) header.i=@newyork.example.com + Received: from smtp.newyork.example.com + (smtp.newyork.example.com [192.0.2.220]) + by mail-router.example.net (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; + + + +Kucherawy Standards Track [Page 38] + +RFC 7001 Authentication-Results Header Field September 2013 + + + d=newyork.example.com; + t=1188964191; c=simple/simple; + h=From:Date:To:Message-Id:Subject; + bh=sEu28nfs9fuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m7=; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + From: sender@newyork.example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: meetings@example.net + Message-Id: <12345.abc@newyork.example.com> + Subject: here's a sample + + Example 6: Headers Reporting Results from Multiple MTAs + in Different ADMDs + + In this example, we see multi-tiered authentication with an extended + trust boundary. + + The message was sent from someone at example.com's New York office + (newyork.example.com) to a mailing list managed at an intermediary. + The message was signed at the origin using DKIM. + + The message was sent to a mailing list service provider called + example.net, which is used by example.com. There, + meetings@example.net is expanded to a long list of recipients, one of + whom is at the Chicago office. In this example, we will assume that + the trust boundary for chicago.example.com includes the mailing list + server at example.net. + + The mailing list server there first authenticated the message and + affixed an Authentication-Results header field indicating such using + its DNS domain name for the authserv-id. It then altered the message + by affixing some footer text to the body, including some + administrivia such as unsubscription instructions. Finally, the + mailing list server affixes a second DKIM signature and begins + distribution of the message. + + The border MTA for chicago.example.com explicitly trusts results from + mail-router.example.net, so that header field is not removed. It + performs evaluation of both signatures and determines that the first + (most recent) is a "pass" but, because of the aforementioned + modifications, the second is a "fail". However, the first signature + included the Authentication-Results header added at mail- + router.example.net that validated the second signature. Thus, + indirectly, it can be determined that the authentications claimed by + both signatures are indeed valid. + + + + + + +Kucherawy Standards Track [Page 39] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Note that two styles of presenting metadata about the result are in + use here. In one case, the "reason=" clause is present, which is + intended for easy extraction by parsers; in the other case, the CFWS + production of the ABNF is used to include such data as a header field + comment. The latter can be harder for parsers to extract given the + varied supported syntaxes of mail header fields. + +C.7. Comment-Heavy Example + + The formal syntax permits comments within the content in a number of + places. For the sake of illustration, this example is also legal: + + Authentication-Results: foo.example.net (foobar) 1 (baz); + dkim (Because I like it) / 1 (One yay) = (wait for it) fail + policy (A dot can go here) . (like that) expired + (this surprised me) = (as I wasn't expecting it) 1362471462 + + Example 7: A Very Comment-Heavy but Perfectly Legal Example + +Appendix D. Operational Considerations about Message Authentication + + This protocol is predicated on the idea that authentication (and + presumably in the future, reputation) work is typically done by + border MTAs rather than MUAs or intermediate MTAs; the latter merely + make use of the results determined by the former. Certainly this is + not mandatory for participation in electronic mail or message + authentication, but this protocol and its deployment to date are + based on that model. The assumption satisfies several common ADMD + requirements: + + 1. Service operators prefer to resolve the handling of problem + messages as close to the border of the ADMD as possible. This + enables, for example, rejection of messages at the SMTP level + rather than generating a DSN internally. Thus, doing any of the + authentication or reputation work exclusively at the MUA or + intermediate MTA renders this desire unattainable. + + 2. Border MTAs are more likely to have direct access to external + sources of authentication or reputation information since modern + MUAs are more likely to be heavily firewalled. Thus, some MUAs + might not even be able to complete the task of performing + authentication or reputation evaluations without complex proxy + configurations or similar burdens. + + + + + + + + +Kucherawy Standards Track [Page 40] + +RFC 7001 Authentication-Results Header Field September 2013 + + + 3. MUAs rely upon the upstream MTAs within their trust boundaries to + make correct (as much as is possible) evaluations about the + message's envelope, header, and content. Thus, MUAs don't need + to know how to do the work that upstream MTAs do; they only need + the results of that work. + + 4. Evaluations about the quality of a message, from simple token + matching (e.g., a list of preferred DNS domains) to cryptanalysis + (e.g., public/private key work), are at least a little bit + expensive and thus need to be minimized. To that end, performing + those tests at the border MTA is far preferred to doing that work + at each MUA that handles a message. If an ADMD's environment + adheres to common messaging protocols, a reputation query or an + authentication check performed by a border MTA would return the + same result as the same query performed by an MUA. By contrast, + in an environment where the MUA does the work, a message arriving + for multiple recipients would thus cause authentication or + reputation evaluation to be done more than once for the same + message (i.e., at each MUA), causing needless amplification of + resource use and creating a possible denial-of-service attack + vector. + + 5. Minimizing change is good. As new authentication and reputation + methods emerge, the list of methods supported by this header + field would presumably be extended. If MUAs simply consume the + contents of this header field rather than actually attempt to do + authentication and/or reputation work, then MUAs only need to + learn to parse this header field once; emergence of new methods + requires only a configuration change at the MUAs and software + changes at the MTAs (which are presumably fewer in number). When + choosing to implement these functions in MTAs vs. MUAs, the + issues of individual flexibility, infrastructure inertia, and + scale of effort must be considered. It is typically easier to + change a single MUA than an MTA because the modification affects + fewer users and can be pursued with less care. However, changing + many MUAs is more effort than changing a smaller number of MTAs. + + 6. For decisions affecting message delivery and display, assessment + based on authentication and reputation is best performed close to + the time of message transit, as a message makes its journey + toward a user's inbox, not afterwards. DKIM keys and IP address + reputations, etc., can change over time or even become invalid, + and users can take a long time to read a message once delivered. + The value of this work thus degrades, perhaps quickly, once the + delivery process has completed. This seriously diminishes the + value of this work when done other than at MTAs. + + + + + +Kucherawy Standards Track [Page 41] + +RFC 7001 Authentication-Results Header Field September 2013 + + + Many operational choices are possible within an ADMD, including the + venue for performing authentication and/or reputation assessment. + The current specification does not dictate any of those choices. + Rather, it facilitates those cases in which information produced by + one stage of analysis needs to be transported with the message to the + next stage. + +Appendix E. Changes since RFC 5451 + + o Erratum #2617 was addressed in RFC 6577 and was incorporated here. + + o Requested Internet Standard status. + + o Changed IANA rules from "IETF Review" to "designated expert". + + o Updated existing IANA registries from the old RFC to this one. + + o Added references to ADSP, ATPS, and VBR. + + o Removed all the "X-" stuff, per BCP 178. + + o Adjusted language to indicate that this header field was already + defined and that we're just refreshing and revising. + + o In a few places, RFC 2119 language had been used in lowercase + terms; fixed here. + + o Erratum #2818 addressed. + + o Erratum #3195 addressed. + + o Performed some minor wordsmithing and removed odd prose. + + o ABNF: changed "dot-atom" to "Keyword" since "dot-atom" allows "=", + which leads to ambiguous productions. + + o ABNF: the authserv-id can be a "value", not a "dot-atom". + + o ABNF: separated the spec version from the method version; they're + syntactically the same but semantically different. Added a + section discussing them. + + o Called out the SMTP verb exceptions ("mailfrom" and "rcptto"); the + previous RFC didn't do this, leading to interoperability problems. + + o Rather than deleting suspect header fields, they could also be + renamed to something harmless; there is at least one + implementation of this. + + + +Kucherawy Standards Track [Page 42] + +RFC 7001 Authentication-Results Header Field September 2013 + + + o Updated IANA "Email Authentication Methods" registry to include + version numbers. + + o Rather than repeating what RFC 4408 says the SPF results are, just + referred to those documents. + + o To avoid confusing consumers, constrained inclusion of unnecessary + properties. + + o Reviewed usage of "should" vs. "SHOULD". + + o Updated prose around authserv-id (Section 2.4). + +Author's Address + + Murray S. Kucherawy + 270 Upland Drive + San Francisco, CA 94127 + US + + EMail: superuser@gmail.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 43] + diff --git a/rfc/rfc7410.txt b/rfc/rfc7410.txt new file mode 100644 index 0000000000..ed3c0434b7 --- /dev/null +++ b/rfc/rfc7410.txt @@ -0,0 +1,283 @@ + + + + + + +Internet Engineering Task Force (IETF) M. Kucherawy +Request for Comments: 7410 December 2014 +Updates: 7001 +Category: Standards Track +ISSN: 2070-1721 + + + A Property Types Registry for the Authentication-Results Header Field + +Abstract + + This document updates RFC 7001 by creating a registry for property + types in the Authentication-Results header field, used in email + authentication work, rather than limiting participants to using the + original, small set of fixed values. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc7410. + +Copyright Notice + + Copyright (c) 2014 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + +Kucherawy Standards Track [Page 1] + +RFC 7410 Authentication-Results Property Types December 2014 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Updated "ptype" Definition . . . . . . . . . . . . . . . . . 2 + 3. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 3 + 4. Security Considerations . . . . . . . . . . . . . . . . . . . 4 + 5. Normative References . . . . . . . . . . . . . . . . . . . . 5 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 5 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 5 + +1. Introduction + + [RFC7001] defines the email Authentication-Results header field that + presents the results of an authentication effort in a machine- + readable format. The header field creates a place to collect the + output from authentication processes that are disjoint from later + processes that might use the output, such as analysis, filtering, or + sorting mechanisms. + + The specification in that document enumerated a small set of types of + properties that can be reported using this mechanism. There has + emerged a desire to report types of properties about a message + through this mechanism. Accordingly, this document updates the + specification to allow for additional property types ("ptypes") + beyond the original set and creates a registry where new ones can be + listed and their defining documents referenced. + +2. Updated "ptype" Definition + + Advanced Backus Naur Form (ABNF) is defined in [RFC5234]. + + The ABNF in Section 2.2 of [RFC7001] is updated as follows: + + ptype = Keyword + ; indicates whether the property being evaluated was + ; a parameter to an [SMTP] command, was a value taken + ; from a message header field, was some property of + ; the message body, or was some other property evaluated by + ; the receiving Message Transfer Agent (MTA) + + The ABNF token "Keyword" is defined in Section 4.1.2 of [RFC5321]. + + + + + + + + + + +Kucherawy Standards Track [Page 2] + +RFC 7410 Authentication-Results Property Types December 2014 + + + Legal values of "ptype" are as defined in the IANA "Email + Authentication Property Types" registry (see Section 3). The initial + values are as follows, matching those defined in [RFC7001]: + + body: Indicates information that was extracted from the body of the + message. This might be an arbitrary string of bytes, a hash of a + string of bytes, a Uniform Resource Identifier, or some other + content of interest. + + header: Indicates information that was extracted from the header of + the message. This might be the value of a header field or some + portion of a header field. + + policy: A local policy mechanism was applied that augments or + overrides the result returned by the authentication mechanism. + See Section 2.3 of [RFC7001]. + + smtp: Indicates information that was extracted from an SMTP command + that was used to relay the message. + + When a consumer of this header field encounters a "ptype" that it + does not understand, it ignores the result reported with that + "ptype". + +3. IANA Considerations + + IANA has created the "Email Authentication Property Types" sub- + registry within the existing "Email Authentication Parameters" + registry. Entries in this registry are subject to the Expert Review + rules as described in [RFC5226]. Each entry in the registry requires + the following values: + + o The "ptype" token to be registered, which must fit within the ABNF + described in Section 2. + + o A brief description of what sort of information this "ptype" is + meant to cover. + + o An optional reference to the defining document. This is + recommended, but not required. + + + + + + + + + + + +Kucherawy Standards Track [Page 3] + +RFC 7410 Authentication-Results Property Types December 2014 + + + The initial entries in this table are as follows, taken from + [RFC7001]: + + +--------+-------------+----------------------------------------+ + | ptype | Definition | Description | + +--------+-------------+----------------------------------------+ + | body | RFC 7001 | The property being reported was found | + | | Section 2.2 | in the body of the message. | + +--------+-------------+----------------------------------------+ + | header | RFC 7001 | The property being reported was found | + | | Section 2.2 | in a header field of the message. | + +--------+-------------+----------------------------------------+ + | policy | RFC 7001 | The property being reported relates to | + | | Section 2.3 | a locally defined policy. | + +--------+-------------+----------------------------------------+ + | smtp | RFC 7001 | The property being reported is a | + | | Section 2.2 | parameter to an SMTP command used to | + | | | relay the message. | + +--------+-------------+----------------------------------------+ + + For new entries, the Designated Expert needs to assure that the + description provided for the new entry adequately describes the + intended use. An example would be helpful to include in the entry's + defining document, if any, although entries in the "Email + Authentication Methods" registry or the "Email Authentication Result + Names" registry might also serve as examples of intended use. + +4. Security Considerations + + It is unknown how legacy code, which expects one of a fixed set of + "ptype" tokens, will handle new tokens as they begin to appear. + There are typically two options: prevent delivery of the message, or + ignore those portions of the field that use unknown "ptype" tokens + and allow processing of the message to continue. + + The choice comes down to whether the consumer considers it a threat + when there are unknown "ptypes" present. The semantics of the report + are unknown; the report might be indicating the message is authentic, + fraudulent, or that a test failed to complete. The report itself is + not actionable because it cannot be understood, and only its presence + is certain. + + Generally, the advice in this situation is to ignore unknown + "ptypes". It is anticipated that a new property type evaluated by + earlier handling agents would also result in the filtering of + messages by those agents until consumers can be updated to interpret + them. + + + + +Kucherawy Standards Track [Page 4] + +RFC 7410 Authentication-Results Property Types December 2014 + + +5. Normative References + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 5226, + May 2008, . + + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008, + . + + [RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, + October 2008, . + + [RFC7001] Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", RFC 7001, September 2013, + . + +Acknowledgements + + The author wishes to acknowledge the following for their review and + constructive criticism of this update: Dave Crocker, Tim Draegen, + Scott Kitterman, and Franck Martin. + +Author's Address + + Murray S. Kucherawy + 270 Upland Drive + San Francisco, CA 94127 + United States + + EMail: superuser@gmail.com + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 5] + diff --git a/rfc/rfc7601.txt b/rfc/rfc7601.txt new file mode 100644 index 0000000000..0e4b6696ef --- /dev/null +++ b/rfc/rfc7601.txt @@ -0,0 +1,2971 @@ + + + + + + +Internet Engineering Task Force (IETF) M. Kucherawy +Request for Comments: 7601 August 2015 +Obsoletes: 7001, 7410 +Category: Standards Track +ISSN: 2070-1721 + + + Message Header Field for Indicating Message Authentication Status + +Abstract + + This document specifies a message header field called Authentication- + Results for use with electronic mail messages to indicate the results + of message authentication efforts. Any receiver-side software, such + as mail filters or Mail User Agents (MUAs), can use this header field + to relay that information in a convenient and meaningful way to users + or to make sorting and filtering decisions. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc7601. + +Copyright Notice + + Copyright (c) 2015 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + +Kucherawy Standards Track [Page 1] + +RFC 7601 Authentication-Results Header Field August 2015 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 + 1.1. Purpose . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.2. Trust Boundary . . . . . . . . . . . . . . . . . . . . . 5 + 1.3. Processing Scope . . . . . . . . . . . . . . . . . . . . 6 + 1.4. Requirements . . . . . . . . . . . . . . . . . . . . . . 6 + 1.5. Definitions . . . . . . . . . . . . . . . . . . . . . . . 6 + 1.5.1. Key Words . . . . . . . . . . . . . . . . . . . . . . 6 + 1.5.2. Security . . . . . . . . . . . . . . . . . . . . . . 7 + 1.5.3. Email Architecture . . . . . . . . . . . . . . . . . 7 + 1.5.4. Other Terms . . . . . . . . . . . . . . . . . . . . . 8 + 1.6. Trust Environment . . . . . . . . . . . . . . . . . . . . 8 + 2. Definition and Format of the Header Field . . . . . . . . . . 9 + 2.1. General Description . . . . . . . . . . . . . . . . . . . 9 + 2.2. Formal Definition . . . . . . . . . . . . . . . . . . . . 10 + 2.3. Property Types (ptypes) and Properties . . . . . . . . . 12 + 2.4. The "policy" ptype . . . . . . . . . . . . . . . . . . . 13 + 2.5. Authentication Identifier Field . . . . . . . . . . . . . 14 + 2.6. Version Tokens . . . . . . . . . . . . . . . . . . . . . 15 + 2.7. Defined Methods and Result Values . . . . . . . . . . . . 15 + 2.7.1. DKIM and DomainKeys . . . . . . . . . . . . . . . . . 16 + 2.7.2. SPF and Sender ID . . . . . . . . . . . . . . . . . . 18 + 2.7.3. "iprev" . . . . . . . . . . . . . . . . . . . . . . . 19 + 2.7.4. SMTP AUTH . . . . . . . . . . . . . . . . . . . . . . 20 + 2.7.5. Other Registered Codes . . . . . . . . . . . . . . . 21 + 2.7.6. Extension Methods . . . . . . . . . . . . . . . . . . 21 + 2.7.7. Extension Result Codes . . . . . . . . . . . . . . . 22 + 3. The "iprev" Authentication Method . . . . . . . . . . . . . . 22 + 4. Adding the Header Field to a Message . . . . . . . . . . . . 23 + 4.1. Header Field Position and Interpretation . . . . . . . . 25 + 4.2. Local Policy Enforcement . . . . . . . . . . . . . . . . 26 + 5. Removing Existing Header Fields . . . . . . . . . . . . . . . 26 + 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 27 + 6.1. The Authentication-Results Header Field . . . . . . . . . 27 + 6.2. "Email Authentication Methods" Registry Description . . . 28 + 6.3. "Email Authentication Methods" Registry Update . . . . . 29 + 6.4. "Email Authentication Property Types" Registry . . . . . 30 + 6.5. "Email Authentication Result Names" Description . . . . . 31 + 6.6. "Email Authentication Result Names" Update . . . . . . . 32 + 6.7. SMTP Enhanced Status Codes . . . . . . . . . . . . . . . 33 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 33 + 7.1. Forged Header Fields . . . . . . . . . . . . . . . . . . 33 + 7.2. Misleading Results . . . . . . . . . . . . . . . . . . . 35 + 7.3. Header Field Position . . . . . . . . . . . . . . . . . . 35 + 7.4. Reverse IP Query Denial-of-Service Attacks . . . . . . . 35 + 7.5. Mitigation of Backscatter . . . . . . . . . . . . . . . . 36 + 7.6. Internal MTA Lists . . . . . . . . . . . . . . . . . . . 36 + + + +Kucherawy Standards Track [Page 2] + +RFC 7601 Authentication-Results Header Field August 2015 + + + 7.7. Attacks against Authentication Methods . . . . . . . . . 36 + 7.8. Intentionally Malformed Header Fields . . . . . . . . . . 36 + 7.9. Compromised Internal Hosts . . . . . . . . . . . . . . . 36 + 7.10. Encapsulated Instances . . . . . . . . . . . . . . . . . 37 + 7.11. Reverse Mapping . . . . . . . . . . . . . . . . . . . . . 37 + 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 37 + 8.1. Normative References . . . . . . . . . . . . . . . . . . 37 + 8.2. Informative References . . . . . . . . . . . . . . . . . 38 + Appendix A. Legacy MUAs . . . . . . . . . . . . . . . . . . . . 42 + Appendix B. Authentication-Results Examples . . . . . . . . . . 42 + B.1. Trivial Case; Header Field Not Present . . . . . . . . . 42 + B.2. Nearly Trivial Case; Service Provided, but No + Authentication Done . . . . . . . . . . . . . . . . . . . 43 + B.3. Service Provided, Authentication Done . . . . . . . . . . 44 + B.4. Service Provided, Several Authentications Done, Single + MTA . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 + B.5. Service Provided, Several Authentications Done, Different + MTAs . . . . . . . . . . . . . . . . . . . . . . . . . . 46 + B.6. Service Provided, Multi-tiered Authentication Done . . . 48 + B.7. Comment-Heavy Example . . . . . . . . . . . . . . . . . . 49 + Appendix C. Operational Considerations about Message + Authentication . . . . . . . . . . . . . . . . . . . 50 + Appendix D. Changes since RFC 7001 . . . . . . . . . . . . . . . 51 + Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 53 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 53 + +1. Introduction + + This document describes a header field called Authentication-Results + for electronic mail messages that presents the results of a message + authentication effort in a machine-readable format. The intent of + the header field is to create a place to collect such data when + message authentication mechanisms are in use so that a Mail User + Agent (MUA) and downstream filters can make filtering decisions and/ + or provide a recommendation to the user as to the validity of the + message's origin and possibly the safety and integrity of its + content. + + This document revises the original definition found in [RFC5451] + based upon various authentication protocols in current use and + incorporates errata logged since the publication of the original + specification. + + End users are not expected to be direct consumers of this header + field. This header field is intended for consumption by programs + that will then use such data or render it in a human-usable form. + + + + + +Kucherawy Standards Track [Page 3] + +RFC 7601 Authentication-Results Header Field August 2015 + + + This document specifies the format of this header field and discusses + the implications of its presence or absence. However, it does not + discuss how the data contained in the header field ought to be used, + such as what filtering decisions are appropriate or how an MUA might + render those results, as these are local policy and/or user interface + design questions that are not appropriate for this document. + + At the time of publication of this document, the following are + published email authentication methods: + + o Author Domain Signing Practices ([ADSP]) (Historic) + + o SMTP Service Extension for Authentication ([AUTH]) + + o DomainKeys Identified Mail Signatures ([DKIM]) + + o Domain-based Message Authentication, Reporting and Conformance + ([DMARC]) + + o Sender Policy Framework ([SPF]) + + o reverse IP address name validation ("iprev", defined in Section 3) + + o Require-Recipient-Valid-Since Header Field and SMTP Service + Extension ([RRVS]) + + o S/MIME Signature Verification ([SMIME-REG]) + + o Vouch By Reference ([VBR]) + + o DomainKeys ([DOMAINKEYS]) (Historic) + + o Sender ID ([SENDERID]) (Experimental) + + There exist registries for tokens used within this header field that + refer to the specifications listed above. Section 6 describes the + registries and their contents and specifies the process by which + entries are added or updated. It also updates the existing contents + to match the current states of these specifications. + + This specification is not intended to be restricted to domain-based + authentication schemes, but the existing schemes in that family have + proven to be a good starting point for implementations. The goal is + to give current and future authentication schemes a common framework + within which to deliver their results to downstream agents and + discourage the creation of unique header fields for each. + + + + + +Kucherawy Standards Track [Page 4] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Although SPF defined a header field called "Received-SPF" and the + historic DomainKeys defined one called "DomainKey-Status" for this + purpose, those header fields are specific to the conveyance of their + respective results only and thus are insufficient to satisfy the + requirements enumerated below. In addition, many SPF implementations + have adopted the header field specified here at least as an option, + and DomainKeys has been obsoleted by DKIM. + +1.1. Purpose + + The header field defined in this document is expected to serve + several purposes: + + 1. Convey the results of various message authentication checks, + which are applied by upstream filters and Mail Transfer Agents + (MTAs) and then passed to MUAs and downstream filters within the + same "trust domain". Such agents might wish to render those + results to end users or to use those data to apply more or less + stringent content checks based on authentication results; + + 2. Provide a common location within a message for this data; + + 3. Create an extensible framework for reporting new authentication + methods as they emerge. + + In particular, the mere presence of this header field does not mean + its contents are valid. Rather, the header field is reporting + assertions made by one or more authentication schemes (supposedly) + applied somewhere upstream. For an MUA or downstream filter to treat + the assertions as actually valid, there must be an assessment of the + trust relationship among such agents, the validating MTA, and the + mechanism for conveying the information. + +1.2. Trust Boundary + + This document makes several references to the "trust boundary" of an + administrative management domain (ADMD). Given the diversity among + existing mail environments, a precise definition of this term isn't + possible. + + Simply put, a transfer from the producer of the header field to the + consumer must occur within a context that permits the consumer to + treat assertions by the producer as being reliable and accurate + (trustworthy). How this trust is obtained is outside the scope of + this document. It is entirely a local matter. + + + + + + +Kucherawy Standards Track [Page 5] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Thus, this document defines a "trust boundary" as the delineation + between "external" and "internal" entities. Services that are + internal -- within the trust boundary -- are provided by the ADMD's + infrastructure for its users. Those that are external are outside of + the authority of the ADMD. By this definition, hosts that are within + a trust boundary are subject to the ADMD's authority and policies, + independent of their physical placement or their physical operation. + For example, a host within a trust boundary might actually be + operated by a remote service provider and reside physically within + its data center. + + It is possible for a message to be evaluated inside a trust boundary + but then depart and re-enter the trust boundary. An example might be + a forwarded message such as a message/rfc822 attachment (see + Multipurpose Internet Mail Extensions [MIME]) or one that is part of + a multipart/digest. The details reported by this field cannot be + trusted in that case. Thus, this field found within one of those + media types is typically ignored. + +1.3. Processing Scope + + The content of this header field is meant to convey to message + consumers that authentication work on the message was already done + within its trust boundary, and those results are being presented. It + is not intended to provide message parameters to consumers so that + they can perform authentication protocols on their own. + +1.4. Requirements + + This document establishes no new requirements on existing protocols + or servers. + + In particular, this document establishes no requirement on MTAs to + reject or filter arriving messages that do not pass authentication + checks. The data conveyed by the specified header field's contents + are for the information of MUAs and filters and are to be used at + their discretion. + +1.5. Definitions + + This section defines various terms used throughout this document. + +1.5.1. Key Words + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [KEYWORDS]. + + + + +Kucherawy Standards Track [Page 6] + +RFC 7601 Authentication-Results Header Field August 2015 + + +1.5.2. Security + + "Guidelines for Writing RFC Text on Security Considerations" + ([SECURITY]) discusses authentication and authorization and the + conflation of the two concepts. The use of those terms within the + context of recent message security work has given rise to slightly + different definitions, and this document reflects those current + usages, as follows: + + o "Authorization" is the establishment of permission to use a + resource or represent an identity. In this context, authorization + indicates that a message from a particular ADMD arrived via a + route the ADMD has explicitly approved. + + o "Authentication" is the assertion of validity of a piece of data + about a message (such as the sender's identity) or the message in + its entirety. + + As examples: SPF and Sender ID are authorization mechanisms in that + they express a result that shows whether or not the ADMD that + apparently sent the message has explicitly authorized the connecting + Simple Mail Transfer Protocol ([SMTP]) client to relay messages on + its behalf, but they do not actually validate any other property of + the message itself. By contrast, DKIM is agnostic as to the routing + of a message but uses cryptographic signatures to authenticate + agents, assign (some) responsibility for the message (which implies + authorization), and ensure that the listed portions of the message + were not modified in transit. Since the signatures are not tied to + SMTP connections, they can be added by either the ADMD of origin, + intermediate ADMDs (such as a mailing list server), other handling + agents, or any combination. + + Rather than create a separate header field for each class of + solution, this proposal groups them both into a single header field. + +1.5.3. Email Architecture + + o A "border MTA" is an MTA that acts as a gateway between the + general Internet and the users within an organizational boundary. + (See also Section 1.2.) + + o A "delivery MTA" (or Mail Delivery Agent or MDA) is an MTA that + actually enacts delivery of a message to a user's inbox or other + final delivery. + + o An "intermediate MTA" is any MTA that is not a delivery MTA and is + also not the first MTA to handle the message. + + + + +Kucherawy Standards Track [Page 7] + +RFC 7601 Authentication-Results Header Field August 2015 + + + The following diagram illustrates the flow of mail among these + defined components. See Internet Mail Architecture [EMAIL-ARCH] for + further discussion on general email system architecture, which + includes detailed descriptions of these components, and Appendix C of + this document for discussion about the common aspects of email + authentication in current environments. + + +-----+ +-----+ +------------+ + | MUA |-->| MSA |-->| Border MTA | + +-----+ +-----+ +------------+ + | + | + V + +----------+ + | Internet | + +----------+ + | + | + V + +-----+ +-----+ +------------------+ +------------+ + | MUA |<--| MDA |<--| Intermediate MTA |<--| Border MTA | + +-----+ +-----+ +------------------+ +------------+ + + Generally, it is assumed that the work of applying message + authentication schemes takes place at a border MTA or a delivery MTA. + This specification is written with that assumption in mind. However, + there are some sites at which the entire mail infrastructure consists + of a single host. In such cases, such terms as "border MTA" and + "delivery MTA" might well apply to the same machine or even the very + same agent. It is also possible that some message authentication + tests could take place on an intermediate MTA. Although this + document doesn't specifically describe such cases, they are not meant + to be excluded. + +1.5.4. Other Terms + + In this document, the term "producer" refers to any component that + adds this header field to messages it is handling, and "consumer" + refers to any component that identifies, extracts, and parses the + header field to use as part of a handling decision. + +1.6. Trust Environment + + This header field permits one or more message validation mechanisms + to communicate output to one or more separate assessment mechanisms. + These mechanisms operate within a unified trust boundary that defines + an Administrative Management Domain (ADMD). An ADMD contains one or + more entities that perform validation and generate the header field + + + +Kucherawy Standards Track [Page 8] + +RFC 7601 Authentication-Results Header Field August 2015 + + + and one or more that consume it for some type of assessment. The + field often contains no integrity or validation mechanism of its own, + so its presence must be trusted implicitly. Hence, valid use of the + header field requires removing any occurrences of it that are present + when the message enters the ADMD. This ensures that later + occurrences have been added within the trust boundary of the ADMD. + + The authserv-id token defined in Section 2.2 can be used to reference + an entire ADMD or a specific validation engine within an ADMD. + Although the labeling scheme is left as an operational choice, some + guidance for selecting a token is provided in later sections of this + document. + +2. Definition and Format of the Header Field + + This section gives a general overview of the format of the header + field being defined and then provides more formal specification. + +2.1. General Description + + The header field specified here is called Authentication-Results. It + is a Structured Header Field as defined in Internet Message Format + ([MAIL]), and thus all of the related definitions in that document + apply. + + This header field is added at the top of the message as it transits + MTAs that do authentication checks, so some idea of how far away the + checks were done can be inferred. It is therefore considered to be a + trace field as defined in [MAIL], and thus all of the related + definitions in that document apply. + + The value of the header field (after removing comments) consists of + an authentication identifier, an optional version, and then a series + of statements and supporting data. The statements are of the form + "method=result" and indicate which authentication method(s) were + applied and their respective results. For each such statement, the + supporting data can include a "reason" string and one or more + "property=value" statements indicating which message properties were + evaluated to reach that conclusion. + + The header field can appear more than once in a single message, more + than one result can be represented in a single header field, or a + combination of these can be applied. + + + + + + + + +Kucherawy Standards Track [Page 9] + +RFC 7601 Authentication-Results Header Field August 2015 + + +2.2. Formal Definition + + Formally, the header field is specified as follows using Augmented + Backus-Naur Form ([ABNF]): + + authres-header = "Authentication-Results:" [CFWS] authserv-id + [ CFWS authres-version ] + ( no-result / 1*resinfo ) [CFWS] CRLF + + authserv-id = value + ; see below for a description of this element + + authres-version = 1*DIGIT [CFWS] + ; indicates which version of this specification is in use; + ; this specification is version "1", and the absence of a + ; version implies this version of the specification + + no-result = [CFWS] ";" [CFWS] "none" + ; the special case of "none" is used to indicate that no + ; message authentication was performed + + resinfo = [CFWS] ";" methodspec [ CFWS reasonspec ] + *( CFWS propspec ) + + methodspec = [CFWS] method [CFWS] "=" [CFWS] result + ; indicates which authentication method was evaluated + ; and what its output was + + reasonspec = "reason" [CFWS] "=" [CFWS] value + ; a free-form comment on the reason the given result + ; was returned + + propspec = ptype [CFWS] "." [CFWS] property [CFWS] "=" pvalue + ; an indication of which properties of the message + ; were evaluated by the authentication scheme being + ; applied to yield the reported result + + method = Keyword [ [CFWS] "/" [CFWS] method-version ] + ; a method indicates which method's result is + ; represented by "result", and is one of the methods + ; explicitly defined as valid in this document + ; or is an extension method as defined below + + method-version = 1*DIGIT [CFWS] + ; indicates which version of the method specification is + ; in use, corresponding to the matching entry in the IANA + ; "Email Authentication Methods" registry; a value of "1" + ; is assumed if this version string is absent + + + +Kucherawy Standards Track [Page 10] + +RFC 7601 Authentication-Results Header Field August 2015 + + + result = Keyword + ; indicates the results of the attempt to authenticate + ; the message; see below for details + + ptype = Keyword + ; indicates whether the property being evaluated was + ; a parameter to an [SMTP] command, was a value taken + ; from a message header field, was some property of + ; the message body, or was some other property evaluated by + ; the receiving MTA; expected to be one of the "property + ; types" explicitly defined as valid, or an extension + ; ptype, as defined below + + property = special-smtp-verb / Keyword + ; indicates more specifically than "ptype" what the + ; source of the evaluated property is; the exact meaning + ; is specific to the method whose result is being reported + ; and is defined more clearly below + + special-smtp-verb = "mailfrom" / "rcptto" + ; special cases of [SMTP] commands that are made up + ; of multiple words + + pvalue = [CFWS] ( value / [ [ local-part ] "@" ] domain-name ) + [CFWS] + ; the value extracted from the message property defined + ; by the "ptype.property" construction + + "local-part" is defined in Section 3.4.1 of [MAIL], and "CFWS" is + defined in Section 3.2.2 of [MAIL]. + + "Keyword" is defined in Section 4.1.2 of [SMTP]. + + The "value" is as defined in Section 5.1 of [MIME]. + + The "domain-name" is as defined in Section 3.5 of [DKIM]. + + The "Keyword" used in "result" above is further constrained by the + necessity of being enumerated in Section 2.7. + + See Section 2.5 for a description of the authserv-id element. + + If the value portion of a "pvalue" construction identifies something + intended to be an email identity, then it MUST use the right hand + portion of that ABNF definition. + + The list of commands eligible for use with the "smtp" ptype can be + found in Section 4.1 of [SMTP]. + + + +Kucherawy Standards Track [Page 11] + +RFC 7601 Authentication-Results Header Field August 2015 + + + The "propspec" may be omitted if, for example, the method was unable + to extract any properties to do its evaluation yet has a result to + report. + + Where an SMTP command name is being reported as a "property", the + agent generating the header field represents that command by + converting it to lowercase and dropping any spaces (e.g., "MAIL FROM" + becomes "mailfrom", "RCPT TO" becomes "rcptto", etc.). + + A "ptype" value of "policy" indicates a policy decision about the + message not specific to a property of the message that could be + extracted. See Section 2.4 for details. + + Examples of complete messages using this header field can be found in + Appendix B. + +2.3. Property Types (ptypes) and Properties + + The "ptype" in the ABNF above indicates the general type of property + being described by the result being reported, upon which the reported + result was based. Coupled with the "property", which is more + specific, they indicate from which particular part of the message the + reported data were extracted. + + Combinations of ptypes and properties are registered and described in + the "Email Authentication Methods" registry, coupled with the + authentication methods with which they are used. This is further + described in Section 6. + + Legal values of "ptype" are as defined in the IANA "Email + Authentication Property Types" registry, created by [RFC7410]. The + initial values and what they typically indicate are as follows, based + on [RFC7001]: + + body: Information that was extracted from the body of the message. + This might be an arbitrary string of bytes, a hash of a string of + bytes, a Uniform Resource Identifier, or some other content of + interest. The "property" is an indication of where within the + message body the extracted content was found, and can indicate an + offset, identify a MIME part, etc. + + header: Indicates information that was extracted from the header of + the message. This might be the value of a header field or some + portion of a header field. The "property" gives a more precise + indication of the place in the header from which the extraction + took place. + + + + + +Kucherawy Standards Track [Page 12] + +RFC 7601 Authentication-Results Header Field August 2015 + + + policy: A local policy mechanism was applied that augments or + overrides the result returned by the authentication mechanism. + (See Section 2.4.) + + smtp: Indicates information that was extracted from an SMTP command + that was used to relay the message. The "property" indicates + which SMTP command included the extracted content as a parameter. + + Results reported using unknown ptypes MUST NOT be used in making + handling decisions. They can be safely ignored by consumers. + + Entries in the "Email Authentication Methods" registry can define + properties that deviate from these definitions when appropriate. + Such deviations need to be clear in the registry and/or in the + defining document. See Section 2.7.1 for an example. + +2.4. The "policy" ptype + + A special ptype value of "policy" is also defined. This ptype is + provided to indicate that some local policy mechanism was applied + that augments or even replaces (i.e., overrides) the result returned + by the authentication mechanism. The property and value in this case + identify the local policy that was applied and the result it + returned. + + For example, a DKIM signature is not required to include the Subject + header field in the set of fields that are signed. An ADMD receiving + such a message might decide that such a signature is unacceptable, + even if it passes, because the content of the Subject header field + could be altered post-signing without invalidating the signature. + Such an ADMD could replace the DKIM "pass" result with a "policy" + result and then also include the following in the corresponding + Authentication-Result field: + + ... dkim=fail policy.dkim-rules=unsigned-subject ... + + In this case, the property is "dkim-rules", indicating some local + check by that name took place and that check returned a result of + "unsigned-subject". These are arbitrary names selected by (and + presumably used within) the ADMD making use of them, so they are not + normally registered with IANA or otherwise specified apart from + setting syntax restrictions that allow for easy parsing within the + rest of the header field. + + This ptype existed in the original specification for this header + field, but without a complete description or example of intended use. + + + + + +Kucherawy Standards Track [Page 13] + +RFC 7601 Authentication-Results Header Field August 2015 + + + As a result, it has not seen any practical use to date that matches + its intended purpose. These added details are provided to guide + implementers toward proper use. + +2.5. Authentication Identifier Field + + Every Authentication-Results header field has an authentication + service identifier field (authserv-id above). Specifically, this is + any string intended to identify the authentication service within the + ADMD that conducted authentication checks on the message. This + identifier is intended to be machine-readable and not necessarily + meaningful to users. + + Since agents consuming this field will use this identifier to + determine whether its contents are of interest (and are safe to use), + the uniqueness of the identifier MUST be guaranteed by the ADMD that + generates it and MUST pertain to that ADMD. MUAs or downstream + filters SHOULD use this identifier to determine whether or not the + data contained in an Authentication-Results header field ought to be + used or ignored. + + For simplicity and scalability, the authentication service identifier + SHOULD be a common token used throughout the ADMD. Common practice + is to use the DNS domain name used by or within that ADMD, sometimes + called the "organizational domain", but this is not strictly + necessary. + + For tracing and debugging purposes, the authentication identifier can + instead be the specific hostname of the MTA performing the + authentication check whose result is being reported. Moreover, some + implementations define a substructure to the identifier; these are + outside of the scope of this specification. + + Note, however, that using a local, relative identifier like a flat + hostname, rather than a hierarchical and globally unique ADMD + identifier like a DNS domain name, makes configuration more difficult + for large sites. The hierarchical identifier permits aggregating + related, trusted systems together under a single, parent identifier, + which in turn permits assessing the trust relationship with a single + reference. The alternative is a flat namespace requiring + individually listing each trusted system. Since consumers will use + the identifier to determine whether to use the contents of the header + field: + + o Changes to the identifier impose a large, centralized + administrative burden. + + + + + +Kucherawy Standards Track [Page 14] + +RFC 7601 Authentication-Results Header Field August 2015 + + + o Ongoing administrative changes require constantly updating this + centralized table, making it difficult to ensure that an MUA or + downstream filter will have access to accurate information for + assessing the usability of the header field's content. In + particular, consumers of the header field will need to know not + only the current identifier(s) in use but previous ones as well to + account for delivery latency or later re-assessment of the header + field's contents. + + Examples of valid authentication identifiers are "example.com", + "mail.example.org", "ms1.newyork.example.com", and "example-auth". + +2.6. Version Tokens + + The grammar above provides for the optional inclusion of versions on + both the header field itself (attached to the authserv-id token) and + on each of the methods being reported. The method version refers to + the method itself, which is specified in the documents describing + those methods, while the authserv-id version refers to this document + and thus the syntax of this header field. + + The purpose of including these is to avoid misinterpretation of the + results. That is, if a parser finds a version after an authserv-id + that it does not explicitly know, it can immediately discontinue + trying to parse since what follows might not be in an expected + format. For a method version, the parser SHOULD ignore a method + result if the version is not supported in case the semantics of the + result have a different meaning than what is expected. For example, + if a hypothetical DKIM version 2 yielded a "pass" result for + different reasons than version 1 does, a consumer of this field might + not want to use the altered semantics. Allowing versions in the + syntax is a way to indicate this and let the consumer of the header + field decide. + +2.7. Defined Methods and Result Values + + Each individual authentication method returns one of a set of + specific result values. The subsections below provide references to + the documents defining the authentication methods specifically + supported by this document, and their corresponding result values. + Verifiers SHOULD use these values as described below. New methods + not specified in this document, but intended to be supported by the + header field defined here, MUST include a similar result table either + in their defining documents or in supplementary ones. + + + + + + + +Kucherawy Standards Track [Page 15] + +RFC 7601 Authentication-Results Header Field August 2015 + + +2.7.1. DKIM and DomainKeys + + DKIM is represented by the "dkim" method and is defined in [DKIM]. + DomainKeys is defined in [DOMAINKEYS] and is represented by the + "domainkeys" method. + + Section 3.8 of [DOMAINKEYS] enumerates some possible results of a + DomainKeys evaluation. Those results are not used when generating + this header field; rather, the results returned are listed below. + + A signature is "acceptable to the ADMD" if it passes local policy + checks (or there are no specific local policy checks). For example, + an ADMD policy might require that the signature(s) on the message be + added using the DNS domain present in the From header field of the + message, thus making third-party signatures unacceptable even if they + verify. + + Both DKIM and DomainKeys use the same result set, as follows: + + none: The message was not signed. + + pass: The message was signed, the signature or signatures were + acceptable to the ADMD, and the signature(s) passed verification + tests. + + fail: The message was signed and the signature or signatures were + acceptable to the ADMD, but they failed the verification test(s). + + policy: The message was signed, but some aspect of the signature or + signatures was not acceptable to the ADMD. + + neutral: The message was signed, but the signature or signatures + contained syntax errors or were not otherwise able to be + processed. This result is also used for other failures not + covered elsewhere in this list. + + temperror: The message could not be verified due to some error that + is likely transient in nature, such as a temporary inability to + retrieve a public key. A later attempt may produce a final + result. + + permerror: The message could not be verified due to some error that + is unrecoverable, such as a required header field being absent. A + later attempt is unlikely to produce a final result. + + DKIM results are reported using a ptype of "header". The property, + however, represents one of the tags found in the DKIM-Signature + header field rather than a distinct header field. For example, the + + + +Kucherawy Standards Track [Page 16] + +RFC 7601 Authentication-Results Header Field August 2015 + + + ptype-property combination "header.d" refers to the content of the + "d" (signing domain) tag from within the signature header field, and + not a distinct header field called "d". + + The ability to report different DKIM results for a message with + multiple signatures is described in [RFC6008]. + + [DKIM] advises that if a message fails verification, it is to be + treated as an unsigned message. A report of "fail" here permits the + receiver of the report to decide how to handle the failure. A report + of "neutral" or "none" preempts that choice, ensuring the message + will be treated as if it had not been signed. + + Section 3.1 of [DOMAINKEYS] describes a process by which the sending + address of the message is determined. DomainKeys results are thus + reported along with the signing domain name, the sending address of + the message, and the name of the header field from which the latter + was extracted. This means that a DomainKeys result includes a ptype- + property combination of "header.d", plus one of "header.from" and + "header.sender". The sending address extracted from the header is + included with any [MAIL]-style comments removed; moreover, the local- + part of the address and the "@" character are removed if it has not + been authenticated in some way. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 17] + +RFC 7601 Authentication-Results Header Field August 2015 + + +2.7.2. SPF and Sender ID + + SPF and Sender ID use the "spf" and "sender-id" method names, + respectively. The result values for SPF are defined in Section 2.6 + of [SPF], and those definitions are included here by reference: + + +-----------+--------------------------------+ + | Code | Meaning | + +-----------+--------------------------------+ + | none | [RFC7208], Section 2.6.1 | + +-----------+--------------------------------+ + | pass | [RFC7208], Section 2.6.3 | + +-----------+--------------------------------+ + | fail | [RFC7208], Section 2.6.4 | + +-----------+--------------------------------+ + | softfail | [RFC7208], Section 2.6.5 | + +-----------+--------------------------------+ + | policy | RFC 7601, Section 2.4 | + +-----------+--------------------------------+ + | neutral | [RFC7208], Section 2.6.2 | + +-----------+--------------------------------+ + | temperror | [RFC7208], Section 2.6.6 | + +-----------+--------------------------------+ + | permerror | [RFC7208], Section 2.6.7 | + +-----------+--------------------------------+ + + These result codes are used in the context of this specification to + reflect the result returned by the component conducting SPF + evaluation. + + For SPF, the ptype used is "smtp", and the property is either + "mailfrom" or "helo", since those values are the ones SPF can + evaluate. (If the SMTP client issued the EHLO command instead of + HELO, the property used is "helo".) + + The "sender-id" method is described in [SENDERID]. For this method, + the ptype used is "header" and the property will be the name of the + header field from which the Purported Responsible Address (see [PRA]) + was extracted -- namely, one of "Resent-Sender", "Resent-From", + "Sender", or "From". + + The results for Sender ID are listed and described in Section 4.2 of + [SENDERID], but for the purposes of this specification, the SPF + definitions enumerated above are used instead. Also, [SENDERID] + specifies result codes that use mixed case, but they are typically + used all lowercase in this context. + + + + + +Kucherawy Standards Track [Page 18] + +RFC 7601 Authentication-Results Header Field August 2015 + + + For both methods, an additional result of "policy" is defined, which + means the client was authorized to inject or relay mail on behalf of + the sender's DNS domain according to the authentication method's + algorithm, but local policy dictates that the result is unacceptable. + For example, "policy" might be used if SPF returns a "pass" result, + but a local policy check matches the sending DNS domain to one found + in an explicit list of unacceptable DNS domains (e.g., spammers). + + If the retrieved sender policies used to evaluate SPF and Sender ID + do not contain explicit provisions for authenticating the local-part + (see Section 3.4.1 of [MAIL]) of an address, the "pvalue" reported + along with results for these mechanisms SHOULD NOT include the local- + part or the following "@" character. + +2.7.3. "iprev" + + The result values used by the "iprev" method, defined in Section 3, + are as follows: + + pass: The DNS evaluation succeeded, i.e., the "reverse" and + "forward" lookup results were returned and were in agreement. + + fail: The DNS evaluation failed. In particular, the "reverse" and + "forward" lookups each produced results, but they were not in + agreement, or the "forward" query completed but produced no + result, e.g., a DNS RCODE of 3, commonly known as NXDOMAIN, or an + RCODE of 0 (NOERROR) in a reply containing no answers, was + returned. + + temperror: The DNS evaluation could not be completed due to some + error that is likely transient in nature, such as a temporary DNS + error, e.g., a DNS RCODE of 2, commonly known as SERVFAIL, or + other error condition resulted. A later attempt may produce a + final result. + + permerror: The DNS evaluation could not be completed because no PTR + data are published for the connecting IP address, e.g., a DNS + RCODE of 3, commonly known as NXDOMAIN, or an RCODE of 0 (NOERROR) + in a reply containing no answers, was returned. This prevented + completion of the evaluation. A later attempt is unlikely to + produce a final result. + + There is no "none" for this method since any TCP connection + delivering email has an IP address associated with it, so some kind + of evaluation will always be possible. + + The result is reported using a ptype of "policy" (as this is not part + of any established protocol) and a property of "iprev". + + + +Kucherawy Standards Track [Page 19] + +RFC 7601 Authentication-Results Header Field August 2015 + + + For discussion of the format of DNS replies, see "Domain Names - + Implementation and Specification" ([DNS]). + +2.7.4. SMTP AUTH + + SMTP AUTH (defined in [AUTH]) is represented by the "auth" method. + Its result values are as follows: + + none: SMTP authentication was not attempted. + + pass: The SMTP client authenticated to the server reporting the + result using the protocol described in [AUTH]. + + fail: The SMTP client attempted to authenticate to the server using + the protocol described in [AUTH] but was not successful (such as + providing a valid identity but an incorrect password). + + temperror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error that is likely transient in nature, such + as a temporary directory service lookup error. A later attempt + may produce a final result. + + permerror: The SMTP client attempted to authenticate using the + protocol described in [AUTH] but was not able to complete the + attempt due to some error that is likely not transient in nature, + such as a permanent directory service lookup error. A later + attempt is not likely to produce a final result. + + The result of AUTH is reported using a ptype of "smtp" and a property + of either: + + o "auth", in which case the value is the authorization identity + generated by the exchange initiated by the AUTH command; or + + o "mailfrom", in which case the value is the mailbox identified by + the AUTH parameter used with the MAIL FROM command. + + If both identities are available, both can be reported. For example, + consider this command issued by a client that has completed session + authentication with the AUTH command resulting in an authorized + identity of "client@c.example": + + MAIL FROM: AUTH= + + This could result in a "resinfo" construction like so: + + ; auth=pass smtp.auth=client@c.example smtp.mailfrom=bob@b.example + + + +Kucherawy Standards Track [Page 20] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Note that in all cases other than "pass", the message was sent by an + unauthenticated client. All non-"pass" cases SHOULD thus be treated + as equivalent with respect to this method. + +2.7.5. Other Registered Codes + + Result codes were also registered in other RFCs as follows: + + o Vouch By Reference (in [AR-VBR], represented by "vbr"); + + o Authorized Third-Party Signatures (in [ATPS], represented by + "dkim-atps"); + + o Author Domain Signing Practices (in [ADSP], represented by "dkim- + adsp"); + + o Require-Recipient-Valid-Since (in [RRVS], represented by "rrvs"); + + o S/MIME (in [SMIME-REG], represented by "smime"). + +2.7.6. Extension Methods + + Additional authentication method identifiers (extension methods) may + be defined in the future by later revisions or extensions to this + specification. These method identifiers are registered with the + Internet Assigned Numbers Authority (IANA) and, preferably, published + in an RFC. See Section 6 for further details. + + Extension methods can be defined for the following reasons: + + 1. To allow additional information from new authentication systems + to be communicated to MUAs or downstream filters. The names of + such identifiers ought to reflect the name of the method being + defined but ought not be needlessly long. + + 2. To allow the creation of "sub-identifiers" that indicate + different levels of authentication and differentiate between + their relative strengths, e.g., "auth1-weak" and "auth1-strong". + + Authentication method implementers are encouraged to provide adequate + information, via message header field comments if necessary, to allow + an MUA developer to understand or relay ancillary details of + authentication results. For example, if it might be of interest to + relay what data was used to perform an evaluation, such information + could be relayed as a comment in the header field, such as: + + Authentication-Results: example.com; + foo=pass bar.baz=blob (2 of 3 tests OK) + + + +Kucherawy Standards Track [Page 21] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Experimental method identifiers MUST only be used within ADMDs that + have explicitly consented to use them. These method identifiers and + the parameters associated with them are not documented in RFCs. + Therefore, they are subject to change at any time and not suitable + for production use. Any MTA, MUA, or downstream filter intended for + production use SHOULD ignore or delete any Authentication-Results + header field that includes an experimental (unknown) method + identifier. + +2.7.7. Extension Result Codes + + Additional result codes (extension results) might be defined in the + future by later revisions or extensions to this specification. + Result codes MUST be registered with the Internet Assigned Numbers + Authority (IANA) and preferably published in an RFC. See Section 6 + for further details. + + Experimental results MUST only be used within ADMDs that have + explicitly consented to use them. These results and the parameters + associated with them are not formally documented. Therefore, they + are subject to change at any time and not suitable for production + use. Any MTA, MUA, or downstream filter intended for production use + SHOULD ignore or delete any Authentication-Results header field that + includes an extension result. + +3. The "iprev" Authentication Method + + This section defines an additional authentication method called + "iprev". + + "iprev" is an attempt to verify that a client appears to be valid + based on some DNS queries, which is to say that the IP address is + explicitly associated with a domain name. Upon receiving a session + initiation of some kind from a client, the IP address of the client + peer is queried for matching names (i.e., a number-to-name + translation, also known as a "reverse lookup" or a "PTR" record + query). Once that result is acquired, a lookup of each of the names + (i.e., a name-to-number translation, or an "A" or "AAAA" record + query) thus retrieved is done. The response to this second check + will typically result in at least one mapping back to the client's IP + address. + + Expressed as an algorithm: If the client peer's IP address is I, the + list of names to which I maps (after a "PTR" query) is the set N, and + the union of IP addresses to which each member of N maps (after + corresponding "A" and "AAAA" queries) is L, then this test is + successful if I is an element of L. + + + + +Kucherawy Standards Track [Page 22] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Often an MTA receiving a connection that fails this test will simply + reject the connection using the enhanced status code defined in + [AUTH-ESC]. If an operator instead wishes to make this information + available to downstream agents as a factor in handling decisions, it + records a result in accordance with Section 2.7.3. + + The response to a PTR query could contain multiple names. To prevent + heavy DNS loads, agents performing these queries MUST be implemented + such that the number of names evaluated by generation of + corresponding A or AAAA queries is limited so as not to be unduly + taxing to the DNS infrastructure, though it MAY be configurable by an + administrator. As an example, Section 4.6.4 of [SPF] chose a limit + of 10 for its implementation of this algorithm. + + "DNS Extensions to Support IP Version 6" ([DNS-IP6]) discusses the + query formats for the IPv6 case. + + There is some contention regarding the wisdom and reliability of this + test. For example, in some regions, it can be difficult for this + test ever to pass because the practice of arranging to match the + forward and reverse DNS is infrequently observed. Therefore, the + precise implementation details of how a verifier performs an "iprev" + test are not specified here. The verifier MAY report a successful or + failed "iprev" test at its discretion having done some kind of check + of the validity of the connection's identity using DNS. It is + incumbent upon an agent making use of the reported "iprev" result to + understand what exactly that particular verifier is attempting to + report. + + Extensive discussion of reverse DNS mapping and its implications can + be found in "Considerations for the use of DNS Reverse Mapping" + ([DNSOP-REVERSE]). In particular, it recommends that applications + avoid using this test as a means of authentication or security. Its + presence in this document is not an endorsement but is merely + acknowledgment that the method remains common and provides the means + to relay the results of that test. + +4. Adding the Header Field to a Message + + This specification makes no attempt to evaluate the relative + strengths of various message authentication methods that may become + available. The methods listed are an order-independent set; their + sequence does not indicate relative strength or importance of one + method over another. Instead, the MUA or downstream filter consuming + this header field is to interpret the result of each method based on + its own knowledge of what that method evaluates. + + + + + +Kucherawy Standards Track [Page 23] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Each "method" MUST refer to an authentication method declared in the + IANA registry or an extension method as described in Section 2.7.6, + and each "result" MUST refer to a result code declared in the IANA + registry or an extension result code as defined in Section 2.7.7. + See Section 6 for further information about the registered methods + and result codes. + + An MTA compliant with this specification adds this header field + (after performing one or more message authentication tests) to + indicate which MTA or ADMD performed the test, which test got + applied, and what the result was. If an MTA applies more than one + such test, it adds this header field either once per test or once + indicating all of the results. An MTA MUST NOT add a result to an + existing header field. + + An MTA MAY add this header field containing only the authentication + identifier portion and the "none" token (see Section 2.2) to indicate + explicitly that no message authentication schemes were applied prior + to delivery of this message. + + An MTA adding this header field has to take steps to identify it as + legitimate to the MUAs or downstream filters that will ultimately + consume its content. One process to do so is described in Section 5. + Further measures may be necessary in some environments. Some + possible solutions are enumerated in Section 7.1. This document does + not mandate any specific solution to this issue as each environment + has its own facilities and limitations. + + Most known message authentication methods focus on a particular + identifier to evaluate. SPF and Sender ID differ in that they can + yield a result based on more than one identifier; specifically, SPF + can evaluate the RFC5321.HELO parameter or the RFC5321.MailFrom + parameter, and Sender ID can evaluate the RFC5321.MailFrom parameter + or the Purported Responsible Address (PRA) identity. When generating + this field to report those results, only the parameter that yielded + the result is included. + + For MTAs that add this header field, adding header fields in order + (at the top), per Section 3.6 of [MAIL], is particularly important. + Moreover, this header field SHOULD be inserted above any other trace + header fields such MTAs might prepend. This placement allows easy + detection of header fields that can be trusted. + + End users making direct use of this header field might inadvertently + trust information that has not been properly vetted. If, for + example, a basic SPF result were to be relayed that claims an + authenticated addr-spec, the local-part of that addr-spec has + actually not been authenticated. Thus, an MTA adding this header + + + +Kucherawy Standards Track [Page 24] + +RFC 7601 Authentication-Results Header Field August 2015 + + + field SHOULD NOT include any data that has not been authenticated by + the method(s) being applied. Moreover, MUAs SHOULD NOT render to + users such information if it is presented by a method known not to + authenticate it. + +4.1. Header Field Position and Interpretation + + In order to ensure non-ambiguous results and avoid the impact of + false header fields, MUAs and downstream filters SHOULD NOT interpret + this header field unless specifically configured to do so by the user + or administrator. That is, this interpretation should not be "on by + default". Naturally then, users or administrators ought not activate + such a feature unless (1) they are certain the header field will be + validly added by an agent within the ADMD that accepts the mail that + is ultimately read by the MUA, and (2) instances of the header field + that appear to originate within the ADMD but are actually added by + foreign MTAs will be removed before delivery. + + Furthermore, MUAs and downstream filters SHOULD NOT interpret this + header field unless the authentication service identifier it bears + appears to be one used within its own ADMD as configured by the user + or administrator. + + MUAs and downstream filters MUST ignore any result reported using a + "result" not specified in the IANA "Result Code" registry or a + "ptype" not listed in the "Email Authentication Property Types" + registry for such values as defined in Section 6. Moreover, such + agents MUST ignore a result indicated for any "method" they do not + specifically support. + + An MUA SHOULD NOT reveal these results to end users, absent careful + human factors design considerations and testing, for the presentation + of trust-related materials. For example, an attacker could register + examp1e.com (note the digit "1" (one)) and send signed mail to + intended victims; a verifier would detect that the signature was + valid and report a "pass" even though it's clear the DNS domain name + was intended to mislead. See Section 7.2 for further discussion. + + As stated in Section 2.1, this header field MUST be treated as though + it were a trace header field as defined in Section 3.6.7 of [MAIL] + and hence MUST NOT be reordered and MUST be prepended to the message, + so that there is generally some indication upon delivery of where in + the chain of handling MTAs the message authentication was done. + + Note that there are a few message handlers that are only capable of + appending new header fields to a message. Strictly speaking, these + handlers are not compliant with this specification. They can still + add the header field to carry authentication details, but any signal + + + +Kucherawy Standards Track [Page 25] + +RFC 7601 Authentication-Results Header Field August 2015 + + + about where in the handling chain the work was done may be lost. + Consumers SHOULD be designed such that this can be tolerated, + especially from a producer known to have this limitation. + + MUAs SHOULD ignore instances of this header field discovered within + message/rfc822 MIME attachments. + + Further discussion of these topics can be found in Section 7 below. + +4.2. Local Policy Enforcement + + Some sites have a local policy that considers any particular + authentication policy's non-recoverable failure results (typically + "fail" or similar) as justification for rejecting the message. In + such cases, the border MTA SHOULD issue an SMTP rejection response to + the message, rather than adding this header field and allowing the + message to proceed toward delivery. This is more desirable than + allowing the message to reach an internal host's MTA or spam filter, + thus possibly generating a local rejection such as a Delivery Status + Notification (DSN) [DSN] to a forged originator. Such generated + rejections are colloquially known as "backscatter". + + The same MAY also be done for local policy decisions overriding the + results of the authentication methods (e.g., the "policy" result + codes described in Section 2.7). + + Such rejections at the SMTP protocol level are not possible if local + policy is enforced at the MUA and not the MTA. + +5. Removing Existing Header Fields + + For security reasons, any MTA conforming to this specification MUST + delete any discovered instance of this header field that claims, by + virtue of its authentication service identifier, to have been added + within its trust boundary but that did not come directly from another + trusted MTA. For example, an MTA for example.com receiving a message + MUST delete or otherwise obscure any instance of this header field + bearing an authentication service identifier indicating that the + header field was added within example.com prior to adding its own + header fields. This could mean each MTA will have to be equipped + with a list of internal MTAs known to be compliant (and hence + trustworthy). + + For simplicity and maximum security, a border MTA could remove all + instances of this header field on mail crossing into its trust + boundary. However, this may conflict with the desire to access + authentication results performed by trusted external service + providers. It may also invalidate signed messages whose signatures + + + +Kucherawy Standards Track [Page 26] + +RFC 7601 Authentication-Results Header Field August 2015 + + + cover external instances of this header field. A more robust border + MTA could allow a specific list of authenticating MTAs whose + information is to be admitted, removing the header field originating + from all others. + + As stated in Section 1.2, a formal definition of "trust boundary" is + deliberately not made here. It is entirely possible that a border + MTA for example.com will explicitly trust authentication results + asserted by upstream host example.net even though they exist in + completely disjoint administrative boundaries. In that case, the + border MTA MAY elect not to delete those results; moreover, the + upstream host doing some authentication work could apply a signing + technology such as [DKIM] on its own results to assure downstream + hosts of their authenticity. An example of this is provided in + Appendix B. + + Similarly, in the case of messages signed using [DKIM] or other + message-signing methods that sign header fields, this removal action + could invalidate one or more signatures on the message if they + covered the header field to be removed. This behavior can be + desirable since there's little value in validating the signature on a + message with forged header fields. However, signing agents MAY + therefore elect to omit these header fields from signing to avoid + this situation. + + An MTA SHOULD remove any instance of this header field bearing a + version (express or implied) that it does not support. However, an + MTA MUST remove such a header field if the [SMTP] connection relaying + the message is not from a trusted internal MTA. This means the MTA + needs to be able to understand versions of this header field at least + as late as the ones understood by the MUAs or other consumers within + its ADMD. + +6. IANA Considerations + + IANA has registered the defined header field and created tables as + described below. These registry actions were originally defined by + [RFC5451] and updated by [RFC6577] and [RFC7001]. The created + registries are being further updated here to increase their + completeness. + +6.1. The Authentication-Results Header Field + + [RFC5451] added the Authentication-Results header field to the IANA + "Permanent Message Header Field Names" registry, per the procedure + found in [IANA-HEADERS]. That entry has been updated to reference + this document. The following is the registration template: + + + + +Kucherawy Standards Track [Page 27] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Header field name: Authentication-Results + Applicable protocol: mail ([MAIL]) + Status: Standard + Author/Change controller: IETF + Specification document(s): RFC 7601 + Related information: none + +6.2. "Email Authentication Methods" Registry Description + + Names of message authentication methods supported by this + specification have been registered with IANA, with the exception of + experimental names as described in Section 2.7.6. Along with each + method is recorded the properties that accompany the method's result. + + The "Email Authentication Parameters" group, and within it the "Email + Authentication Methods" registry, were created by [RFC5451] for this + purpose. [RFC6577] added a "status" field for each entry. [RFC7001] + amended the rules governing that registry and also added a "version" + field to the registry. + + The reference for that registry has been updated to reference this + document. + + New entries are assigned only for values that have received Expert + Review, per [IANA-CONSIDERATIONS]. The designated expert shall be + appointed by the IESG. The designated expert has discretion to + request that a publication be referenced if a clear, concise + definition of the authentication method cannot be provided such that + interoperability is assured. Registrations should otherwise be + permitted. The designated expert can also handle requests to mark + any current registration as "deprecated". + + No two entries can have the same combination of method, ptype, and + property. + + An entry in this registry contains the following: + + Method: the name of the method. + + Definition: a reference to the document that created this entry, if + any (see below). + + ptype: a "ptype" value appropriate for use with that method. + + property: a "property" value matching that "ptype" also appropriate + for use with that method. + + + + + +Kucherawy Standards Track [Page 28] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Value: a brief description of the value to be supplied with that + method/ptype/property tuple. + + Status: the status of this entry, which is either: + + active: The entry is in current use. + + deprecated: The entry is no longer in current use. + + Version: a version number associated with the method (preferably + starting at "1"). + + The "Definition" field will typically refer to a permanent document, + or at least some descriptive text, where additional information about + the entry being added can be found. This might in turn reference the + document where the method is defined so that all of the semantics + around creating or interpreting an Authentication-Results header + field using this method, ptype, and property can be understood. + +6.3. "Email Authentication Methods" Registry Update + + The following changes have been made to this registry per this + document: + + 1. The "Defined" field has been renamed "Definition", to be + consistent with the other registries in this group. + + 2. The entry for the "dkim" method, "header" ptype, and "b" property + now reference [RFC6008] as the defining document, and the + reference has be removed from the description. + + 3. All other "dkim", "domainkeys", "iprev", "sender-id", and "spf" + method entries have had their "Definition" fields changed to + refer to this document, as this document contains a complete + description of the registry and these corresponding values. + + 4. All "smime" entries have had their "Definition" fields changed to + [SMIME-REG]. + + 5. The "value" field of the "smime" entry using property "smime- + part" has been changed to read: "The MIME body part reference + that contains the S/MIME signature. See Section 3.2.1 of RFC + 7281 for full syntax." + + + + + + + + +Kucherawy Standards Track [Page 29] + +RFC 7601 Authentication-Results Header Field August 2015 + + + 6. The single entry for the "auth" method was intended to reflect + the identity indicated by the "AUTH" parameter to the SMTP "MAIL + FROM" command verb. However, there is also an "AUTH" command + verb. To clarify this ambiguity, the entry for the "auth" method + has had its "property" field changed to "mailfrom", and its + "Definition" field changed to this document. + + 7. The following entry has been added: + + Method: auth + + Definition: this document (RFC 7601) + + ptype: smtp + + property: auth + + Value: identity confirmed by the AUTH command + + Status: active + + Version: 1 + + 8. The values of the "domainkeys" entries for ptype "header" have + been updated as follows: + + from: contents of the [MAIL] From: header field, after removing + comments, and removing the local-part and following "@" if not + authenticated + + sender: contents of the [MAIL] Sender: header field, after + removing comments, and removing the local-part and following + "@" if not authenticated + + 9. For all entries for "dkim-adsp" and "domainkeys", their Status + values have been changed to "deprecated", reflecting the fact + that the corresponding specifications now have Historic status. + Their "Definition" fields have also been modified to include a + reference to this document. + +6.4. "Email Authentication Property Types" Registry + + [RFC7410] created the "Email Authentication Property Types" registry. + + Entries in this registry are subject to the Expert Review rules as + described in [IANA-CONSIDERATIONS]. Each entry in the registry + requires the following values: + + + + +Kucherawy Standards Track [Page 30] + +RFC 7601 Authentication-Results Header Field August 2015 + + + ptype: The name of the ptype being registered, which must fit within + the ABNF described in Section 2.2. + + Definition: An optional reference to a defining specification. + + Description: A brief description of what sort of information this + "ptype" is meant to cover. + + For new entries, the Designated Expert needs to assure that the + description provided for the new entry adequately describes the + intended use. An example would be helpful to include in the entry's + defining document, if any, although entries in the "Email + Authentication Methods" registry or the "Email Authentication Result + Names" registry might also serve as examples of intended use. + + As this is a complete restatement of the definition and rules for + this registry, IANA has updated this registry to show Section 2.3 of + this document as the current definitions for the "body", "header", + "policy", and "smtp" entries of that registry. References to + [RFC7001] and [RFC7410] have been removed. + +6.5. "Email Authentication Result Names" Description + + Names of message authentication result codes supported by this + specification must be registered with IANA, with the exception of + experimental codes as described in Section 2.7.7. A registry was + created by [RFC5451] for this purpose. [RFC6577] added the "status" + column and [RFC7001] updated the rules governing that registry. + + New entries are assigned only for values that have received Expert + Review, per [IANA-CONSIDERATIONS]. The designated expert shall be + appointed by the IESG. The designated expert has discretion to + request that a publication be referenced if a clear, concise + definition of the authentication result cannot be provided such that + interoperability is assured. Registrations should otherwise be + permitted. The designated expert can also handle requests to mark + any current registration as "deprecated". + + No two entries can have the same combination of method and code. + + An entry in this registry contains the following: + + Auth Method: an authentication method for which results are being + returned using the header field defined in this document. + + Code: a result code that can be returned for this authentication + method. + + + + +Kucherawy Standards Track [Page 31] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Specification: either free form text explaining the meaning of this + method-code combination, or a reference to such a definition. + + Status: the status of this entry, which is either: + + active: The entry is in current use. + + deprecated: The entry is no longer in current use. + +6.6. "Email Authentication Result Names" Update + + This document includes a complete description of the registry, + obsoleting [RFC7001]. Accordingly, the following changes have been + made to this registry per this document: + + o The "Defined" field has been removed. + + o The "Meaning" field has been renamed "Specification", as described + above. + + o The "Auth Method" field now appears before the "Code" field. + + o For easier searching, the table has been arranged such that it is + sorted first by Auth Method, then by Code within each Auth Method + grouping. + + o All entries for the "dkim", "domainkeys", "spf", "sender-id", + "auth", and "iprev" methods have had their "Specification" fields + replaced as follows: + + dkim: Section 2.7.1 of this document (RFC 7601) + + domainkeys: Section 2.7.1 of this document (RFC 7601) + + spf: for "hardfail", Section 2.4.2 of [RFC5451]; for all others, + Section 2.7.2 of this document (RFC 7601) + + sender-id: for "hardfail", Section 2.4.2 of [RFC5451]; for all + others, Section 2.7.2 of this document (RFC 7601) + + auth: Section 2.7.4 of this document (RFC 7601) + + iprev: Section 2.7.3 of this document (RFC 7601) + + o All entries for "dkim-adsp" that were missing an explicit + reference to a defining document now reference [ADSP] in their + "Specification" fields. + + + + +Kucherawy Standards Track [Page 32] + +RFC 7601 Authentication-Results Header Field August 2015 + + + o All entries for "dmarc" have had their "Specification" fields + changed to reference Section 11.2 of [DMARC]. + + o All entries for "dkim-adsp" and "domainkeys" have had their Status + values changed to "deprecated", reflecting the fact that the + corresponding specifications now have Historic status. Their + "Specification" fields have also been modified to include a + reference to this document. + +6.7. SMTP Enhanced Status Codes + + The entry for X.7.25 in the "Enumerated Status Codes" sub-registry of + the "Simple Mail Transfer Protocol (SMTP) Enhanced Status Codes + Registry" has been updated to refer to this document instead of + [RFC7001]. + +7. Security Considerations + + The following security considerations apply when adding or processing + the Authentication-Results header field: + +7.1. Forged Header Fields + + An MUA or filter that accesses a mailbox whose messages are handled + by a non-conformant MTA, and understands Authentication-Results + header fields, could potentially make false conclusions based on + forged header fields. A malicious user or agent could forge a header + field using the DNS domain of a receiving ADMD as the authserv-id + token in the value of the header field and, with the rest of the + value, claim that the message was properly authenticated. The non- + conformant MTA would fail to strip the forged header field, and the + MUA could inappropriately trust it. + + For this reason, it is best not to have processing of the + Authentication-Results header field enabled by default; instead, it + should be ignored, at least for the purposes of enacting filtering + decisions, unless specifically enabled by the user or administrator + after verifying that the border MTA is compliant. It is acceptable + to have an MUA aware of this specification but have an explicit list + of hostnames whose Authentication-Results header fields are + trustworthy; however, this list should initially be empty. + + Proposed alternative solutions to this problem were made some time + ago and are listed below. To date, they have not been developed due + to lack of demand but are documented here should the information be + useful at some point in the future: + + + + + +Kucherawy Standards Track [Page 33] + +RFC 7601 Authentication-Results Header Field August 2015 + + + 1. Possibly the simplest is a digital signature protecting the + header field, such as using [DKIM], that can be verified by an + MUA by using a posted public key. Although one of the main + purposes of this document is to relieve the burden of doing + message authentication work at the MUA, this only requires that + the MUA learn a single authentication scheme even if a number of + them are in use at the border MTA. Note that [DKIM] requires + that the From header field be signed, although in this + application, the signing agent (a trusted MTA) likely cannot + authenticate that value, so the fact that it is signed should be + ignored. Where the authserv-id is the ADMD's domain name, the + authserv-id matching this valid internal signature's "d=" DKIM + value is sufficient. + + 2. Another would be a means to interrogate the MTA that added the + header field to see if it is actually providing any message + authentication services and saw the message in question, but this + isn't especially palatable given the work required to craft and + implement such a scheme. + + 3. Yet another might be a method to interrogate the internal MTAs + that apparently handled the message (based on Received header + fields) to determine whether any of them conform to Section 5 of + this memo. This, too, has potentially high barriers to entry. + + 4. Extensions to [IMAP], [SMTP], and [POP3] could be defined to + allow an MUA or filtering agent to acquire the authserv-id in use + within an ADMD, thus allowing it to identify which + Authentication-Results header fields it can trust. + + 5. On the presumption that internal MTAs are fully compliant with + Section 3.6 of [MAIL] and the compliant internal MTAs are using + their own hostnames or the ADMD's DNS domain name as the + authserv-id token, the header field proposed here should always + appear above a Received header added by a trusted MTA. This can + be used as a test for header field validity. + + Support for some of these is being considered for future work. + + In any case, a mechanism needs to exist for an MUA or filter to + verify that the host that appears to have added the header field (a) + actually did so and (b) is legitimately adding that header field for + this delivery. Given the variety of messaging environments deployed + today, consensus appears to be that specifying a particular mechanism + for doing so is not appropriate for this document. + + + + + + +Kucherawy Standards Track [Page 34] + +RFC 7601 Authentication-Results Header Field August 2015 + + + Mitigation of the forged header field attack can also be accomplished + by moving the authentication results data into metadata associated + with the message. In particular, an [SMTP] extension could be + established to communicate authentication results from the border MTA + to intermediate and delivery MTAs; the latter of these could arrange + to store the authentication results as metadata retrieved and + rendered along with the message by an [IMAP] client aware of a + similar extension in that protocol. The delivery MTA would be told + to trust data via this extension only from MTAs it trusts, and border + MTAs would not accept data via this extension from any source. There + is no vector in such an arrangement for forgery of authentication + data by an outside agent. + +7.2. Misleading Results + + Until some form of service for querying the reputation of a sending + agent is widely deployed, the existence of this header field + indicating a "pass" does not render the message trustworthy. It is + possible for an arriving piece of spam or other undesirable mail to + pass checks by several of the methods enumerated above (e.g., a piece + of spam signed using [DKIM] by the originator of the spam, which + might be a spammer or a compromised system). In particular, this + issue is not resolved by forged header field removal discussed above. + + Hence, MUAs and downstream filters must take some care with use of + this header even after possibly malicious headers are scrubbed. + +7.3. Header Field Position + + Despite the requirements of [MAIL], header fields can sometimes be + reordered en route by intermediate MTAs. The goal of requiring + header field addition only at the top of a message is an + acknowledgment that some MTAs do reorder header fields, but most do + not. Thus, in the general case, there will be some indication of + which MTAs (if any) handled the message after the addition of the + header field defined here. + +7.4. Reverse IP Query Denial-of-Service Attacks + + Section 4.6.4 of [SPF] describes a DNS-based denial-of-service attack + for verifiers that attempt DNS-based identity verification of + arriving client connections. A verifier wishing to do this check and + report this information needs to take care not to go to unbounded + lengths to resolve "A" and "PTR" queries. MUAs or other filters + making use of an "iprev" result specified by this document need to be + aware of the algorithm used by the verifier reporting the result and, + especially, its limitations. + + + + +Kucherawy Standards Track [Page 35] + +RFC 7601 Authentication-Results Header Field August 2015 + + +7.5. Mitigation of Backscatter + + Failing to follow the instructions of Section 4.2 can result in a + denial-of-service attack caused by the generation of [DSN] messages + (or equivalent) to addresses that did not send the messages being + rejected. + +7.6. Internal MTA Lists + + Section 5 describes a procedure for scrubbing header fields that may + contain forged authentication results about a message. A compliant + installation will have to include, at each MTA, a list of other MTAs + known to be compliant and trustworthy. Failing to keep this list + current as internal infrastructure changes may expose an ADMD to + attack. + +7.7. Attacks against Authentication Methods + + If an attack becomes known against an authentication method, clearly + then the agent verifying that method can be fooled into thinking an + inauthentic message is authentic, and thus the value of this header + field can be misleading. It follows that any attack against the + authentication methods supported by this document is also a security + consideration here. + +7.8. Intentionally Malformed Header Fields + + It is possible for an attacker to add an Authentication-Results + header field that is extraordinarily large or otherwise malformed in + an attempt to discover or exploit weaknesses in header field parsing + code. Implementers must thoroughly verify all such header fields + received from MTAs and be robust against intentionally as well as + unintentionally malformed header fields. + +7.9. Compromised Internal Hosts + + An internal MUA or MTA that has been compromised could generate mail + with a forged From header field and a forged Authentication-Results + header field that endorses it. Although it is clearly a larger + concern to have compromised internal machines than it is to prove the + value of this header field, this risk can be mitigated by arranging + that internal MTAs will remove this header field if it claims to have + been added by a trusted border MTA (as described above), yet the + [SMTP] connection is not coming from an internal machine known to be + running an authorized MTA. However, in such a configuration, + legitimate MTAs will have to add this header field when legitimate + internal-only messages are generated. This is also covered in + Section 5. + + + +Kucherawy Standards Track [Page 36] + +RFC 7601 Authentication-Results Header Field August 2015 + + +7.10. Encapsulated Instances + + MIME messages can contain attachments of type "message/rfc822", which + contain other messages. Such an encapsulated message can also + contain an Authentication-Results header field. Although the + processing of these is outside of the intended scope of this document + (see Section 1.3), some early guidance to MUA developers is + appropriate here. + + Since MTAs are unlikely to strip Authentication-Results header fields + after mailbox delivery, MUAs are advised in Section 4.1 to ignore + such instances within MIME attachments. Moreover, when extracting a + message digest to separate mail store messages or other media, such + header fields should be removed so that they will never be + interpreted improperly by MUAs that might later consume them. + +7.11. Reverse Mapping + + Although Section 3 of this memo includes explicit support for the + "iprev" method, its value as an authentication mechanism is limited. + Implementers of both this proposal and agents that use the data it + relays are encouraged to become familiar with the issues raised by + [DNSOP-REVERSE] when deciding whether or not to include support for + "iprev". + +8. References + +8.1. Normative References + + [ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, + DOI 10.17487/RFC5234, January 2008, + . + + [IANA-HEADERS] + Klyne, G., Nottingham, M., and J. Mogul, "Registration + Procedures for Message Header Fields", BCP 90, RFC 3864, + DOI 10.17487/RFC3864, September 2004, + . + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [MAIL] Resnick, P., Ed., "Internet Message Format", RFC 5322, + DOI 10.17487/RFC5322, October 2008, + . + + + +Kucherawy Standards Track [Page 37] + +RFC 7601 Authentication-Results Header Field August 2015 + + + [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996, + . + + [SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, + DOI 10.17487/RFC5321, October 2008, + . + +8.2. Informative References + + [ADSP] Allman, E., Fenton, J., Delany, M., and J. Levine, + "DomainKeys Identified Mail (DKIM) Author Domain Signing + Practices (ADSP)", RFC 5617, DOI 10.17487/RFC5617, August + 2009, . + + [AR-VBR] Kucherawy, M., "Authentication-Results Registration for + Vouch by Reference Results", RFC 6212, + DOI 10.17487/RFC6212, April 2011, + . + + [ATPS] Kucherawy, M., "DomainKeys Identified Mail (DKIM) + Authorized Third-Party Signatures", RFC 6541, + DOI 10.17487/RFC6541, February 2012, + . + + [AUTH] Siemborski, R., Ed. and A. Melnikov, Ed., "SMTP Service + Extension for Authentication", RFC 4954, + DOI 10.17487/RFC4954, July 2007, + . + + [AUTH-ESC] + Kucherawy, M., "Email Authentication Status Codes", + RFC 7372, DOI 10.17487/RFC7372, September 2014, + . + + [DKIM] Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed., + "DomainKeys Identified Mail (DKIM) Signatures", STD 76, + RFC 6376, DOI 10.17487/RFC6376, September 2011, + . + + [DMARC] Kucherawy, M., Ed. and E. Zwicky, Ed., "Domain-based + Message Authentication, Reporting, and Conformance + (DMARC)", RFC 7489, DOI 10.17487/RFC7489, March 2015, + . + + + + + + +Kucherawy Standards Track [Page 38] + +RFC 7601 Authentication-Results Header Field August 2015 + + + [DNS] Mockapetris, P., "Domain names - implementation and + specification", STD 13, RFC 1035, DOI 10.17487/RFC1035, + November 1987, . + + [DNS-IP6] Thomson, S., Huitema, C., Ksinant, V., and M. Souissi, + "DNS Extensions to Support IP Version 6", RFC 3596, + DOI 10.17487/RFC3596, October 2003, + . + + [DNSOP-REVERSE] + Senie, D. and A. Sullivan, "Considerations for the use of + DNS Reverse Mapping", Work in Progress, draft-ietf-dnsop- + reverse-mapping-considerations-06, March 2008. + + [DOMAINKEYS] + Delany, M., "Domain-Based Email Authentication Using + Public Keys Advertised in the DNS (DomainKeys)", RFC 4870, + DOI 10.17487/RFC4870, May 2007, + . + + [DSN] Moore, K. and G. Vaudreuil, "An Extensible Message Format + for Delivery Status Notifications", RFC 3464, + DOI 10.17487/RFC3464, January 2003, + . + + [EMAIL-ARCH] + Crocker, D., "Internet Mail Architecture", RFC 5598, + DOI 10.17487/RFC5598, July 2009, + . + + [IANA-CONSIDERATIONS] + Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 5226, + DOI 10.17487/RFC5226, May 2008, + . + + [IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION + 4rev1", RFC 3501, DOI 10.17487/RFC3501, March 2003, + . + + [POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", + STD 53, RFC 1939, DOI 10.17487/RFC1939, May 1996, + . + + [PRA] Lyon, J., "Purported Responsible Address in E-Mail + Messages", RFC 4407, DOI 10.17487/RFC4407, April 2006, + . + + + + +Kucherawy Standards Track [Page 39] + +RFC 7601 Authentication-Results Header Field August 2015 + + + [RFC5451] Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", RFC 5451, + DOI 10.17487/RFC5451, April 2009, + . + + [RFC6008] Kucherawy, M., "Authentication-Results Registration for + Differentiating among Cryptographic Results", RFC 6008, + DOI 10.17487/RFC6008, September 2010, + . + + [RFC6577] Kucherawy, M., "Authentication-Results Registration Update + for Sender Policy Framework (SPF) Results", RFC 6577, + DOI 10.17487/RFC6577, March 2012, + . + + [RFC7001] Kucherawy, M., "Message Header Field for Indicating + Message Authentication Status", RFC 7001, + DOI 10.17487/RFC7001, September 2013, + . + + [RFC7410] Kucherawy, M., "A Property Types Registry for the + Authentication-Results Header Field", RFC 7410, + DOI 10.17487/RFC7410, December 2014, + . + + [RRVS] Mills, W. and M. Kucherawy, "The Require-Recipient-Valid- + Since Header Field and SMTP Service Extension", RFC 7293, + DOI 10.17487/RFC7293, July 2014, + . + + [SECURITY] Rescorla, E. and B. Korver, "Guidelines for Writing RFC + Text on Security Considerations", BCP 72, RFC 3552, + DOI 10.17487/RFC3552, July 2003, + . + + [SENDERID] Lyon, J. and M. Wong, "Sender ID: Authenticating E-Mail", + RFC 4406, DOI 10.17487/RFC4406, April 2006, + . + + [SMIME-REG] + Melnikov, A., "Authentication-Results Registration for + S/MIME Signature Verification", RFC 7281, + DOI 10.17487/RFC7281, June 2014, + . + + + + + + + +Kucherawy Standards Track [Page 40] + +RFC 7601 Authentication-Results Header Field August 2015 + + + [SPF] Kitterman, S., "Sender Policy Framework (SPF) for + Authorizing Use of Domains in Email, Version 1", RFC 7208, + DOI 10.17487/RFC7208, April 2014, + . + + [VBR] Hoffman, P., Levine, J., and A. Hathcock, "Vouch By + Reference", RFC 5518, DOI 10.17487/RFC5518, April 2009, + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 41] + +RFC 7601 Authentication-Results Header Field August 2015 + + +Appendix A. Legacy MUAs + + Implementers of this protocol should be aware that many MUAs are + unlikely to be retrofitted to support the new header field and its + semantics. In the interests of convenience and quicker adoption, a + delivery MTA might want to consider adding things that are processed + by existing MUAs in addition to the Authentication-Results header + field. One suggestion is to include a Priority header field, on + messages that don't already have such a header field, containing a + value that reflects the strength of the authentication that was + accomplished, e.g., "low" for weak or no authentication, "normal" or + "high" for good or strong authentication. + + Some modern MUAs can already filter based on the content of this + header field. However, there is keen interest in having MUAs make + some kind of graphical representation of this header field's meaning + to end users. Until this capability is added (i.e., while this + proposal and its successors are being adopted), other interim means + of conveying authentication results may be necessary. + +Appendix B. Authentication-Results Examples + + This section presents some examples of the use of this header field + to indicate authentication results. + +B.1. Trivial Case; Header Field Not Present + + The trivial case: + + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 1: Trivial Case + + + + + + + + +Kucherawy Standards Track [Page 42] + +RFC 7601 Authentication-Results Header Field August 2015 + + + The Authentication-Results header field is completely absent. The + MUA may make no conclusion about the validity of the message. This + could be the case because the message authentication services were + not available at the time of delivery, or no service is provided, or + the MTA is not in compliance with this specification. + +B.2. Nearly Trivial Case; Service Provided, but No Authentication Done + + A message that was delivered by an MTA that conforms to this + specification but provides no actual message authentication service: + + Authentication-Results: example.org 1; none + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by server.example.org (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.org + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 2: Header Present but No Authentication Done + + The Authentication-Results header field is present, showing that the + delivering MTA conforms to this specification. It used its DNS + domain name as the authserv-id. The presence of "none" (and the + absence of any method or result tokens) indicates that no message + authentication was done. The version number of the specification to + which the field's content conforms is explicitly provided. + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 43] + +RFC 7601 Authentication-Results Header Field August 2015 + + +B.3. Service Provided, Authentication Done + + A message that was delivered by an MTA that conforms to this + specification and applied some message authentication: + + Authentication-Results: example.com; + spf=pass smtp.mailfrom=example.net + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.net + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.net> + Subject: here's a sample + + Hello! Goodbye! + + Example 3: Header Reporting Results + + The Authentication-Results header field is present, indicating that + the border MTA conforms to this specification. The authserv-id is + once again the DNS domain name. Furthermore, the message was + authenticated by that MTA via the method specified in [SPF]. Note + that since that method cannot authenticate the local-part, it has + been omitted from the result's value. The MUA could extract and + relay this extra information if desired. + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 44] + +RFC 7601 Authentication-Results Header Field August 2015 + + +B.4. Service Provided, Several Authentications Done, Single MTA + + A message that was relayed inbound via a single MTA that conforms to + this specification and applied three different message authentication + checks: + + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.net; + spf=pass smtp.mailfrom=example.net + Authentication-Results: example.com; + sender-id=pass header.from=example.net + Received: from dialup-1-2-3-4.example.net (8.11.6/8.11.6) + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTPA id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + From: sender@example.net + Message-Id: <12345.abc@example.net> + Subject: here's a sample + + Hello! Goodbye! + + Example 4: Headers Reporting Results from One MTA + + The Authentication-Results header field is present, indicating that + the delivering MTA conforms to this specification. Once again, the + receiving DNS domain name is used as the authserv-id. Furthermore, + the sender authenticated herself/himself to the MTA via a method + specified in [AUTH], and both SPF and Sender ID checks were done and + passed. The MUA could extract and relay this extra information if + desired. + + Two Authentication-Results header fields are not required since the + same host did all of the checking. The authenticating agent could + have consolidated all the results into one header field. + + This example illustrates a scenario in which a remote user on a dial- + up connection (example.net) sends mail to a border MTA (example.com) + using SMTP authentication to prove identity. The dial-up provider + has been explicitly authorized to relay mail as example.com, + producing "pass" results from the SPF and Sender ID checks. + + + + + + + + +Kucherawy Standards Track [Page 45] + +RFC 7601 Authentication-Results Header Field August 2015 + + +B.5. Service Provided, Several Authentications Done, Different MTAs + + A message that was relayed inbound by two different MTAs that conform + to this specification and applied multiple message authentication + checks: + + Authentication-Results: example.com; + sender-id=fail header.from=example.com; + dkim=pass (good signature) header.d=example.com + Received: from mail-router.example.com + (mail-router.example.com [192.0.2.1]) + by auth-checker.example.com (8.11.6/8.11.6) + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; d=example.com; + t=1188964191; c=simple/simple; h=From:Date:To:Subject: + Message-Id:Authentication-Results; + bh=sEuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m70; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + Authentication-Results: example.com; + auth=pass (cram-md5) smtp.auth=sender@example.com; + spf=fail smtp.mailfrom=example.com + Received: from dialup-1-2-3-4.example.net + (dialup-1-2-3-4.example.net [192.0.2.200]) + by mail-router.example.com (8.11.6/8.11.6) + with ESMTPA id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + From: sender@example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: receiver@example.com + Message-Id: <12345.abc@example.com> + Subject: here's a sample + + Hello! Goodbye! + + Example 5: Headers Reporting Results from Multiple MTAs + + The Authentication-Results header field is present, indicating + conformance to this specification. Once again, the authserv-id used + is the recipient's DNS domain name. The header field is present + twice because two different MTAs in the chain of delivery did + authentication tests. The first MTA, mail-router.example.com, + reports that SMTP AUTH and SPF were both used and that the former + passed while the latter failed. In the SMTP AUTH case, additional + information is provided in the comment field, which the MUA can + choose to render if desired. + + + + + +Kucherawy Standards Track [Page 46] + +RFC 7601 Authentication-Results Header Field August 2015 + + + The second MTA, auth-checker.example.com, reports that it did a + Sender ID test (which failed) and a DKIM test (which passed). Again, + additional data about one of the tests is provided as a comment, + which the MUA may choose to render. Also noteworthy here is the fact + that there is a DKIM signature added by example.com that assured the + integrity of the lower Authentication-Results field. + + Since different hosts did the two sets of authentication checks, the + header fields cannot be consolidated in this example. + + This example illustrates more typical transmission of mail into + example.com from a user on a dial-up connection example.net. The + user appears to be legitimate as he/she had a valid password allowing + authentication at the border MTA using SMTP AUTH. The SPF and Sender + ID tests failed since example.com has not granted example.net + authority to relay mail on its behalf. However, the DKIM test passed + because the sending user had a private key matching one of + example.com's published public keys and used it to sign the message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 47] + +RFC 7601 Authentication-Results Header Field August 2015 + + +B.6. Service Provided, Multi-tiered Authentication Done + + A message that had authentication done at various stages, one of + which was outside the receiving ADMD: + + Authentication-Results: example.com; + dkim=pass reason="good signature" + header.i=@mail-router.example.net; + dkim=fail reason="bad signature" + header.i=@newyork.example.com + Received: from mail-router.example.net + (mail-router.example.net [192.0.2.250]) + by chicago.example.com (8.11.6/8.11.6) + for + with ESMTP id i7PK0sH7021929; + Fri, Feb 15 2002 17:19:22 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=furble; + d=mail-router.example.net; t=1188964198; c=relaxed/simple; + h=From:Date:To:Message-Id:Subject:Authentication-Results; + bh=ftA9J6GtX8OpwUECzHnCkRzKw1uk6FNiLfJl5Nmv49E=; + b=oINEO8hgn/gnunsg ... 9n9ODSNFSDij3= + Authentication-Results: example.net; + dkim=pass (good signature) header.i=@newyork.example.com + Received: from smtp.newyork.example.com + (smtp.newyork.example.com [192.0.2.220]) + by mail-router.example.net (8.11.6/8.11.6) + with ESMTP id g1G0r1kA003489; + Fri, Feb 15 2002 17:19:07 -0800 + DKIM-Signature: v=1; a=rsa-sha256; s=gatsby; + d=newyork.example.com; + t=1188964191; c=simple/simple; + h=From:Date:To:Message-Id:Subject; + bh=sEu28nfs9fuZGD/pSr7ANysbY3jtdaQ3Xv9xPQtS0m7=; + b=EToRSuvUfQVP3Bkz ... rTB0t0gYnBVCM= + From: sender@newyork.example.com + Date: Fri, Feb 15 2002 16:54:30 -0800 + To: meetings@example.net + Message-Id: <12345.abc@newyork.example.com> + Subject: here's a sample + + Example 6: Headers Reporting Results from Multiple MTAs in + Different ADMDs + + In this example, we see multi-tiered authentication with an extended + trust boundary. + + + + + + +Kucherawy Standards Track [Page 48] + +RFC 7601 Authentication-Results Header Field August 2015 + + + The message was sent from someone at example.com's New York office + (newyork.example.com) to a mailing list managed at an intermediary. + The message was signed at the origin using DKIM. + + The message was sent to a mailing list service provider called + example.net, which is used by example.com. There, + meetings@example.net is expanded to a long list of recipients, one of + whom is at the Chicago office. In this example, we will assume that + the trust boundary for chicago.example.com includes the mailing list + server at example.net. + + The mailing list server there first authenticated the message and + affixed an Authentication-Results header field indicating such using + its DNS domain name for the authserv-id. It then altered the message + by affixing some footer text to the body, including some + administrivia such as unsubscription instructions. Finally, the + mailing list server affixes a second DKIM signature and begins + distribution of the message. + + The border MTA for chicago.example.com explicitly trusts results from + mail-router.example.net, so that header field is not removed. It + performs evaluation of both signatures and determines that the first + (most recent) is a "pass" but, because of the aforementioned + modifications, the second is a "fail". However, the first signature + included the Authentication-Results header added at mail- + router.example.net that validated the second signature. Thus, + indirectly, it can be determined that the authentications claimed by + both signatures are indeed valid. + + Note that two styles of presenting metadata about the result are in + use here. In one case, the "reason=" clause is present, which is + intended for easy extraction by parsers; in the other case, the CFWS + production of the ABNF is used to include such data as a header field + comment. The latter can be harder for parsers to extract given the + varied supported syntaxes of mail header fields. + +B.7. Comment-Heavy Example + + The formal syntax permits comments within the content in a number of + places. For the sake of illustration, this example is also legal: + + Authentication-Results: foo.example.net (foobar) 1 (baz); + dkim (Because I like it) / 1 (One yay) = (wait for it) fail + policy (A dot can go here) . (like that) expired + (this surprised me) = (as I wasn't expecting it) 1362471462 + + Example 7: A Very Comment-Heavy but Perfectly Legal Example + + + + +Kucherawy Standards Track [Page 49] + +RFC 7601 Authentication-Results Header Field August 2015 + + +Appendix C. Operational Considerations about Message Authentication + + This protocol is predicated on the idea that authentication (and + presumably in the future, reputation) work is typically done by + border MTAs rather than MUAs or intermediate MTAs; the latter merely + make use of the results determined by the former. Certainly this is + not mandatory for participation in electronic mail or message + authentication, but this protocol and its deployment to date are + based on that model. The assumption satisfies several common ADMD + requirements: + + 1. Service operators prefer to resolve the handling of problem + messages as close to the border of the ADMD as possible. This + enables, for example, rejection of messages at the SMTP level + rather than generating a DSN internally. Thus, doing any of the + authentication or reputation work exclusively at the MUA or + intermediate MTA renders this desire unattainable. + + 2. Border MTAs are more likely to have direct access to external + sources of authentication or reputation information since modern + MUAs are more likely to be heavily firewalled. Thus, some MUAs + might not even be able to complete the task of performing + authentication or reputation evaluations without complex proxy + configurations or similar burdens. + + 3. MUAs rely upon the upstream MTAs within their trust boundaries to + make correct (as much as is possible) evaluations about the + message's envelope, header, and content. Thus, MUAs don't need + to know how to do the work that upstream MTAs do; they only need + the results of that work. + + 4. Evaluations about the quality of a message, from simple token + matching (e.g., a list of preferred DNS domains) to cryptanalysis + (e.g., public/private key work), do have a cost and thus need to + be minimized. To that end, performing those tests at the border + MTA is far preferred to doing that work at each MUA that handles + a message. If an ADMD's environment adheres to common messaging + protocols, a reputation query or an authentication check + performed by a border MTA would return the same result as the + same query performed by an MUA. By contrast, in an environment + where the MUA does the work, a message arriving for multiple + recipients would thus cause authentication or reputation + evaluation to be done more than once for the same message (i.e., + at each MUA), causing needless amplification of resource use and + creating a possible denial-of-service attack vector. + + + + + + +Kucherawy Standards Track [Page 50] + +RFC 7601 Authentication-Results Header Field August 2015 + + + 5. Minimizing change is good. As new authentication and reputation + methods emerge, the list of methods supported by this header + field would presumably be extended. If MUAs simply consume the + contents of this header field rather than actually attempt to do + authentication and/or reputation work, then MUAs only need to + learn to parse this header field once; emergence of new methods + requires only a configuration change at the MUAs and software + changes at the MTAs (which are presumably fewer in number). When + choosing to implement these functions in MTAs vs. MUAs, the + issues of individual flexibility, infrastructure inertia, and + scale of effort must be considered. It is typically easier to + change a single MUA than an MTA because the modification affects + fewer users and can be pursued with less care. However, changing + many MUAs is more effort than changing a smaller number of MTAs. + + 6. For decisions affecting message delivery and display, assessment + based on authentication and reputation is best performed close to + the time of message transit, as a message makes its journey + toward a user's inbox, not afterwards. DKIM keys and IP address + reputations, etc., can change over time or even become invalid, + and users can take a long time to read a message once delivered. + The value of this work thus degrades, perhaps quickly, once the + delivery process has completed. This seriously diminishes the + value of this work when done elsewhere than at MTAs. + + Many operational choices are possible within an ADMD, including the + venue for performing authentication and/or reputation assessment. + The current specification does not dictate any of those choices. + Rather, it facilitates those cases in which information produced by + one stage of analysis needs to be transported with the message to the + next stage. + +Appendix D. Changes since RFC 7001 + + o Applied RFC 7410. + + o Updated all references to RFC 4408 with RFC 7208. + + o Added section explaining "property" values. (Addressed Erratum + #4201.) + + o Did some minor text reorganization. + + o Gave registry history -- enough that this is now the authoritative + registry definition. + + o Added text explaining each of the method-ptype-property tuples + registered by this document. + + + +Kucherawy Standards Track [Page 51] + +RFC 7601 Authentication-Results Header Field August 2015 + + + o Changed the meaning of the "Defined" column of the methods + registry to be the place where each entry was created and + described; it is expected that this will then refer to the + method's defining document. Provided IANA with corresponding + update instructions. + + o Cleaned up registry structure and content, and replaced all + references to RFC 7001 with pointers to this document. + + o Added references: [DMARC], [PRA], [RFC6008], [RFC6577], [RRVS], + [SMIME-REG]. + + o Added description of values that can be extracted from SMTP AUTH + sessions and an example. + + o Provided much more complete descriptions of reporting DomainKeys + results. + + o Added more detail about Sender ID. + + o Marked all ADSP and DomainKeys entries as deprecated since their + defining documents are as well. + + o Reworked some text around ignoring unknown ptypes. + + o Completely described the ptypes registry. + + o Mentioned that EHLO is mapped to HELO for SPF. + + o RFC 7208 uses all-lowercase result strings now, so adjusted prose + accordingly. + + o Updated list of supported methods, and mentioned the registries + immediately below. + + o Mentioned that when a local-part is removed, the "@" goes with it. + + o Referred to RFC 7328 in the "iprev" definition. + + o Corrected the "smime-part" prose. + + o Updated examples that use SMTP AUTH to claim "with ESMTPA" in the + Received fields. + + o Made minor editorial adjustments. + + + + + + +Kucherawy Standards Track [Page 52] + +RFC 7601 Authentication-Results Header Field August 2015 + + +Acknowledgments + + The author wishes to acknowledge the following individuals for their + review and constructive criticism of this document: Stephane + Bortzmeyer, Scott Kitterman, John Levine, Tom Petch, and Pete + Resnick. + +Author's Address + + Murray S. Kucherawy + 270 Upland Drive + San Francisco, CA 94127 + United States + + Email: superuser@gmail.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kucherawy Standards Track [Page 53] + diff --git a/rfc/rfc8301.txt b/rfc/rfc8301.txt new file mode 100644 index 0000000000..4112df8ccb --- /dev/null +++ b/rfc/rfc8301.txt @@ -0,0 +1,283 @@ + + + + + + +Internet Engineering Task Force (IETF) S. Kitterman +Request for Comments: 8301 Kitterman Technical Services +Updates: 6376 January 2018 +Category: Standards Track +ISSN: 2070-1721 + + + Cryptographic Algorithm and Key Usage Update to + DomainKeys Identified Mail (DKIM) + +Abstract + + The cryptographic algorithm and key size requirements included when + DomainKeys Identified Mail (DKIM) was designed a decade ago are + functionally obsolete and in need of immediate revision. This + document updates DKIM requirements to those minimally suitable for + operation with currently specified algorithms. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc8301. + +Copyright Notice + + Copyright (c) 2018 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + +Kitterman Standards Track [Page 1] + +RFC 8301 DKIM Crypto Usage Update January 2018 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 2 + 3. Updates to DKIM Signing and Verification Requirements . . . . 3 + 3.1. Signing and Verification Algorithms . . . . . . . . . . . 3 + 3.2. Key Sizes . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4. Security Considerations . . . . . . . . . . . . . . . . . . . 3 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 4 + 6. References . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 6.1. Normative References . . . . . . . . . . . . . . . . . . 4 + 6.2. Informative References . . . . . . . . . . . . . . . . . 4 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 5 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 5 + +1. Introduction + + DKIM [RFC6376] signs email messages by creating hashes of the message + headers and content and signing the header hash with a digital + signature. Message recipients fetch the signature verification key + from the DNS where it is stored in a TXT record. + + The defining documents, RFC 6376 [RFC6376] and its predecessors, + specify a single signing algorithm, RSA [RFC8017], and recommend key + sizes of 1024 to 2048 bits (but require verification of 512-bit + keys). As discussed in US-CERT Vulnerability Note VU#268267 + [VULNOTE], the operational community has recognized that shorter keys + compromise the effectiveness of DKIM. While 1024-bit signatures are + common, stronger signatures are not. Widely used DNS configuration + software places a practical limit on key sizes, because the software + only handles a single 256-octet string in a TXT record, and RSA keys + significantly longer than 1024 bits don't fit in 256 octets. + + Due to the recognized weakness of the SHA-1 hash algorithm (see + [RFC6194]) and the wide availability of the SHA-256 hash algorithm + (it has been a required part of DKIM [RFC6376] since it was + originally standardized in 2007), the SHA-1 hash algorithm MUST NOT + be used. This is being done now to allow the operational community + time to fully shift to SHA-256 in advance of any SHA-1-related + crisis. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + + +Kitterman Standards Track [Page 2] + +RFC 8301 DKIM Crypto Usage Update January 2018 + + +3. Updates to DKIM Signing and Verification Requirements + + This document updates [RFC6376] as follows: + + o Section 3.1 of this document updates Section 3.3 of [RFC6376]. + + o Section 3.2 of this document updates Section 3.3.3 of [RFC6376]. + + o The algorithm described in Section 3.3.1 of [RFC6376] is now + historic and no longer used by DKIM. + + Sections 3.3.2 and 3.3.4 of [RFC6376] are not affected. + +3.1. Signing and Verification Algorithms + + DKIM supports multiple digital signature algorithms. Two algorithms + are defined by this specification at this time: rsa-sha1 and + rsa-sha256. Signers MUST sign using rsa-sha256. Verifiers MUST be + able to verify using rsa-sha256. rsa-sha1 MUST NOT be used for + signing or verifying. + + DKIM signatures identified as having been signed with historic + algorithms (currently, rsa-sha1) have permanently failed evaluation + as discussed in Section 3.9 of [RFC6376]. + +3.2. Key Sizes + + Selecting appropriate key sizes is a trade-off between cost, + performance, and risk. Since short RSA keys more easily succumb to + off-line attacks, Signers MUST use RSA keys of at least 1024 bits for + all keys. Signers SHOULD use RSA keys of at least 2048 bits. + Verifiers MUST be able to validate signatures with keys ranging from + 1024 bits to 4096 bits, and they MAY be able to validate signatures + with larger keys. Verifier policies can use the length of the + signing key as one metric for determining whether a signature is + acceptable. Verifiers MUST NOT consider signatures using RSA keys of + less than 1024 bits as valid signatures. + + DKIM signatures with insufficient key sizes (currently, rsa-sha256 + with less than 1024 bits) have permanently failed evaluation as + discussed in Section 3.9 of [RFC6376]. + +4. Security Considerations + + This document does not change the Security Considerations of + [RFC6376]. It reduces the risk of signature compromise due to weak + cryptography. The SHA-1 risks discussed in Section 3 of [RFC6194] + are resolved due to rsa-sha1 no longer being used by DKIM. + + + +Kitterman Standards Track [Page 3] + +RFC 8301 DKIM Crypto Usage Update January 2018 + + +5. IANA Considerations + + IANA has updated the Reference and Status fields of the "sha1" + registration in the "DKIM Hash Algorithms" registry. The + registration now appears as follows: + + +------+---------------------+----------+ + | Type | Reference | Status | + +------+---------------------+----------+ + | sha1 | [RFC6376] [RFC8301] | historic | + +------+---------------------+----------+ + +6. References + +6.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC6376] Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed., + "DomainKeys Identified Mail (DKIM) Signatures", STD 76, + RFC 6376, DOI 10.17487/RFC6376, September 2011, + . + + [RFC8017] Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch, + "PKCS #1: RSA Cryptography Specifications Version 2.2", + RFC 8017, DOI 10.17487/RFC8017, November 2016, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + +6.2. Informative References + + [RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security + Considerations for the SHA-0 and SHA-1 Message-Digest + Algorithms", RFC 6194, DOI 10.17487/RFC6194, March 2011, + . + + [VULNOTE] US-CERT, "Vulnerability Note VU#268267: DomainKeys + Identified Mail (DKIM) Verifiers may inappropriately + convey message trust", October 2012, + . + + + + + +Kitterman Standards Track [Page 4] + +RFC 8301 DKIM Crypto Usage Update January 2018 + + +Acknowledgements + + The author wishes to acknowledge the following individuals for their + review and comments on this proposal: Kurt Andersen, Murray + S. Kucherawy, Martin Thomson, John Levine, Russ Housley, and Jim + Fenton. + + Thanks to John Levine for his DKIM Crypto Update (DCRUP) work that + was the source for much of the introductory material in this + document. + +Author's Address + + Scott Kitterman + Kitterman Technical Services + 3611 Scheel Dr + Ellicott City, MD 21042 + United States of America + + Phone: +1 301 325-5475 + Email: scott@kitterman.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kitterman Standards Track [Page 5] + diff --git a/rfc/rfc8463.txt b/rfc/rfc8463.txt new file mode 100644 index 0000000000..31ff1eaffe --- /dev/null +++ b/rfc/rfc8463.txt @@ -0,0 +1,395 @@ + + + + + + +Internet Engineering Task Force (IETF) J. Levine +Request for Comments: 8463 Taughannock Networks +Updates: 6376 September 2018 +Category: Standards Track +ISSN: 2070-1721 + + + A New Cryptographic Signature Method for + DomainKeys Identified Mail (DKIM) + +Abstract + + This document adds a new signing algorithm, Ed25519-SHA256, to + "DomainKeys Identified Mail (DKIM) Signatures" (RFC 6376). DKIM + verifiers are required to implement this algorithm. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc8463. + +Copyright Notice + + Copyright (c) 2018 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + +Levine Standards Track [Page 1] + +RFC 8463 DKIM Crypto Update September 2018 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 2 + 3. Ed25519-SHA256 Signing Algorithm . . . . . . . . . . . . . . 3 + 4. Signature and Key Syntax . . . . . . . . . . . . . . . . . . 3 + 4.1. Signature Syntax . . . . . . . . . . . . . . . . . . . . 3 + 4.2. Key Syntax . . . . . . . . . . . . . . . . . . . . . . . 3 + 5. Choice and Strength of Keys and Algorithms . . . . . . . . . 4 + 6. Transition Considerations . . . . . . . . . . . . . . . . . . 4 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 4 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 4 + 8.1. "DKIM Key Type" Registry . . . . . . . . . . . . . . . . 4 + 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 9.1. Normative References . . . . . . . . . . . . . . . . . . 5 + 9.2. Informative References . . . . . . . . . . . . . . . . . 5 + Appendix A. Example of a Signed Message . . . . . . . . . . . . 6 + A.1. Secret Keys . . . . . . . . . . . . . . . . . . . . . . . 6 + A.2. Public Key DNS Records . . . . . . . . . . . . . . . . . 6 + A.3. Signed Message . . . . . . . . . . . . . . . . . . . . . 7 + Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 7 + +1. Introduction + + DKIM [RFC6376] signs email messages by creating hashes of selected + message header fields and body and signing the header hash with a + digital signature. Message recipients fetch the signature + verification key from the DNS. The defining documents specify a + single signing algorithm, RSA [RFC3447] (which has since been + obsoleted by [RFC8017]). + + This document adds a new, stronger signing algorithm, Edwards-Curve + Digital Signature Algorithm, using the Curve25519 curve (Ed25519), + which has much shorter keys than RSA for similar levels of security. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + Syntax descriptions use Augmented BNF (ABNF) [RFC5234]. The ABNF + tokens sig-a-tag-k and key-k-tag-type are imported from [RFC6376]. + + + + + + +Levine Standards Track [Page 2] + +RFC 8463 DKIM Crypto Update September 2018 + + +3. Ed25519-SHA256 Signing Algorithm + + The Ed25519-SHA256 signing algorithm computes a message hash as + defined in Section 3 of [RFC6376] using SHA-256 [FIPS-180-4-2015] as + the hash-alg. It signs the hash with the PureEdDSA variant Ed25519, + as defined in RFC 8032, Section 5.1 [RFC8032]. Example keys and + signatures in Appendix A are based on the test vectors in RFC 8032, + Section 7.1 [RFC8032]. + + The DNS record for the verification public key has a "k=ed25519" tag + to indicate that the key is an Ed25519 rather than an RSA key. + + This is an additional DKIM signature algorithm added to Section 3.3 + of [RFC6376] as envisioned in Section 3.3.4 of that document. + + Note: since Ed25519 public keys are 256 bits long, the base64-encoded + key is only 44 octets, so DNS key record data will generally fit in a + single 255-byte TXT string and work even with DNS provisioning + software that doesn't handle multistring TXT records. + +4. Signature and Key Syntax + + The syntax of DKIM signatures and DKIM keys are updated as follows. + +4.1. Signature Syntax + + The syntax of DKIM algorithm tags in Section 3.5 of [RFC6376] is + updated by adding this rule to the existing rule for sig-a-tag-k: + + ABNF: + + sig-a-tag-k =/ "ed25519" + +4.2. Key Syntax + + The syntax of DKIM key tags in Section 3.6.1 of [RFC6376] is updated + by adding this rule to the existing rule for key-k-tag-type: + + ABNF: + + key-k-tag-type =/ "ed25519" + + The p= value in the key record is the Ed25519 public key encoded in + base64. Since the key is 256 bits long, the base64 text is 44 octets + long. See Appendix A.2 for a sample key record using the public key + in [RFC8032], Section 7.1, Test 1. + + + + + +Levine Standards Track [Page 3] + +RFC 8463 DKIM Crypto Update September 2018 + + +5. Choice and Strength of Keys and Algorithms + + Section 3.3 of [RFC6376] describes DKIM's hash and signature + algorithms. It is updated as follows: + + Signers SHOULD implement and verifiers MUST implement the + Ed25519-SHA256 algorithm. + +6. Transition Considerations + + For backward compatibility, signers can add multiple signatures that + use old and new signing algorithms. Since there can only be a single + key record in the DNS for each selector, the signatures have to use + different selectors, although they can use the same d= and i= + identifiers. + + The example message in Appendix A has two signatures with the same d= + and i= identifiers but different a= algorithms and s= selectors. + +7. Security Considerations + + All of the security advice in [RFC6376] continues to apply, except + that the security advice about Ed25519 in Section 8 of [RFC8032] + supplants the advice about RSA threats. + +8. IANA Considerations + + IANA has updated a registry as follows. + +8.1. "DKIM Key Type" Registry + + The following value has been added to the "DKIM Key Type" registry: + + +---------+-----------+--------+ + | TYPE | REFERENCE | STATUS | + +---------+-----------+--------+ + | ed25519 | [RFC8032] | active | + +---------+-----------+--------+ + + Table 1: Value Added to the "DKIM Key Type" Registry + + + + + + + + + + + +Levine Standards Track [Page 4] + +RFC 8463 DKIM Crypto Update September 2018 + + +9. References + +9.1. Normative References + + [FIPS-180-4-2015] + National Institute of Standards and Technology, "Secure + Hash Standard (SHS)", FIPS PUB 180-4, + DOI 10.6028/NIST.FIPS.180-4, August 2015, + . + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC5234] Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, + DOI 10.17487/RFC5234, January 2008, + . + + [RFC6376] Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed., + "DomainKeys Identified Mail (DKIM) Signatures", STD 76, + RFC 6376, DOI 10.17487/RFC6376, September 2011, + . + + [RFC8017] Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch, + "PKCS #1: RSA Cryptography Specifications Version 2.2", + RFC 8017, DOI 10.17487/RFC8017, November 2016, + . + + [RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital + Signature Algorithm (EdDSA)", RFC 8032, + DOI 10.17487/RFC8032, January 2017, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + +9.2. Informative References + + [RFC3447] Jonsson, J. and B. Kaliski, "Public-Key Cryptography + Standards (PKCS) #1: RSA Cryptography Specifications + Version 2.1", RFC 3447, DOI 10.17487/RFC3447, February + 2003, . + + + + + +Levine Standards Track [Page 5] + +RFC 8463 DKIM Crypto Update September 2018 + + +Appendix A. Example of a Signed Message + + This is a small message with both RSA-SHA256 and Ed25519-SHA256 DKIM + signatures. The signatures are independent of each other, so either + signature would be valid if the other were not present. + +A.1. Secret Keys + + Ed25519 secret key in base64. This is the secret key from [RFC8032], + Section 7.1, Test 1, converted from hex to base64. + + nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A= + + RSA secret key in PEM format. + + -----BEGIN RSA PRIVATE KEY----- + MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi + Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM + KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB + AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm + 6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe + zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy + 6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc + uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy + WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd + WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a + licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst + o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe + uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL + -----END RSA PRIVATE KEY----- + +A.2. Public Key DNS Records + + The public key p= value in the first record is the public key from + [RFC8032], Section 7.1, Test 1, converted from hex to base64. + +brisbane._domainkey.football.example.com. IN TXT ( + "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=") + +test._domainkey.football.example.com. IN TXT ( + "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWR" + "iGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutAC" + "DfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3" + "Ip3G+2kryOTIKT+l/K4w3QIDAQAB") + + + + + + + +Levine Standards Track [Page 6] + +RFC 8463 DKIM Crypto Update September 2018 + + +A.3. Signed Message + + The text in each line of the message starts at the first position + except for the continuation lines on the DKIM-Signature header + fields, which start with a single space. A blank line follows the + "Joe." line. + + DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; + d=football.example.com; i=@football.example.com; + q=dns/txt; s=brisbane; t=1528637909; h=from : to : + subject : date : message-id : from : subject : date; + bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; + b=/gCrinpcQOoIfuHNQIbq4pgh9kyIK3AQUdt9OdqQehSwhEIug4D11Bus + Fa3bT3FY5OsU7ZbnKELq+eXdp1Q1Dw== + DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=football.example.com; i=@football.example.com; + q=dns/txt; s=test; t=1528637909; h=from : to : subject : + date : message-id : from : subject : date; + bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; + b=F45dVWDfMbQDGHJFlXUNB2HKfbCeLRyhDXgFpEL8GwpsRe0IeIixNTe3 + DhCVlUrSjV4BwcVcOF6+FF3Zo9Rpo1tFOeS9mPYQTnGdaSGsgeefOsk2Jz + dA+L10TeYt9BgDfQNZtKdN1WO//KgIqXP7OdEFE4LjFYNcUxZQ4FADY+8= + From: Joe SixPack + To: Suzie Q + Subject: Is dinner ready? + Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT) + Message-ID: <20030712040037.46341.5F8J@football.example.com> + + Hi. + + We lost the game. Are you hungry yet? + + Joe. + +Author's Address + + John Levine + Taughannock Networks + PO Box 727 + Trumansburg, NY 14886 + United States of America + + Phone: +883.5100.01196712 + Email: standards@taugh.com + + + + + + + +Levine Standards Track [Page 7] + diff --git a/rfc/rfc8550.txt b/rfc/rfc8550.txt new file mode 100644 index 0000000000..f143190781 --- /dev/null +++ b/rfc/rfc8550.txt @@ -0,0 +1,1571 @@ + + + + + + +Internet Engineering Task Force (IETF) J. Schaad +Request for Comments: 8550 August Cellars +Obsoletes: 5750 B. Ramsdell +Category: Standards Track Brute Squad Labs, Inc. +ISSN: 2070-1721 S. Turner + sn3rd + April 2019 + + + Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 + Certificate Handling + +Abstract + + This document specifies conventions for X.509 certificate usage by + Secure/Multipurpose Internet Mail Extensions (S/MIME) v4.0 agents. + S/MIME provides a method to send and receive secure MIME messages, + and certificates are an integral part of S/MIME agent processing. + S/MIME agents validate certificates as described in RFC 5280 + ("Internet X.509 Public Key Infrastructure Certificate and + Certificate Revocation List (CRL) Profile"). S/MIME agents must meet + the certificate-processing requirements in this document as well as + those in RFC 5280. This document obsoletes RFC 5750. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc8550. + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 1] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +Copyright Notice + + Copyright (c) 2019 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + This document may contain material from IETF Documents or IETF + Contributions published or made publicly available before November + 10, 2008. The person(s) controlling the copyright in some of this + material may not have granted the IETF Trust the right to allow + modifications of such material outside the IETF Standards Process. + Without obtaining an adequate license from the person(s) controlling + the copyright in such materials, this document may not be modified + outside the IETF Standards Process, and derivative works of it may + not be created outside the IETF Standards Process, except to format + it for publication as an RFC or to translate it into languages other + than English. + + + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 2] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Definitions . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.2. Conventions Used in This Document . . . . . . . . . . . . 5 + 1.3. Compatibility with Prior Practice of S/MIME . . . . . . . 6 + 1.4. Changes from S/MIME v3 to S/MIME v3.1 . . . . . . . . . . 6 + 1.5. Changes from S/MIME v3.1 to S/MIME v3.2 . . . . . . . . . 7 + 1.6. Changes since S/MIME 3.2 . . . . . . . . . . . . . . . . 8 + 2. CMS Options . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 2.1. Certificate Revocation Lists . . . . . . . . . . . . . . 9 + 2.2. Certificate Choices . . . . . . . . . . . . . . . . . . . 9 + 2.2.1. Historical Note about CMS Certificates . . . . . . . 9 + 2.3. Included Certificates . . . . . . . . . . . . . . . . . . 10 + 3. Using Distinguished Names for Internet Mail . . . . . . . . . 11 + 4. Certificate Processing . . . . . . . . . . . . . . . . . . . 12 + 4.1. Certificate Revocation Lists . . . . . . . . . . . . . . 13 + 4.2. Certificate Path Validation . . . . . . . . . . . . . . . 13 + 4.3. Certificate and CRL Signing Algorithms, and Key Sizes . . 14 + 4.4. PKIX Certificate Extensions . . . . . . . . . . . . . . . 15 + 4.4.1. Basic Constraints . . . . . . . . . . . . . . . . . . 16 + 4.4.2. Key Usage Extension . . . . . . . . . . . . . . . . . 16 + 4.4.3. Subject Alternative Name . . . . . . . . . . . . . . 17 + 4.4.4. Extended Key Usage Extension . . . . . . . . . . . . 17 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 18 + 6. Security Considerations . . . . . . . . . . . . . . . . . . . 18 + 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 20 + 7.1. Reference Conventions . . . . . . . . . . . . . . . . . . 20 + 7.1. Normative References . . . . . . . . . . . . . . . . . . 20 + 7.2. Informative References . . . . . . . . . . . . . . . . . 23 + Appendix A. Historic Considerations . . . . . . . . . . . . . . 26 + A.1. Signature Algorithms and Key Sizes . . . . . . . . . . . 26 + Appendix B. Moving S/MIME v2 Certificate Handling to Historic + Status . . . . . . . . . . . . . . . . . . . . . . . 27 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 28 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 28 + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 3] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +1. Introduction + + S/MIME (Secure/Multipurpose Internet Mail Extensions) v4.0, described + in [RFC8551], provides a method to send and receive secure MIME + messages. Before using a public key to provide security services, + the S/MIME agent MUST verify that the public key is valid. S/MIME + agents MUST use PKIX certificates to validate public keys as + described in [RFC5280] ("Internet X.509 Public Key Infrastructure + Certificate and Certificate Revocation List (CRL) Profile"). S/MIME + agents MUST meet the certificate-processing requirements specified in + this document in addition to those stated in [RFC5280]. + + This specification is compatible with the Cryptographic Message + Syntax (CMS) [RFC5652] in that it uses the data types defined by CMS. + It also inherits all the varieties of architectures for certificate- + based key management supported by CMS. + + This document obsoletes [RFC5750]. The most significant changes + revolve around changes in recommendations around the cryptographic + algorithms used by the specification. More details can be found in + Section 1.6. + + This specification contains a number of references to documents that + have been obsoleted or replaced. This is intentional, as the updated + documents often do not have the same information or protocol + requirements in them. + +1.1. Definitions + + For the purposes of this document, the following definitions apply. + + ASN.1: + Abstract Syntax Notation One, as defined in ITU-T X.680 [X.680]. + + Attribute certificate (AC): + An X.509 AC is a separate structure from a subject's public key + X.509 certificate. A subject may have multiple X.509 ACs + associated with each of its public key X.509 certificates. Each + X.509 AC binds one or more attributes with one of the subject's + public key X.509 certificates. The X.509 AC syntax is defined in + [RFC5755]. + + + + + + + + + + +Schaad, et al. Standards Track [Page 4] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + Certificate: + A type that binds an entity's name to a public key with a digital + signature. This type is defined in [RFC5280]. This type also + contains the distinguished name of the certificate issuer (the + signer), an issuer-specific serial number, the issuer's signature + algorithm identifier, a validity period, and extensions also + defined in that document. + + Certificate Revocation List (CRL): + A type that contains information about certificates whose validity + an issuer has revoked. The information consists of an issuer + name, the time of issue, the next scheduled time of issue, a list + of certificate serial numbers and their associated revocation + times, and extensions as defined in [RFC5280]. The CRL is signed + by the issuer. The type intended by this specification is the one + defined in [RFC5280]. + + Receiving agent: + Software that interprets and processes S/MIME CMS objects, MIME + body parts that contain CMS objects, or both. + + Sending agent: + Software that creates S/MIME CMS objects, MIME body parts that + contain CMS objects, or both. + + S/MIME agent: + User software that is a receiving agent, a sending agent, or both. + +1.2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + We define the additional requirement levels: + + SHOULD+ This term means the same as SHOULD. However, the authors + expect that a requirement marked as SHOULD+ will be + promoted at some future time to be a MUST. + + SHOULD- This term means the same as SHOULD. However, the authors + expect that a requirement marked as SHOULD- will be demoted + to a MAY in a future version of this document. + + + + + + +Schaad, et al. Standards Track [Page 5] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + MUST- This term means the same as MUST. However, the authors + expect that this requirement will no longer be a MUST in a + future document. Although its status will be determined at + a later time, it is reasonable to expect that if a future + revision of a document alters the status of a MUST- + requirement, it will remain at least a SHOULD or a SHOULD-. + + The term "RSA" in this document almost always refers to the + PKCS #1 v1.5 RSA signature algorithm even when not qualified as such. + There are a couple of places where it refers to the general RSA + cryptographic operation; these can be determined from the context + where it is used. + +1.3. Compatibility with Prior Practice of S/MIME + + S/MIME version 4.0 agents ought to attempt to have the greatest + interoperability possible with agents for prior versions of S/MIME. + + - S/MIME version 2 is described in RFC 2311 through RFC 2315 + inclusive [SMIMEv2]. + + - S/MIME version 3 is described in RFC 2630 through RFC 2634 + inclusive and RFC 5035 [SMIMEv3]. + + - S/MIME version 3.1 is described in RFC 2634, RFC 3850, RFC 3851, + RFC 3852, and RFC 5035 [SMIMEv3.1]. + + - S/MIME version 3.2 is described in RFC 2634, RFC 5035, RFC 5652, + RFC 5750, and RFC 5751 [SMIMEv3.2]. + + - RFC 2311 also has historical information about the development of + S/MIME. + + Appendix A contains information about algorithms that were used for + prior versions of S/MIME but are no longer considered to meet modern + security standards. Support of these algorithms may be needed to + support historic S/MIME artifacts such as messages or files but + SHOULD NOT be used for new artifacts. + +1.4. Changes from S/MIME v3 to S/MIME v3.1 + + This section reflects the changes that were made when S/MIME v3.1 was + released. The language of RFC 2119 ("MUST", "SHOULD", etc.) used for + S/MIME v3 may have been superseded in later versions. + + - Version 1 and version 2 CRLs MUST be supported. + + + + + +Schaad, et al. Standards Track [Page 6] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + - Multiple certification authority (CA) certificates with the same + subject and public key, but with overlapping validity periods, + MUST be supported. + + - Version 2 ACs SHOULD be supported, and version 1 ACs MUST NOT be + used. + + - The use of the MD2 digest algorithm for certificate signatures is + discouraged, and security language was added. + + - Clarified email address use in certificates. Certificates that do + not contain an email address have no requirements for verifying + the email address associated with the certificate. + + - Receiving agents SHOULD display certificate information when + displaying the results of signature verification. + + - Receiving agents MUST NOT accept a signature made with a + certificate that does not have at least one of the + digitalSignature or nonRepudiation bits set. + + - Added clarifications for the interpretation of the key usage and + extended key usage extensions. + +1.5. Changes from S/MIME v3.1 to S/MIME v3.2 + + This section reflects the changes that were made when S/MIME v3.2 was + released. The language of RFC 2119 ("MUST", "SHOULD", etc.) used for + S/MIME v3.1 may have been superseded in later versions. + + Note that the section numbers listed here (e.g., "Section 6") are + from [RFC5750]. + + - Moved "Conventions Used in This Document" to Section 1.2. Added + definitions for SHOULD+, SHOULD-, and MUST-. + + - Section 1.1: Updated ASN.1 definition and reference. + + - Section 1.3: Added text about v3.1 RFCs. + + - Section 3: Aligned email address text with RFC 5280. Updated note + to indicate that the emailAddress IA5String upper bound is + 255 characters. Added text about matching email addresses. + + - Section 4.2: Added text to indicate how S/MIME agents locate the + correct user certificate. + + + + + +Schaad, et al. Standards Track [Page 7] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + - Section 4.3: RSA with SHA-256 (PKCS #1 v1.5) added as MUST; DSA + with SHA-256 added as SHOULD+; RSA with SHA-1, DSA with SHA-1, and + RSA with MD5 changed to SHOULD-; and RSASSA-PSS with SHA-256 added + as SHOULD+. Updated key sizes and changed pointer to PKIX RFCs. + + - Section 4.4.1: Aligned with PKIX on the use of a basicConstraints + extension in CA certificates. Clarified which extension is used + to constrain end entities from using their keys to perform + issuing-authority operations. + + - Section 5: Updated security considerations. + + - Section 6: Moved references from Appendix A of RFC 3850 to this + section. Updated the references. + + - Appendix A: Added Appendix A to move S/MIME v2 Certificate + Handling to Historic status. + +1.6. Changes since S/MIME 3.2 + + This section reflects the changes that were made when S/MIME v4.0 was + released. The language of RFC 2119 ("MUST", "SHOULD", etc.) used for + S/MIME v3.2 may have been superseded by S/MIME v4.0 and may be + superseded by future versions. + + - Section 3: Support for internationalized email addresses is + required. + + - Section 4.3: Mandated support for the Elliptic Curve Digital + Signature Algorithm (ECDSA) with P-256 and the Edwards-curve + Digital Signature Algorithm (EdDSA) with curve25519 [RFC8410]. + SHA-1 and MD5 algorithms are marked as historical, as they are no + longer considered secure. As the Digital Signature Algorithm + (DSA) has been replaced by elliptic curve versions, support for + DSA is now considered historical. Increased lower bounds on RSA + key sizes. + + - Appendix A: Added Appendix A for algorithms that are now + considered to be historical. + +2. CMS Options + + The CMS message format allows for a wide variety of options in + content and algorithm support. This section puts forth a number of + support requirements and recommendations in order to achieve a base + level of interoperability among all S/MIME implementations. Most of + the CMS format for S/MIME messages is defined in [RFC8551]. + + + + +Schaad, et al. Standards Track [Page 8] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +2.1. Certificate Revocation Lists + + Receiving agents MUST support the CRL format defined in [RFC5280]. + If sending agents include CRLs in outgoing messages, the CRL format + defined in [RFC5280] MUST be used. Receiving agents MUST support + both v1 and v2 CRLs. + + All agents MUST be capable of performing revocation checks using CRLs + as specified in [RFC5280]. All agents MUST perform revocation status + checking in accordance with [RFC5280]. Receiving agents MUST + recognize CRLs in received S/MIME messages. + + Agents SHOULD store CRLs received in messages for use in processing + later messages. + +2.2. Certificate Choices + + Receiving agents MUST support v1 X.509 and v3 X.509 certificates as + profiled in [RFC5280]. End-entity certificates MAY include an + Internet mail address, as described in Section 3. + + Receiving agents SHOULD support X.509 version 2 ACs. See [RFC5755] + for details about the profile for ACs. + +2.2.1. Historical Note about CMS Certificates + + The CMS message format supports a choice of certificate formats for + public key content types: PKIX, PKCS #6 extended certificates + [PKCS6], and PKIX ACs. + + The PKCS #6 format is not in widespread use. In addition, PKIX + certificate extensions address much of the same functionality and + flexibility as was intended in the PKCS #6 certificate extensions. + Thus, sending and receiving agents MUST NOT use PKCS #6 extended + certificates. Receiving agents MUST be able to parse and process a + message containing PKCS #6 extended certificates, although ignoring + those certificates is expected behavior. + + X.509 version 1 ACs are also not widely implemented and have + been superseded by version 2 ACs. Sending agents MUST NOT send + version 1 ACs. + + + + + + + + + + +Schaad, et al. Standards Track [Page 9] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +2.3. Included Certificates + + Receiving agents MUST be able to handle an arbitrary number of + certificates of arbitrary relationship to the message sender and to + each other in arbitrary order. In many cases, the certificates + included in a signed message may represent a chain of certification + from the sender to a particular root. There may be, however, + situations where the certificates in a signed message may be + unrelated and included for convenience. + + Sending agents SHOULD include any certificates for the user's public + key(s) and associated issuer certificates. This increases the + likelihood that the intended recipient can establish trust in the + originator's public key(s). This is especially important when + sending a message to recipients that may not have access to the + sender's public key through any other means or when sending a signed + message to a new recipient. The inclusion of certificates in + outgoing messages can be omitted if S/MIME objects are sent within a + group of correspondents that have established access to each other's + certificates by some other means such as a shared directory or manual + certificate distribution. Receiving S/MIME agents SHOULD be able to + handle messages without certificates by using a database or directory + lookup scheme to find them. + + A sending agent SHOULD include at least one chain of certificates up + to, but not including, a CA that it believes that the recipient may + trust as authoritative. A receiving agent MUST be able to handle an + arbitrarily large number of certificates and chains. + + Agents MAY send CA certificates -- that is, cross-certificates, + self-issued certificates, and self-signed certificates. Note that + receiving agents SHOULD NOT simply trust any self-signed certificates + as valid CAs but SHOULD use some other mechanism to determine if this + is a CA that should be trusted. Also note that when certificates + contain DSA public keys the parameters may be located in the root + certificate. This would require that the recipient possess both the + end-entity certificate and the root certificate to perform a + signature verification, and is a valid example of a case where + transmitting the root certificate may be required. + + Receiving agents MUST support chaining based on the distinguished + name fields. Other methods of building certificate chains MAY be + supported. + + Receiving agents SHOULD support the decoding of X.509 ACs included in + CMS objects. All other issues regarding the generation and use of + X.509 ACs are outside the scope of this specification. One + specification that addresses AC use is defined in [RFC3114]. + + + +Schaad, et al. Standards Track [Page 10] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +3. Using Distinguished Names for Internet Mail + + End-entity certificates MAY contain an Internet mail address. + Email addresses restricted to 7-bit ASCII characters use the + pkcs-9-at-emailAddress object identifier (OID) (see below) and are + encoded as described in Section 4.2.1.6 of [RFC5280]. + Internationalized email address names use the OID defined in + [RFC8398] and are encoded as described therein. The email address + SHOULD be in the subjectAltName extension and SHOULD NOT be in the + subject distinguished name. + + Receiving agents MUST recognize and accept certificates that contain + no email address. Agents are allowed to provide an alternative + mechanism for associating an email address with a certificate that + does not contain an email address, such as through the use of the + agent's address book, if available. Receiving agents MUST recognize + both ASCII and internationalized email addresses in the + subjectAltName extension. Receiving agents MUST recognize email + addresses in the distinguished name field in the PKCS #9 [RFC2985] + emailAddress attribute: + + pkcs-9-at-emailAddress OBJECT IDENTIFIER ::= + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 1 } + + Note that this attribute MUST be encoded as IA5String and has an + upper bound of 255 characters. The comparing of email addresses is + fraught with peril. [RFC8398] defines the procedure for doing the + comparison of internationalized email addresses. For ASCII email + addresses, the domain component (right-hand side of the '@') MUST be + compared using a case-insensitive function. The local name + component (left-hand side of the '@') SHOULD be compared using a + case-insensitive function. Some localities may perform other + transformations on the local name component before doing the + comparison; however, an S/MIME client cannot know what specific + localities do. + + Sending agents SHOULD make the address in the From or Sender header + in a mail message match an Internet mail address in the signer's + certificate. Receiving agents MUST check that the address in the + From or Sender header of a mail message matches an Internet mail + address in the signer's certificate, if mail addresses are present in + the certificate. A receiving agent SHOULD provide some explicit + alternate processing of the message if this comparison fails; this + might be done by displaying or logging a message that shows the + recipient the mail addresses in the certificate or other certificate + details. + + + + + +Schaad, et al. Standards Track [Page 11] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + A receiving agent SHOULD display a subject name or other certificate + details when displaying an indication of successful or unsuccessful + signature verification. + + All subject and issuer names MUST be populated (i.e., not an empty + SEQUENCE) in S/MIME-compliant X.509 certificates, except that the + subject distinguished name in a user's (i.e., an end entity's) + certificate MAY be an empty SEQUENCE, in which case the + subjectAltName extension will include the subject's identifier and + MUST be marked as critical. + +4. Certificate Processing + + S/MIME agents need to provide some certificate retrieval mechanism in + order to gain access to certificates for recipients of digital + envelopes. There are many ways to implement certificate retrieval + mechanisms. [X.500] directory service is an excellent example of a + certificate retrieval-only mechanism that is compatible with classic + X.500 distinguished names. The IETF has published [RFC8162], which + describes an experimental protocol to retrieve certificates from the + Domain Name System (DNS). Until such mechanisms are widely used, + their utility may be limited by the small number of the + correspondent's certificates that can be retrieved. At a minimum, + for initial S/MIME deployment, a user agent could automatically + generate a message to an intended recipient requesting the + recipient's certificate in a signed return message. + + Receiving and sending agents SHOULD also provide a mechanism to allow + a user to "store and protect" certificates for correspondents in such + a way as to guarantee their later retrieval. In many environments, + it may be desirable to link the certificate retrieval/storage + mechanisms together in some sort of certificate database. In its + simplest form, a certificate database would be local to a particular + user and would function in a way similar to an "address book" that + stores a user's frequent correspondents. In this way, the + certificate retrieval mechanism would be limited to the certificates + that a user has stored (presumably from incoming messages). A + comprehensive certificate retrieval/storage solution might combine + two or more mechanisms to allow the greatest flexibility and utility + to the user. For instance, a secure Internet mail agent might resort + to checking a centralized certificate retrieval mechanism for a + certificate if it cannot be found in a user's local certificate + storage/retrieval database. + + + + + + + + +Schaad, et al. Standards Track [Page 12] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + Receiving and sending agents SHOULD provide a mechanism for the + import and export of certificates, using a CMS certs-only message. + This allows for import and export of full certificate chains as + opposed to just a single certificate. This is described in + [RFC8551]. + + Agents MUST handle multiple valid CA certificates containing the same + subject name and the same public keys but with overlapping validity + intervals. + +4.1. Certificate Revocation Lists + + In general, it is always better to get the latest CRL information + from a CA than to get information stored in an incoming message. A + receiving agent SHOULD have access to some CRL retrieval mechanism in + order to gain access to certificate revocation information when + validating certification paths. A receiving or sending agent SHOULD + also provide a mechanism to allow a user to store incoming + certificate revocation information for correspondents in such a way + as to guarantee its later retrieval. + + Receiving and sending agents SHOULD retrieve and utilize CRL + information every time a certificate is verified as part of a + certification path validation even if the certificate was already + verified in the past. However, in many instances (such as off-line + verification), access to the latest CRL information may be difficult + or impossible. The use of CRL information, therefore, may be + dictated by the value of the information that is protected. The + value of the CRL information in a particular context is beyond the + scope of this specification but may be governed by the policies + associated with particular certification paths. + + All agents MUST be capable of performing revocation checks using CRLs + as specified in [RFC5280]. All agents MUST perform revocation status + checking in accordance with [RFC5280]. Receiving agents MUST + recognize CRLs in received S/MIME messages. + +4.2. Certificate Path Validation + + In creating a user agent for secure messaging, certificate, CRL, and + certification path validation should be highly automated while still + acting in the best interests of the user. Certificate, CRL, and path + validation MUST be performed as per [RFC5280] when validating a + correspondent's public key. This is necessary before using a public + key to provide security services such as verifying a signature, + encrypting a content-encryption key (e.g., RSA), or forming a + pairwise symmetric key (e.g., Diffie-Hellman) to be used to encrypt + or decrypt a content-encryption key. + + + +Schaad, et al. Standards Track [Page 13] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + Certificates and CRLs are made available to the path validation + procedure in two ways: a) incoming messages and b) certificate and + CRL retrieval mechanisms. Certificates and CRLs in incoming messages + are not required to be in any particular order, nor are they required + to be in any way related to the sender or recipient of the message + (although in most cases they will be related to the sender). + Incoming certificates and CRLs SHOULD be cached for use in path + validation and optionally stored for later use. This temporary + certificate and CRL cache SHOULD be used to augment any other + certificate and CRL retrieval mechanisms for path validation on + incoming signed messages. + + When verifying a signature and the certificates that are included in + the message, if a signingCertificate attribute from RFC 2634 [ESS] or + a signingCertificateV2 attribute from RFC 5035 [ESS] is found in an + S/MIME message, it SHALL be used to identify the signer's + certificate. Otherwise, the certificate is identified in an S/MIME + message, using either (1) the issuerAndSerialNumber, which identifies + the signer's certificate by the issuer's distinguished name and the + certificate serial number or (2) the subjectKeyIdentifier, which + identifies the signer's certificate by a key identifier. + + When decrypting an encrypted message, if an + SMIMEEncryptionKeyPreference attribute is found in an encapsulating + SignedData, it SHALL be used to identify the originator's certificate + found in OriginatorInfo. See [RFC5652] for the CMS fields that + reference the originator's and recipient's certificates. + +4.3. Certificate and CRL Signing Algorithms, and Key Sizes + + Certificates and CRLs are signed by the certificate issuer. + Receiving agents: + + - MUST support ECDSA with curve P-256 with SHA-256. + + - MUST support EdDSA with curve25519 using PureEdDSA mode. + + - MUST- support RSA PKCS #1 v1.5 with SHA-256. + + - SHOULD support the RSA Probabilistic Signature Scheme (RSASSA-PSS) + with SHA-256. + + Implementations SHOULD use deterministic generation for the parameter + 'k' for ECDSA as outlined in [RFC6979]. EdDSA is defined to generate + this parameter deterministically. + + + + + + +Schaad, et al. Standards Track [Page 14] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + The following are the RSA and RSASSA-PSS key size requirements for + S/MIME receiving agents during certificate and CRL signature + verification: + + key size <= 2047 : SHOULD NOT (see Appendix A) + 2048 <= key size <= 4096 : MUST (see Security Considerations) + 4096 < key size : MAY (see Security Considerations) + + The signature algorithm OIDs for RSA PKCS #1 v1.5 and RSASSA-PSS with + SHA-256 using 1024-bit through 3072-bit public keys are specified in + [RFC4055], and the signature algorithm definition is found in + [FIPS186-2] with Change Notice 1. + + The signature algorithm OIDs for RSA PKCS #1 v1.5 and RSASSA-PSS with + SHA-256 using 4096-bit public keys are specified in [RFC4055], and + the signature algorithm definition is found in [RFC3447]. + + For RSASSA-PSS with SHA-256, see [RFC4056]. + + For ECDSA, see [RFC5758] and [RFC6090]. The first reference provides + the signature algorithm's OID, and the second provides the signature + algorithm's definition. Curves other than curve P-256 MAY be used as + well. + + For EdDSA, see [RFC8032] and [RFC8410]. The first reference provides + the signature algorithm's OID, and the second provides the signature + algorithm's definition. Curves other than curve25519 MAY be used as + well. + +4.4. PKIX Certificate Extensions + + PKIX describes an extensible framework in which the basic certificate + information can be extended and describes how such extensions can be + used to control the process of issuing and validating certificates. + The LAMPS Working Group has ongoing efforts to identify and create + extensions that have value in particular certification environments. + Further, there are active efforts underway to issue PKIX certificates + for business purposes. This document identifies the minimum required + set of certificate extensions that have the greatest value in the + S/MIME environment. The syntax and semantics of all the identified + extensions are defined in [RFC5280]. + + Sending and receiving agents MUST correctly handle the basic + constraints, key usage, authority key identifier, subject key + identifier, and subject alternative name certificate extensions when + they appear in end-entity and CA certificates. Some mechanism SHOULD + exist to gracefully handle other certificate extensions when they + appear in end-entity or CA certificates. + + + +Schaad, et al. Standards Track [Page 15] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + Certificates issued for the S/MIME environment SHOULD NOT contain any + critical extensions (extensions that have the critical field set to + TRUE) other than those listed here. These extensions SHOULD be + marked as non-critical, unless the proper handling of the extension + is deemed critical to the correct interpretation of the associated + certificate. Other extensions may be included, but those extensions + SHOULD NOT be marked as critical. + + Interpretation and syntax for all extensions MUST follow [RFC5280], + unless otherwise specified here. + +4.4.1. Basic Constraints + + The basicConstraints extension serves to delimit the role and + position that an issuing-authority or end-entity certificate plays in + a certification path. + + For example, certificates issued to CAs and subordinate CAs contain a + basicConstraints extension that identifies them as issuing-authority + certificates. End-entity certificates contain the key usage + extension, which restrains end entities from using the key when + performing issuing-authority operations (see Section 4.4.2). + + As per [RFC5280], certificates MUST contain a basicConstraints + extension in CA certificates and SHOULD NOT contain that extension in + end-entity certificates. + +4.4.2. Key Usage Extension + + The key usage extension serves to limit the technical purposes for + which a public key listed in a valid certificate may be used. + Issuing-authority certificates may contain a key usage extension that + restricts the key to signing certificates, CRLs, and other data. + + For example, a CA may create subordinate issuer certificates that + contain a key usage extension that specifies that the corresponding + public key can be used to sign end-user certificates and CRLs. + + If a key usage extension is included in a PKIX certificate, then it + MUST be marked as critical. + + S/MIME receiving agents MUST NOT accept the signature of a message if + it was verified using a certificate that contains a key usage + extension without at least one of the digitalSignature or + nonRepudiation bits set. Sometimes S/MIME is used as a secure + message transport for applications beyond interpersonal messaging; in + + + + + +Schaad, et al. Standards Track [Page 16] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + such cases, the S/MIME-enabled application can specify additional + requirements concerning the digitalSignature or nonRepudiation bits + within this extension. + + If the key usage extension is not specified, receiving clients MUST + presume that both the digitalSignature and nonRepudiation bits + are set. + +4.4.3. Subject Alternative Name + + The subject alternative name extension is used in S/MIME as the + preferred means to convey the email address or addresses that + correspond to the entity for this certificate. If the local portion + of the email address is ASCII, it MUST be encoded using the + rfc822Name CHOICE of the GeneralName type as described in [RFC5280], + Section 4.2.1.6. If the local portion of the email address is not + ASCII, it MUST be encoded using the otherName CHOICE of the + GeneralName type as described in [RFC8398], Section 3. Since the + SubjectAltName type is a SEQUENCE OF GeneralName, multiple email + addresses MAY be present. + +4.4.4. Extended Key Usage Extension + + The extended key usage extension also serves to limit the technical + purposes for which a public key listed in a valid certificate may be + used. The set of technical purposes for the certificate therefore + are the intersection of the uses indicated in the key usage and + extended key usage extensions. + + For example, if the certificate contains a key usage extension + indicating a digital signature and an extended key usage extension + that includes the id-kp-emailProtection OID, then the certificate may + be used for signing but not encrypting S/MIME messages. If the + certificate contains a key usage extension indicating a digital + signature but no extended key usage extension, then the certificate + may also be used to sign but not encrypt S/MIME messages. + + If the extended key usage extension is present in the certificate, + then interpersonal-message S/MIME receiving agents MUST check that it + contains either the id-kp-emailProtection OID or the + anyExtendedKeyUsage OID as defined in [RFC5280]. S/MIME uses other + than interpersonal messaging MAY require the explicit presence of the + extended key usage extension, the presence of other OIDs in the + extension, or both. + + + + + + + +Schaad, et al. Standards Track [Page 17] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +5. IANA Considerations + + This document has no IANA actions. + +6. Security Considerations + + All of the security issues faced by any cryptographic application + must be faced by an S/MIME agent. Among these issues are protecting + the user's private key, preventing various attacks, and helping the + user avoid mistakes such as inadvertently encrypting a message for + the wrong recipient. The entire list of security considerations is + beyond the scope of this document, but some significant concerns are + listed here. + + When processing certificates, there are many situations where the + processing might fail. Because the processing may be done by a user + agent, a security gateway, or some other program, there is no single + way to handle such failures. Just because the methods to handle the + failures have not been listed, however, the reader should not assume + that they are not important. The opposite is true: if a certificate + is not provably valid and associated with the message, the processing + software should take immediate and noticeable steps to inform the end + user about it. + + Some of the many places where signature and certificate checking + might fail include the following: + + - no Internet mail addresses in a certificate match the sender of a + message, if the certificate contains at least one mail address + + - no certificate chain leads to a trusted CA + + - no ability to check the CRL for a certificate is implemented + + - an invalid CRL was received + + - the CRL being checked is expired + + - the certificate is expired + + - the certificate has been revoked + + There are certainly other instances where a certificate may be + invalid, and it is the responsibility of the processing software to + check them all thoroughly and decide what to do if the check fails. + + + + + + +Schaad, et al. Standards Track [Page 18] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + It is possible for there to be multiple unexpired CRLs for a CA. If + an agent is consulting CRLs for certificate validation, it SHOULD + make sure that the most recently issued CRL for that CA is consulted, + since an S/MIME message sender could deliberately include an older + unexpired CRL in an S/MIME message. This older CRL might not include + recently revoked certificates; this scenario might lead an agent to + accept a certificate that has been revoked in a subsequent CRL. + + When determining the time for a certificate validity check, agents + have to be careful to use a reliable time. In most cases, the time + used SHOULD be the current time. Some exceptions to this would be as + follows: + + - The time the message was received is stored in a secure manner and + is used at a later time to validate the message. + + - The time in a SigningTime attribute is found in a countersignature + attribute [RFC5652] that has been successfully validated. + + The signingTime attribute could be deliberately set to a time where + the receiving agent would (1) use a CRL that does not contain a + revocation for the signing certificate or (2) use a certificate that + has expired or is not yet valid. This could be done by either + (1) the sender of the message or (2) an attacker that has compromised + the key of the sender. + + In addition to the security considerations identified in [RFC5280], + caution should be taken when processing certificates that have not + first been validated to a trust anchor. Certificates could be + manufactured by untrusted sources for the purpose of mounting denial- + of-service attacks or other attacks. For example, keys selected to + require excessive cryptographic processing, or extensive lists of CRL + Distribution Point (CDP) and/or Authority Information Access (AIA) + addresses in the certificate, could be used to mount denial-of- + service attacks. Similarly, attacker-specified CDP and/or AIA + addresses could be included in fake certificates to allow the + originator to detect receipt of the message even if signature + verification fails. + + RSA keys of less than 2048 bits are now considered by many experts to + be cryptographically insecure (due to advances in computing power) + and SHOULD no longer be used to sign certificates or CRLs. Such keys + were previously considered secure, so processing previously received + signed and encrypted mail may require processing certificates or CRLs + signed with weak keys. Implementations that wish to support previous + versions of S/MIME or process old messages need to consider the + security risks that result from accepting certificates and CRLs with + smaller key sizes (e.g., spoofed certificates) versus the costs of + + + +Schaad, et al. Standards Track [Page 19] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + denial of service. If an implementation supports verification of + certificates or CRLs generated with RSA and DSA keys of less than + 2048 bits, it MUST warn the user. Implementers should consider + providing a stronger warning for weak signatures on certificates and + CRLs associated with newly received messages than the one provided + for certificates and CRLs associated with previously stored messages. + Server implementations (e.g., secure mail list servers) where user + warnings are not appropriate SHOULD reject messages with weak + cryptography. + + If an implementation is concerned about compliance with National + Institute of Standards and Technology (NIST) key size + recommendations, then see [SP800-57]. + +7. References + +7.1. Reference Conventions + + [ESS] refers to [RFC2634] and [RFC5035]. + + [SMIMEv2] refers to [RFC2311], [RFC2312], [RFC2313], [RFC2314], and + [RFC2315]. + + [SMIMEv3] refers to [RFC2630], [RFC2631], [RFC2632], [RFC2633], + [RFC2634], and [RFC5035]. + + [SMIMEv3.1] refers to [RFC2634], [RFC3850], [RFC3851], [RFC3852], + and [RFC5035]. + + [SMIMEv3.2] refers to [RFC2634], [RFC5035], [RFC5652], [RFC5750], + and [RFC5751]. + + [SMIMEv4] refers to [RFC2634], [RFC5035], [RFC5652], [RFC8551], and + this document. + +7.2. Normative References + + [FIPS186-2] + National Institute of Standards and Technology (NIST), + "Digital Signature Standard (DSS) (also with Change + Notice 1)", Federal Information Processing Standards + Publication 186-2, January 2000, + . + + + + + + + +Schaad, et al. Standards Track [Page 20] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + [FIPS186-3] + National Institute of Standards and Technology (NIST), + "Digital Signature Standard (DSS)", Federal Information + Processing Standards Publication 186-3, June 2009, + . + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2634] Hoffman, P., Ed., "Enhanced Security Services for S/MIME", + RFC 2634, DOI 10.17487/RFC2634, June 1999, + . + + [RFC2985] Nystrom, M. and B. Kaliski, "PKCS #9: Selected Object + Classes and Attribute Types Version 2.0", RFC 2985, + DOI 10.17487/RFC2985, November 2000, + . + + [RFC3279] Bassham, L., Polk, W., and R. Housley, "Algorithms and + Identifiers for the Internet X.509 Public Key + Infrastructure Certificate and Certificate Revocation List + (CRL) Profile", RFC 3279, DOI 10.17487/RFC3279, April + 2002, . + + [RFC3447] Jonsson, J. and B. Kaliski, "Public-Key Cryptography + Standards (PKCS) #1: RSA Cryptography Specifications + Version 2.1", RFC 3447, DOI 10.17487/RFC3447, February + 2003, . + + [RFC4055] Schaad, J., Kaliski, B., and R. Housley, "Additional + Algorithms and Identifiers for RSA Cryptography for use in + the Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile", RFC 4055, + DOI 10.17487/RFC4055, June 2005, + . + + [RFC4056] Schaad, J., "Use of the RSASSA-PSS Signature Algorithm in + Cryptographic Message Syntax (CMS)", RFC 4056, + DOI 10.17487/RFC4056, June 2005, + . + + [RFC5035] Schaad, J., "Enhanced Security Services (ESS) Update: + Adding CertID Algorithm Agility", RFC 5035, + DOI 10.17487/RFC5035, August 2007, + . + + + +Schaad, et al. Standards Track [Page 21] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., + Housley, R., and W. Polk, "Internet X.509 Public Key + Infrastructure Certificate and Certificate Revocation List + (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008, + . + + [RFC5652] Housley, R., "Cryptographic Message Syntax (CMS)", STD 70, + RFC 5652, DOI 10.17487/RFC5652, September 2009, + . + + [RFC5750] Ramsdell, B. and S. Turner, "Secure/Multipurpose Internet + Mail Extensions (S/MIME) Version 3.2 Certificate + Handling", RFC 5750, DOI 10.17487/RFC5750, January 2010, + . + + [RFC5755] Farrell, S., Housley, R., and S. Turner, "An Internet + Attribute Certificate Profile for Authorization", + RFC 5755, DOI 10.17487/RFC5755, January 2010, + . + + [RFC5758] Dang, Q., Santesson, S., Moriarty, K., Brown, D., and T. + Polk, "Internet X.509 Public Key Infrastructure: + Additional Algorithms and Identifiers for DSA and ECDSA", + RFC 5758, DOI 10.17487/RFC5758, January 2010, + . + + [RFC6979] Pornin, T., "Deterministic Usage of the Digital Signature + Algorithm (DSA) and Elliptic Curve Digital Signature + Algorithm (ECDSA)", RFC 6979, DOI 10.17487/RFC6979, August + 2013, . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8398] Melnikov, A., Ed. and W. Chuang, Ed., "Internationalized + Email Addresses in X.509 Certificates", RFC 8398, + DOI 10.17487/RFC8398, May 2018, + . + + [RFC8551] Schaad, J., Ramsdell, B., and S. Turner, + "Secure/Multipurpose Internet Mail Extensions (S/MIME) + Version 4.0 Message Specification", RFC 8551, + DOI 10.17487/RFC8551, April 2019, + . + + + + + + +Schaad, et al. Standards Track [Page 22] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + [X.680] "Information Technology - Abstract Syntax Notation One + (ASN.1): Specification of basic notation", ITU-T + Recommendation X.680, ISO/IEC 8824-1:2015, August 2015, + . + +7.3 Informative References + + [PKCS6] RSA Laboratories, "PKCS #6: Extended-Certificate Syntax + Standard", November 1993. + + [RFC2311] Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L., and + L. Repka, "S/MIME Version 2 Message Specification", + RFC 2311, DOI 10.17487/RFC2311, March 1998, + . + + [RFC2312] Dusse, S., Hoffman, P., Ramsdell, B., and J. Weinstein, + "S/MIME Version 2 Certificate Handling", RFC 2312, + DOI 10.17487/RFC2312, March 1998, + . + + [RFC2313] Kaliski, B., "PKCS #1: RSA Encryption Version 1.5", + RFC 2313, DOI 10.17487/RFC2313, March 1998, + . + + [RFC2314] Kaliski, B., "PKCS #10: Certification Request Syntax + Version 1.5", RFC 2314, DOI 10.17487/RFC2314, March 1998, + . + + [RFC2315] Kaliski, B., "PKCS #7: Cryptographic Message Syntax + Version 1.5", RFC 2315, DOI 10.17487/RFC2315, March 1998, + . + + [RFC2630] Housley, R., "Cryptographic Message Syntax", RFC 2630, + DOI 10.17487/RFC2630, June 1999, + . + + [RFC2631] Rescorla, E., "Diffie-Hellman Key Agreement Method", + RFC 2631, DOI 10.17487/RFC2631, June 1999, + . + + [RFC2632] Ramsdell, B., Ed., "S/MIME Version 3 Certificate + Handling", RFC 2632, DOI 10.17487/RFC2632, June 1999, + . + + [RFC2633] Ramsdell, B., Ed., "S/MIME Version 3 Message + Specification", RFC 2633, DOI 10.17487/RFC2633, June 1999, + . + + + + +Schaad, et al. Standards Track [Page 23] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + [RFC3114] Nicolls, W., "Implementing Company Classification Policy + with the S/MIME Security Label", RFC 3114, + DOI 10.17487/RFC3114, May 2002, + . + + [RFC3850] Ramsdell, B., Ed., "Secure/Multipurpose Internet Mail + Extensions (S/MIME) Version 3.1 Certificate Handling", + RFC 3850, DOI 10.17487/RFC3850, July 2004, + . + + [RFC3851] Ramsdell, B., Ed., "Secure/Multipurpose Internet Mail + Extensions (S/MIME) Version 3.1 Message Specification", + RFC 3851, DOI 10.17487/RFC3851, July 2004, + . + + [RFC3852] Housley, R., "Cryptographic Message Syntax (CMS)", + RFC 3852, DOI 10.17487/RFC3852, July 2004, + . + + [RFC5751] Ramsdell, B. and S. Turner, "Secure/Multipurpose Internet + Mail Extensions (S/MIME) Version 3.2 Message + Specification", RFC 5751, DOI 10.17487/RFC5751, + January 2010, . + + [RFC6090] McGrew, D., Igoe, K., and M. Salter, "Fundamental Elliptic + Curve Cryptography Algorithms", RFC 6090, + DOI 10.17487/RFC6090, February 2011, + . + + [RFC6151] Turner, S. and L. Chen, "Updated Security Considerations + for the MD5 Message-Digest and the HMAC-MD5 Algorithms", + RFC 6151, DOI 10.17487/RFC6151, March 2011, + . + + [RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security + Considerations for the SHA-0 and SHA-1 Message-Digest + Algorithms", RFC 6194, DOI 10.17487/RFC6194, March 2011, + . + + [RFC8032] Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital + Signature Algorithm (EdDSA)", RFC 8032, + DOI 10.17487/RFC8032, January 2017, + . + + [RFC8162] Hoffman, P. and J. Schlyter, "Using Secure DNS to + Associate Certificates with Domain Names for S/MIME", + RFC 8162, DOI 10.17487/RFC8162, May 2017, + . + + + +Schaad, et al. Standards Track [Page 24] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + [RFC8410] Josefsson, S. and J. Schaad, "Algorithm Identifiers for + Ed25519, Ed448, X25519, and X448 for Use in the Internet + X.509 Public Key Infrastructure", RFC 8410, + DOI 10.17487/RFC8410, August 2018, + . + + [SP800-57] National Institute of Standards and Technology (NIST), + "Recommendation for Key Management - Part 1: General", + NIST Special Publication 800-57 Revision 4, + DOI 10.6028/NIST.SP.800-57pt1r4, January 2016, + . + + [X.500] "Information technology - Open Systems Interconnection - + The Directory - Part 1: Overview of concepts, models and + services", ITU-T Recommendation X.500, + ISO/IEC 9594-1:2017. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 25] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +Appendix A. Historic Considerations + +A.1. Signature Algorithms and Key Sizes + + There are a number of problems with validating certificates on + sufficiently historic messages. For this reason, it is strongly + suggested that user agents treat these certificates differently from + those on current messages. These problems include the following: + + - CAs are not required to keep certificates on a CRL beyond one + update after a certificate has expired. This means that unless + CRLs are cached as part of the message it is not always possible + to check to see if a certificate has been revoked. The same + problems exist with Online Certificate Status Protocol (OCSP) + responses, as they may be based on a CRL rather than on the + certificate database. + + - RSA and DSA keys of less than 2048 bits are now considered by many + experts to be cryptographically insecure (due to advances in + computing power). Such keys were previously considered secure, so + the processing of historic certificates will often result in the + use of weak keys. Implementations that wish to support previous + versions of S/MIME or process old messages need to consider the + security risks that result from smaller key sizes (e.g., spoofed + messages) versus the costs of denial of service. + + [SMIMEv3.2] set the lower limit on suggested key sizes for + creating and validation at 1024 bits. [SMIMEv3.1] set the lower + limit at 768 bits. Prior to that, the lower bound on key sizes + was 512 bits. + + - Hash functions used to validate signatures on historic messages + may no longer be considered to be secure (see below). While there + are not currently any known practical pre-image or second + pre-image attacks against MD5 or SHA-1, the fact that they are no + longer considered to be collision resistant implies that the + security level of any signature that is created with these hash + algorithms should also be considered as suspect. + + The following algorithms have been called out for some level of + support by previous S/MIME specifications: + + - RSA with MD5 was dropped in [SMIMEv4]. MD5 is no longer + considered to be secure, as it is no longer collision resistant. + Details can be found in [RFC6151]. + + + + + + +Schaad, et al. Standards Track [Page 26] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + + - RSA and DSA with SHA-1 were dropped in [SMIMEv4]. SHA-1 is no + longer considered to be secure, as it is no longer collision + resistant. The IETF statement on SHA-1 can be found in [RFC6194], + but it is out of date relative to the most recent advances. + + - DSA with SHA-256 support was dropped in [SMIMEv4]. DSA was + dropped as part of a general movement from finite fields to + elliptic curves. Issues related to dealing with non-deterministic + generation of the parameter 'k' have come up (see [RFC6979]). + + For 512-bit RSA with SHA-1, see [RFC3279] and [FIPS186-2] without + Change Notice 1; for 512-bit RSA with SHA-256, see [RFC4055] and + [FIPS186-2] without Change Notice 1. The first reference provides + the signature algorithm's OID, and the second provides the signature + algorithm's definition. + + For 512-bit DSA with SHA-1, see [RFC3279] and [FIPS186-2] without + Change Notice 1; for 512-bit DSA with SHA-256, see [RFC5758] and + [FIPS186-2] without Change Notice 1; for 1024-bit DSA with SHA-1, see + [RFC3279] and [FIPS186-2] with Change Notice 1; and for 1024-bit + through 3072-bit DSA with SHA-256, see [RFC5758] and [FIPS186-3]. + The first reference provides the signature algorithm's OID, and the + second provides the signature algorithm's definition. + +Appendix B. Moving S/MIME v2 Certificate Handling to Historic Status + + The S/MIME v3 [SMIMEv3], v3.1 [SMIMEv3.1], v3.2 [SMIMEv3.2], and v4.0 + (this document) specifications are backward compatible with the + S/MIME v2 Certificate Handling Specification [SMIMEv2], with the + exception of the algorithms (dropped RC2/40 requirement, and added + DSA and RSASSA-PSS requirements). Therefore, RFC 2312 [SMIMEv2] was + moved to Historic status. + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 27] + +RFC 8550 S/MIME 4.0 Certificate Handling April 2019 + + +Acknowledgements + + Many thanks go out to the other authors of the S/MIME v2 Certificate + Handling RFC: Steve Dusse, Paul Hoffman, and Jeff Weinstein. Without + v2, there wouldn't be a v3, v3.1, v3.2, or v4.0. + + A number of the members of the S/MIME Working Group have also worked + very hard and contributed to this document. Any list of people is + doomed to omission, and for that I apologize. In alphabetical order, + the following people stand out in my mind because they made direct + contributions to this document. + + Bill Flanigan, Trevor Freeman, Elliott Ginsburg, Alfred Hoenes, Paul + Hoffman, Russ Housley, David P. Kemp, Michael Myers, John Pawling, + and Denis Pinkas. + + The version 4 update to the S/MIME documents was done under the + auspices of the LAMPS Working Group. + +Authors' Addresses + + Jim Schaad + August Cellars + + Email: ietf@augustcellars.com + + + Blake Ramsdell + Brute Squad Labs, Inc. + + Email: blaker@gmail.com + + + Sean Turner + sn3rd + + Email: sean@sn3rd.com + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 28] + diff --git a/rfc/rfc8551.txt b/rfc/rfc8551.txt new file mode 100644 index 0000000000..b07ea0897c --- /dev/null +++ b/rfc/rfc8551.txt @@ -0,0 +1,3531 @@ + + + + + + +Internet Engineering Task Force (IETF) J. Schaad +Request for Comments: 8551 August Cellars +Obsoletes: 5751 B. Ramsdell +Category: Standards Track Brute Squad Labs, Inc. +ISSN: 2070-1721 S. Turner + sn3rd + April 2019 + + + Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 + Message Specification + +Abstract + + This document defines Secure/Multipurpose Internet Mail Extensions + (S/MIME) version 4.0. S/MIME provides a consistent way to send and + receive secure MIME data. Digital signatures provide authentication, + message integrity, and non-repudiation with proof of origin. + Encryption provides data confidentiality. Compression can be used to + reduce data size. This document obsoletes RFC 5751. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc8551. + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 1] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +Copyright Notice + + Copyright (c) 2019 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + This document may contain material from IETF Documents or IETF + Contributions published or made publicly available before November + 10, 2008. The person(s) controlling the copyright in some of this + material may not have granted the IETF Trust the right to allow + modifications of such material outside the IETF Standards Process. + Without obtaining an adequate license from the person(s) controlling + the copyright in such materials, this document may not be modified + outside the IETF Standards Process, and derivative works of it may + not be created outside the IETF Standards Process, except to format + it for publication as an RFC or to translate it into languages other + than English. + + + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 2] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.1. Specification Overview . . . . . . . . . . . . . . . . . 5 + 1.2. Definitions . . . . . . . . . . . . . . . . . . . . . . . 6 + 1.3. Conventions Used in This Document . . . . . . . . . . . . 7 + 1.4. Compatibility with Prior Practice of S/MIME . . . . . . . 8 + 1.5. Changes from S/MIME v3 to S/MIME v3.1 . . . . . . . . . . 9 + 1.6. Changes from S/MIME v3.1 to S/MIME v3.2 . . . . . . . . . 9 + 1.7. Changes for S/MIME v4.0 . . . . . . . . . . . . . . . . . 11 + 2. CMS Options . . . . . . . . . . . . . . . . . . . . . . . . . 12 + 2.1. DigestAlgorithmIdentifier . . . . . . . . . . . . . . . . 12 + 2.2. SignatureAlgorithmIdentifier . . . . . . . . . . . . . . 12 + 2.3. KeyEncryptionAlgorithmIdentifier . . . . . . . . . . . . 13 + 2.4. General Syntax . . . . . . . . . . . . . . . . . . . . . 13 + 2.4.1. Data Content Type . . . . . . . . . . . . . . . . . . 14 + 2.4.2. SignedData Content Type . . . . . . . . . . . . . . . 14 + 2.4.3. EnvelopedData Content Type . . . . . . . . . . . . . 14 + 2.4.4. AuthEnvelopedData Content Type . . . . . . . . . . . 14 + 2.4.5. CompressedData Content Type . . . . . . . . . . . . . 14 + 2.5. Attributes and the SignerInfo Type . . . . . . . . . . . 15 + 2.5.1. Signing Time Attribute . . . . . . . . . . . . . . . 15 + 2.5.2. SMIMECapabilities Attribute . . . . . . . . . . . . . 16 + 2.5.3. Encryption Key Preference Attribute . . . . . . . . . 17 + 2.6. SignerIdentifier SignerInfo Type . . . . . . . . . . . . 19 + 2.7. ContentEncryptionAlgorithmIdentifier . . . . . . . . . . 19 + 2.7.1. Deciding Which Encryption Method to Use . . . . . . . 19 + 2.7.2. Choosing Weak Encryption . . . . . . . . . . . . . . 21 + 2.7.3. Multiple Recipients . . . . . . . . . . . . . . . . . 21 + 3. Creating S/MIME Messages . . . . . . . . . . . . . . . . . . 21 + 3.1. Preparing the MIME Entity for Signing, Enveloping, or + Compressing . . . . . . . . . . . . . . . . . . . . . . . 22 + 3.1.1. Canonicalization . . . . . . . . . . . . . . . . . . 23 + 3.1.2. Transfer Encoding . . . . . . . . . . . . . . . . . . 24 + 3.1.3. Transfer Encoding for Signing Using multipart/signed 25 + 3.1.4. Sample Canonical MIME Entity . . . . . . . . . . . . 25 + 3.2. The application/pkcs7-mime Media Type . . . . . . . . . . 26 + 3.2.1. The name and filename Parameters . . . . . . . . . . 27 + 3.2.2. The smime-type Parameter . . . . . . . . . . . . . . 28 + 3.3. Creating an Enveloped-Only Message . . . . . . . . . . . 29 + 3.4. Creating an Authenticated Enveloped-Only Message . . . . 30 + 3.5. Creating a Signed-Only Message . . . . . . . . . . . . . 31 + 3.5.1. Choosing a Format for Signed-Only Messages . . . . . 32 + 3.5.2. Signing Using application/pkcs7-mime with SignedData 32 + 3.5.3. Signing Using the multipart/signed Format . . . . . . 33 + 3.6. Creating a Compressed-Only Message . . . . . . . . . . . 36 + 3.7. Multiple Operations . . . . . . . . . . . . . . . . . . . 37 + 3.8. Creating a Certificate Management Message . . . . . . . . 38 + + + +Schaad, et al. Standards Track [Page 3] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + 3.9. Registration Requests . . . . . . . . . . . . . . . . . . 38 + 3.10. Identifying an S/MIME Message . . . . . . . . . . . . . . 39 + 4. Certificate Processing . . . . . . . . . . . . . . . . . . . 39 + 4.1. Key Pair Generation . . . . . . . . . . . . . . . . . . . 40 + 4.2. Signature Generation . . . . . . . . . . . . . . . . . . 40 + 4.3. Signature Verification . . . . . . . . . . . . . . . . . 40 + 4.4. Encryption . . . . . . . . . . . . . . . . . . . . . . . 41 + 4.5. Decryption . . . . . . . . . . . . . . . . . . . . . . . 41 + 5. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 41 + 5.1. Media Type for application/pkcs7-mime . . . . . . . . . . 42 + 5.2. Media Type for application/pkcs7-signature . . . . . . . 43 + 5.3. authEnveloped-data smime-type . . . . . . . . . . . . . . 44 + 5.4. Reference Updates . . . . . . . . . . . . . . . . . . . . 44 + 6. Security Considerations . . . . . . . . . . . . . . . . . . . 44 + 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 48 + 7.1. Reference Conventions . . . . . . . . . . . . . . . . . . 48 + 7.2. Normative References . . . . . . . . . . . . . . . . . . 49 + 7.3. Informative References . . . . . . . . . . . . . . . . . 52 + Appendix A. ASN.1 Module . . . . . . . . . . . . . . . . . . . . 57 + Appendix B. Historic Mail Considerations . . . . . . . . . . . . 59 + B.1. DigestAlgorithmIdentifier . . . . . . . . . . . . . . . . 59 + B.2. Signature Algorithms . . . . . . . . . . . . . . . . . . 59 + B.3. ContentEncryptionAlgorithmIdentifier . . . . . . . . . . 61 + B.4. KeyEncryptionAlgorithmIdentifier . . . . . . . . . . . . 62 + Appendix C. Moving S/MIME v2 Message Specification to Historic + Status . . . . . . . . . . . . . . . . . . . . . . . 62 + Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 62 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 63 + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 4] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +1. Introduction + + S/MIME (Secure/Multipurpose Internet Mail Extensions) provides a + consistent way to send and receive secure MIME data. Based on the + popular Internet MIME standard, S/MIME provides the following + cryptographic security services for electronic messaging + applications: authentication, message integrity, and non-repudiation + of origin (using digital signatures), and data confidentiality (using + encryption). As a supplementary service, S/MIME provides message + compression. + + S/MIME can be used by traditional mail user agents (MUAs) to add + cryptographic security services to mail that is sent, and to + interpret cryptographic security services in mail that is received. + However, S/MIME is not restricted to mail; it can be used with any + transport mechanism that transports MIME data, such as HTTP or SIP. + As such, S/MIME takes advantage of the object-based features of MIME + and allows secure messages to be exchanged in mixed-transport + systems. + + Further, S/MIME can be used in automated message transfer agents that + use cryptographic security services that do not require any human + intervention, such as the signing of software-generated documents and + the encryption of FAX messages sent over the Internet. + + This document defines version 4.0 of the S/MIME Message + Specification. As such, this document obsoletes version 3.2 of the + S/MIME Message Specification [RFC5751]. + + This specification contains a number of references to documents that + have been obsoleted or replaced. This is intentional, as the updated + documents often do not have the same information or protocol + requirements in them. + +1.1. Specification Overview + + This document describes a protocol for adding cryptographic signature + and encryption services to MIME data. The MIME standard [MIME-SPEC] + provides a general structure for the content of Internet messages and + allows extensions for new applications based on content-type. + + This specification defines how to create a MIME body part that has + been cryptographically enhanced according to the Cryptographic + Message Syntax (CMS) [CMS], which is derived from PKCS #7 [RFC2315]. + This specification also defines the application/pkcs7-mime media + type, which can be used to transport those body parts. + + + + + +Schaad, et al. Standards Track [Page 5] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + This document also discusses how to use the multipart/signed media + type defined in [RFC1847] to transport S/MIME signed messages. + multipart/signed is used in conjunction with the + application/pkcs7-signature media type, which is used to transport a + detached S/MIME signature. + + In order to create S/MIME messages, an S/MIME agent MUST follow the + specifications in this document, as well as the specifications listed + in [CMS], [RFC3370], [RFC4056], [RFC3560], and [RFC5754]. + + Throughout this specification, there are requirements and + recommendations made for how receiving agents handle incoming + messages. There are separate requirements and recommendations for + how sending agents create outgoing messages. In general, the best + strategy is to follow the Robustness Principle (be liberal in what + you receive and conservative in what you send). Most of the + requirements are placed on the handling of incoming messages, while + the recommendations are mostly on the creation of outgoing messages. + + The separation for requirements on receiving agents and sending + agents also derives from the likelihood that there will be S/MIME + systems that involve software other than traditional Internet mail + clients. S/MIME can be used with any system that transports MIME + data. An automated process that sends an encrypted message might not + be able to receive an encrypted message at all, for example. Thus, + the requirements and recommendations for the two types of agents are + listed separately when appropriate. + +1.2. Definitions + + For the purposes of this specification, the following definitions + apply. + + ASN.1: + Abstract Syntax Notation One, as defined in ITU-T Recommendations + X.680, X.681, X.682, and X.683 [ASN.1]. + + BER: + Basic Encoding Rules for ASN.1, as defined in ITU-T Recommendation + X.690 [X.690]. + + Certificate: + A type that binds an entity's name to a public key with a digital + signature. + + DER: + Distinguished Encoding Rules for ASN.1, as defined in ITU-T + Recommendation X.690 [X.690]. + + + +Schaad, et al. Standards Track [Page 6] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + 7-bit data: + Text data with lines less than 998 characters long, where none of + the characters have the 8th bit set, and there are no NULL + characters. and occur only as part of a + end-of-line delimiter. + + 8-bit data: + Text data with lines less than 998 characters, and where none of + the characters are NULL characters. and occur only as + part of a end-of-line delimiter. + + Binary data: + Arbitrary data. + + Transfer encoding: + A reversible transformation made on data so 8-bit or binary data + can be sent via a channel that only transmits 7-bit data. + + Receiving agent: + Software that interprets and processes S/MIME CMS objects, MIME + body parts that contain CMS content types, or both. + + Sending agent: + Software that creates S/MIME CMS content types, MIME body parts + that contain CMS content types, or both. + + S/MIME agent: + User software that is a receiving agent, a sending agent, or both. + + Data integrity service: + A security service that protects against unauthorized changes to + data by ensuring that changes to the data are detectable + [RFC4949]. + + Data confidentiality: + The property that data is not disclosed to system entities unless + they have been authorized to know the data [RFC4949]. + +1.3. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + + + + + +Schaad, et al. Standards Track [Page 7] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + We define the additional requirement levels: + + SHOULD+ This term means the same as SHOULD. However, the authors + expect that a requirement marked as SHOULD+ will be + promoted at some future time to be a MUST. + + SHOULD- This term means the same as SHOULD. However, the authors + expect that a requirement marked as SHOULD- will be demoted + to a MAY in a future version of this document. + + MUST- This term means the same as MUST. However, the authors + expect that this requirement will no longer be a MUST in a + future document. Although its status will be determined at + a later time, it is reasonable to expect that if a future + revision of a document alters the status of a MUST- + requirement, it will remain at least a SHOULD or a SHOULD-. + + The term "RSA" in this document almost always refers to the + PKCS #1 v1.5 RSA [RFC2313] signature or encryption algorithms even + when not qualified as such. There are a couple of places where it + refers to the general RSA cryptographic operation; these can be + determined from the context where it is used. + +1.4. Compatibility with Prior Practice of S/MIME + + S/MIME version 4.0 agents ought to attempt to have the greatest + interoperability possible with agents for prior versions of S/MIME. + + - S/MIME version 2 is described in RFC 2311 through RFC 2315 + inclusive [SMIMEv2]. + + - S/MIME version 3 is described in RFC 2630 through RFC 2634 + inclusive and RFC 5035 [SMIMEv3]. + + - S/MIME version 3.1 is described in RFC 2634, RFC 3850, RFC 3851, + RFC 3852, and RFC 5035 [SMIMEv3.1]. + + - S/MIME version 3.2 is described in RFC 2634, RFC 5035, RFC 5652, + RFC 5750, and RFC 5751 [SMIMEv3.2]. + + - [RFC2311] also has historical information about the development of + S/MIME. + + + + + + + + + +Schaad, et al. Standards Track [Page 8] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +1.5. Changes from S/MIME v3 to S/MIME v3.1 + + This section describes the changes made between S/MIME v3 and + S/MIME v3.1. Note that the requirement levels indicated by the + capitalized key words ("MUST", "SHOULD", etc.) may have changed in + later versions of S/MIME. + + - The RSA public key algorithm was changed to a MUST implement. The + key wrap algorithm and the Diffie-Hellman (DH) algorithm [RFC2631] + were changed to a SHOULD implement. + + - The AES symmetric encryption algorithm has been included as a + SHOULD implement. + + - The RSA public key algorithm was changed to a MUST implement + signature algorithm. + + - Ambiguous language about the use of "empty" SignedData messages to + transmit certificates was clarified to reflect that transmission + of Certificate Revocation Lists is also allowed. + + - The use of binary encoding for some MIME entities is now + explicitly discussed. + + - Header protection through the use of the message/rfc822 media type + has been added. + + - Use of the CompressedData CMS type is allowed, along with required + media type and file extension additions. + +1.6. Changes from S/MIME v3.1 to S/MIME v3.2 + + This section describes the changes made between S/MIME v3.1 and + S/MIME v3.2. Note that the requirement levels indicated by the + capitalized key words ("MUST", "SHOULD", etc.) may have changed in + later versions of S/MIME. Note that the section numbers listed here + (e.g., 3.4.3.2) are from [RFC5751]. + + - Made editorial changes, e.g., replaced "MIME type" with "media + type", "content-type" with "Content-Type". + + - Moved "Conventions Used in This Document" to Section 1.3. Added + definitions for SHOULD+, SHOULD-, and MUST-. + + - Section 1.1 and Appendix A: Added references to RFCs for + RSASSA-PSS, RSAES-OAEP, and SHA2 CMS algorithms. Added CMS + Multiple Signers Clarification to CMS reference. + + + + +Schaad, et al. Standards Track [Page 9] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - Section 1.2: Updated references to ASN.1 to X.680, and BER and DER + to X.690. + + - Section 1.4: Added references to S/MIME v3.1 RFCs. + + - Section 2.1 (digest algorithm): SHA-256 added as MUST, SHA-1 and + MD5 made SHOULD-. + + - Section 2.2 (signature algorithms): RSA with SHA-256 added as + MUST; DSA with SHA-256 added as SHOULD+; RSA with SHA-1, DSA with + SHA-1, and RSA with MD5 changed to SHOULD-; and RSASSA-PSS with + SHA-256 added as SHOULD+. Also added note about what S/MIME v3.1 + clients support. + + - Section 2.3 (key encryption): DH changed to SHOULD-, and RSAES- + OAEP added as SHOULD+. Elaborated on requirements for key wrap + algorithm. + + - Section 2.5.1: Added requirement that receiving agents MUST + support both GeneralizedTime and UTCTime. + + - Section 2.5.2: Replaced reference "sha1WithRSAEncryption" with + "sha256WithRSAEncryption", replaced "DES-3EDE-CBC" with "AES-128 + CBC", and deleted the RC5 example. + + - Section 2.5.2.1: Deleted entire section (discussed + deprecated RC2). + + - Section 2.7, Section 2.7.1, and Appendix A: References to RC2/40 + removed. + + - Section 2.7 (content encryption): AES-128 CBC added as MUST, + AES-192 and AES-256 CBC SHOULD+, and tripleDES now SHOULD-. + + - Section 2.7.1: Updated pointers from 2.7.2.1 through 2.7.2.4 to + 2.7.1.1 and 2.7.1.2. + + - Section 3.1.1: Removed text about MIME character sets. + + - Sections 3.2.2 and 3.6: Replaced "encrypted" with "enveloped". + Updated OID example to use AES-128 CBC OID. + + - Section 3.4.3.2: Replaced "micalg" parameter for "SHA-1" with + "sha-1". + + - Section 4: Updated reference to CERT v3.2. + + + + + +Schaad, et al. Standards Track [Page 10] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - Section 4.1: Updated RSA and DSA key size discussion. Moved last + four sentences to security considerations. Updated reference to + randomness requirements for security. + + - Section 5: Added IANA registration templates to update media type + registry to point to this document as opposed to RFC 2311. + + - Section 6: Updated security considerations. + + - Section 7: Moved references from Appendix B to this section. + Updated references. Added informative references to SMIMEv2, + SMIMEv3, and SMIMEv3.1. + + - Appendix B: Added Appendix B to move S/MIME v2 to Historic status. + +1.7. Changes for S/MIME v4.0 + + This section describes the changes made between S/MIME v3.2 and + S/MIME v4.0. + + - Added the use of AuthEnvelopedData, including defining and + registering an smime-type value (Sections 2.4.4 and 3.4). + + - Updated the content-encryption algorithms (Sections 2.7 and + 2.7.1.2): added AES-256 Galois/Counter Mode (GCM), added + ChaCha20-Poly1305, removed mention of AES-192 Cipher Block + Chaining (CBC), and marked tripleDES as historic. + + - Updated the set of signature algorithms (Section 2.2): added the + Edwards-curve Digital Signature Algorithm (EdDSA), added the + Elliptic Curve Digital Signature Algorithm (ECDSA), and marked DSA + as historic. + + - Updated the set of digest algorithms (Section 2.1): added SHA-512, + and marked SHA-1 as historic. + + - Updated the size of keys to be used for RSA encryption and RSA + signing (Section 4). + + - Created Appendix B, which discusses considerations for dealing + with historic email messages. + + + + + + + + + + +Schaad, et al. Standards Track [Page 11] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +2. CMS Options + + CMS allows for a wide variety of options in content, attributes, and + algorithm support. This section puts forth a number of support + requirements and recommendations in order to achieve a base level of + interoperability among all S/MIME implementations. [RFC3370] and + [RFC5754] provide additional details regarding the use of the + cryptographic algorithms. [ESS] provides additional details + regarding the use of additional attributes. + +2.1. DigestAlgorithmIdentifier + + The algorithms here are used for digesting the body of the message + and are not the same as the digest algorithms used as part of the + signature algorithms. The result of this is placed in the + message-digest attribute of the signed attributes. It is RECOMMENDED + that the algorithm used for digesting the body of the message be of + similar strength to, or greater strength than, the signature + algorithm. + + Sending and receiving agents: + + - MUST support SHA-256. + + - MUST support SHA-512. + + [RFC5754] provides the details for using these algorithms with + S/MIME. + +2.2. SignatureAlgorithmIdentifier + + There are different sets of requirements placed on receiving and + sending agents. By having the different requirements, the maximum + amount of interoperability is achieved, as it allows for specialized + protection of private key material but maximum signature validation. + + Receiving agents: + + - MUST support ECDSA with curve P-256 and SHA-256. + + - MUST support EdDSA with curve25519 using PureEdDSA mode [RFC8419]. + + - MUST- support RSA PKCS #1 v1.5 with SHA-256. + + - SHOULD support the RSA Probabilistic Signature Scheme (RSASSA-PSS) + with SHA-256. + + + + + +Schaad, et al. Standards Track [Page 12] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + Sending agents: + + - MUST support at least one of the following algorithms: ECDSA with + curve P-256 and SHA-256, or EdDSA with curve25519 using PureEdDSA + mode. + + - MUST- support RSA PKCS #1 v1.5 with SHA-256. + + - SHOULD support RSASSA-PSS with SHA-256. + + See Section 4.1 for information on key size and algorithm references. + +2.3. KeyEncryptionAlgorithmIdentifier + + Receiving and sending agents: + + - MUST support Elliptic Curve Diffie-Hellman (ECDH) ephemeral-static + mode for P-256, as specified in [RFC5753]. + + - MUST support ECDH ephemeral-static mode for X25519 using HKDF-256 + ("HKDF" stands for "HMAC-based Key Derivation Function") for the + KDF, as specified in [RFC8418]. + + - MUST- support RSA encryption, as specified in [RFC3370]. + + - SHOULD+ support RSA Encryption Scheme - Optimal Asymmetric + Encryption Padding (RSAES-OAEP), as specified in [RFC3560]. + + When ECDH ephemeral-static is used, a key wrap algorithm is also + specified in the KeyEncryptionAlgorithmIdentifier [RFC5652]. The + underlying encryption functions for the key wrap and content- + encryption algorithms [RFC3370] [RFC3565] and the key sizes for the + two algorithms MUST be the same (e.g., AES-128 key wrap algorithm + with AES-128 content-encryption algorithm). As both 128-bit and + 256-bit AES modes are mandatory to implement as content-encryption + algorithms (Section 2.7), both the AES-128 and AES-256 key wrap + algorithms MUST be supported when ECDH ephemeral-static is used. + Recipients MAY enforce this but MUST use the weaker of the two as + part of any cryptographic strength computations they might do. + + Appendix B provides information on algorithm support in older + versions of S/MIME. + +2.4. General Syntax + + There are several CMS content types. Of these, only the Data, + SignedData, EnvelopedData, AuthEnvelopedData, and CompressedData + content types are currently used for S/MIME. + + + +Schaad, et al. Standards Track [Page 13] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +2.4.1. Data Content Type + + Sending agents MUST use the id-data content type identifier to + identify the "inner" MIME message content. For example, when + applying a digital signature to MIME data, the CMS SignedData + encapContentInfo eContentType MUST include the id-data object + identifier (OID), and the media type MUST be stored in the SignedData + encapContentInfo eContent OCTET STRING (unless the sending agent is + using multipart/signed, in which case the eContent is absent, per + Section 3.5.3 of this document). As another example, when applying + encryption to MIME data, the CMS EnvelopedData encryptedContentInfo + contentType MUST include the id-data OID and the encrypted MIME + content MUST be stored in the EnvelopedData encryptedContentInfo + encryptedContent OCTET STRING. + +2.4.2. SignedData Content Type + + Sending agents MUST use the SignedData content type to apply a + digital signature to a message or, in a degenerate case where there + is no signature information, to convey certificates. Applying a + signature to a message provides authentication, message integrity, + and non-repudiation of origin. + +2.4.3. EnvelopedData Content Type + + This content type is used to apply data confidentiality to a message. + In order to distribute the symmetric key, a sender needs to have + access to a public key for each intended message recipient to use + this service. + +2.4.4. AuthEnvelopedData Content Type + + This content type is used to apply data confidentiality and message + integrity to a message. This content type does not provide + authentication or non-repudiation. In order to distribute the + symmetric key, a sender needs to have access to a public key for each + intended message recipient to use this service. + +2.4.5. CompressedData Content Type + + This content type is used to apply data compression to a message. + This content type does not provide authentication, message integrity, + non-repudiation, or data confidentiality; it is only used to reduce + the message's size. + + See Section 3.7 for further guidance on the use of this type in + conjunction with other CMS types. + + + + +Schaad, et al. Standards Track [Page 14] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +2.5. Attributes and the SignerInfo Type + + The SignerInfo type allows the inclusion of unsigned and signed + attributes along with a signature. These attributes can be required + for the processing of messages (e.g., message digest), information + the signer supplied (e.g., SMIME capabilities) that should be + processed, or attributes that are not relevant to the current + situation (e.g., mlExpansionHistory [RFC2634] for mail viewers). + + Receiving agents MUST be able to handle zero or one instance of each + of the signed attributes listed here. Sending agents SHOULD generate + one instance of each of the following signed attributes in each + S/MIME message: + + - Signing time (Section 2.5.1 in this document) + + - SMIME capabilities (Section 2.5.2 in this document) + + - Encryption key Preference (Section 2.5.3 in this document) + + - Message digest (Section 11.2 in [RFC5652]) + + - Content type (Section 11.1 in [RFC5652]) + + Further, receiving agents SHOULD be able to handle zero or one + instance of the signingCertificate and signingCertificateV2 signed + attributes, as defined in Section 5 of RFC 2634 [ESS] and Section 3 + of RFC 5035 [ESS], respectively. + + Sending agents SHOULD generate one instance of the signingCertificate + or signingCertificateV2 signed attribute in each SignerInfo + structure. + + Additional attributes and values for these attributes might be + defined in the future. Receiving agents SHOULD handle attributes or + values that they do not recognize in a graceful manner. + + Interactive sending agents that include signed attributes that are + not listed here SHOULD display those attributes to the user, so that + the user is aware of all of the data being signed. + +2.5.1. Signing Time Attribute + + The signingTime attribute is used to convey the time that a message + was signed. The time of signing will most likely be created by a + signer and therefore is only as trustworthy as that signer. + + + + + +Schaad, et al. Standards Track [Page 15] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + Sending agents MUST encode signing time through the year 2049 as + UTCTime; signing times in 2050 or later MUST be encoded as + GeneralizedTime. When the UTCTime CHOICE is used, S/MIME agents MUST + interpret the year field (YY) as follows: + + If YY is greater than or equal to 50, the year is interpreted as + 19YY; if YY is less than 50, the year is interpreted as 20YY. + + Receiving agents MUST be able to process signingTime attributes that + are encoded in either UTCTime or GeneralizedTime. + +2.5.2. SMIMECapabilities Attribute + + The SMIMECapabilities attribute includes signature algorithms (such + as "sha256WithRSAEncryption"), symmetric algorithms (such as "AES-128 + CBC"), authenticated symmetric algorithms (such as "AES-128 GCM"), + and key encipherment algorithms (such as "rsaEncryption"). The + presence of an SMIMECapability attribute containing an algorithm + implies that the sender can deal with the algorithm as well as + understand the ASN.1 structures associated with that algorithm. + There are also several identifiers that indicate support for other + optional features such as binary encoding and compression. The + SMIMECapabilities attribute was designed to be flexible and + extensible so that, in the future, a means of identifying other + capabilities and preferences such as certificates can be added in a + way that will not cause current clients to break. + + If present, the SMIMECapabilities attribute MUST be a + SignedAttribute. CMS defines SignedAttributes as a SET OF Attribute. + The SignedAttributes in a signerInfo MUST include a single instance + of the SMIMECapabilities attribute. CMS defines the ASN.1 syntax for + Attribute to include attrValues SET OF AttributeValue. An + SMIMECapabilities attribute MUST only include a single instance of + AttributeValue. If a signature is detected as violating these + requirements, the signature SHOULD be treated as failing. + + The semantics of the SMIMECapabilities attribute specify a partial + list as to what the client announcing the SMIMECapabilities can + support. A client does not have to list every capability it + supports, and it need not list all its capabilities so that the + capabilities list doesn't get too long. In an SMIMECapabilities + attribute, the OIDs are listed in order of their preference but + SHOULD be separated logically along the lines of their categories + (signature algorithms, symmetric algorithms, key encipherment + algorithms, etc.). + + + + + + +Schaad, et al. Standards Track [Page 16] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + The structure of the SMIMECapabilities attribute is to facilitate + simple table lookups and binary comparisons in order to determine + matches. For instance, the encoding for the SMIMECapability for + sha256WithRSAEncryption includes rather than omits the NULL + parameter. Because of the requirement for identical encoding, + individuals documenting algorithms to be used in the + SMIMECapabilities attribute SHOULD explicitly document the correct + byte sequence for the common cases. + + For any capability, the associated parameters for the OID MUST + specify all of the parameters necessary to differentiate between two + instances of the same algorithm. + + The same OID that is used to identify an algorithm SHOULD also be + used in the SMIMECapability for that algorithm. There are cases + where a single OID can correspond to multiple algorithms. In these + cases, a single algorithm MUST be assigned to the SMIMECapability + using that OID. Additional OIDs from the smimeCapabilities OID tree + are then allocated for the other algorithms usages. For instance, in + an earlier specification, rsaEncryption was ambiguous because it + could refer to either a signature algorithm or a key encipherment + algorithm. In the event that an OID is ambiguous, it needs to be + arbitrated by the maintainer of the registered SMIMECapabilities list + as to which type of algorithm will use the OID, and a new OID MUST be + allocated under the smimeCapabilities OID to satisfy the other use of + the OID. + + The registered SMIMECapabilities list specifies the parameters for + OIDs that need them, most notably key lengths in the case of + variable-length symmetric ciphers. In the event that there are no + differentiating parameters for a particular OID, the parameters MUST + be omitted and MUST NOT be encoded as NULL. Additional values for + the SMIMECapabilities attribute might be defined in the future. + Receiving agents MUST handle an SMIMECapabilities object that has + values that it does not recognize in a graceful manner. + + Section 2.7.1 explains a strategy for caching capabilities. + +2.5.3. Encryption Key Preference Attribute + + The encryption key preference attribute allows the signer to + unambiguously describe which of the signer's certificates has the + signer's preferred encryption key. This attribute is designed to + enhance behavior for interoperating with those clients that use + separate keys for encryption and signing. This attribute is used to + convey to anyone viewing the attribute which of the listed + certificates is appropriate for encrypting a session key for future + encrypted messages. + + + +Schaad, et al. Standards Track [Page 17] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + If present, the SMIMEEncryptionKeyPreference attribute MUST be a + SignedAttribute. CMS defines SignedAttributes as a SET OF Attribute. + The SignedAttributes in a signerInfo MUST include a single instance + of the SMIMEEncryptionKeyPreference attribute. CMS defines the ASN.1 + syntax for Attribute to include attrValues SET OF AttributeValue. An + SMIMEEncryptionKeyPreference attribute MUST only include a single + instance of AttributeValue. If a signature is detected as violating + these requirements, the signature SHOULD be treated as failing. + + The sending agent SHOULD include the referenced certificate in the + set of certificates included in the signed message if this attribute + is used. The certificate MAY be omitted if it has been previously + made available to the receiving agent. Sending agents SHOULD use + this attribute if the commonly used or preferred encryption + certificate is not the same as the certificate used to sign the + message. + + Receiving agents SHOULD store the preference data if the signature on + the message is valid and the signing time is greater than the + currently stored value. (As with the SMIMECapabilities, the clock + skew SHOULD be checked and the data not used if the skew is too + great.) Receiving agents SHOULD respect the sender's encryption key + preference attribute if possible. This, however, represents only a + preference, and the receiving agent can use any certificate in + replying to the sender that is valid. + + Section 2.7.1 explains a strategy for caching preference data. + +2.5.3.1. Selection of Recipient Key Management Certificate + + In order to determine the key management certificate to be used when + sending a future CMS EnvelopedData message for a particular + recipient, the following steps SHOULD be followed: + + - If an SMIMEEncryptionKeyPreference attribute is found in a + SignedData object received from the desired recipient, this + identifies the X.509 certificate that SHOULD be used as the X.509 + key management certificate for the recipient. + + - If an SMIMEEncryptionKeyPreference attribute is not found in a + SignedData object received from the desired recipient, the set of + X.509 certificates SHOULD be searched for an X.509 certificate + with the same subject name as the signer of an X.509 certificate + that can be used for key management. + + + + + + + +Schaad, et al. Standards Track [Page 18] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - Or, use some other method of determining the user's key management + key. If an X.509 key management certificate is not found, then + encryption cannot be done with the signer of the message. If + multiple X.509 key management certificates are found, the S/MIME + agent can make an arbitrary choice between them. + +2.6. SignerIdentifier SignerInfo Type + + S/MIME v4.0 implementations MUST support both issuerAndSerialNumber + and subjectKeyIdentifier. Messages that use the subjectKeyIdentifier + choice cannot be read by S/MIME v2 clients. + + It is important to understand that some certificates use a value for + subjectKeyIdentifier that is not suitable for uniquely identifying a + certificate. Implementations MUST be prepared for multiple + certificates for potentially different entities to have the same + value for subjectKeyIdentifier and MUST be prepared to try each + matching certificate during signature verification before indicating + an error condition. + +2.7. ContentEncryptionAlgorithmIdentifier + + Sending and receiving agents: + + - MUST support encryption and decryption with AES-128 GCM and + AES-256 GCM [RFC5084]. + + - MUST- support encryption and decryption with AES-128 CBC + [RFC3565]. + + - SHOULD+ support encryption and decryption with ChaCha20-Poly1305 + [RFC7905]. + +2.7.1. Deciding Which Encryption Method to Use + + When a sending agent creates an encrypted message, it has to decide + which type of encryption to use. The decision process involves using + information garnered from the capabilities lists included in messages + received from the recipient, as well as out-of-band information such + as private agreements, user preferences, legal restrictions, and + so on. + + Section 2.5.2 defines a method by which a sending agent can + optionally announce, among other things, its decrypting capabilities + in its order of preference. The following method for processing and + remembering the encryption capabilities attribute in incoming signed + messages SHOULD be used. + + + + +Schaad, et al. Standards Track [Page 19] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - If the receiving agent has not yet created a list of capabilities + for the sender's public key, then, after verifying the signature + on the incoming message and checking the timestamp, the receiving + agent SHOULD create a new list containing at least the signing + time and the symmetric capabilities. + + - If such a list already exists, the receiving agent SHOULD verify + that the signing time in the incoming message is greater than the + signing time stored in the list and that the signature is valid. + If so, the receiving agent SHOULD update both the signing time and + capabilities in the list. Values of the signing time that lie far + in the future (that is, a greater discrepancy than any reasonable + clock skew), or a capabilities list in messages whose signature + could not be verified, MUST NOT be accepted. + + The list of capabilities SHOULD be stored for future use in creating + messages. + + Before sending a message, the sending agent MUST decide whether it is + willing to use weak encryption for the particular data in the + message. If the sending agent decides that weak encryption is + unacceptable for this data, then the sending agent MUST NOT use a + weak algorithm. The decision to use or not use weak encryption + overrides any other decision in this section about which encryption + algorithm to use. + + Sections 2.7.1.1 and 2.7.1.2 describe the decisions a sending agent + SHOULD use when choosing which type of encryption will be applied to + a message. These rules are ordered, so the sending agent SHOULD make + its decision in the order given. + +2.7.1.1. Rule 1: Known Capabilities + + If the sending agent has received a set of capabilities from the + recipient for the message the agent is about to encrypt, then the + sending agent SHOULD use that information by selecting the first + capability in the list (that is, the capability most preferred by the + intended recipient) that the sending agent knows how to encrypt. The + sending agent SHOULD use one of the capabilities in the list if the + agent reasonably expects the recipient to be able to decrypt the + message. + +2.7.1.2. Rule 2: Unknown Capabilities, Unknown Version of S/MIME + + If the following two conditions are met, the sending agent SHOULD use + AES-256 GCM, as AES-256 GCM is a stronger algorithm and is required + by S/MIME v4.0: + + + + +Schaad, et al. Standards Track [Page 20] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - The sending agent has no knowledge of the encryption capabilities + of the recipient. + + - The sending agent has no knowledge of the version of S/MIME used + or supported by the recipient. + + If the sending agent chooses not to use AES-256 GCM in this step, + given the presumption is that a client implementing AES-GCM would do + both AES-256 and AES-128, it SHOULD use AES-128 CBC. + +2.7.2. Choosing Weak Encryption + + Algorithms such as RC2 are considered to be weak encryption + algorithms. Algorithms such as TripleDES are not state of the art + and are considered to be weaker algorithms than AES. A sending agent + that is controlled by a human SHOULD allow a human sender to + determine the risks of sending data using a weaker encryption + algorithm before sending the data, and possibly allow the human to + use a stronger encryption algorithm such as AES GCM or AES CBC even + if there is a possibility that the recipient will not be able to + process that algorithm. + +2.7.3. Multiple Recipients + + If a sending agent is composing an encrypted message to a group of + recipients where the encryption capabilities of some of the + recipients do not overlap, the sending agent is forced to send more + than one message. Please note that if the sending agent chooses to + send a message encrypted with a strong algorithm and then send the + same message encrypted with a weak algorithm, someone watching the + communications channel could learn the contents of the strongly + encrypted message simply by decrypting the weakly encrypted message. + +3. Creating S/MIME Messages + + This section describes the S/MIME message formats and how they are + created. S/MIME messages are a combination of MIME bodies and CMS + content types. Several media types as well as several CMS content + types are used. The data to be secured is always a canonical MIME + entity. The MIME entity and other data, such as certificates and + algorithm identifiers, are given to CMS processing facilities that + produce a CMS object. Finally, the CMS object is wrapped in MIME. + The "Enhanced Security Services for S/MIME" documents [ESS] provide + descriptions of how nested, secured S/MIME messages are formatted. + ESS provides a description of how a triple-wrapped S/MIME message is + formatted using multipart/signed and application/pkcs7-mime for the + signatures. + + + + +Schaad, et al. Standards Track [Page 21] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + S/MIME provides one format for enveloped-only data, several formats + for signed-only data, and several formats for signed and enveloped + data. Several formats are required to accommodate several + environments -- in particular, for signed messages. The criteria for + choosing among these formats are also described. + + Anyone reading this section is expected to understand MIME as + described in [MIME-SPEC] and [RFC1847]. + +3.1. Preparing the MIME Entity for Signing, Enveloping, or Compressing + + S/MIME is used to secure MIME entities. A MIME message is composed + of a MIME header and a MIME body. A body can consist of a single + MIME entity or a tree of MIME entities (rooted with a multipart). + S/MIME can be used to secure either a single MIME entity or a tree of + MIME entities. These entities can be in locations other than the + root. S/MIME can be applied multiple times to different entities in + a single message. A MIME entity that is the whole message includes + only the MIME message headers and MIME body and does not include the + rfc822 header. Note that S/MIME can also be used to secure MIME + entities used in applications other than Internet mail. For cases + where protection of the rfc822 header is required, the use of the + message/rfc822 media type is explained later in this section. + + The MIME entity that is secured and described in this section can be + thought of as the "inside" MIME entity. That is, it is the + "innermost" object in what is possibly a larger MIME message. + Processing "outside" MIME entities into CMS EnvelopedData, + CompressedData, and AuthEnvelopedData content types is described in + Sections 3.2 and 3.5. Other documents define additional CMS content + types; those documents should be consulted for processing those CMS + content types. + + The procedure for preparing a MIME entity is given in [MIME-SPEC]. + The same procedure is used here with some additional restrictions + when signing. The description of the procedures from [MIME-SPEC] is + repeated here, but it is suggested that the reader refer to those + documents for the exact procedures. This section also describes + additional requirements. + + A single procedure is used for creating MIME entities that are to + have any combination of signing, enveloping, and compressing applied. + Some additional steps are recommended to defend against known + corruptions that can occur during mail transport that are of + particular importance for clear-signing using the multipart/signed + format. It is recommended that these additional steps be performed + on enveloped messages, or signed and enveloped messages, so that the + messages can be forwarded to any environment without modification. + + + +Schaad, et al. Standards Track [Page 22] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + These steps are descriptive rather than prescriptive. The + implementer is free to use any procedure as long as the result is + the same. + + Step 1. The MIME entity is prepared according to local conventions. + + Step 2. The leaf parts of the MIME entity are converted to + canonical form. + + Step 3. Appropriate transfer encoding is applied to the leaves + of the MIME entity. + + When an S/MIME message is received, the security services on the + message are processed, and the result is the MIME entity. That MIME + entity is typically passed to a MIME-capable user agent where it is + further decoded and presented to the user or receiving application. + + In order to protect outer, non-content-related message header fields + (for instance, the "Subject", "To", "From", and "Cc" fields), the + sending client MAY wrap a full MIME message in a message/rfc822 + wrapper in order to apply S/MIME security services to these header + fields. It is up to the receiving client to decide how to present + this "inner" header along with the unprotected "outer" header. Given + the security difference between headers, it is RECOMMENDED that the + receiving client provide a distinction between header fields, + depending on where they are located. + + When an S/MIME message is received, if the top-level protected MIME + entity has a Content-Type of message/rfc822, it can be assumed that + the intent was to provide header protection. This entity SHOULD be + presented as the top-level message, taking into account + header-merging issues as previously discussed. + +3.1.1. Canonicalization + + Each MIME entity MUST be converted to a canonical form that is + uniquely and unambiguously representable in the environment where the + signature is created and the environment where the signature will be + verified. MIME entities MUST be canonicalized for enveloping and + compressing as well as signing. + + The exact details of canonicalization depend on the actual media type + and subtype of an entity and are not described here. Instead, the + standard for the particular media type SHOULD be consulted. For + example, canonicalization of type text/plain is different from + canonicalization of audio/basic. Other than text types, most types + have only one representation, regardless of computing platform or + environment, that can be considered their canonical representation. + + + +Schaad, et al. Standards Track [Page 23] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + In general, canonicalization will be performed by the non-security + part of the sending agent rather than the S/MIME implementation. + + The most common and important canonicalization is for text, which is + often represented differently in different environments. MIME + entities of major type "text" MUST have both their line endings and + character set canonicalized. The line ending MUST be the pair of + characters , and the charset SHOULD be a registered charset + [CHARSETS]. The details of the canonicalization are specified in + [MIME-SPEC]. + + Note that some charsets such as ISO-2022 have multiple + representations for the same characters. When preparing such text + for signing, the canonical representation specified for the charset + MUST be used. + +3.1.2. Transfer Encoding + + When generating any of the secured MIME entities below, except the + signing using the multipart/signed format, no transfer encoding is + required at all. S/MIME implementations MUST be able to deal with + binary MIME objects. If no Content-Transfer-Encoding header field is + present, the transfer encoding is presumed to be 7BIT. + + As a rule, S/MIME implementations SHOULD use transfer encoding as + described in Section 3.1.3 for all MIME entities they secure. The + reason for securing only 7-bit MIME entities, even for enveloped data + that is not exposed to the transport, is that it allows the MIME + entity to be handled in any environment without changing it. For + example, a trusted gateway might remove the envelope, but not the + signature, of a message, and then forward the signed message on to + the end recipient so that they can verify the signatures directly. + If the transport internal to the site is not 8-bit clean, such as on + a wide-area network with a single mail gateway, verifying the + signature will not be possible unless the original MIME entity was + only 7-bit data. + + In the case where S/MIME implementations can determine that all + intended recipients are capable of handling inner (all but the + outermost) binary MIME objects, implementations SHOULD use binary + encoding as opposed to a 7-bit-safe transfer encoding for the inner + entities. The use of a 7-bit-safe encoding (such as base64) + unnecessarily expands the message size. Implementations MAY + determine that recipient implementations are capable of + handling inner binary MIME entities by (1) interpreting the + id-cap-preferBinaryInside SMIMECapabilities attribute, (2) prior + agreement, or (3) other means. + + + + +Schaad, et al. Standards Track [Page 24] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + If one or more intended recipients are unable to handle inner binary + MIME objects or if this capability is unknown for any of the intended + recipients, S/MIME implementations SHOULD use transfer encoding as + described in Section 3.1.3 for all MIME entities they secure. + +3.1.3. Transfer Encoding for Signing Using multipart/signed + + If a multipart/signed entity is ever to be transmitted over the + standard Internet SMTP infrastructure or other transport that is + constrained to 7-bit text, it MUST have transfer encoding applied so + that it is represented as 7-bit text. MIME entities that are already + 7-bit data need no transfer encoding. Entities such as 8-bit text + and binary data can be encoded with quoted-printable or base64 + transfer encoding. + + The primary reason for the 7-bit requirement is that the Internet + mail transport infrastructure cannot guarantee transport of 8-bit or + binary data. Even though many segments of the transport + infrastructure now handle 8-bit and even binary data, it is sometimes + not possible to know whether the transport path is 8-bit clean. If a + mail message with 8-bit data were to encounter a message transfer + agent that cannot transmit 8-bit or binary data, the agent has three + options, none of which are acceptable for a clear-signed message: + + - The agent could change the transfer encoding; this would + invalidate the signature. + + - The agent could transmit the data anyway, which would most likely + result in the 8th bit being corrupted; this too would invalidate + the signature. + + - The agent could return the message to the sender. + + [RFC1847] prohibits an agent from changing the transfer encoding of + the first part of a multipart/signed message. If a compliant agent + that cannot transmit 8-bit or binary data encountered a + multipart/signed message with 8-bit or binary data in the first part, + it would have to return the message to the sender as undeliverable. + +3.1.4. Sample Canonical MIME Entity + + This example shows a multipart/mixed message with full transfer + encoding. This message contains a text part and an attachment. The + sample message text includes characters that are not ASCII and thus + need to be transfer encoded. Though not shown here, the end of each + line is . The line ending of the MIME headers, the text, and + the transfer-encoded parts all MUST be . + + + + +Schaad, et al. Standards Track [Page 25] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + Note that this example is not an example of an S/MIME message. + + Content-Type: multipart/mixed; boundary=bar + + --bar + Content-Type: text/plain; charset=iso-8859-1 + Content-Transfer-Encoding: quoted-printable + + =A1Hola Michael! + + How do you like the new S/MIME specification? + + It's generally a good idea to encode lines that begin with + From=20because some mail transport agents will insert a + greater-than (>) sign, thus invalidating the signature. + + Also, in some cases it might be desirable to encode any =20 + trailing whitespace that occurs on lines in order to ensure =20 + that the message signature is not invalidated when passing =20 + a gateway that modifies such whitespace (like BITNET). =20 + + --bar + Content-Type: image/jpeg + Content-Transfer-Encoding: base64 + + iQCVAwUBMJrRF2N9oWBghPDJAQE9UQQAtl7LuRVndBjrk4EqYBIb3h5QXIX/LC// + jJV5bNvkZIGPIcEmI5iFd9boEgvpirHtIREEqLQRkYNoBActFBZmh9GC3C041WGq + uMbrbxc+nIs1TIKlA08rVi9ig/2Yh7LFrK5Ein57U/W72vgSxLhe/zhdfolT9Brn + HOxEa44b+EI= + + --bar-- + +3.2. The application/pkcs7-mime Media Type + + The application/pkcs7-mime media type is used to carry CMS content + types, including EnvelopedData, SignedData, and CompressedData. The + details of constructing these entities are described in subsequent + sections. This section describes the general characteristics of the + application/pkcs7-mime media type. + + The carried CMS object always contains a MIME entity that is prepared + as described in Section 3.1 if the eContentType is id-data. Other + contents MAY be carried when the eContentType contains different + values. See [ESS] for an example of this with signed receipts. + + Since CMS content types are binary data, in most cases base64 + transfer encoding is appropriate -- in particular, when used with + SMTP transport. The transfer encoding used depends on the transport + + + +Schaad, et al. Standards Track [Page 26] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + through which the object is to be sent and is not a characteristic of + the media type. + + Note that this discussion refers to the transfer encoding of the CMS + object or "outside" MIME entity. It is completely distinct from, and + unrelated to, the transfer encoding of the MIME entity secured by the + CMS object -- the "inside" object, which is described in Section 3.1. + + Because there are several types of application/pkcs7-mime objects, a + sending agent SHOULD do as much as possible to help a receiving agent + know about the contents of the object without forcing the receiving + agent to decode the ASN.1 for the object. The Content-Type header + field of all application/pkcs7-mime objects SHOULD include the + optional "smime-type" parameter, as described in the following + sections. + +3.2.1. The name and filename Parameters + + For application/pkcs7-mime, sending agents SHOULD emit the + optional "name" parameter to the Content-Type field for compatibility + with older systems. Sending agents SHOULD also emit the optional + Content-Disposition field [RFC2183] with the "filename" parameter. + If a sending agent emits the above parameters, the value of the + parameters SHOULD be a filename with the appropriate extension: + + File + Media Type Extension + ------------------------------------------------------------------- + application/pkcs7-mime (SignedData, EnvelopedData, .p7m + AuthEnvelopedData) + application/pkcs7-mime (degenerate SignedData certificate .p7c + management message) + application/pkcs7-mime (CompressedData) .p7z + application/pkcs7-signature (SignedData) .p7s + + In addition, the filename SHOULD be limited to eight characters + followed by a three-letter extension. The eight-character filename + base can be any distinct name; the use of the filename base "smime" + SHOULD be used to indicate that the MIME entity is associated with + S/MIME. + + Including a filename serves two purposes. It facilitates easier use + of S/MIME objects as files on disk. It also can convey type + information across gateways. When a MIME entity of type + application/pkcs7-mime (for example) arrives at a gateway that has no + special knowledge of S/MIME, it will default the entity's media type + to application/octet-stream and treat it as a generic attachment, + thus losing the type information. However, the suggested filename + + + +Schaad, et al. Standards Track [Page 27] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + for an attachment is often carried across a gateway. This often + allows the receiving systems to determine the appropriate application + to hand the attachment off to -- in this case, a standalone S/MIME + processing application. Note that this mechanism is provided as a + convenience for implementations in certain environments. A proper + S/MIME implementation MUST use the media types and MUST NOT rely on + the file extensions. + +3.2.2. The smime-type Parameter + + The application/pkcs7-mime content type defines the optional + "smime-type" parameter. The intent of this parameter is to convey + details about the security applied (signed or enveloped) along with + information about the contained content. This specification defines + the following smime-types. + + Name CMS Type Inner Content + ---------------------------------------------------------- + enveloped-data EnvelopedData id-data + signed-data SignedData id-data + certs-only SignedData id-data + compressed-data CompressedData id-data + authEnveloped-data AuthEnvelopedData id-data + + In order for consistency to be obtained with future specifications, + the following guidelines SHOULD be followed when assigning a new + smime-type parameter. + + 1. If both signing and encryption can be applied to the content, + then three values for smime-type SHOULD be assigned: "signed-*", + "authEnv-*", and "enveloped-*". If one operation can be + assigned, then this can be omitted. Thus, since "certs-only" can + only be signed, "signed-" is omitted. + + 2. A common string for a content OID SHOULD be assigned. We use + "data" for the id-data content OID when MIME is the inner + content. + + 3. If no common string is assigned, then the common string of + "OID." is recommended (for example, + "OID.2.16.840.1.101.3.4.1.2" would be AES-128 CBC). + + It is explicitly intended that this field be a suitable hint for mail + client applications to indicate whether a message is "signed", + "authEnveloped", or "enveloped" without having to tunnel into the CMS + payload. + + + + + +Schaad, et al. Standards Track [Page 28] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + A registry for additional smime-type parameter values has been + defined in [RFC7114]. + +3.3. Creating an Enveloped-Only Message + + This section describes the format for enveloping a MIME entity + without signing it. It is important to note that sending enveloped + but not signed messages does not provide for data integrity. The + "enveloped-only" structure does not support authenticated symmetric + algorithms. Use the "authenticated enveloped" structure for these + algorithms. Thus, it is possible to replace ciphertext in such a way + that the processed message will still be valid, but the meaning can + be altered. + + Step 1. The MIME entity to be enveloped is prepared according to + Section 3.1. + + Step 2. The MIME entity and other required data are processed into a + CMS object of type EnvelopedData. In addition to encrypting + a copy of the content-encryption key (CEK) for each + recipient, a copy of the CEK SHOULD be encrypted for the + originator and included in the EnvelopedData (see [RFC5652], + Section 6). + + Step 3. The EnvelopedData object is wrapped in a CMS ContentInfo + object. + + Step 4. The ContentInfo object is inserted into an + application/pkcs7-mime MIME entity. + + The smime-type parameter for enveloped-only messages is + "enveloped-data". The file extension for this type of message + is ".p7m". + + A sample message would be: + + Content-Type: application/pkcs7-mime; name=smime.p7m; + smime-type=enveloped-data + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename=smime.p7m + + MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEw + dDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAC3EN5nGI + iJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FBs3IWg+f6KgCLx3M1eC + bWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd8Ch4H/dd9gdzTd+taTEgS0ip + dSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBA + gtaMXpRwZRNYAgDsiSf8Z9P43LrY4OxUk660cu1lXeCSFOSOpOJ7FuVyU= + + + + +Schaad, et al. Standards Track [Page 29] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +3.4. Creating an Authenticated Enveloped-Only Message + + This section describes the format for enveloping a MIME entity + without signing it. Authenticated enveloped messages provide + confidentiality and data integrity. It is important to note that + sending authenticated enveloped messages does not provide for proof + of origination when using S/MIME. It is possible for a third party + to replace ciphertext in such a way that the processed message will + still be valid, but the meaning can be altered. However, this is + substantially more difficult than it is for an enveloped-only + message, as the algorithm does provide a level of authentication. + Any recipient for whom the message is encrypted can replace it + without detection. + + Step 1. The MIME entity to be enveloped is prepared according to + Section 3.1. + + Step 2. The MIME entity and other required data are processed into a + CMS object of type AuthEnvelopedData. In addition to + encrypting a copy of the CEK for each recipient, a copy of + the CEK SHOULD be encrypted for the originator and included + in the AuthEnvelopedData (see [RFC5083]). + + Step 3. The AuthEnvelopedData object is wrapped in a CMS ContentInfo + object. + + Step 4. The ContentInfo object is inserted into an + application/pkcs7-mime MIME entity. + + The smime-type parameter for authenticated enveloped-only messages is + "authEnveloped-data". The file extension for this type of message + is ".p7m". + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 30] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + A sample message would be: + + Content-Type: application/pkcs7-mime; smime-type=authEnveloped-data; + name=smime.p7m + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename=smime.p7m + + MIIDWQYLKoZIhvcNAQkQARegggNIMIIDRAIBADGBvjCBuwIBADAmMBIxEDAO + BgNVBAMTB0NhcmxSU0ECEEY0a8eAAFa8EdNuLs1dcdAwCwYJKoZIhvcNAQEB + BIGAgyZJo0ERTxA4xdTri5P5tVMyh0RARepTUCORZvlUbcUlaI8IpJZH3/J1 + Fv6MxTRS4O/K+ZcTlQmYeWLQvwdltQdOIP3mhpqXzTnOYhTK1IDtF2zx75Lg + vE+ilpcLIzXfJB4RCBPtBWaHAof4Wb+VMQvLkk9OolX4mRSH1LPktgAwggJq + BgkqhkiG9w0BBwEwGwYJYIZIAWUDBAEGMA4EDGPizioC9OHSsnNx4oCCAj7Y + Cb8rOy8+55106newEJohC/aDgWbJhrMKzSOwa7JraXOV3HXD3NvKbl665dRx + vmDwSCNaLCRU5q8/AxQx2SvnAbM+JKcEfC/VFdd4SiHNiUECAApLku2rMi5B + WrhW/FXmx9d+cjum2BRwB3wj0q1wajdB0/kVRbQwg697dnlYyUog4vpJERjr + 7KAkawZx1RMHaM18wgZjUNpCBXFS3chQi9mTBp2i2Hf5iZ8OOtTx+rCQUmI6 + Jhy03vdcPCCARBjn3v0d3upZYDZddMA41CB9fKnnWFjadV1KpYwv80tqsEfx + Vo0lJQ5VtJ8MHJiBpLVKadRIZ4iH2ULC0JtN5mXE1SrFKh7cqbJ4+7nqSRL3 + oBTud3rX41DGshOjpqcYHT4sqYlgZkc6dp0g1+hF1p3cGmjHdpysV2NVSUev + ghHbvSqhIsXFzRSWKiZOigmlkv3R5LnjpYyP4brM62Jl7y0qborvV4dNMz7m + D+5YxSlH0KAe8z6TT3LHuQdN7QCkFoiUSCaNhpAFaakkGIpqcqLhpOK4lXxt + kptCG93eUwNCcTxtx6bXufPR5TUHohvZvfeqMp42kL37FJC/A8ZHoOxXy8+X + X5QYxCQNuofWlvnIWv0Nr8w65x6lgVjPYmd/cHwzQKBTBMXN6pBud/PZL5zF + tw3QHlQkBR+UflMWZKeN9L0KdQ27mQlCo5gQS85aifxoiiA2v9+0hxZw91rP + IW4D+GS7oMMoKj8ZNyCJJsyf5smRZ+WxeBoolb3+TiGcBBCsRnfe6noLZiFO + 6Zeu2ZwE + +3.5. Creating a Signed-Only Message + + There are two formats for signed messages defined for S/MIME: + + - application/pkcs7-mime with SignedData. + + - multipart/signed. + + In general, the multipart/signed form is preferred for sending, and + receiving agents MUST be able to handle both. + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 31] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +3.5.1. Choosing a Format for Signed-Only Messages + + There are no hard-and-fast rules as to when a particular signed-only + format is chosen. It depends on the capabilities of all the + receivers and the relative importance of receivers with S/MIME + facilities being able to verify the signature versus the importance + of receivers without S/MIME software being able to view the message. + + Messages signed using the multipart/signed format can always be + viewed by the receiver whether or not they have S/MIME software. + They can also be viewed whether they are using a MIME-native user + agent or they have messages translated by a gateway. In this + context, "be viewed" means the ability to process the message + essentially as if it were not a signed message, including any other + MIME structure the message might have. + + Messages signed using the SignedData format cannot be viewed by a + recipient unless they have S/MIME facilities. However, the + SignedData format protects the message content from being changed by + benign intermediate agents. Such agents might do line wrapping or + content-transfer encoding changes that would break the signature. + +3.5.2. Signing Using application/pkcs7-mime with SignedData + + This signing format uses the application/pkcs7-mime media type. The + steps to create this format are as follows: + + Step 1. The MIME entity is prepared according to Section 3.1. + + Step 2. The MIME entity and other required data are processed into a + CMS object of type SignedData. + + Step 3. The SignedData object is wrapped in a CMS ContentInfo + object. + + Step 4. The ContentInfo object is inserted into an + application/pkcs7-mime MIME entity. + + The smime-type parameter for messages using application/pkcs7-mime + with SignedData is "signed-data". The file extension for this type + of message is ".p7m". + + + + + + + + + + +Schaad, et al. Standards Track [Page 32] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + A sample message would be: + + Content-Type: application/pkcs7-mime; smime-type=signed-data; + name=smime.p7m + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename=smime.p7m + + MIIDmQYJKoZIhvcNAQcCoIIDijCCA4YCAQExCTAHBgUrDgMCGjAtBgkqhkiG9w0BBw + GgIAQeDQpUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIIC4DCCAtwwggKboAMC + AQICAgDIMAkGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUzAeFw05OTA4MTcwMT + EwNDlaFw0zOTEyMzEyMzU5NTlaMBMxETAPBgNVBAMTCEFsaWNlRFNTMIIBtjCCASsG + ByqGSM44BAEwggEeAoGBAIGNze2D6gqeOT7CSCij5EeT3Q7XqA7sU8WrhAhP/5Thc0 + h+DNbzREjR/p+vpKGJL+HZMMg23j+bv7dM3F9piuR10DcMkQiVm96nXvn89J8v3UOo + i1TxP7AHCEdNXYjDw7Wz41UIddU5dhDEeL3/nbCElzfy5FEbteQJllzzflvbAhUA4k + emGkVmuBPG2o+4NyErYov3k80CgYAmONAUiTKqOfs+bdlLWWpMdiM5BAI1XPLLGjDD + HlBd3ZtZ4s2qBT1YwHuiNrhuB699ikIlp/R1z0oIXks+kPht6pzJIYo7dhTpzi5dow + fNI4W4LzABfG1JiRGJNkS9+MiVSlNWteL5c+waYTYfEX/Cve3RUP+YdMLRgUpgObo2 + OQOBhAACgYBc47ladRSWC6l63eM/qeysXty9txMRNKYWiSgRI9k0hmd1dRMSPUNbb+ + VRv/qJ8qIbPiR9PQeNW2PIu0WloErjhdbOBoA/6CN+GvIkq1MauCcNHu8Iv2YUgFxi + rGX6FYvxuzTU0pY39mFHssQyhPB+QUD9RqdjTjPypeL08oPluKOBgTB/MAwGA1UdEw + EB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMB8GA1UdIwQYMBaAFHBEPoIub4feStN14z0g + vEMrk/EfMB0GA1UdDgQWBBS+bKGz48H37UNwpM4TAeL945f+zTAfBgNVHREEGDAWgR + RBbGljZURTU0BleGFtcGxlLmNvbTAJBgcqhkjOOAQDAzAAMC0CFFUMpBkfQiuJcSIz + jYNqtT1na79FAhUAn2FTUlQLXLLd2ud2HeIQUltDXr0xYzBhAgEBMBgwEjEQMA4GA1 + UEAxMHQ2FybERTUwICAMgwBwYFKw4DAhowCQYHKoZIzjgEAwQuMCwCFD1cSW6LIUFz + eXle3YI5SKSBer/sAhQmCq7s/CTFHOEjgASeUjbMpx5g6A== + +3.5.3. Signing Using the multipart/signed Format + + This format is a clear-signing format. Recipients without any S/MIME + or CMS processing facilities are able to view the message. It makes + use of the multipart/signed media type described in [RFC1847]. The + multipart/signed media type has two parts. The first part contains + the MIME entity that is signed; the second part contains the + "detached signature" CMS SignedData object in which the + encapContentInfo eContent field is absent. + +3.5.3.1. The application/pkcs7-signature Media Type + + This media type always contains a CMS ContentInfo containing a single + CMS object of type SignedData. The SignedData encapContentInfo + eContent field MUST be absent. The signerInfos field contains the + signatures for the MIME entity. + + The file extension for signed-only messages using + application/pkcs7-signature is ".p7s". + + + + + +Schaad, et al. Standards Track [Page 33] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +3.5.3.2. Creating a multipart/signed Message + + Step 1. The MIME entity to be signed is prepared according to + Section 3.1, taking special care for clear-signing. + + Step 2. The MIME entity is presented to CMS processing in order to + obtain an object of type SignedData in which the + encapContentInfo eContent field is absent. + + Step 3. The MIME entity is inserted into the first part of a + multipart/signed message with no processing other than that + described in Section 3.1. + + Step 4. Transfer encoding is applied to the "detached signature" CMS + SignedData object, and it is inserted into a MIME entity of + type application/pkcs7-signature. + + Step 5. The MIME entity of the application/pkcs7-signature is + inserted into the second part of the multipart/signed + entity. + + The multipart/signed Content-Type has two required parameters: the + protocol parameter and the micalg parameter. + + The protocol parameter MUST be "application/pkcs7-signature". Note + that quotation marks are required around the protocol parameter + because MIME requires that the "/" character in the parameter value + MUST be quoted. + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 34] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + The micalg parameter allows for one-pass processing when the + signature is being verified. The value of the micalg parameter is + dependent on the message digest algorithm(s) used in the calculation + of the Message Integrity Check. If multiple message digest + algorithms are used, they MUST be separated by commas per [RFC1847]. + The values to be placed in the micalg parameter SHOULD be from the + following: + + Algorithm Value Used + ----------------------------------------------------------- + MD5* md5 + SHA-1* sha-1 + SHA-224 sha-224 + SHA-256 sha-256 + SHA-384 sha-384 + SHA-512 sha-512 + Any other (defined separately in the algorithm profile + or "unknown" if not defined) + + *Note: MD5 and SHA-1 are historical and no longer considered secure. + See Appendix B for details. + + (Historical note: Some early implementations of S/MIME emitted and + expected "rsa-md5", "rsa-sha1", and "sha1" for the micalg parameter.) + Receiving agents SHOULD be able to recover gracefully from a micalg + parameter value that they do not recognize. Future values for this + parameter will be taken from the IANA "Hash Function Textual Names" + registry. + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 35] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +3.5.3.3. Sample multipart/signed Message + + Content-Type: multipart/signed; + micalg=sha-256; + boundary="----=_NextBoundary____Fri,_06_Sep_2002_00:25:21"; + protocol="application/pkcs7-signature" + + This is a multipart message in MIME format. + + ------=_NextBoundary____Fri,_06_Sep_2002_00:25:21 + + This is some sample content. + ------=_NextBoundary____Fri,_06_Sep_2002_00:25:21 + Content-Type: application/pkcs7-signature; name=smime.p7s + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename=smime.p7s + + MIIBJgYJKoZIhvcNAQcCoIIBFzCCARMCAQExADALBgkqhkiG9w0BBwExgf4w + gfsCAQIwJjASMRAwDgYDVQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7EELOw + MAsGCWCGSAFlAwQCAaAxMC8GCSqGSIb3DQEJBDEiBCCxwpZGNZzTSsugsn+f + lEidzQK4mf/ozKqfmbxhcIkKqjALBgkqhkiG9w0BAQsEgYB0XJV7fjPa5Nuh + oth5msDfP8A5urYUMjhNpWgXG8ae3XpppqVrPi2nVO41onHnkByjkeD/wc31 + A9WH8MzFQgSTsrJ65JvffTTXkOpRPxsSHn3wJFwP/atWHkh8YK/jR9bULhUl + Mv5jQEDiwVX5DRasxu6Ld8zv9u5/TsdBNiufGw== + + ------=_NextBoundary____Fri,_06_Sep_2002_00:25:21-- + + The content that is digested (the first part of the multipart/signed) + consists of the bytes: + + 54 68 69 73 20 69 73 20 73 6f 6d 65 20 73 61 6d 70 6c 65 20 63 6f 6e + 74 65 6e 74 2e 0d 0a + +3.6. Creating a Compressed-Only Message + + This section describes the format for compressing a MIME entity. + Please note that versions of S/MIME prior to version 3.1 did not + specify any use of CompressedData and will not recognize it. The use + of a capability to indicate the ability to receive CompressedData is + described in [RFC3274] and is the preferred method for compatibility. + + Step 1. The MIME entity to be compressed is prepared according to + Section 3.1. + + Step 2. The MIME entity and other required data are processed into a + CMS object of type CompressedData. + + + + + +Schaad, et al. Standards Track [Page 36] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + Step 3. The CompressedData object is wrapped in a CMS ContentInfo + object. + + Step 4. The ContentInfo object is inserted into an + application/pkcs7-mime MIME entity. + + The smime-type parameter for compressed-only messages is + "compressed-data". The file extension for this type of message + is ".p7z". + + A sample message would be: + + Content-Type: application/pkcs7-mime; smime-type=compressed-data; + name=smime.p7z + Content-Transfer-Encoding: base64 + Content-Disposition: attachment; filename=smime.p7z + + eNoLycgsVgCi4vzcVIXixNyCnFSF5Py8ktS8Ej0AlCkKVA== + +3.7. Multiple Operations + + The signed-only, enveloped-only, and compressed-only MIME formats can + be nested. This works because these formats are all MIME entities + that encapsulate other MIME entities. + + An S/MIME implementation MUST be able to receive and process + arbitrarily nested S/MIME within reasonable resource limits of the + recipient computer. + + It is possible to apply any of the signing, encrypting, and + compressing operations in any order. It is up to the implementer and + the user to choose. When signing first, the signatories are then + securely obscured by the enveloping. When enveloping first, the + signatories are exposed, but it is possible to verify signatures + without removing the enveloping. This can be useful in an + environment where automatic signature verification is desired, as no + private key material is required to verify a signature. + + There are security ramifications related to choosing whether to sign + first or encrypt first. A recipient of a message that is encrypted + and then signed can validate that the encrypted block was unaltered + but cannot determine any relationship between the signer and the + unencrypted contents of the message. A recipient of a message that + is signed and then encrypted can assume that the signed message + itself has not been altered but that a careful attacker could have + changed the unauthenticated portions of the encrypted message. + + + + + +Schaad, et al. Standards Track [Page 37] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + When using compression, keep the following guidelines in mind: + + - Compression of encrypted data that is transferred as binary data + is discouraged, since it will not yield significant compression. + Encrypted data that is transferred as base64-encoded data could + benefit as well. + + - If a lossy compression algorithm is used with signing, you will + need to compress first, then sign. + +3.8. Creating a Certificate Management Message + + The certificate management message or MIME entity is used to + transport certificates and/or Certificate Revocation Lists (CRLs), + such as in response to a registration request. + + Step 1. The certificates and/or CRLs are made available to the CMS + generating process that creates a CMS object of type + SignedData. The SignedData encapContentInfo eContent field + MUST be absent, and the signerInfos field MUST be empty. + + Step 2. The SignedData object is wrapped in a CMS ContentInfo + object. + + Step 3. The ContentInfo object is enclosed in an + application/pkcs7-mime MIME entity. + + The smime-type parameter for a certificate management message is + "certs-only". The file extension for this type of message is ".p7c". + +3.9. Registration Requests + + A sending agent that signs messages MUST have a certificate for the + signature so that a receiving agent can verify the signature. There + are many ways of getting certificates, such as through an exchange + with a certification authority, through a hardware token or diskette, + and so on. + + S/MIME v2 [SMIMEv2] specified a method for "registering" public keys + with certificate authorities using an application/pkcs10 body part. + Since that time, the IETF PKIX Working Group has developed other + methods for requesting certificates. However, S/MIME v4.0 does not + require a particular certificate request mechanism. + + + + + + + + +Schaad, et al. Standards Track [Page 38] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +3.10. Identifying an S/MIME Message + + Because S/MIME takes into account interoperation in non-MIME + environments, several different mechanisms are employed to carry the + type information, and it becomes a bit difficult to identify S/MIME + messages. The following table lists criteria for determining whether + or not a message is an S/MIME message. A message is considered an + S/MIME message if it matches any of the criteria listed below. + + The file suffix in the table below comes from the "name" parameter in + the Content-Type header field or the "filename" parameter in the + Content-Disposition header field. The MIME parameters that carry the + file suffix are not listed below. + + Media Type Parameters File Suffix + --------------------------------------------------------------------- + application/pkcs7-mime N/A N/A + + multipart/signed protocol= N/A + "application/pkcs7-signature" + + application/octet-stream N/A p7m, p7s, + p7c, p7z + +4. Certificate Processing + + A receiving agent MUST provide some certificate retrieval mechanism + in order to gain access to certificates for recipients of digital + envelopes. This specification does not cover how S/MIME agents + handle certificates -- only what they do after a certificate has been + validated or rejected. S/MIME certificate issues are covered in + [RFC5750]. + + At a minimum, for initial S/MIME deployment, a user agent could + automatically generate a message to an intended recipient requesting + that recipient's certificate in a signed return message. Receiving + and sending agents SHOULD also provide a mechanism to allow a user to + "store and protect" certificates for correspondents in such a way as + to guarantee their later retrieval. + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 39] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +4.1. Key Pair Generation + + All key pairs MUST be generated from a good source of + non-deterministic random input [RFC4086], and the private key MUST be + protected in a secure fashion. + + An S/MIME user agent MUST NOT generate asymmetric keys less than + 2048 bits for use with an RSA signature algorithm. + + For 2048-bit through 4096-bit RSA with SHA-256, see [RFC5754] and + [FIPS186-4]. The first reference provides the signature algorithm's + OID, and the second provides the signature algorithm's definition. + + For RSASSA-PSS with SHA-256, see [RFC4056]. For RSAES-OAEP, see + [RFC3560]. + +4.2. Signature Generation + + The following are the requirements for an S/MIME agent when + generating RSA and RSASSA-PSS signatures: + + key size <= 2047 : SHOULD NOT (Note 2) + 2048 <= key size <= 4096 : SHOULD (Note 1) + 4096 < key size : MAY (Note 1) + + Note 1: See Security Considerations in Section 6. + Note 2: See Historical Mail Considerations in Appendix B. + + Key sizes for ECDSA and EdDSA are fixed by the curve. + +4.3. Signature Verification + + The following are the requirements for S/MIME receiving agents during + verification of RSA and RSASSA-PSS signatures: + + key size <= 2047 : SHOULD NOT (Note 2) + 2048 <= key size <= 4096 : MUST (Note 1) + 4096 < key size : MAY (Note 1) + + Note 1: See Security Considerations in Section 6. + Note 2: See Historical Mail Considerations in Appendix B. + + Key sizes for ECDSA and EdDSA are fixed by the curve. + + + + + + + + +Schaad, et al. Standards Track [Page 40] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +4.4. Encryption + + The following are the requirements for an S/MIME agent when + establishing keys for content encryption using the RSA and RSA-OAEP + algorithms: + + key size <= 2047 : SHOULD NOT (Note 2) + 2048 <= key size <= 4096 : SHOULD (Note 1) + 4096 < key size : MAY (Note 1) + + Note 1: See Security Considerations in Section 6. + Note 2: See Historical Mail Considerations in Appendix B. + + Key sizes for ECDH are fixed by the curve. + +4.5. Decryption + + The following are the requirements for an S/MIME agent when + establishing keys for content decryption using the RSA and RSAES-OAEP + algorithms: + + key size <= 2047 : MAY (Note 2) + 2048 <= key size <= 4096 : MUST (Note 1) + 4096 < key size : MAY (Note 1) + + Note 1: See Security Considerations in Section 6. + Note 2: See Historical Mail Considerations in Appendix B. + + Key sizes for ECDH are fixed by the curve. + +5. IANA Considerations + + This section (1) updates the media type registrations for + application/pkcs7-mime and application/pkcs7-signature to refer to + this document as opposed to RFC 5751, (2) adds authEnveloped-data to + the list of values for smime-type, and (3) updates references from + RFC 5751 to this document in general. + + Note that other documents can define additional media types for + S/MIME. + + + + + + + + + + + +Schaad, et al. Standards Track [Page 41] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +5.1. Media Type for application/pkcs7-mime + + Type name: application + + Subtype Name: pkcs7-mime + + Required Parameters: NONE + + Optional Parameters: smime-type + name + + Encoding Considerations: See Section 3 of this document + + Security Considerations: See Section 6 of this document + + Interoperability Considerations: See Sections 1-6 of this document + + Published Specification: RFC 2311, RFC 2633, RFC 5751, + and this document + + Applications that use this media type: Security applications + + Fragment identifier considerations: N/A + + Additional information: + Deprecated alias names for this type: N/A + Magic number(s): N/A + File extensions(s): See Section 3.2.1 of this document + Macintosh file type code(s): N/A + + Person & email address to contact for further information: + The IESG + + Intended usage: COMMON + + Restrictions on usage: NONE + + Author: Sean Turner + + Change Controller: LAMPS working group delegated from the IESG + + + + + + + + + + + +Schaad, et al. Standards Track [Page 42] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +5.2. Media Type for application/pkcs7-signature + + Type name: application + + Subtype Name: pkcs7-signature + + Required Parameters: N/A + + Optional Parameters: N/A + + Encoding Considerations: See Section 3 of this document + + Security Considerations: See Section 6 of this document + + Interoperability Considerations: See Sections 1-6 of this document + + Published Specification: RFC 2311, RFC 2633, RFC 5751, + and this document + + Applications that use this media type: Security applications + + Fragment identifier considerations: N/A + + Additional information: + Deprecated alias names for this type: N/A + Magic number(s): N/A + File extensions(s): See Section 3.2.1 of this document + Macintosh file type code(s): N/A + + Person & email address to contact for further information: + The IESG + + Intended usage: COMMON + + Restrictions on usage: N/A + + Author: Sean Turner + + Change Controller: LAMPS working group delegated from the IESG + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 43] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +5.3. authEnveloped-data smime-type + + IANA has registered the following value in the "Parameter Values for + the smime-type Parameter" registry. + + smime-type value: authEnveloped-data + + Reference: RFC 8551, Section 3.2.2 + +5.4. Reference Updates + + IANA is to update all references to RFC 5751 to this document. Known + registries to be updated are "CoAP Content-Formats" and "media- + types". + +6. Security Considerations + + Cryptographic algorithms will be broken or weakened over time. + Implementers and users need to check that the cryptographic + algorithms listed in this document continue to provide the expected + level of security. The IETF from time to time may issue documents + dealing with the current state of the art. For example: + + - The Million Message Attack described in RFC 3218 [RFC3218]. + + - The Diffie-Hellman "small-subgroup" attacks described in RFC 2785 + [RFC2785]. + + - The attacks against hash algorithms described in RFC 4270 + [RFC4270]. + + This specification uses Public-Key Cryptography technologies. It is + assumed that the private key is protected to ensure that it is not + accessed or altered by unauthorized parties. + + It is impossible for most people or software to estimate the value of + a message's content. Further, it is impossible for most people or + software to estimate the actual cost of recovering an encrypted + message's content that is encrypted with a key of a particular size. + Further, it is quite difficult to determine the cost of a failed + decryption if a recipient cannot process a message's content. Thus, + choosing between different key sizes (or choosing whether to just use + plaintext) is also impossible for most people or software. However, + decisions based on these criteria are made all the time, and + therefore this specification gives a framework for using those + estimates in choosing algorithms. + + + + + +Schaad, et al. Standards Track [Page 44] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + The choice of 2048 bits as an RSA asymmetric key size in this + specification is based on the desire to provide at least 100 bits of + security. The key sizes that must be supported to conform to this + specification seem appropriate for the Internet, based on [RFC3766]. + Of course, there are environments, such as financial and medical + systems, that may select different key sizes. For this reason, an + implementation MAY support key sizes beyond those recommended in this + specification. + + Receiving agents that validate signatures and sending agents that + encrypt messages need to be cautious of cryptographic processing + usage when validating signatures and encrypting messages using keys + larger than those mandated in this specification. An attacker could + send certificates with keys that would result in excessive + cryptographic processing -- for example, keys larger than those + mandated in this specification, as such keys could swamp the + processing element. Agents that use such keys without first + validating the certificate to a trust anchor are advised to have some + sort of cryptographic resource management system to prevent such + attacks. + + Some cryptographic algorithms such as RC2 offer little actual + security over sending plaintext. Other algorithms such as TripleDES + provide security but are no longer considered to be state of the art. + S/MIME requires the use of current state-of-the-art algorithms such + as AES and provides the ability to announce cryptographic + capabilities to parties with whom you communicate. This allows the + sender to create messages that can use the strongest common + encryption algorithm. Using algorithms such as RC2 is never + recommended unless the only alternative is no cryptography. + + RSA and DSA keys of less than 2048 bits are now considered by many + experts to be cryptographically insecure (due to advances in + computing power) and should no longer be used to protect messages. + Such keys were previously considered secure, so processing previously + received signed and encrypted mail will often result in the use of + weak keys. Implementations that wish to support previous versions of + S/MIME or process old messages need to consider the security risks + that result from smaller key sizes (e.g., spoofed messages) versus + the costs of denial of service. If an implementation supports + verification of digital signatures generated with RSA and DSA keys of + less than 1024 bits, it MUST warn the user. Implementers should + consider providing different warnings for newly received messages and + previously stored messages. Server implementations (e.g., secure + mail list servers) where user warnings are not appropriate SHOULD + reject messages with weak signatures. + + + + + +Schaad, et al. Standards Track [Page 45] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + Implementers SHOULD be aware that multiple active key pairs can be + associated with a single individual. For example, one key pair can + be used to support confidentiality, while a different key pair can be + used for digital signatures. + + If a sending agent is sending the same message using different + strengths of cryptography, an attacker watching the communications + channel might be able to determine the contents of the strongly + encrypted message by decrypting the weakly encrypted version. In + other words, a sender SHOULD NOT send a copy of a message using + weaker cryptography than they would use for the original of the + message. + + Modification of the ciphertext in EnvelopedData can go undetected if + authentication is not also used, which is the case when sending + EnvelopedData without wrapping it in SignedData or enclosing + SignedData within it. This is one of the reasons for moving from + EnvelopedData to AuthEnvelopedData, as the authenticated encryption + algorithms provide the authentication without needing the SignedData + layer. + + If an implementation is concerned about compliance with National + Institute of Standards and Technology (NIST) key size + recommendations, then see [SP800-57]. + + If messaging environments make use of the fact that a message is + signed to change the behavior of message processing (examples would + be running rules or UI display hints), without first verifying that + the message is actually signed and knowing the state of the + signature, this can lead to incorrect handling of the message. + Visual indicators on messages may need to have the signature + validation code checked periodically if the indicator is supposed to + give information on the current status of a message. + + Many people assume that the use of an authenticated encryption + algorithm is all that is needed for the sender of the message to be + authenticated. In almost all cases, this is not a correct statement. + There are a number of preconditions that need to hold for an + authenticated encryption algorithm to provide this service: + + - The starting key must be bound to a single entity. The use of a + group key only would allow for the statement that a message was + sent by one of the entities that held the key but will not + identify a specific entity. + + + + + + + +Schaad, et al. Standards Track [Page 46] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - The message must have exactly one sender and one recipient. + Having more than one recipient would allow for the second + recipient to create a message that the first recipient would + believe is from the sender by stripping the second recipient from + the message. + + - A direct path needs to exist from the starting key to the key used + as the CEK. That path needs to guarantee that no third party + could have seen the resulting CEK. This means that one needs to + be using an algorithm that is called a "Direct Encryption" or a + "Direct Key Agreement" algorithm in other contexts. This means + that the starting key is (1) used directly as the CEK or (2) used + to create a secret that is then transformed into the CEK via a + KDF step. + + S/MIME implementations almost universally use ephemeral-static rather + than static-static key agreement and do not use a shared secret for + encryption. This means that the first precondition is not met. + [RFC6278] defines how to use static-static key agreement with CMS, so + the first precondition can be met. Currently, all S/MIME key + agreement methods derive a key-encryption key (KEK) and wrap a CEK. + This violates the third precondition above. New key agreement + algorithms that directly created the CEK without creating an + intervening KEK would need to be defined. + + Even when all of the preconditions are met and origination of a + message is established by the use of an authenticated encryption + algorithm, users need to be aware that there is no way to prove this + to a third party. This is because either of the parties can + successfully create the message (or just alter the content) based on + the fact that the CEK is going to be known to both parties. Thus, + the origination is always built on a presumption that "I did not send + this message to myself." + + All of the authenticated encryption algorithms in this document use + counter mode for the encryption portion of the algorithm. This means + that the length of the plaintext will always be known, as the + ciphertext length and the plaintext length are always the same. This + information can enable passive observers to infer information based + solely on the length of the message. Applications for which this is + a concern need to provide some type of padding so that the length of + the message does not provide this information. + + When compression is used with encryption, it has the potential to + provide an additional layer of security. However, care needs to be + taken when designing a protocol that relies on using compression, so + as not to create a compression oracle. Compression oracle attacks + require an adaptive input to the process and attack the unknown + + + +Schaad, et al. Standards Track [Page 47] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + content of a message based on the length of the compressed output. + This means that no attack on the encryption key is necessarily + required. + + A recent paper on S/MIME and OpenPGP email security [Efail] has + pointed out a number of problems with the current S/MIME + specifications and how people have implemented mail clients. Due to + the nature of how CBC mode operates, the modes allow for malleability + of plaintexts. This malleability allows for attackers to make + changes in the ciphertext and, if parts of the plaintext are known, + create arbitrary blocks of plaintext. These changes can be made + without the weak integrity check in CBC mode being triggered. This + type of attack can be prevented by the use of an Authenticated + Encryption with Associated Data (AEAD) algorithm with a more robust + integrity check on the decryption process. It is therefore + recommended that mail systems migrate to using AES-GCM as quickly as + possible and that the decrypted content not be acted on prior to + finishing the integrity check. + + The other attack that is highlighted in [Efail] is due to an error in + how mail clients deal with HTML and multipart/mixed messages. + Clients MUST require that a text/html content type be a complete HTML + document (per [RFC1866]). Clients SHOULD treat each of the different + pieces of the multipart/mixed construct as being of different + origins. Clients MUST treat each encrypted or signed piece of a MIME + message as being of different origins both from unprotected content + and from each other. + +7. References + +7.1. Reference Conventions + + [ASN.1] refers to [X.680], [X.681], [X.682], and [X.683]. + + [CMS] refers to [RFC5083] and [RFC5652]. + + [ESS] refers to [RFC2634] and [RFC5035]. + + [MIME-SPEC] refers to [RFC2045], [RFC2046], [RFC2047], [RFC2049], + [RFC6838], and [RFC4289]. + + [SMIMEv2] refers to [RFC2311], [RFC2312], [RFC2313], [RFC2314], and + [RFC2315]. + + [SMIMEv3] refers to [RFC2630], [RFC2631], [RFC2632], [RFC2633], + [RFC2634], and [RFC5035]. + + + + + +Schaad, et al. Standards Track [Page 48] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [SMIMEv3.1] refers to [RFC2634], [RFC5035], [RFC5652], [RFC5750], and + [RFC5751]. + + [SMIMEv3.2] refers to [RFC2634], [RFC3850], [RFC3851], [RFC3852], and + [RFC5035]. + + [SMIMEv4] refers to [RFC2634], [RFC5035], [RFC5652], [RFC8550], and + this document. + +7.2. Normative References + + [CHARSETS] IANA, "Character sets assigned by IANA", + . + + [FIPS186-4] + National Institute of Standards and Technology (NIST), + "Digital Signature Standard (DSS)", Federal Information + Processing Standards Publication 186-4, + DOI 10.6028/NIST.FIPS.186-4, July 2013, + . + + [RFC1847] Galvin, J., Murphy, S., Crocker, S., and N. Freed, + "Security Multiparts for MIME: Multipart/Signed and + Multipart/Encrypted", RFC 1847, DOI 10.17487/RFC1847, + October 1995, . + + [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part One: Format of Internet Message + Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996, + . + + [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types", RFC 2046, + DOI 10.17487/RFC2046, November 1996, + . + + [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions) + Part Three: Message Header Extensions for Non-ASCII Text", + RFC 2047, DOI 10.17487/RFC2047, November 1996, + . + + [RFC2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Five: Conformance Criteria and + Examples", RFC 2049, DOI 10.17487/RFC2049, November 1996, + . + + + + + +Schaad, et al. Standards Track [Page 49] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, + DOI 10.17487/RFC2119, March 1997, + . + + [RFC2183] Troost, R., Dorner, S., and K. Moore, Ed., "Communicating + Presentation Information in Internet Messages: The + Content-Disposition Header Field", RFC 2183, + DOI 10.17487/RFC2183, August 1997, + . + + [RFC2634] Hoffman, P., Ed., "Enhanced Security Services for S/MIME", + RFC 2634, DOI 10.17487/RFC2634, June 1999, + . + + [RFC3274] Gutmann, P., "Compressed Data Content Type for + Cryptographic Message Syntax (CMS)", RFC 3274, + DOI 10.17487/RFC3274, June 2002, + . + + [RFC3370] Housley, R., "Cryptographic Message Syntax (CMS) + Algorithms", RFC 3370, DOI 10.17487/RFC3370, August 2002, + . + + [RFC3560] Housley, R., "Use of the RSAES-OAEP Key Transport + Algorithm in Cryptographic Message Syntax (CMS)", + RFC 3560, DOI 10.17487/RFC3560, July 2003, + . + + [RFC3565] Schaad, J., "Use of the Advanced Encryption Standard (AES) + Encryption Algorithm in Cryptographic Message Syntax + (CMS)", RFC 3565, DOI 10.17487/RFC3565, July 2003, + . + + [RFC4289] Freed, N. and J. Klensin, "Multipurpose Internet Mail + Extensions (MIME) Part Four: Registration Procedures", + BCP 13, RFC 4289, DOI 10.17487/RFC4289, December 2005, + . + + [RFC4056] Schaad, J., "Use of the RSASSA-PSS Signature Algorithm in + Cryptographic Message Syntax (CMS)", RFC 4056, + DOI 10.17487/RFC4056, June 2005, + . + + [RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, + "Randomness Requirements for Security", BCP 106, RFC 4086, + DOI 10.17487/RFC4086, June 2005, + . + + + +Schaad, et al. Standards Track [Page 50] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [RFC5083] Housley, R., "Cryptographic Message Syntax (CMS) + Authenticated-Enveloped-Data Content Type", RFC 5083, + DOI 10.17487/RFC5083, November 2007, + . + + [RFC5084] Housley, R., "Using AES-CCM and AES-GCM Authenticated + Encryption in the Cryptographic Message Syntax (CMS)", + RFC 5084, DOI 10.17487/RFC5084, November 2007, + . + + [RFC5652] Housley, R., "Cryptographic Message Syntax (CMS)", STD 70, + RFC 5652, DOI 10.17487/RFC5652, September 2009, + . + + [RFC5753] Turner, S. and D. Brown, "Use of Elliptic Curve + Cryptography (ECC) Algorithms in Cryptographic Message + Syntax (CMS)", RFC 5753, DOI 10.17487/RFC5753, + January 2010, . + + [RFC5754] Turner, S., "Using SHA2 Algorithms with Cryptographic + Message Syntax", RFC 5754, DOI 10.17487/RFC5754, + January 2010, . + + [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type + Specifications and Registration Procedures", BCP 13, + RFC 6838, DOI 10.17487/RFC6838, January 2013, + . + + [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC + 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, + May 2017, . + + [RFC8418] Housley, R., "Use of the Elliptic Curve Diffie-Hellman Key + Agreement Algorithm with X25519 and X448 in the + Cryptographic Message Syntax (CMS)", RFC 8418, + DOI 10.17487/RFC8418, August 2018, + . + + [RFC8419] Housley, R., "Use of Edwards-Curve Digital Signature + Algorithm (EdDSA) Signatures in the Cryptographic Message + Syntax (CMS)", RFC 8419, DOI 10.17487/RFC8419, + August 2018, . + + [RFC8550] Schaad, J., Ramsdell, B., and S. Turner, + "Secure/Multipurpose Internet Mail Extensions (S/MIME) + Version 4.0 Certificate Handling", RFC 8550, + DOI 10.17487/RFC8550, April 2019, + . + + + +Schaad, et al. Standards Track [Page 51] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [X.680] "Information Technology - Abstract Syntax Notation One + (ASN.1): Specification of basic notation", ITU-T + Recommendation X.680, ISO/IEC 8824-1:2015, August 2015, + . + + [X.681] "Information Technology - Abstract Syntax Notation One + (ASN.1): Information object specification", ITU-T + Recommendation X.681, ISO/IEC 8824-2:2015, August 2015, + . + + [X.682] "Information Technology - Abstract Syntax Notation One + (ASN.1): Constraint specification", ITU-T + Recommendation X.682, ISO/IEC 8824-3:2015, August 2015, + . + + [X.683] "Information Technology - Abstract Syntax Notation One + (ASN.1): Parameterization of ASN.1 specifications", ITU-T + Recommendation X.683, ISO/IEC 8824-4:2015, August 2015, + . + + [X.690] "Information Technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), Canonical + Encoding Rules (CER) and Distinguished Encoding Rules + (DER)", ITU-T Recommendation X.690, ISO/IEC 8825-1:2015, + August 2015, . + +7.3. Informative References + + [Efail] Poddebniak, D., Dresen, C., Muller, J., Ising, F., + Schinzel, S., Friedberger, S., Somorovsky, J., and J. + Schwenk, "Efail: Breaking S/MIME and OpenPGP Email + Encryption using Exfiltration Channels", + UsenixSecurity 2018, August 2018, + . + + [FIPS186-2] + National Institute of Standards and Technology (NIST), + "Digital Signature Standard (DSS) (also with Change + Notice 1)", Federal Information Processing Standards + Publication 186-2, January 2000, + . + + [RFC1866] Berners-Lee, T. and D. Connolly, "Hypertext Markup + Language - 2.0", RFC 1866, DOI 10.17487/RFC1866, + November 1995, . + + + + +Schaad, et al. Standards Track [Page 52] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [RFC2268] Rivest, R., "A Description of the RC2(r) Encryption + Algorithm", RFC 2268, DOI 10.17487/RFC2268, March 1998, + . + + [RFC2311] Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L., and + L. Repka, "S/MIME Version 2 Message Specification", + RFC 2311, DOI 10.17487/RFC2311, March 1998, + . + + [RFC2312] Dusse, S., Hoffman, P., Ramsdell, B., and J. Weinstein, + "S/MIME Version 2 Certificate Handling", RFC 2312, DOI + 10.17487/RFC2312, March 1998, + . + + [RFC2313] Kaliski, B., "PKCS #1: RSA Encryption Version 1.5", + RFC 2313, DOI 10.17487/RFC2313, March 1998, + . + + [RFC2314] Kaliski, B., "PKCS #10: Certification Request Syntax + Version 1.5", RFC 2314, DOI 10.17487/RFC2314, March 1998, + . + + [RFC2315] Kaliski, B., "PKCS #7: Cryptographic Message Syntax + Version 1.5", RFC 2315, DOI 10.17487/RFC2315, March 1998, + . + + [RFC2630] Housley, R., "Cryptographic Message Syntax", RFC 2630, + DOI 10.17487/RFC2630, June 1999, + . + + [RFC2631] Rescorla, E., "Diffie-Hellman Key Agreement Method", + RFC 2631, DOI 10.17487/RFC2631, June 1999, + . + + [RFC2632] Ramsdell, B., Ed., "S/MIME Version 3 Certificate + Handling", RFC 2632, DOI 10.17487/RFC2632, June 1999, + . + + [RFC2633] Ramsdell, B., Ed., "S/MIME Version 3 Message + Specification", RFC 2633, DOI 10.17487/RFC2633, June 1999, + . + + [RFC2785] Zuccherato, R., "Methods for Avoiding the "Small-Subgroup" + Attacks on the Diffie-Hellman Key Agreement Method for + S/MIME", RFC 2785, DOI 10.17487/RFC2785, March 2000, + . + + + + + +Schaad, et al. Standards Track [Page 53] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [RFC3218] Rescorla, E., "Preventing the Million Message Attack on + Cryptographic Message Syntax", RFC 3218, + DOI 10.17487/RFC3218, January 2002, + . + + [RFC3766] Orman, H. and P. Hoffman, "Determining Strengths For + Public Keys Used For Exchanging Symmetric Keys", BCP 86, + RFC 3766, DOI 10.17487/RFC3766, April 2004, + . + + [RFC3850] Ramsdell, B., Ed., "Secure/Multipurpose Internet Mail + Extensions (S/MIME) Version 3.1 Certificate Handling", + RFC 3850, DOI 10.17487/RFC3850, July 2004, + . + + [RFC3851] Ramsdell, B., Ed., "Secure/Multipurpose Internet Mail + Extensions (S/MIME) Version 3.1 Message Specification", + RFC 3851, DOI 10.17487/RFC3851, July 2004, + . + + [RFC3852] Housley, R., "Cryptographic Message Syntax (CMS)", + RFC 3852, DOI 10.17487/RFC3852, July 2004, + . + + [RFC4134] Hoffman, P., Ed., "Examples of S/MIME Messages", RFC 4134, + DOI 10.17487/RFC4134, July 2005, + . + + [RFC4270] Hoffman, P. and B. Schneier, "Attacks on Cryptographic + Hashes in Internet Protocols", RFC 4270, + DOI 10.17487/RFC4270, November 2005, + . + + [RFC4949] Shirey, R., "Internet Security Glossary, Version 2", + FYI 36, RFC 4949, DOI 10.17487/RFC4949, August 2007, + . + + [RFC5035] Schaad, J., "Enhanced Security Services (ESS) Update: + Adding CertID Algorithm Agility", RFC 5035, DOI + 10.17487/RFC5035, August 2007, + . + + [RFC5750] Ramsdell, B. and S. Turner, "Secure/Multipurpose Internet + Mail Extensions (S/MIME) Version 3.2 Certificate + Handling", RFC 5750, DOI 10.17487/RFC5750, January 2010, + . + + + + + +Schaad, et al. Standards Track [Page 54] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [RFC5751] Ramsdell, B. and S. Turner, "Secure/Multipurpose Internet + Mail Extensions (S/MIME) Version 3.2 Message + Specification", RFC 5751, DOI 10.17487/RFC5751, + January 2010, . + + [RFC6151] Turner, S. and L. Chen, "Updated Security Considerations + for the MD5 Message-Digest and the HMAC-MD5 Algorithms", + RFC 6151, DOI 10.17487/RFC6151, March 2011, + . + + [RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, "Security + Considerations for the SHA-0 and SHA-1 Message-Digest + Algorithms", RFC 6194, DOI 10.17487/RFC6194, March 2011, + . + + [RFC6268] Schaad, J. and S. Turner, "Additional New ASN.1 Modules + for the Cryptographic Message Syntax (CMS) and the Public + Key Infrastructure Using X.509 (PKIX)", RFC 6268, + DOI 10.17487/RFC6268, July 2011, + . + + [RFC6278] Herzog, J. and R. Khazan, "Use of Static-Static Elliptic + Curve Diffie-Hellman Key Agreement in Cryptographic + Message Syntax", RFC 6278, DOI 10.17487/RFC6278, + June 2011, . + + [RFC7114] Leiba, B., "Creation of a Registry for smime-type + Parameter Values", RFC 7114, DOI 10.17487/RFC7114, + January 2014, . + + [RFC7905] Langley, A., Chang, W., Mavrogiannopoulos, N., + Strombergson, J., and S. Josefsson, "ChaCha20-Poly1305 + Cipher Suites for Transport Layer Security (TLS)", + RFC 7905, DOI 10.17487/RFC7905, June 2016, + . + + [SP800-56A] + National Institute of Standards and Technology (NIST), + "Recommendation for Pair-Wise Key Establishment Schemes + Using Discrete Logarithm Cryptography", NIST Special + Publication 800-56A Revision 2, + DOI 10.6028/NIST.SP.800-56Ar2, May 2013, + . + + + + + + + +Schaad, et al. Standards Track [Page 55] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + [SP800-57] National Institute of Standards and Technology (NIST), + "Recommendation for Key Management - Part 1: General", + NIST Special Publication 800-57 Revision 4, + DOI 10.6028/NIST.SP.800-57pt1r4, January 2016, + . + + [TripleDES] + Tuchman, W., "Hellman Presents No Shortcut Solutions to + the DES", IEEE Spectrum v. 16, n. 7, pp. 40-41, + DOI 10.1109/MSPEC.1979.6368160, July 1979. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 56] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +Appendix A. ASN.1 Module + + Note: The ASN.1 module contained herein is unchanged from RFC 5751 + [SMIMEv2] and RFC 3851 [SMIMEv3.1], with the exception of a change to + the preferBinaryInside ASN.1 comment in RFC 3851 [SMIMEv3.1]. If a + module is needed that is compatible with current ASN.1 standards, one + can be found in [RFC6268]. This module uses the 1988 version + of ASN.1. + + SecureMimeMessageV3dot1 + + { iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-9(9) smime(16) modules(0) msg-v3dot1(21) } + + DEFINITIONS IMPLICIT TAGS ::= + + BEGIN + + IMPORTS + + -- Cryptographic Message Syntax [CMS] + SubjectKeyIdentifier, IssuerAndSerialNumber, + RecipientKeyIdentifier + FROM CryptographicMessageSyntax + { iso(1) member-body(2) us(840) rsadsi(113549) + pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2001(14) }; + + -- id-aa is the arc with all new authenticated and unauthenticated + -- attributes produced by the S/MIME Working Group. + + id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} + + -- S/MIME Capabilities provides a method of broadcasting the + -- symmetric capabilities understood. Algorithms SHOULD be ordered + -- by preference and grouped by type. + + smimeCapabilities OBJECT IDENTIFIER ::= {iso(1) member-body(2) + us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 15} + + SMIMECapability ::= SEQUENCE { + capabilityID OBJECT IDENTIFIER, + parameters ANY DEFINED BY capabilityID OPTIONAL } + + SMIMECapabilities ::= SEQUENCE OF SMIMECapability + + -- Encryption Key Preference provides a method of broadcasting the + -- preferred encryption certificate. + + + +Schaad, et al. Standards Track [Page 57] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} + + SMIMEEncryptionKeyPreference ::= CHOICE { + issuerAndSerialNumber [0] IssuerAndSerialNumber, + receipentKeyId [1] RecipientKeyIdentifier, + subjectAltKeyIdentifier [2] SubjectKeyIdentifier + } + + -- "receipentKeyId" is spelled incorrectly but is kept for + -- historical reasons. + + id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + rsadsi(113549) pkcs(1) pkcs-9(9) 16 } + + id-cap OBJECT IDENTIFIER ::= { id-smime 11 } + + -- The preferBinaryInside OID indicates an ability to receive + -- messages with binary encoding inside the CMS wrapper. + -- The preferBinaryInside attribute's value field is ABSENT. + + id-cap-preferBinaryInside OBJECT IDENTIFIER ::= { id-cap 1 } + + -- The following is a list of OIDs to be used with S/MIME v3. + + -- Signature Algorithms Not Found in [RFC3370], [RFC5754], [RFC4056], + -- and [RFC3560] + + -- + -- md2WithRSAEncryption OBJECT IDENTIFIER ::= + -- {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) + -- 2} + + -- + -- Other Signed Attributes + -- + -- signingTime OBJECT IDENTIFIER ::= + -- {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) + -- 5} + -- See [CMS] for a description of how to encode the attribute + -- value. + + SMIMECapabilitiesParametersForRC2CBC ::= INTEGER + -- (RC2 Key Length (number of bits)) + + END + + + + + + +Schaad, et al. Standards Track [Page 58] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +Appendix B. Historic Mail Considerations + + Over the course of updating the S/MIME specifications, the set of + recommended algorithms has been modified each time the documents have + been updated. This means that if a user has historic emails and + their user agent has been updated to only support the current set of + recommended algorithms, some of those old emails will no longer be + accessible. It is strongly suggested that user agents implement some + of the following algorithms for dealing with historic emails. + + This appendix contains a number of references to documents that have + been obsoleted or replaced. This is intentional, as the updated + documents often do not have the same information in them. + +B.1. DigestAlgorithmIdentifier + + The following algorithms have been called out for some level of + support by previous S/MIME specifications: + + - SHA-1 was dropped in [SMIMEv4]. SHA-1 is no longer considered to + be secure, as it is no longer collision resistant. The IETF + statement on SHA-1 can be found in [RFC6194], but it is out of + date relative to the most recent advances. + + - MD5 was dropped in [SMIMEv4]. MD5 is no longer considered to be + secure, as it is no longer collision resistant. Details can be + found in [RFC6151]. + +B.2. Signature Algorithms + + There are a number of problems with validating signatures on + sufficiently historic messages. For this reason, it is strongly + suggested that user agents treat these signatures differently from + those on current messages. These problems include the following: + + - Certification authorities are not required to keep certificates on + a CRL beyond one update after a certificate has expired. This + means that unless CRLs are cached as part of the message it is not + always possible to check to see if a certificate has been revoked. + The same problems exist with Online Certificate Status Protocol + (OCSP) responses, as they may be based on a CRL rather than on the + certificate database. + + + + + + + + + +Schaad, et al. Standards Track [Page 59] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + - RSA and DSA keys of less than 2048 bits are now considered by many + experts to be cryptographically insecure (due to advances in + computing power). Such keys were previously considered secure, so + the processing of historic signed messages will often result in + the use of weak keys. Implementations that wish to support + previous versions of S/MIME or process old messages need to + consider the security risks that result from smaller key sizes + (e.g., spoofed messages) versus the costs of denial of service. + + [SMIMEv3.1] set the lower limit on suggested key sizes for + creating and validation at 1024 bits. Prior to that, the lower + bound on key sizes was 512 bits. + + - Hash functions used to validate signatures on historic messages + may no longer be considered to be secure (see below). While there + are not currently any known practical pre-image or second + pre-image attacks against MD5 or SHA-1, the fact that they are no + longer considered to be collision resistant implies that the + security levels of the signatures are generally considered + suspect. If a message is known to be historic and it has been in + the possession of the client for some time, then it might still be + considered to be secure. + + - The previous two issues apply to the certificates used to validate + the binding of the public key to the identity that signed the + message as well. + + The following algorithms have been called out for some level of + support by previous S/MIME specifications: + + - RSA with MD5 was dropped in [SMIMEv4]. MD5 is no longer + considered to be secure, as it is no longer collision resistant. + Details can be found in [RFC6151]. + + - RSA and DSA with SHA-1 were dropped in [SMIMEv4]. SHA-1 is no + longer considered to be secure, as it is no longer collision + resistant. The IETF statement on SHA-1 can be found in [RFC6194], + but it is out of date relative to the most recent advances. + + - DSA with SHA-256 was dropped in [SMIMEv4]. DSA has been replaced + by elliptic curve versions. + + + + + + + + + + +Schaad, et al. Standards Track [Page 60] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + + As requirements for "mandatory to implement" have changed over time, + some issues have been created that can cause interoperability + problems: + + - S/MIME v2 clients are only required to verify digital signatures + using the rsaEncryption algorithm with SHA-1 or MD5 and might not + implement id-dsa-with-sha1 or id-dsa at all. + + - S/MIME v3 clients might only implement signing or signature + verification using id-dsa-with-sha1 and might also use id-dsa as + an AlgorithmIdentifier in this field. + + - Note that S/MIME v3.1 clients support verifying id-dsa-with-sha1 + and rsaEncryption and might not implement sha256WithRSAEncryption. + + NOTE: Receiving clients SHOULD recognize id-dsa as equivalent to + id-dsa-with-sha1. + + For 512-bit RSA with SHA-1, see [RFC3370] and [FIPS186-2] without + Change Notice 1; for 512-bit RSA with SHA-256, see [RFC5754] and + [FIPS186-2] without Change Notice 1; and for 1024-bit through + 2048-bit RSA with SHA-256, see [RFC5754] and [FIPS186-2] with Change + Notice 1. The first reference provides the signature algorithm's + OID, and the second provides the signature algorithm's definition. + + For 512-bit DSA with SHA-1, see [RFC3370] and [FIPS186-2] without + Change Notice 1; for 512-bit DSA with SHA-256, see [RFC5754] and + [FIPS186-2] without Change Notice 1; for 1024-bit DSA with SHA-1, see + [RFC3370] and [FIPS186-2] with Change Notice 1; and for 1024-bit and + above DSA with SHA-256, see [RFC5754] and [FIPS186-4]. The first + reference provides the signature algorithm's OID, and the second + provides the signature algorithm's definition. + +B.3. ContentEncryptionAlgorithmIdentifier + + The following algorithms have been called out for some level of + support by previous S/MIME specifications: + + - RC2/40 [RFC2268] was dropped in [SMIMEv3.2]. The algorithm is + known to be insecure and, if supported, should only be used to + decrypt existing email. + + - DES EDE3 CBC [TripleDES], also known as "tripleDES", was dropped + in [SMIMEv4]. This algorithm is removed from the list of + supported algorithms because (1) it has a 64-bit block size and + (2) it offers less than 128 bits of security. This algorithm + should be supported only to decrypt existing email; it should not + be used to encrypt new emails. + + + +Schaad, et al. Standards Track [Page 61] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +B.4. KeyEncryptionAlgorithmIdentifier + + The following algorithms have been called out for some level of + support by previous S/MIME specifications: + + - DH ephemeral-static mode, as specified in [RFC3370] and + [SP800-57], was dropped in [SMIMEv4]. + + - RSA key sizes have been increased over time. Decrypting old mail + with smaller key sizes is reasonable; however, new mail should use + the updated key sizes. + + For 1024-bit DH, see [RFC3370]. For 1024-bit and larger DH, see + [SP800-56A]; regardless, use the KDF, which is from X9.42, specified + in [RFC3370]. + +Appendix C. Moving S/MIME v2 Message Specification to Historic Status + + The S/MIME v3 [SMIMEv3], v3.1 [SMIMEv3.1], and v3.2 [SMIMEv3.2] + specifications are backward compatible with the S/MIME v2 Message + Specification [SMIMEv2], with the exception of the algorithms + (dropped RC2/40 requirement and added DSA and RSASSA-PSS + requirements). Therefore, RFC 2311 [SMIMEv2] was moved to Historic + status. + +Acknowledgements + + Many thanks go out to the other authors of the S/MIME version 2 + Message Specification RFC: Steve Dusse, Paul Hoffman, Laurence + Lundblade, and Lisa Repka. Without v2, there wouldn't be a v3, v3.1, + v3.2, or v4.0. + + Some of the examples in this document were copied from [RFC4134]. + Thanks go to the people who wrote and verified the examples in that + document. + + A number of the members of the S/MIME Working Group have also worked + very hard and contributed to this document. Any list of people is + doomed to omission, and for that I apologize. In alphabetical order, + the following people stand out in my mind because they made direct + contributions to this document: + + Tony Capel, Piers Chivers, Dave Crocker, Bill Flanigan, Peter + Gutmann, Alfred Hoenes, Paul Hoffman, Russ Housley, William Ottaway, + and John Pawling. + + The version 4 update to the S/MIME documents was done under the + auspices of the LAMPS Working Group. + + + +Schaad, et al. Standards Track [Page 62] + +RFC 8551 S/MIME 4.0 Message Specification April 2019 + + +Authors' Addresses + + Jim Schaad + August Cellars + + Email: ietf@augustcellars.com + + + Blake Ramsdell + Brute Squad Labs, Inc. + + Email: blaker@gmail.com + + + Sean Turner + sn3rd + + Email: sean@sn3rd.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Schaad, et al. Standards Track [Page 63] + diff --git a/samples/DkimVerifier/DkimVerifier.sln b/samples/DkimVerifier/DkimVerifier.sln index 940213cb8e..0a7ddc76c2 100644 --- a/samples/DkimVerifier/DkimVerifier.sln +++ b/samples/DkimVerifier/DkimVerifier.sln @@ -1,17 +1,24 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DkimVerifier", "DkimVerifier\DkimVerifier.csproj", "{0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Debug|x86.ActiveCfg = Debug|x86 - {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Debug|x86.Build.0 = Debug|x86 - {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Release|x86.ActiveCfg = Release|x86 - {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Release|x86.Build.0 = Release|x86 + {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {469B0A01-06AE-4F83-9EF7-CC8053651B75} EndGlobalSection EndGlobal diff --git a/samples/DkimVerifier/DkimVerifier/DkimVerifier.csproj b/samples/DkimVerifier/DkimVerifier/DkimVerifier.csproj index 222d2364d8..ae732ff000 100644 --- a/samples/DkimVerifier/DkimVerifier/DkimVerifier.csproj +++ b/samples/DkimVerifier/DkimVerifier/DkimVerifier.csproj @@ -2,54 +2,47 @@ Debug - x86 + AnyCPU {0871D5C3-BDF0-4FFF-9E2A-F94D49F4A382} Exe DkimVerifier DkimVerifier v4.5 + 7.3 - + + AnyCPU true full - false - bin\Debug + bin\Debug\ DEBUG; prompt - 4 - true - x86 + MinimumRecommendedRules.ruleset - + + AnyCPU + bin\Release\ true - bin\Release prompt - 4 - true - x86 + MinimumRecommendedRules.ruleset - - ..\packages\MimeKit.2.0.1\lib\net45\MimeKit.dll - - - ..\packages\Heijden.Dns.2.0.0\lib\net35\Heijden.Dns.dll - - - ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll - + + + + - + - \ No newline at end of file + diff --git a/samples/DkimVerifier/DkimVerifier/Program.cs b/samples/DkimVerifier/DkimVerifier/Program.cs index 81cff1ccb6..c0fc452ecc 100644 --- a/samples/DkimVerifier/DkimVerifier/Program.cs +++ b/samples/DkimVerifier/DkimVerifier/Program.cs @@ -8,14 +8,13 @@ using Heijden.DNS; using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.OpenSsl; using MimeKit; using MimeKit.Cryptography; -namespace DkimVerifier +namespace DkimVerifierExample { - class DkimPublicKeyLocator : IDkimPublicKeyLocator + class DkimPublicKeyLocator : DkimPublicKeyLocatorBase { readonly Dictionary cache; readonly Resolver resolver; @@ -51,69 +50,14 @@ AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationTo } var txt = builder.ToString (); - string k = null, p = null; - int index = 0; - // parse the response (will look something like: "k=rsa; p=") - while (index < txt.Length) { - while (index < txt.Length && char.IsWhiteSpace (txt[index])) - index++; + pubkey = GetPublicKey (txt); + cache.Add (query, pubkey); - if (index == txt.Length) - break; - - // find the end of the key - int startIndex = index; - while (index < txt.Length && txt[index] != '=') - index++; - - if (index == txt.Length) - break; - - var key = txt.Substring (startIndex, index - startIndex); - - // skip over the '=' - index++; - - // find the end of the value - startIndex = index; - while (index < txt.Length && txt[index] != ';') - index++; - - var value = txt.Substring (startIndex, index - startIndex); - - switch (key) { - case "k": k = value; break; - case "p": p = value; break; - } - - // skip over the ';' - index++; - } - - if (k != null && p != null) { - var data = "-----BEGIN PUBLIC KEY-----\r\n" + p + "\r\n-----END PUBLIC KEY-----\r\n"; - var rawData = Encoding.ASCII.GetBytes (data); - - using (var stream = new MemoryStream (rawData, false)) { - using (var reader = new StreamReader (stream)) { - var pem = new PemReader (reader); - - pubkey = pem.ReadObject () as AsymmetricKeyParameter; - - if (pubkey != null) { - cache.Add (query, pubkey); - - return pubkey; - } - } - } - } - - throw new Exception (string.Format ("Failed to look up public key for: {0}", domain)); + return pubkey; } - public AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + public override AsymmetricKeyParameter LocatePublicKey (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) { var methodList = methods.Split (new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < methodList.Length; i++) { @@ -124,7 +68,7 @@ AsymmetricKeyParameter DnsLookup (string domain, string selector, CancellationTo throw new NotSupportedException (string.Format ("{0} does not include any suported lookup methods.", methods)); } - public Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) + public override Task LocatePublicKeyAsync (string methods, string domain, string selector, CancellationToken cancellationToken = default (CancellationToken)) { throw new NotImplementedException ("Asynchronous DKIM public key lookup is not implemented in this sample."); } @@ -147,6 +91,10 @@ public static void Main (string[] args) } var locator = new DkimPublicKeyLocator (); + var verifier = new DkimVerifier (locator); + + // RSA-SHA1 is disabled by default starting with MimeKit 2.2.0 + verifier.Enable (DkimSignatureAlgorithm.RsaSha1); for (int i = 0; i < args.Length; i++) { if (!File.Exists (args[i])) { @@ -166,7 +114,7 @@ public static void Main (string[] args) var dkim = message.Headers[index]; - if (message.Verify (dkim, locator)) { + if (verifier.Verify (message, dkim)) { // the DKIM-Signature header is valid! Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine ("VALID"); diff --git a/samples/DkimVerifier/DkimVerifier/app.config b/samples/DkimVerifier/DkimVerifier/app.config new file mode 100644 index 0000000000..0cac7f9a1b --- /dev/null +++ b/samples/DkimVerifier/DkimVerifier/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/samples/DkimVerifier/DkimVerifier/packages.config b/samples/DkimVerifier/DkimVerifier/packages.config deleted file mode 100644 index 4f7f950975..0000000000 --- a/samples/DkimVerifier/DkimVerifier/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/samples/MessageReader.Android/MessageReader.Android.sln b/samples/MessageReader.Android/MessageReader.Android.sln index 08cc24fb8d..279d254324 100644 --- a/samples/MessageReader.Android/MessageReader.Android.sln +++ b/samples/MessageReader.Android/MessageReader.Android.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29409.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageReader.Android", "MessageReader.Android\MessageReader.Android.csproj", "{215D2B5C-8D37-4CB1-8196-B30A3ECFE2B6}" EndProject @@ -19,6 +19,9 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {03EAE69B-2102-4CDF-A274-10F2F7E6F9F9} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = MessageReader.Android\MessageReader.Android.csproj EndGlobalSection diff --git a/samples/MessageReader.Android/MessageReader.Android/HtmlPreviewVisitor.cs b/samples/MessageReader.Android/MessageReader.Android/HtmlPreviewVisitor.cs index 5786da4580..e10aa04e1a 100644 --- a/samples/MessageReader.Android/MessageReader.Android/HtmlPreviewVisitor.cs +++ b/samples/MessageReader.Android/MessageReader.Android/HtmlPreviewVisitor.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -117,9 +117,8 @@ protected override void VisitTextPart (TextPart entity) }; } else if (entity.IsFlowed) { var flowed = new FlowedToHtml (); - string delsp; - if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp)) + if (entity.ContentType.Parameters.TryGetValue ("delsp", out string delsp)) flowed.DeleteSpace = delsp.ToLowerInvariant () == "yes"; converter = flowed; diff --git a/samples/MessageReader.Android/MessageReader.Android/MainActivity.cs b/samples/MessageReader.Android/MessageReader.Android/MainActivity.cs index 342099b38c..e65c35de64 100644 --- a/samples/MessageReader.Android/MessageReader.Android/MainActivity.cs +++ b/samples/MessageReader.Android/MessageReader.Android/MainActivity.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/samples/MessageReader.Android/MessageReader.Android/MessageReader.Android.csproj b/samples/MessageReader.Android/MessageReader.Android/MessageReader.Android.csproj index a7161af351..e81e6499c8 100644 --- a/samples/MessageReader.Android/MessageReader.Android/MessageReader.Android.csproj +++ b/samples/MessageReader.Android/MessageReader.Android/MessageReader.Android.csproj @@ -15,8 +15,8 @@ False MessageReader.Android Properties\AndroidManifest.xml - v5.0 - armeabi,armeabi-v7a,x86 + v9.0 + armeabi-v7a,x86 @@ -30,9 +30,9 @@ 4 None false - True + true - True + true CJK,Mideast,Rare,West,Other Xamarin @@ -55,12 +55,6 @@ False - - ..\packages\MimeKit.2.0.1\lib\monoandroid\BouncyCastle.dll - - - ..\packages\MimeKit.2.0.1\lib\monoandroid\MimeKit.dll - @@ -68,6 +62,9 @@ + + + @@ -77,7 +74,6 @@ - @@ -93,4 +89,4 @@ xamarin3.msg - \ No newline at end of file + diff --git a/samples/MessageReader.Android/MessageReader.Android/MultipartRelatedWebViewClient.cs b/samples/MessageReader.Android/MessageReader.Android/MultipartRelatedWebViewClient.cs index c5270622dd..b142d77174 100644 --- a/samples/MessageReader.Android/MessageReader.Android/MultipartRelatedWebViewClient.cs +++ b/samples/MessageReader.Android/MessageReader.Android/MultipartRelatedWebViewClient.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -59,9 +59,7 @@ public override WebResourceResponse ShouldInterceptRequest (WebView view, IWebRe if ((index = related.IndexOf (uri)) == -1) continue; - var part = related[index] as MimePart; - - if (part != null) { + if (related[index] is MimePart part) { var mimeType = part.ContentType.MimeType; var charset = part.ContentType.Charset; var stream = part.Content.Open (); diff --git a/samples/MessageReader.Android/MessageReader.Android/Properties/AndroidManifest.xml b/samples/MessageReader.Android/MessageReader.Android/Properties/AndroidManifest.xml index d11acbfb37..f4f6ef74d9 100644 --- a/samples/MessageReader.Android/MessageReader.Android/Properties/AndroidManifest.xml +++ b/samples/MessageReader.Android/MessageReader.Android/Properties/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/samples/MessageReader.Android/MessageReader.Android/Resources/Resource.designer.cs b/samples/MessageReader.Android/MessageReader.Android/Resources/Resource.designer.cs index 0b3d5c5caf..a2353c9a24 100644 --- a/samples/MessageReader.Android/MessageReader.Android/Resources/Resource.designer.cs +++ b/samples/MessageReader.Android/MessageReader.Android/Resources/Resource.designer.cs @@ -2,7 +2,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -15,7 +14,7 @@ namespace MessageReader.Android { - [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] public partial class Resource { @@ -44,8 +43,8 @@ private Attribute() public partial class Drawable { - // aapt resource value: 0x7f020000 - public const int Icon = 2130837504; + // aapt resource value: 0x7F010000 + public const int Icon = 2130771968; static Drawable() { @@ -60,8 +59,8 @@ private Drawable() public partial class Id { - // aapt resource value: 0x7f050000 - public const int webView = 2131034112; + // aapt resource value: 0x7F020000 + public const int webView = 2130837504; static Id() { @@ -76,7 +75,7 @@ private Id() public partial class Layout { - // aapt resource value: 0x7f030000 + // aapt resource value: 0x7F030000 public const int Main = 2130903040; static Layout() @@ -92,11 +91,11 @@ private Layout() public partial class String { - // aapt resource value: 0x7f040001 - public const int app_name = 2130968577; + // aapt resource value: 0x7F040000 + public const int app_name = 2130968576; - // aapt resource value: 0x7f040000 - public const int hello = 2130968576; + // aapt resource value: 0x7F040001 + public const int hello = 2130968577; static String() { diff --git a/samples/MessageReader.Android/MessageReader.Android/packages.config b/samples/MessageReader.Android/MessageReader.Android/packages.config deleted file mode 100644 index 242eec6576..0000000000 --- a/samples/MessageReader.Android/MessageReader.Android/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/samples/MessageReader.iOS/MessageReader.iOS.sln b/samples/MessageReader.iOS/MessageReader.iOS.sln index 5b4467314e..8403f69a47 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS.sln +++ b/samples/MessageReader.iOS/MessageReader.iOS.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26403.3 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29409.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageReader.iOS", "MessageReader.iOS\MessageReader.iOS.csproj", "{60EA692F-305A-4CF7-97A8-3565CC81310A}" EndProject @@ -33,6 +33,9 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3689B0D3-C33B-4BE1-A7BD-A5DEBFB67496} + EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = MessageReader.iOS\MessageReader.iOS.csproj EndGlobalSection diff --git a/samples/MessageReader.iOS/MessageReader.iOS/AppDelegate.cs b/samples/MessageReader.iOS/MessageReader.iOS/AppDelegate.cs index 233e196905..9315fc52f9 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/AppDelegate.cs +++ b/samples/MessageReader.iOS/MessageReader.iOS/AppDelegate.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/samples/MessageReader.iOS/MessageReader.iOS/HtmlPreviewVisitor.cs b/samples/MessageReader.iOS/MessageReader.iOS/HtmlPreviewVisitor.cs index 761033cacb..6eaf9482cb 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/HtmlPreviewVisitor.cs +++ b/samples/MessageReader.iOS/MessageReader.iOS/HtmlPreviewVisitor.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -117,9 +117,8 @@ protected override void VisitTextPart (TextPart entity) }; } else if (entity.IsFlowed) { var flowed = new FlowedToHtml (); - string delsp; - if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp)) + if (entity.ContentType.Parameters.TryGetValue ("delsp", out string delsp)) flowed.DeleteSpace = delsp.ToLowerInvariant () == "yes"; converter = flowed; diff --git a/samples/MessageReader.iOS/MessageReader.iOS/Main.cs b/samples/MessageReader.iOS/MessageReader.iOS/Main.cs index 683d25e588..c14469d6a7 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/Main.cs +++ b/samples/MessageReader.iOS/MessageReader.iOS/Main.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/samples/MessageReader.iOS/MessageReader.iOS/MessageReader.iOS.csproj b/samples/MessageReader.iOS/MessageReader.iOS/MessageReader.iOS.csproj index 3a091c7f28..7d54d37ff3 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/MessageReader.iOS.csproj +++ b/samples/MessageReader.iOS/MessageReader.iOS/MessageReader.iOS.csproj @@ -67,12 +67,6 @@ Default - - ..\packages\MimeKit.2.0.1\lib\xamarinios\BouncyCastle.dll - - - ..\packages\MimeKit.2.0.1\lib\xamarinios\MimeKit.dll - @@ -80,13 +74,15 @@ + + + - @@ -107,4 +103,4 @@ xamarin3.msg - \ No newline at end of file + diff --git a/samples/MessageReader.iOS/MessageReader.iOS/MessageReaderViewController.cs b/samples/MessageReader.iOS/MessageReader.iOS/MessageReaderViewController.cs index 823f5b65f1..bcd1edba2f 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/MessageReaderViewController.cs +++ b/samples/MessageReader.iOS/MessageReader.iOS/MessageReaderViewController.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/samples/MessageReader.iOS/MessageReader.iOS/MultipartRelatedUrlCache.cs b/samples/MessageReader.iOS/MessageReader.iOS/MultipartRelatedUrlCache.cs index db90bf1950..c373e82c0f 100644 --- a/samples/MessageReader.iOS/MessageReader.iOS/MultipartRelatedUrlCache.cs +++ b/samples/MessageReader.iOS/MessageReader.iOS/MultipartRelatedUrlCache.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2020 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -59,9 +59,7 @@ public override NSCachedUrlResponse CachedResponseForRequest (NSUrlRequest reque if ((index = related.IndexOf (uri)) == -1) continue; - var part = related[index] as MimePart; - - if (part != null) { + if (related[index] is MimePart part) { var mimeType = part.ContentType.MimeType; var charset = part.ContentType.Charset; NSUrlResponse response; diff --git a/samples/MessageReader.iOS/MessageReader.iOS/packages.config b/samples/MessageReader.iOS/MessageReader.iOS/packages.config deleted file mode 100644 index 47aec25145..0000000000 --- a/samples/MessageReader.iOS/MessageReader.iOS/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/samples/MessageReader/MessageReader.sln b/samples/MessageReader/MessageReader.sln index d64e220940..79ef2c106e 100644 --- a/samples/MessageReader/MessageReader.sln +++ b/samples/MessageReader/MessageReader.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29409.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessageReader", "MessageReader\MessageReader.csproj", "{B9E3F73F-F805-4E5F-AF4D-E483A9AAA890}" EndProject @@ -19,4 +19,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9CFBF477-70C0-42FE-A071-E1E15FF149E4} + EndGlobalSection EndGlobal diff --git a/samples/MessageReader/MessageReader/App.config b/samples/MessageReader/MessageReader/App.config index 8e15646352..2cbdeef832 100644 --- a/samples/MessageReader/MessageReader/App.config +++ b/samples/MessageReader/MessageReader/App.config @@ -1,6 +1,14 @@ - + + + + + + + + + \ No newline at end of file diff --git a/samples/MessageReader/MessageReader/HtmlPreviewVisitor.cs b/samples/MessageReader/MessageReader/HtmlPreviewVisitor.cs index 2355b8699e..6c1827ec00 100644 --- a/samples/MessageReader/MessageReader/HtmlPreviewVisitor.cs +++ b/samples/MessageReader/MessageReader/HtmlPreviewVisitor.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2019 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -137,13 +137,13 @@ string GetDataUri (MimePart attachment) } // Replaces urls that refer to images embedded within the message with - // "file://" urls that the browser control will actually be able to load. + // "data:" urls that the browser control will actually be able to load. void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter) { if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) { ctx.WriteTag (htmlWriter, false); - // replace the src attribute with a file:// URL + // replace the src attribute with a "data:" URL foreach (var attribute in ctx.Attributes) { if (attribute.Id == HtmlAttributeId.Src) { MimePart image; diff --git a/samples/MessageReader/MessageReader/MessageReader.csproj b/samples/MessageReader/MessageReader/MessageReader.csproj index 788979e746..f387472050 100644 --- a/samples/MessageReader/MessageReader/MessageReader.csproj +++ b/samples/MessageReader/MessageReader/MessageReader.csproj @@ -32,13 +32,6 @@ 4 - - ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll - True - - - ..\packages\MimeKit.2.0.1\lib\net45\MimeKit.dll - @@ -52,6 +45,9 @@ + + + Form @@ -73,7 +69,6 @@ True Resources.resx - SettingsSingleFileGenerator Settings.Designer.cs @@ -99,4 +94,4 @@ --> - \ No newline at end of file + diff --git a/samples/MessageReader/MessageReader/MessageViewWindow.cs b/samples/MessageReader/MessageReader/MessageViewWindow.cs index 59ccd830c7..19051821f7 100644 --- a/samples/MessageReader/MessageReader/MessageViewWindow.cs +++ b/samples/MessageReader/MessageReader/MessageViewWindow.cs @@ -3,7 +3,7 @@ // // Author: Jeffrey Stedfast // -// Copyright (c) 2014-2017 Jeffrey Stedfast +// Copyright (c) 2014-2019 Jeffrey Stedfast // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/samples/MessageReader/MessageReader/packages.config b/samples/MessageReader/MessageReader/packages.config deleted file mode 100644 index 4f53df1153..0000000000 --- a/samples/MessageReader/MessageReader/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/submodules/Portable.Text.Encoding b/submodules/Portable.Text.Encoding deleted file mode 160000 index 74147c65ff..0000000000 --- a/submodules/Portable.Text.Encoding +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 74147c65fff30b872ea585fccf2c384b8d708353 diff --git a/submodules/bc-csharp b/submodules/bc-csharp deleted file mode 160000 index b19e68a517..0000000000 --- a/submodules/bc-csharp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b19e68a517e56ef08cd2e50df4dcb8a96ddbe507