pax_global_header00006660000000000000000000000064121443406160014513gustar00rootroot0000000000000052 comment=a2756162bcdd0e16eaf3ac88f51c2f9740cb4d24 mail-2.5.4/000077500000000000000000000000001214434061600124455ustar00rootroot00000000000000mail-2.5.4/.gitignore000066400000000000000000000002511214434061600144330ustar00rootroot00000000000000/.bundle /.ruby-version /.rvmrc /bin /coverage /Gemfile.lock /gems /mail-*.gem /mail.tmproj /rdoc /spec/fixtures/emails/failed_emails/ /tags /tmp *.rbc *.swp .idea .rbx mail-2.5.4/.travis.yml000066400000000000000000000006141214434061600145570ustar00rootroot00000000000000language: ruby rvm: - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 - ruby-head - jruby-18mode - jruby-19mode - jruby-head - rbx-18mode - rbx-19mode matrix: allow_failures: - rvm: ruby-head # green, but unstable - rvm: jruby-head # green, but unstable - rvm: rbx-18mode # seems to be running 1.9 mode instead!? - rvm: rbx-19mode # segfaulting in String#ascii_only? mail-2.5.4/CHANGELOG.rdoc000066400000000000000000001130551214434061600146120ustar00rootroot00000000000000== HEAD == Version 2.5.4 - Tue May 14 14:45:00 +1100 2013 Mikel Lindsaar Features: * Save settings passed to TestMailer#new (svanderbleek) * Allow the setting of envelope from directly (jeremy) * Accept other IETF/IANA-registered Content-Types and Content-Transfer-Encodings (jeremy) * Alias shift-jis charset to Shift_JIS Ruby encoding (jeremy) * Add support for ks_c_5601-1987 charset, aliased to CP949 Ruby encoding (jeremy) * Don't allow colons in header names (jeremy) * Can assign arrays of Message-IDs to References and In-Reply-To (jeremy) * Setting the html_ or text_part sets a default text/html or text/plain content type (jeremy) * Setting the html_ or text_part to nil removes it (jeremy) * Addresses without a parsable email or display name still format as their raw text (jeremy) * Close pull request 504 - Alias GB2312 charset to GB18030 Ruby encoding (bpot) * Close pull request 399 - Accept :ca_path and :ca_file options for SMTP delivery (ndbroadbent) * Close pull request 389 - Don't add superfluous message headers to MIME parts (djmaze, jeremy) Performance: * Close pull request 488 - Speed up field construction & comparison (bpot) Bugs: * Don't include separating semicolon in paramter value when sanitizing (bpot) * Fix fencepost encoding problem with binhex strings and only one token (drasch) * Fix sendmail delivery to addresses with a leading hyphen (lifo, jeremy) * Correctly format mbox From headers per RFC4155 (bpot, jeremy) * Fix bogus '=' at the end of some quoted-printable messages (jeremy) * Shouldn't be fooled into encoding strings on 1.8 by unrelated Encoding constant (emiellohr, jeremy) * Header encoding should be US-ASCII, not the default external encoding (jeremy) * Address elements should return decoded display names by default (jeremy) * Fix up tests that depend on utf-8 external encoding; read fixtures as binary (jeremy) * Capture stderr from Sendmail and Exim deliveries (jeremy) * RFC2822 quoted_string content may be empty (jeremy) * Calling #to_s on a field with a nil value returns an empty string instead of nil (jeremy) * The Received header may contain zero name/value pairs, qmail-style (jeremy) * Fix that setting an attachment with a :mime_type and :encoding would override the :encoding (jeremy) * Fix that declaring an html_part but no text_part would use multipart/alternative anyway (jeremy) * Close pull request 508 - Don't add an extra CRLF to MIME parts; split MIME parts on correct CRLF boundaries (Aalanar) * Close pull request 506 - Escape backslashes in quoted strings (ConradIrwin) * Close pull request 496 - Correctly handle quoted-printable line breaks (jeremy) * Close pull request 493 - Repair misencoded quoted-printable line breaks (jeremy) * Close pull request 487 - Extract comments from group email addresses (bpot) * Close pull request 481 - Correctly quote filename attributes (bpot) * Close pull request 480 - Support mixed encodings in a single header body (adamvaughan) * Close pull request 471 - Fix Ruby 1.8 build when UTF16/32 default to little-endian (kennyj) Coping with third-party bugs: * Parse multipart boundary from Content-Type headers containing extra semicolons (jeremy) * Close pull request 389 - Only add Content-ID to inline attachments to appease Outlook (djmaze, jeremy) Housekeeping: * Add development gem dependency on rdoc (jeremy) * Refresh Bundler dependencies & setup (jeremy) * Remove i18n dependency and last vestiges of activesupport dependency in specs (jeremy) * Clarify that Sender is a single address, not an address list (jeremy) * Add an MIT-LICENSE file to make licensing clear & obvious; update to 2013 (jeremy) * Close pull request 501 - Tighten up header/body whitespace splitting (ConradIrwin) * Close pull request 499 - Clean up some dead code (ConradIrwin) * Close pull request 489, 495 - Docs typos (JackDanger, francois) * Close pull request 485 - Be explicit about unsupported address parsing (bpot) * Close pull request 484 - Remove #tree specs in preparation for deprecation removal (bpot) * Close pull request 482 - Update address field specs to reflect to #initialize API (bpot) * Close pull request 475 - Shush warning on Object#blank? redefinition (amatsuda) * Close pull request 472 - Clean up UTF8/UTF-8 internals (kennyj) == Version 2.5.3 - Sun Dec 4 15:52:00 +1100 2012 Mikel Lindsaar * Close pull request 468 - Remove debug output to STDOUT (tadman) * Fix up spec warnings * Remove un needed require * Ensure spec_helper constants only defined once * Use stub against time instead of DateTime to avoid double redefinition error == Version 2.5.2 - Sun Nov 18 15:01:00 +1100 2012 Mikel Lindsaar * Removing double loading of treetop parsers to remove warnings * Making parsers auto compile on spec suite and load in production code to avoid error that caused yank of 2.5.0 * Reapply pull request 443 - CC fields with semicolon are now parsed right (paulwittmann) == Version 2.5.1 - Sun Nov 18 14:01:00 +1100 2012 Mikel Lindsaar * Yanked 2.5.0 * Reverted pull request 443 - CC fields with semicolon are now parsed right (paulwittmann) == Version 2.5.0 - Sun Nov 18 12:20:00 +1100 2012 Mikel Lindsaar Features: * Close pull request 406 - Add Mail#eager_autoload! to load all autoloaded files on demand (bpot) * Close pull request 461 - Allow string as delivery_method (skyeagle, radar) * Close pull request 407 - Do not require Net::IMAP or Net::POP if they're already loaded (bpot) * Close pull request 400 - Raise exception if delivery values or from values are missing completely from an email that is getting delivered (dmathieu) * Close pull request 397 - Support dots in local part of the addresses (eac) * Close pull request 477 - Fixed handling content_type with superfluous spaces (ledermann) * Close pull request 451 - Ignore nil in addresses so things do not blow up when e.g. a user had no email (grosser) * Close pull request 362 - Enable TLS in Ruby 1.8 (kingargyle) * Close pull request 358 - Fix Mail::CommonAddress#value=, Mail::CommonAddress#<< and Mail::Encodings.encode_non_usascii (mrkn) * Close pull request 350 - Makes mail Header object ennumerable (ged) Performance: * Close pull request 369 - Mail::Header#charset is called pretty often during header parser work (bogdan) * Close pull request 368 - Improve existing code by moving some objects to contstant instead of constructing them over and over again. (bogdan) * Close pull request 366 - Headers parsing performance optimization (bogdan) * Close pull request 365 - Add maximum_amount of parsed headers configuration parameter (bogdan) Bugs: * Close pull request 444 - Fix typo in spec (cczona) * Close pull request 439 - Fix Ruby 1.9 behaviour to match 1.8.7 behaviour on ignoring invalid or undefined characters (ochko) * Close pull request 430 - Unstructured field converts to string before calling encoding on it (brupm mikel) * Close pull request 424 - Use String#to_crlf instead of String#gsub (okkez) * Close pull request 429 - Fix an obvious bug in exim delivery_method (dskim) * Close pull request 425 - Remove Gemfile.lock from generated gem (kbackowski) * Close pull request 414 - Fix typo on "ignoring" (derwiki) * Close pull request 405 - Fix stack overflow (RegexpError) triggered by large emails with an envelope (bpot) * Close pull request 402 - Prevent InReplyTo, Keyword, References or ResentMessageId fields from generating lines longer than 998 chars (pplr) * Close pull request 391 - Fixed failed attachment parsing when file name in headers contains spaces and is not wrapped in quotes (danieltreacy) * Close pull request 385 - Fix Multibyte::Chars#upcase/downcase (technoweenie) * Close pull request 384 - copy dat unicode over from active support (technoweenie) * Close pull request 380 - Split strictly on MIME boundary lines (ConradIrwin) * Close pull request 277 - Fix specific email decoding failure example (yalab) * Close pull request 361 - Support 8bit encoding for ruby 1.9 (bogdan) * Close pull request 346 - Fix two bugs of TestRetriever (ermaker) * Close pull request 337 - Make the behavior of value_decode the same between Ruby 1.8 and Ruby 1.9. (kennyj) * Close pull request 336 - Fix more warning: possibly useless use of == in void context (kennyj) * Close pull request 293 - make charset and mime type more resliant to bad header values (kmeehl) * Fix failing spec Issue 453 on Ruby 1.9.3 * Fix mail reading: don't raise invalid byte sequence in UTF-8 when reading non-UTF-8 emails (mreinsch) * Close pull request 353 - define NilClass#blank? only if not defined yet (amatsuda) * Close pull request 357 - Fixes #349 an inverted condition on imap open read_only (felixroeser) * Remove duplicated line feed from regexp * Remove unused variable * Updated IMAP documentation * Tweak publisher == Version 2.4.4 - Wed Mar 14 22:44:00 +1100 2012 Mikel Lindsaar * Fix security vulnerability allowing command line exploit when using file delivery method == Version 2.4.3 - Tue Mar 6 19:38:00 UTC 2012 Mikel Lindsaar * Fix security vulnerability allowing command line exploit when using exim or sendmail from the command line * Change Mail#deliver! to also inform the interceptors * Encodings.value_decode(str): Treat lines with mixed encoding correctly when the line ends with a plain text part. == Version 2.4.1 - Thu Jan 19 13:49:34 UTC 2012 Mikel Lindsaar * Fix non ascii character folding problems * Handle multipart mail in Mail::Message#to_yaml / #from_yaml * More warning fixes * Normalize the Parse Error class and messages * Fix for Mail::Encodings.unquote_and_convert not handling unquoted characters mixed in between quoted strings * Updated treetop to latest version, specs now run approximately 25-30% faster! * Version bump to 2.4.1 and gem release == Version 2.4.0 - Sun Jan 15 18:15:56 UTC 2011 Mikel Lindsaar * Speed up reading of messages by about 12x * Added Message#without_attachments! that removes all message's attachments * Added shoulda-style RSpec matchers * Added support for @ in display name * Added support for the :tls and :ssl options * Added UTF-16 and UTF-32 support * Added Exim as it's own delivery manager * Added Ruby 1.9.3 compatibility * Fix for Sendmail return-path escaping * Fix for alias for SJIS was changed from shift_jis to windows-31J in Ruby 1.9.3 * Fix for undefined method 'constantize' error when no ActiveSupport loaded * Fix Mail::Field#== comparison * Fixed Regexp warning: character class has duplicated range * Fixed encoding non-latin names in addresses * Fixed issue with non-7bit attachment filenames * Now define String#blank? only if not defined yet * Decoding text parts using charset from Content-Type field * Per RFC 5322, do not accept emails with consecutive dots * Bunch of bug fixes from contributed pull requests * Travis CI setup and passing on 6 rubies * Upgrade RSpec to 2.8.0 * Lots of warnings fixed * Version bump to 2.4.0 and gem release == Version 2.3.0 - Tue Apr 26 09:59:56 UTC 2011 Mikel Lindsaar * Remove ActiveSupport from the dependencies, load Active Support if present, or use internals if not * Created v2.2 branch for all 2.2 related commits * Update activesupport require to use inflector - closes #217 * Version bump to 2.3 and gem release == Tue Apr 26 06:18:19 UTC 2011 Mikel Lindsaar * Fixed charset warning issue with multipart messages - https://github.com/arvindsv * Version bump to 2.2.18 and gem release == Wed 20 Apr 2011 15:16:20 UTC Mikel Lindsaar * Mail::Field.new("Subject: foobar", 'iso-2022-jp') does not set charset - https://github.com/yalab == Tue Apr 19 00:20:54 UTC 2011 Mikel Lindsaar * Fixed an exception with nil in Reply-To and References field - https://github.com/dcormier * Version bump to 2.2.17 and gem release == Sat Apr 16 12:57:27 UTC 2011 Mikel Lindsaar * Added support for open SMTP connections and returning the Mail server's response - https://github.com/spiegela * RE: not appended to subject when replying to a reply - https://github.com/prateekdayal * Support not ascii compatible charset mail send - https://github.com/yalab * Fix for issue 208 "mail.body after mail.add_file truncates message body" - https://github.com/glongman * Handle bad subject encoding (or ":invalid => :replace" is ineffective for utf-8 to utf-8 encoding) - https://github.com/choonkeat * Handle blank Received header field - https://github.com/bcantin * Handle part with missing content type - https://github.com/bcantin * Handle a "<>" Return field - https://github.com/bcantin * Performance improvements for 1.9 - https://github.com/nobu * Fix heavy CPU issues when messages are missing a space - https://github.com/scsmith * Tighten up allowed encodings - https://github.com/scsmith * Added to_yaml & from_yaml (as well as to_hash & from_hash) - https://github.com/srushti * Fix up some comments - https://github.com/takahashim * Version bump to 2.2.16 and gem release == Wed 26 Jan 2011 02:23:09 UTC Mikel Lindsaar * Update addresses passed into sendmail to escape them (Andy Lindeman) * Version bump to 2.2.15 and gem release == Mon 3 Jan 2011 12:48:59 UTC Mikel Lindsaar * Update field_spec to handle encodings, closes issues 44 and 120 (Luis Lopez) * Version bump to 2.2.14 and gem release == Mon 3 Jan 2011 00:09:27 UTC Mikel Lindsaar * Use default IANA port on the IMAP retriever_method (Adrian Silva) * Updated README to reflect latest ruby versions we test against (mikel) * Only remove tlsconnect if it exists (mikel) == Thu 23 Dec 2010 09:15:58 UTC Mikel Lindsaar * Added backport fix for net/smtp bug (Aaron Patterson) * Changed "Mail#text_part" so that it does not return a plain text attachment (Anton Mironov) * Added in rescue blocks for badly formatted dates as well as encoding problems (Karl Baum) * Fixed warning errors of duplicated regular expressions (Kouhei Sutou) * Removed duplication from Regex's containing [\w\d]+ as \w contains \d (mikel) * Add authentication selection for imap retriever (Björn Albers) * Removing warning on @name not being initialized (mikel) * Version bump to 2.2.13 and gem release == Fri 10 Dec 2010 09:06:49 UTC Mikel Lindsaar * Fixing problems with multibyte filenamed attachment (amatsuda) * Providing IMAP uid and imap object as options to IMAP calls (dball) * Fixing filename for windows (mikel) == Sun Dec 5 02:24:55 UTC 2010 Mikel Lindsaar * Updating requirement on i18n to be more relaxed for now until we nuke ActiveSupport dependency (Mikel) * Version bump to 2.2.12 and gem release == Tue 30 Nov 2010 00:36:11 UTC Mikel Lindsaar * Allow address lists to handle and ignore empty addresses (Donald Ball) * Allow address lists to handle repeating strings of commas (Donald Ball) * Noting pending test for malformed folding whitespace (Donald Ball) * Adding spec to test error email for missing addresses in to header (Mikel) * Bumping i18n dependency to ~> 0.5.0 * Version bump to 2.2.11 and gem release == Wed 17 Nov 2010 00:43:31 UTC Mikel Lindsaar * Added test retriever and updated documentation (Donald Ball) * Fix test suite to work in any timezone (Donald Ball) * Added dependency for tlsmail for Ruby 1.8.6 (Donald Ball) * Added new feature, replies for mail message * Fix references header to use CFWS instead of comma as the separator per RFC2822 * Version Bum to 2.2.10 and pushed. == Mon Nov 15 13:04:41 UTC 2010 Mikel Lindsaar * Add find_and_delete convenience method for consistency with POP3, document delete_after_find option (Donald Ball) * Documenting the openssl_verify_mode setting (Donald Ball) * Added ruby-1.8.6 back into the list of tested platforms (Donald Ball) * Relax i18n dependency until we remove active support requirement * Version Bump to 2.2.9.1 to include new i18n dependency == Tue Oct 26 07:14:36 UTC 2010 Mikel Lindsaar * Version Bump to 2.2.9 and tag * Updating Gemfile and gemspec to include i18n and sync dependency versions * Added work from Kendall Gifford closing issues #104, #107 and #117 * Always encode mailbox names with UTF-7 (github: fasta) == Tue Oct 26 06:43:17 UTC 2010 Mikel Lindsaar * Added updates from Donald Ball (github: dball) to improve 1.8.6 support * Added patch from Ryan Bigg (github: ryanb) for #mark_for_delete == Thu Oct 7 15:44:31 UTC 2010 Mikel Lindsaar * Version Bump to 2.2.7 * Release 2.2.7 == Thu Oct 7 15:42:57 UTC 2010 Mikel Lindsaar * Added fix for Windows using 'rb' flags, thanks to Luis Lavena and dzhang for pointing it out * Fixed up Rakefile to require bundler to run specs and give more appropriate errors messages if this fails == Tue Sep 28 14:59:03 UTC 2010 Mikel Lindsaar * Merged POP3 delete support work from Michael Prendergast * Merged IMAP support work from Fabian Staubli == Mon Sep 13 02:31:21 UTC 2010 Mikel Lindsaar * Replace some missing documentation * Version bump to 2.2.6.1 == Sat 11 Sep 2010 05:13:36 UTC Mikel Lindsaar * Fixed parsing an email with an empty In-Reply-To header (Reported by Eugene Pimenov) * Adding address spec for groupname+domain.com@example.com format emails * Version bump to 2.2.6 == Sat Sep 11 01:56:59 UTC 2010 Mikel Lindsaar * Added new way to do versioning for rubygems * Added additional specs for Content-Disposition: inline which are not being encoded correctly - Shawn Pyle * Make sure Mail::Message#attachment? returns true/false - Simone Carletti * Replace hard-coded references to Mail with more generic self references to allow easier inheritance (closes #61) - Simone Carletti * Force encoding on Regexp for Ruby 1.9 to avoid encoding conflicts - Golubev Pavel * Added lazy evaluation to message body: body is not parsed until need. It greatly improves performance with big mails if you don't need to read the body (yet) * Added Mail.read_from_string as an explicit method (mcansky) * Fixed bounce detection for multipart reports that contain a human readable report status part * Closed Issue #65 found (incredibly) by quetz - major Kudos for bug hunting * Fixed missing trailing CRLF in content type field - Closes issue #57 - Kudos to Henry Flower for finding it * Version bump to 2.2.5.2 == Sat Sep 11 01:32:13 UTC 2010 Mikel Lindsaar * Closed issue #58 - Content Type not parsing unless lower case. * Version bump to 2.2.5.1 == Thu 17 Jun 2010 22:13:18 UTC Mikel Lindsaar * Added Mail::POP3.delete_all, including specs (Martijn Storck) * Lars Pind updates on header folding * Version bump to 2.2.5 == Tue Jun 8 01:55:21 UTC 2010 Mikel Lindsaar * Added inline attachment support to mail (mikel) == Mon Jun 7 18:00:39 UTC 2010 Mikel Lindsaar * Updating versioning so we only have one source, VERSION.yml (mikel) * Changed activesupport dependency to 2.3.6 to fix #53, #64, and def #67. (Artem Titoulenko) * Fixing typo in break_down_to.rb. (mikel) == Mon Jun 7 18:07:16 UTC 2010 Mikel Lindsaar * fixing a typo when generating docs. (Andrew Bloom) * Changing \r\n\t to \r\n\s throughout mail (mikel) * Handle multiple quoted words in Encodings.unquote_and_convert_to (Eric Kidd) * Ruby 1.9: mark source encoding so it's usable with -Ks, -Ke, etc (Jeremy Kemper) * Add #include? to mail body for convenience (Maxim Chernyak) * Use Mail::TestMailer.deliveries in README example (John Trupiano) * Allow bundler to automatically build a gem directly from git (Eric Kidd) == Sun Apr 11 07:49:15 UTC 2010 Mikel Lindsaar * Lots of updates on encoding and decoding of headers and unstructured fields. This is now a lot cleaner and nicer. Also more predictable. * Merged encoding branch back into head * Version bump to 2.2.0 * Tagged 2.2.0 == Sun Apr 4 06:41:46 UTC 2010 Mikel Lindsaar * Created non-ascii header auto encoding for address fields and unstructured fields * Changed default behaviour of mail, if you specify a charset, it will use that charset regardless of what is in the body. Previously, if the body was all US-ASCII, it would set the charset to US-ASCII in preference. * Many internal version jumps from 2.1.5.3 => 2.1.5.8 - unreleased development versions == Mon 29 Mar 2010 07:04:34 UTC Mikel Lindsaar * Version bump to 2.1.5.3 * No longer depend on vendor'd treetop as treetop now has optional loading of parts of the library * Change treetop dependency to 1.4.5 == Sun 28 Mar 2010 10:31:33 UTC Mikel Lindsaar * Version bump to 2.1.5.2 * Fixed up preserve case in header fields when assigned from a message closes issue #46 == Sun 28 Mar 2010 09:02:20 UTC Mikel Lindsaar * Version bump to 2.1.5.1 * Fixed net/pop3.rb regression for Ruby 1.8.6 * Merged in Jeremy Kemper's updates: * Bump vendored treetop to 1.4.4 * Use Mikel's treetop for cucumber workaround * Use LOAD_PATH for spec_helper instead of relative requires * Force treetop from git so cucumber doesn't pull in old version == Sun Mar 28 07:01:07 UTC 2010 Mikel Lindsaar * Version bump to 2.1.5 * Changed guess encoding to short circuit to binary if the mime type is unknown, should be safe * Renaming spec to match the file for attachment_lists.rb * Adding Message#decoded returns Message#body#decoded if the message is not multipart == Sun Mar 28 02:55:42 UTC 2010 Mikel Lindsaar * Version bump to 2.1.4 == Sun Mar 28 00:26:27 UTC 2010 Mikel Lindsaar * Merged in Jeremy/treetop to vendored treetop * Merged in nathansobo/treetop to vendored treetop * Merged in pzbowen/mail into mail - Adds body auto encoding - awesome work * Fixed content-transfer-encoding parser to be more compliant per RFC, also now handles trailing semi-colons correctly * Fixed content-transfer-encoding parser to handle weird "from the wild" misspellings * Added message.errors, header.errors arrays, returns array of [field_name, value, error_object] for each field that failed to parse * Removed bundler require from Rakefile == Sun Mar 17 03:03:03 UTC 2010 Mikel Lindsaar * Keep header name case when failing to unstructured field == Wed Feb 24 09:14:56 UTC 2010 Mikel Lindsaar * Fixed multiaddress bounce messages crashing when calling .bounced? Now just take the first report and return that. * Closes issue 38 - final_recipient method give problem when one bounce email for multiple email ids * Fixing up TODO and Docs == Sun Mar 22 03:24:15 UTC 2010 Mikel Lindsaar * Version bump to 2.1.3 == Thu Jan 28 00:25:02 UTC 2010 Mikel Lindsaar * Added TMM1's patch to not raise errors if a email is not multipart/report * Added html_part and text_part now return the first text/html or text/plain part they find. Order is from top to bottom of the email, all parts, flattened. * Cleaning up register_interceptor and register_observer including documentation * Renamed #register_for_delivery_notification to #register_observer * Renamed #register_for_delivery_interception to #register_interceptor * Adding spec to check for folding of non ASCII words that have been encoded * Updating Message#inspect to be a bit more friendly... it is for us mere mortals after all * Version bump to 2.1.2 == Sun Jan 28 02:59:34 UTC 2010 Mikel Lindsaar * Removed old method of setting delivery_method == Mon Jan 25 11:36:13 UTC 2010 Mikel Lindsaar * Added ability for address fields to init on an array instead of just a string. * Version bump to 2.1.1 == Mon Jan 25 10:36:33 UTC 2010 Mikel Lindsaar * Now passes a block to the delivery handler, which can just call yield if it want's Mail to just do it's normal delivery method * Moved Mail.deliveries into Mail::TestMailer.deliveries. Now only gets mail appended to it if you are sending with the :test delivery_method (only for testing) * Version bump to 2.1.0 == Mon Jan 25 01:44:13 UTC 2010 Mikel Lindsaar * Change :deliver! to deliver a mail object, bypassing the :perform_deliveries and :raise_delivery_errors flags, also does not append the mail object to Mail.deliveries, thus the ! (dangerous). The intended use for :deliver! is for people wanting to have their own delivery_handler (like ActionMailer uses) to track and handle delivery failures. * Added :delivery_handler to Message. Allows you to pass an object that will be sent :deliver_mail(self) by the Mail::Message instance when it is sent :deliver and bypasses the usual delivery method. * Changed :perform_deliveries flag to be more consistent with it's name, mail will not append itself to the Mail.deliveries collection if :perform_deliveries is false == Sat Jan 23 23:49:50 UTC 2010 Mikel Lindsaar * Version bump to 2.0.5 * Added :raise_delivery_errors to Mail::Message, if set to false will silently rescue all errors raised by the delivery methods, set to true by default == Sat Jan 23 23:28:42 UTC 2010 Mikel Lindsaar * Version bump to 2.0.4 * Added :perform_deliveries to mail, will not actually call deliver on the delivery method if this is set to false, set to true by default. * Added @delivery_notification_observers to mail messages, you can register an observer with mail by calling mail.register_for_delivery_notification(observer) and then when mail is told to :deliver it will call your observer with observer.delivered_email(self). It will call your observer if it actually performed the delivery or not (that is, irregardless of the :perform_deliveries flag) * Added ability to overwrite the Mail.deliveries store with an object of your choice instead of just an array, this is a good way to find out if something actually got delivered as if :perform_deliveries is false, this collection will not get the mail message appended == Sat Jan 23 05:32:53 UTC 2010 Mikel Lindsaar * Version bump to 2.0.3 * Made body.sort_parts! recursive, to do the entire body * Added ability to use << on the results returned by the various address fields, ie, mail.to << 'new@address' now works * Message now adds multipart/mixed as the content type if nothing is set and there are parts to the message * Added #display_names and #addrs to all address fields. #addrs returns the actual Mail::Address object for each address in the field. * Body should call to_s on given input... incase someone gave it an IO.readlines result (Array) * == Thu Jan 21 05:27:17 UTC 2010 Mikel Lindsaar * Version bump to 2.0.2 * Major change to attachments, add_file now only accepts {:filename => 'full/path/to/file.png'} or {:filename => 'file.png', :content => 'string of file content'} you can also now do mail.attachments['filename.png'] = File.read('path/to/file.png') which is nice too! == Fri Jan 15 09:20:51 UTC 2010 Mikel Lindsaar * Rewrote all network classes to not use singletons. Means different Mail::Message objects can have different delivery methods. * Added examples for how to send via GMail, MobileMe, Sendmail, File etc. * Version bump to 2.0.0 as Network API changed drastically, now not a singleton class. * Fixed that return-path should only return one address == Thu Jan 14 10:41:22 UTC 2010 Mikel Lindsaar * Version update to 1.6.0 - API change on mail.address_fields to always return arrays * Updated all message.address_field methods to always return arrays, so mail.from #=> ['one@address.com'] now, is least surprise * Updated handling of empty group lists so it didn't crash == Thu Jan 12 10:41:47 UTC 2010 Mikel Lindsaar * Version 1.5.3, handling invalid input on fields. Highly recommended update * Updated fields to always try parsing the given data (unless blank). This allows mail to catch invalid input and return UnstructuredFields. Makes mail a lot more resistant to invalid input. == Fri 8 Jan 2010 00:00:08 UTC Mikel Lindsaar * Version bump to 1.5.2 == Fri 8 Jan 8:55:49 2010 +1100 Mikel Lindsaar * Updated Sendmail and SMTP delivery methods to use return-path if present * Fix up a lot of content-type parsing problems * Updating compat listing * Moving error emails into one directory * Moving error emails into one directory * Initializing @tls variable to remove warnings * Moved default corpus directory * Fixed up git ignore file == Thu 6 Jan 2010 23:59:29 UTC Mikel Lindsaar * Added compatibility list to Readme.rdoc * Fixing encoding of return path to be per RFC 2822, adding angle brackets around the addr_spec * Specs covering return path setting and preserving == Thu 5 Jan 2010 23:59:48 UTC Mikel Lindsaar * Moving the require for tlsmail for Ruby 1.8.6 into mail.rb == Sun Jan 3 00:08:06 UTC 2010 Mikel Lindsaar * Version bump to 1.5.0 * Major API change in Message#field_name. This WILL break your applications that use Mail. Message#field_name now returns good, intelligent, default values. You can still access the field object by calling Message#[:field_name] or Message#['field_name']. == Sat Jan 2 04:12:53 UTC 2010 Mikel Lindsaar * Message-ID, Content-ID, References et al, now return the default value of the message ID without the angle brackets, as per RFC 2822, "Semantically, the angle bracket characters are not part of the msg-id; the msg-id is what is contained between the two angle bracket characters." * Message class now has getter and setter methods for all the supported field types explicitly. This allows us to return a "default" value for all fields. * All address fields, when called from Message#to or Message#from or the like, return either a string of the address spec (mikel@test.lindsaar.net) if it is a single entry, or an array of address specs if there is more than one ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] == Mon 28 Dec 2009 01:21:52 UTC Mikel Lindsaar * Added sorting of parts, default is text/plain, then text/enriched and text/html. Access through Body#set_sort_order and Body#sort_parts! (called from Body#encode automatically) * Version bump to 1.4.2 == Sun Dec 27 10:38:24 UTC 2009 Mikel Lindsaar * Updating treetop and mail to initialize uninitialized instance variables to nil * Version bump to 1.4.1 == Sun Dec 27 09:51:27 UTC 2009 Mikel Lindsaar * Version bump to 1.4 because now :to_s calls :decoded for all fields and body while :to_s calls :encoded for Message and Header containers. Makes sense... really. == Sun Dec 27 07:30:02 UTC 2009 Mikel Lindsaar * Changed fields to default to :decoded on :to_s, all container objects retain :encoded as the default for :to_s == Thu Dec 17 06:35:05 UTC 2009 Mikel Lindsaar * Fixed parsing error 'Subject: =?ISO-8859-1?Q?Re=3A_ol=E1?=' (has a new line embedded) == Thu Dec 17 02:14:23 UTC 2009 Mikel Lindsaar * Version 1.3.4 * Vendor'd treetop == Thu Dec 17 01:32:00 UTC 2009 Mikel Lindsaar * Version 1.3.3 * Removed dependency on treetop, don't need it at runtime == Wed Dec 16 23:48:46 UTC 2009 Mikel Lindsaar * Version 1.3.2 * Resolved Ruby 1.9.1-head not working because File.basename only accepts US-ASCII or 8Bit == Sun Dec 13 01:06:17 UTC 2009 Mikel Lindsaar * Version 1.3.1 * Resolved Issue #18 - Wrong instance variable name * Resolved Issue #15 - Duplicate block call == Thu Dec 10 21:25:37 UTC 2009 Mikel Lindsaar * Resolved Issue #13 - replacing From field results in from field becoming optional field. == Thu 3 Dec 2009 00:52:12 UTC Mikel Lindsaar * Added POP upgrades from Nicolas Fouché * Added patch to handle multiple from lines in email from Luke Grimstrup == Mon Nov 23 23:34:22 UTC 2009 Mikel Lindsaar * Resolved Issue #12 - Wrong comment in smtp.rb == Mon Nov 23 22:35:50 UTC 2009 Mikel Lindsaar * Changed the way attachments are added so that it does not break depending on the order of the Hash passed in. * Version bump to 1.3.0 - Now works with Edge ActionMailer, MRI 1.8.6, 1.8.7, 1.9.1, all tests passing == Sun Nov 22 12:19:44 UTC 2009 Mikel Lindsaar * Added check on add_part to make sure if there is already a body, and if so, make a text_part of the body * Fixing up attachment adding and making sure multipart emails always have boundaries * Change Message#attachments to now recursively return all attachments in the email in an ordered flattened array * Added ability for Mail::Message to accept {:headers => {'custom-header' => 'value', 'another-custom-header' => 'value'}} as a param on init * Adding ability to Mail::Message to add a part via :part(params) with optional block * Fixed up QP encoding forcing underscores into everything with a space * Added ReturnPathField#address * Updating gem loads and active support loads == Sat Nov 21 12:52:46 UTC 2009 Mikel Lindsaar * Changed Mail::Encodings to clean it up, added in unquote_and_convert_to as well as refactor in this area == Thu Nov 19 04:16:10 UTC 2009 Mikel Lindsaar * Added sendmail support from (Simon Rozet) * Changed to bundler for gem dependancies and moved gem generation into rakefile (Simon Rozet) * Bumped to 1.2.6 for sendmail support == Wed Nov 18 04:26:21 UTC 2009 Mikel Lindsaar * Changed Encodings.param_encode(string) so it intelligently encodes and quotes needed items and leaves plain, no special char, US-ASCII alone unquoted. == Sat Nov 14 08:20:21 UTC 2009 Mikel Lindsaar * Resolved Issue #10 - empty/nil cc/bcc field causes exception (Mail::Field::ParseError) == Fri Nov 13 00:31:04 UTC 2009 Mikel Lindsaar * Hacked and mutilated the network section, made it easier to extend out with other delivery and retriever methods. API changed SLIGHTLY with this. Please check the readme * Resolved Issue #8 - Mail::SMTP now delivers to all mail.destinations * Version bump to 1.2.5 == Thu Nov 12 02:58:01 UTC 2009 Mikel Lindsaar * Resolved Issue #5 - Message ID not handling multiple periods in left hand side * Resolved Issue #6 - Ordering of add_file and body items causes invalid emails == Tue Nov 10 08:15:14 UTC 2009 Mikel Lindsaar * Resolved Issue #5 - Message ID generation issue * Resolved Issue #7 - README add_file examples don't seem to work - Updated readme and rdoc in Message#add_file == Mon Nov 9 23:38:33 UTC 2009 Mikel Lindsaar * Added ability to create new email via a hash or hash-like object. * Moved all of the Part init into the Message class. Part now just uses Message's init, also moved all the attachment related functions into Message. As Part is a subclass of message, you shouldn't see any interface changes here. == Fri Nov 6 22:52:10 UTC 2009 Mikel Lindsaar * a6ef2b4: Fixed Issue #4 - Can't call encoding on non existant content-transer-encoding header == Fri Nov 6 00:51:55 UTC 2009 Mikel Lindsaar * Handled unstructured field folding "blank" lines * Fixed error in header.rb that created fields into an array, instead of a FieldList, resulting in mail.encode returning a random sort order on the header. * Made unstructured fields attempt to decode their values on :decode == Thu Nov 5 04:45:31 UTC 2009 Mikel Lindsaar * 2acb70a: Closes Issue #1 - Handling badly formatted content-type fields == Wed Nov 4 23:24:32 UTC 2009 Mikel Lindsaar * 2b5d608: Closes Issue #2 - Empty header field values not parsing * Version bumb to 1.2.1 == Wed Nov 4 12:54:43 UTC 2009 Mikel Lindsaar * Renamed Mail::Message.encode! to Mail::Message.ready_to_send!, deprecated :encode! * Rewrote encoding and decoding methods on all classes. Adds a lot of boiler plate code, but allows us to be really precise in each field type that needs custom encoding. Now all encoding is done by the field_type itself. Need to follow through on the body. * Bump version to 1.2.0 due to changes of :encoded, :decoded behaviour == Tue Nov 3 00:59:45 UTC 2009 Mikel Lindsaar * Tested mail against entire Enron set (2.3gb) and the Trec 2005 set (0.5gb), ~ half a million emails without crashing * Some headers only can appear once, enforce during header parse assignment. * Convert empty bodies into empty arrays instead of nil. * Handle blank content dispositions. * Mention Trec 2005 Spam Corpus in readme * Add 'rake corpus:verify_all' to allow parse checks in bulk. * Added handling of multi value parameters, like filename*1*="us-ascii'en'blah" filename*2="bleh" * Added dependency on ActiveSupport 2.3 or higher == Sun Nov 1 12:00:00 UTC 2009 Mikel Lindsaar * handle OpenSSL::SSL::VERIFY_NONE returning 0 * doing Mail.new { content_type [text, plain, { charset => UTF-8 }] } is now possible (content type accepts an array) == Sat Oct 31 11:00:41 UTC 2009 Mikel Lindsaar * Fixed attachment handling, so mail can find attachment from a content-type, content-disposition or content-location * Added content-location field and parser * Added message.has_attachments? for ActionMailer friendliness * Added attachment.original_filename for ActionMailer friendliness == Sat Oct 25 13:38:01 UTC 2009 Mikel Lindsaar * Birthday, Mail released as a gem... phew mail-2.5.4/CONTRIBUTING.md000066400000000000000000000037251214434061600147050ustar00rootroot00000000000000Contributing to Mail ==================== Hi there, I welcome pull requests! Here are some thoughts on how to get your pull request merged quickly: 1. Check the Reference RFCs, they are in the References directory, so no excuses. 2. Check for a ticket on GitHub, maybe someone else has the problem too 3. Make a fork of my GitHub repository 4. Run the specs. We only take pull requests with passing tests, and it's great to know that you have a clean slate: `bundle && bundle exec rake` 5. Add a spec for your change. Only refactoring and documentation changes require no new specs. If you are adding functionality or fixing a bug, we need a spec! 6. Test the spec _at_ _least_ against MRI-1.9.3 and MRI-1.8.7 7. Update the README if needed to reflect your change / addition 8. With all specs passing push your changes back to your fork 9. Send me a pull request Note, specs that break MRI 1.8.7 or 1.9.3 will not be accepted. At this point you're waiting on us. We like to at least comment on, if not accept, pull requests within three business days (and, typically, one business day). We may suggest some changes or improvements or alternatives. Some things that will increase the chance that your pull request is accepted, taken straight from the Ruby on Rails guide: * Tell me you have tested it against more than one version of Ruby, RVM is great for this. I test against 7 rubies before I push into master. * Use good, idiomatic, structured and modular code * Include tests that fail without your code, and pass with it * Update the documentation, the surrounding one, examples elsewhere, guides, whatever is affected by your contribution Syntax: * Two spaces, no tabs. * No trailing whitespace. Blank lines should not have any space. * Prefer &&/|| over and/or. * MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg. * a = b and not a=b. * Follow the conventions you see used in the source already. And in case we didn't emphasize it enough: we love specs! mail-2.5.4/Dependencies.txt000066400000000000000000000003251214434061600155740ustar00rootroot00000000000000treetop: we need to include this in the gem spec tlsmail: if ruby < 1.8.6... we could make it optional, or embed it in Mail mime/types: I think we embed a simplified version, or help maintain it, it is old (2006) mail-2.5.4/Gemfile000066400000000000000000000003571214434061600137450ustar00rootroot00000000000000source 'https://rubygems.org' gemspec gem "treetop", "~> 1.4.10" gem "mime-types", "~> 1.16" gem "tlsmail" if RUBY_VERSION <= '1.8.6' gem 'jruby-openssl', :platform => :jruby group :test do gem "ruby-debug", :platform => :mri_18 end mail-2.5.4/MIT-LICENSE000066400000000000000000000020471214434061600141040ustar00rootroot00000000000000Copyright (c) 2009-2013 Mikel Lindsaar 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. mail-2.5.4/README.md000066400000000000000000000501661214434061600137340ustar00rootroot00000000000000Mail [![Build Status](https://travis-ci.org/mikel/mail.png?branch=master)](https://travis-ci.org/mikel/mail) ==== Introduction ------------ Mail is an internet library for Ruby that is designed to handle emails generation, parsing and sending in a simple, rubyesque manner. The purpose of this library is to provide a single point of access to handle all email functions, including sending and receiving emails. All network type actions are done through proxy methods to Net::SMTP, Net::POP3 etc. Built from my experience with TMail, it is designed to be a pure ruby implementation that makes generating, sending and parsing emails a no brainer. It is also designed form the ground up to work with Ruby 1.9. This is because Ruby 1.9 handles text encodings much more magically than Ruby 1.8.x and so these features have been taken full advantage of in this library allowing Mail to handle a lot more messages more cleanly than TMail. Mail does run on Ruby 1.8.x... it's just not as fun to code. Finally, Mail has been designed with a very simple object oriented system that really opens up the email messages you are parsing, if you know what you are doing, you can fiddle with every last bit of your email directly. Donations ------------- Mail has been downloaded millions of times, by people around the world, in fact, it represents more than 1% of *all* gems downloaded. It is (like all open source software) a labour of love and something I am doing with my own free time. If you would like to say thanks, please feel free to [make a donation](http://www.pledgie.com/campaigns/8790) and feel free to send me a nice email :) Click here to lend your support to: mail and make a donation at www.pledgie.com ! Compatibility ------------- Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml) * ruby-1.8.7-p370 [ i686 ] * ruby-1.9.2-p290 [ x86_64 ] * ruby-1.9.3-p327 [ x86_64 ] * ruby-2.0.0-rc1 [ x86_64 ] * jruby-1.6.8 [ x86_64 ] * jruby-1.7.0 [ x86_64 ] * rbx-d18 [ x86_64 ] * rbx-d19 [ x86_64 ] Discussion ---------- If you want to discuss mail with like minded individuals, please subscribe to the [Google Group](http://groups.google.com/group/mail-ruby). Current Capabilities of Mail ---------------------------- * RFC2822 Support, Reading and Writing * RFC2045-2049 Support for multipart emails * Support for creating multipart alternate emails * Support for reading multipart/report emails & getting details from such * Support for multibyte emails - needs quite a lot of work and testing * Wrappers for File, Net/POP3, Net/SMTP * Auto encoding of non US-ASCII header fields * Auto encoding of non US-ASCII bodies Mail is RFC2822 compliant now, that is, it can parse and generate valid US-ASCII emails. There are a few obsoleted syntax emails that it will have problems with, but it also is quite robust, meaning, if it finds something it doesn't understand it will not crash, instead, it will skip the problem and keep parsing. In the case of a header it doesn't understand, it will initialise the header as an optional unstructured field and continue parsing. This means Mail won't (ever) crunch your data (I think). You can also create MIME emails. There are helper methods for making a multipart/alternate email for text/plain and text/html (the most common pair) and you can manually create any other type of MIME email. Roadmap ------- Next TODO: * Improve MIME support for character sets in headers, currently works, mostly, needs refinement. Testing Policy -------------- Basically... we do BDD on Mail. No method gets written in Mail without a corresponding or covering spec. We expect as a minimum 100% coverage measured by RCov. While this is not perfect by any measure, it is pretty good. Additionally, all functional tests from TMail are to be passing before the gem gets released. It also means you can be sure Mail will behave correctly. API Policy ---------- No API removals within a single point release. All removals to be deprecated with warnings for at least one MINOR point release before removal. Also, all private or protected methods to be declared as such - though this is still I/P. Installation ------------ Installation is fairly simple, I host mail on rubygems, so you can just do: # gem install mail Encodings --------- If you didn't know, handling encodings in Emails is not as straight forward as you would hope. I have tried to simplify it some: 1. All objects that can render into an email, have an `#encoded` method. Encoded will return the object as a complete string ready to send in the mail system, that is, it will include the header field and value and CRLF at the end and wrapped as needed. 2. All objects that can render into an email, have a `#decoded` method. Decoded will return the object's "value" only as a string. This means it will not include the header fields (like 'To:' or 'Subject:'). 3. By default, calling #to_s on a container object will call its encoded method, while #to_s on a field object will call its decoded method. So calling #to_s on a Mail object will return the mail, all encoded ready to send, while calling #to_s on the From field or the body will return the decoded value of the object. The header object of Mail is considered a container. If you are in doubt, call #encoded, or #decoded explicitly, this is safer if you are not sure. 4. Structured fields that have parameter values that can be encoded (e.g. Content-Type) will provide decoded parameter values when you call the parameter names as methods against the object. 5. Structured fields that have parameter values that can be encoded (e.g. Content-Type) will provide encoded parameter values when you call the parameter names through the object.parameters[''] method call. Contributing ------------ Please do! Contributing is easy in Mail. Please read the CONTRIBUTING.md document for more info Usage ----- All major mail functions should be able to happen from the Mail module. So, you should be able to just require 'mail' to get started. ### Making an email ```ruby mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body File.read('body.txt') end mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@... ``` ### Making an email, have it your way: ```ruby mail = Mail.new do body File.read('body.txt') end mail['from'] = 'mikel@test.lindsaar.net' mail[:to] = 'you@test.lindsaar.net' mail.subject = 'This is a test email' mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@... ``` ### Don't Worry About Message IDs: ```ruby mail = Mail.new do to 'you@test.lindsaar.net' body 'Some simple body' end mail.to_s =~ /Message\-ID: <[\d\w_]+@.+.mail/ #=> 27 ``` Mail will automatically add a Message-ID field if it is missing and give it a unique, random Message-ID along the lines of: <4a7ff76d7016_13a81ab802e1@local.host.mail> ### Or do worry about Message-IDs: ```ruby mail = Mail.new do to 'you@test.lindsaar.net' message_id '' body 'Some simple body' end mail.to_s =~ /Message\-ID: / #=> 27 ``` Mail will take the message_id you assign to it trusting that you know what you are doing. ### Sending an email: Mail defaults to sending via SMTP to local host port 25. If you have a sendmail or postfix daemon running on on this port, sending email is as easy as: ```ruby Mail.deliver do from 'me@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'Here is the image you wanted' body File.read('body.txt') add_file '/full/path/to/somefile.png' end ``` or ```ruby mail = Mail.new do from 'me@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'Here is the image you wanted' body File.read('body.txt') add_file :filename => 'somefile.png', :content => File.read('/somefile.png') end mail.deliver! ``` Sending via sendmail can be done like so: ```ruby mail = Mail.new do from 'me@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'Here is the image you wanted' body File.read('body.txt') add_file :filename => 'somefile.png', :content => File.read('/somefile.png') end mail.delivery_method :sendmail mail.deliver ``` Exim requires its own delivery manager, and can be used like so: ```ruby mail.delivery_method :exim, :location => "/usr/bin/exim" mail.deliver ``` ### Getting emails from a pop server: You can configure Mail to receive email using retriever_method within Mail.defaults: ```ruby Mail.defaults do retriever_method :pop3, :address => "pop.gmail.com", :port => 995, :user_name => '', :password => '', :enable_ssl => true end ``` You can access incoming email in a number of ways. The most recent email: ```ruby Mail.all #=> Returns an array of all emails Mail.first #=> Returns the first unread email Mail.last #=> Returns the last unread email ``` The first 10 emails sorted by date in ascending order: ```ruby emails = Mail.find(:what => :first, :count => 10, :order => :asc) emails.length #=> 10 ``` Or even all emails: ```ruby emails = Mail.all emails.length #=> LOTS! ``` ### Reading an Email ```ruby mail = Mail.read('/path/to/message.eml') mail.envelope.from #=> 'mikel@test.lindsaar.net' mail.from.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] mail.sender.address #=> 'mikel@test.lindsaar.net' mail.to #=> 'bob@test.lindsaar.net' mail.cc #=> 'sam@test.lindsaar.net' mail.subject #=> "This is the subject" mail.date.to_s #=> '21 Nov 1997 09:55:06 -0600' mail.message_id #=> '<4D6AA7EB.6490534@xxx.xxx>' mail.body.decoded #=> 'This is the body of the email... ``` Many more methods available. ### Reading a Multipart Email ```ruby mail = Mail.read('multipart_email') mail.multipart? #=> true mail.parts.length #=> 2 mail.body.preamble #=> "Text before the first part" mail.body.epilogue #=> "Text after the last part" mail.parts.map { |p| p.content_type } #=> ['text/plain', 'application/pdf'] mail.parts.map { |p| p.class } #=> [Mail::Message, Mail::Message] mail.parts[0].content_type_parameters #=> {'charset' => 'ISO-8859-1'} mail.parts[1].content_type_parameters #=> {'name' => 'my.pdf'} ``` Mail generates a tree of parts. Each message has many or no parts. Each part is another message which can have many or no parts. A message will only have parts if it is a multipart/mixed or related/mixed content type and has a boundary defined. ### Testing and extracting attachments ```ruby mail.attachments.each do | attachment | # Attachments is an AttachmentsList object containing a # number of Part objects if (attachment.content_type.start_with?('image/')) # extracting images for example... filename = attachment.filename begin File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.body.decoded} rescue Exception => e puts "Unable to save data for #{filename} because #{e.message}" end end end ``` ### Writing and sending a multipart/alternative (html and text) email Mail makes some basic assumptions and makes doing the common thing as simple as possible.... (asking a lot from a mail library) ```ruby mail = Mail.deliver do to 'nicolas@test.lindsaar.net.au' from 'Mikel Lindsaar ' subject 'First multipart email sent with Mail' text_part do body 'This is plain text' end html_part do content_type 'text/html; charset=UTF-8' body '

This is HTML

' end end ``` Mail then delivers the email at the end of the block and returns the resulting Mail::Message object, which you can then inspect if you so desire... ``` puts mail.to_s #=> To: nicolas@test.lindsaar.net.au From: Mikel Lindsaar Subject: First multipart email sent with Mail Content-Type: multipart/alternative; boundary=--==_mimepart_4a914f0c911be_6f0f1ab8026659 Message-ID: <4a914f12ac7e_6f0f1ab80267d1@baci.local.mail> Date: Mon, 24 Aug 2009 00:15:46 +1000 Mime-Version: 1.0 Content-Transfer-Encoding: 7bit ----==_mimepart_4a914f0c911be_6f0f1ab8026659 Content-ID: <4a914f12c8c4_6f0f1ab80268d6@baci.local.mail> Date: Mon, 24 Aug 2009 00:15:46 +1000 Mime-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 7bit This is plain text ----==_mimepart_4a914f0c911be_6f0f1ab8026659 Content-Type: text/html; charset=UTF-8 Content-ID: <4a914f12cf86_6f0f1ab802692c@baci.local.mail> Date: Mon, 24 Aug 2009 00:15:46 +1000 Mime-Version: 1.0 Content-Transfer-Encoding: 7bit

This is HTML

----==_mimepart_4a914f0c911be_6f0f1ab8026659-- ``` Mail inserts the content transfer encoding, the mime version, the content-id's and handles the content-type and boundary. Mail assumes that if your text in the body is only us-ascii, that your transfer encoding is 7bit and it is text/plain. You can override this by explicitly declaring it. ### Making Multipart/Alternate, without a block You don't have to use a block with the text and html part included, you can just do it declaratively. However, you need to add Mail::Parts to an email, not Mail::Messages. ```ruby mail = Mail.new do to 'nicolas@test.lindsaar.net.au' from 'Mikel Lindsaar ' subject 'First multipart email sent with Mail' end text_part = Mail::Part.new do body 'This is plain text' end html_part = Mail::Part.new do content_type 'text/html; charset=UTF-8' body '

This is HTML

' end mail.text_part = text_part mail.html_part = html_part ``` Results in the same email as done using the block form ### Getting error reports from an email: ```ruby @mail = Mail.read('/path/to/bounce_message.eml') @mail.bounced? #=> true @mail.final_recipient #=> rfc822;mikel@dont.exist.com @mail.action #=> failed @mail.error_status #=> 5.5.0 @mail.diagnostic_code #=> smtp;550 Requested action not taken: mailbox unavailable @mail.retryable? #=> false ``` ### Attaching and Detaching Files You can just read the file off an absolute path, Mail will try to guess the mime_type and will encode the file in Base64 for you. ```ruby @mail = Mail.new @mail.add_file("/path/to/file.jpg") @mail.parts.first.attachment? #=> true @mail.parts.first.content_transfer_encoding.to_s #=> 'base64' @mail.attachments.first.mime_type #=> 'image/jpg' @mail.attachments.first.filename #=> 'file.jpg' @mail.attachments.first.decoded == File.read('/path/to/file.jpg') #=> true ``` Or You can pass in file_data and give it a filename, again, mail will try and guess the mime_type for you. ```ruby @mail = Mail.new @mail.attachments['myfile.pdf'] = File.read('path/to/myfile.pdf') @mail.parts.first.attachment? #=> true @mail.attachments.first.mime_type #=> 'application/pdf' @mail.attachments.first.decoded == File.read('path/to/myfile.pdf') #=> true ``` You can also override the guessed MIME media type if you really know better than mail (this should be rarely needed) ```ruby @mail = Mail.new file_data = File.read('path/to/myfile.pdf') @mail.attachments['myfile.pdf'] = { :mime_type => 'application/x-pdf', :content => File.read('path/to/myfile.pdf') } @mail.parts.first.mime_type #=> 'application/x-pdf' ``` Of course... Mail will round trip an attachment as well ```ruby @mail = Mail.new do to 'nicolas@test.lindsaar.net.au' from 'Mikel Lindsaar ' subject 'First multipart email sent with Mail' text_part do body 'Here is the attachment you wanted' end html_part do content_type 'text/html; charset=UTF-8' body '

Funky Title

Here is the attachment you wanted

' end add_file '/path/to/myfile.pdf' end @round_tripped_mail = Mail.new(@mail.encoded) @round_tripped_mail.attachments.length #=> 1 @round_tripped_mail.attachments.first.filename #=> 'myfile.pdf' ``` See "Testing and extracting attachments" above for more details. Using Mail with Testing or Spec'ing Libraries --------------------------------------------- If mail is part of your system, you'll need a way to test it without actually sending emails, the TestMailer can do this for you. ``` require 'mail' => true Mail.defaults do delivery_method :test end => # Mail::TestMailer.deliveries => [] Mail.deliver do to 'mikel@me.com' from 'you@you.com' subject 'testing' body 'hello' end => # 1 Mail::TestMailer.deliveries.first => # [] ``` There is also a set of RSpec matchers stolen fr^H^H^H^H^H^H^H^H inspired by Shoulda's ActionMailer matchers (you'll want to set delivery_method as above too): ``` Mail.defaults do delivery_method :test # in practice you'd do this in spec_helper.rb end describe "sending an email" do include Mail::Matchers before(:each) do Mail::TestMailer.deliveries.clear Mail.deliver do to ['mikel@me.com', 'mike2@me.com'] from 'you@you.com' subject 'testing' body 'hello' end end it { should have_sent_email } # passes if any email at all was sent it { should have_sent_email.from('you@you.com') } it { should have_sent_email.to('mike1@me.com') } # can specify a list of recipients... it { should have_sent_email.to(['mike1@me.com', 'mike2@me.com']) } # ...or chain recipients together it { should have_sent_email.to('mike1@me.com').to('mike2@me.com') } it { should have_sent_email.with_subject('testing') } it { should have_sent_email.with_body('hello') } # Can match subject or body with a regex # (or anything that responds_to? :match) it { should have_sent_email.matching_subject(/test(ing)?/) } it { should have_sent_email.matching_body(/h(a|e)llo/) } # Can chain together modifiers # Note that apart from recipients, repeating a modifier overwrites old value. it { should have_sent_email.from('you@you.com').to('mike1@me.com').matching_body(/hell/) end ``` Excerpts from TREC Spam Corpus 2005 ----------------------------------- The spec fixture files in spec/fixtures/emails/from_trec_2005 are from the 2005 TREC Public Spam Corpus. They remain copyrighted under the terms of that project and license agreement. They are used in this project to verify and describe the development of this email parser implementation. http://plg.uwaterloo.ca/~gvcormac/treccorpus/ They are used as allowed by 'Permitted Uses, Clause 3': "Small excerpts of the information may be displayed to others or published in a scientific or technical context, solely for the purpose of describing the research and development and related issues." -- http://plg.uwaterloo.ca/~gvcormac/treccorpus/ License ------- (The MIT License) Copyright (c) 2009-2013 Mikel Lindsaar 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. mail-2.5.4/ROADMAP000066400000000000000000000046011214434061600134540ustar00rootroot00000000000000=Mail Development Road Path ------------------------------------------------------------- ==Basic Email Handling * Everything so far [DONE - ML] * Address parsing working with all TMail tests passing [DONE - ML] * All address fields handling addresses correctly [DONE - ML] * Mail able to instantiate on any known header type, use method missing [DONE - ML] * Keywords and comments fields working (low hanging fruit) [DONE - ML] * Date parsing working [DONE - ML] * Date fields handling dates correctly [DONE - ML] * Trace fields decided on method to handle [DONE - ML] * Trace fields parsing correctly [DONE - ML] * All trace field functionality working [DONE - ML] * Message ID fields handling correctly [DONE - ML] * Message ID fields generating correctly [DONE - ML] * Work out basic API on address fields [DONE - ML] * All RFC 2822 example emails passing [DONE - ML] * All TMail tests relating to RFC2822 passing * All RFC 2822 obsolete example emails passing ==Multipart Email Handling (need to break down into smaller steps when we get here) * Initial stages of RFC 2045 implemented (content-type and 2046, 2047) [DONE - ML] * Mime-Version field parsing [DONE - ML] * Mime-Version field setting [DONE - ML] * Content-ID field parsing [DONE - ML] * Content-ID field setting [DONE - ML] * Content-Description field parsing [DONE - ML] * Content-Description field setting [DONE - ML] * Content-Transfer-Encoding parsing [DONE - ML] * Content-Transfer-Encoding setting [DONE - ML] * Content-Type field parsing [DONE - ML] * Content-Type field setting [DONE - ML] * Multipart email support [DONE - ML] * Reading multipart emails [DONE - ML] * Creating multipart emails [DONE - ML] * Multipart/Report reporting done [DONE - ML] * Implement all helper methods on adding and deleting parts and attachments [DONE - ML] ==Encoding/Decoding * Support for content-transport-encoding handling [DONE - ML] (base64) * Handle non us-ascii in Subject, keywords, header fields in general [DONE - ML] * handle encoding and decoding of multipart emails [DONE - ML] (base64) ==Basic Email Sending & Receiving * Wrap up Net/SMTP [DONE - NF] (missing STMPS and Authentication Schemes support) * Wrap up Net/POP3 [DONE - NF] (missing APOP support) * Provide SMTP/POP3/IMAP default configurations for all known webmails * Wrap up Net/IMAP (if we really want to...) * Get a mbox parser and handler written mail-2.5.4/Rakefile000066400000000000000000000007411214434061600141140ustar00rootroot00000000000000ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', __FILE__) require 'rubygems' require 'bundler/setup' require 'rake/testtask' require 'rspec/core/rake_task' desc "Build a gem file" task :build do system "gem build mail.gemspec" end task :default => :spec RSpec::Core::RakeTask.new(:spec) do |t| t.ruby_opts = '-w' t.rspec_opts = %w(--backtrace --color) end # load custom rake tasks Dir["#{File.dirname(__FILE__)}/lib/tasks/**/*.rake"].sort.each { |ext| load ext } mail-2.5.4/TODO.rdoc000066400000000000000000000006511214434061600140650ustar00rootroot00000000000000== Not really in any order: * Add multibyte handling to fields, if they get a multibyte string, try encoding it into UTF-8 B first, if this fails, throw an error. * Cleanup the treetop parsers......... do I _really_ need that many entrance files? * Simplify the relationship of Headers and Fields. Doing too much of the Field work in the Header class on instantiating fields. Header should just say "Field, do it!" mail-2.5.4/lib/000077500000000000000000000000001214434061600132135ustar00rootroot00000000000000mail-2.5.4/lib/VERSION000066400000000000000000000000371214434061600142630ustar00rootroot00000000000000major:2 minor:5 patch:4 build: mail-2.5.4/lib/load_parsers.rb000066400000000000000000000016541214434061600162240ustar00rootroot00000000000000# encoding: utf-8 # This file loads up the parsers for mail to use. It also will attempt to compile parsers # if they don't exist. # # It also only uses the compiler if we are running the SPEC suite module Mail # :doc: require 'treetop/runtime' def self.compile_parser(parser) require 'treetop/compiler' Treetop.load(File.join(File.dirname(__FILE__)) + "/mail/parsers/#{parser}") end parsers = %w[ rfc2822_obsolete rfc2822 address_lists phrase_lists date_time received message_ids envelope_from rfc2045 mime_version content_type content_disposition content_transfer_encoding content_location ] if defined?(MAIL_SPEC_SUITE_RUNNING) parsers.each do |parser| compile_parser(parser) end else parsers.each do |parser| begin require "mail/parsers/#{parser}" rescue LoadError compile_parser(parser) end end end endmail-2.5.4/lib/mail.rb000066400000000000000000000041151214434061600144630ustar00rootroot00000000000000# encoding: utf-8 module Mail # :doc: require 'date' require 'shellwords' require 'uri' require 'net/smtp' require 'mime/types' if RUBY_VERSION <= '1.8.6' begin require 'tlsmail' rescue LoadError raise "You need to install tlsmail if you are using ruby <= 1.8.6" end end if RUBY_VERSION >= "1.9.0" require 'mail/version_specific/ruby_1_9' RubyVer = Ruby19 else require 'mail/version_specific/ruby_1_8' RubyVer = Ruby18 end require 'mail/version' require 'mail/core_extensions/nil' require 'mail/core_extensions/object' require 'mail/core_extensions/string' require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3' require 'mail/indifferent_hash' # Only load our multibyte extensions if AS is not already loaded if defined?(ActiveSupport) require 'active_support/inflector' else require 'mail/core_extensions/string/access' require 'mail/core_extensions/string/multibyte' require 'mail/multibyte' end require 'mail/patterns' require 'mail/utilities' require 'mail/configuration' @@autoloads = {} def self.register_autoload(name, path) @@autoloads[name] = path autoload(name, path) end # This runs through the autoload list and explictly requires them for you. # Useful when running mail in a threaded process. # # Usage: # # require 'mail' # Mail.eager_autoload! def self.eager_autoload! @@autoloads.each { |_,path| require(path) } end # Autoload mail send and receive classes. require 'mail/network' require 'mail/message' require 'mail/part' require 'mail/header' require 'mail/parts_list' require 'mail/attachments_list' require 'mail/body' require 'mail/field' require 'mail/field_list' require 'mail/envelope' require 'load_parsers' # Autoload header field elements and transfer encodings. require 'mail/elements' require 'mail/encodings' require 'mail/encodings/base64' require 'mail/encodings/quoted_printable' require 'mail/matchers/has_sent_mail' # Finally... require all the Mail.methods require 'mail/mail' end mail-2.5.4/lib/mail/000077500000000000000000000000001214434061600141355ustar00rootroot00000000000000mail-2.5.4/lib/mail/attachments_list.rb000066400000000000000000000063571214434061600200430ustar00rootroot00000000000000module Mail class AttachmentsList < Array def initialize(parts_list) @parts_list = parts_list @content_disposition_type = 'attachment' parts_list.map { |p| if p.content_type == "message/rfc822" Mail.new(p.body).attachments elsif p.parts.empty? p if p.attachment? else p.attachments end }.flatten.compact.each { |a| self << a } self end def inline @content_disposition_type = 'inline' self end # Returns the attachment by filename or at index. # # mail.attachments['test.png'] = File.read('test.png') # mail.attachments['test.jpg'] = File.read('test.jpg') # # mail.attachments['test.png'].filename #=> 'test.png' # mail.attachments[1].filename #=> 'test.jpg' def [](index_value) if index_value.is_a?(Fixnum) self.fetch(index_value) else self.select { |a| a.filename == index_value }.first end end def []=(name, value) encoded_name = Mail::Encodings.decode_encode name, :encode default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{encoded_name}\"", :content_transfer_encoding => "#{guess_encoding}", :content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" } if value.is_a?(Hash) default_values[:body] = value.delete(:content) if value[:content] default_values[:body] = value.delete(:data) if value[:data] encoding = value.delete(:transfer_encoding) || value.delete(:encoding) if encoding if Mail::Encodings.defined? encoding default_values[:content_transfer_encoding] = encoding else raise "Do not know how to handle Content Transfer Encoding #{encoding}, please choose either quoted-printable or base64" end end if value[:mime_type] default_values[:content_type] = value.delete(:mime_type) @mime_type = MIME::Types[default_values[:content_type]].first default_values[:content_transfer_encoding] ||= guess_encoding end hash = default_values.merge(value) else default_values[:body] = value hash = default_values end if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding? if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary" hash[:body].force_encoding("BINARY") end end attachment = Part.new(hash) attachment.add_content_id(hash[:content_id]) @parts_list << attachment end # Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we # set it to binary, otherwise as set to plain text def guess_encoding if @mime_type && !@mime_type.binary? "7bit" else "binary" end end def set_mime_type(filename) # Have to do this because MIME::Types is not Ruby 1.9 safe yet if RUBY_VERSION >= '1.9' filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode) end @mime_type = MIME::Types.type_for(filename).first end end end mail-2.5.4/lib/mail/body.rb000066400000000000000000000206341214434061600154240ustar00rootroot00000000000000# encoding: utf-8 module Mail # = Body # # The body is where the text of the email is stored. Mail treats the body # as a single object. The body itself has no information about boundaries # used in the MIME standard, it just looks at its content as either a single # block of text, or (if it is a multipart message) as an array of blocks of text. # # A body has to be told to split itself up into a multipart message by calling # #split with the correct boundary. This is because the body object has no way # of knowing what the correct boundary is for itself (there could be many # boundaries in a body in the case of a nested MIME text). # # Once split is called, Mail::Body will slice itself up on this boundary, # assigning anything that appears before the first part to the preamble, and # anything that appears after the closing boundary to the epilogue, then # each part gets initialized into a Mail::Part object. # # The boundary that is used to split up the Body is also stored in the Body # object for use on encoding itself back out to a string. You can # overwrite this if it needs to be changed. # # On encoding, the body will return the preamble, then each part joined by # the boundary, followed by a closing boundary string and then the epilogue. class Body def initialize(string = '') @boundary = nil @preamble = nil @epilogue = nil @charset = nil @part_sort_order = [ "text/plain", "text/enriched", "text/html" ] @parts = Mail::PartsList.new if string.blank? @raw_source = '' else # Do join first incase we have been given an Array in Ruby 1.9 if string.respond_to?(:join) @raw_source = string.join('') elsif string.respond_to?(:to_s) @raw_source = string.to_s else raise "You can only assign a string or an object that responds_to? :join or :to_s to a body." end end @encoding = (only_us_ascii? ? '7bit' : '8bit') set_charset end # Matches this body with another body. Also matches the decoded value of this # body with a string. # # Examples: # # body = Mail::Body.new('The body') # body == body #=> true # # body = Mail::Body.new('The body') # body == 'The body' #=> true # # body = Mail::Body.new("VGhlIGJvZHk=\n") # body.encoding = 'base64' # body == "The body" #=> true def ==(other) if other.class == String self.decoded == other else super end end # Accepts a string and performs a regular expression against the decoded text # # Examples: # # body = Mail::Body.new('The body') # body =~ /The/ #=> 0 # # body = Mail::Body.new("VGhlIGJvZHk=\n") # body.encoding = 'base64' # body =~ /The/ #=> 0 def =~(regexp) self.decoded =~ regexp end # Accepts a string and performs a regular expression against the decoded text # # Examples: # # body = Mail::Body.new('The body') # body.match(/The/) #=> # # # body = Mail::Body.new("VGhlIGJvZHk=\n") # body.encoding = 'base64' # body.match(/The/) #=> # def match(regexp) self.decoded.match(regexp) end # Accepts anything that responds to #to_s and checks if it's a substring of the decoded text # # Examples: # # body = Mail::Body.new('The body') # body.include?('The') #=> true # # body = Mail::Body.new("VGhlIGJvZHk=\n") # body.encoding = 'base64' # body.include?('The') #=> true def include?(other) self.decoded.include?(other.to_s) end # Allows you to set the sort order of the parts, overriding the default sort order. # Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content # type coming after. def set_sort_order(order) @part_sort_order = order end # Allows you to sort the parts according to the default sort order, or the sort order you # set with :set_sort_order. # # sort_parts! is also called from :encode, so there is no need for you to call this explicitly def sort_parts! @parts.each do |p| p.body.set_sort_order(@part_sort_order) @parts.sort!(@part_sort_order) p.body.sort_parts! end end # Returns the raw source that the body was initialized with, without # any tampering def raw_source @raw_source end def get_best_encoding(target) target_encoding = Mail::Encodings.get_encoding(target) target_encoding.get_best_compatible(encoding, raw_source) end # Returns a body encoded using transfer_encoding. Multipart always uses an # identiy encoding (i.e. no encoding). # Calling this directly is not a good idea, but supported for compatibility # TODO: Validate that preamble and epilogue are valid for requested encoding def encoded(transfer_encoding = '8bit') if multipart? self.sort_parts! encoded_parts = parts.map { |p| p.encoded } ([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s else be = get_best_encoding(transfer_encoding) dec = Mail::Encodings::get_encoding(encoding) enc = Mail::Encodings::get_encoding(be) if transfer_encoding == encoding and dec.nil? # Cannot decode, so skip normalization raw_source else # Decode then encode to normalize and allow transforming # from base64 to Q-P and vice versa decoded = dec.decode(raw_source) if defined?(Encoding) && charset && charset != "US-ASCII" decoded.encode!(charset) decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible? end enc.encode(decoded) end end end def decoded if !Encodings.defined?(encoding) raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself." else Encodings.get_encoding(encoding).decode(raw_source) end end def to_s decoded end def charset @charset end def charset=( val ) @charset = val end def encoding(val = nil) if val self.encoding = val else @encoding end end def encoding=( val ) @encoding = if val == "text" || val.blank? (only_us_ascii? ? '7bit' : '8bit') else val end end # Returns the preamble (any text that is before the first MIME boundary) def preamble @preamble end # Sets the preamble to a string (adds text before the first MIME boundary) def preamble=( val ) @preamble = val end # Returns the epilogue (any text that is after the last MIME boundary) def epilogue @epilogue end # Sets the epilogue to a string (adds text after the last MIME boundary) def epilogue=( val ) @epilogue = val end # Returns true if there are parts defined in the body def multipart? true unless parts.empty? end # Returns the boundary used by the body def boundary @boundary end # Allows you to change the boundary of this Body object def boundary=( val ) @boundary = val end def parts @parts end def <<( val ) if @parts @parts << val else @parts = Mail::PartsList.new[val] end end def split!(boundary) self.boundary = boundary parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary)}(?=(?:--)?\s*$)/) # Make the preamble equal to the preamble (if any) self.preamble = parts[0].to_s.strip # Make the epilogue equal to the epilogue (if any) self.epilogue = parts[-1].to_s.sub('--', '').strip parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) } self end def only_us_ascii? !(raw_source =~ /[^\x01-\x7f]/) end def empty? !!raw_source.to_s.empty? end private def crlf_boundary "\r\n--#{boundary}\r\n" end def end_boundary "\r\n--#{boundary}--\r\n" end def set_charset only_us_ascii? ? @charset = 'US-ASCII' : @charset = nil end end end mail-2.5.4/lib/mail/check_delivery_params.rb000066400000000000000000000013441214434061600210070ustar00rootroot00000000000000module Mail module CheckDeliveryParams def check_delivery_params(mail) if mail.smtp_envelope_from.blank? raise ArgumentError.new('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end if mail.smtp_envelope_to.blank? raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end message = mail.encoded if mail.respond_to?(:encoded) if message.blank? raise ArgumentError.new('An encoded message is required to send an email') end [mail.smtp_envelope_from, mail.smtp_envelope_to, message] end end end mail-2.5.4/lib/mail/configuration.rb000066400000000000000000000032471214434061600173370ustar00rootroot00000000000000# encoding: utf-8 # # Thanks to Nicolas Fouché for this wrapper # require 'singleton' module Mail # The Configuration class is a Singleton used to hold the default # configuration for all Mail objects. # # Each new mail object gets a copy of these values at initialization # which can be overwritten on a per mail object basis. class Configuration include Singleton def initialize @delivery_method = nil @retriever_method = nil super end def delivery_method(method = nil, settings = {}) return @delivery_method if @delivery_method && method.nil? @delivery_method = lookup_delivery_method(method).new(settings) end def lookup_delivery_method(method) case method.is_a?(String) ? method.to_sym : method when nil Mail::SMTP when :smtp Mail::SMTP when :sendmail Mail::Sendmail when :exim Mail::Exim when :file Mail::FileDelivery when :smtp_connection Mail::SMTPConnection when :test Mail::TestMailer else method end end def retriever_method(method = nil, settings = {}) return @retriever_method if @retriever_method && method.nil? @retriever_method = lookup_retriever_method(method).new(settings) end def lookup_retriever_method(method) case method when nil Mail::POP3 when :pop3 Mail::POP3 when :imap Mail::IMAP when :test Mail::TestRetriever else method end end def param_encode_language(value = nil) value ? @encode_language = value : @encode_language ||= 'en' end end end mail-2.5.4/lib/mail/core_extensions/000077500000000000000000000000001214434061600173445ustar00rootroot00000000000000mail-2.5.4/lib/mail/core_extensions/nil.rb000066400000000000000000000003471214434061600204570ustar00rootroot00000000000000# encoding: utf-8 # This is not loaded if ActiveSupport is already loaded class NilClass #:nodoc: unless nil.respond_to? :blank? def blank? true end end def to_crlf '' end def to_lf '' end end mail-2.5.4/lib/mail/core_extensions/object.rb000066400000000000000000000002711214434061600211370ustar00rootroot00000000000000# encoding: utf-8 unless Object.method_defined? :blank? class Object def blank? if respond_to?(:empty?) empty? else !self end end end end mail-2.5.4/lib/mail/core_extensions/smtp.rb000066400000000000000000000012011214434061600206460ustar00rootroot00000000000000# encoding: utf-8 module Net class SMTP # This is a backport of r30294 from ruby trunk because of a bug in net/smtp. # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294 # # Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby begin alias_method :original_tlsconnect, :tlsconnect def tlsconnect(s) verified = false begin original_tlsconnect(s).tap { verified = true } ensure unless verified s.close rescue nil end end end rescue NameError end end end mail-2.5.4/lib/mail/core_extensions/string.rb000066400000000000000000000011531214434061600211770ustar00rootroot00000000000000# encoding: utf-8 class String #:nodoc: def to_crlf to_str.gsub(/\n|\r\n|\r/) { "\r\n" } end def to_lf to_str.gsub(/\n|\r\n|\r/) { "\n" } end unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?) def blank? self !~ /\S/ end end unless method_defined?(:ascii_only?) # Backport from Ruby 1.9 checks for non-us-ascii characters. def ascii_only? self !~ MATCH_NON_US_ASCII end MATCH_NON_US_ASCII = /[^\x00-\x7f]/ end def not_ascii_only? !ascii_only? end unless method_defined?(:bytesize) alias :bytesize :length end end mail-2.5.4/lib/mail/core_extensions/string/000077500000000000000000000000001214434061600206525ustar00rootroot00000000000000mail-2.5.4/lib/mail/core_extensions/string/access.rb000066400000000000000000000072671214434061600224540ustar00rootroot00000000000000# encoding: utf-8 # This is not loaded if ActiveSupport is already loaded # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail # itself does not depend on ActiveSupport to avoid versioning conflicts class String unless '1.9'.respond_to?(:force_encoding) # Returns the character at the +position+ treating the string as an array (where 0 is the first character). # # Examples: # "hello".at(0) # => "h" # "hello".at(4) # => "o" # "hello".at(10) # => ERROR if < 1.9, nil in 1.9 def at(position) mb_chars[position, 1].to_s end # Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character). # # Examples: # "hello".from(0) # => "hello" # "hello".from(2) # => "llo" # "hello".from(10) # => "" if < 1.9, nil in 1.9 def from(position) mb_chars[position..-1].to_s end # Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character). # # Examples: # "hello".to(0) # => "h" # "hello".to(2) # => "hel" # "hello".to(10) # => "hello" def to(position) mb_chars[0..position].to_s end # Returns the first character of the string or the first +limit+ characters. # # Examples: # "hello".first # => "h" # "hello".first(2) # => "he" # "hello".first(10) # => "hello" def first(limit = 1) if limit == 0 '' elsif limit >= size self else mb_chars[0...limit].to_s end end # Returns the last character of the string or the last +limit+ characters. # # Examples: # "hello".last # => "o" # "hello".last(2) # => "lo" # "hello".last(10) # => "hello" def last(limit = 1) if limit == 0 '' elsif limit >= size self else mb_chars[(-limit)..-1].to_s end end else def at(position) self[position] end def from(position) self[position..-1] end def to(position) self[0..position] end def first(limit = 1) if limit == 0 '' elsif limit >= size self else to(limit - 1) end end def last(limit = 1) if limit == 0 '' elsif limit >= size self else from(-limit) end end end if Module.method(:const_get).arity == 1 # Tries to find a constant with the name specified in the argument string: # # "Module".constantize # => Module # "Test::Unit".constantize # => Test::Unit # # The name is assumed to be the one of a top-level constant, no matter whether # it starts with "::" or not. No lexical context is taken into account: # # C = 'outside' # module M # C = 'inside' # C # => 'inside' # "C".constantize # => 'outside', same as ::C # end # # NameError is raised when the name is not in CamelCase or the constant is # unknown. def constantize names = self.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name) end constant end else def constantize #:nodoc: names = self.split('::') names.shift if names.empty? || names.first.empty? constant = Object names.each do |name| constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name) end constant end end end mail-2.5.4/lib/mail/core_extensions/string/multibyte.rb000066400000000000000000000053411214434061600232200ustar00rootroot00000000000000# encoding: utf-8 # This is not loaded if ActiveSupport is already loaded # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail # itself does not depend on ActiveSupport to avoid versioning conflicts require 'mail/multibyte' class String if RUBY_VERSION >= "1.9" # == Multibyte proxy # # +mb_chars+ is a multibyte safe proxy for string methods. # # In Ruby 1.8 and older it creates and returns an instance of the Mail::Multibyte::Chars class which # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string. # # name = 'Claus Müller' # name.reverse # => "rell??M sualC" # name.length # => 13 # # name.mb_chars.reverse.to_s # => "rellüM sualC" # name.mb_chars.length # => 12 # # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that # it becomes easy to run one version of your code on multiple Ruby versions. # # == Method chaining # # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows # method chaining on the result of any of these methods. # # name.mb_chars.reverse.length # => 12 # # == Interoperability and configuration # # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between # String and Char work like expected. The bang! methods change the internal string representation in the Chars # object. Interoperability problems can be resolved easily with a +to_s+ call. # # For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For # information about how to change the default Multibyte behaviour see Mail::Multibyte. def mb_chars if Mail::Multibyte.proxy_class.consumes?(self) Mail::Multibyte.proxy_class.new(self) else self end end def is_utf8? #:nodoc case encoding when Encoding::UTF_8 valid_encoding? when Encoding::ASCII_8BIT, Encoding::US_ASCII dup.force_encoding(Encoding::UTF_8).valid_encoding? else false end end else def mb_chars if Mail::Multibyte.proxy_class.wants?(self) Mail::Multibyte.proxy_class.new(self) else self end end # Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have # them), returns false otherwise. def is_utf8? Mail::Multibyte::Chars.consumes?(self) end end end mail-2.5.4/lib/mail/elements.rb000066400000000000000000000016421214434061600163010ustar00rootroot00000000000000module Mail register_autoload :Address, 'mail/elements/address' register_autoload :AddressList, 'mail/elements/address_list' register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element' register_autoload :ContentLocationElement, 'mail/elements/content_location_element' register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element' register_autoload :ContentTypeElement, 'mail/elements/content_type_element' register_autoload :DateTimeElement, 'mail/elements/date_time_element' register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element' register_autoload :MessageIdsElement, 'mail/elements/message_ids_element' register_autoload :MimeVersionElement, 'mail/elements/mime_version_element' register_autoload :PhraseList, 'mail/elements/phrase_list' register_autoload :ReceivedElement, 'mail/elements/received_element' end mail-2.5.4/lib/mail/elements/000077500000000000000000000000001214434061600157515ustar00rootroot00000000000000mail-2.5.4/lib/mail/elements/address.rb000066400000000000000000000225341214434061600177310ustar00rootroot00000000000000# encoding: utf-8 module Mail class Address include Mail::Utilities # Mail::Address handles all email addresses in Mail. It takes an email address string # and parses it, breaking it down into its component parts and allowing you to get the # address, comments, display name, name, local part, domain part and fully formatted # address. # # Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It # handles all obsolete versions including obsolete domain routing on the local part. # # a = Address.new('Mikel Lindsaar (My email address) ') # a.format #=> 'Mikel Lindsaar (My email address)' # a.address #=> 'mikel@test.lindsaar.net' # a.display_name #=> 'Mikel Lindsaar' # a.local #=> 'mikel' # a.domain #=> 'test.lindsaar.net' # a.comments #=> ['My email address'] # a.to_s #=> 'Mikel Lindsaar (My email address)' def initialize(value = nil) @output_type = :decode @tree = nil @raw_text = value case when value.nil? @parsed = false return else parse(value) end end # Returns the raw imput of the passed in string, this is before it is passed # by the parser. def raw @raw_text end # Returns a correctly formatted address for the email going out. If given # an incorrectly formatted address as input, Mail::Address will do its best # to format it correctly. This includes quoting display names as needed and # putting the address in angle brackets etc. # # a = Address.new('Mikel Lindsaar (My email address) ') # a.format #=> 'Mikel Lindsaar (My email address)' def format parse unless @parsed case when tree.nil? '' when display_name [quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ") when address [address, format_comments].compact.join(" ") else tree.text_value end end # Returns the address that is in the address itself. That is, the # local@domain string, without any angle brackets or the like. # # a = Address.new('Mikel Lindsaar (My email address) ') # a.address #=> 'mikel@test.lindsaar.net' def address parse unless @parsed domain ? "#{local}@#{domain}" : local end # Provides a way to assign an address to an already made Mail::Address object. # # a = Address.new # a.address = 'Mikel Lindsaar (My email address) ' # a.address #=> 'mikel@test.lindsaar.net' def address=(value) parse(value) end # Returns the display name of the email address passed in. # # a = Address.new('Mikel Lindsaar (My email address) ') # a.display_name #=> 'Mikel Lindsaar' def display_name parse unless @parsed @display_name ||= get_display_name Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name end # Provides a way to assign a display name to an already made Mail::Address object. # # a = Address.new # a.address = 'mikel@test.lindsaar.net' # a.display_name = 'Mikel Lindsaar' # a.format #=> 'Mikel Lindsaar ' def display_name=( str ) @display_name = str end # Returns the local part (the left hand side of the @ sign in the email address) of # the address # # a = Address.new('Mikel Lindsaar (My email address) ') # a.local #=> 'mikel' def local parse unless @parsed "#{obs_domain_list}#{get_local.strip}" if get_local end # Returns the domain part (the right hand side of the @ sign in the email address) of # the address # # a = Address.new('Mikel Lindsaar (My email address) ') # a.domain #=> 'test.lindsaar.net' def domain parse unless @parsed strip_all_comments(get_domain) if get_domain end # Returns an array of comments that are in the email, or an empty array if there # are no comments # # a = Address.new('Mikel Lindsaar (My email address) ') # a.comments #=> ['My email address'] def comments parse unless @parsed if get_comments.empty? nil else get_comments.map { |c| c.squeeze(" ") } end end # Sometimes an address will not have a display name, but might have the name # as a comment field after the address. This returns that name if it exists. # # a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)') # a.name #=> 'Mikel Lindsaar' def name parse unless @parsed get_name end # Returns the format of the address, or returns nothing # # a = Address.new('Mikel Lindsaar (My email address) ') # a.format #=> 'Mikel Lindsaar (My email address)' def to_s parse unless @parsed format end # Shows the Address object basic details, including the Address # a = Address.new('Mikel (My email) ') # a.inspect #=> "# (My email)| >" def inspect parse unless @parsed "#<#{self.class}:#{self.object_id} Address: |#{to_s}| >" end def encoded @output_type = :encode format end def decoded @output_type = :decode format end private def parse(value = nil) @parsed = true case when value.nil? nil when value.class == String self.tree = Mail::AddressList.new(value).address_nodes.first else self.tree = value end end def get_domain if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain) @domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip elsif tree.respond_to?(:domain) @domain_text ||= tree.domain.text_value.strip elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain) tree.addr_spec.domain.text_value.strip else nil end end def strip_all_comments(string) unless comments.blank? comments.each do |comment| string = string.gsub("(#{comment})", '') end end string.strip end def strip_domain_comments(value) unless comments.blank? comments.each do |comment| if get_domain && get_domain.include?("(#{comment})") value = value.gsub("(#{comment})", '') end end end value.to_s.strip end def get_comments if tree.respond_to?(:comments) @comments = tree.comments.map { |c| unparen(c.text_value.to_str) } else @comments = [] end end def get_display_name if tree.respond_to?(:display_name) name = unquote(tree.display_name.text_value.strip) str = strip_all_comments(name.to_s) elsif comments if domain str = strip_domain_comments(format_comments) else str = nil end else nil end if str.blank? nil else str end end def get_name if display_name str = display_name else if comments comment_text = comments.join(' ').squeeze(" ") str = "(#{comment_text})" end end if str.blank? nil else unparen(str) end end # Provides access to the Treetop parse tree for this address def tree @tree end def tree=(value) @tree = value end def format_comments if comments comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ") @format_comments ||= "(#{comment_text})" else nil end end def obs_domain_list if tree.respond_to?(:angle_addr) obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) } !obs.empty? ? obs.first.text_value : nil else nil end end def get_local case when tree.respond_to?(:local_dot_atom_text) tree.local_dot_atom_text.text_value when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_part) tree.angle_addr.addr_spec.local_part.text_value when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part) tree.addr_spec.local_part.text_value when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_dot_atom_text) # Ignore local dot atom text when in angle brackets nil when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_dot_atom_text) # Ignore local dot atom text when in angle brackets nil else tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil end end end end mail-2.5.4/lib/mail/elements/address_list.rb000066400000000000000000000045021214434061600207570ustar00rootroot00000000000000# encoding: utf-8 module Mail class AddressList # :nodoc: # Mail::AddressList is the class that parses To, From and other address fields from # emails passed into Mail. # # AddressList provides a way to query the groups and mailbox lists of the passed in # string. # # It can supply all addresses in an array, or return each address as an address object. # # Mail::AddressList requires a correctly formatted group or mailbox list per RFC2822 or # RFC822. It also handles all obsolete versions in those RFCs. # # list = 'ada@test.lindsaar.net, My Group: mikel@test.lindsaar.net, Bob ;' # a = AddressList.new(list) # a.addresses #=> [# ["My Group"] def initialize(string) if string.blank? @address_nodes = [] return self end parser = Mail::AddressListsParser.new if tree = parser.parse(string) @address_nodes = tree.addresses else raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason) end end # Returns a list of address objects from the parsed line def addresses @addresses ||= get_addresses.map do |address_tree| Mail::Address.new(address_tree) end end # Returns a list of all recipient syntax trees that are not part of a group def individual_recipients # :nodoc: @individual_recipients ||= @address_nodes - group_recipients end # Returns a list of all recipient syntax trees that are part of a group def group_recipients # :nodoc: @group_recipients ||= @address_nodes.select { |an| an.respond_to?(:group_name) } end # Returns the names as an array of strings of all groups def group_names # :nodoc: group_recipients.map { |g| g.group_name.text_value } end # Returns a list of address syntax trees def address_nodes # :nodoc: @address_nodes end private def get_addresses (individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten end def get_group_addresses(g) if g.group_list.respond_to?(:addresses) g.group_list.addresses else [] end end end end mail-2.5.4/lib/mail/elements/content_disposition_element.rb000066400000000000000000000012501214434061600241030ustar00rootroot00000000000000# encoding: utf-8 module Mail class ContentDispositionElement # :nodoc: include Mail::Utilities def initialize( string ) parser = Mail::ContentDispositionParser.new if tree = parser.parse(cleaned(string)) @disposition_type = tree.disposition_type.text_value.downcase @parameters = tree.parameters else raise Mail::Field::ParseError.new(ContentDispositionElement, string, parser.failure_reason) end end def disposition_type @disposition_type end def parameters @parameters end def cleaned(string) string =~ /(.+);\s*$/ ? $1 : string end end end mail-2.5.4/lib/mail/elements/content_location_element.rb000066400000000000000000000007731214434061600233600ustar00rootroot00000000000000# encoding: utf-8 module Mail class ContentLocationElement # :nodoc: include Mail::Utilities def initialize( string ) parser = Mail::ContentLocationParser.new if tree = parser.parse(string) @location = tree.location.text_value else raise Mail::Field::ParseError.new(ContentLocationElement, string, parser.failure_reason) end end def location @location end def to_s(*args) location.to_s end end end mail-2.5.4/lib/mail/elements/content_transfer_encoding_element.rb000066400000000000000000000010371214434061600252340ustar00rootroot00000000000000# encoding: utf-8 module Mail class ContentTransferEncodingElement include Mail::Utilities def initialize( string ) parser = Mail::ContentTransferEncodingParser.new case when string.blank? @encoding = '' when tree = parser.parse(string.to_s.downcase) @encoding = tree.encoding.text_value else raise Mail::Field::ParseError.new(ContentTransferEncodingElement, string, parser.failure_reason) end end def encoding @encoding end end end mail-2.5.4/lib/mail/elements/content_type_element.rb000066400000000000000000000013331214434061600225220ustar00rootroot00000000000000# encoding: utf-8 module Mail class ContentTypeElement # :nodoc: include Mail::Utilities def initialize( string ) parser = Mail::ContentTypeParser.new if tree = parser.parse(cleaned(string)) @main_type = tree.main_type.text_value.downcase @sub_type = tree.sub_type.text_value.downcase @parameters = tree.parameters else raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason) end end def main_type @main_type end def sub_type @sub_type end def parameters @parameters end def cleaned(string) string =~ /(.+);\s*$/ ? $1 : string end end end mail-2.5.4/lib/mail/elements/date_time_element.rb000066400000000000000000000010261214434061600217410ustar00rootroot00000000000000# encoding: utf-8 module Mail class DateTimeElement # :nodoc: include Mail::Utilities def initialize( string ) parser = Mail::DateTimeParser.new if tree = parser.parse(string) @date_string = tree.date.text_value @time_string = tree.time.text_value else raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason) end end def date_string @date_string end def time_string @time_string end end end mail-2.5.4/lib/mail/elements/envelope_from_element.rb000066400000000000000000000021411214434061600226450ustar00rootroot00000000000000# encoding: utf-8 module Mail class EnvelopeFromElement include Mail::Utilities def initialize( string ) parser = Mail::EnvelopeFromParser.new if @tree = parser.parse(string) @address = tree.addr_spec.text_value.strip @date_time = ::DateTime.parse("#{tree.ctime_date.text_value}") else raise Mail::Field::ParseError.new(EnvelopeFromElement, string, parser.failure_reason) end end def tree @tree end def date_time @date_time end def address @address end # RFC 4155: # a timestamp indicating the UTC date and time when the message # was originally received, conformant with the syntax of the # traditional UNIX 'ctime' output sans timezone (note that the # use of UTC precludes the need for a timezone indicator); def formatted_date_time if @date_time.respond_to?(:ctime) @date_time.ctime else @date_time.strftime '%a %b %e %T %Y' end end def to_s "#{@address} #{formatted_date_time}" end end end mail-2.5.4/lib/mail/elements/message_ids_element.rb000066400000000000000000000011321214434061600222670ustar00rootroot00000000000000# encoding: utf-8 module Mail class MessageIdsElement include Mail::Utilities def initialize(string) parser = Mail::MessageIdsParser.new if tree = parser.parse(string) @message_ids = tree.message_ids.map { |msg_id| clean_msg_id(msg_id.text_value) } else raise Mail::Field::ParseError.new(MessageIdsElement, string, parser.failure_reason) end end def message_ids @message_ids end def message_id @message_ids.first end def clean_msg_id( val ) val =~ /.*<(.*)>.*/ ; $1 end end end mail-2.5.4/lib/mail/elements/mime_version_element.rb000066400000000000000000000007631214434061600225110ustar00rootroot00000000000000# encoding: utf-8 module Mail class MimeVersionElement include Mail::Utilities def initialize( string ) parser = Mail::MimeVersionParser.new if tree = parser.parse(string) @major = tree.major.text_value @minor = tree.minor.text_value else raise Mail::Field::ParseError.new(MimeVersionElement, string, parser.failure_reason) end end def major @major end def minor @minor end end end mail-2.5.4/lib/mail/elements/phrase_list.rb000066400000000000000000000006551214434061600206210ustar00rootroot00000000000000# encoding: utf-8 module Mail class PhraseList include Mail::Utilities def initialize(string) parser = Mail::PhraseListsParser.new if tree = parser.parse(string) @phrases = tree.phrases else raise Mail::Field::ParseError.new(PhraseList, string, parser.failure_reason) end end def phrases @phrases.map { |p| unquote(p.text_value) } end end end mail-2.5.4/lib/mail/elements/received_element.rb000066400000000000000000000012121214434061600215710ustar00rootroot00000000000000# encoding: utf-8 module Mail class ReceivedElement include Mail::Utilities def initialize( string ) parser = Mail::ReceivedParser.new if tree = parser.parse(string) @date_time = ::DateTime.parse("#{tree.date_time.date.text_value} #{tree.date_time.time.text_value}") @info = tree.name_val_list.text_value else raise Mail::Field::ParseError.new(ReceivedElement, string, parser.failure_reason) end end def date_time @date_time end def info @info end def to_s(*args) "#{@info}; #{@date_time.to_s(*args)}" end end end mail-2.5.4/lib/mail/encodings.rb000066400000000000000000000231421214434061600164350ustar00rootroot00000000000000# encoding: utf-8 module Mail # Raised when attempting to decode an unknown encoding type class UnknownEncodingType < StandardError #:nodoc: end module Encodings include Mail::Patterns extend Mail::Utilities @transfer_encodings = {} # Register transfer encoding # # Example # # Encodings.register "base64", Mail::Encodings::Base64 def Encodings.register(name, cls) @transfer_encodings[get_name(name)] = cls end # Is the encoding we want defined? # # Example: # # Encodings.defined?(:base64) #=> true def Encodings.defined?( str ) @transfer_encodings.include? get_name(str) end # Gets a defined encoding type, QuotedPrintable or Base64 for now. # # Each encoding needs to be defined as a Mail::Encodings::ClassName for # this to work, allows us to add other encodings in the future. # # Example: # # Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64 def Encodings.get_encoding( str ) @transfer_encodings[get_name(str)] end def Encodings.get_all @transfer_encodings.values end def Encodings.get_name(enc) enc = enc.to_s.gsub("-", "_").downcase end # Encodes a parameter value using URI Escaping, note the language field 'en' can # be set using Mail::Configuration, like so: # # Mail.defaults do # param_encode_language 'jp' # end # # The character set used for encoding will either be the value of $KCODE for # Ruby < 1.9 or the encoding on the string passed in. # # Example: # # Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun" def Encodings.param_encode(str) case when str.ascii_only? && str =~ TOKEN_UNSAFE %Q{"#{str}"} when str.ascii_only? str else RubyVer.param_encode(str) end end # Decodes a parameter value using URI Escaping. # # Example: # # Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun" # # str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1') # str.encoding #=> 'ISO-8859-1' ## Only on Ruby 1.9 # str #=> "This is fun" def Encodings.param_decode(str, encoding) RubyVer.param_decode(str, encoding) end # Decodes or encodes a string as needed for either Base64 or QP encoding types in # the =??[QB]??=" format. # # The output type needs to be :decode to decode the input string or :encode to # encode the input string. The character set used for encoding will either be # the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in. # # On encoding, will only send out Base64 encoded strings. def Encodings.decode_encode(str, output_type) case when output_type == :decode Encodings.value_decode(str) else if str.ascii_only? str else Encodings.b_value_encode(str, find_encoding(str)) end end end # Decodes a given string as Base64 or Quoted Printable, depending on what # type it is. # # String has to be of the format =??[QB]??= def Encodings.value_decode(str) # Optimization: If there's no encoded-words in the string, just return it return str unless str =~ /\=\?[^?]+\?[QB]\?[^?]+?\?\=/xmi lines = collapse_adjacent_encodings(str) # Split on white-space boundaries with capture, so we capture the white-space as well lines.map do |line| line.split(/([ \t])/).map do |text| if text.index('=?').nil? text else # Search for occurences of quoted strings or plain strings text.scan(/( # Group around entire regex to include it in matches \=\?[^?]+\?([QB])\?[^?]+?\?\= # Quoted String with subgroup for encoding method | # or .+?(?=\=\?|$) # Plain String )/xmi).map do |matches| string, method = *matches if method == 'b' || method == 'B' b_value_decode(string) elsif method == 'q' || method == 'Q' q_value_decode(string) else string end end end end end.flatten.join("") end # Takes an encoded string of the format =??[QB]??= def Encodings.unquote_and_convert_to(str, to_encoding) output = value_decode( str ).to_s # output is already converted to UTF-8 if 'utf8' == to_encoding.to_s.downcase.gsub("-", "") output elsif to_encoding begin if RUBY_VERSION >= '1.9' output.encode(to_encoding) else require 'iconv' Iconv.iconv(to_encoding, 'UTF-8', output).first end rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL # the 'from' parameter specifies a charset other than what the text # actually is...not much we can do in this case but just return the # unconverted text. # # Ditto if either parameter represents an unknown charset, like # X-UNKNOWN. output end else output end end def Encodings.address_encode(address, charset = 'utf-8') if address.is_a?(Array) # loop back through for each element address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ") else # find any word boundary that is not ascii and encode it encode_non_usascii(address, charset) if address end end def Encodings.encode_non_usascii(address, charset) return address if address.ascii_only? or charset.nil? us_ascii = %Q{\x00-\x7f} # Encode any non usascii strings embedded inside of quotes address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) } # Then loop through all remaining items and encode as needed tokens = address.split(/\s/) map_with_index(tokens) do |word, i| if word.ascii_only? word else previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only? if previous_non_ascii #why are we adding an extra space here? word = " #{word}" end Encodings.b_value_encode(word, charset) end end.join(' ') end # Encode a string with Base64 Encoding and returns it ready to be inserted # as a value for a field, that is, in the =??B??= format # # Example: # # Encodings.b_value_encode('This is あ string', 'UTF-8') # #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" def Encodings.b_value_encode(encoded_str, encoding = nil) return encoded_str if encoded_str.to_s.ascii_only? string, encoding = RubyVer.b_value_encode(encoded_str, encoding) map_lines(string) do |str| "=?#{encoding}?B?#{str.chomp}?=" end.join(" ") end # Encode a string with Quoted-Printable Encoding and returns it ready to be inserted # as a value for a field, that is, in the =??Q??= format # # Example: # # Encodings.q_value_encode('This is あ string', 'UTF-8') # #=> "=?UTF-8?Q?This_is_=E3=81=82_string?=" def Encodings.q_value_encode(encoded_str, encoding = nil) return encoded_str if encoded_str.to_s.ascii_only? string, encoding = RubyVer.q_value_encode(encoded_str, encoding) string.gsub!("=\r\n", '') # We already have limited the string to the length we want map_lines(string) do |str| "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?=" end.join(" ") end private # Decodes a Base64 string from the "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" format # # Example: # # Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=") # #=> 'This is あ string' def Encodings.b_value_decode(str) RubyVer.b_value_decode(str) end # Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format # # Example: # # Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=") # #=> 'This is あ string' def Encodings.q_value_decode(str) RubyVer.q_value_decode(str) end def Encodings.split_encoding_from_string( str ) match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi) if match match[1] else nil end end def Encodings.find_encoding(str) RUBY_VERSION >= '1.9' ? str.encoding : $KCODE end # Gets the encoding type (Q or B) from the string. def Encodings.split_value_encoding_from_string(str) match = str.match(/\=\?[^?]+?\?([QB])\?(.+)?\?\=/mi) if match match[1] else nil end end # When the encoded string consists of multiple lines, lines with the same # encoding (Q or B) can be joined together. # # String has to be of the format =??[QB]??= def Encodings.collapse_adjacent_encodings(str) lines = str.split(/(\?=)\s*(=\?)/).each_slice(2).map(&:join) results = [] previous_encoding = nil lines.each do |line| encoding = split_value_encoding_from_string(line) if encoding == previous_encoding line = results.pop + line line.gsub!(/\?\=\=\?.+?\?[QqBb]\?/m, '') end previous_encoding = encoding results << line end results end end end mail-2.5.4/lib/mail/encodings/000077500000000000000000000000001214434061600161065ustar00rootroot00000000000000mail-2.5.4/lib/mail/encodings/7bit.rb000066400000000000000000000010371214434061600173010ustar00rootroot00000000000000# encoding: utf-8 require 'mail/encodings/8bit' module Mail module Encodings class SevenBit < EightBit NAME = '7bit' PRIORITY = 1 # 7bit and 8bit operate the same # Decode the string def self.decode(str) super end # Encode the string def self.encode(str) super end # Idenity encodings have a fixed cost, 1 byte out per 1 byte in def self.cost(str) super end Encodings.register(NAME, self) end end end mail-2.5.4/lib/mail/encodings/8bit.rb000066400000000000000000000010661214434061600173040ustar00rootroot00000000000000# encoding: utf-8 require 'mail/encodings/binary' module Mail module Encodings class EightBit < Binary NAME = '8bit' PRIORITY = 4 # 8bit is an identiy encoding, meaning nothing to do # Decode the string def self.decode(str) str.to_lf end # Encode the string def self.encode(str) str.to_crlf end # Idenity encodings have a fixed cost, 1 byte out per 1 byte in def self.cost(str) 1.0 end Encodings.register(NAME, self) end end end mail-2.5.4/lib/mail/encodings/base64.rb000066400000000000000000000011541214434061600175200ustar00rootroot00000000000000# encoding: utf-8 require 'mail/encodings/7bit' module Mail module Encodings class Base64 < SevenBit NAME = 'base64' PRIORITY = 3 def self.can_encode?(enc) true end # Decode the string from Base64 def self.decode(str) RubyVer.decode_base64( str ) end # Encode the string to Base64 def self.encode(str) RubyVer.encode_base64( str ).to_crlf end # Base64 has a fixed cost, 4 bytes out per 3 bytes in def self.cost(str) 4.0/3 end Encodings.register(NAME, self) end end end mail-2.5.4/lib/mail/encodings/binary.rb000066400000000000000000000010771214434061600177240ustar00rootroot00000000000000# encoding: utf-8 require 'mail/encodings/transfer_encoding' module Mail module Encodings class Binary < TransferEncoding NAME = 'binary' PRIORITY = 5 # Binary is an identiy encoding, meaning nothing to do # Decode the string def self.decode(str) str end # Encode the string def self.encode(str) str end # Idenity encodings have a fixed cost, 1 byte out per 1 byte in def self.cost(str) 1.0 end Encodings.register(NAME, self) end end end mail-2.5.4/lib/mail/encodings/quoted_printable.rb000066400000000000000000000017231214434061600217770ustar00rootroot00000000000000# encoding: utf-8 require 'mail/encodings/7bit' module Mail module Encodings class QuotedPrintable < SevenBit NAME='quoted-printable' PRIORITY = 2 def self.can_encode?(str) EightBit.can_encode? str end # Decode the string from Quoted-Printable. Cope with hard line breaks # that were incorrectly encoded as hex instead of literal CRLF. def self.decode(str) str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf end def self.encode(str) [str.to_lf].pack("M").to_crlf end def self.cost(str) # These bytes probably do not need encoding c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E") # Everything else turns into =XX where XX is a # two digit hex number (taking 3 bytes) total = (str.bytesize - c)*3 + c total.to_f/str.bytesize end private Encodings.register(NAME, self) end end end mail-2.5.4/lib/mail/encodings/transfer_encoding.rb000066400000000000000000000025041214434061600221260ustar00rootroot00000000000000# encoding: utf-8 module Mail module Encodings class TransferEncoding NAME = '' PRIORITY = -1 def self.can_transport?(enc) enc = Encodings.get_name(enc) if Encodings.defined? enc Encodings.get_encoding(enc).new.is_a? self else false end end def self.can_encode?(enc) can_transport? enc end def self.cost(str) raise "Unimplemented" end def self.to_s self::NAME end def self.get_best_compatible(source_encoding, str) if self.can_transport? source_encoding then source_encoding else choices = [] Encodings.get_all.each do |enc| choices << enc if self.can_transport? enc and enc.can_encode? source_encoding end best = nil best_cost = 100 choices.each do |enc| this_cost = enc.cost str if this_cost < best_cost then best_cost = this_cost best = enc elsif this_cost == best_cost then best = enc if enc::PRIORITY < best::PRIORITY end end best end end def to_s self.class.to_s end end end end mail-2.5.4/lib/mail/envelope.rb000066400000000000000000000013701214434061600163000ustar00rootroot00000000000000# encoding: utf-8 # # = Mail Envelope # # The Envelope class provides a field for the first line in an # mbox file, that looks like "From mikel@test.lindsaar.net DATETIME" # # This envelope class reads that line, and turns it into an # Envelope.from and Envelope.date for your use. module Mail class Envelope < StructuredField def initialize(*args) super(FIELD_NAME, strip_field(FIELD_NAME, args.last)) end def tree @element ||= Mail::EnvelopeFromElement.new(value) @tree ||= @element.tree end def element @element ||= Mail::EnvelopeFromElement.new(value) end def date ::DateTime.parse("#{element.date_time}") end def from element.address end end end mail-2.5.4/lib/mail/field.rb000066400000000000000000000147421214434061600155550ustar00rootroot00000000000000require 'mail/fields' # encoding: utf-8 module Mail # Provides a single class to call to create a new structured or unstructured # field. Works out per RFC what field of field it is being given and returns # the correct field of class back on new. # # ===Per RFC 2822 # # 2.2. Header Fields # # Header fields are lines composed of a field name, followed by a colon # (":"), followed by a field body, and terminated by CRLF. A field # name MUST be composed of printable US-ASCII characters (i.e., # characters that have values between 33 and 126, inclusive), except # colon. A field body may be composed of any US-ASCII characters, # except for CR and LF. However, a field body may contain CRLF when # used in header "folding" and "unfolding" as described in section # 2.2.3. All field bodies MUST conform to the syntax described in # sections 3 and 4 of this standard. # class Field include Patterns include Comparable STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition content-id content-location content-transfer-encoding content-type date from in-reply-to keywords message-id mime-version received references reply-to resent-bcc resent-cc resent-date resent-from resent-message-id resent-sender resent-to return-path sender to ] KNOWN_FIELDS = STRUCTURED_FIELDS + ['comments', 'subject'] FIELDS_MAP = { "to" => ToField, "cc" => CcField, "bcc" => BccField, "message-id" => MessageIdField, "in-reply-to" => InReplyToField, "references" => ReferencesField, "subject" => SubjectField, "comments" => CommentsField, "keywords" => KeywordsField, "date" => DateField, "from" => FromField, "sender" => SenderField, "reply-to" => ReplyToField, "resent-date" => ResentDateField, "resent-from" => ResentFromField, "resent-sender" => ResentSenderField, "resent-to" => ResentToField, "resent-cc" => ResentCcField, "resent-bcc" => ResentBccField, "resent-message-id" => ResentMessageIdField, "return-path" => ReturnPathField, "received" => ReceivedField, "mime-version" => MimeVersionField, "content-transfer-encoding" => ContentTransferEncodingField, "content-description" => ContentDescriptionField, "content-disposition" => ContentDispositionField, "content-type" => ContentTypeField, "content-id" => ContentIdField, "content-location" => ContentLocationField, } # Generic Field Exception class FieldError < StandardError end # Raised when a parsing error has occurred (ie, a StructuredField has tried # to parse a field that is invalid or improperly written) class ParseError < FieldError #:nodoc: attr_accessor :element, :value, :reason def initialize(element, value, reason) @element = element @value = value @reason = reason super("#{element} can not parse |#{value}|\nReason was: #{reason}") end end # Raised when attempting to set a structured field's contents to an invalid syntax class SyntaxError < FieldError #:nodoc: end # Accepts a string: # # Field.new("field-name: field data") # # Or name, value pair: # # Field.new("field-name", "value") # # Or a name by itself: # # Field.new("field-name") # # Note, does not want a terminating carriage return. Returns # self appropriately parsed. If value is not a string, then # it will be passed through as is, for example, content-type # field can accept an array with the type and a hash of # parameters: # # Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}]) def initialize(name, value = nil, charset = 'utf-8') case when name =~ /:/ # Field.new("field-name: field data") charset = value unless value.blank? name, value = split(name) create_field(name, value, charset) when name !~ /:/ && value.blank? # Field.new("field-name") create_field(name, nil, charset) else # Field.new("field-name", "value") create_field(name, value, charset) end return self end def field=(value) @field = value end def field @field end def name field.name end def value field.value end def value=(val) create_field(name, val, charset) end def to_s field.to_s end def update(name, value) create_field(name, value, charset) end def same( other ) match_to_s(other.name, field.name) end alias_method :==, :same def <=>( other ) self.field_order_id <=> other.field_order_id end def field_order_id @field_order_id ||= (FIELD_ORDER_LOOKUP[self.name.to_s.downcase] || 100) end def method_missing(name, *args, &block) field.send(name, *args, &block) end FIELD_ORDER = %w[ return-path received resent-date resent-from resent-sender resent-to resent-cc resent-bcc resent-message-id date from sender reply-to to cc bcc message-id in-reply-to references subject comments keywords mime-version content-type content-transfer-encoding content-location content-disposition content-description ] FIELD_ORDER_LOOKUP = Hash[FIELD_ORDER.each_with_index.to_a] private def split(raw_field) match_data = raw_field.mb_chars.match(FIELD_SPLIT) [match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip] rescue STDERR.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'" end def create_field(name, value, charset) begin self.field = new_field(name, value, charset) rescue Mail::Field::ParseError => e self.field = Mail::UnstructuredField.new(name, value) self.field.errors << [name, value, e] self.field end end def new_field(name, value, charset) lower_case_name = name.to_s.downcase if field_klass = FIELDS_MAP[lower_case_name] field_klass.new(value, charset) else OptionalField.new(name, value, charset) end end end end mail-2.5.4/lib/mail/field_list.rb000066400000000000000000000013771214434061600166100ustar00rootroot00000000000000# encoding: utf-8 module Mail # Field List class provides an enhanced array that keeps a list of # email fields in order. And allows you to insert new fields without # having to worry about the order they will appear in. class FieldList < Array include Enumerable def <<( new_field ) current_entry = self.rindex(new_field) if current_entry self.insert((current_entry + 1), new_field) else insert_idx = -1 self.each_with_index do |item, idx| case item <=> new_field when -1 next when 0 next when 1 insert_idx = idx break end end insert(insert_idx, new_field) end end end endmail-2.5.4/lib/mail/fields.rb000066400000000000000000000042461214434061600157360ustar00rootroot00000000000000module Mail register_autoload :UnstructuredField, 'mail/fields/unstructured_field' register_autoload :StructuredField, 'mail/fields/structured_field' register_autoload :OptionalField, 'mail/fields/optional_field' register_autoload :BccField, 'mail/fields/bcc_field' register_autoload :CcField, 'mail/fields/cc_field' register_autoload :CommentsField, 'mail/fields/comments_field' register_autoload :ContentDescriptionField, 'mail/fields/content_description_field' register_autoload :ContentDispositionField, 'mail/fields/content_disposition_field' register_autoload :ContentIdField, 'mail/fields/content_id_field' register_autoload :ContentLocationField, 'mail/fields/content_location_field' register_autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field' register_autoload :ContentTypeField, 'mail/fields/content_type_field' register_autoload :DateField, 'mail/fields/date_field' register_autoload :FromField, 'mail/fields/from_field' register_autoload :InReplyToField, 'mail/fields/in_reply_to_field' register_autoload :KeywordsField, 'mail/fields/keywords_field' register_autoload :MessageIdField, 'mail/fields/message_id_field' register_autoload :MimeVersionField, 'mail/fields/mime_version_field' register_autoload :ReceivedField, 'mail/fields/received_field' register_autoload :ReferencesField, 'mail/fields/references_field' register_autoload :ReplyToField, 'mail/fields/reply_to_field' register_autoload :ResentBccField, 'mail/fields/resent_bcc_field' register_autoload :ResentCcField, 'mail/fields/resent_cc_field' register_autoload :ResentDateField, 'mail/fields/resent_date_field' register_autoload :ResentFromField, 'mail/fields/resent_from_field' register_autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field' register_autoload :ResentSenderField, 'mail/fields/resent_sender_field' register_autoload :ResentToField, 'mail/fields/resent_to_field' register_autoload :ReturnPathField, 'mail/fields/return_path_field' register_autoload :SenderField, 'mail/fields/sender_field' register_autoload :SubjectField, 'mail/fields/subject_field' register_autoload :ToField, 'mail/fields/to_field' end mail-2.5.4/lib/mail/fields/000077500000000000000000000000001214434061600154035ustar00rootroot00000000000000mail-2.5.4/lib/mail/fields/bcc_field.rb000066400000000000000000000033151214434061600176240ustar00rootroot00000000000000# encoding: utf-8 # # = Blind Carbon Copy Field # # The Bcc field inherits from StructuredField and handles the Bcc: header # field in the email. # # Sending bcc to a mail message will instantiate a Mail::Field object that # has a BccField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Bcc field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.bcc = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:bcc] #=> '# '# '# '' # Bcc field does not get output into an email # mail[:bcc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:bcc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class BccField < StructuredField include Mail::CommonAddress FIELD_NAME = 'bcc' CAPITALIZED_FIELD = 'Bcc' def initialize(value = '', charset = 'utf-8') @charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end # Bcc field should never be :encoded def encoded '' end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/cc_field.rb000066400000000000000000000032751214434061600174670ustar00rootroot00000000000000# encoding: utf-8 # # = Carbon Copy Field # # The Cc field inherits from StructuredField and handles the Cc: header # field in the email. # # Sending cc to a mail message will instantiate a Mail::Field object that # has a CcField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Cc field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.cc = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:cc] #=> '# '# '# 'Cc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:cc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:cc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class CcField < StructuredField include Mail::CommonAddress FIELD_NAME = 'cc' CAPITALIZED_FIELD = 'Cc' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/comments_field.rb000066400000000000000000000024101214434061600207150ustar00rootroot00000000000000# encoding: utf-8 # # = Comments Field # # The Comments field inherits from UnstructuredField and handles the Comments: # header field in the email. # # Sending comments to a mail message will instantiate a Mail::Field object that # has a CommentsField as its field type. # # An email header can have as many comments fields as it wants. There is no upper # limit, the comments field is also optional (that is, no comment is needed) # # == Examples: # # mail = Mail.new # mail.comments = 'This is a comment' # mail.comments #=> 'This is a comment' # mail[:comments] #=> '# '# '# ['This is a comment', "This is another comment"] # module Mail class CommentsField < UnstructuredField FIELD_NAME = 'comments' CAPITALIZED_FIELD = 'Comments' def initialize(value = nil, charset = 'utf-8') @charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value)) self.parse self end end end mail-2.5.4/lib/mail/fields/common/000077500000000000000000000000001214434061600166735ustar00rootroot00000000000000mail-2.5.4/lib/mail/fields/common/address_container.rb000066400000000000000000000003141214434061600227050ustar00rootroot00000000000000module Mail class AddressContainer < Array def initialize(field, list = []) @field = field super(list) end def << (address) @field << address end end endmail-2.5.4/lib/mail/fields/common/common_address.rb000066400000000000000000000074271214434061600222270ustar00rootroot00000000000000# encoding: utf-8 require 'mail/fields/common/address_container' module Mail module CommonAddress # :nodoc: def parse(val = value) unless val.blank? @tree = AddressList.new(encode_if_needed(val)) else nil end end def charset @charset end def encode_if_needed(val) Encodings.address_encode(val, charset) end # Allows you to iterate through each address object in the syntax tree def each tree.addresses.each do |address| yield(address) end end # Returns the address string of all the addresses in the address list def addresses list = tree.addresses.map { |a| a.address } Mail::AddressContainer.new(self, list) end # Returns the formatted string of all the addresses in the address list def formatted list = tree.addresses.map { |a| a.format } Mail::AddressContainer.new(self, list) end # Returns the display name of all the addresses in the address list def display_names list = tree.addresses.map { |a| a.display_name } Mail::AddressContainer.new(self, list) end # Returns the actual address objects in the address list def addrs list = tree.addresses Mail::AddressContainer.new(self, list) end # Returns a hash of group name => address strings for the address list def groups @groups = Hash.new tree.group_recipients.each do |group| @groups[group.group_name.text_value.to_str] = get_group_addresses(group.group_list) end @groups end # Returns the addresses that are part of groups def group_addresses decoded_group_addresses end # Returns a list of decoded group addresses def decoded_group_addresses groups.map { |k,v| v.map { |a| a.decoded } }.flatten end # Returns a list of encoded group addresses def encoded_group_addresses groups.map { |k,v| v.map { |a| a.encoded } }.flatten end # Returns the name of all the groups in a string def group_names # :nodoc: tree.group_names end def default addresses end def <<(val) case when val.nil? raise ArgumentError, "Need to pass an address to <<" when val.blank? parse(encoded) else self.value = [self.value, val].reject {|a| a.blank? }.join(", ") end end def value=(val) super parse(self.value) end private def do_encode(field_name) return '' if value.blank? address_array = tree.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded } address_text = address_array.join(", \r\n\s") group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" } group_text = group_array.join(" \r\n\s") return_array = [address_text, group_text].reject { |a| a.blank? } "#{field_name}: #{return_array.join(", \r\n\s")}\r\n" end def do_decode return nil if value.blank? address_array = tree.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded } address_text = address_array.join(", ") group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" } group_text = group_array.join(" ") return_array = [address_text, group_text].reject { |a| a.blank? } return_array.join(", ") end # Returns the syntax tree of the Addresses def tree # :nodoc: @tree ||= AddressList.new(value) end def get_group_addresses(group_list) if group_list.respond_to?(:addresses) group_list.addresses.map do |address_tree| Mail::Address.new(address_tree) end else [] end end end end mail-2.5.4/lib/mail/fields/common/common_date.rb000066400000000000000000000013651214434061600215120ustar00rootroot00000000000000# encoding: utf-8 module Mail module CommonDate # :nodoc: # Returns a date time object of the parsed date def date_time ::DateTime.parse("#{element.date_string} #{element.time_string}") end def default date_time end def parse(val = value) unless val.blank? @element = Mail::DateTimeElement.new(val) @tree = @element.tree else nil end end private def do_encode(field_name) "#{field_name}: #{value}\r\n" end def do_decode "#{value}" end def element @element ||= Mail::DateTimeElement.new(value) end # Returns the syntax tree of the Date def tree @tree ||= element.tree end end end mail-2.5.4/lib/mail/fields/common/common_field.rb000066400000000000000000000016301214434061600216530ustar00rootroot00000000000000# encoding: utf-8 module Mail module CommonField # :nodoc: def name=(value) @name = value end def name @name ||= nil end def value=(value) @length = nil @tree = nil @element = nil @value = value end def value @value end def to_s decoded.to_s end def default decoded end def field_length @length ||= "#{name}: #{encode(decoded)}".length end def responsible_for?( val ) name.to_s.casecmp(val.to_s) == 0 end private def strip_field(field_name, value) if value.is_a?(Array) value else value.to_s.gsub(/#{field_name}:\s+/i, '') end end FILENAME_RE = /\b(filename|name)=([^;"\r\n]+\s[^;"\r\n]+)/ def ensure_filename_quoted(value) if value.is_a?(String) value.sub! FILENAME_RE, '\1="\2"' end end end end mail-2.5.4/lib/mail/fields/common/common_message_id.rb000066400000000000000000000016041214434061600226710ustar00rootroot00000000000000# encoding: utf-8 module Mail module CommonMessageId # :nodoc: def element @element ||= Mail::MessageIdsElement.new(value) unless value.blank? end def parse(val = value) unless val.blank? @element = Mail::MessageIdsElement.new(val) else nil end end def message_id element.message_id if element end def message_ids element.message_ids if element end def default return nil unless message_ids if message_ids.length == 1 message_ids[0] else message_ids end end private def do_encode(field_name) %Q{#{field_name}: #{formated_message_ids("\r\n ")}\r\n} end def do_decode formated_message_ids(' ') end def formated_message_ids(join) message_ids.map{ |m| "<#{m}>" }.join(join) if message_ids end end end mail-2.5.4/lib/mail/fields/common/parameter_hash.rb000066400000000000000000000033211214434061600222020ustar00rootroot00000000000000# encoding: utf-8 module Mail # ParameterHash is an intelligent Hash that allows you to add # parameter values including the MIME extension paramaters that # have the name*0="blah", name*1="bleh" keys, and will just return # a single key called name="blahbleh" and do any required un-encoding # to make that happen # Parameters are defined in RFC2045, split keys are in RFC2231 class ParameterHash < IndifferentHash include Mail::Utilities def [](key_name) key_pattern = Regexp.escape(key_name.to_s) pairs = [] exact = nil each do |k,v| if k =~ /^#{key_pattern}(\*|$)/i if $1 == '*' pairs << [k, v] else exact = k end end end if pairs.empty? # Just dealing with a single value pair super(exact || key_name) else # Dealing with a multiple value pair or a single encoded value pair string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('') if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/) string = mt[3] encoding = mt[1] else encoding = nil end Mail::Encodings.param_decode(string, encoding) end end def encoded map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value| unless value.ascii_only? value = Mail::Encodings.param_encode(value) key_name = "#{key_name}*" end %Q{#{key_name}=#{quote_token(value)}} end.join(";\r\n\s") end def decoded map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value| %Q{#{key_name}=#{quote_token(value)}} end.join("; ") end end end mail-2.5.4/lib/mail/fields/content_description_field.rb000066400000000000000000000006051214434061600231510ustar00rootroot00000000000000# encoding: utf-8 # # # module Mail class ContentDescriptionField < UnstructuredField FIELD_NAME = 'content-description' CAPITALIZED_FIELD = 'Content-Description' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end end end mail-2.5.4/lib/mail/fields/content_disposition_field.rb000066400000000000000000000030051214434061600231670ustar00rootroot00000000000000# encoding: utf-8 require 'mail/fields/common/parameter_hash' module Mail class ContentDispositionField < StructuredField FIELD_NAME = 'content-disposition' CAPITALIZED_FIELD = 'Content-Disposition' def initialize(value = nil, charset = 'utf-8') self.charset = charset ensure_filename_quoted(value) super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::ContentDispositionElement.new(val) end end def element @element ||= Mail::ContentDispositionElement.new(value) end def disposition_type element.disposition_type end def parameters @parameters = ParameterHash.new element.parameters.each { |p| @parameters.merge!(p) } @parameters end def filename case when !parameters['filename'].blank? @filename = parameters['filename'] when !parameters['name'].blank? @filename = parameters['name'] else @filename = nil end @filename end # TODO: Fix this up def encoded if parameters.length > 0 p = ";\r\n\s#{parameters.encoded}\r\n" else p = "\r\n" end "#{CAPITALIZED_FIELD}: #{disposition_type}" + p end def decoded if parameters.length > 0 p = "; #{parameters.decoded}" else p = "" end "#{disposition_type}" + p end end end mail-2.5.4/lib/mail/fields/content_id_field.rb000066400000000000000000000021371214434061600212240ustar00rootroot00000000000000# encoding: utf-8 # # # module Mail class ContentIdField < StructuredField FIELD_NAME = 'content-id' CAPITALIZED_FIELD = "Content-ID" def initialize(value = nil, charset = 'utf-8') self.charset = charset @uniq = 1 if value.blank? value = generate_content_id else value = strip_field(FIELD_NAME, value) end super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::MessageIdsElement.new(val) end end def element @element ||= Mail::MessageIdsElement.new(value) end def name 'Content-ID' end def content_id element.message_id end def to_s "<#{content_id}>" end # TODO: Fix this up def encoded "#{CAPITALIZED_FIELD}: #{to_s}\r\n" end def decoded "#{to_s}" end private def generate_content_id "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>" end end end mail-2.5.4/lib/mail/fields/content_location_field.rb000066400000000000000000000014161214434061600224370ustar00rootroot00000000000000# encoding: utf-8 # # # module Mail class ContentLocationField < StructuredField FIELD_NAME = 'content-location' CAPITALIZED_FIELD = 'Content-Location' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::ContentLocationElement.new(val) end end def element @element ||= Mail::ContentLocationElement.new(value) end def location element.location end # TODO: Fix this up def encoded "#{CAPITALIZED_FIELD}: #{location}\r\n" end def decoded location end end end mail-2.5.4/lib/mail/fields/content_transfer_encoding_field.rb000066400000000000000000000021771214434061600243260ustar00rootroot00000000000000# encoding: utf-8 # # # module Mail class ContentTransferEncodingField < StructuredField FIELD_NAME = 'content-transfer-encoding' CAPITALIZED_FIELD = 'Content-Transfer-Encoding' def initialize(value = nil, charset = 'utf-8') self.charset = charset value = '7bit' if value.to_s =~ /7-?bits?/i value = '8bit' if value.to_s =~ /8-?bits?/i super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::ContentTransferEncodingElement.new(val) end end def tree STDERR.puts("tree is deprecated. Please use encoding to get parse result\n#{caller}") @element ||= Mail::ContentTransferEncodingElement.new(value) @tree ||= @element.tree end def element @element ||= Mail::ContentTransferEncodingElement.new(value) end def encoding element.encoding end # TODO: Fix this up def encoded "#{CAPITALIZED_FIELD}: #{encoding}\r\n" end def decoded encoding end end end mail-2.5.4/lib/mail/fields/content_type_field.rb000066400000000000000000000117211214434061600216100ustar00rootroot00000000000000# encoding: utf-8 require 'mail/fields/common/parameter_hash' module Mail class ContentTypeField < StructuredField FIELD_NAME = 'content-type' CAPITALIZED_FIELD = 'Content-Type' def initialize(value = nil, charset = 'utf-8') self.charset = charset if value.class == Array @main_type = value[0] @sub_type = value[1] @parameters = ParameterHash.new.merge!(value.last) else @main_type = nil @sub_type = nil @parameters = nil value = strip_field(FIELD_NAME, value) end ensure_filename_quoted(value) super(CAPITALIZED_FIELD, value, charset) self.parse self end def parse(val = value) unless val.blank? self.value = val @element = nil element end end def element begin @element ||= Mail::ContentTypeElement.new(value) rescue attempt_to_clean end end def attempt_to_clean # Sanitize the value, handle special cases @element ||= Mail::ContentTypeElement.new(sanatize(value)) rescue # All else fails, just get the MIME media type @element ||= Mail::ContentTypeElement.new(get_mime_type(value)) end def main_type @main_type ||= element.main_type end def sub_type @sub_type ||= element.sub_type end def string "#{main_type}/#{sub_type}" end def default decoded end alias :content_type :string def parameters unless @parameters @parameters = ParameterHash.new element.parameters.each { |p| @parameters.merge!(p) } end @parameters end def ContentTypeField.with_boundary(type) new("#{type}; boundary=#{generate_boundary}") end def ContentTypeField.generate_boundary "--==_mimepart_#{Mail.random_tag}" end def value if @value.class == Array "#{@main_type}/#{@sub_type}; #{stringify(parameters)}" else @value end end def stringify(params) params.map { |k,v| "#{k}=#{Encodings.param_encode(v)}" }.join("; ") end def filename case when parameters['filename'] @filename = parameters['filename'] when parameters['name'] @filename = parameters['name'] else @filename = nil end @filename end # TODO: Fix this up def encoded if parameters.length > 0 p = ";\r\n\s#{parameters.encoded}" else p = "" end "#{CAPITALIZED_FIELD}: #{content_type}#{p}\r\n" end def decoded if parameters.length > 0 p = "; #{parameters.decoded}" else p = "" end "#{content_type}" + p end private def method_missing(name, *args, &block) if name.to_s =~ /(\w+)=/ self.parameters[$1] = args.first @value = "#{content_type}; #{stringify(parameters)}" else super end end # Various special cases from random emails found that I am not going to change # the parser for def sanatize( val ) # TODO: check if there are cases where whitespace is not a separator val = val. gsub(/\s*=\s*/,'='). # remove whitespaces around equal sign tr(' ',';'). squeeze(';'). gsub(';', '; '). #use '; ' as a separator (or EOL) gsub(/;\s*$/,'') #remove trailing to keep examples below if val =~ /(boundary=(\S*))/i val = "#{$`.downcase}boundary=#{$2}#{$'.downcase}" else val.downcase! end case when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;;+(.*)$/i # Handles 'text/plain;; format="flowed"' (double semi colon) "#{$1}/#{$2}; #{$3}" when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;\s?(ISO[\w\-]+)$/i # Microsoft helper: # Handles 'type/subtype;ISO-8559-1' "#{$1}/#{$2}; charset=#{quote_atom($3)}" when val.chomp =~ /^text;?$/i # Handles 'text;' and 'text' "text/plain;" when val.chomp =~ /^(\w+);\s(.*)$/i # Handles 'text; ' "text/plain; #{$2}" when val =~ /([\w\-]+\/[\w\-]+);\scharset="charset="(\w+)""/i # Handles text/html; charset="charset="GB2312"" "#{$1}; charset=#{quote_atom($2)}" when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i type = $1 # Handles misquoted param values # e.g: application/octet-stream; name=archiveshelp1[1].htm # and: audio/x-midi;\r\n\sname=Part .exe params = $2.to_s.split(/\s+/) params = params.map { |i| i.to_s.chomp.strip } params = params.map { |i| i.split(/\s*\=\s*/) } params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s.gsub(/;$/,""))}" }.join('; ') "#{type}; #{params}" when val =~ /^\s*$/ 'text/plain' else '' end end def get_mime_type( val ) case when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i "#{$1}/#{$2}" else 'text/plain' end end end end mail-2.5.4/lib/mail/fields/date_field.rb000066400000000000000000000031431214434061600200110ustar00rootroot00000000000000# encoding: utf-8 # # = Date Field # # The Date field inherits from StructuredField and handles the Date: header # field in the email. # # Sending date to a mail message will instantiate a Mail::Field object that # has a DateField as its field type. This includes all Mail::CommonAddress # module instance methods. # # There must be excatly one Date field in an RFC2822 email. # # == Examples: # # mail = Mail.new # mail.date = 'Mon, 24 Nov 1997 14:22:01 -0800' # mail.date #=> # # mail.date.to_s #=> 'Mon, 24 Nov 1997 14:22:01 -0800' # mail[:date] #=> '# '# '# e raise e unless "invalid date"==e.message end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/from_field.rb000066400000000000000000000033341214434061600200410ustar00rootroot00000000000000# encoding: utf-8 # # = From Field # # The From field inherits from StructuredField and handles the From: header # field in the email. # # Sending from to a mail message will instantiate a Mail::Field object that # has a FromField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one From field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.from = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:from] #=> '# '# '# 'from: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:from].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:from].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class FromField < StructuredField include Mail::CommonAddress FIELD_NAME = 'from' CAPITALIZED_FIELD = 'From' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/in_reply_to_field.rb000066400000000000000000000033661214434061600214260ustar00rootroot00000000000000# encoding: utf-8 # # = In-Reply-To Field # # The In-Reply-To field inherits from StructuredField and handles the # In-Reply-To: header field in the email. # # Sending in_reply_to to a mail message will instantiate a Mail::Field object that # has a InReplyToField as its field type. This includes all Mail::CommonMessageId # module instance metods. # # Note that, the #message_ids method will return an array of message IDs without the # enclosing angle brackets which per RFC are not syntactically part of the message id. # # Only one InReplyTo field can appear in a header, though it can have multiple # Message IDs. # # == Examples: # # mail = Mail.new # mail.in_reply_to = '' # mail.in_reply_to #=> '' # mail[:in_reply_to] #=> '# '# '# ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] # require 'mail/fields/common/common_message_id' module Mail class InReplyToField < StructuredField include Mail::CommonMessageId FIELD_NAME = 'in-reply-to' CAPITALIZED_FIELD = 'In-Reply-To' def initialize(value = nil, charset = 'utf-8') self.charset = charset value = value.join("\r\n\s") if value.is_a?(Array) super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/keywords_field.rb000066400000000000000000000015231214434061600207430ustar00rootroot00000000000000# encoding: utf-8 # # keywords = "Keywords:" phrase *("," phrase) CRLF module Mail class KeywordsField < StructuredField FIELD_NAME = 'keywords' CAPITALIZED_FIELD = 'Keywords' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @phrase_list ||= PhraseList.new(value) end end def phrase_list @phrase_list ||= PhraseList.new(value) end def keywords phrase_list.phrases end def encoded "#{CAPITALIZED_FIELD}: #{keywords.join(",\r\n ")}\r\n" end def decoded keywords.join(', ') end def default keywords end end end mail-2.5.4/lib/mail/fields/message_id_field.rb000066400000000000000000000044461214434061600212030ustar00rootroot00000000000000# encoding: utf-8 # # = Message-ID Field # # The Message-ID field inherits from StructuredField and handles the # Message-ID: header field in the email. # # Sending message_id to a mail message will instantiate a Mail::Field object that # has a MessageIdField as its field type. This includes all Mail::CommonMessageId # module instance metods. # # Only one MessageId field can appear in a header, and syntactically it can only have # one Message ID. The message_ids method call has been left in however as it will only # return the one message id, ie, an array of length 1. # # Note that, the #message_ids method will return an array of message IDs without the # enclosing angle brackets which per RFC are not syntactically part of the message id. # # == Examples: # # mail = Mail.new # mail.message_id = '' # mail.message_id #=> '' # mail[:message_id] #=> '# '# '# 'F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom' # mail[:message_id].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] # require 'mail/fields/common/common_message_id' module Mail class MessageIdField < StructuredField include Mail::CommonMessageId FIELD_NAME = 'message-id' CAPITALIZED_FIELD = 'Message-ID' def initialize(value = nil, charset = 'utf-8') self.charset = charset @uniq = 1 if value.blank? self.name = CAPITALIZED_FIELD self.value = generate_message_id else super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) end self.parse self end def name 'Message-ID' end def message_ids [message_id] end def to_s "<#{message_id}>" end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end private def generate_message_id "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>" end end end mail-2.5.4/lib/mail/fields/mime_version_field.rb000066400000000000000000000016201214434061600215660ustar00rootroot00000000000000# encoding: utf-8 # # # module Mail class MimeVersionField < StructuredField FIELD_NAME = 'mime-version' CAPITALIZED_FIELD = 'Mime-Version' def initialize(value = nil, charset = 'utf-8') self.charset = charset if value.blank? value = '1.0' end super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::MimeVersionElement.new(val) end end def element @element ||= Mail::MimeVersionElement.new(value) end def version "#{element.major}.#{element.minor}" end def major element.major.to_i end def minor element.minor.to_i end def encoded "#{CAPITALIZED_FIELD}: #{version}\r\n" end def decoded version end end end mail-2.5.4/lib/mail/fields/optional_field.rb000066400000000000000000000005001214434061600207130ustar00rootroot00000000000000# encoding: utf-8 # # The field names of any optional-field MUST NOT be identical to any # field name specified elsewhere in this standard. # # optional-field = field-name ":" unstructured CRLF require 'mail/fields/unstructured_field' module Mail class OptionalField < UnstructuredField end end mail-2.5.4/lib/mail/fields/received_field.rb000066400000000000000000000032461214434061600206660ustar00rootroot00000000000000# encoding: utf-8 # # trace = [return] # 1*received # # return = "Return-Path:" path CRLF # # path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / # obs-path # # received = "Received:" name-val-list ";" date-time CRLF # # name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] # # name-val-pair = item-name CFWS item-value # # item-name = ALPHA *(["-"] (ALPHA / DIGIT)) # # item-value = 1*angle-addr / addr-spec / # atom / domain / msg-id # module Mail class ReceivedField < StructuredField FIELD_NAME = 'received' CAPITALIZED_FIELD = 'Received' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def parse(val = value) unless val.blank? @element = Mail::ReceivedElement.new(val) end end def element @element ||= Mail::ReceivedElement.new(value) end def date_time @datetime ||= ::DateTime.parse("#{element.date_time}") end def info element.info end def formatted_date date_time.strftime("%a, %d %b %Y %H:%M:%S ") + date_time.zone.delete(':') end def encoded if value.blank? "#{CAPITALIZED_FIELD}: \r\n" else "#{CAPITALIZED_FIELD}: #{info}; #{formatted_date}\r\n" end end def decoded if value.blank? "" else "#{info}; #{formatted_date}" end end end end mail-2.5.4/lib/mail/fields/references_field.rb000066400000000000000000000033551214434061600212220ustar00rootroot00000000000000# encoding: utf-8 # # = References Field # # The References field inherits references StructuredField and handles the References: header # field in the email. # # Sending references to a mail message will instantiate a Mail::Field object that # has a ReferencesField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Note that, the #message_ids method will return an array of message IDs without the # enclosing angle brackets which per RFC are not syntactically part of the message id. # # Only one References field can appear in a header, though it can have multiple # Message IDs. # # == Examples: # # mail = Mail.new # mail.references = '' # mail.references #=> '' # mail[:references] #=> '# '# '# ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] # require 'mail/fields/common/common_message_id' module Mail class ReferencesField < StructuredField include CommonMessageId FIELD_NAME = 'references' CAPITALIZED_FIELD = 'References' def initialize(value = nil, charset = 'utf-8') self.charset = charset value = value.join("\r\n\s") if value.is_a?(Array) super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/reply_to_field.rb000066400000000000000000000034671214434061600207420ustar00rootroot00000000000000# encoding: utf-8 # # = Reply-To Field # # The Reply-To field inherits reply-to StructuredField and handles the Reply-To: header # field in the email. # # Sending reply_to to a mail message will instantiate a Mail::Field object that # has a ReplyToField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Reply-To field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.reply_to = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:reply_to] #=> '# '# '# 'Reply-To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:reply_to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:reply_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:reply_to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ReplyToField < StructuredField include Mail::CommonAddress FIELD_NAME = 'reply-to' CAPITALIZED_FIELD = 'Reply-To' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_bcc_field.rb000066400000000000000000000035461214434061600212120ustar00rootroot00000000000000# encoding: utf-8 # # = Resent-Bcc Field # # The Resent-Bcc field inherits resent-bcc StructuredField and handles the # Resent-Bcc: header field in the email. # # Sending resent_bcc to a mail message will instantiate a Mail::Field object that # has a ResentBccField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Resent-Bcc field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.resent_bcc = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_bcc] #=> '# '# '# 'Resent-Bcc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:resent_bcc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:resent_bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_bcc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ResentBccField < StructuredField include Mail::CommonAddress FIELD_NAME = 'resent-bcc' CAPITALIZED_FIELD = 'Resent-Bcc' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_cc_field.rb000066400000000000000000000035161214434061600210450ustar00rootroot00000000000000# encoding: utf-8 # # = Resent-Cc Field # # The Resent-Cc field inherits resent-cc StructuredField and handles the Resent-Cc: header # field in the email. # # Sending resent_cc to a mail message will instantiate a Mail::Field object that # has a ResentCcField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Resent-Cc field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.resent_cc = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_cc] #=> '# '# '# 'Resent-Cc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:resent_cc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:resent_cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_cc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ResentCcField < StructuredField include Mail::CommonAddress FIELD_NAME = 'resent-cc' CAPITALIZED_FIELD = 'Resent-Cc' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_date_field.rb000066400000000000000000000014341214434061600213720ustar00rootroot00000000000000# encoding: utf-8 # # resent-date = "Resent-Date:" date-time CRLF require 'mail/fields/common/common_date' module Mail class ResentDateField < StructuredField include Mail::CommonDate FIELD_NAME = 'resent-date' CAPITALIZED_FIELD = 'Resent-Date' def initialize(value = nil, charset = 'utf-8') self.charset = charset if value.blank? value = ::DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z') else value = strip_field(FIELD_NAME, value) value = ::DateTime.parse(value.to_s).strftime('%a, %d %b %Y %H:%M:%S %z') end super(CAPITALIZED_FIELD, value, charset) self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_from_field.rb000066400000000000000000000035731214434061600214260ustar00rootroot00000000000000# encoding: utf-8 # # = Resent-From Field # # The Resent-From field inherits resent-from StructuredField and handles the Resent-From: header # field in the email. # # Sending resent_from to a mail message will instantiate a Mail::Field object that # has a ResentFromField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Resent-From field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.resent_from = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_from] #=> '# '# '# 'Resent-From: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:resent_from].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:resent_from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_from].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ResentFromField < StructuredField include Mail::CommonAddress FIELD_NAME = 'resent-from' CAPITALIZED_FIELD = 'Resent-From' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_message_id_field.rb000066400000000000000000000012431214434061600225530ustar00rootroot00000000000000# encoding: utf-8 # # resent-msg-id = "Resent-Message-ID:" msg-id CRLF require 'mail/fields/common/common_message_id' module Mail class ResentMessageIdField < StructuredField include CommonMessageId FIELD_NAME = 'resent-message-id' CAPITALIZED_FIELD = 'Resent-Message-ID' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def name 'Resent-Message-ID' end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_sender_field.rb000066400000000000000000000035571214434061600217450ustar00rootroot00000000000000# encoding: utf-8 # # = Resent-Sender Field # # The Resent-Sender field inherits resent-sender StructuredField and handles the Resent-Sender: header # field in the email. # # Sending resent_sender to a mail message will instantiate a Mail::Field object that # has a ResentSenderField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Resent-Sender field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.resent_sender = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_sender #=> ['mikel@test.lindsaar.net'] # mail[:resent_sender] #=> '# '# '# 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_sender.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail.resent_sender.formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ResentSenderField < StructuredField include Mail::CommonAddress FIELD_NAME = 'resent-sender' CAPITALIZED_FIELD = 'Resent-Sender' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def addresses [address.address] end def address tree.addresses.first end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/resent_to_field.rb000066400000000000000000000035161214434061600211020ustar00rootroot00000000000000# encoding: utf-8 # # = Resent-To Field # # The Resent-To field inherits resent-to StructuredField and handles the Resent-To: header # field in the email. # # Sending resent_to to a mail message will instantiate a Mail::Field object that # has a ResentToField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Resent-To field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.resent_to = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_to] #=> '# '# '# 'Resent-To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:resent_to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:resent_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:resent_to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ResentToField < StructuredField include Mail::CommonAddress FIELD_NAME = 'resent-to' CAPITALIZED_FIELD = 'Resent-To' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/return_path_field.rb000066400000000000000000000032071214434061600214300ustar00rootroot00000000000000# encoding: utf-8 # # 4.4.3. REPLY-TO / RESENT-REPLY-TO # # Note: The "Return-Path" field is added by the mail transport # service, at the time of final deliver. It is intended # to identify a path back to the orginator of the mes- # sage. The "Reply-To" field is added by the message # originator and is intended to direct replies. # # trace = [return] # 1*received # # return = "Return-Path:" path CRLF # # path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / # obs-path # # received = "Received:" name-val-list ";" date-time CRLF # # name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] # # name-val-pair = item-name CFWS item-value # # item-name = ALPHA *(["-"] (ALPHA / DIGIT)) # # item-value = 1*angle-addr / addr-spec / # atom / domain / msg-id # require 'mail/fields/common/common_address' module Mail class ReturnPathField < StructuredField include Mail::CommonAddress FIELD_NAME = 'return-path' CAPITALIZED_FIELD = 'Return-Path' def initialize(value = nil, charset = 'utf-8') value = nil if value == '<>' self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded "#{CAPITALIZED_FIELD}: <#{address}>\r\n" end def decoded do_decode end def address addresses.first end def default address end end end mail-2.5.4/lib/mail/fields/sender_field.rb000066400000000000000000000034221214434061600203540ustar00rootroot00000000000000# encoding: utf-8 # # = Sender Field # # The Sender field inherits sender StructuredField and handles the Sender: header # field in the email. # # Sending sender to a mail message will instantiate a Mail::Field object that # has a SenderField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one Sender field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.sender = 'Mikel Lindsaar ' # mail.sender #=> 'mikel@test.lindsaar.net' # mail[:sender] #=> '# '# '# "Sender: Mikel Lindsaar \r\n" # mail[:sender].decoded #=> 'Mikel Lindsaar ' # mail[:sender].addresses #=> ['mikel@test.lindsaar.net'] # mail[:sender].formatted #=> ['Mikel Lindsaar '] # require 'mail/fields/common/common_address' module Mail class SenderField < StructuredField include Mail::CommonAddress FIELD_NAME = 'sender' CAPITALIZED_FIELD = 'Sender' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def addresses [address.address] end def address tree.addresses.first end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end def default address.address end end end mail-2.5.4/lib/mail/fields/structured_field.rb000066400000000000000000000027421214434061600213040ustar00rootroot00000000000000# encoding: utf-8 require 'mail/fields/common/common_field' module Mail # Provides access to a structured header field # # ===Per RFC 2822: # 2.2.2. Structured Header Field Bodies # # Some field bodies in this standard have specific syntactical # structure more restrictive than the unstructured field bodies # described above. These are referred to as "structured" field bodies. # Structured field bodies are sequences of specific lexical tokens as # described in sections 3 and 4 of this standard. Many of these tokens # are allowed (according to their syntax) to be introduced or end with # comments (as described in section 3.2.3) as well as the space (SP, # ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters # (together known as the white space characters, WSP), and those WSP # characters are subject to header "folding" and "unfolding" as # described in section 2.2.3. Semantic analysis of structured field # bodies is given along with their syntax. class StructuredField include Mail::CommonField include Mail::Utilities def initialize(name = nil, value = nil, charset = nil) self.name = name self.value = value self.charset = charset self end def charset @charset end def charset=(val) @charset = val end def default decoded end def errors [] end end end mail-2.5.4/lib/mail/fields/subject_field.rb000066400000000000000000000005671214434061600205420ustar00rootroot00000000000000# encoding: utf-8 # # subject = "Subject:" unstructured CRLF module Mail class SubjectField < UnstructuredField FIELD_NAME = 'subject' CAPITALIZED_FIELD = "Subject" def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) end end end mail-2.5.4/lib/mail/fields/to_field.rb000066400000000000000000000032621214434061600175200ustar00rootroot00000000000000# encoding: utf-8 # # = To Field # # The To field inherits to StructuredField and handles the To: header # field in the email. # # Sending to to a mail message will instantiate a Mail::Field object that # has a ToField as its field type. This includes all Mail::CommonAddress # module instance metods. # # Only one To field can appear in a header, though it can have multiple # addresses and groups of addresses. # # == Examples: # # mail = Mail.new # mail.to = 'Mikel Lindsaar , ada@test.lindsaar.net' # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:to] #=> '# '# '# 'To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' # mail[:to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' # mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # mail[:to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] # require 'mail/fields/common/common_address' module Mail class ToField < StructuredField include Mail::CommonAddress FIELD_NAME = 'to' CAPITALIZED_FIELD = 'To' def initialize(value = nil, charset = 'utf-8') self.charset = charset super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset) self.parse self end def encoded do_encode(CAPITALIZED_FIELD) end def decoded do_decode end end end mail-2.5.4/lib/mail/fields/unstructured_field.rb000066400000000000000000000143351214434061600216500ustar00rootroot00000000000000# encoding: utf-8 require 'mail/fields/common/common_field' module Mail # Provides access to an unstructured header field # # ===Per RFC 2822: # 2.2.1. Unstructured Header Field Bodies # # Some field bodies in this standard are defined simply as # "unstructured" (which is specified below as any US-ASCII characters, # except for CR and LF) with no further restrictions. These are # referred to as unstructured field bodies. Semantically, unstructured # field bodies are simply to be treated as a single line of characters # with no further processing (except for header "folding" and # "unfolding" as described in section 2.2.3). class UnstructuredField include Mail::CommonField include Mail::Utilities attr_accessor :charset attr_reader :errors def initialize(name, value, charset = nil) @errors = [] if value.is_a?(Array) # Probably has arrived here from a failed parse of an AddressList Field value = value.join(', ') else # Ensure we are dealing with a string value = value.to_s end if charset self.charset = charset else if value.respond_to?(:encoding) self.charset = value.encoding else self.charset = $KCODE end end self.name = name self.value = value self end def encoded do_encode end def decoded do_decode end def default decoded end def parse # An unstructured field does not parse self end private def do_encode value.nil? ? '' : "#{wrapped_value}\r\n" end def do_decode value.blank? ? nil : Encodings.decode_encode(value, :decode) end # 2.2.3. Long Header Fields # # Each header field is logically a single line of characters comprising # the field name, the colon, and the field body. For convenience # however, and to deal with the 998/78 character limitations per line, # the field body portion of a header field can be split into a multiple # line representation; this is called "folding". The general rule is # that wherever this standard allows for folding white space (not # simply WSP characters), a CRLF may be inserted before any WSP. For # example, the header field: # # Subject: This is a test # # can be represented as: # # Subject: This # is a test # # Note: Though structured field bodies are defined in such a way that # folding can take place between many of the lexical tokens (and even # within some of the lexical tokens), folding SHOULD be limited to # placing the CRLF at higher-level syntactic breaks. For instance, if # a field body is defined as comma-separated values, it is recommended # that folding occur after the comma separating the structured items in # preference to other places where the field could be folded, even if # it is allowed elsewhere. def wrapped_value # :nodoc: wrap_lines(name, fold("#{name}: ".length)) end # 6.2. Display of 'encoded-word's # # When displaying a particular header field that contains multiple # 'encoded-word's, any 'linear-white-space' that separates a pair of # adjacent 'encoded-word's is ignored. (This is to allow the use of # multiple 'encoded-word's to represent long strings of unencoded text, # without having to separate 'encoded-word's where spaces occur in the # unencoded text.) def wrap_lines(name, folded_lines) result = ["#{name}: #{folded_lines.shift}"] result.concat(folded_lines) result.join("\r\n\s") end def fold(prepend = 0) # :nodoc: encoding = normalized_encoding decoded_string = decoded.to_s should_encode = decoded_string.not_ascii_only? if should_encode first = true words = decoded_string.split(/[ \t]/).map do |word| if first first = !first else word = " " << word end if word.not_ascii_only? word else word.scan(/.{7}|.+$/) end end.flatten else words = decoded_string.split(/[ \t]/) end folded_lines = [] while !words.empty? limit = 78 - prepend limit = limit - 7 - encoding.length if should_encode line = "" while !words.empty? break unless word = words.first.dup word.encode!(charset) if charset && word.respond_to?(:encode!) word = encode(word) if should_encode word = encode_crlf(word) # Skip to next line if we're going to go past the limit # Unless this is the first word, in which case we're going to add it anyway # Note: This means that a word that's longer than 998 characters is going to break the spec. Please fix if this is a problem for you. # (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and # the linebreak will be ignored) break if !line.empty? && (line.length + word.length + 1 > limit) # Remove the word from the queue ... words.shift # Add word separator line << " " unless (line.empty? || should_encode) # ... add it in encoded form to the current line line << word end # Encode the line if necessary line = "=?#{encoding}?Q?#{line}?=" if should_encode # Add the line to the output and reset the prepend folded_lines << line prepend = 0 end folded_lines end def encode(value) value = [value].pack("M").gsub("=\n", '') value.gsub!(/"/, '=22') value.gsub!(/\(/, '=28') value.gsub!(/\)/, '=29') value.gsub!(/\?/, '=3F') value.gsub!(/_/, '=5F') value.gsub!(/ /, '_') value end def encode_crlf(value) value.gsub!("\r", '=0D') value.gsub!("\n", '=0A') value end def normalized_encoding encoding = charset.to_s.upcase.gsub('_', '-') encoding = 'UTF-8' if encoding == 'UTF8' # Ruby 1.8.x and $KCODE == 'u' encoding end end end mail-2.5.4/lib/mail/header.rb000066400000000000000000000226671214434061600157270ustar00rootroot00000000000000# encoding: utf-8 module Mail # Provides access to a header object. # # ===Per RFC2822 # # 2.2. Header Fields # # Header fields are lines composed of a field name, followed by a colon # (":"), followed by a field body, and terminated by CRLF. A field # name MUST be composed of printable US-ASCII characters (i.e., # characters that have values between 33 and 126, inclusive), except # colon. A field body may be composed of any US-ASCII characters, # except for CR and LF. However, a field body may contain CRLF when # used in header "folding" and "unfolding" as described in section # 2.2.3. All field bodies MUST conform to the syntax described in # sections 3 and 4 of this standard. class Header include Patterns include Utilities include Enumerable @@maximum_amount = 1000 # Large amount of headers in Email might create extra high CPU load # Use this parameter to limit number of headers that will be parsed by # mail library. # Default: 1000 def self.maximum_amount @@maximum_amount end def self.maximum_amount=(value) @@maximum_amount = value end # Creates a new header object. # # Accepts raw text or nothing. If given raw text will attempt to parse # it and split it into the various fields, instantiating each field as # it goes. # # If it finds a field that should be a structured field (such as content # type), but it fails to parse it, it will simply make it an unstructured # field and leave it alone. This will mean that the data is preserved but # no automatic processing of that field will happen. If you find one of # these cases, please make a patch and send it in, or at the least, send # me the example so we can fix it. def initialize(header_text = nil, charset = nil) @errors = [] @charset = charset self.raw_source = header_text.to_crlf.lstrip split_header if header_text end # The preserved raw source of the header as you passed it in, untouched # for your Regexing glory. def raw_source @raw_source end # Returns an array of all the fields in the header in order that they # were read in. def fields @fields ||= FieldList.new end # 3.6. Field definitions # # It is important to note that the header fields are not guaranteed to # be in a particular order. They may appear in any order, and they # have been known to be reordered occasionally when transported over # the Internet. However, for the purposes of this standard, header # fields SHOULD NOT be reordered when a message is transported or # transformed. More importantly, the trace header fields and resent # header fields MUST NOT be reordered, and SHOULD be kept in blocks # prepended to the message. See sections 3.6.6 and 3.6.7 for more # information. # # Populates the fields container with Field objects in the order it # receives them in. # # Acceps an array of field string values, for example: # # h = Header.new # h.fields = ['From: mikel@me.com', 'To: bob@you.com'] def fields=(unfolded_fields) @fields = Mail::FieldList.new warn "Warning: more than #{self.class.maximum_amount} header fields only using the first #{self.class.maximum_amount}" if unfolded_fields.length > self.class.maximum_amount unfolded_fields[0..(self.class.maximum_amount-1)].each do |field| field = Field.new(field, nil, charset) field.errors.each { |error| self.errors << error } if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any? selected.first.update(field.name, field.value) else @fields << field end end end def errors @errors end # 3.6. Field definitions # # The following table indicates limits on the number of times each # field may occur in a message header as well as any special # limitations on the use of those fields. An asterisk next to a value # in the minimum or maximum column indicates that a special restriction # appears in the Notes column. # # # # As per RFC, many fields can appear more than once, we will return a string # of the value if there is only one header, or if there is more than one # matching header, will return an array of values in order that they appear # in the header ordered from top to bottom. # # Example: # # h = Header.new # h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20'] # h['To'] #=> 'mikel@me.com' # h['X-Mail-SPAM'] #=> ['15', '20'] def [](name) name = dasherize(name).downcase selected = select_field_for(name) case when selected.length > 1 selected.map { |f| f } when !selected.blank? selected.first else nil end end # Sets the FIRST matching field in the header to passed value, or deletes # the FIRST field matched from the header if passed nil # # Example: # # h = Header.new # h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20'] # h['To'] = 'bob@you.com' # h['To'] #=> 'bob@you.com' # h['X-Mail-SPAM'] = '10000' # h['X-Mail-SPAM'] # => ['15', '20', '10000'] # h['X-Mail-SPAM'] = nil # h['X-Mail-SPAM'] # => nil def []=(name, value) name = dasherize(name) if name.include?(':') raise ArgumentError, "Header names may not contain a colon: #{name.inspect}" end fn = name.downcase selected = select_field_for(fn) case # User wants to delete the field when !selected.blank? && value == nil fields.delete_if { |f| selected.include?(f) } # User wants to change the field when !selected.blank? && limited_field?(fn) selected.first.update(fn, value) # User wants to create the field else # Need to insert in correct order for trace fields self.fields << Field.new(name.to_s, value, charset) end if dasherize(fn) == "content-type" # Update charset if specified in Content-Type params = self[:content_type].parameters rescue nil @charset = params && params[:charset] end end def charset @charset end def charset=(val) params = self[:content_type].parameters rescue nil if params params[:charset] = val end @charset = val end LIMITED_FIELDS = %w[ date from sender reply-to to cc bcc message-id in-reply-to references subject return-path content-type mime-version content-transfer-encoding content-description content-id content-disposition content-location] def encoded buffer = '' buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding) fields.each do |field| buffer << field.encoded end buffer end def to_s encoded end def decoded raise NoMethodError, 'Can not decode an entire header as there could be character set conflicts, try calling #decoded on the various fields.' end def field_summary fields.map { |f| "<#{f.name}: #{f.value}>" }.join(", ") end # Returns true if the header has a Message-ID defined (empty or not) def has_message_id? !fields.select { |f| f.responsible_for?('Message-ID') }.empty? end # Returns true if the header has a Content-ID defined (empty or not) def has_content_id? !fields.select { |f| f.responsible_for?('Content-ID') }.empty? end # Returns true if the header has a Date defined (empty or not) def has_date? !fields.select { |f| f.responsible_for?('Date') }.empty? end # Returns true if the header has a MIME version defined (empty or not) def has_mime_version? !fields.select { |f| f.responsible_for?('Mime-Version') }.empty? end private def raw_source=(val) @raw_source = val end # 2.2.3. Long Header Fields # # The process of moving from this folded multiple-line representation # of a header field to its single line representation is called # "unfolding". Unfolding is accomplished by simply removing any CRLF # that is immediately followed by WSP. Each header field should be # treated in its unfolded form for further syntactic and semantic # evaluation. def unfold(string) string.gsub(/#{CRLF}#{WSP}+/, ' ').gsub(/#{WSP}+/, ' ') end # Returns the header with all the folds removed def unfolded_header @unfolded_header ||= unfold(raw_source) end # Splits an unfolded and line break cleaned header into individual field # strings. def split_header self.fields = unfolded_header.split(CRLF) end def select_field_for(name) fields.select { |f| f.responsible_for?(name) } end def limited_field?(name) LIMITED_FIELDS.include?(name.to_s.downcase) end # Enumerable support; yield each field in order to the block if there is one, # or return an Enumerator for them if there isn't. def each( &block ) return self.fields.each( &block ) if block self.fields.each end end end mail-2.5.4/lib/mail/indifferent_hash.rb000066400000000000000000000074041214434061600177670ustar00rootroot00000000000000# encoding: utf-8 # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail # itself does not depend on ActiveSupport to avoid versioning conflicts module Mail class IndifferentHash < Hash def initialize(constructor = {}) if constructor.is_a?(Hash) super() update(constructor) else super(constructor) end end def default(key = nil) if key.is_a?(Symbol) && include?(key = key.to_s) self[key] else super end end def self.new_from_hash_copying_default(hash) IndifferentHash.new(hash).tap do |new_hash| new_hash.default = hash.default end end alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) alias_method :regular_update, :update unless method_defined?(:regular_update) # Assigns a new value to the hash: # # hash = HashWithIndifferentAccess.new # hash[:key] = "value" # def []=(key, value) regular_writer(convert_key(key), convert_value(value)) end alias_method :store, :[]= # Updates the instantized hash with values from the second: # # hash_1 = HashWithIndifferentAccess.new # hash_1[:key] = "value" # # hash_2 = HashWithIndifferentAccess.new # hash_2[:key] = "New Value!" # # hash_1.update(hash_2) # => {"key"=>"New Value!"} # def update(other_hash) other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) } self end alias_method :merge!, :update # Checks the hash for a key matching the argument passed in: # # hash = HashWithIndifferentAccess.new # hash["key"] = "value" # hash.key? :key # => true # hash.key? "key" # => true # def key?(key) super(convert_key(key)) end alias_method :include?, :key? alias_method :has_key?, :key? alias_method :member?, :key? # Fetches the value for the specified key, same as doing hash[key] def fetch(key, *extras) super(convert_key(key), *extras) end # Returns an array of the values at the specified indices: # # hash = HashWithIndifferentAccess.new # hash[:a] = "x" # hash[:b] = "y" # hash.values_at("a", "b") # => ["x", "y"] # def values_at(*indices) indices.collect {|key| self[convert_key(key)]} end # Returns an exact copy of the hash. def dup IndifferentHash.new(self) end # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash # Does not overwrite the existing hash. def merge(hash) self.dup.update(hash) end # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess. def reverse_merge(other_hash) super self.class.new_from_hash_copying_default(other_hash) end def reverse_merge!(other_hash) replace(reverse_merge( other_hash )) end # Removes a specified key from the hash. def delete(key) super(convert_key(key)) end def stringify_keys!; self end def stringify_keys; dup end def symbolize_keys; to_hash.symbolize_keys end def to_options!; self end def to_hash Hash.new(default).merge!(self) end protected def convert_key(key) key.kind_of?(Symbol) ? key.to_s : key end def convert_value(value) if value.class == Hash self.class.new_from_hash_copying_default(value) elsif value.is_a?(Array) value.dup.replace(value.map { |e| convert_value(e) }) else value end end end end mail-2.5.4/lib/mail/mail.rb000066400000000000000000000201441214434061600154050ustar00rootroot00000000000000# encoding: utf-8 module Mail # Allows you to create a new Mail::Message object. # # You can make an email via passing a string or passing a block. # # For example, the following two examples will create the same email # message: # # Creating via a string: # # string = "To: mikel@test.lindsaar.net\r\n" # string << "From: bob@test.lindsaar.net\r\n" # string << "Subject: This is an email\r\n" # string << "\r\n" # string << "This is the body" # Mail.new(string) # # Or creating via a block: # # message = Mail.new do # to 'mikel@test.lindsaar.net' # from 'bob@test.lindsaar.net' # subject 'This is an email' # body 'This is the body' # end # # Or creating via a hash (or hash like object): # # message = Mail.new({:to => 'mikel@test.lindsaar.net', # 'from' => 'bob@test.lindsaar.net', # :subject => 'This is an email', # :body => 'This is the body' }) # # Note, the hash keys can be strings or symbols, the passed in object # does not need to be a hash, it just needs to respond to :each_pair # and yield each key value pair. # # As a side note, you can also create a new email through creating # a Mail::Message object directly and then passing in values via string, # symbol or direct method calls. See Mail::Message for more information. # # mail = Mail.new # mail.to = 'mikel@test.lindsaar.net' # mail[:from] = 'bob@test.lindsaar.net' # mail['subject'] = 'This is an email' # mail.body = 'This is the body' def self.new(*args, &block) Message.new(args, &block) end # Sets the default delivery method and retriever method for all new Mail objects. # The delivery_method and retriever_method default to :smtp and :pop3, with defaults # set. # # So sending a new email, if you have an SMTP server running on localhost is # as easy as: # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'bob@test.lindsaar.net' # subject 'hi there!' # body 'this is a body' # end # # If you do not specify anything, you will get the following equivalent code set in # every new mail object: # # Mail.defaults do # delivery_method :smtp, { :address => "localhost", # :port => 25, # :domain => 'localhost.localdomain', # :user_name => nil, # :password => nil, # :authentication => nil, # :enable_starttls_auto => true } # # retriever_method :pop3, { :address => "localhost", # :port => 995, # :user_name => nil, # :password => nil, # :enable_ssl => true } # end # # Mail.delivery_method.new #=> Mail::SMTP instance # Mail.retriever_method.new #=> Mail::POP3 instance # # Each mail object inherits the default set in Mail.delivery_method, however, on # a per email basis, you can override the method: # # mail.delivery_method :sendmail # # Or you can override the method and pass in settings: # # mail.delivery_method :sendmail, { :address => 'some.host' } # # You can also just modify the settings: # # mail.delivery_settings = { :address => 'some.host' } # # The passed in hash is just merged against the defaults with +merge!+ and the result # assigned the mail object. So the above example will change only the :address value # of the global smtp_settings to be 'some.host', keeping all other values def self.defaults(&block) Configuration.instance.instance_eval(&block) end # Returns the delivery method selected, defaults to an instance of Mail::SMTP def self.delivery_method Configuration.instance.delivery_method end # Returns the retriever method selected, defaults to an instance of Mail::POP3 def self.retriever_method Configuration.instance.retriever_method end # Send an email using the default configuration. You do need to set a default # configuration first before you use self.deliver, if you don't, an appropriate # error will be raised telling you to. # # If you do not specify a delivery type, SMTP will be used. # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'This is a test email' # body 'Not much to say here' # end # # You can also do: # # mail = Mail.read('email.eml') # mail.deliver! # # And your email object will be created and sent. def self.deliver(*args, &block) mail = self.new(args, &block) mail.deliver mail end # Find emails from the default retriever # See Mail::Retriever for a complete documentation. def self.find(*args, &block) retriever_method.find(*args, &block) end # Finds and then deletes retrieved emails from the default retriever # See Mail::Retriever for a complete documentation. def self.find_and_delete(*args, &block) retriever_method.find_and_delete(*args, &block) end # Receive the first email(s) from the default retriever # See Mail::Retriever for a complete documentation. def self.first(*args, &block) retriever_method.first(*args, &block) end # Receive the first email(s) from the default retriever # See Mail::Retriever for a complete documentation. def self.last(*args, &block) retriever_method.last(*args, &block) end # Receive all emails from the default retriever # See Mail::Retriever for a complete documentation. def self.all(*args, &block) retriever_method.all(*args, &block) end # Reads in an email message from a path and instantiates it as a new Mail::Message def self.read(filename) self.new(File.open(filename, 'rb') { |f| f.read }) end # Delete all emails from the default retriever # See Mail::Retriever for a complete documentation. def self.delete_all(*args, &block) retriever_method.delete_all(*args, &block) end # Instantiates a new Mail::Message using a string def Mail.read_from_string(mail_as_string) Mail.new(mail_as_string) end def Mail.connection(&block) retriever_method.connection(&block) end # Initialize the observers and interceptors arrays @@delivery_notification_observers = [] @@delivery_interceptors = [] # You can register an object to be informed of every email that is sent through # this method. # # Your object needs to respond to a single method #delivered_email(mail) # which receives the email that is sent. def self.register_observer(observer) unless @@delivery_notification_observers.include?(observer) @@delivery_notification_observers << observer end end # You can register an object to be given every mail object that will be sent, # before it is sent. So if you want to add special headers or modify any # email that gets sent through the Mail library, you can do so. # # Your object needs to respond to a single method #delivering_email(mail) # which receives the email that is about to be sent. Make your modifications # directly to this object. def self.register_interceptor(interceptor) unless @@delivery_interceptors.include?(interceptor) @@delivery_interceptors << interceptor end end def self.inform_observers(mail) @@delivery_notification_observers.each do |observer| observer.delivered_email(mail) end end def self.inform_interceptors(mail) @@delivery_interceptors.each do |interceptor| interceptor.delivering_email(mail) end end protected def self.random_tag t = Time.now sprintf('%x%x_%x%x%d%x', t.to_i, t.tv_usec, $$, Thread.current.object_id.abs, self.uniq, rand(255)) end private def self.something_random (Thread.current.object_id * rand(255) / Time.now.to_f).to_s.slice(-3..-1).to_i end def self.uniq @@uniq += 1 end @@uniq = self.something_random end mail-2.5.4/lib/mail/matchers/000077500000000000000000000000001214434061600157435ustar00rootroot00000000000000mail-2.5.4/lib/mail/matchers/has_sent_mail.rb000066400000000000000000000063471214434061600211100ustar00rootroot00000000000000module Mail module Matchers def have_sent_email HasSentEmailMatcher.new(self) end class HasSentEmailMatcher def initialize(_context) end def matches?(subject) matching_deliveries = filter_matched_deliveries(Mail::TestMailer.deliveries) !(matching_deliveries.empty?) end def from(sender) @sender = sender self end def to(recipient_or_list) @recipients ||= [] if recipient_or_list.kind_of?(Array) @recipients += recipient_or_list else @recipients << recipient_or_list end self end def with_subject(subject) @subject = subject self end def matching_subject(subject_matcher) @subject_matcher = subject_matcher self end def with_body(body) @body = body self end def matching_body(body_matcher) @body_matcher = body_matcher self end def description result = "send a matching email" result end def failure_message result = "Expected email to be sent " result += explain_expectations result += dump_deliveries result end def negative_failure_message result = "Expected no email to be sent " result += explain_expectations result += dump_deliveries result end protected def filter_matched_deliveries(deliveries) candidate_deliveries = deliveries %w(sender recipients subject subject_matcher body body_matcher).each do |modifier_name| next unless instance_variable_defined?("@#{modifier_name}") candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)} end candidate_deliveries end def matches_on_sender?(delivery) delivery.from.include?(@sender) end def matches_on_recipients?(delivery) @recipients.all? {|recipient| delivery.to.include?(recipient) } end def matches_on_subject?(delivery) delivery.subject == @subject end def matches_on_subject_matcher?(delivery) @subject_matcher.match delivery.subject end def matches_on_body?(delivery) delivery.body == @body end def matches_on_body_matcher?(delivery) @body_matcher.match delivery.body.raw_source end def explain_expectations result = '' result += "from #{@sender} " if instance_variable_defined?('@sender') result += "to #{@recipients.inspect} " if instance_variable_defined?('@recipients') result += "with subject \"#{@subject}\" " if instance_variable_defined?('@subject') result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher') result += "with body \"#{@body}\" " if instance_variable_defined?('@body') result += "with body matching \"#{@body_matcher}\" " if instance_variable_defined?('@body_matcher') result end def dump_deliveries "(actual deliveries: " + Mail::TestMailer.deliveries.inspect + ")" end end end end mail-2.5.4/lib/mail/message.rb000066400000000000000000002050531214434061600161130ustar00rootroot00000000000000# encoding: utf-8 require "yaml" module Mail # The Message class provides a single point of access to all things to do with an # email message. # # You create a new email message by calling the Mail::Message.new method, or just # Mail.new # # A Message object by default has the following objects inside it: # # * A Header object which contains all information and settings of the header of the email # * Body object which contains all parts of the email that are not part of the header, this # includes any attachments, body text, MIME parts etc. # # ==Per RFC2822 # # 2.1. General Description # # At the most basic level, a message is a series of characters. A # message that is conformant with this standard is comprised of # characters with values in the range 1 through 127 and interpreted as # US-ASCII characters [ASCII]. For brevity, this document sometimes # refers to this range of characters as simply "US-ASCII characters". # # Note: This standard specifies that messages are made up of characters # in the US-ASCII range of 1 through 127. There are other documents, # specifically the MIME document series [RFC2045, RFC2046, RFC2047, # RFC2048, RFC2049], that extend this standard to allow for values # outside of that range. Discussion of those mechanisms is not within # the scope of this standard. # # Messages are divided into lines of characters. A line is a series of # characters that is delimited with the two characters carriage-return # and line-feed; that is, the carriage return (CR) character (ASCII # value 13) followed immediately by the line feed (LF) character (ASCII # value 10). (The carriage-return/line-feed pair is usually written in # this document as "CRLF".) # # A message consists of header fields (collectively called "the header # of the message") followed, optionally, by a body. The header is a # sequence of lines of characters with special syntax as defined in # this standard. The body is simply a sequence of characters that # follows the header and is separated from the header by an empty line # (i.e., a line with nothing preceding the CRLF). class Message include Patterns include Utilities # ==Making an email # # You can make an new mail object via a block, passing a string, file or direct assignment. # # ===Making an email via a block # # mail = Mail.new do # from 'mikel@test.lindsaar.net' # to 'you@test.lindsaar.net' # subject 'This is a test email' # body File.read('body.txt') # end # # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@... # # ===Making an email via passing a string # # mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!") # mail.body.to_s #=> 'Hi there!' # mail.subject #=> 'Hello' # mail.to #=> 'mikel@test.lindsaar.net' # # ===Making an email from a file # # mail = Mail.read('path/to/file.eml') # mail.body.to_s #=> 'Hi there!' # mail.subject #=> 'Hello' # mail.to #=> 'mikel@test.lindsaar.net' # # ===Making an email via assignment # # You can assign values to a mail object via four approaches: # # * Message#field_name=(value) # * Message#field_name(value) # * Message#['field_name']=(value) # * Message#[:field_name]=(value) # # Examples: # # mail = Mail.new # mail['from'] = 'mikel@test.lindsaar.net' # mail[:to] = 'you@test.lindsaar.net' # mail.subject 'This is a test email' # mail.body = 'This is a body' # # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@... # def initialize(*args, &block) @body = nil @body_raw = nil @separate_parts = false @text_part = nil @html_part = nil @errors = nil @header = nil @charset = 'UTF-8' @defaulted_charset = true @smtp_envelope_from = nil @smtp_envelope_to = nil @perform_deliveries = true @raise_delivery_errors = true @delivery_handler = nil @delivery_method = Mail.delivery_method.dup @transport_encoding = Mail::Encodings.get_encoding('7bit') @mark_for_delete = false if args.flatten.first.respond_to?(:each_pair) init_with_hash(args.flatten.first) else init_with_string(args.flatten[0].to_s) end if block_given? instance_eval(&block) end self end # If you assign a delivery handler, mail will call :deliver_mail on the # object you assign to delivery_handler, it will pass itself as the # single argument. # # If you define a delivery_handler, then you are responsible for the # following actions in the delivery cycle: # # * Appending the mail object to Mail.deliveries as you see fit. # * Checking the mail.perform_deliveries flag to decide if you should # actually call :deliver! the mail object or not. # * Checking the mail.raise_delivery_errors flag to decide if you # should raise delivery errors if they occur. # * Actually calling :deliver! (with the bang) on the mail object to # get it to deliver itself. # # A simplest implementation of a delivery_handler would be # # class MyObject # # def initialize # @mail = Mail.new('To: mikel@test.lindsaar.net') # @mail.delivery_handler = self # end # # attr_accessor :mail # # def deliver_mail(mail) # yield # end # end # # Then doing: # # obj = MyObject.new # obj.mail.deliver # # Would cause Mail to call obj.deliver_mail passing itself as a parameter, # which then can just yield and let Mail do its own private do_delivery # method. attr_accessor :delivery_handler # If set to false, mail will go through the motions of doing a delivery, # but not actually call the delivery method or append the mail object to # the Mail.deliveries collection. Useful for testing. # # Mail.deliveries.size #=> 0 # mail.delivery_method :smtp # mail.perform_deliveries = false # mail.deliver # Mail::SMTP not called here # Mail.deliveries.size #=> 0 # # If you want to test and query the Mail.deliveries collection to see what # mail you sent, you should set perform_deliveries to true and use # the :test mail delivery_method: # # Mail.deliveries.size #=> 0 # mail.delivery_method :test # mail.perform_deliveries = true # mail.deliver # Mail.deliveries.size #=> 1 # # This setting is ignored by mail (though still available as a flag) if you # define a delivery_handler attr_accessor :perform_deliveries # If set to false, mail will silently catch and ignore any exceptions # raised through attempting to deliver an email. # # This setting is ignored by mail (though still available as a flag) if you # define a delivery_handler attr_accessor :raise_delivery_errors def register_for_delivery_notification(observer) STDERR.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead") Mail.register_observer(observer) end def inform_observers Mail.inform_observers(self) end def inform_interceptors Mail.inform_interceptors(self) end # Delivers an mail object. # # Examples: # # mail = Mail.read('file.eml') # mail.deliver def deliver inform_interceptors if delivery_handler delivery_handler.deliver_mail(self) { do_delivery } else do_delivery end inform_observers self end # This method bypasses checking perform_deliveries and raise_delivery_errors, # so use with caution. # # It still however fires off the intercepters and calls the observers callbacks if they are defined. # # Returns self def deliver! inform_interceptors response = delivery_method.deliver!(self) inform_observers delivery_method.settings[:return_response] ? response : self end def delivery_method(method = nil, settings = {}) unless method @delivery_method else @delivery_method = Configuration.instance.lookup_delivery_method(method).new(settings) end end def reply(*args, &block) self.class.new.tap do |reply| if message_id bracketed_message_id = "<#{message_id}>" reply.in_reply_to = bracketed_message_id if !references.nil? refs = [references].flatten.map { |r| "<#{r}>" } refs << bracketed_message_id reply.references = refs.join(' ') elsif !in_reply_to.nil? && !in_reply_to.kind_of?(Array) reply.references = "<#{in_reply_to}> #{bracketed_message_id}" end reply.references ||= bracketed_message_id end if subject reply.subject = subject =~ /^Re:/i ? subject : "RE: #{subject}" end if reply_to || from reply.to = self[reply_to ? :reply_to : :from].to_s end if to reply.from = self[:to].formatted.first.to_s end unless args.empty? if args.flatten.first.respond_to?(:each_pair) reply.send(:init_with_hash, args.flatten.first) else reply.send(:init_with_string, args.flatten[0].to_s.strip) end end if block_given? reply.instance_eval(&block) end end end # Provides the operator needed for sort et al. # # Compares this mail object with another mail object, this is done by date, so an # email that is older than another will appear first. # # Example: # # mail1 = Mail.new do # date(Time.now) # end # mail2 = Mail.new do # date(Time.now - 86400) # 1 day older # end # [mail2, mail1].sort #=> [mail2, mail1] def <=>(other) if other.nil? 1 else self.date <=> other.date end end # Two emails are the same if they have the same fields and body contents. One # gotcha here is that Mail will insert Message-IDs when calling encoded, so doing # mail1.encoded == mail2.encoded is most probably not going to return what you think # as the assigned Message-IDs by Mail (if not already defined as the same) will ensure # that the two objects are unique, and this comparison will ALWAYS return false. # # So the == operator has been defined like so: Two messages are the same if they have # the same content, ignoring the Message-ID field, unless BOTH emails have a defined and # different Message-ID value, then they are false. # # So, in practice the == operator works like this: # # m1 = Mail.new("Subject: Hello\r\n\r\nHello") # m2 = Mail.new("Subject: Hello\r\n\r\nHello") # m1 == m2 #=> true # # m1 = Mail.new("Subject: Hello\r\n\r\nHello") # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello") # m1 == m2 #=> true # # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello") # m2 = Mail.new("Subject: Hello\r\n\r\nHello") # m1 == m2 #=> true # # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello") # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello") # m1 == m2 #=> true # # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello") # m2 = Mail.new("Message-ID: \r\nSubject: Hello\r\n\r\nHello") # m1 == m2 #=> false def ==(other) return false unless other.respond_to?(:encoded) if self.message_id && other.message_id result = (self.encoded == other.encoded) else self_message_id, other_message_id = self.message_id, other.message_id self.message_id, other.message_id = '', '' result = self.encoded == other.encoded self.message_id = "<#{self_message_id}>" if self_message_id other.message_id = "<#{other_message_id}>" if other_message_id result end end # Provides access to the raw source of the message as it was when it # was instantiated. This is set at initialization and so is untouched # by the parsers or decoder / encoders # # Example: # # mail = Mail.new('This is an invalid email message') # mail.raw_source #=> "This is an invalid email message" def raw_source @raw_source end # Sets the envelope from for the email def set_envelope( val ) @raw_envelope = val @envelope = Mail::Envelope.new( val ) end # The raw_envelope is the From mikel@test.lindsaar.net Mon May 2 16:07:05 2009 # type field that you can see at the top of any email that has come # from a mailbox def raw_envelope @raw_envelope end def envelope_from @envelope ? @envelope.from : nil end def envelope_date @envelope ? @envelope.date : nil end # Sets the header of the message object. # # Example: # # mail.header = 'To: mikel@test.lindsaar.net\r\nFrom: Bob@bob.com' # mail.header #=> <#Mail::Header def header=(value) @header = Mail::Header.new(value, charset) end # Returns the header object of the message object. Or, if passed # a parameter sets the value. # # Example: # # mail = Mail::Message.new('To: mikel\r\nFrom: you') # mail.header #=> # 1 # message.errors.first[0] #=> "Content-Transfer-Encoding" # message.errors.first[1] #=> "weirdo" # message.errors.first[3] #=> # # This is a good first defence on detecting spam by the way. Some spammers send # invalid emails to try and get email parsers to give up parsing them. def errors header.errors end # Returns the Bcc value of the mail object as an array of strings of # address specs. # # Example: # # mail.bcc = 'Mikel ' # mail.bcc #=> ['mikel@test.lindsaar.net'] # mail.bcc = 'Mikel , ada@test.lindsaar.net' # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.bcc 'Mikel ' # mail.bcc #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.bcc 'Mikel ' # mail.bcc << 'ada@test.lindsaar.net' # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def bcc( val = nil ) default :bcc, val end # Sets the Bcc value of the mail object, pass in a string of the field # # Example: # # mail.bcc = 'Mikel ' # mail.bcc #=> ['mikel@test.lindsaar.net'] # mail.bcc = 'Mikel , ada@test.lindsaar.net' # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def bcc=( val ) header[:bcc] = val end # Returns the Cc value of the mail object as an array of strings of # address specs. # # Example: # # mail.cc = 'Mikel ' # mail.cc #=> ['mikel@test.lindsaar.net'] # mail.cc = 'Mikel , ada@test.lindsaar.net' # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.cc 'Mikel ' # mail.cc #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.cc 'Mikel ' # mail.cc << 'ada@test.lindsaar.net' # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def cc( val = nil ) default :cc, val end # Sets the Cc value of the mail object, pass in a string of the field # # Example: # # mail.cc = 'Mikel ' # mail.cc #=> ['mikel@test.lindsaar.net'] # mail.cc = 'Mikel , ada@test.lindsaar.net' # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def cc=( val ) header[:cc] = val end def comments( val = nil ) default :comments, val end def comments=( val ) header[:comments] = val end def content_description( val = nil ) default :content_description, val end def content_description=( val ) header[:content_description] = val end def content_disposition( val = nil ) default :content_disposition, val end def content_disposition=( val ) header[:content_disposition] = val end def content_id( val = nil ) default :content_id, val end def content_id=( val ) header[:content_id] = val end def content_location( val = nil ) default :content_location, val end def content_location=( val ) header[:content_location] = val end def content_transfer_encoding( val = nil ) default :content_transfer_encoding, val end def content_transfer_encoding=( val ) header[:content_transfer_encoding] = val end def content_type( val = nil ) default :content_type, val end def content_type=( val ) header[:content_type] = val end def date( val = nil ) default :date, val end def date=( val ) header[:date] = val end def transport_encoding( val = nil) if val self.transport_encoding = val else @transport_encoding end end def transport_encoding=( val ) @transport_encoding = Mail::Encodings.get_encoding(val) end # Returns the From value of the mail object as an array of strings of # address specs. # # Example: # # mail.from = 'Mikel ' # mail.from #=> ['mikel@test.lindsaar.net'] # mail.from = 'Mikel , ada@test.lindsaar.net' # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.from 'Mikel ' # mail.from #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.from 'Mikel ' # mail.from << 'ada@test.lindsaar.net' # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def from( val = nil ) default :from, val end # Sets the From value of the mail object, pass in a string of the field # # Example: # # mail.from = 'Mikel ' # mail.from #=> ['mikel@test.lindsaar.net'] # mail.from = 'Mikel , ada@test.lindsaar.net' # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def from=( val ) header[:from] = val end def in_reply_to( val = nil ) default :in_reply_to, val end def in_reply_to=( val ) header[:in_reply_to] = val end def keywords( val = nil ) default :keywords, val end def keywords=( val ) header[:keywords] = val end # Returns the Message-ID of the mail object. Note, per RFC 2822 the Message ID # consists of what is INSIDE the < > usually seen in the mail header, so this method # will return only what is inside. # # Example: # # mail.message_id = '<1234@message.id>' # mail.message_id #=> '1234@message.id' # # Also allows you to set the Message-ID by passing a string as a parameter # # mail.message_id '<1234@message.id>' # mail.message_id #=> '1234@message.id' def message_id( val = nil ) default :message_id, val end # Sets the Message-ID. Note, per RFC 2822 the Message ID consists of what is INSIDE # the < > usually seen in the mail header, so this method will return only what is inside. # # mail.message_id = '<1234@message.id>' # mail.message_id #=> '1234@message.id' def message_id=( val ) header[:message_id] = val end # Returns the MIME version of the email as a string # # Example: # # mail.mime_version = '1.0' # mail.mime_version #=> '1.0' # # Also allows you to set the MIME version by passing a string as a parameter. # # Example: # # mail.mime_version '1.0' # mail.mime_version #=> '1.0' def mime_version( val = nil ) default :mime_version, val end # Sets the MIME version of the email by accepting a string # # Example: # # mail.mime_version = '1.0' # mail.mime_version #=> '1.0' def mime_version=( val ) header[:mime_version] = val end def received( val = nil ) if val header[:received] = val else header[:received] end end def received=( val ) header[:received] = val end def references( val = nil ) default :references, val end def references=( val ) header[:references] = val end # Returns the Reply-To value of the mail object as an array of strings of # address specs. # # Example: # # mail.reply_to = 'Mikel ' # mail.reply_to #=> ['mikel@test.lindsaar.net'] # mail.reply_to = 'Mikel , ada@test.lindsaar.net' # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.reply_to 'Mikel ' # mail.reply_to #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.reply_to 'Mikel ' # mail.reply_to << 'ada@test.lindsaar.net' # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def reply_to( val = nil ) default :reply_to, val end # Sets the Reply-To value of the mail object, pass in a string of the field # # Example: # # mail.reply_to = 'Mikel ' # mail.reply_to #=> ['mikel@test.lindsaar.net'] # mail.reply_to = 'Mikel , ada@test.lindsaar.net' # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def reply_to=( val ) header[:reply_to] = val end # Returns the Resent-Bcc value of the mail object as an array of strings of # address specs. # # Example: # # mail.resent_bcc = 'Mikel ' # mail.resent_bcc #=> ['mikel@test.lindsaar.net'] # mail.resent_bcc = 'Mikel , ada@test.lindsaar.net' # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.resent_bcc 'Mikel ' # mail.resent_bcc #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.resent_bcc 'Mikel ' # mail.resent_bcc << 'ada@test.lindsaar.net' # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_bcc( val = nil ) default :resent_bcc, val end # Sets the Resent-Bcc value of the mail object, pass in a string of the field # # Example: # # mail.resent_bcc = 'Mikel ' # mail.resent_bcc #=> ['mikel@test.lindsaar.net'] # mail.resent_bcc = 'Mikel , ada@test.lindsaar.net' # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_bcc=( val ) header[:resent_bcc] = val end # Returns the Resent-Cc value of the mail object as an array of strings of # address specs. # # Example: # # mail.resent_cc = 'Mikel ' # mail.resent_cc #=> ['mikel@test.lindsaar.net'] # mail.resent_cc = 'Mikel , ada@test.lindsaar.net' # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.resent_cc 'Mikel ' # mail.resent_cc #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.resent_cc 'Mikel ' # mail.resent_cc << 'ada@test.lindsaar.net' # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_cc( val = nil ) default :resent_cc, val end # Sets the Resent-Cc value of the mail object, pass in a string of the field # # Example: # # mail.resent_cc = 'Mikel ' # mail.resent_cc #=> ['mikel@test.lindsaar.net'] # mail.resent_cc = 'Mikel , ada@test.lindsaar.net' # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_cc=( val ) header[:resent_cc] = val end def resent_date( val = nil ) default :resent_date, val end def resent_date=( val ) header[:resent_date] = val end # Returns the Resent-From value of the mail object as an array of strings of # address specs. # # Example: # # mail.resent_from = 'Mikel ' # mail.resent_from #=> ['mikel@test.lindsaar.net'] # mail.resent_from = 'Mikel , ada@test.lindsaar.net' # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.resent_from ['Mikel '] # mail.resent_from #=> 'mikel@test.lindsaar.net' # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.resent_from 'Mikel ' # mail.resent_from << 'ada@test.lindsaar.net' # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_from( val = nil ) default :resent_from, val end # Sets the Resent-From value of the mail object, pass in a string of the field # # Example: # # mail.resent_from = 'Mikel ' # mail.resent_from #=> ['mikel@test.lindsaar.net'] # mail.resent_from = 'Mikel , ada@test.lindsaar.net' # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_from=( val ) header[:resent_from] = val end def resent_message_id( val = nil ) default :resent_message_id, val end def resent_message_id=( val ) header[:resent_message_id] = val end # Returns the Resent-Sender value of the mail object, as a single string of an address # spec. A sender per RFC 2822 must be a single address, so you can not append to # this address. # # Example: # # mail.resent_sender = 'Mikel ' # mail.resent_sender #=> 'mikel@test.lindsaar.net' # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.resent_sender 'Mikel ' # mail.resent_sender #=> 'mikel@test.lindsaar.net' def resent_sender( val = nil ) default :resent_sender, val end # Sets the Resent-Sender value of the mail object, pass in a string of the field # # Example: # # mail.resent_sender = 'Mikel ' # mail.resent_sender #=> 'mikel@test.lindsaar.net' def resent_sender=( val ) header[:resent_sender] = val end # Returns the Resent-To value of the mail object as an array of strings of # address specs. # # Example: # # mail.resent_to = 'Mikel ' # mail.resent_to #=> ['mikel@test.lindsaar.net'] # mail.resent_to = 'Mikel , ada@test.lindsaar.net' # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.resent_to 'Mikel ' # mail.resent_to #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.resent_to 'Mikel ' # mail.resent_to << 'ada@test.lindsaar.net' # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_to( val = nil ) default :resent_to, val end # Sets the Resent-To value of the mail object, pass in a string of the field # # Example: # # mail.resent_to = 'Mikel ' # mail.resent_to #=> ['mikel@test.lindsaar.net'] # mail.resent_to = 'Mikel , ada@test.lindsaar.net' # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def resent_to=( val ) header[:resent_to] = val end # Returns the return path of the mail object, or sets it if you pass a string def return_path( val = nil ) default :return_path, val end # Sets the return path of the object def return_path=( val ) header[:return_path] = val end # Returns the Sender value of the mail object, as a single string of an address # spec. A sender per RFC 2822 must be a single address. # # Example: # # mail.sender = 'Mikel ' # mail.sender #=> 'mikel@test.lindsaar.net' # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.sender 'Mikel ' # mail.sender #=> 'mikel@test.lindsaar.net' def sender( val = nil ) default :sender, val end # Sets the Sender value of the mail object, pass in a string of the field # # Example: # # mail.sender = 'Mikel ' # mail.sender #=> 'mikel@test.lindsaar.net' def sender=( val ) header[:sender] = val end # Returns the SMTP Envelope From value of the mail object, as a single # string of an address spec. # # Defaults to Return-Path, Sender, or the first From address. # # Example: # # mail.smtp_envelope_from = 'Mikel ' # mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net' # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.smtp_envelope_from 'Mikel ' # mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net' def smtp_envelope_from( val = nil ) if val self.smtp_envelope_from = val else @smtp_envelope_from || return_path || sender || from_addrs.first end end # Sets the From address on the SMTP Envelope. # # Example: # # mail.smtp_envelope_from = 'Mikel ' # mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net' def smtp_envelope_from=( val ) @smtp_envelope_from = val end # Returns the SMTP Envelope To value of the mail object. # # Defaults to #destinations: To, Cc, and Bcc addresses. # # Example: # # mail.smtp_envelope_to = 'Mikel ' # mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net' # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.smtp_envelope_to ['Mikel ', 'Lindsaar '] # mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net'] def smtp_envelope_to( val = nil ) if val self.smtp_envelope_to = val else @smtp_envelope_to || destinations end end # Sets the To addresses on the SMTP Envelope. # # Example: # # mail.smtp_envelope_to = 'Mikel ' # mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net' # # mail.smtp_envelope_to = ['Mikel ', 'Lindsaar '] # mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net'] def smtp_envelope_to=( val ) @smtp_envelope_to = case val when Array, NilClass val else [val] end end # Returns the decoded value of the subject field, as a single string. # # Example: # # mail.subject = "G'Day mate" # mail.subject #=> "G'Day mate" # mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?=' # mail.subject #=> "This is あ string" # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.subject "G'Day mate" # mail.subject #=> "G'Day mate" def subject( val = nil ) default :subject, val end # Sets the Subject value of the mail object, pass in a string of the field # # Example: # # mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?=' # mail.subject #=> "This is あ string" def subject=( val ) header[:subject] = val end # Returns the To value of the mail object as an array of strings of # address specs. # # Example: # # mail.to = 'Mikel ' # mail.to #=> ['mikel@test.lindsaar.net'] # mail.to = 'Mikel , ada@test.lindsaar.net' # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] # # Also allows you to set the value by passing a value as a parameter # # Example: # # mail.to 'Mikel ' # mail.to #=> ['mikel@test.lindsaar.net'] # # Additionally, you can append new addresses to the returned Array like # object. # # Example: # # mail.to 'Mikel ' # mail.to << 'ada@test.lindsaar.net' # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def to( val = nil ) default :to, val end # Sets the To value of the mail object, pass in a string of the field # # Example: # # mail.to = 'Mikel ' # mail.to #=> ['mikel@test.lindsaar.net'] # mail.to = 'Mikel , ada@test.lindsaar.net' # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] def to=( val ) header[:to] = val end # Returns the default value of the field requested as a symbol. # # Each header field has a :default method which returns the most common use case for # that field, for example, the date field types will return a DateTime object when # sent :default, the subject, or unstructured fields will return a decoded string of # their value, the address field types will return a single addr_spec or an array of # addr_specs if there is more than one. def default( sym, val = nil ) if val header[sym] = val else header[sym].default if header[sym] end end # Sets the body object of the message object. # # Example: # # mail.body = 'This is the body' # mail.body #=> # 2 # mail.parts.last.content_type.content_type #=> 'This is a body' def body=(value) body_lazy(value) end # Returns the body of the message object. Or, if passed # a parameter sets the value. # # Example: # # mail = Mail::Message.new('To: mikel\r\n\r\nThis is the body') # mail.body #=> # 3 # mail.destinations.first #=> 'mikel@test.lindsaar.net' def destinations [to_addrs, cc_addrs, bcc_addrs].compact.flatten end # Returns an array of addresses (the encoded value) in the From field, # if no From field, returns an empty array def from_addrs from ? [from].flatten : [] end # Returns an array of addresses (the encoded value) in the To field, # if no To field, returns an empty array def to_addrs to ? [to].flatten : [] end # Returns an array of addresses (the encoded value) in the Cc field, # if no Cc field, returns an empty array def cc_addrs cc ? [cc].flatten : [] end # Returns an array of addresses (the encoded value) in the Bcc field, # if no Bcc field, returns an empty array def bcc_addrs bcc ? [bcc].flatten : [] end # Allows you to add an arbitrary header # # Example: # # mail['foo'] = '1234' # mail['foo'].to_s #=> '1234' def []=(name, value) if name.to_s == 'body' self.body = value elsif name.to_s =~ /content[-_]type/i header[name] = value elsif name.to_s == 'charset' self.charset = value else header[name] = value end end # Allows you to read an arbitrary header # # Example: # # mail['foo'] = '1234' # mail['foo'].to_s #=> '1234' def [](name) header[underscoreize(name)] end # Method Missing in this implementation allows you to set any of the # standard fields directly as you would the "to", "subject" etc. # # Those fields used most often (to, subject et al) are given their # own method for ease of documentation and also to avoid the hook # call to method missing. # # This will only catch the known fields listed in: # # Mail::Field::KNOWN_FIELDS # # as per RFC 2822, any ruby string or method name could pretty much # be a field name, so we don't want to just catch ANYTHING sent to # a message object and interpret it as a header. # # This method provides all three types of header call to set, read # and explicitly set with the = operator # # Examples: # # mail.comments = 'These are some comments' # mail.comments #=> 'These are some comments' # # mail.comments 'These are other comments' # mail.comments #=> 'These are other comments' # # # mail.date = 'Tue, 1 Jul 2003 10:52:37 +0200' # mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200' # # mail.date 'Tue, 1 Jul 2003 10:52:37 +0200' # mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200' # # # mail.resent_msg_id = '<1234@resent_msg_id.lindsaar.net>' # mail.resent_msg_id #=> '<1234@resent_msg_id.lindsaar.net>' # # mail.resent_msg_id '<4567@resent_msg_id.lindsaar.net>' # mail.resent_msg_id #=> '<4567@resent_msg_id.lindsaar.net>' def method_missing(name, *args, &block) #:nodoc: # Only take the structured fields, as we could take _anything_ really # as it could become an optional field... "but therin lies the dark side" field_name = underscoreize(name).chomp("=") if Mail::Field::KNOWN_FIELDS.include?(field_name) if args.empty? header[field_name] else header[field_name] = args.first end else super # otherwise pass it on end #:startdoc: end # Returns an FieldList of all the fields in the header in the order that # they appear in the header def header_fields header.fields end # Returns true if the message has a message ID field, the field may or may # not have a value, but the field exists or not. def has_message_id? header.has_message_id? end # Returns true if the message has a Date field, the field may or may # not have a value, but the field exists or not. def has_date? header.has_date? end # Returns true if the message has a Date field, the field may or may # not have a value, but the field exists or not. def has_mime_version? header.has_mime_version? end def has_content_type? tmp = header[:content_type].main_type rescue nil !!tmp end def has_charset? tmp = header[:content_type].parameters rescue nil !!(has_content_type? && tmp && tmp['charset']) end def has_content_transfer_encoding? header[:content_transfer_encoding] && header[:content_transfer_encoding].errors.blank? end def has_transfer_encoding? # :nodoc: STDERR.puts(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}") has_content_transfer_encoding? end # Creates a new empty Message-ID field and inserts it in the correct order # into the Header. The MessageIdField object will automatically generate # a unique message ID if you try and encode it or output it to_s without # specifying a message id. # # It will preserve the message ID you specify if you do. def add_message_id(msg_id_val = '') header['message-id'] = msg_id_val end # Creates a new empty Date field and inserts it in the correct order # into the Header. The DateField object will automatically generate # DateTime.now's date if you try and encode it or output it to_s without # specifying a date yourself. # # It will preserve any date you specify if you do. def add_date(date_val = '') header['date'] = date_val end # Creates a new empty Mime Version field and inserts it in the correct order # into the Header. The MimeVersion object will automatically generate # set itself to '1.0' if you try and encode it or output it to_s without # specifying a version yourself. # # It will preserve any date you specify if you do. def add_mime_version(ver_val = '') header['mime-version'] = ver_val end # Adds a content type and charset if the body is US-ASCII # # Otherwise raises a warning def add_content_type header[:content_type] = 'text/plain' end # Adds a content type and charset if the body is US-ASCII # # Otherwise raises a warning def add_charset if !body.empty? # Only give a warning if this isn't an attachment, has non US-ASCII and the user # has not specified an encoding explicitly. if @defaulted_charset && body.raw_source.not_ascii_only? && !self.attachment? warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n" STDERR.puts(warning) end header[:content_type].parameters['charset'] = @charset end end # Adds a content transfer encoding # # Otherwise raises a warning def add_content_transfer_encoding if body.only_us_ascii? header[:content_transfer_encoding] = '7bit' else warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n" STDERR.puts(warning) header[:content_transfer_encoding] = '8bit' end end def add_transfer_encoding # :nodoc: STDERR.puts(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}") add_content_transfer_encoding end def transfer_encoding # :nodoc: STDERR.puts(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}") content_transfer_encoding end # Returns the MIME media type of part we are on, this is taken from the content-type header def mime_type has_content_type? ? header[:content_type].string : nil rescue nil end def message_content_type STDERR.puts(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}") mime_type end # Returns the character set defined in the content type field def charset if @header has_content_type? ? content_type_parameters['charset'] : @charset else @charset end end # Sets the charset to the supplied value. def charset=(value) @defaulted_charset = false @charset = value @header.charset = value end # Returns the main content type def main_type has_content_type? ? header[:content_type].main_type : nil rescue nil end # Returns the sub content type def sub_type has_content_type? ? header[:content_type].sub_type : nil rescue nil end # Returns the content type parameters def mime_parameters STDERR.puts(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead') content_type_parameters end # Returns the content type parameters def content_type_parameters has_content_type? ? header[:content_type].parameters : nil rescue nil end # Returns true if the message is multipart def multipart? has_content_type? ? !!(main_type =~ /^multipart$/i) : false end # Returns true if the message is a multipart/report def multipart_report? multipart? && sub_type =~ /^report$/i end # Returns true if the message is a multipart/report; report-type=delivery-status; def delivery_status_report? multipart_report? && content_type_parameters['report-type'] =~ /^delivery-status$/i end # returns the part in a multipart/report email that has the content-type delivery-status def delivery_status_part @delivery_stats_part ||= parts.select { |p| p.delivery_status_report_part? }.first end def bounced? delivery_status_part and delivery_status_part.bounced? end def action delivery_status_part and delivery_status_part.action end def final_recipient delivery_status_part and delivery_status_part.final_recipient end def error_status delivery_status_part and delivery_status_part.error_status end def diagnostic_code delivery_status_part and delivery_status_part.diagnostic_code end def remote_mta delivery_status_part and delivery_status_part.remote_mta end def retryable? delivery_status_part and delivery_status_part.retryable? end # Returns the current boundary for this message part def boundary content_type_parameters ? content_type_parameters['boundary'] : nil end # Returns a parts list object of all the parts in the message def parts body.parts end # Returns an AttachmentsList object, which holds all of the attachments in # the receiver object (either the entier email or a part within) and all # of its descendants. # # It also allows you to add attachments to the mail object directly, like so: # # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg') # # If you do this, then Mail will take the file name and work out the MIME media type # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and # base64 encode the contents of the attachment all for you. # # You can also specify overrides if you want by passing a hash instead of a string: # # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', # :content => File.read('/path/to/filename.jpg')} # # If you want to use a different encoding than Base64, you can pass an encoding in, # but then it is up to you to pass in the content pre-encoded, and don't expect # Mail to know how to decode this data: # # file_content = SpecialEncode(File.read('/path/to/filename.jpg')) # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip', # :encoding => 'SpecialEncoding', # :content => file_content } # # You can also search for specific attachments: # # # By Filename # mail.attachments['filename.jpg'] #=> Mail::Part object or nil # # # or by index # mail.attachments[0] #=> Mail::Part (first attachment) # def attachments parts.attachments end def has_attachments? !attachments.empty? end # Accessor for html_part def html_part(&block) if block_given? self.html_part = Mail::Part.new(:content_type => 'text/html', &block) else @html_part || find_first_mime_type('text/html') end end # Accessor for text_part def text_part(&block) if block_given? self.text_part = Mail::Part.new(:content_type => 'text/plain', &block) else @text_part || find_first_mime_type('text/plain') end end # Helper to add a html part to a multipart/alternative email. If this and # text_part are both defined in a message, then it will be a multipart/alternative # message and set itself that way. def html_part=(msg) # Assign the html part and set multipart/alternative if there's a text part. if msg @html_part = msg @html_part.content_type = 'text/html' unless @html_part.has_content_type? add_multipart_alternate_header if text_part add_part @html_part # If nil, delete the html part and back out of multipart/alternative. elsif @html_part parts.delete_if { |p| p.object_id == @html_part.object_id } @html_part = nil if text_part self.content_type = nil body.boundary = nil end end end # Helper to add a text part to a multipart/alternative email. If this and # html_part are both defined in a message, then it will be a multipart/alternative # message and set itself that way. def text_part=(msg) # Assign the text part and set multipart/alternative if there's an html part. if msg @text_part = msg @text_part.content_type = 'text/plain' unless @text_part.has_content_type? add_multipart_alternate_header if html_part add_part @text_part # If nil, delete the text part and back out of multipart/alternative. elsif @text_part parts.delete_if { |p| p.object_id == @text_part.object_id } @text_part = nil if html_part self.content_type = nil body.boundary = nil end end end # Adds a part to the parts list or creates the part list def add_part(part) if !body.multipart? && !self.body.decoded.blank? @text_part = Mail::Part.new('Content-Type: text/plain;') @text_part.body = body.decoded self.body << @text_part add_multipart_alternate_header end add_boundary self.body << part end # Allows you to add a part in block form to an existing mail message object # # Example: # # mail = Mail.new do # part :content_type => "multipart/alternative", :content_disposition => "inline" do |p| # p.part :content_type => "text/plain", :body => "test text\nline #2" # p.part :content_type => "text/html", :body => "test HTML
\nline #2" # end # end def part(params = {}) new_part = Part.new(params) yield new_part if block_given? add_part(new_part) end # Adds a file to the message. You have two options with this method, you can # just pass in the absolute path to the file you want and Mail will read the file, # get the filename from the path you pass in and guess the MIME media type, or you # can pass in the filename as a string, and pass in the file content as a blob. # # Example: # # m = Mail.new # m.add_file('/path/to/filename.png') # # m = Mail.new # m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg')) # # Note also that if you add a file to an existing message, Mail will convert that message # to a MIME multipart email, moving whatever plain text body you had into its own text # plain part. # # Example: # # m = Mail.new do # body 'this is some text' # end # m.multipart? #=> false # m.add_file('/path/to/filename.png') # m.multipart? #=> true # m.parts.first.content_type.content_type #=> 'text/plain' # m.parts.last.content_type.content_type #=> 'image/png' # # See also #attachments def add_file(values) convert_to_multipart unless self.multipart? || self.body.decoded.blank? add_multipart_mixed_header if values.is_a?(String) basename = File.basename(values) filedata = File.open(values, 'rb') { |f| f.read } else basename = values[:filename] filedata = values[:content] || File.open(values[:filename], 'rb') { |f| f.read } end self.attachments[basename] = filedata end def convert_to_multipart text = body.decoded self.body = '' text_part = Mail::Part.new({:content_type => 'text/plain;', :body => text}) text_part.charset = charset unless @defaulted_charset self.body << text_part end # Encodes the message, calls encode on all its parts, gets an email message # ready to send def ready_to_send! identify_and_set_transfer_encoding parts.sort!([ "text/plain", "text/enriched", "text/html", "multipart/alternative" ]) parts.each do |part| part.transport_encoding = transport_encoding part.ready_to_send! end add_required_fields end def encode! STDERR.puts("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.") ready_to_send! end # Outputs an encoded string representation of the mail message including # all headers, attachments, etc. This is an encoded email in US-ASCII, # so it is able to be directly sent to an email server. def encoded ready_to_send! buffer = header.encoded buffer << "\r\n" buffer << body.encoded(content_transfer_encoding) buffer end def without_attachments! return self unless has_attachments? parts.delete_if { |p| p.attachment? } body_raw = if parts.empty? '' else body.encoded end @body = Mail::Body.new(body_raw) self end def to_yaml(opts = {}) hash = {} hash['headers'] = {} header.fields.each do |field| hash['headers'][field.name] = field.value end hash['delivery_handler'] = delivery_handler.to_s if delivery_handler hash['transport_encoding'] = transport_encoding.to_s special_variables = [:@header, :@delivery_handler, :@transport_encoding] if multipart? hash['multipart_body'] = [] body.parts.map { |part| hash['multipart_body'] << part.to_yaml } special_variables.push(:@body, :@text_part, :@html_part) end (instance_variables.map(&:to_sym) - special_variables).each do |var| hash[var.to_s] = instance_variable_get(var) end hash.to_yaml(opts) end def self.from_yaml(str) hash = YAML.load(str) m = self.new(:headers => hash['headers']) hash.delete('headers') hash.each do |k,v| case when k == 'delivery_handler' begin m.delivery_handler = Object.const_get(v) unless v.blank? rescue NameError end when k == 'transport_encoding' m.transport_encoding(v) when k == 'multipart_body' v.map {|part| m.add_part Mail::Part.from_yaml(part) } when k =~ /^@/ m.instance_variable_set(k.to_sym, v) end end m end def self.from_hash(hash) Mail::Message.new(hash) end def to_s encoded end def inspect "#<#{self.class}:#{self.object_id}, Multipart: #{multipart?}, Headers: #{header.field_summary}>" end def decoded case when self.text? decode_body_as_text when self.attachment? decode_body when !self.multipart? body.decoded else raise NoMethodError, 'Can not decode an entire message, try calling #decoded on the various fields and body or parts if it is a multipart message.' end end def read if self.attachment? decode_body else raise NoMethodError, 'Can not call read on a part unless it is an attachment.' end end def decode_body body.decoded end # Returns true if this part is an attachment, # false otherwise. def attachment? !!find_attachment end # Returns the attachment data if there is any def attachment @attachment end # Returns the filename of the attachment def filename find_attachment end def all_parts parts.map { |p| [p, p.all_parts] }.flatten end def find_first_mime_type(mt) all_parts.detect { |p| p.mime_type == mt && !p.attachment? } end # Skips the deletion of this message. All other messages # flagged for delete still will be deleted at session close (i.e. when # #find exits). Only has an effect if you're using #find_and_delete # or #find with :delete_after_find set to true. def skip_deletion @mark_for_delete = false end # Sets whether this message should be deleted at session close (i.e. # after #find). Message will only be deleted if messages are retrieved # using the #find_and_delete method, or by calling #find with # :delete_after_find set to true. def mark_for_delete=(value = true) @mark_for_delete = value end # Returns whether message will be marked for deletion. # If so, the message will be deleted at session close (i.e. after #find # exits), but only if also using the #find_and_delete method, or by # calling #find with :delete_after_find set to true. # # Side-note: Just to be clear, this method will return true even if # the message hasn't yet been marked for delete on the mail server. # However, if this method returns true, it *will be* marked on the # server after each block yields back to #find or #find_and_delete. def is_marked_for_delete? return @mark_for_delete end def text? has_content_type? ? !!(main_type =~ /^text$/i) : false end private # 2.1. General Description # A message consists of header fields (collectively called "the header # of the message") followed, optionally, by a body. The header is a # sequence of lines of characters with special syntax as defined in # this standard. The body is simply a sequence of characters that # follows the header and is separated from the header by an empty line # (i.e., a line with nothing preceding the CRLF). # # Additionally, I allow for the case where someone might have put whitespace # on the "gap line" def parse_message header_part, body_part = raw_source.lstrip.split(/#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m, 2) self.header = header_part self.body = body_part end def raw_source=(value) value.force_encoding("binary") if RUBY_VERSION >= "1.9.1" @raw_source = value.to_crlf end # see comments to body=. We take data and process it lazily def body_lazy(value) process_body_raw if @body_raw && value case when value == nil || value.length<=0 @body = Mail::Body.new('') @body_raw = nil add_encoding_to_body when @body && @body.multipart? @body << Mail::Part.new(value) add_encoding_to_body else @body_raw = value # process_body_raw end end def process_body_raw @body = Mail::Body.new(@body_raw) @body_raw = nil separate_parts if @separate_parts add_encoding_to_body end def set_envelope_header raw_string = raw_source.to_s if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m) set_envelope(match_data[1]) self.raw_source = raw_string.sub(match_data[0], "") end end def separate_parts body.split!(boundary) end def add_encoding_to_body if has_content_transfer_encoding? @body.encoding = content_transfer_encoding end end def identify_and_set_transfer_encoding if body && body.multipart? self.content_transfer_encoding = @transport_encoding else self.content_transfer_encoding = body.get_best_encoding(@transport_encoding) end end def add_required_fields add_required_message_fields add_multipart_mixed_header if body.multipart? add_content_type unless has_content_type? add_charset unless has_charset? add_content_transfer_encoding unless has_content_transfer_encoding? end def add_required_message_fields add_date unless has_date? add_mime_version unless has_mime_version? add_message_id unless has_message_id? end def add_multipart_alternate_header header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value header['content_type'].parameters[:charset] = @charset body.boundary = boundary end def add_boundary unless body.boundary && boundary header['content-type'] = 'multipart/mixed' unless header['content-type'] header['content-type'].parameters[:boundary] = ContentTypeField.generate_boundary header['content_type'].parameters[:charset] = @charset body.boundary = boundary end end def add_multipart_mixed_header unless header['content-type'] header['content-type'] = ContentTypeField.with_boundary('multipart/mixed').value header['content_type'].parameters[:charset] = @charset body.boundary = boundary end end def init_with_hash(hash) passed_in_options = IndifferentHash.new(hash) self.raw_source = '' @header = Mail::Header.new @body = Mail::Body.new @body_raw = nil # We need to store the body until last, as we need all headers added first body_content = nil passed_in_options.each_pair do |k,v| k = underscoreize(k).to_sym if k.class == String if k == :headers self.headers(v) elsif k == :body body_content = v else self[k] = v end end if body_content self.body = body_content if has_content_transfer_encoding? body.encoding = content_transfer_encoding end end end def init_with_string(string) self.raw_source = string set_envelope_header parse_message @separate_parts = multipart? end # Returns the filename of the attachment (if it exists) or returns nil def find_attachment content_type_name = header[:content_type].filename rescue nil content_disp_name = header[:content_disposition].filename rescue nil content_loc_name = header[:content_location].location rescue nil case when content_type && content_type_name filename = content_type_name when content_disposition && content_disp_name filename = content_disp_name when content_location && content_loc_name filename = content_loc_name else filename = nil end filename = Mail::Encodings.decode_encode(filename, :decode) if filename rescue filename filename end def do_delivery begin if perform_deliveries delivery_method.deliver!(self) end rescue Exception => e # Net::SMTP errors or sendmail pipe errors raise e if raise_delivery_errors end end def decode_body_as_text body_text = decode_body if charset if RUBY_VERSION < '1.9' require 'iconv' return Iconv.conv("UTF-8//TRANSLIT//IGNORE", charset, body_text) else if encoding = Encoding.find(charset) rescue nil body_text.force_encoding(encoding) return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '') end end end body_text end end end mail-2.5.4/lib/mail/multibyte.rb000066400000000000000000000032451214434061600165040ustar00rootroot00000000000000# encoding: utf-8 module Mail #:nodoc: module Multibyte require 'mail/multibyte/exceptions' require 'mail/multibyte/chars' require 'mail/multibyte/unicode' # The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy # class so you can support other encodings. See the Mail::Multibyte::Chars implementation for # an example how to do this. # # Example: # Mail::Multibyte.proxy_class = CharsForUTF32 def self.proxy_class=(klass) @proxy_class = klass end # Returns the current proxy class def self.proxy_class @proxy_class ||= Mail::Multibyte::Chars end # Regular expressions that describe valid byte sequences for a character VALID_CHARACTER = { # Borrowed from the Kconv library by Shinji KONO - (also as seen on the W3C site) 'UTF-8' => /\A(?: [\x00-\x7f] | [\xc2-\xdf] [\x80-\xbf] | \xe0 [\xa0-\xbf] [\x80-\xbf] | [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] | \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] | [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] | \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf])\z /xn, # Quick check for valid Shift-JIS characters, disregards the odd-even pairing 'Shift_JIS' => /\A(?: [\x00-\x7e\xa1-\xdf] | [\x81-\x9f\xe0-\xef] [\x40-\x7e\x80-\x9e\x9f-\xfc])\z /xn } end end require 'mail/multibyte/utils'mail-2.5.4/lib/mail/multibyte/000077500000000000000000000000001214434061600161535ustar00rootroot00000000000000mail-2.5.4/lib/mail/multibyte/chars.rb000066400000000000000000000423071214434061600176060ustar00rootroot00000000000000# encoding: utf-8 module Mail #:nodoc: module Multibyte #:nodoc: # Chars enables you to work transparently with UTF-8 encoding in the Ruby String class without having extensive # knowledge about the encoding. A Chars object accepts a string upon initialization and proxies String methods in an # encoding safe manner. All the normal String methods are also implemented on the proxy. # # String methods are proxied through the Chars object, and can be accessed through the +mb_chars+ method. Methods # which would normally return a String object now return a Chars object so methods can be chained. # # "The Perfect String ".mb_chars.downcase.strip.normalize # => "the perfect string" # # Chars objects are perfectly interchangeable with String objects as long as no explicit class checks are made. # If certain methods do explicitly check the class, call +to_s+ before you pass chars objects to them. # # bad.explicit_checking_method "T".mb_chars.downcase.to_s # # The default Chars implementation assumes that the encoding of the string is UTF-8, if you want to handle different # encodings you can write your own multibyte string handler and configure it through # Mail::Multibyte.proxy_class. # # class CharsForUTF32 # def size # @wrapped_string.size / 4 # end # # def self.accepts?(string) # string.length % 4 == 0 # end # end # # Mail::Multibyte.proxy_class = CharsForUTF32 class Chars attr_reader :wrapped_string alias to_s wrapped_string alias to_str wrapped_string if RUBY_VERSION >= "1.9" # Creates a new Chars instance by wrapping _string_. def initialize(string) @wrapped_string = string @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen? end else def initialize(string) #:nodoc: @wrapped_string = string end end # Forward all undefined methods to the wrapped string. def method_missing(method, *args, &block) if method.to_s =~ /!$/ @wrapped_string.__send__(method, *args, &block) self else result = @wrapped_string.__send__(method, *args, &block) result.kind_of?(String) ? chars(result) : result end end # Returns +true+ if _obj_ responds to the given method. Private methods are included in the search # only if the optional second parameter evaluates to +true+. def respond_to?(method, include_private=false) super || @wrapped_string.respond_to?(method, include_private) || false end # Enable more predictable duck-typing on String-like classes. See Object#acts_like?. def acts_like_string? true end # Returns +true+ when the proxy class can handle the string. Returns +false+ otherwise. def self.consumes?(string) # Unpack is a little bit faster than regular expressions. string.unpack('U*') true rescue ArgumentError false end include Comparable # Returns -1, 0, or 1, depending on whether the Chars object is to be sorted before, # equal or after the object on the right side of the operation. It accepts any object # that implements +to_s+: # # 'é'.mb_chars <=> 'ü'.mb_chars # => -1 # # See String#<=> for more details. def <=>(other) @wrapped_string <=> other.to_s end if RUBY_VERSION < "1.9" # Returns +true+ if the Chars class can and should act as a proxy for the string _string_. Returns # +false+ otherwise. def self.wants?(string) $KCODE == 'UTF8' && consumes?(string) end # Returns a new Chars object containing the _other_ object concatenated to the string. # # Example: # ('Café'.mb_chars + ' périferôl').to_s # => "Café périferôl" def +(other) chars(@wrapped_string + other) end # Like String#=~ only it returns the character offset (in codepoints) instead of the byte offset. # # Example: # 'Café périferôl'.mb_chars =~ /ô/ # => 12 def =~(other) translate_offset(@wrapped_string =~ other) end # Inserts the passed string at specified codepoint offsets. # # Example: # 'Café'.mb_chars.insert(4, ' périferôl').to_s # => "Café périferôl" def insert(offset, fragment) unpacked = Unicode.u_unpack(@wrapped_string) unless offset > unpacked.length @wrapped_string.replace( Unicode.u_unpack(@wrapped_string).insert(offset, *Unicode.u_unpack(fragment)).pack('U*') ) else raise IndexError, "index #{offset} out of string" end self end # Returns +true+ if contained string contains _other_. Returns +false+ otherwise. # # Example: # 'Café'.mb_chars.include?('é') # => true def include?(other) # We have to redefine this method because Enumerable defines it. @wrapped_string.include?(other) end # Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found. # # Example: # 'Café périferôl'.mb_chars.index('ô') # => 12 # 'Café périferôl'.mb_chars.index(/\w/u) # => 0 def index(needle, offset=0) wrapped_offset = first(offset).wrapped_string.length index = @wrapped_string.index(needle, wrapped_offset) index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil end # Returns the position _needle_ in the string, counting in # codepoints, searching backward from _offset_ or the end of the # string. Returns +nil+ if _needle_ isn't found. # # Example: # 'Café périferôl'.mb_chars.rindex('é') # => 6 # 'Café périferôl'.mb_chars.rindex(/\w/u) # => 13 def rindex(needle, offset=nil) offset ||= length wrapped_offset = first(offset).wrapped_string.length index = @wrapped_string.rindex(needle, wrapped_offset) index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil end # Returns the number of codepoints in the string def size Unicode.u_unpack(@wrapped_string).size end alias_method :length, :size # Strips entire range of Unicode whitespace from the right of the string. def rstrip chars(@wrapped_string.gsub(Unicode::TRAILERS_PAT, '')) end # Strips entire range of Unicode whitespace from the left of the string. def lstrip chars(@wrapped_string.gsub(Unicode::LEADERS_PAT, '')) end # Strips entire range of Unicode whitespace from the right and left of the string. def strip rstrip.lstrip end # Returns the codepoint of the first character in the string. # # Example: # 'こんにちは'.mb_chars.ord # => 12371 def ord Unicode.u_unpack(@wrapped_string)[0] end # Works just like String#rjust, only integer specifies characters instead of bytes. # # Example: # # "¾ cup".mb_chars.rjust(8).to_s # # => " ¾ cup" # # "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace # # => "   ¾ cup" def rjust(integer, padstr=' ') justify(integer, :right, padstr) end # Works just like String#ljust, only integer specifies characters instead of bytes. # # Example: # # "¾ cup".mb_chars.rjust(8).to_s # # => "¾ cup " # # "¾ cup".mb_chars.rjust(8, " ").to_s # Use non-breaking whitespace # # => "¾ cup   " def ljust(integer, padstr=' ') justify(integer, :left, padstr) end # Works just like String#center, only integer specifies characters instead of bytes. # # Example: # # "¾ cup".mb_chars.center(8).to_s # # => " ¾ cup " # # "¾ cup".mb_chars.center(8, " ").to_s # Use non-breaking whitespace # # => " ¾ cup  " def center(integer, padstr=' ') justify(integer, :center, padstr) end else def =~(other) @wrapped_string =~ other end end # Works just like String#split, with the exception that the items in the resulting list are Chars # instances instead of String. This makes chaining methods easier. # # Example: # 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"] def split(*args) @wrapped_string.split(*args).map { |i| i.mb_chars } end # Like String#[]=, except instead of byte offsets you specify character offsets. # # Example: # # s = "Müller" # s.mb_chars[2] = "e" # Replace character with offset 2 # s # # => "Müeler" # # s = "Müller" # s.mb_chars[1, 2] = "ö" # Replace 2 characters at character offset 1 # s # # => "Möler" def []=(*args) replace_by = args.pop # Indexed replace with regular expressions already works if args.first.is_a?(Regexp) @wrapped_string[*args] = replace_by else result = Unicode.u_unpack(@wrapped_string) if args[0].is_a?(Fixnum) raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length min = args[0] max = args[1].nil? ? min : (min + args[1] - 1) range = Range.new(min, max) replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum) elsif args.first.is_a?(Range) raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length range = args[0] else needle = args[0].to_s min = index(needle) max = min + Unicode.u_unpack(needle).length - 1 range = Range.new(min, max) end result[range] = Unicode.u_unpack(replace_by) @wrapped_string.replace(result.pack('U*')) end end # Reverses all characters in the string. # # Example: # 'Café'.mb_chars.reverse.to_s # => 'éfaC' def reverse chars(Unicode.g_unpack(@wrapped_string).reverse.flatten.pack('U*')) end # Implements Unicode-aware slice with codepoints. Slicing on one point returns the codepoints for that # character. # # Example: # 'こんにちは'.mb_chars.slice(2..3).to_s # => "にち" def slice(*args) if args.size > 2 raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native elsif (args.size == 2 && !(args.first.is_a?(Numeric) || args.first.is_a?(Regexp))) raise TypeError, "cannot convert #{args.first.class} into Integer" # Do as if we were native elsif (args.size == 2 && !args[1].is_a?(Numeric)) raise TypeError, "cannot convert #{args[1].class} into Integer" # Do as if we were native elsif args[0].kind_of? Range cps = Unicode.u_unpack(@wrapped_string).slice(*args) result = cps.nil? ? nil : cps.pack('U*') elsif args[0].kind_of? Regexp result = @wrapped_string.slice(*args) elsif args.size == 1 && args[0].kind_of?(Numeric) character = Unicode.u_unpack(@wrapped_string)[args[0]] result = character && [character].pack('U') else cps = Unicode.u_unpack(@wrapped_string).slice(*args) result = cps && cps.pack('U*') end result && chars(result) end alias_method :[], :slice # Limit the byte size of the string to a number of bytes without breaking characters. Usable # when the storage for a string is limited for some reason. # # Example: # s = 'こんにちは' # s.mb_chars.limit(7) # => "こに" def limit(limit) slice(0...translate_offset(limit)) end # Convert characters in the string to uppercase. # # Example: # 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?" def upcase chars(Unicode.apply_mapping(@wrapped_string, :uppercase_mapping)) end # Convert characters in the string to lowercase. # # Example: # 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum" def downcase chars(Unicode.apply_mapping(@wrapped_string, :lowercase_mapping)) end # Converts the first character to uppercase and the remainder to lowercase. # # Example: # 'über'.mb_chars.capitalize.to_s # => "Über" def capitalize (slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase end # Capitalizes the first letter of every word, when possible. # # Example: # "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró" # "日本語".mb_chars.titleize # => "日本語" def titleize chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping }) end alias_method :titlecase, :titleize # Returns the KC normalization of the string by default. NFKC is considered the best normalization form for # passing strings to databases and validations. # # * form - The form you want to normalize in. Should be one of the following: # :c, :kc, :d, or :kd. Default is # Mail::Multibyte::Unicode.default_normalization_form def normalize(form = nil) chars(Unicode.normalize(@wrapped_string, form)) end # Performs canonical decomposition on all the characters. # # Example: # 'é'.length # => 2 # 'é'.mb_chars.decompose.to_s.length # => 3 def decompose chars(Unicode.decompose_codepoints(:canonical, Unicode.u_unpack(@wrapped_string)).pack('U*')) end # Performs composition on all the characters. # # Example: # 'é'.length # => 3 # 'é'.mb_chars.compose.to_s.length # => 2 def compose chars(Unicode.compose_codepoints(Unicode.u_unpack(@wrapped_string)).pack('U*')) end # Returns the number of grapheme clusters in the string. # # Example: # 'क्षि'.mb_chars.length # => 4 # 'क्षि'.mb_chars.g_length # => 3 def g_length Unicode.g_unpack(@wrapped_string).length end # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string. # # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1. def tidy_bytes(force = false) chars(Unicode.tidy_bytes(@wrapped_string, force)) end %w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method| # Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will # exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings. if public_method_defined?(method) define_method("#{method}!") do |*args| @wrapped_string = send(args.nil? ? method : method, *args).to_s self end end end protected def translate_offset(byte_offset) #:nodoc: return nil if byte_offset.nil? return 0 if @wrapped_string == '' if @wrapped_string.respond_to?(:force_encoding) @wrapped_string = @wrapped_string.dup.force_encoding(Encoding::ASCII_8BIT) end begin @wrapped_string[0...byte_offset].unpack('U*').length rescue ArgumentError byte_offset -= 1 retry end end def justify(integer, way, padstr=' ') #:nodoc: raise ArgumentError, "zero width padding" if padstr.length == 0 padsize = integer - size padsize = padsize > 0 ? padsize : 0 case way when :right result = @wrapped_string.dup.insert(0, padding(padsize, padstr)) when :left result = @wrapped_string.dup.insert(-1, padding(padsize, padstr)) when :center lpad = padding((padsize / 2.0).floor, padstr) rpad = padding((padsize / 2.0).ceil, padstr) result = @wrapped_string.dup.insert(0, lpad).insert(-1, rpad) end chars(result) end def padding(padsize, padstr=' ') #:nodoc: if padsize != 0 chars(padstr * ((padsize / Unicode.u_unpack(padstr).size) + 1)).slice(0, padsize) else '' end end def chars(string) #:nodoc: self.class.new(string) end end end end mail-2.5.4/lib/mail/multibyte/exceptions.rb000066400000000000000000000002631214434061600206620ustar00rootroot00000000000000# encoding: utf-8 module Mail #:nodoc: module Multibyte #:nodoc: # Raised when a problem with the encoding was found. class EncodingError < StandardError; end end endmail-2.5.4/lib/mail/multibyte/unicode.rb000066400000000000000000000355171214434061600201410ustar00rootroot00000000000000module Mail module Multibyte module Unicode extend self # A list of all available normalization forms. See http://www.unicode.org/reports/tr15/tr15-29.html for more # information about normalization. NORMALIZATION_FORMS = [:c, :kc, :d, :kd] # The Unicode version that is supported by the implementation UNICODE_VERSION = '5.2.0' # The default normalization used for operations that require normalization. It can be set to any of the # normalizations in NORMALIZATION_FORMS. # # Example: # Mail::Multibyte::Unicode.default_normalization_form = :c attr_accessor :default_normalization_form @default_normalization_form = :kc # Hangul character boundaries and properties HANGUL_SBASE = 0xAC00 HANGUL_LBASE = 0x1100 HANGUL_VBASE = 0x1161 HANGUL_TBASE = 0x11A7 HANGUL_LCOUNT = 19 HANGUL_VCOUNT = 21 HANGUL_TCOUNT = 28 HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT HANGUL_SCOUNT = 11172 HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT HANGUL_JAMO_FIRST = 0x1100 HANGUL_JAMO_LAST = 0x11FF # All the unicode whitespace WHITESPACE = [ (0x0009..0x000D).to_a, # White_Space # Cc [5] .. 0x0020, # White_Space # Zs SPACE 0x0085, # White_Space # Cc 0x00A0, # White_Space # Zs NO-BREAK SPACE 0x1680, # White_Space # Zs OGHAM SPACE MARK 0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE 0x2028, # White_Space # Zl LINE SEPARATOR 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE ].flatten.freeze # BOM (byte order mark) can also be seen as whitespace, it's a non-rendering character used to distinguish # between little and big endian. This is not an issue in utf-8, so it must be ignored. LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM # Returns a regular expression pattern that matches the passed Unicode codepoints def self.codepoints_to_pattern(array_of_codepoints) #:nodoc: array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|') end TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u # Unpack the string at codepoints boundaries. Raises an EncodingError when the encoding of the string isn't # valid UTF-8. # # Example: # Unicode.u_unpack('Café') # => [67, 97, 102, 233] def u_unpack(string) begin string.unpack 'U*' rescue ArgumentError raise EncodingError, 'malformed UTF-8 character' end end # Detect whether the codepoint is in a certain character class. Returns +true+ when it's in the specified # character class and +false+ otherwise. Valid character classes are: :cr, :lf, :l, # :v, :lv, :lvt and :t. # # Primarily used by the grapheme cluster support. def in_char_class?(codepoint, classes) classes.detect { |c| database.boundary[c] === codepoint } ? true : false end # Unpack the string at grapheme boundaries. Returns a list of character lists. # # Example: # Unicode.g_unpack('क्षि') # => [[2325, 2381], [2359], [2367]] # Unicode.g_unpack('Café') # => [[67], [97], [102], [233]] def g_unpack(string) codepoints = u_unpack(string) unpacked = [] pos = 0 marker = 0 eoc = codepoints.length while(pos < eoc) pos += 1 previous = codepoints[pos-1] current = codepoints[pos] if ( # CR X LF ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or # L X (L|V|LV|LVT) ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or # (LV|V) X (V|T) ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or # (LVT|T) X (T) ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or # X Extend (database.boundary[:extend] === current) ) else unpacked << codepoints[marker..pos-1] marker = pos end end unpacked end # Reverse operation of g_unpack. # # Example: # Unicode.g_pack(Unicode.g_unpack('क्षि')) # => 'क्षि' def g_pack(unpacked) (unpacked.flatten).pack('U*') end # Re-order codepoints so the string becomes canonical. def reorder_characters(codepoints) length = codepoints.length- 1 pos = 0 while pos < length do cp1, cp2 = database.codepoints[codepoints[pos]], database.codepoints[codepoints[pos+1]] if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0) codepoints[pos..pos+1] = cp2.code, cp1.code pos += (pos > 0 ? -1 : 1) else pos += 1 end end codepoints end # Decompose composed characters to the decomposed form. def decompose_codepoints(type, codepoints) codepoints.inject([]) do |decomposed, cp| # if it's a hangul syllable starter character if HANGUL_SBASE <= cp and cp < HANGUL_SLAST sindex = cp - HANGUL_SBASE ncp = [] # new codepoints ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT tindex = sindex % HANGUL_TCOUNT ncp << (HANGUL_TBASE + tindex) unless tindex == 0 decomposed.concat ncp # if the codepoint is decomposable in with the current decomposition type elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatability) decomposed.concat decompose_codepoints(type, ncp.dup) else decomposed << cp end end end # Compose decomposed characters to the composed form. def compose_codepoints(codepoints) pos = 0 eoa = codepoints.length - 1 starter_pos = 0 starter_char = codepoints[0] previous_combining_class = -1 while pos < eoa pos += 1 lindex = starter_char - HANGUL_LBASE # -- Hangul if 0 <= lindex and lindex < HANGUL_LCOUNT vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1 if 0 <= vindex and vindex < HANGUL_VCOUNT tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1 if 0 <= tindex and tindex < HANGUL_TCOUNT j = starter_pos + 2 eoa -= 2 else tindex = 0 j = starter_pos + 1 eoa -= 1 end codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE end starter_pos += 1 starter_char = codepoints[starter_pos] # -- Other characters else current_char = codepoints[pos] current = database.codepoints[current_char] if current.combining_class > previous_combining_class if ref = database.composition_map[starter_char] composition = ref[current_char] else composition = nil end unless composition.nil? codepoints[starter_pos] = composition starter_char = composition codepoints.delete_at pos eoa -= 1 pos -= 1 previous_combining_class = -1 else previous_combining_class = current.combining_class end else previous_combining_class = current.combining_class end if current.combining_class == 0 starter_pos = pos starter_char = codepoints[pos] end end end codepoints end # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string. # # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1. def tidy_bytes(string, force = false) if force return string.unpack("C*").map do |b| tidy_byte(b) end.flatten.compact.pack("C*").unpack("U*").pack("U*") end bytes = string.unpack("C*") conts_expected = 0 last_lead = 0 bytes.each_index do |i| byte = bytes[i] is_cont = byte > 127 && byte < 192 is_lead = byte > 191 && byte < 245 is_unused = byte > 240 is_restricted = byte > 244 # Impossible or highly unlikely byte? Clean it. if is_unused || is_restricted bytes[i] = tidy_byte(byte) elsif is_cont # Not expecting contination byte? Clean up. Otherwise, now expect one less. conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1 else if conts_expected > 0 # Expected continuation, but got ASCII or leading? Clean backwards up to # the leading byte. (1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])} conts_expected = 0 end if is_lead # Final byte is leading? Clean it. if i == bytes.length - 1 bytes[i] = tidy_byte(bytes.last) else # Valid leading byte? Expect continuations determined by position of # first zero bit, with max of 3. conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3 last_lead = i end end end end bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*") end # Returns the KC normalization of the string by default. NFKC is considered the best normalization form for # passing strings to databases and validations. # # * string - The string to perform normalization on. # * form - The form you want to normalize in. Should be one of the following: # :c, :kc, :d, or :kd. Default is # Mail::Multibyte.default_normalization_form def normalize(string, form=nil) form ||= @default_normalization_form # See http://www.unicode.org/reports/tr15, Table 1 codepoints = u_unpack(string) case form when :d reorder_characters(decompose_codepoints(:canonical, codepoints)) when :c compose_codepoints(reorder_characters(decompose_codepoints(:canonical, codepoints))) when :kd reorder_characters(decompose_codepoints(:compatability, codepoints)) when :kc compose_codepoints(reorder_characters(decompose_codepoints(:compatability, codepoints))) else raise ArgumentError, "#{form} is not a valid normalization variant", caller end.pack('U*') end def apply_mapping(string, mapping) #:nodoc: u_unpack(string).map do |codepoint| cp = database.codepoints[codepoint] if cp and (ncp = cp.send(mapping)) and ncp > 0 ncp else codepoint end end.pack('U*') end # Holds data about a codepoint in the Unicode database class Codepoint attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping end # Holds static data from the Unicode database class UnicodeDatabase ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252 attr_writer(*ATTRIBUTES) def initialize @codepoints = Hash.new(Codepoint.new) @composition_exclusion = [] @composition_map = {} @boundary = {} @cp1252 = {} end # Lazy load the Unicode database so it's only loaded when it's actually used ATTRIBUTES.each do |attr_name| class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{attr_name} # def codepoints load # load @#{attr_name} # @codepoints end # end EOS end # Loads the Unicode database and returns all the internal objects of UnicodeDatabase. def load begin @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read } rescue Exception => e raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), Mail::Multibyte is unusable") end # Redefine the === method so we can write shorter rules for grapheme cluster breaks @boundary.each do |k,_| @boundary[k].instance_eval do def ===(other) detect { |i| i === other } ? true : false end end if @boundary[k].kind_of?(Array) end # define attr_reader methods for the instance variables class << self attr_reader(*ATTRIBUTES) end end # Returns the directory in which the data files are stored def self.dirname File.dirname(__FILE__) + '/../values/' end # Returns the filename for the data file for this version def self.filename File.expand_path File.join(dirname, "unicode_tables.dat") end end private def tidy_byte(byte) if byte < 160 [database.cp1252[byte] || byte].pack("U").unpack("C*") elsif byte < 192 [194, byte] else [195, byte - 64] end end def database @database ||= UnicodeDatabase.new end end end end unless defined?(ActiveSupport) module ActiveSupport unless const_defined?(:Multibyte) Multibyte = Mail::Multibyte end end end mail-2.5.4/lib/mail/multibyte/utils.rb000066400000000000000000000031701214434061600176410ustar00rootroot00000000000000# encoding: utf-8 module Mail #:nodoc: module Multibyte #:nodoc: if RUBY_VERSION >= "1.9" # Returns a regular expression that matches valid characters in the current encoding def self.valid_character VALID_CHARACTER[Encoding.default_external.to_s] end else def self.valid_character case $KCODE when 'UTF8' VALID_CHARACTER['UTF-8'] when 'SJIS' VALID_CHARACTER['Shift_JIS'] end end end if 'string'.respond_to?(:valid_encoding?) # Verifies the encoding of a string def self.verify(string) string.valid_encoding? end else def self.verify(string) if expression = valid_character # Splits the string on character boundaries, which are determined based on $KCODE. string.split(//).all? { |c| expression =~ c } else true end end end # Verifies the encoding of the string and raises an exception when it's not valid def self.verify!(string) raise EncodingError.new("Found characters with invalid encoding") unless verify(string) end if 'string'.respond_to?(:force_encoding) # Removes all invalid characters from the string. # # Note: this method is a no-op in Ruby 1.9 def self.clean(string) string end else def self.clean(string) if expression = valid_character # Splits the string on character boundaries, which are determined based on $KCODE. string.split(//).grep(expression).join else string end end end end end mail-2.5.4/lib/mail/network.rb000066400000000000000000000013211214434061600161500ustar00rootroot00000000000000require 'mail/network/retriever_methods/base' module Mail register_autoload :SMTP, 'mail/network/delivery_methods/smtp' register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery' register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail' register_autoload :Exim, 'mail/network/delivery_methods/exim' register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection' register_autoload :TestMailer, 'mail/network/delivery_methods/test_mailer' register_autoload :POP3, 'mail/network/retriever_methods/pop3' register_autoload :IMAP, 'mail/network/retriever_methods/imap' register_autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever' end mail-2.5.4/lib/mail/network/000077500000000000000000000000001214434061600156265ustar00rootroot00000000000000mail-2.5.4/lib/mail/network/delivery_methods/000077500000000000000000000000001214434061600211745ustar00rootroot00000000000000mail-2.5.4/lib/mail/network/delivery_methods/exim.rb000066400000000000000000000024511214434061600224650ustar00rootroot00000000000000module Mail # A delivery method implementation which sends via exim. # # To use this, first find out where the exim binary is on your computer, # if you are on a mac or unix box, it is usually in /usr/sbin/exim, this will # be your exim location. # # Mail.defaults do # delivery_method :exim # end # # Or if your exim binary is not at '/usr/sbin/exim' # # Mail.defaults do # delivery_method :exim, :location => '/absolute/path/to/your/exim' # end # # Then just deliver the email as normal: # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing exim' # body 'testing exim' # end # # Or by calling deliver on a Mail message # # mail = Mail.new do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing exim' # body 'testing exim' # end # # mail.deliver! class Exim < Sendmail def initialize(values) self.settings = { :location => '/usr/sbin/exim', :arguments => '-i -t' }.merge(values) end def self.call(path, arguments, destinations, mail) popen "#{path} #{arguments}" do |io| io.puts mail.encoded.to_lf io.flush end end end end mail-2.5.4/lib/mail/network/delivery_methods/file_delivery.rb000066400000000000000000000024121214434061600243420ustar00rootroot00000000000000require 'mail/check_delivery_params' module Mail # FileDelivery class delivers emails into multiple files based on the destination # address. Each file is appended to if it already exists. # # So if you have an email going to fred@test, bob@test, joe@anothertest, and you # set your location path to /path/to/mails then FileDelivery will create the directory # if it does not exist, and put one copy of the email in three files, called # by their message id # # Make sure the path you specify with :location is writable by the Ruby process # running Mail. class FileDelivery include Mail::CheckDeliveryParams if RUBY_VERSION >= '1.9.1' require 'fileutils' else require 'ftools' end def initialize(values) self.settings = { :location => './mails' }.merge!(values) end attr_accessor :settings def deliver!(mail) check_delivery_params(mail) if ::File.respond_to?(:makedirs) ::File.makedirs settings[:location] else ::FileUtils.mkdir_p settings[:location] end mail.destinations.uniq.each do |to| ::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" } end end end end mail-2.5.4/lib/mail/network/delivery_methods/sendmail.rb000066400000000000000000000052421214434061600233200ustar00rootroot00000000000000require 'mail/check_delivery_params' module Mail # A delivery method implementation which sends via sendmail. # # To use this, first find out where the sendmail binary is on your computer, # if you are on a mac or unix box, it is usually in /usr/sbin/sendmail, this will # be your sendmail location. # # Mail.defaults do # delivery_method :sendmail # end # # Or if your sendmail binary is not at '/usr/sbin/sendmail' # # Mail.defaults do # delivery_method :sendmail, :location => '/absolute/path/to/your/sendmail' # end # # Then just deliver the email as normal: # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # Or by calling deliver on a Mail message # # mail = Mail.new do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # mail.deliver! class Sendmail include Mail::CheckDeliveryParams def initialize(values) self.settings = { :location => '/usr/sbin/sendmail', :arguments => '-i' }.merge(values) end attr_accessor :settings def deliver!(mail) smtp_from, smtp_to, message = check_delivery_params(mail) from = "-f #{self.class.shellquote(smtp_from)}" to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ') arguments = "#{settings[:arguments]} #{from} --" self.class.call(settings[:location], arguments, to, message) end def self.call(path, arguments, destinations, encoded_message) popen "#{path} #{arguments} #{destinations}" do |io| io.puts encoded_message.to_lf io.flush end end if RUBY_VERSION < '1.9.0' def self.popen(command, &block) IO.popen "#{command} 2>&1", 'w+', &block end else def self.popen(command, &block) IO.popen command, 'w+', :err => :out, &block end end # The following is an adaptation of ruby 1.9.2's shellwords.rb file, # it is modified to include '+' in the allowed list to allow for # sendmail to accept email addresses as the sender with a + in them. def self.shellquote(address) # Process as a single byte sequence because not all shell # implementations are multibyte aware. # # A LF cannot be escaped with a backslash because a backslash + LF # combo is regarded as line continuation and simply ignored. Strip it. escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '') %("#{escaped}") end end end mail-2.5.4/lib/mail/network/delivery_methods/smtp.rb000066400000000000000000000121021214434061600225000ustar00rootroot00000000000000require 'mail/check_delivery_params' module Mail # == Sending Email with SMTP # # Mail allows you to send emails using SMTP. This is done by wrapping Net::SMTP in # an easy to use manner. # # === Sending via SMTP server on Localhost # # Sending locally (to a postfix or sendmail server running on localhost) requires # no special setup. Just to Mail.deliver &block or message.deliver! and it will # be sent in this method. # # === Sending via MobileMe # # Mail.defaults do # delivery_method :smtp, { :address => "smtp.me.com", # :port => 587, # :domain => 'your.host.name', # :user_name => '', # :password => '', # :authentication => 'plain', # :enable_starttls_auto => true } # end # # === Sending via GMail # # Mail.defaults do # delivery_method :smtp, { :address => "smtp.gmail.com", # :port => 587, # :domain => 'your.host.name', # :user_name => '', # :password => '', # :authentication => 'plain', # :enable_starttls_auto => true } # end # # === Certificate verification # # When using TLS, some mail servers provide certificates that are self-signed # or whose names do not exactly match the hostname given in the address. # OpenSSL will reject these by default. The best remedy is to use the correct # hostname or update the certificate authorities trusted by your ruby. If # that isn't possible, you can control this behavior with # an :openssl_verify_mode setting. Its value may be either an OpenSSL # verify mode constant (OpenSSL::SSL::VERIFY_NONE), or a string containing # the name of an OpenSSL verify mode (none, peer, client_once, # fail_if_no_peer_cert). # # === Others # # Feel free to send me other examples that were tricky # # === Delivering the email # # Once you have the settings right, sending the email is done by: # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # Or by calling deliver on a Mail message # # mail = Mail.new do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # mail.deliver! class SMTP include Mail::CheckDeliveryParams def initialize(values) self.settings = { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true, :openssl_verify_mode => nil, :ssl => nil, :tls => nil }.merge!(values) end attr_accessor :settings # Send the message via SMTP. # The from and to attributes are optional. If not set, they are retrieve from the Message. def deliver!(mail) smtp_from, smtp_to, message = check_delivery_params(mail) smtp = Net::SMTP.new(settings[:address], settings[:port]) if settings[:tls] || settings[:ssl] if smtp.respond_to?(:enable_tls) smtp.enable_tls(ssl_context) end elsif settings[:enable_starttls_auto] if smtp.respond_to?(:enable_starttls_auto) smtp.enable_starttls_auto(ssl_context) end end response = nil smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj| response = smtp_obj.sendmail(message, smtp_from, smtp_to) end if settings[:return_response] response else self end end private # Allow SSL context to be configured via settings, for Ruby >= 1.9 # Just returns openssl verify mode for Ruby 1.8.x def ssl_context openssl_verify_mode = settings[:openssl_verify_mode] if openssl_verify_mode.kind_of?(String) openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize end if RUBY_VERSION < '1.9.0' openssl_verify_mode else context = Net::SMTP.default_ssl_context context.verify_mode = openssl_verify_mode context.ca_path = settings[:ca_path] if settings[:ca_path] context.ca_file = settings[:ca_file] if settings[:ca_file] context end end end end mail-2.5.4/lib/mail/network/delivery_methods/smtp_connection.rb000066400000000000000000000035031214434061600247240ustar00rootroot00000000000000require 'mail/check_delivery_params' module Mail # == Sending Email with SMTP # # Mail allows you to send emails using an open SMTP connection. This is done by # passing a created Net::SMTP object. This way we can get better performance to # our local mail server by reducing the number of connections at any one time. # # === Sending via SMTP server on Localhost # # To send mail open a connection with Net::Smtp using any options you like # === Delivering the email # # Once you have the settings right, sending the email is done by: # # smtp_conn = Net::SMTP.start(settings[:address], settings[:port]) # Mail.defaults do # delivery_method :smtp_connection, { :connection => smtp_conn } # end # # Mail.deliver do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # Or by calling deliver on a Mail message # # mail = Mail.new do # to 'mikel@test.lindsaar.net' # from 'ada@test.lindsaar.net' # subject 'testing sendmail' # body 'testing sendmail' # end # # mail.deliver! class SMTPConnection include Mail::CheckDeliveryParams def initialize(values) raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil? self.smtp = values[:connection] self.settings = values end attr_accessor :smtp attr_accessor :settings # Send the message via SMTP. # The from and to attributes are optional. If not set, they are retrieve from the Message. def deliver!(mail) smtp_from, smtp_to, message = check_delivery_params(mail) response = smtp.sendmail(message, smtp_from, smtp_to) settings[:return_response] ? response : self end end end mail-2.5.4/lib/mail/network/delivery_methods/test_mailer.rb000066400000000000000000000022051214434061600240300ustar00rootroot00000000000000require 'mail/check_delivery_params' module Mail # The TestMailer is a bare bones mailer that does nothing. It is useful # when you are testing. # # It also provides a template of the minimum methods you require to implement # if you want to make a custom mailer for Mail class TestMailer include Mail::CheckDeliveryParams # Provides a store of all the emails sent with the TestMailer so you can check them. def TestMailer.deliveries @@deliveries ||= [] end # Allows you to over write the default deliveries store from an array to some # other object. If you just want to clear the store, # call TestMailer.deliveries.clear. # # If you place another object here, please make sure it responds to: # # * << (message) # * clear # * length # * size # * and other common Array methods def TestMailer.deliveries=(val) @@deliveries = val end def initialize(values) @settings = values.dup end attr_accessor :settings def deliver!(mail) check_delivery_params(mail) Mail::TestMailer.deliveries << mail end end end mail-2.5.4/lib/mail/network/retriever_methods/000077500000000000000000000000001214434061600213605ustar00rootroot00000000000000mail-2.5.4/lib/mail/network/retriever_methods/base.rb000066400000000000000000000036471214434061600226310ustar00rootroot00000000000000# encoding: utf-8 module Mail class Retriever # Get the oldest received email(s) # # Possible options: # count: number of emails to retrieve. The default value is 1. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # def first(options = {}, &block) options ||= {} options[:what] = :first options[:count] ||= 1 find(options, &block) end # Get the most recent received email(s) # # Possible options: # count: number of emails to retrieve. The default value is 1. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # def last(options = {}, &block) options ||= {} options[:what] = :last options[:count] ||= 1 find(options, &block) end # Get all emails. # # Possible options: # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # def all(options = {}, &block) options ||= {} options[:count] = :all find(options, &block) end # Find emails in the mailbox, and then deletes them. Without any options, the # five last received emails are returned. # # Possible options: # what: last or first emails. The default is :first. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # count: number of emails to retrieve. The default value is 10. A value of 1 returns an # instance of Message, not an array of Message instances. # delete_after_find: flag for whether to delete each retreived email after find. Default # is true. Call #find if you would like this to default to false. # def find_and_delete(options = {}, &block) options ||= {} options[:delete_after_find] ||= true find(options, &block) end end end mail-2.5.4/lib/mail/network/retriever_methods/imap.rb000066400000000000000000000165121214434061600226400ustar00rootroot00000000000000# encoding: utf-8 module Mail # The IMAP retriever allows to get the last, first or all emails from a IMAP server. # Each email retrieved (RFC2822) is given as an instance of +Message+. # # While being retrieved, emails can be yielded if a block is given. # # === Example of retrieving Emails from GMail: # # Mail.defaults do # retriever_method :imap, { :address => "imap.googlemail.com", # :port => 993, # :user_name => '', # :password => '', # :enable_ssl => true } # end # # Mail.all #=> Returns an array of all emails # Mail.first #=> Returns the first unread email # Mail.last #=> Returns the last unread email # # You can also pass options into Mail.find to locate an email in your imap mailbox # with the following options: # # mailbox: name of the mailbox used for email retrieval. The default is 'INBOX'. # what: last or first emails. The default is :first. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # count: number of emails to retrieve. The default value is 10. A value of 1 returns an # instance of Message, not an array of Message instances. # keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string, # or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list # The default is 'ALL' # # Mail.find(:what => :first, :count => 10, :order => :asc, :keys=>'ALL') # #=> Returns the first 10 emails in ascending order # class IMAP < Retriever require 'net/imap' unless defined?(Net::IMAP) def initialize(values) self.settings = { :address => "localhost", :port => 143, :user_name => nil, :password => nil, :authentication => nil, :enable_ssl => false }.merge!(values) end attr_accessor :settings # Find emails in a IMAP mailbox. Without any options, the 10 last received emails are returned. # # Possible options: # mailbox: mailbox to search the email(s) in. The default is 'INBOX'. # what: last or first emails. The default is :first. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # count: number of emails to retrieve. The default value is 10. A value of 1 returns an # instance of Message, not an array of Message instances. # read_only: will ensure that no writes are made to the inbox during the session. Specifically, if this is # set to true, the code will use the EXAMINE command to retrieve the mail. If set to false, which # is the default, a SELECT command will be used to retrieve the mail # This is helpful when you don't want your messages to be set to read automatically. Default is false. # delete_after_find: flag for whether to delete each retreived email after find. Default # is false. Use #find_and_delete if you would like this to default to true. # keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string, # or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list # The default is 'ALL' # def find(options={}, &block) options = validate_options(options) start do |imap| options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox]) message_ids = imap.uid_search(options[:keys]) message_ids.reverse! if options[:what].to_sym == :last message_ids = message_ids.first(options[:count]) if options[:count].is_a?(Integer) message_ids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) || (options[:what].to_sym != :last && options[:order].to_sym == :desc) if block_given? message_ids.each do |message_id| fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0] new_message = Mail.new(fetchdata.attr['RFC822']) new_message.mark_for_delete = true if options[:delete_after_find] if block.arity == 3 yield new_message, imap, message_id else yield new_message end imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete? end imap.expunge if options[:delete_after_find] else emails = [] message_ids.each do |message_id| fetchdata = imap.uid_fetch(message_id, ['RFC822'])[0] emails << Mail.new(fetchdata.attr['RFC822']) imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] end imap.expunge if options[:delete_after_find] emails.size == 1 && options[:count] == 1 ? emails.first : emails end end end # Delete all emails from a IMAP mailbox def delete_all(mailbox='INBOX') mailbox ||= 'INBOX' mailbox = Net::IMAP.encode_utf7(mailbox) start do |imap| imap.uid_search(['ALL']).each do |message_id| imap.uid_store(message_id, "+FLAGS", [Net::IMAP::DELETED]) end imap.expunge end end # Returns the connection object of the retrievable (IMAP or POP3) def connection(&block) raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given? start do |imap| yield imap end end private # Set default options def validate_options(options) options ||= {} options[:mailbox] ||= 'INBOX' options[:count] ||= 10 options[:order] ||= :asc options[:what] ||= :first options[:keys] ||= 'ALL' options[:delete_after_find] ||= false options[:mailbox] = Net::IMAP.encode_utf7(options[:mailbox]) options[:read_only] ||= false options end # Start an IMAP session and ensures that it will be closed in any case. def start(config=Mail::Configuration.instance, &block) raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given? imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false) if settings[:authentication].nil? imap.login(settings[:user_name], settings[:password]) else # Note that Net::IMAP#authenticate('LOGIN', ...) is not equal with Net::IMAP#login(...)! # (see also http://www.ensta.fr/~diam/ruby/online/ruby-doc-stdlib/libdoc/net/imap/rdoc/classes/Net/IMAP.html#M000718) imap.authenticate(settings[:authentication], settings[:user_name], settings[:password]) end yield imap ensure if defined?(imap) && imap && !imap.disconnected? imap.disconnect end end end end mail-2.5.4/lib/mail/network/retriever_methods/pop3.rb000066400000000000000000000122431214434061600225700ustar00rootroot00000000000000# encoding: utf-8 module Mail # The Pop3 retriever allows to get the last, first or all emails from a POP3 server. # Each email retrieved (RFC2822) is given as an instance of +Message+. # # While being retrieved, emails can be yielded if a block is given. # # === Example of retrieving Emails from GMail: # # Mail.defaults do # retriever_method :pop3, { :address => "pop.gmail.com", # :port => 995, # :user_name => '', # :password => '', # :enable_ssl => true } # end # # Mail.all #=> Returns an array of all emails # Mail.first #=> Returns the first unread email # Mail.last #=> Returns the last unread email # # You can also pass options into Mail.find to locate an email in your pop mailbox # with the following options: # # what: last or first emails. The default is :first. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # count: number of emails to retrieve. The default value is 10. A value of 1 returns an # instance of Message, not an array of Message instances. # # Mail.find(:what => :first, :count => 10, :order => :asc) # #=> Returns the first 10 emails in ascending order # class POP3 < Retriever require 'net/pop' unless defined?(Net::POP) def initialize(values) self.settings = { :address => "localhost", :port => 110, :user_name => nil, :password => nil, :authentication => nil, :enable_ssl => false }.merge!(values) end attr_accessor :settings # Find emails in a POP3 mailbox. Without any options, the 5 last received emails are returned. # # Possible options: # what: last or first emails. The default is :first. # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc. # count: number of emails to retrieve. The default value is 10. A value of 1 returns an # instance of Message, not an array of Message instances. # delete_after_find: flag for whether to delete each retreived email after find. Default # is false. Use #find_and_delete if you would like this to default to true. # def find(options = {}, &block) options = validate_options(options) start do |pop3| mails = pop3.mails pop3.reset # Clears all "deleted" marks. This prevents non-explicit/accidental deletions due to server settings. mails.sort! { |m1, m2| m2.number <=> m1.number } if options[:what] == :last mails = mails.first(options[:count]) if options[:count].is_a? Integer if options[:what].to_sym == :last && options[:order].to_sym == :desc || options[:what].to_sym == :first && options[:order].to_sym == :asc || mails.reverse! end if block_given? mails.each do |mail| new_message = Mail.new(mail.pop) new_message.mark_for_delete = true if options[:delete_after_find] yield new_message mail.delete if options[:delete_after_find] && new_message.is_marked_for_delete? # Delete if still marked for delete end else emails = [] mails.each do |mail| emails << Mail.new(mail.pop) mail.delete if options[:delete_after_find] end emails.size == 1 && options[:count] == 1 ? emails.first : emails end end end # Delete all emails from a POP3 server def delete_all start do |pop3| unless pop3.mails.empty? pop3.delete_all pop3.finish end end end # Returns the connection object of the retrievable (IMAP or POP3) def connection(&block) raise ArgumentError.new('Mail::Retrievable#connection takes a block') unless block_given? start do |pop3| yield pop3 end end private # Set default options def validate_options(options) options ||= {} options[:count] ||= 10 options[:order] ||= :asc options[:what] ||= :first options[:delete_after_find] ||= false options end # Start a POP3 session and ensure that it will be closed in any case. Any messages # marked for deletion via #find_and_delete or with the :delete_after_find option # will be deleted when the session is closed. def start(config = Configuration.instance, &block) raise ArgumentError.new("Mail::Retrievable#pop3_start takes a block") unless block_given? pop3 = Net::POP3.new(settings[:address], settings[:port], false) pop3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if settings[:enable_ssl] pop3.start(settings[:user_name], settings[:password]) yield pop3 ensure if defined?(pop3) && pop3 && pop3.started? pop3.finish end end end end mail-2.5.4/lib/mail/network/retriever_methods/test_retriever.rb000066400000000000000000000022771214434061600247630ustar00rootroot00000000000000# encoding: utf-8 module Mail class TestRetriever < Retriever def self.emails @@emails end def self.emails=(val) @@emails = val end def initialize(values) @@emails = [] end def find(options = {}, &block) options[:count] ||= :all options[:order] ||= :asc options[:what] ||= :first emails_index = (0...@@emails.size).to_a emails_index.reverse! if options[:what] == :last emails_index = case count = options[:count] when :all then emails_index when Fixnum then emails_index[0, count] else raise 'Invalid count option value: ' + count.inspect end if options[:what] == :last && options[:order] == :asc || options[:what] == :first && options[:order] == :desc emails_index.reverse! end emails_index.each { |idx| @@emails[idx].mark_for_delete = true } if options[:delete_after_find] emails = emails_index.map { |idx| @@emails[idx] } emails.each { |email| yield email } if block_given? @@emails.reject!(&:is_marked_for_delete?) if options[:delete_after_find] emails.size == 1 && options[:count] == 1 ? emails.first : emails end end end mail-2.5.4/lib/mail/parsers/000077500000000000000000000000001214434061600156145ustar00rootroot00000000000000mail-2.5.4/lib/mail/parsers/address_lists.rb000066400000000000000000000024331214434061600210060ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module AddressLists include Treetop::Runtime def root @root ||= :primary_address end include RFC2822 module PrimaryAddress0 def addresses ([first_addr] + other_addr.elements.map { |o| o.addr_value }).reject { |e| e.empty? } end end module PrimaryAddress1 def addresses [first_addr] + other_addr.elements.map { |o| o.addr_value } end end def _nt_primary_address start_index = index if node_cache[:primary_address].has_key?(index) cached = node_cache[:primary_address][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_address_list r1.extend(PrimaryAddress0) if r1 r0 = r1 else r2 = _nt_obs_addr_list r2.extend(PrimaryAddress1) if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:primary_address][start_index] = r0 r0 end end class AddressListsParser < Treetop::Runtime::CompiledParser include AddressLists end end mail-2.5.4/lib/mail/parsers/address_lists.treetop000066400000000000000000000006121214434061600220620ustar00rootroot00000000000000module Mail grammar AddressLists include RFC2822 rule primary_address address_list { def addresses ([first_addr] + other_addr.elements.map { |o| o.addr_value }).reject { |e| e.empty? } end } / obs_addr_list { def addresses [first_addr] + other_addr.elements.map { |o| o.addr_value } end } end end end mail-2.5.4/lib/mail/parsers/content_disposition.rb000066400000000000000000000275671214434061600222600ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module ContentDisposition include Treetop::Runtime def root @root ||= :content_disposition end include RFC2822 include RFC2045 module ContentDisposition0 def CFWS1 elements[0] end def parameter elements[2] end def CFWS2 elements[3] end end module ContentDisposition1 def disposition_type elements[0] end def param_hashes elements[1] end end module ContentDisposition2 def parameters param_hashes.elements.map do |param| param.parameter.param_hash end end end def _nt_content_disposition start_index = index if node_cache[:content_disposition].has_key?(index) cached = node_cache[:content_disposition][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_disposition_type s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] r4 = _nt_CFWS s3 << r4 if r4 if has_terminal?(";", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r5 = nil end s3 << r5 if r5 r6 = _nt_parameter s3 << r6 if r6 r7 = _nt_CFWS s3 << r7 end end end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ContentDisposition0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ContentDisposition1) r0.extend(ContentDisposition2) else @index = i0 r0 = nil end node_cache[:content_disposition][start_index] = r0 r0 end module DispositionType0 end module DispositionType1 end def _nt_disposition_type start_index = index if node_cache[:disposition_type].has_key?(index) cached = node_cache[:disposition_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] if has_terminal?('\G[iI]', true, index) r2 = true @index += 1 else r2 = nil end s1 << r2 if r2 if has_terminal?('\G[nN]', true, index) r3 = true @index += 1 else r3 = nil end s1 << r3 if r3 if has_terminal?('\G[lL]', true, index) r4 = true @index += 1 else r4 = nil end s1 << r4 if r4 if has_terminal?('\G[iI]', true, index) r5 = true @index += 1 else r5 = nil end s1 << r5 if r5 if has_terminal?('\G[nN]', true, index) r6 = true @index += 1 else r6 = nil end s1 << r6 if r6 if has_terminal?('\G[eE]', true, index) r7 = true @index += 1 else r7 = nil end s1 << r7 end end end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(DispositionType0) else @index = i1 r1 = nil end if r1 r0 = r1 else i8, s8 = index, [] if has_terminal?('\G[aA]', true, index) r9 = true @index += 1 else r9 = nil end s8 << r9 if r9 if has_terminal?('\G[tT]', true, index) r10 = true @index += 1 else r10 = nil end s8 << r10 if r10 if has_terminal?('\G[tT]', true, index) r11 = true @index += 1 else r11 = nil end s8 << r11 if r11 if has_terminal?('\G[aA]', true, index) r12 = true @index += 1 else r12 = nil end s8 << r12 if r12 if has_terminal?('\G[cC]', true, index) r13 = true @index += 1 else r13 = nil end s8 << r13 if r13 if has_terminal?('\G[hH]', true, index) r14 = true @index += 1 else r14 = nil end s8 << r14 if r14 if has_terminal?('\G[mM]', true, index) r15 = true @index += 1 else r15 = nil end s8 << r15 if r15 if has_terminal?('\G[eE]', true, index) r16 = true @index += 1 else r16 = nil end s8 << r16 if r16 if has_terminal?('\G[nN]', true, index) r17 = true @index += 1 else r17 = nil end s8 << r17 if r17 if has_terminal?('\G[tT]', true, index) r18 = true @index += 1 else r18 = nil end s8 << r18 end end end end end end end end end if s8.last r8 = instantiate_node(SyntaxNode,input, i8...index, s8) r8.extend(DispositionType1) else @index = i8 r8 = nil end if r8 r0 = r8 else r19 = _nt_extension_token if r19 r0 = r19 else if has_terminal?('', false, index) r20 = instantiate_node(SyntaxNode,input, index...(index + 0)) @index += 0 else terminal_parse_failure('') r20 = nil end if r20 r0 = r20 else @index = i0 r0 = nil end end end end node_cache[:disposition_type][start_index] = r0 r0 end def _nt_extension_token start_index = index if node_cache[:extension_token].has_key?(index) cached = node_cache[:extension_token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_ietf_token if r1 r0 = r1 else r2 = _nt_custom_x_token if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:extension_token][start_index] = r0 r0 end module Parameter0 def attr elements[1] end def val elements[3] end end module Parameter1 def param_hash {attr.text_value => val.text_value} end end def _nt_parameter start_index = index if node_cache[:parameter].has_key?(index) cached = node_cache[:parameter][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_attribute s0 << r3 if r3 if has_terminal?("=", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("=") r4 = nil end s0 << r4 if r4 r5 = _nt_value s0 << r5 if r5 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Parameter0) r0.extend(Parameter1) else @index = i0 r0 = nil end node_cache[:parameter][start_index] = r0 r0 end def _nt_attribute start_index = index if node_cache[:attribute].has_key?(index) cached = node_cache[:attribute][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do r1 = _nt_token if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:attribute][start_index] = r0 r0 end module Value0 def text_value quoted_content.text_value end end def _nt_value start_index = index if node_cache[:value].has_key?(index) cached = node_cache[:value][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_quoted_string r1.extend(Value0) if r1 r0 = r1 else s2, i2 = [], index loop do i3 = index r4 = _nt_token if r4 r3 = r4 else if has_terminal?('\G[\\x3d]', true, index) r5 = true @index += 1 else r5 = nil end if r5 r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:value][start_index] = r0 r0 end end class ContentDispositionParser < Treetop::Runtime::CompiledParser include ContentDisposition end end mail-2.5.4/lib/mail/parsers/content_disposition.treetop000066400000000000000000000016351214434061600233230ustar00rootroot00000000000000module Mail grammar ContentDisposition include RFC2822 include RFC2045 rule content_disposition disposition_type param_hashes:(CFWS ";" parameter CFWS)* { def parameters param_hashes.elements.map do |param| param.parameter.param_hash end end } end rule disposition_type [iI] [nN] [lL] [iI] [nN] [eE] / [aA] [tT] [tT] [aA] [cC] [hH] [mM] [eE] [nN] [tT] / extension_token / '' end rule extension_token ietf_token / custom_x_token end rule parameter CFWS? attr:attribute "=" val:value CFWS? { def param_hash {attr.text_value => val.text_value} end } end rule attribute token+ end rule value quoted_string { def text_value quoted_content.text_value end } / (token / [\x3d])+ end end end mail-2.5.4/lib/mail/parsers/content_location.rb000066400000000000000000000051111214434061600215010ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module ContentLocation include Treetop::Runtime def root @root ||= :primary end include RFC2822 include RFC2045 module Primary0 def CFWS1 elements[0] end def location elements[1] end def CFWS2 elements[2] end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_CFWS s0 << r1 if r1 r2 = _nt_location s0 << r2 if r2 r3 = _nt_CFWS s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Primary0) else @index = i0 r0 = nil end node_cache[:primary][start_index] = r0 r0 end module Location0 def text_value quoted_content.text_value end end def _nt_location start_index = index if node_cache[:location].has_key?(index) cached = node_cache[:location][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_quoted_string r1.extend(Location0) if r1 r0 = r1 else s2, i2 = [], index loop do i3 = index r4 = _nt_token if r4 r3 = r4 else if has_terminal?('\G[\\x3d]', true, index) r5 = true @index += 1 else r5 = nil end if r5 r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:location][start_index] = r0 r0 end end class ContentLocationParser < Treetop::Runtime::CompiledParser include ContentLocation end endmail-2.5.4/lib/mail/parsers/content_location.treetop000066400000000000000000000004441214434061600225640ustar00rootroot00000000000000module Mail grammar ContentLocation include RFC2822 include RFC2045 rule primary CFWS location CFWS end rule location quoted_string { def text_value quoted_content.text_value end } / (token / [\x3d])+ end end endmail-2.5.4/lib/mail/parsers/content_transfer_encoding.rb000066400000000000000000000115131214434061600233660ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module ContentTransferEncoding include Treetop::Runtime def root @root ||= :primary end include RFC2822 include RFC2045 module Primary0 def CFWS1 elements[0] end def encoding elements[1] end def CFWS2 elements[2] end def CFWS3 elements[4] end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_CFWS s0 << r1 if r1 r2 = _nt_encoding s0 << r2 if r2 r3 = _nt_CFWS s0 << r3 if r3 if has_terminal?(";", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r5 = nil end if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 if r4 r6 = _nt_CFWS s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Primary0) else @index = i0 r0 = nil end node_cache[:primary][start_index] = r0 r0 end def _nt_encoding start_index = index if node_cache[:encoding].has_key?(index) cached = node_cache[:encoding][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("7bits", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 5)) @index += 5 else terminal_parse_failure("7bits") r1 = nil end if r1 r0 = r1 else if has_terminal?("8bits", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 5)) @index += 5 else terminal_parse_failure("8bits") r2 = nil end if r2 r0 = r2 else if has_terminal?("7bit", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 4)) @index += 4 else terminal_parse_failure("7bit") r3 = nil end if r3 r0 = r3 else if has_terminal?("8bit", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 4)) @index += 4 else terminal_parse_failure("8bit") r4 = nil end if r4 r0 = r4 else if has_terminal?("binary", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 6)) @index += 6 else terminal_parse_failure("binary") r5 = nil end if r5 r0 = r5 else if has_terminal?("quoted-printable", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 16)) @index += 16 else terminal_parse_failure("quoted-printable") r6 = nil end if r6 r0 = r6 else if has_terminal?("base64", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 6)) @index += 6 else terminal_parse_failure("base64") r7 = nil end if r7 r0 = r7 else r8 = _nt_ietf_token if r8 r0 = r8 else r9 = _nt_custom_x_token if r9 r0 = r9 else @index = i0 r0 = nil end end end end end end end end end node_cache[:encoding][start_index] = r0 r0 end end class ContentTransferEncodingParser < Treetop::Runtime::CompiledParser include ContentTransferEncoding end end mail-2.5.4/lib/mail/parsers/content_transfer_encoding.treetop000066400000000000000000000005011214434061600244400ustar00rootroot00000000000000module Mail grammar ContentTransferEncoding include RFC2822 include RFC2045 rule primary CFWS encoding CFWS ";"? CFWS end rule encoding "7bits" / "8bits" / "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" / ietf_token / custom_x_token end end end mail-2.5.4/lib/mail/parsers/content_type.rb000066400000000000000000000560241214434061600206630ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module ContentType include Treetop::Runtime def root @root ||= :content_type end include RFC2822 include RFC2045 module ContentType0 def CFWS1 elements[0] end def parameter elements[2] end def CFWS2 elements[3] end end module ContentType1 def main_type elements[0] end def sub_type elements[2] end def param_hashes elements[3] end end module ContentType2 def parameters param_hashes.elements.map do |param| param.parameter.param_hash end end end def _nt_content_type start_index = index if node_cache[:content_type].has_key?(index) cached = node_cache[:content_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_main_type s0 << r1 if r1 if has_terminal?("/", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("/") r2 = nil end s0 << r2 if r2 r3 = _nt_sub_type s0 << r3 if r3 s4, i4 = [], index loop do i5, s5 = index, [] r6 = _nt_CFWS s5 << r6 if r6 s7, i7 = [], index loop do if has_terminal?(";", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r8 = nil end if r8 s7 << r8 else break end end r7 = instantiate_node(SyntaxNode,input, i7...index, s7) s5 << r7 if r7 r9 = _nt_parameter s5 << r9 if r9 r10 = _nt_CFWS s5 << r10 end end end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(ContentType0) else @index = i5 r5 = nil end if r5 s4 << r5 else break end end r4 = instantiate_node(SyntaxNode,input, i4...index, s4) s0 << r4 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ContentType1) r0.extend(ContentType2) else @index = i0 r0 = nil end node_cache[:content_type][start_index] = r0 r0 end def _nt_main_type start_index = index if node_cache[:main_type].has_key?(index) cached = node_cache[:main_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_discrete_type if r1 r0 = r1 else r2 = _nt_composite_type if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:main_type][start_index] = r0 r0 end module DiscreteType0 end module DiscreteType1 end module DiscreteType2 end module DiscreteType3 end module DiscreteType4 end def _nt_discrete_type start_index = index if node_cache[:discrete_type].has_key?(index) cached = node_cache[:discrete_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] if has_terminal?('\G[tT]', true, index) r2 = true @index += 1 else r2 = nil end s1 << r2 if r2 if has_terminal?('\G[eE]', true, index) r3 = true @index += 1 else r3 = nil end s1 << r3 if r3 if has_terminal?('\G[xX]', true, index) r4 = true @index += 1 else r4 = nil end s1 << r4 if r4 if has_terminal?('\G[tT]', true, index) r5 = true @index += 1 else r5 = nil end s1 << r5 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(DiscreteType0) else @index = i1 r1 = nil end if r1 r0 = r1 else i6, s6 = index, [] if has_terminal?('\G[iI]', true, index) r7 = true @index += 1 else r7 = nil end s6 << r7 if r7 if has_terminal?('\G[mM]', true, index) r8 = true @index += 1 else r8 = nil end s6 << r8 if r8 if has_terminal?('\G[aA]', true, index) r9 = true @index += 1 else r9 = nil end s6 << r9 if r9 if has_terminal?('\G[gG]', true, index) r10 = true @index += 1 else r10 = nil end s6 << r10 if r10 if has_terminal?('\G[eE]', true, index) r11 = true @index += 1 else r11 = nil end s6 << r11 end end end end if s6.last r6 = instantiate_node(SyntaxNode,input, i6...index, s6) r6.extend(DiscreteType1) else @index = i6 r6 = nil end if r6 r0 = r6 else i12, s12 = index, [] if has_terminal?('\G[aA]', true, index) r13 = true @index += 1 else r13 = nil end s12 << r13 if r13 if has_terminal?('\G[uU]', true, index) r14 = true @index += 1 else r14 = nil end s12 << r14 if r14 if has_terminal?('\G[dD]', true, index) r15 = true @index += 1 else r15 = nil end s12 << r15 if r15 if has_terminal?('\G[iI]', true, index) r16 = true @index += 1 else r16 = nil end s12 << r16 if r16 if has_terminal?('\G[oO]', true, index) r17 = true @index += 1 else r17 = nil end s12 << r17 end end end end if s12.last r12 = instantiate_node(SyntaxNode,input, i12...index, s12) r12.extend(DiscreteType2) else @index = i12 r12 = nil end if r12 r0 = r12 else i18, s18 = index, [] if has_terminal?('\G[vV]', true, index) r19 = true @index += 1 else r19 = nil end s18 << r19 if r19 if has_terminal?('\G[iI]', true, index) r20 = true @index += 1 else r20 = nil end s18 << r20 if r20 if has_terminal?('\G[dD]', true, index) r21 = true @index += 1 else r21 = nil end s18 << r21 if r21 if has_terminal?('\G[eE]', true, index) r22 = true @index += 1 else r22 = nil end s18 << r22 if r22 if has_terminal?('\G[oO]', true, index) r23 = true @index += 1 else r23 = nil end s18 << r23 end end end end if s18.last r18 = instantiate_node(SyntaxNode,input, i18...index, s18) r18.extend(DiscreteType3) else @index = i18 r18 = nil end if r18 r0 = r18 else i24, s24 = index, [] if has_terminal?('\G[aA]', true, index) r25 = true @index += 1 else r25 = nil end s24 << r25 if r25 if has_terminal?('\G[pP]', true, index) r26 = true @index += 1 else r26 = nil end s24 << r26 if r26 if has_terminal?('\G[pP]', true, index) r27 = true @index += 1 else r27 = nil end s24 << r27 if r27 if has_terminal?('\G[lL]', true, index) r28 = true @index += 1 else r28 = nil end s24 << r28 if r28 if has_terminal?('\G[iI]', true, index) r29 = true @index += 1 else r29 = nil end s24 << r29 if r29 if has_terminal?('\G[cC]', true, index) r30 = true @index += 1 else r30 = nil end s24 << r30 if r30 if has_terminal?('\G[aA]', true, index) r31 = true @index += 1 else r31 = nil end s24 << r31 if r31 if has_terminal?('\G[tT]', true, index) r32 = true @index += 1 else r32 = nil end s24 << r32 if r32 if has_terminal?('\G[iI]', true, index) r33 = true @index += 1 else r33 = nil end s24 << r33 if r33 if has_terminal?('\G[oO]', true, index) r34 = true @index += 1 else r34 = nil end s24 << r34 if r34 if has_terminal?('\G[nN]', true, index) r35 = true @index += 1 else r35 = nil end s24 << r35 end end end end end end end end end end if s24.last r24 = instantiate_node(SyntaxNode,input, i24...index, s24) r24.extend(DiscreteType4) else @index = i24 r24 = nil end if r24 r0 = r24 else r36 = _nt_extension_token if r36 r0 = r36 else @index = i0 r0 = nil end end end end end end node_cache[:discrete_type][start_index] = r0 r0 end module CompositeType0 end module CompositeType1 end def _nt_composite_type start_index = index if node_cache[:composite_type].has_key?(index) cached = node_cache[:composite_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] if has_terminal?('\G[mM]', true, index) r2 = true @index += 1 else r2 = nil end s1 << r2 if r2 if has_terminal?('\G[eE]', true, index) r3 = true @index += 1 else r3 = nil end s1 << r3 if r3 if has_terminal?('\G[sS]', true, index) r4 = true @index += 1 else r4 = nil end s1 << r4 if r4 if has_terminal?('\G[sS]', true, index) r5 = true @index += 1 else r5 = nil end s1 << r5 if r5 if has_terminal?('\G[aA]', true, index) r6 = true @index += 1 else r6 = nil end s1 << r6 if r6 if has_terminal?('\G[gG]', true, index) r7 = true @index += 1 else r7 = nil end s1 << r7 if r7 if has_terminal?('\G[eE]', true, index) r8 = true @index += 1 else r8 = nil end s1 << r8 end end end end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(CompositeType0) else @index = i1 r1 = nil end if r1 r0 = r1 else i9, s9 = index, [] if has_terminal?('\G[mM]', true, index) r10 = true @index += 1 else r10 = nil end s9 << r10 if r10 if has_terminal?('\G[uU]', true, index) r11 = true @index += 1 else r11 = nil end s9 << r11 if r11 if has_terminal?('\G[lL]', true, index) r12 = true @index += 1 else r12 = nil end s9 << r12 if r12 if has_terminal?('\G[tT]', true, index) r13 = true @index += 1 else r13 = nil end s9 << r13 if r13 if has_terminal?('\G[iI]', true, index) r14 = true @index += 1 else r14 = nil end s9 << r14 if r14 if has_terminal?('\G[pP]', true, index) r15 = true @index += 1 else r15 = nil end s9 << r15 if r15 if has_terminal?('\G[aA]', true, index) r16 = true @index += 1 else r16 = nil end s9 << r16 if r16 if has_terminal?('\G[rR]', true, index) r17 = true @index += 1 else r17 = nil end s9 << r17 if r17 if has_terminal?('\G[tT]', true, index) r18 = true @index += 1 else r18 = nil end s9 << r18 end end end end end end end end if s9.last r9 = instantiate_node(SyntaxNode,input, i9...index, s9) r9.extend(CompositeType1) else @index = i9 r9 = nil end if r9 r0 = r9 else r19 = _nt_extension_token if r19 r0 = r19 else @index = i0 r0 = nil end end end node_cache[:composite_type][start_index] = r0 r0 end def _nt_extension_token start_index = index if node_cache[:extension_token].has_key?(index) cached = node_cache[:extension_token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_ietf_token if r1 r0 = r1 else r2 = _nt_custom_x_token if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:extension_token][start_index] = r0 r0 end def _nt_sub_type start_index = index if node_cache[:sub_type].has_key?(index) cached = node_cache[:sub_type][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_extension_token if r1 r0 = r1 else r2 = _nt_iana_token if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:sub_type][start_index] = r0 r0 end module Parameter0 def attr elements[1] end def val elements[3] end end module Parameter1 def param_hash {attr.text_value => val.text_value} end end def _nt_parameter start_index = index if node_cache[:parameter].has_key?(index) cached = node_cache[:parameter][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_attribute s0 << r3 if r3 if has_terminal?("=", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("=") r4 = nil end s0 << r4 if r4 r5 = _nt_value s0 << r5 if r5 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Parameter0) r0.extend(Parameter1) else @index = i0 r0 = nil end node_cache[:parameter][start_index] = r0 r0 end def _nt_attribute start_index = index if node_cache[:attribute].has_key?(index) cached = node_cache[:attribute][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do r1 = _nt_token if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:attribute][start_index] = r0 r0 end module Value0 def text_value quoted_content.text_value end end def _nt_value start_index = index if node_cache[:value].has_key?(index) cached = node_cache[:value][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_quoted_string r1.extend(Value0) if r1 r0 = r1 else s2, i2 = [], index loop do i3 = index r4 = _nt_token if r4 r3 = r4 else if has_terminal?('\G[\\x3d]', true, index) r5 = true @index += 1 else r5 = nil end if r5 r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:value][start_index] = r0 r0 end end class ContentTypeParser < Treetop::Runtime::CompiledParser include ContentType end end mail-2.5.4/lib/mail/parsers/content_type.treetop000066400000000000000000000030241214434061600217320ustar00rootroot00000000000000module Mail grammar ContentType include RFC2822 include RFC2045 rule content_type main_type "/" sub_type param_hashes:(CFWS ";"* parameter CFWS)* { def parameters param_hashes.elements.map do |param| param.parameter.param_hash end end } end rule main_type discrete_type / composite_type end # This matches in a case insensitive way: # # rule discrete_type # "text" / "image" / "audio" / "video" / "application" / extension_token # end rule discrete_type [tT] [eE] [xX] [tT] / [iI] [mM] [aA] [gG] [eE] / [aA] [uU] [dD] [iI] [oO] / [vV] [iI] [dD] [eE] [oO] / [aA] [pP] [pP] [lL] [iI] [cC] [aA] [tT] [iI] [oO] [nN] / extension_token end # This matches in a case insensitive way: # # rule composite_type # "message" / "multipart" / extension_token # end rule composite_type [mM] [eE] [sS] [sS] [aA] [gG] [eE] / [mM] [uU] [lL] [tT] [iI] [pP] [aA] [rR] [tT] / extension_token end rule extension_token ietf_token / custom_x_token end rule sub_type extension_token / iana_token end rule parameter CFWS? attr:attribute "=" val:value CFWS? { def param_hash {attr.text_value => val.text_value} end } end rule attribute token+ end rule value quoted_string { def text_value quoted_content.text_value end } / (token / [\x3d])+ end end end mail-2.5.4/lib/mail/parsers/date_time.rb000066400000000000000000000041731214434061600201010ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module DateTime include Treetop::Runtime def root @root ||= :primary end include RFC2822 module Primary0 def day_of_week elements[0] end end module Primary1 def date elements[1] end def FWS elements[2] end def time elements[3] end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i2, s2 = index, [] r3 = _nt_day_of_week s2 << r3 if r3 if has_terminal?(",", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r4 = nil end s2 << r4 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(Primary0) else @index = i2 r2 = nil end if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r5 = _nt_date s0 << r5 if r5 r6 = _nt_FWS s0 << r6 if r6 r7 = _nt_time s0 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s0 << r8 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Primary1) else @index = i0 r0 = nil end node_cache[:primary][start_index] = r0 r0 end end class DateTimeParser < Treetop::Runtime::CompiledParser include DateTime end endmail-2.5.4/lib/mail/parsers/date_time.treetop000066400000000000000000000002121214434061600211460ustar00rootroot00000000000000module Mail grammar DateTime include RFC2822 rule primary ( day_of_week ",")? date FWS time CFWS? end end endmail-2.5.4/lib/mail/parsers/envelope_from.rb000066400000000000000000000103721214434061600210040ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module EnvelopeFrom include Treetop::Runtime def root @root ||= :primary end include RFC2822 module Primary0 def addr_spec elements[0] end def ctime_date elements[1] end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_addr_spec s0 << r1 if r1 r2 = _nt_ctime_date s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Primary0) else @index = i0 r0 = nil end node_cache[:primary][start_index] = r0 r0 end module CtimeDate0 def day_name elements[0] end def month_name elements[2] end def day elements[4] end def time_of_day elements[6] end def year elements[8] end end def _nt_ctime_date start_index = index if node_cache[:ctime_date].has_key?(index) cached = node_cache[:ctime_date][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_day_name s0 << r1 if r1 s2, i2 = [], index loop do if has_terminal?(" ", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(" ") r3 = nil end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 r4 = _nt_month_name s0 << r4 if r4 s5, i5 = [], index loop do if has_terminal?(" ", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(" ") r6 = nil end if r6 s5 << r6 else break end end if s5.empty? @index = i5 r5 = nil else r5 = instantiate_node(SyntaxNode,input, i5...index, s5) end s0 << r5 if r5 r7 = _nt_day s0 << r7 if r7 if has_terminal?(" ", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(" ") r8 = nil end s0 << r8 if r8 r9 = _nt_time_of_day s0 << r9 if r9 if has_terminal?(" ", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(" ") r10 = nil end s0 << r10 if r10 r11 = _nt_year s0 << r11 end end end end end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(CtimeDate0) else @index = i0 r0 = nil end node_cache[:ctime_date][start_index] = r0 r0 end end class EnvelopeFromParser < Treetop::Runtime::CompiledParser include EnvelopeFrom end endmail-2.5.4/lib/mail/parsers/envelope_from.treetop000066400000000000000000000016761214434061600220720ustar00rootroot00000000000000module Mail grammar EnvelopeFrom include RFC2822 # The exact character sequence of "From"; # # a single Space character (0x20); # # the email address of the message sender (as obtained from the # message envelope or other authoritative source), conformant # with the "addr-spec" syntax from RFC 2822; # # a single Space character; # # a timestamp indicating the UTC date and time when the message # was originally received, conformant with the syntax of the # traditional UNIX 'ctime' output sans timezone (note that the # use of UTC precludes the need for a timezone indicator); # Thu Nov 24 18:22:48 1986 # # an end-of-line marker. rule primary addr_spec ctime_date end rule ctime_date day_name " "+ month_name " "+ day " " time_of_day " " year end end endmail-2.5.4/lib/mail/parsers/message_ids.rb000066400000000000000000000015401214434061600204240ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module MessageIds include Treetop::Runtime def root @root ||= :primary end include RFC2822 module Primary0 def message_ids [first_msg_id] + other_msg_ids.elements.map { |o| o.msg_id_value } end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_message_ids r0.extend(Primary0) node_cache[:primary][start_index] = r0 r0 end end class MessageIdsParser < Treetop::Runtime::CompiledParser include MessageIds end endmail-2.5.4/lib/mail/parsers/message_ids.treetop000066400000000000000000000003531214434061600215040ustar00rootroot00000000000000module Mail grammar MessageIds include RFC2822 rule primary message_ids { def message_ids [first_msg_id] + other_msg_ids.elements.map { |o| o.msg_id_value } end } end end endmail-2.5.4/lib/mail/parsers/mime_version.rb000066400000000000000000000056651214434061600206510ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module MimeVersion include Treetop::Runtime def root @root ||= :version end include RFC2822 module Version0 def CFWS1 elements[0] end def major_digits elements[1] end def minor_digits elements[5] end def CFWS2 elements[6] end end module Version1 def major major_digits end def minor minor_digits end end def _nt_version start_index = index if node_cache[:version].has_key?(index) cached = node_cache[:version][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_CFWS s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_DIGIT if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 r5 = _nt_comment if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 if r4 if has_terminal?(".", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r6 = nil end s0 << r6 if r6 r8 = _nt_comment if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s0 << r7 if r7 s9, i9 = [], index loop do r10 = _nt_DIGIT if r10 s9 << r10 else break end end if s9.empty? @index = i9 r9 = nil else r9 = instantiate_node(SyntaxNode,input, i9...index, s9) end s0 << r9 if r9 r11 = _nt_CFWS s0 << r11 end end end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Version0) r0.extend(Version1) else @index = i0 r0 = nil end node_cache[:version][start_index] = r0 r0 end end class MimeVersionParser < Treetop::Runtime::CompiledParser include MimeVersion end endmail-2.5.4/lib/mail/parsers/mime_version.treetop000066400000000000000000000004521214434061600217150ustar00rootroot00000000000000module Mail grammar MimeVersion include RFC2822 rule version CFWS major_digits:DIGIT+ comment? "." comment? minor_digits:DIGIT+ CFWS { def major major_digits end def minor minor_digits end } end end endmail-2.5.4/lib/mail/parsers/phrase_lists.rb000066400000000000000000000016161214434061600206450ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module PhraseLists include Treetop::Runtime def root @root ||= :primary_phrase end include RFC2822 module PrimaryPhrase0 def phrases [first_phrase] + other_phrases.elements.map { |o| o.phrase_value } end end def _nt_primary_phrase start_index = index if node_cache[:primary_phrase].has_key?(index) cached = node_cache[:primary_phrase][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_phrase_list r0.extend(PrimaryPhrase0) node_cache[:primary_phrase][start_index] = r0 r0 end end class PhraseListsParser < Treetop::Runtime::CompiledParser include PhraseLists end endmail-2.5.4/lib/mail/parsers/phrase_lists.treetop000066400000000000000000000003531214434061600217210ustar00rootroot00000000000000module Mail grammar PhraseLists include RFC2822 rule primary_phrase phrase_list { def phrases [first_phrase] + other_phrases.elements.map { |o| o.phrase_value } end } end end endmail-2.5.4/lib/mail/parsers/received.rb000066400000000000000000000025331214434061600177320ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module Received include Treetop::Runtime def root @root ||= :primary end include RFC2822 module Primary0 def name_val_list elements[0] end def date_time elements[2] end end def _nt_primary start_index = index if node_cache[:primary].has_key?(index) cached = node_cache[:primary][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_name_val_list s0 << r1 if r1 if has_terminal?(";", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r2 = nil end s0 << r2 if r2 r3 = _nt_date_time s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Primary0) else @index = i0 r0 = nil end node_cache[:primary][start_index] = r0 r0 end end class ReceivedParser < Treetop::Runtime::CompiledParser include Received end endmail-2.5.4/lib/mail/parsers/received.treetop000066400000000000000000000001761214434061600210120ustar00rootroot00000000000000module Mail grammar Received include RFC2822 rule primary name_val_list ";" date_time end end endmail-2.5.4/lib/mail/parsers/rfc2045.rb000066400000000000000000000275421214434061600172400ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module RFC2045 include Treetop::Runtime def root @root ||= :tspecials end def _nt_tspecials start_index = index if node_cache[:tspecials].has_key?(index) cached = node_cache[:tspecials][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("(", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("(") r1 = nil end if r1 r0 = r1 else if has_terminal?(")", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(")") r2 = nil end if r2 r0 = r2 else if has_terminal?("<", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r3 = nil end if r3 r0 = r3 else if has_terminal?(">", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r4 = nil end if r4 r0 = r4 else if has_terminal?("@", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r5 = nil end if r5 r0 = r5 else if has_terminal?(",", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r6 = nil end if r6 r0 = r6 else if has_terminal?(";", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r7 = nil end if r7 r0 = r7 else if has_terminal?(":", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r8 = nil end if r8 r0 = r8 else if has_terminal?('\\', false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('\\') r9 = nil end if r9 r0 = r9 else if has_terminal?("<", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r10 = nil end if r10 r0 = r10 else if has_terminal?(">", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r11 = nil end if r11 r0 = r11 else if has_terminal?("/", false, index) r12 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("/") r12 = nil end if r12 r0 = r12 else if has_terminal?("[", false, index) r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("[") r13 = nil end if r13 r0 = r13 else if has_terminal?("]", false, index) r14 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("]") r14 = nil end if r14 r0 = r14 else if has_terminal?("?", false, index) r15 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("?") r15 = nil end if r15 r0 = r15 else if has_terminal?("=", false, index) r16 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("=") r16 = nil end if r16 r0 = r16 else @index = i0 r0 = nil end end end end end end end end end end end end end end end end node_cache[:tspecials][start_index] = r0 r0 end def _nt_ietf_token start_index = index if node_cache[:ietf_token].has_key?(index) cached = node_cache[:ietf_token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do r1 = _nt_token if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:ietf_token][start_index] = r0 r0 end module CustomXToken0 end def _nt_custom_x_token start_index = index if node_cache[:custom_x_token].has_key?(index) cached = node_cache[:custom_x_token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?('\G[xX]', true, index) r1 = true @index += 1 else r1 = nil end s0 << r1 if r1 if has_terminal?("-", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("-") r2 = nil end s0 << r2 if r2 s3, i3 = [], index loop do r4 = _nt_token if r4 s3 << r4 else break end end if s3.empty? @index = i3 r3 = nil else r3 = instantiate_node(SyntaxNode,input, i3...index, s3) end s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(CustomXToken0) else @index = i0 r0 = nil end node_cache[:custom_x_token][start_index] = r0 r0 end def _nt_iana_token start_index = index if node_cache[:iana_token].has_key?(index) cached = node_cache[:iana_token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do r1 = _nt_token if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:iana_token][start_index] = r0 r0 end def _nt_token start_index = index if node_cache[:token].has_key?(index) cached = node_cache[:token][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?('\G[\\x21-\\x27]', true, index) r1 = true @index += 1 else r1 = nil end if r1 r0 = r1 else if has_terminal?('\G[\\x2a-\\x2b]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x2c-\\x2e]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else if has_terminal?('\G[\\x30-\\x39]', true, index) r4 = true @index += 1 else r4 = nil end if r4 r0 = r4 else if has_terminal?('\G[\\x41-\\x5a]', true, index) r5 = true @index += 1 else r5 = nil end if r5 r0 = r5 else if has_terminal?('\G[\\x5e-\\x7e]', true, index) r6 = true @index += 1 else r6 = nil end if r6 r0 = r6 else @index = i0 r0 = nil end end end end end end node_cache[:token][start_index] = r0 r0 end end class RFC2045Parser < Treetop::Runtime::CompiledParser include RFC2045 end end mail-2.5.4/lib/mail/parsers/rfc2045.treetop000066400000000000000000000012711214434061600203060ustar00rootroot00000000000000module Mail grammar RFC2045 rule tspecials "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / '\\' / "<" / ">" / "/" / "[" / "]" / "?" / "=" end rule ietf_token token+ end rule custom_x_token [xX] "-" token+ end rule iana_token token+ # end rule token [\x21-\x27] / # any (US-ASCII) CHAR [\x2a-\x2b] / # except SPACE, [\x2c-\x2e] / # CTLs, [\x30-\x39] / # or tspecials [\x41-\x5a] / [\x5e-\x7e] end end end mail-2.5.4/lib/mail/parsers/rfc2822.rb000066400000000000000000003754361214434061600172530ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module RFC2822 include Treetop::Runtime def root @root ||= :ALPHA end include RFC2822Obsolete def _nt_ALPHA start_index = index if node_cache[:ALPHA].has_key?(index) cached = node_cache[:ALPHA][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?('\G[a-zA-Z]', true, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else r0 = nil end node_cache[:ALPHA][start_index] = r0 r0 end def _nt_DIGIT start_index = index if node_cache[:DIGIT].has_key?(index) cached = node_cache[:DIGIT][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?('\G[0-9]', true, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else r0 = nil end node_cache[:DIGIT][start_index] = r0 r0 end def _nt_DQUOTE start_index = index if node_cache[:DQUOTE].has_key?(index) cached = node_cache[:DQUOTE][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?('"', false, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('"') r0 = nil end node_cache[:DQUOTE][start_index] = r0 r0 end def _nt_LF start_index = index if node_cache[:LF].has_key?(index) cached = node_cache[:LF][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?("\n", false, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("\n") r0 = nil end node_cache[:LF][start_index] = r0 r0 end def _nt_CR start_index = index if node_cache[:CR].has_key?(index) cached = node_cache[:CR][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?("\r", false, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("\r") r0 = nil end node_cache[:CR][start_index] = r0 r0 end def _nt_CRLF start_index = index if node_cache[:CRLF].has_key?(index) cached = node_cache[:CRLF][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?("\r\n", false, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 2)) @index += 2 else terminal_parse_failure("\r\n") r0 = nil end node_cache[:CRLF][start_index] = r0 r0 end def _nt_WSP start_index = index if node_cache[:WSP].has_key?(index) cached = node_cache[:WSP][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end if has_terminal?('\G[\\x09\\x20]', true, index) r0 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else r0 = nil end node_cache[:WSP][start_index] = r0 r0 end module FWS0 def CRLF elements[1] end end module FWS1 def CRLF elements[0] end end def _nt_FWS start_index = index if node_cache[:FWS].has_key?(index) cached = node_cache[:FWS][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s1 << r2 if r2 r4 = _nt_CRLF s1 << r4 if r4 s5, i5 = [], index loop do r6 = _nt_WSP if r6 s5 << r6 else break end end if s5.empty? @index = i5 r5 = nil else r5 = instantiate_node(SyntaxNode,input, i5...index, s5) end s1 << r5 end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(FWS0) else @index = i1 r1 = nil end if r1 r0 = r1 else i7, s7 = index, [] r8 = _nt_CRLF s7 << r8 if r8 s9, i9 = [], index loop do r10 = _nt_WSP if r10 s9 << r10 else break end end if s9.empty? @index = i9 r9 = nil else r9 = instantiate_node(SyntaxNode,input, i9...index, s9) end s7 << r9 end if s7.last r7 = instantiate_node(SyntaxNode,input, i7...index, s7) r7.extend(FWS1) else @index = i7 r7 = nil end if r7 r0 = r7 else r11 = _nt_obs_FWS if r11 r0 = r11 else @index = i0 r0 = nil end end end node_cache[:FWS][start_index] = r0 r0 end module CFWS0 def comment elements[1] end end module CFWS1 end def _nt_CFWS start_index = index if node_cache[:CFWS].has_key?(index) cached = node_cache[:CFWS][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do i2, s2 = index, [] s3, i3 = [], index loop do r4 = _nt_FWS if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s2 << r3 if r3 r5 = _nt_comment s2 << r5 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(CFWS0) else @index = i2 r2 = nil end if r2 s1 << r2 else break end end r1 = instantiate_node(SyntaxNode,input, i1...index, s1) s0 << r1 if r1 r7 = _nt_FWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(CFWS1) else @index = i0 r0 = nil end node_cache[:CFWS][start_index] = r0 r0 end def _nt_NO_WS_CTL start_index = index if node_cache[:NO_WS_CTL].has_key?(index) cached = node_cache[:NO_WS_CTL][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?('\G[\\x01-\\x08]', true, index) r1 = true @index += 1 else r1 = nil end if r1 r0 = r1 else if has_terminal?('\G[\\x0B-\\x0C]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x0E-\\x1F]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else if has_terminal?('\G[\\x7f]', true, index) r4 = true @index += 1 else r4 = nil end if r4 r0 = r4 else @index = i0 r0 = nil end end end end node_cache[:NO_WS_CTL][start_index] = r0 r0 end def _nt_specials start_index = index if node_cache[:specials].has_key?(index) cached = node_cache[:specials][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("(", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("(") r1 = nil end if r1 r0 = r1 else if has_terminal?(")", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(")") r2 = nil end if r2 r0 = r2 else if has_terminal?("<", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r3 = nil end if r3 r0 = r3 else if has_terminal?(">", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r4 = nil end if r4 r0 = r4 else if has_terminal?("[", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("[") r5 = nil end if r5 r0 = r5 else if has_terminal?("]", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("]") r6 = nil end if r6 r0 = r6 else if has_terminal?(":", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r7 = nil end if r7 r0 = r7 else if has_terminal?(";", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r8 = nil end if r8 r0 = r8 else if has_terminal?("@", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r9 = nil end if r9 r0 = r9 else if has_terminal?('\\', false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure('\\') r10 = nil end if r10 r0 = r10 else if has_terminal?(",", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r11 = nil end if r11 r0 = r11 else if has_terminal?(".", false, index) r12 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r12 = nil end if r12 r0 = r12 else r13 = _nt_DQUOTE if r13 r0 = r13 else @index = i0 r0 = nil end end end end end end end end end end end end end node_cache[:specials][start_index] = r0 r0 end def _nt_ctext start_index = index if node_cache[:ctext].has_key?(index) cached = node_cache[:ctext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_NO_WS_CTL if r1 r0 = r1 else if has_terminal?('\G[\\x21-\\x27]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x2a-\\x5b]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else if has_terminal?('\G[\\x5d-\\x7e]', true, index) r4 = true @index += 1 else r4 = nil end if r4 r0 = r4 else @index = i0 r0 = nil end end end end node_cache[:ctext][start_index] = r0 r0 end def _nt_ccontent start_index = index if node_cache[:ccontent].has_key?(index) cached = node_cache[:ccontent][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_ctext if r1 r0 = r1 else r2 = _nt_quoted_pair if r2 r0 = r2 else r3 = _nt_comment if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:ccontent][start_index] = r0 r0 end module Comment0 def ccontent elements[1] end end module Comment1 end def _nt_comment start_index = index if node_cache[:comment].has_key?(index) cached = node_cache[:comment][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("(", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("(") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] r5 = _nt_FWS if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 r6 = _nt_ccontent s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(Comment0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 r8 = _nt_FWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s0 << r7 if r7 if has_terminal?(")", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(")") r9 = nil end s0 << r9 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Comment1) else @index = i0 r0 = nil end node_cache[:comment][start_index] = r0 r0 end def _nt_atext start_index = index if node_cache[:atext].has_key?(index) cached = node_cache[:atext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_ALPHA if r1 r0 = r1 else r2 = _nt_DIGIT if r2 r0 = r2 else if has_terminal?("!", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("!") r3 = nil end if r3 r0 = r3 else if has_terminal?("#", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("#") r4 = nil end if r4 r0 = r4 else if has_terminal?("$", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("$") r5 = nil end if r5 r0 = r5 else if has_terminal?("%", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("%") r6 = nil end if r6 r0 = r6 else if has_terminal?("&", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("&") r7 = nil end if r7 r0 = r7 else if has_terminal?("'", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("'") r8 = nil end if r8 r0 = r8 else if has_terminal?("*", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("*") r9 = nil end if r9 r0 = r9 else if has_terminal?("+", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("+") r10 = nil end if r10 r0 = r10 else if has_terminal?("-", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("-") r11 = nil end if r11 r0 = r11 else if has_terminal?("/", false, index) r12 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("/") r12 = nil end if r12 r0 = r12 else if has_terminal?("=", false, index) r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("=") r13 = nil end if r13 r0 = r13 else if has_terminal?("?", false, index) r14 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("?") r14 = nil end if r14 r0 = r14 else if has_terminal?("^", false, index) r15 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("^") r15 = nil end if r15 r0 = r15 else if has_terminal?("_", false, index) r16 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("_") r16 = nil end if r16 r0 = r16 else if has_terminal?("`", false, index) r17 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("`") r17 = nil end if r17 r0 = r17 else if has_terminal?("{", false, index) r18 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("{") r18 = nil end if r18 r0 = r18 else if has_terminal?("|", false, index) r19 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("|") r19 = nil end if r19 r0 = r19 else if has_terminal?("}", false, index) r20 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("}") r20 = nil end if r20 r0 = r20 else if has_terminal?("~", false, index) r21 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("~") r21 = nil end if r21 r0 = r21 else @index = i0 r0 = nil end end end end end end end end end end end end end end end end end end end end end node_cache[:atext][start_index] = r0 r0 end def _nt_mtext start_index = index if node_cache[:mtext].has_key?(index) cached = node_cache[:mtext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1 = index r2 = _nt_atext if r2 r1 = r2 else if has_terminal?(".", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r3 = nil end if r3 r1 = r3 else @index = i1 r1 = nil end end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:mtext][start_index] = r0 r0 end module Atom0 end def _nt_atom start_index = index if node_cache[:atom].has_key?(index) cached = node_cache[:atom][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 s3, i3 = [], index loop do r4 = _nt_atext if r4 s3 << r4 else break end end if s3.empty? @index = i3 r3 = nil else r3 = instantiate_node(SyntaxNode,input, i3...index, s3) end s0 << r3 if r3 r6 = _nt_CFWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s0 << r5 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Atom0) else @index = i0 r0 = nil end node_cache[:atom][start_index] = r0 r0 end module DotAtom0 def dot_atom_text elements[1] end end def _nt_dot_atom start_index = index if node_cache[:dot_atom].has_key?(index) cached = node_cache[:dot_atom][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_dot_atom_text s0 << r3 if r3 r5 = _nt_CFWS if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(DotAtom0) else @index = i0 r0 = nil end node_cache[:dot_atom][start_index] = r0 r0 end module LocalDotAtom0 def local_dot_atom_text elements[1] end end def _nt_local_dot_atom start_index = index if node_cache[:local_dot_atom].has_key?(index) cached = node_cache[:local_dot_atom][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_local_dot_atom_text s0 << r3 if r3 r5 = _nt_CFWS if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(LocalDotAtom0) else @index = i0 r0 = nil end node_cache[:local_dot_atom][start_index] = r0 r0 end def _nt_message_id_text start_index = index if node_cache[:message_id_text].has_key?(index) cached = node_cache[:message_id_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do r1 = _nt_mtext if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:message_id_text][start_index] = r0 r0 end module DotAtomText0 def domain_text elements[0] end end def _nt_dot_atom_text start_index = index if node_cache[:dot_atom_text].has_key?(index) cached = node_cache[:dot_atom_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1, s1 = index, [] r2 = _nt_domain_text s1 << r2 if r2 if has_terminal?(".", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r4 = nil end if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(DotAtomText0) else @index = i1 r1 = nil end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:dot_atom_text][start_index] = r0 r0 end module LocalDotAtomText0 def domain_text elements[1] end end def _nt_local_dot_atom_text start_index = index if node_cache[:local_dot_atom_text].has_key?(index) cached = node_cache[:local_dot_atom_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1, s1 = index, [] s2, i2 = [], index loop do if has_terminal?(".", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s1 << r2 if r2 r4 = _nt_domain_text s1 << r4 if r4 s5, i5 = [], index loop do if has_terminal?(".", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r6 = nil end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s1 << r5 end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(LocalDotAtomText0) else @index = i1 r1 = nil end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:local_dot_atom_text][start_index] = r0 r0 end module DomainText0 def quoted_domain elements[1] end end module DomainText1 def DQUOTE1 elements[0] end def DQUOTE2 elements[3] end end def _nt_domain_text start_index = index if node_cache[:domain_text].has_key?(index) cached = node_cache[:domain_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DQUOTE s1 << r2 if r2 s3, i3 = [], index loop do i4, s4 = index, [] r6 = _nt_FWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s4 << r5 if r5 r7 = _nt_quoted_domain s4 << r7 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(DomainText0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end if s3.empty? @index = i3 r3 = nil else r3 = instantiate_node(SyntaxNode,input, i3...index, s3) end s1 << r3 if r3 r9 = _nt_FWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s1 << r8 if r8 r10 = _nt_DQUOTE s1 << r10 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(DomainText1) else @index = i1 r1 = nil end if r1 r0 = r1 else s11, i11 = [], index loop do r12 = _nt_atext if r12 s11 << r12 else break end end if s11.empty? @index = i11 r11 = nil else r11 = instantiate_node(SyntaxNode,input, i11...index, s11) end if r11 r0 = r11 else @index = i0 r0 = nil end end node_cache[:domain_text][start_index] = r0 r0 end module QuotedDomain0 def text elements[1] end end def _nt_quoted_domain start_index = index if node_cache[:quoted_domain].has_key?(index) cached = node_cache[:quoted_domain][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_qdcontent if r1 r0 = r1 else i2, s2 = index, [] if has_terminal?("\\", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("\\") r3 = nil end s2 << r3 if r3 r4 = _nt_text s2 << r4 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(QuotedDomain0) else @index = i2 r2 = nil end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:quoted_domain][start_index] = r0 r0 end def _nt_qdcontent start_index = index if node_cache[:qdcontent].has_key?(index) cached = node_cache[:qdcontent][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_NO_WS_CTL if r1 r0 = r1 else if has_terminal?('\G[\\x21]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x23-\\x45]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else if has_terminal?('\G[\\x47-\\x5b]', true, index) r4 = true @index += 1 else r4 = nil end if r4 r0 = r4 else if has_terminal?('\G[\\x5d-\\x7e]', true, index) r5 = true @index += 1 else r5 = nil end if r5 r0 = r5 else @index = i0 r0 = nil end end end end end node_cache[:qdcontent][start_index] = r0 r0 end def _nt_phrase start_index = index if node_cache[:phrase].has_key?(index) cached = node_cache[:phrase][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_obs_phrase if r1 r0 = r1 else s2, i2 = [], index loop do r3 = _nt_word if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:phrase][start_index] = r0 r0 end def _nt_word start_index = index if node_cache[:word].has_key?(index) cached = node_cache[:word][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_atom if r1 r0 = r1 else r2 = _nt_quoted_string if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:word][start_index] = r0 r0 end module PhraseList0 def phrase_value elements[2] end end module PhraseList1 def first_phrase elements[0] end def other_phrases elements[1] end end def _nt_phrase_list start_index = index if node_cache[:phrase_list].has_key?(index) cached = node_cache[:phrase_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_phrase s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] if has_terminal?(",", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r4 = nil end s3 << r4 if r4 s5, i5 = [], index loop do r6 = _nt_FWS if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s3 << r5 if r5 r7 = _nt_phrase s3 << r7 end end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(PhraseList0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(PhraseList1) else @index = i0 r0 = nil end node_cache[:phrase_list][start_index] = r0 r0 end module DomainLiteral0 def dcontent elements[1] end end module DomainLiteral1 end def _nt_domain_literal start_index = index if node_cache[:domain_literal].has_key?(index) cached = node_cache[:domain_literal][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 if has_terminal?("[", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("[") r3 = nil end s0 << r3 if r3 s4, i4 = [], index loop do i5, s5 = index, [] r7 = _nt_FWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 r8 = _nt_dcontent s5 << r8 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(DomainLiteral0) else @index = i5 r5 = nil end if r5 s4 << r5 else break end end r4 = instantiate_node(SyntaxNode,input, i4...index, s4) s0 << r4 if r4 r10 = _nt_FWS if r10 r9 = r10 else r9 = instantiate_node(SyntaxNode,input, index...index) end s0 << r9 if r9 if has_terminal?("]", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("]") r11 = nil end s0 << r11 if r11 r13 = _nt_CFWS if r13 r12 = r13 else r12 = instantiate_node(SyntaxNode,input, index...index) end s0 << r12 end end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(DomainLiteral1) else @index = i0 r0 = nil end node_cache[:domain_literal][start_index] = r0 r0 end def _nt_dcontent start_index = index if node_cache[:dcontent].has_key?(index) cached = node_cache[:dcontent][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_dtext if r1 r0 = r1 else r2 = _nt_quoted_pair if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:dcontent][start_index] = r0 r0 end def _nt_dtext start_index = index if node_cache[:dtext].has_key?(index) cached = node_cache[:dtext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_NO_WS_CTL if r1 r0 = r1 else if has_terminal?('\G[\\x21-\\x5a]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x5e-\\x7e]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:dtext][start_index] = r0 r0 end module AngleAddr0 def addr_spec elements[2] end end def _nt_angle_addr start_index = index if node_cache[:angle_addr].has_key?(index) cached = node_cache[:angle_addr][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r3 = _nt_CFWS if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s1 << r2 if r2 if has_terminal?("<", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r4 = nil end s1 << r4 if r4 r5 = _nt_addr_spec s1 << r5 if r5 if has_terminal?(">", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r6 = nil end s1 << r6 if r6 r8 = _nt_CFWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s1 << r7 end end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(AngleAddr0) else @index = i1 r1 = nil end if r1 r0 = r1 else r9 = _nt_obs_angle_addr if r9 r0 = r9 else @index = i0 r0 = nil end end node_cache[:angle_addr][start_index] = r0 r0 end module AddrSpec0 def local_part elements[0] end def domain elements[2] end end def _nt_addr_spec start_index = index if node_cache[:addr_spec].has_key?(index) cached = node_cache[:addr_spec][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_local_part s1 << r2 if r2 if has_terminal?("@", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r3 = nil end s1 << r3 if r3 r4 = _nt_domain s1 << r4 end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(AddrSpec0) else @index = i1 r1 = nil end if r1 r0 = r1 else r5 = _nt_local_part if r5 r0 = r5 else @index = i0 r0 = nil end end node_cache[:addr_spec][start_index] = r0 r0 end def _nt_local_part start_index = index if node_cache[:local_part].has_key?(index) cached = node_cache[:local_part][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_local_dot_atom if r1 r0 = r1 else r2 = _nt_quoted_string if r2 r0 = r2 else r3 = _nt_obs_local_part if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:local_part][start_index] = r0 r0 end def _nt_domain start_index = index if node_cache[:domain].has_key?(index) cached = node_cache[:domain][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_dot_atom if r1 r0 = r1 else r2 = _nt_domain_literal if r2 r0 = r2 else r3 = _nt_obs_domain if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:domain][start_index] = r0 r0 end module Group0 def group_name elements[0] end def group_list elements[2] end end def _nt_group start_index = index if node_cache[:group].has_key?(index) cached = node_cache[:group][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_display_name s0 << r1 if r1 if has_terminal?(":", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r2 = nil end s0 << r2 if r2 i4 = index r5 = _nt_mailbox_list_group if r5 r4 = r5 else r6 = _nt_CFWS if r6 r4 = r6 else @index = i4 r4 = nil end end if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s0 << r3 if r3 if has_terminal?(";", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r7 = nil end s0 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s0 << r8 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Group0) else @index = i0 r0 = nil end node_cache[:group][start_index] = r0 r0 end module MailboxListGroup0 def addresses [first_addr] + other_addr.elements.map { |o| o.addr_value } end end def _nt_mailbox_list_group start_index = index if node_cache[:mailbox_list_group].has_key?(index) cached = node_cache[:mailbox_list_group][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_mailbox_list r0.extend(MailboxListGroup0) node_cache[:mailbox_list_group][start_index] = r0 r0 end module QuotedString0 def qcontent elements[1] end end module QuotedString1 def DQUOTE1 elements[1] end def quoted_content elements[2] end def DQUOTE2 elements[4] end end def _nt_quoted_string start_index = index if node_cache[:quoted_string].has_key?(index) cached = node_cache[:quoted_string][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_DQUOTE s0 << r3 if r3 s4, i4 = [], index loop do i5, s5 = index, [] r7 = _nt_FWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s5 << r6 if r6 r8 = _nt_qcontent s5 << r8 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(QuotedString0) else @index = i5 r5 = nil end if r5 s4 << r5 else break end end r4 = instantiate_node(SyntaxNode,input, i4...index, s4) s0 << r4 if r4 r10 = _nt_FWS if r10 r9 = r10 else r9 = instantiate_node(SyntaxNode,input, index...index) end s0 << r9 if r9 r11 = _nt_DQUOTE s0 << r11 if r11 r13 = _nt_CFWS if r13 r12 = r13 else r12 = instantiate_node(SyntaxNode,input, index...index) end s0 << r12 end end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(QuotedString1) else @index = i0 r0 = nil end node_cache[:quoted_string][start_index] = r0 r0 end def _nt_qcontent start_index = index if node_cache[:qcontent].has_key?(index) cached = node_cache[:qcontent][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_qtext if r1 r0 = r1 else r2 = _nt_quoted_pair if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:qcontent][start_index] = r0 r0 end module QuotedPair0 def text elements[1] end end def _nt_quoted_pair start_index = index if node_cache[:quoted_pair].has_key?(index) cached = node_cache[:quoted_pair][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] if has_terminal?("\\", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("\\") r2 = nil end s1 << r2 if r2 r3 = _nt_text s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(QuotedPair0) else @index = i1 r1 = nil end if r1 r0 = r1 else r4 = _nt_obs_qp if r4 r0 = r4 else @index = i0 r0 = nil end end node_cache[:quoted_pair][start_index] = r0 r0 end def _nt_qtext start_index = index if node_cache[:qtext].has_key?(index) cached = node_cache[:qtext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_NO_WS_CTL if r1 r0 = r1 else if has_terminal?('\G[\\x21]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x23-\\x5b]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else if has_terminal?('\G[\\x5d-\\x7e]', true, index) r4 = true @index += 1 else r4 = nil end if r4 r0 = r4 else @index = i0 r0 = nil end end end end node_cache[:qtext][start_index] = r0 r0 end def _nt_text start_index = index if node_cache[:text].has_key?(index) cached = node_cache[:text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?('\G[\\x01-\\x09]', true, index) r1 = true @index += 1 else r1 = nil end if r1 r0 = r1 else if has_terminal?('\G[\\x0b-\\x0c]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x0e-\\x7e]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else r4 = _nt_obs_text if r4 r0 = r4 else @index = i0 r0 = nil end end end end node_cache[:text][start_index] = r0 r0 end def _nt_display_name start_index = index if node_cache[:display_name].has_key?(index) cached = node_cache[:display_name][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_phrase node_cache[:display_name][start_index] = r0 r0 end module NameAddr0 def display_name elements[0] end def angle_addr elements[1] end end def _nt_name_addr start_index = index if node_cache[:name_addr].has_key?(index) cached = node_cache[:name_addr][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_display_name s1 << r2 if r2 r3 = _nt_angle_addr s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(NameAddr0) else @index = i1 r1 = nil end if r1 r0 = r1 else r4 = _nt_angle_addr if r4 r0 = r4 else @index = i0 r0 = nil end end node_cache[:name_addr][start_index] = r0 r0 end module MailboxList0 def addr_value elements[1] end end module MailboxList1 def first_addr elements[0] end def other_addr elements[1] end end def _nt_mailbox_list start_index = index if node_cache[:mailbox_list].has_key?(index) cached = node_cache[:mailbox_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_mailbox s1 << r2 if r2 s3, i3 = [], index loop do i4, s4 = index, [] i5 = index if has_terminal?(",", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r6 = nil end if r6 r5 = r6 else if has_terminal?(";", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r7 = nil end if r7 r5 = r7 else @index = i5 r5 = nil end end s4 << r5 if r5 r8 = _nt_mailbox s4 << r8 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(MailboxList0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(MailboxList1) else @index = i1 r1 = nil end if r1 r0 = r1 else r9 = _nt_obs_mbox_list if r9 r0 = r9 else @index = i0 r0 = nil end end node_cache[:mailbox_list][start_index] = r0 r0 end module Mailbox0 def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end end def _nt_mailbox start_index = index if node_cache[:mailbox].has_key?(index) cached = node_cache[:mailbox][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_name_addr if r1 r0 = r1 r0.extend(Mailbox0) else r2 = _nt_addr_spec if r2 r0 = r2 r0.extend(Mailbox0) else @index = i0 r0 = nil end end node_cache[:mailbox][start_index] = r0 r0 end module Address0 def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end end def _nt_address start_index = index if node_cache[:address].has_key?(index) cached = node_cache[:address][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_group r1.extend(Address0) if r1 r0 = r1 else r2 = _nt_mailbox if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:address][start_index] = r0 r0 end module AddressList0 def addr_value elements[3] end end module AddressList1 def first_addr elements[0] end def other_addr elements[1] end end def _nt_address_list start_index = index if node_cache[:address_list].has_key?(index) cached = node_cache[:address_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_address if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 s3, i3 = [], index loop do i4, s4 = index, [] s5, i5 = [], index loop do r6 = _nt_FWS if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s4 << r5 if r5 i7 = index if has_terminal?(",", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r8 = nil end if r8 r7 = r8 else if has_terminal?(";", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r9 = nil end if r9 r7 = r9 else @index = i7 r7 = nil end end s4 << r7 if r7 s10, i10 = [], index loop do r11 = _nt_FWS if r11 s10 << r11 else break end end r10 = instantiate_node(SyntaxNode,input, i10...index, s10) s4 << r10 if r10 r13 = _nt_address if r13 r12 = r13 else r12 = instantiate_node(SyntaxNode,input, index...index) end s4 << r12 end end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(AddressList0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s0 << r3 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(AddressList1) else @index = i0 r0 = nil end node_cache[:address_list][start_index] = r0 r0 end module DateTime0 def day_of_week elements[0] end end module DateTime1 def date elements[1] end def FWS elements[2] end def time elements[3] end end def _nt_date_time start_index = index if node_cache[:date_time].has_key?(index) cached = node_cache[:date_time][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] i2, s2 = index, [] r3 = _nt_day_of_week s2 << r3 if r3 if has_terminal?(",", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r4 = nil end s2 << r4 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(DateTime0) else @index = i2 r2 = nil end if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r5 = _nt_date s0 << r5 if r5 r6 = _nt_FWS s0 << r6 if r6 r7 = _nt_time s0 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s0 << r8 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(DateTime1) else @index = i0 r0 = nil end node_cache[:date_time][start_index] = r0 r0 end module DayOfWeek0 def day_name elements[1] end end def _nt_day_of_week start_index = index if node_cache[:day_of_week].has_key?(index) cached = node_cache[:day_of_week][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r3 = _nt_FWS if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s1 << r2 if r2 r4 = _nt_day_name s1 << r4 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(DayOfWeek0) else @index = i1 r1 = nil end if r1 r0 = r1 else r5 = _nt_obs_day_of_week if r5 r0 = r5 else @index = i0 r0 = nil end end node_cache[:day_of_week][start_index] = r0 r0 end def _nt_day_name start_index = index if node_cache[:day_name].has_key?(index) cached = node_cache[:day_name][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("Mon", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Mon") r1 = nil end if r1 r0 = r1 else if has_terminal?("Tue", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Tue") r2 = nil end if r2 r0 = r2 else if has_terminal?("Wed", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Wed") r3 = nil end if r3 r0 = r3 else if has_terminal?("Thu", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Thu") r4 = nil end if r4 r0 = r4 else if has_terminal?("Fri", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Fri") r5 = nil end if r5 r0 = r5 else if has_terminal?("Sat", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Sat") r6 = nil end if r6 r0 = r6 else if has_terminal?("Sun", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Sun") r7 = nil end if r7 r0 = r7 else @index = i0 r0 = nil end end end end end end end node_cache[:day_name][start_index] = r0 r0 end module Date0 def day elements[0] end def month elements[1] end def year elements[2] end end def _nt_date start_index = index if node_cache[:date].has_key?(index) cached = node_cache[:date][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_day s0 << r1 if r1 r2 = _nt_month s0 << r2 if r2 r3 = _nt_year s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Date0) else @index = i0 r0 = nil end node_cache[:date][start_index] = r0 r0 end module Year0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end def DIGIT3 elements[2] end def DIGIT4 elements[3] end end def _nt_year start_index = index if node_cache[:year].has_key?(index) cached = node_cache[:year][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DIGIT s1 << r2 if r2 r3 = _nt_DIGIT s1 << r3 if r3 r4 = _nt_DIGIT s1 << r4 if r4 r5 = _nt_DIGIT s1 << r5 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Year0) else @index = i1 r1 = nil end if r1 r0 = r1 else r6 = _nt_obs_year if r6 r0 = r6 else @index = i0 r0 = nil end end node_cache[:year][start_index] = r0 r0 end module Month0 def FWS1 elements[0] end def month_name elements[1] end def FWS2 elements[2] end end def _nt_month start_index = index if node_cache[:month].has_key?(index) cached = node_cache[:month][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_FWS s1 << r2 if r2 r3 = _nt_month_name s1 << r3 if r3 r4 = _nt_FWS s1 << r4 end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Month0) else @index = i1 r1 = nil end if r1 r0 = r1 else r5 = _nt_obs_month if r5 r0 = r5 else @index = i0 r0 = nil end end node_cache[:month][start_index] = r0 r0 end def _nt_month_name start_index = index if node_cache[:month_name].has_key?(index) cached = node_cache[:month_name][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("Jan", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Jan") r1 = nil end if r1 r0 = r1 else if has_terminal?("Feb", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Feb") r2 = nil end if r2 r0 = r2 else if has_terminal?("Mar", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Mar") r3 = nil end if r3 r0 = r3 else if has_terminal?("Apr", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Apr") r4 = nil end if r4 r0 = r4 else if has_terminal?("May", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("May") r5 = nil end if r5 r0 = r5 else if has_terminal?("Jun", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Jun") r6 = nil end if r6 r0 = r6 else if has_terminal?("Jul", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Jul") r7 = nil end if r7 r0 = r7 else if has_terminal?("Aug", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Aug") r8 = nil end if r8 r0 = r8 else if has_terminal?("Sep", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Sep") r9 = nil end if r9 r0 = r9 else if has_terminal?("Oct", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Oct") r10 = nil end if r10 r0 = r10 else if has_terminal?("Nov", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Nov") r11 = nil end if r11 r0 = r11 else if has_terminal?("Dec", false, index) r12 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Dec") r12 = nil end if r12 r0 = r12 else @index = i0 r0 = nil end end end end end end end end end end end end node_cache[:month_name][start_index] = r0 r0 end module Day0 def DIGIT elements[1] end end def _nt_day start_index = index if node_cache[:day].has_key?(index) cached = node_cache[:day][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r3 = _nt_FWS if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s1 << r2 if r2 r4 = _nt_DIGIT s1 << r4 if r4 r6 = _nt_DIGIT if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s1 << r5 end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Day0) else @index = i1 r1 = nil end if r1 r0 = r1 else r7 = _nt_obs_day if r7 r0 = r7 else @index = i0 r0 = nil end end node_cache[:day][start_index] = r0 r0 end module Time0 def time_of_day elements[0] end def FWS elements[1] end def zone elements[2] end end def _nt_time start_index = index if node_cache[:time].has_key?(index) cached = node_cache[:time][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_time_of_day s0 << r1 if r1 r2 = _nt_FWS s0 << r2 if r2 r3 = _nt_zone s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Time0) else @index = i0 r0 = nil end node_cache[:time][start_index] = r0 r0 end module TimeOfDay0 def second elements[1] end end module TimeOfDay1 def hour elements[0] end def minute elements[2] end end def _nt_time_of_day start_index = index if node_cache[:time_of_day].has_key?(index) cached = node_cache[:time_of_day][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_hour s0 << r1 if r1 if has_terminal?(":", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r2 = nil end s0 << r2 if r2 r3 = _nt_minute s0 << r3 if r3 i5, s5 = index, [] if has_terminal?(":", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r6 = nil end s5 << r6 if r6 r7 = _nt_second s5 << r7 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(TimeOfDay0) else @index = i5 r5 = nil end if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(TimeOfDay1) else @index = i0 r0 = nil end node_cache[:time_of_day][start_index] = r0 r0 end module Hour0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end def _nt_hour start_index = index if node_cache[:hour].has_key?(index) cached = node_cache[:hour][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DIGIT s1 << r2 if r2 r3 = _nt_DIGIT s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Hour0) else @index = i1 r1 = nil end if r1 r0 = r1 else r4 = _nt_obs_hour if r4 r0 = r4 else @index = i0 r0 = nil end end node_cache[:hour][start_index] = r0 r0 end module Minute0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end def _nt_minute start_index = index if node_cache[:minute].has_key?(index) cached = node_cache[:minute][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DIGIT s1 << r2 if r2 r3 = _nt_DIGIT s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Minute0) else @index = i1 r1 = nil end if r1 r0 = r1 else r4 = _nt_obs_minute if r4 r0 = r4 else @index = i0 r0 = nil end end node_cache[:minute][start_index] = r0 r0 end module Second0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end def _nt_second start_index = index if node_cache[:second].has_key?(index) cached = node_cache[:second][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DIGIT s1 << r2 if r2 r3 = _nt_DIGIT s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Second0) else @index = i1 r1 = nil end if r1 r0 = r1 else r4 = _nt_obs_second if r4 r0 = r4 else @index = i0 r0 = nil end end node_cache[:second][start_index] = r0 r0 end module Zone0 def DIGIT1 elements[1] end def DIGIT2 elements[2] end def DIGIT3 elements[3] end def DIGIT4 elements[4] end end def _nt_zone start_index = index if node_cache[:zone].has_key?(index) cached = node_cache[:zone][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] i2 = index if has_terminal?("+", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("+") r3 = nil end if r3 r2 = r3 else if has_terminal?("-", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("-") r4 = nil end if r4 r2 = r4 else @index = i2 r2 = nil end end s1 << r2 if r2 r5 = _nt_DIGIT s1 << r5 if r5 r6 = _nt_DIGIT s1 << r6 if r6 r7 = _nt_DIGIT s1 << r7 if r7 r8 = _nt_DIGIT s1 << r8 end end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Zone0) else @index = i1 r1 = nil end if r1 r0 = r1 else r9 = _nt_obs_zone if r9 r0 = r9 else @index = i0 r0 = nil end end node_cache[:zone][start_index] = r0 r0 end module Return0 def path elements[0] end def CRLF elements[1] end end def _nt_return start_index = index if node_cache[:return].has_key?(index) cached = node_cache[:return][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_path s0 << r1 if r1 r2 = _nt_CRLF s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Return0) else @index = i0 r0 = nil end node_cache[:return][start_index] = r0 r0 end module Path0 end def _nt_path start_index = index if node_cache[:path].has_key?(index) cached = node_cache[:path][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r3 = _nt_CFWS if r3 r2 = r3 else r2 = instantiate_node(SyntaxNode,input, index...index) end s1 << r2 if r2 if has_terminal?("<", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r4 = nil end s1 << r4 if r4 i5 = index r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end if r6 r5 = r6 else r8 = _nt_addr_spec if r8 r5 = r8 else @index = i5 r5 = nil end end s1 << r5 if r5 if has_terminal?(">", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r9 = nil end s1 << r9 if r9 r11 = _nt_CFWS if r11 r10 = r11 else r10 = instantiate_node(SyntaxNode,input, index...index) end s1 << r10 end end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(Path0) else @index = i1 r1 = nil end if r1 r0 = r1 else r12 = _nt_obs_path if r12 r0 = r12 else @index = i0 r0 = nil end end node_cache[:path][start_index] = r0 r0 end module Received0 def name_val_list elements[0] end def date_time elements[2] end def CRLF elements[3] end end def _nt_received start_index = index if node_cache[:received].has_key?(index) cached = node_cache[:received][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_name_val_list s0 << r1 if r1 if has_terminal?(";", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(";") r2 = nil end s0 << r2 if r2 r3 = _nt_date_time s0 << r3 if r3 r4 = _nt_CRLF s0 << r4 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(Received0) else @index = i0 r0 = nil end node_cache[:received][start_index] = r0 r0 end module NameValList0 def CFWS elements[0] end def name_val_pair elements[1] end end module NameValList1 def name_val_pair elements[0] end end module NameValList2 end def _nt_name_val_list start_index = index if node_cache[:name_val_list].has_key?(index) cached = node_cache[:name_val_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i4, s4 = index, [] r5 = _nt_name_val_pair s4 << r5 if r5 s6, i6 = [], index loop do i7, s7 = index, [] r8 = _nt_CFWS s7 << r8 if r8 r9 = _nt_name_val_pair s7 << r9 end if s7.last r7 = instantiate_node(SyntaxNode,input, i7...index, s7) r7.extend(NameValList0) else @index = i7 r7 = nil end if r7 s6 << r7 else break end end r6 = instantiate_node(SyntaxNode,input, i6...index, s6) s4 << r6 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(NameValList1) else @index = i4 r4 = nil end if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s0 << r3 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NameValList2) else @index = i0 r0 = nil end node_cache[:name_val_list][start_index] = r0 r0 end module NameValPair0 def item_name elements[0] end def CFWS elements[1] end def item_value elements[2] end end def _nt_name_val_pair start_index = index if node_cache[:name_val_pair].has_key?(index) cached = node_cache[:name_val_pair][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_item_name s0 << r1 if r1 r2 = _nt_CFWS s0 << r2 if r2 r3 = _nt_item_value s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NameValPair0) else @index = i0 r0 = nil end node_cache[:name_val_pair][start_index] = r0 r0 end module ItemName0 end module ItemName1 def ALPHA elements[0] end end def _nt_item_name start_index = index if node_cache[:item_name].has_key?(index) cached = node_cache[:item_name][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_ALPHA s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] if has_terminal?("-", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("-") r5 = nil end if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s3 << r4 if r4 i6 = index r7 = _nt_ALPHA if r7 r6 = r7 else r8 = _nt_DIGIT if r8 r6 = r8 else @index = i6 r6 = nil end end s3 << r6 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ItemName0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ItemName1) else @index = i0 r0 = nil end node_cache[:item_name][start_index] = r0 r0 end def _nt_item_value start_index = index if node_cache[:item_value].has_key?(index) cached = node_cache[:item_value][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index s1, i1 = [], index loop do r2 = _nt_angle_addr if r2 s1 << r2 else break end end if s1.empty? @index = i1 r1 = nil else r1 = instantiate_node(SyntaxNode,input, i1...index, s1) end if r1 r0 = r1 else r3 = _nt_addr_spec if r3 r0 = r3 else r4 = _nt_atom if r4 r0 = r4 else r5 = _nt_domain if r5 r0 = r5 else r6 = _nt_msg_id if r6 r0 = r6 else @index = i0 r0 = nil end end end end end node_cache[:item_value][start_index] = r0 r0 end module MessageIds0 def CFWS elements[0] end def msg_id_value elements[1] end end module MessageIds1 def first_msg_id elements[0] end def other_msg_ids elements[1] end end def _nt_message_ids start_index = index if node_cache[:message_ids].has_key?(index) cached = node_cache[:message_ids][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_msg_id s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] r4 = _nt_CFWS s3 << r4 if r4 r5 = _nt_msg_id s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(MessageIds0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(MessageIds1) else @index = i0 r0 = nil end node_cache[:message_ids][start_index] = r0 r0 end module MsgId0 def msg_id_value elements[2] end end def _nt_msg_id start_index = index if node_cache[:msg_id].has_key?(index) cached = node_cache[:msg_id][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 if has_terminal?("<", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r3 = nil end s0 << r3 if r3 r4 = _nt_msg_id_value s0 << r4 if r4 if has_terminal?(">", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r5 = nil end s0 << r5 if r5 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(MsgId0) else @index = i0 r0 = nil end node_cache[:msg_id][start_index] = r0 r0 end module MsgIdValue0 def id_left elements[0] end def id_right elements[2] end end def _nt_msg_id_value start_index = index if node_cache[:msg_id_value].has_key?(index) cached = node_cache[:msg_id_value][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_id_left s0 << r1 if r1 if has_terminal?("@", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r2 = nil end s0 << r2 if r2 r3 = _nt_id_right s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(MsgIdValue0) else @index = i0 r0 = nil end node_cache[:msg_id_value][start_index] = r0 r0 end def _nt_id_left start_index = index if node_cache[:id_left].has_key?(index) cached = node_cache[:id_left][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_message_id_text if r1 r0 = r1 else r2 = _nt_no_fold_quote if r2 r0 = r2 else r3 = _nt_obs_id_left if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:id_left][start_index] = r0 r0 end def _nt_id_right start_index = index if node_cache[:id_right].has_key?(index) cached = node_cache[:id_right][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_msg_id_dot_atom_text if r1 r0 = r1 else r2 = _nt_no_fold_literal if r2 r0 = r2 else r3 = _nt_obs_id_right if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:id_right][start_index] = r0 r0 end module MsgIdDotAtomText0 def msg_id_domain_text elements[0] end end def _nt_msg_id_dot_atom_text start_index = index if node_cache[:msg_id_dot_atom_text].has_key?(index) cached = node_cache[:msg_id_dot_atom_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1, s1 = index, [] r2 = _nt_msg_id_domain_text s1 << r2 if r2 if has_terminal?(".", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r4 = nil end if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s1 << r3 end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(MsgIdDotAtomText0) else @index = i1 r1 = nil end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:msg_id_dot_atom_text][start_index] = r0 r0 end module MsgIdDomainText0 def quoted_domain elements[1] end end module MsgIdDomainText1 def DQUOTE1 elements[0] end def DQUOTE2 elements[3] end end def _nt_msg_id_domain_text start_index = index if node_cache[:msg_id_domain_text].has_key?(index) cached = node_cache[:msg_id_domain_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index i1, s1 = index, [] r2 = _nt_DQUOTE s1 << r2 if r2 s3, i3 = [], index loop do i4, s4 = index, [] r6 = _nt_FWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s4 << r5 if r5 r7 = _nt_quoted_domain s4 << r7 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(MsgIdDomainText0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end if s3.empty? @index = i3 r3 = nil else r3 = instantiate_node(SyntaxNode,input, i3...index, s3) end s1 << r3 if r3 r9 = _nt_FWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s1 << r8 if r8 r10 = _nt_DQUOTE s1 << r10 end end end if s1.last r1 = instantiate_node(SyntaxNode,input, i1...index, s1) r1.extend(MsgIdDomainText1) else @index = i1 r1 = nil end if r1 r0 = r1 else s11, i11 = [], index loop do r12 = _nt_msg_id_atext if r12 s11 << r12 else break end end if s11.empty? @index = i11 r11 = nil else r11 = instantiate_node(SyntaxNode,input, i11...index, s11) end if r11 r0 = r11 else @index = i0 r0 = nil end end node_cache[:msg_id_domain_text][start_index] = r0 r0 end def _nt_msg_id_atext start_index = index if node_cache[:msg_id_atext].has_key?(index) cached = node_cache[:msg_id_atext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_ALPHA if r1 r0 = r1 else r2 = _nt_DIGIT if r2 r0 = r2 else if has_terminal?("!", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("!") r3 = nil end if r3 r0 = r3 else if has_terminal?("#", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("#") r4 = nil end if r4 r0 = r4 else if has_terminal?("$", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("$") r5 = nil end if r5 r0 = r5 else if has_terminal?("%", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("%") r6 = nil end if r6 r0 = r6 else if has_terminal?("&", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("&") r7 = nil end if r7 r0 = r7 else if has_terminal?("'", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("'") r8 = nil end if r8 r0 = r8 else if has_terminal?("*", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("*") r9 = nil end if r9 r0 = r9 else if has_terminal?("+", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("+") r10 = nil end if r10 r0 = r10 else if has_terminal?("-", false, index) r11 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("-") r11 = nil end if r11 r0 = r11 else if has_terminal?("/", false, index) r12 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("/") r12 = nil end if r12 r0 = r12 else if has_terminal?("=", false, index) r13 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("=") r13 = nil end if r13 r0 = r13 else if has_terminal?("?", false, index) r14 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("?") r14 = nil end if r14 r0 = r14 else if has_terminal?("^", false, index) r15 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("^") r15 = nil end if r15 r0 = r15 else if has_terminal?("_", false, index) r16 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("_") r16 = nil end if r16 r0 = r16 else if has_terminal?("`", false, index) r17 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("`") r17 = nil end if r17 r0 = r17 else if has_terminal?("{", false, index) r18 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("{") r18 = nil end if r18 r0 = r18 else if has_terminal?("|", false, index) r19 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("|") r19 = nil end if r19 r0 = r19 else if has_terminal?("}", false, index) r20 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("}") r20 = nil end if r20 r0 = r20 else if has_terminal?("~", false, index) r21 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("~") r21 = nil end if r21 r0 = r21 else if has_terminal?("@", false, index) r22 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r22 = nil end if r22 r0 = r22 else @index = i0 r0 = nil end end end end end end end end end end end end end end end end end end end end end end node_cache[:msg_id_atext][start_index] = r0 r0 end module NoFoldQuote0 def DQUOTE1 elements[0] end def DQUOTE2 elements[2] end end def _nt_no_fold_quote start_index = index if node_cache[:no_fold_quote].has_key?(index) cached = node_cache[:no_fold_quote][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_DQUOTE s0 << r1 if r1 s2, i2 = [], index loop do i3 = index r4 = _nt_qtext if r4 r3 = r4 else r5 = _nt_quoted_pair if r5 r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 r6 = _nt_DQUOTE s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NoFoldQuote0) else @index = i0 r0 = nil end node_cache[:no_fold_quote][start_index] = r0 r0 end module NoFoldLiteral0 end def _nt_no_fold_literal start_index = index if node_cache[:no_fold_literal].has_key?(index) cached = node_cache[:no_fold_literal][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("[", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("[") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do i3 = index r4 = _nt_dtext if r4 r3 = r4 else r5 = _nt_quoted_pair if r5 r3 = r5 else @index = i3 r3 = nil end end if r3 s2 << r3 else break end end if s2.empty? @index = i2 r2 = nil else r2 = instantiate_node(SyntaxNode,input, i2...index, s2) end s0 << r2 if r2 if has_terminal?("]", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("]") r6 = nil end s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(NoFoldLiteral0) else @index = i0 r0 = nil end node_cache[:no_fold_literal][start_index] = r0 r0 end end class RFC2822Parser < Treetop::Runtime::CompiledParser include RFC2822 end end mail-2.5.4/lib/mail/parsers/rfc2822.treetop000066400000000000000000000175341214434061600203220ustar00rootroot00000000000000module Mail grammar RFC2822 include RFC2822Obsolete rule ALPHA [a-zA-Z] end rule DIGIT [0-9] end rule DQUOTE '"' end rule LF "\n" end rule CR "\r" end rule CRLF "\r\n" end rule WSP [\x09\x20] end rule FWS # Folding white space (WSP* CRLF WSP+) / (CRLF WSP+) / obs_FWS end rule CFWS (FWS* comment)* FWS? end rule NO_WS_CTL [\x01-\x08] / # US-ASCII control characters [\x0B-\x0C] / # that do not include the [\x0E-\x1F] / # carriage return, line feed, [\x7f] # and white space characters end rule specials "(" / ")" / # Special characters used in "<" / ">" / # other parts of the syntax "[" / "]" / ":" / ";" / "@" / '\\' / "," / "." / DQUOTE end rule ctext NO_WS_CTL / # Non white space controls [\x21-\x27] / # The rest of the US-ASCII [\x2a-\x5b] / # characters not including "(", [\x5d-\x7e] # ")", or "\" end rule ccontent ctext / quoted_pair / comment end rule comment "(" ( FWS? ccontent )* FWS? ")" end rule atext ALPHA / DIGIT / # Any character except controls, "!" / "#" / # SP, and specials. "$" / "%" / # Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" end rule mtext (atext / ".")+ end rule atom CFWS? atext+ CFWS? end rule dot_atom CFWS? dot_atom_text CFWS? end rule local_dot_atom CFWS? local_dot_atom_text CFWS? end rule message_id_text mtext+ end rule dot_atom_text (domain_text "."?)+ end rule local_dot_atom_text ("."* domain_text "."*)+ end rule domain_text (DQUOTE (FWS? quoted_domain)+ FWS? DQUOTE) / atext+ end rule quoted_domain qdcontent / "\\" text end rule qdcontent NO_WS_CTL / # Non white space controls [\x21] / # The rest of the US-ASCII [\x23-\x45] / # characters not including "\" [\x47-\x5b] / # or the "." or the [\x5d-\x7e] # double quote character end rule phrase obs_phrase / word+ end rule word atom / quoted_string end rule phrase_list first_phrase:phrase other_phrases:("," FWS* phrase_value:phrase)* end rule domain_literal CFWS? "[" (FWS? dcontent)* FWS? "]" CFWS? end rule dcontent dtext / quoted_pair end rule dtext NO_WS_CTL / # Non white space controls [\x21-\x5a] / # The rest of the US-ASCII characters [\x5e-\x7e] # not including "[", "]", or "\" end rule angle_addr CFWS? "<" addr_spec ">" CFWS? / obs_angle_addr end rule addr_spec (local_part "@" domain) / local_part end rule local_part local_dot_atom / quoted_string / obs_local_part end rule domain dot_atom / domain_literal / obs_domain end rule group group_name:display_name ":" group_list:(mailbox_list_group / CFWS)? ";" CFWS? end rule mailbox_list_group mailbox_list { def addresses [first_addr] + other_addr.elements.map { |o| o.addr_value } end } end rule quoted_string CFWS? DQUOTE quoted_content:(FWS? qcontent)* FWS? DQUOTE CFWS? end rule qcontent qtext / quoted_pair end rule quoted_pair ("\\" text) / obs_qp end rule qtext NO_WS_CTL / # Non white space controls [\x21] / # The rest of the US-ASCII [\x23-\x5b] / # characters not including "\" [\x5d-\x7e] # or the quote character end rule text [\x01-\x09] / # Characters excluding CR and LF [\x0b-\x0c] / [\x0e-\x7e] / obs_text end rule display_name phrase end rule name_addr display_name angle_addr / angle_addr end rule mailbox_list (first_addr:mailbox other_addr:(("," / ";") addr_value:mailbox)*) / obs_mbox_list end rule mailbox (name_addr / addr_spec) { def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end } end rule address group { def dig_comments(comments, elements) elements.each { |elem| if elem.respond_to?(:comment) comments << elem.comment end dig_comments(comments, elem.elements) if elem.elements } end def comments comments = [] dig_comments(comments, elements) comments end } / mailbox end rule address_list first_addr:address? other_addr:(FWS* ("," / ";") FWS* addr_value:address?)* end rule date_time ( day_of_week ",")? date FWS time CFWS? end rule day_of_week (FWS? day_name) / obs_day_of_week end rule day_name "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" end rule date day month year end rule year DIGIT DIGIT DIGIT DIGIT / obs_year end rule month (FWS month_name FWS) / obs_month end rule month_name "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" end rule day (FWS? DIGIT DIGIT?) / obs_day end rule time time_of_day FWS zone end rule time_of_day hour ":" minute ( ":" second )? end rule hour DIGIT DIGIT / obs_hour end rule minute DIGIT DIGIT / obs_minute end rule second DIGIT DIGIT / obs_second end rule zone (( "+" / "-" ) DIGIT DIGIT DIGIT DIGIT) / obs_zone end rule return path CRLF end rule path ((CFWS)? "<" ((CFWS)? / addr_spec) ">" (CFWS)?) / obs_path end rule received name_val_list ";" date_time CRLF end rule name_val_list (CFWS)? (name_val_pair (CFWS name_val_pair)*)? end rule name_val_pair item_name CFWS item_value end rule item_name ALPHA (("-")? (ALPHA / DIGIT))* end rule item_value (angle_addr)+ / addr_spec / atom / domain / msg_id end rule message_ids first_msg_id:msg_id other_msg_ids:( CFWS msg_id_value:msg_id )* end rule msg_id (CFWS)? "<" msg_id_value ">" (CFWS)? end rule msg_id_value id_left "@" id_right end rule id_left message_id_text / no_fold_quote / obs_id_left end rule id_right msg_id_dot_atom_text / no_fold_literal / obs_id_right end rule msg_id_dot_atom_text (msg_id_domain_text "."?)+ end rule msg_id_domain_text (DQUOTE (FWS? quoted_domain)+ FWS? DQUOTE) / msg_id_atext+ end rule msg_id_atext ALPHA / DIGIT / # Any character except controls, "!" / "#" / # SP, and specials. "$" / "%" / # Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" / "@" end rule no_fold_quote DQUOTE (qtext / quoted_pair)+ DQUOTE end rule no_fold_literal "[" (dtext / quoted_pair)+ "]" end end end mail-2.5.4/lib/mail/parsers/rfc2822_obsolete.rb000066400000000000000000002553631214434061600211430ustar00rootroot00000000000000# Autogenerated from a Treetop grammar. Edits may be lost. module Mail module RFC2822Obsolete include Treetop::Runtime def root @root ||= :obs_qp end module ObsQp0 end def _nt_obs_qp start_index = index if node_cache[:obs_qp].has_key?(index) cached = node_cache[:obs_qp][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("\\", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("\\") r1 = nil end s0 << r1 if r1 if has_terminal?('\G[\\x00-\\x7F]', true, index) r2 = true @index += 1 else r2 = nil end s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsQp0) else @index = i0 r0 = nil end node_cache[:obs_qp][start_index] = r0 r0 end module ObsText0 def obs_char elements[0] end end module ObsText1 end def _nt_obs_text start_index = index if node_cache[:obs_text].has_key?(index) cached = node_cache[:obs_text][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do r2 = _nt_LF if r2 s1 << r2 else break end end r1 = instantiate_node(SyntaxNode,input, i1...index, s1) s0 << r1 if r1 s3, i3 = [], index loop do r4 = _nt_CR if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s0 << r3 if r3 s5, i5 = [], index loop do i6, s6 = index, [] r7 = _nt_obs_char s6 << r7 if r7 s8, i8 = [], index loop do r9 = _nt_LF if r9 s8 << r9 else break end end r8 = instantiate_node(SyntaxNode,input, i8...index, s8) s6 << r8 if r8 s10, i10 = [], index loop do r11 = _nt_CR if r11 s10 << r11 else break end end r10 = instantiate_node(SyntaxNode,input, i10...index, s10) s6 << r10 end end if s6.last r6 = instantiate_node(SyntaxNode,input, i6...index, s6) r6.extend(ObsText0) else @index = i6 r6 = nil end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsText1) else @index = i0 r0 = nil end node_cache[:obs_text][start_index] = r0 r0 end def _nt_obs_char start_index = index if node_cache[:obs_char].has_key?(index) cached = node_cache[:obs_char][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?('\G[\\x00-\\x09]', true, index) r1 = true @index += 1 else r1 = nil end if r1 r0 = r1 else if has_terminal?('\G[\\x0B-\\x0C]', true, index) r2 = true @index += 1 else r2 = nil end if r2 r0 = r2 else if has_terminal?('\G[\\x0E-\\x7F]', true, index) r3 = true @index += 1 else r3 = nil end if r3 r0 = r3 else @index = i0 r0 = nil end end end node_cache[:obs_char][start_index] = r0 r0 end def _nt_obs_utext start_index = index if node_cache[:obs_utext].has_key?(index) cached = node_cache[:obs_utext][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_obs_text node_cache[:obs_utext][start_index] = r0 r0 end def _nt_obs_phrase start_index = index if node_cache[:obs_phrase].has_key?(index) cached = node_cache[:obs_phrase][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1 = index r2 = _nt_word if r2 r1 = r2 else if has_terminal?(".", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r3 = nil end if r3 r1 = r3 else if has_terminal?("@", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r4 = nil end if r4 r1 = r4 else @index = i1 r1 = nil end end end if r1 s0 << r1 else break end end if s0.empty? @index = i0 r0 = nil else r0 = instantiate_node(SyntaxNode,input, i0...index, s0) end node_cache[:obs_phrase][start_index] = r0 r0 end module ObsPhraseList0 end module ObsPhraseList1 end def _nt_obs_phrase_list start_index = index if node_cache[:obs_phrase_list].has_key?(index) cached = node_cache[:obs_phrase_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index r1 = _nt_phrase if r1 r0 = r1 else i2, s2 = index, [] s3, i3 = [], index loop do i4, s4 = index, [] r6 = _nt_phrase if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s4 << r5 if r5 r8 = _nt_CFWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s4 << r7 if r7 if has_terminal?(",", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r9 = nil end s4 << r9 if r9 r11 = _nt_CFWS if r11 r10 = r11 else r10 = instantiate_node(SyntaxNode,input, index...index) end s4 << r10 end end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(ObsPhraseList0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end if s3.empty? @index = i3 r3 = nil else r3 = instantiate_node(SyntaxNode,input, i3...index, s3) end s2 << r3 if r3 r13 = _nt_phrase if r13 r12 = r13 else r12 = instantiate_node(SyntaxNode,input, index...index) end s2 << r12 end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(ObsPhraseList1) else @index = i2 r2 = nil end if r2 r0 = r2 else @index = i0 r0 = nil end end node_cache[:obs_phrase_list][start_index] = r0 r0 end module ObsFWS0 def CRLF elements[0] end end module ObsFWS1 end def _nt_obs_FWS start_index = index if node_cache[:obs_FWS].has_key?(index) cached = node_cache[:obs_FWS][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do r2 = _nt_WSP if r2 s1 << r2 else break end end if s1.empty? @index = i1 r1 = nil else r1 = instantiate_node(SyntaxNode,input, i1...index, s1) end s0 << r1 if r1 s3, i3 = [], index loop do i4, s4 = index, [] r5 = _nt_CRLF s4 << r5 if r5 s6, i6 = [], index loop do r7 = _nt_WSP if r7 s6 << r7 else break end end if s6.empty? @index = i6 r6 = nil else r6 = instantiate_node(SyntaxNode,input, i6...index, s6) end s4 << r6 end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(ObsFWS0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s0 << r3 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsFWS1) else @index = i0 r0 = nil end node_cache[:obs_FWS][start_index] = r0 r0 end module ObsDayOfWeek0 def day_name elements[1] end end def _nt_obs_day_of_week start_index = index if node_cache[:obs_day_of_week].has_key?(index) cached = node_cache[:obs_day_of_week][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_day_name s0 << r3 if r3 r5 = _nt_CFWS if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsDayOfWeek0) else @index = i0 r0 = nil end node_cache[:obs_day_of_week][start_index] = r0 r0 end module ObsYear0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end module ObsYear1 end def _nt_obs_year start_index = index if node_cache[:obs_year].has_key?(index) cached = node_cache[:obs_year][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3, s3 = index, [] r4 = _nt_DIGIT s3 << r4 if r4 r5 = _nt_DIGIT s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsYear0) else @index = i3 r3 = nil end s0 << r3 if r3 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsYear1) else @index = i0 r0 = nil end node_cache[:obs_year][start_index] = r0 r0 end module ObsMonth0 def CFWS1 elements[0] end def month_name elements[1] end def CFWS2 elements[2] end end def _nt_obs_month start_index = index if node_cache[:obs_month].has_key?(index) cached = node_cache[:obs_month][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_CFWS s0 << r1 if r1 r2 = _nt_month_name s0 << r2 if r2 r3 = _nt_CFWS s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsMonth0) else @index = i0 r0 = nil end node_cache[:obs_month][start_index] = r0 r0 end module ObsDay0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end module ObsDay1 end def _nt_obs_day start_index = index if node_cache[:obs_day].has_key?(index) cached = node_cache[:obs_day][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3 = index r4 = _nt_DIGIT if r4 r3 = r4 else i5, s5 = index, [] r6 = _nt_DIGIT s5 << r6 if r6 r7 = _nt_DIGIT s5 << r7 end if s5.last r5 = instantiate_node(SyntaxNode,input, i5...index, s5) r5.extend(ObsDay0) else @index = i5 r5 = nil end if r5 r3 = r5 else @index = i3 r3 = nil end end s0 << r3 if r3 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s0 << r8 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsDay1) else @index = i0 r0 = nil end node_cache[:obs_day][start_index] = r0 r0 end module ObsHour0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end module ObsHour1 end def _nt_obs_hour start_index = index if node_cache[:obs_hour].has_key?(index) cached = node_cache[:obs_hour][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3, s3 = index, [] r4 = _nt_DIGIT s3 << r4 if r4 r5 = _nt_DIGIT s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsHour0) else @index = i3 r3 = nil end s0 << r3 if r3 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsHour1) else @index = i0 r0 = nil end node_cache[:obs_hour][start_index] = r0 r0 end module ObsMinute0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end module ObsMinute1 end def _nt_obs_minute start_index = index if node_cache[:obs_minute].has_key?(index) cached = node_cache[:obs_minute][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3, s3 = index, [] r4 = _nt_DIGIT s3 << r4 if r4 r5 = _nt_DIGIT s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsMinute0) else @index = i3 r3 = nil end s0 << r3 if r3 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsMinute1) else @index = i0 r0 = nil end node_cache[:obs_minute][start_index] = r0 r0 end module ObsSecond0 def DIGIT1 elements[0] end def DIGIT2 elements[1] end end module ObsSecond1 end def _nt_obs_second start_index = index if node_cache[:obs_second].has_key?(index) cached = node_cache[:obs_second][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 i3, s3 = index, [] r4 = _nt_DIGIT s3 << r4 if r4 r5 = _nt_DIGIT s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsSecond0) else @index = i3 r3 = nil end s0 << r3 if r3 r7 = _nt_CFWS if r7 r6 = r7 else r6 = instantiate_node(SyntaxNode,input, index...index) end s0 << r6 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsSecond1) else @index = i0 r0 = nil end node_cache[:obs_second][start_index] = r0 r0 end def _nt_obs_zone start_index = index if node_cache[:obs_zone].has_key?(index) cached = node_cache[:obs_zone][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0 = index if has_terminal?("UT", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) @index += 2 else terminal_parse_failure("UT") r1 = nil end if r1 r0 = r1 else if has_terminal?("GMT", false, index) r2 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("GMT") r2 = nil end if r2 r0 = r2 else if has_terminal?("EST", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("EST") r3 = nil end if r3 r0 = r3 else if has_terminal?("EDT", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("EDT") r4 = nil end if r4 r0 = r4 else if has_terminal?("CST", false, index) r5 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("CST") r5 = nil end if r5 r0 = r5 else if has_terminal?("CDT", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("CDT") r6 = nil end if r6 r0 = r6 else if has_terminal?("MST", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("MST") r7 = nil end if r7 r0 = r7 else if has_terminal?("MDT", false, index) r8 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("MDT") r8 = nil end if r8 r0 = r8 else if has_terminal?("PST", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("PST") r9 = nil end if r9 r0 = r9 else if has_terminal?("PDT", false, index) r10 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("PDT") r10 = nil end if r10 r0 = r10 else if has_terminal?('\G[\\x41-\\x49]', true, index) r11 = true @index += 1 else r11 = nil end if r11 r0 = r11 else if has_terminal?('\G[\\x4B-\\x5A]', true, index) r12 = true @index += 1 else r12 = nil end if r12 r0 = r12 else if has_terminal?('\G[\\x61-\\x69]', true, index) r13 = true @index += 1 else r13 = nil end if r13 r0 = r13 else if has_terminal?('\G[\\x6B-\\x7A]', true, index) r14 = true @index += 1 else r14 = nil end if r14 r0 = r14 else @index = i0 r0 = nil end end end end end end end end end end end end end end node_cache[:obs_zone][start_index] = r0 r0 end module ObsAngleAddr0 def addr_spec elements[3] end end def _nt_obs_angle_addr start_index = index if node_cache[:obs_angle_addr].has_key?(index) cached = node_cache[:obs_angle_addr][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 if has_terminal?("<", false, index) r3 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("<") r3 = nil end s0 << r3 if r3 r5 = _nt_obs_route if r5 r4 = r5 else r4 = instantiate_node(SyntaxNode,input, index...index) end s0 << r4 if r4 r6 = _nt_addr_spec s0 << r6 if r6 if has_terminal?(">", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(">") r7 = nil end s0 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s0 << r8 end end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsAngleAddr0) else @index = i0 r0 = nil end node_cache[:obs_angle_addr][start_index] = r0 r0 end module ObsRoute0 def obs_domain_list elements[1] end end def _nt_obs_route start_index = index if node_cache[:obs_route].has_key?(index) cached = node_cache[:obs_route][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r2 = _nt_CFWS if r2 r1 = r2 else r1 = instantiate_node(SyntaxNode,input, index...index) end s0 << r1 if r1 r3 = _nt_obs_domain_list s0 << r3 if r3 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r6 = _nt_CFWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s0 << r5 end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsRoute0) else @index = i0 r0 = nil end node_cache[:obs_route][start_index] = r0 r0 end module ObsDomainList0 def domain elements[3] end end module ObsDomainList1 def domain elements[1] end end def _nt_obs_domain_list start_index = index if node_cache[:obs_domain_list].has_key?(index) cached = node_cache[:obs_domain_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("@", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r1 = nil end s0 << r1 if r1 r2 = _nt_domain s0 << r2 if r2 s3, i3 = [], index loop do i4, s4 = index, [] s5, i5 = [], index loop do if has_terminal?(",", false, index) r6 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r6 = nil end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s4 << r5 if r5 r8 = _nt_CFWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end s4 << r7 if r7 if has_terminal?("@", false, index) r9 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure("@") r9 = nil end s4 << r9 if r9 r10 = _nt_domain s4 << r10 end end end if s4.last r4 = instantiate_node(SyntaxNode,input, i4...index, s4) r4.extend(ObsDomainList0) else @index = i4 r4 = nil end if r4 s3 << r4 else break end end r3 = instantiate_node(SyntaxNode,input, i3...index, s3) s0 << r3 end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsDomainList1) else @index = i0 r0 = nil end node_cache[:obs_domain_list][start_index] = r0 r0 end module ObsLocalPart0 def word elements[1] end end module ObsLocalPart1 def word elements[0] end end def _nt_obs_local_part start_index = index if node_cache[:obs_local_part].has_key?(index) cached = node_cache[:obs_local_part][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_word s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] if has_terminal?(".", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r4 = nil end s3 << r4 if r4 r5 = _nt_word s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsLocalPart0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsLocalPart1) else @index = i0 r0 = nil end node_cache[:obs_local_part][start_index] = r0 r0 end module ObsDomain0 def atom elements[1] end end module ObsDomain1 def atom elements[0] end end def _nt_obs_domain start_index = index if node_cache[:obs_domain].has_key?(index) cached = node_cache[:obs_domain][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_atom s0 << r1 if r1 s2, i2 = [], index loop do i3, s3 = index, [] if has_terminal?(".", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(".") r4 = nil end s3 << r4 if r4 r5 = _nt_atom s3 << r5 end if s3.last r3 = instantiate_node(SyntaxNode,input, i3...index, s3) r3.extend(ObsDomain0) else @index = i3 r3 = nil end if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsDomain1) else @index = i0 r0 = nil end node_cache[:obs_domain][start_index] = r0 r0 end module ObsMboxList0 end module ObsMboxList1 end def _nt_obs_mbox_list start_index = index if node_cache[:obs_mbox_list].has_key?(index) cached = node_cache[:obs_mbox_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do i2, s2 = index, [] r4 = _nt_mailbox if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s2 << r3 if r3 r6 = _nt_CFWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s2 << r5 if r5 if has_terminal?(",", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r7 = nil end s2 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s2 << r8 end end end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(ObsMboxList0) else @index = i2 r2 = nil end if r2 s1 << r2 else break end end if s1.empty? @index = i1 r1 = nil else r1 = instantiate_node(SyntaxNode,input, i1...index, s1) end s0 << r1 if r1 r11 = _nt_mailbox if r11 r10 = r11 else r10 = instantiate_node(SyntaxNode,input, index...index) end s0 << r10 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsMboxList1) else @index = i0 r0 = nil end node_cache[:obs_mbox_list][start_index] = r0 r0 end module ObsAddrList0 end module ObsAddrList1 end def _nt_obs_addr_list start_index = index if node_cache[:obs_addr_list].has_key?(index) cached = node_cache[:obs_addr_list][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] s1, i1 = [], index loop do i2, s2 = index, [] r4 = _nt_address if r4 r3 = r4 else r3 = instantiate_node(SyntaxNode,input, index...index) end s2 << r3 if r3 r6 = _nt_CFWS if r6 r5 = r6 else r5 = instantiate_node(SyntaxNode,input, index...index) end s2 << r5 if r5 if has_terminal?(",", false, index) r7 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(",") r7 = nil end s2 << r7 if r7 r9 = _nt_CFWS if r9 r8 = r9 else r8 = instantiate_node(SyntaxNode,input, index...index) end s2 << r8 end end end if s2.last r2 = instantiate_node(SyntaxNode,input, i2...index, s2) r2.extend(ObsAddrList0) else @index = i2 r2 = nil end if r2 s1 << r2 else break end end if s1.empty? @index = i1 r1 = nil else r1 = instantiate_node(SyntaxNode,input, i1...index, s1) end s0 << r1 if r1 r11 = _nt_address if r11 r10 = r11 else r10 = instantiate_node(SyntaxNode,input, index...index) end s0 << r10 end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsAddrList1) else @index = i0 r0 = nil end node_cache[:obs_addr_list][start_index] = r0 r0 end def _nt_obs_fields start_index = index if node_cache[:obs_fields].has_key?(index) cached = node_cache[:obs_fields][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end s0, i0 = [], index loop do i1 = index r2 = _nt_obs_return if r2 r1 = r2 else r3 = _nt_obs_received if r3 r1 = r3 else r4 = _nt_obs_orig_date if r4 r1 = r4 else r5 = _nt_obs_from if r5 r1 = r5 else r6 = _nt_obs_sender if r6 r1 = r6 else r7 = _nt_obs_reply_to if r7 r1 = r7 else r8 = _nt_obs_to if r8 r1 = r8 else r9 = _nt_obs_cc if r9 r1 = r9 else r10 = _nt_obs_bcc if r10 r1 = r10 else r11 = _nt_obs_message_id if r11 r1 = r11 else r12 = _nt_obs_in_reply_to if r12 r1 = r12 else r13 = _nt_obs_references if r13 r1 = r13 else r14 = _nt_obs_subject if r14 r1 = r14 else r15 = _nt_obs_comments if r15 r1 = r15 else r16 = _nt_obs_keywords if r16 r1 = r16 else r17 = _nt_obs_resent_date if r17 r1 = r17 else r18 = _nt_obs_resent_from if r18 r1 = r18 else r19 = _nt_obs_resent_send if r19 r1 = r19 else r20 = _nt_obs_resent_rply if r20 r1 = r20 else r21 = _nt_obs_resent_to if r21 r1 = r21 else r22 = _nt_obs_resent_cc if r22 r1 = r22 else r23 = _nt_obs_resent_bcc if r23 r1 = r23 else r24 = _nt_obs_resent_mid if r24 r1 = r24 else r25 = _nt_obs_optional if r25 r1 = r25 else @index = i1 r1 = nil end end end end end end end end end end end end end end end end end end end end end end end end if r1 s0 << r1 else break end end r0 = instantiate_node(SyntaxNode,input, i0...index, s0) node_cache[:obs_fields][start_index] = r0 r0 end module ObsOrigDate0 def date_time elements[3] end def CRLF elements[4] end end def _nt_obs_orig_date start_index = index if node_cache[:obs_orig_date].has_key?(index) cached = node_cache[:obs_orig_date][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Date", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) @index += 4 else terminal_parse_failure("Date") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_date_time s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsOrigDate0) else @index = i0 r0 = nil end node_cache[:obs_orig_date][start_index] = r0 r0 end module ObsFrom0 def mailbox_list elements[3] end def CRLF elements[4] end end def _nt_obs_from start_index = index if node_cache[:obs_from].has_key?(index) cached = node_cache[:obs_from][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("From", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 4)) @index += 4 else terminal_parse_failure("From") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_mailbox_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsFrom0) else @index = i0 r0 = nil end node_cache[:obs_from][start_index] = r0 r0 end module ObsSender0 def mailbox elements[3] end def CRLF elements[4] end end def _nt_obs_sender start_index = index if node_cache[:obs_sender].has_key?(index) cached = node_cache[:obs_sender][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Sender", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 6)) @index += 6 else terminal_parse_failure("Sender") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_mailbox s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsSender0) else @index = i0 r0 = nil end node_cache[:obs_sender][start_index] = r0 r0 end module ObsReplyTo0 def mailbox_list elements[3] end def CRLF elements[4] end end def _nt_obs_reply_to start_index = index if node_cache[:obs_reply_to].has_key?(index) cached = node_cache[:obs_reply_to][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Reply-To", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 8)) @index += 8 else terminal_parse_failure("Reply-To") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_mailbox_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsReplyTo0) else @index = i0 r0 = nil end node_cache[:obs_reply_to][start_index] = r0 r0 end module ObsTo0 def address_list elements[3] end def CRLF elements[4] end end def _nt_obs_to start_index = index if node_cache[:obs_to].has_key?(index) cached = node_cache[:obs_to][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("To", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) @index += 2 else terminal_parse_failure("To") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_address_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsTo0) else @index = i0 r0 = nil end node_cache[:obs_to][start_index] = r0 r0 end module ObsCc0 def address_list elements[3] end def CRLF elements[4] end end def _nt_obs_cc start_index = index if node_cache[:obs_cc].has_key?(index) cached = node_cache[:obs_cc][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Cc", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 2)) @index += 2 else terminal_parse_failure("Cc") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_address_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsCc0) else @index = i0 r0 = nil end node_cache[:obs_cc][start_index] = r0 r0 end module ObsBcc0 def CRLF elements[4] end end def _nt_obs_bcc start_index = index if node_cache[:obs_bcc].has_key?(index) cached = node_cache[:obs_bcc][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Bcc", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 3)) @index += 3 else terminal_parse_failure("Bcc") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 i5 = index r6 = _nt_address_list if r6 r5 = r6 else r8 = _nt_CFWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end if r7 r5 = r7 else @index = i5 r5 = nil end end s0 << r5 if r5 r9 = _nt_CRLF s0 << r9 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsBcc0) else @index = i0 r0 = nil end node_cache[:obs_bcc][start_index] = r0 r0 end module ObsMessageId0 def msg_id elements[3] end def CRLF elements[4] end end def _nt_obs_message_id start_index = index if node_cache[:obs_message_id].has_key?(index) cached = node_cache[:obs_message_id][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Message-ID", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 10)) @index += 10 else terminal_parse_failure("Message-ID") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_msg_id s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsMessageId0) else @index = i0 r0 = nil end node_cache[:obs_message_id][start_index] = r0 r0 end module ObsInReplyTo0 def CRLF elements[4] end end def _nt_obs_in_reply_to start_index = index if node_cache[:obs_in_reply_to].has_key?(index) cached = node_cache[:obs_in_reply_to][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("In-Reply-To", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 11)) @index += 11 else terminal_parse_failure("In-Reply-To") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 s5, i5 = [], index loop do i6 = index r7 = _nt_phrase if r7 r6 = r7 else r8 = _nt_msg_id if r8 r6 = r8 else @index = i6 r6 = nil end end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 r9 = _nt_CRLF s0 << r9 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsInReplyTo0) else @index = i0 r0 = nil end node_cache[:obs_in_reply_to][start_index] = r0 r0 end module ObsReferences0 def CRLF elements[4] end end def _nt_obs_references start_index = index if node_cache[:obs_references].has_key?(index) cached = node_cache[:obs_references][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("References", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 10)) @index += 10 else terminal_parse_failure("References") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 s5, i5 = [], index loop do i6 = index r7 = _nt_phrase if r7 r6 = r7 else r8 = _nt_msg_id if r8 r6 = r8 else @index = i6 r6 = nil end end if r6 s5 << r6 else break end end r5 = instantiate_node(SyntaxNode,input, i5...index, s5) s0 << r5 if r5 r9 = _nt_CRLF s0 << r9 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsReferences0) else @index = i0 r0 = nil end node_cache[:obs_references][start_index] = r0 r0 end def _nt_obs_id_left start_index = index if node_cache[:obs_id_left].has_key?(index) cached = node_cache[:obs_id_left][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_local_part node_cache[:obs_id_left][start_index] = r0 r0 end def _nt_obs_id_right start_index = index if node_cache[:obs_id_right].has_key?(index) cached = node_cache[:obs_id_right][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_domain node_cache[:obs_id_right][start_index] = r0 r0 end module ObsSubject0 def unstructured elements[3] end def CRLF elements[4] end end def _nt_obs_subject start_index = index if node_cache[:obs_subject].has_key?(index) cached = node_cache[:obs_subject][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Subject", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 7)) @index += 7 else terminal_parse_failure("Subject") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_unstructured s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsSubject0) else @index = i0 r0 = nil end node_cache[:obs_subject][start_index] = r0 r0 end module ObsComments0 def unstructured elements[3] end def CRLF elements[4] end end def _nt_obs_comments start_index = index if node_cache[:obs_comments].has_key?(index) cached = node_cache[:obs_comments][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Comments", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 8)) @index += 8 else terminal_parse_failure("Comments") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_unstructured s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsComments0) else @index = i0 r0 = nil end node_cache[:obs_comments][start_index] = r0 r0 end module ObsKeywords0 def obs_phrase_list elements[3] end def CRLF elements[4] end end def _nt_obs_keywords start_index = index if node_cache[:obs_keywords].has_key?(index) cached = node_cache[:obs_keywords][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Keywords", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 8)) @index += 8 else terminal_parse_failure("Keywords") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_obs_phrase_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsKeywords0) else @index = i0 r0 = nil end node_cache[:obs_keywords][start_index] = r0 r0 end module ObsResentFrom0 def mailbox_list elements[3] end def CRLF elements[4] end end def _nt_obs_resent_from start_index = index if node_cache[:obs_resent_from].has_key?(index) cached = node_cache[:obs_resent_from][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-From", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 11)) @index += 11 else terminal_parse_failure("Resent-From") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_mailbox_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentFrom0) else @index = i0 r0 = nil end node_cache[:obs_resent_from][start_index] = r0 r0 end module ObsResentSend0 def mailbox elements[3] end def CRLF elements[4] end end def _nt_obs_resent_send start_index = index if node_cache[:obs_resent_send].has_key?(index) cached = node_cache[:obs_resent_send][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Sender", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 13)) @index += 13 else terminal_parse_failure("Resent-Sender") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_mailbox s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentSend0) else @index = i0 r0 = nil end node_cache[:obs_resent_send][start_index] = r0 r0 end module ObsResentDate0 def date_time elements[3] end def CRLF elements[4] end end def _nt_obs_resent_date start_index = index if node_cache[:obs_resent_date].has_key?(index) cached = node_cache[:obs_resent_date][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Date", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 11)) @index += 11 else terminal_parse_failure("Resent-Date") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_date_time s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentDate0) else @index = i0 r0 = nil end node_cache[:obs_resent_date][start_index] = r0 r0 end module ObsResentTo0 def address_list elements[3] end def CRLF elements[4] end end def _nt_obs_resent_to start_index = index if node_cache[:obs_resent_to].has_key?(index) cached = node_cache[:obs_resent_to][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-To", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 9)) @index += 9 else terminal_parse_failure("Resent-To") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_address_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentTo0) else @index = i0 r0 = nil end node_cache[:obs_resent_to][start_index] = r0 r0 end module ObsResentCc0 def address_list elements[3] end def CRLF elements[4] end end def _nt_obs_resent_cc start_index = index if node_cache[:obs_resent_cc].has_key?(index) cached = node_cache[:obs_resent_cc][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Cc", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 9)) @index += 9 else terminal_parse_failure("Resent-Cc") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_address_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentCc0) else @index = i0 r0 = nil end node_cache[:obs_resent_cc][start_index] = r0 r0 end module ObsResentBcc0 def CRLF elements[4] end end def _nt_obs_resent_bcc start_index = index if node_cache[:obs_resent_bcc].has_key?(index) cached = node_cache[:obs_resent_bcc][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Bcc", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 10)) @index += 10 else terminal_parse_failure("Resent-Bcc") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 i5 = index r6 = _nt_address_list if r6 r5 = r6 else r8 = _nt_CFWS if r8 r7 = r8 else r7 = instantiate_node(SyntaxNode,input, index...index) end if r7 r5 = r7 else @index = i5 r5 = nil end end s0 << r5 if r5 r9 = _nt_CRLF s0 << r9 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentBcc0) else @index = i0 r0 = nil end node_cache[:obs_resent_bcc][start_index] = r0 r0 end module ObsResentMid0 def msg_id elements[3] end def CRLF elements[4] end end def _nt_obs_resent_mid start_index = index if node_cache[:obs_resent_mid].has_key?(index) cached = node_cache[:obs_resent_mid][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Message-ID", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 17)) @index += 17 else terminal_parse_failure("Resent-Message-ID") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_msg_id s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentMid0) else @index = i0 r0 = nil end node_cache[:obs_resent_mid][start_index] = r0 r0 end module ObsResentRply0 def address_list elements[3] end def CRLF elements[4] end end def _nt_obs_resent_rply start_index = index if node_cache[:obs_resent_rply].has_key?(index) cached = node_cache[:obs_resent_rply][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Resent-Reply-To", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 15)) @index += 15 else terminal_parse_failure("Resent-Reply-To") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_address_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsResentRply0) else @index = i0 r0 = nil end node_cache[:obs_resent_rply][start_index] = r0 r0 end module ObsReturn0 def path elements[3] end def CRLF elements[4] end end def _nt_obs_return start_index = index if node_cache[:obs_return].has_key?(index) cached = node_cache[:obs_return][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Return-Path", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 11)) @index += 11 else terminal_parse_failure("Return-Path") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_path s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsReturn0) else @index = i0 r0 = nil end node_cache[:obs_return][start_index] = r0 r0 end module ObsReceived0 def name_val_list elements[3] end def CRLF elements[4] end end def _nt_obs_received start_index = index if node_cache[:obs_received].has_key?(index) cached = node_cache[:obs_received][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] if has_terminal?("Received", false, index) r1 = instantiate_node(SyntaxNode,input, index...(index + 8)) @index += 8 else terminal_parse_failure("Received") r1 = nil end s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_name_val_list s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsReceived0) else @index = i0 r0 = nil end node_cache[:obs_received][start_index] = r0 r0 end def _nt_obs_path start_index = index if node_cache[:obs_path].has_key?(index) cached = node_cache[:obs_path][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end r0 = _nt_obs_angle_addr node_cache[:obs_path][start_index] = r0 r0 end module ObsOptional0 def field_name elements[0] end def unstructured elements[3] end def CRLF elements[4] end end def _nt_obs_optional start_index = index if node_cache[:obs_optional].has_key?(index) cached = node_cache[:obs_optional][index] if cached cached = SyntaxNode.new(input, index...(index + 1)) if cached == true @index = cached.interval.end end return cached end i0, s0 = index, [] r1 = _nt_field_name s0 << r1 if r1 s2, i2 = [], index loop do r3 = _nt_WSP if r3 s2 << r3 else break end end r2 = instantiate_node(SyntaxNode,input, i2...index, s2) s0 << r2 if r2 if has_terminal?(":", false, index) r4 = instantiate_node(SyntaxNode,input, index...(index + 1)) @index += 1 else terminal_parse_failure(":") r4 = nil end s0 << r4 if r4 r5 = _nt_unstructured s0 << r5 if r5 r6 = _nt_CRLF s0 << r6 end end end end if s0.last r0 = instantiate_node(SyntaxNode,input, i0...index, s0) r0.extend(ObsOptional0) else @index = i0 r0 = nil end node_cache[:obs_optional][start_index] = r0 r0 end end class RFC2822ObsoleteParser < Treetop::Runtime::CompiledParser include RFC2822Obsolete end end mail-2.5.4/lib/mail/parsers/rfc2822_obsolete.treetop000066400000000000000000000107261214434061600222120ustar00rootroot00000000000000module Mail grammar RFC2822Obsolete rule obs_qp "\\" [\x00-\x7F] end rule obs_text LF* CR* (obs_char LF* CR*)* end rule obs_char [\x00-\x09] / # %d0-127 except CR and [\x0B-\x0C] / # LF [\x0E-\x7F] end rule obs_utext obs_text end rule obs_phrase (word / "." / "@")+ end rule obs_phrase_list phrase / (phrase? CFWS? "," CFWS?)+ phrase? end rule obs_FWS WSP+ (CRLF WSP+)* end rule obs_day_of_week CFWS? day_name CFWS? end rule obs_year CFWS? (DIGIT DIGIT) CFWS? end rule obs_month CFWS month_name CFWS end rule obs_day CFWS? (DIGIT / (DIGIT DIGIT)) CFWS? end rule obs_hour CFWS? (DIGIT DIGIT) CFWS? end rule obs_minute CFWS? (DIGIT DIGIT) CFWS? end rule obs_second CFWS? (DIGIT DIGIT) CFWS? end rule obs_zone "UT" / "GMT" / # Universal Time # North American UT # offsets "EST" / "EDT" / # Eastern: - 5/ - 4 "CST" / "CDT" / # Central: - 6/ - 5 "MST" / "MDT" / # Mountain: - 7/ - 6 "PST" / "PDT" / # Pacific: - 8/ - 7 # [\x41-\x49] / # Military zones - "A" [\x4B-\x5A] / # through "I" and "K" [\x61-\x69] / # through "Z", both [\x6B-\x7A] # upper and lower case end rule obs_angle_addr CFWS? "<" obs_route? addr_spec ">" CFWS? end rule obs_route CFWS? obs_domain_list ":" CFWS? end rule obs_domain_list "@" domain (("," )* CFWS? "@" domain)* end rule obs_local_part word ("." word)* end rule obs_domain atom ("." atom)* end rule obs_mbox_list (mailbox? CFWS? "," CFWS?)+ mailbox? end rule obs_addr_list (address? CFWS? "," CFWS?)+ address? end rule obs_fields (obs_return / obs_received / obs_orig_date / obs_from / obs_sender / obs_reply_to / obs_to / obs_cc / obs_bcc / obs_message_id / obs_in_reply_to / obs_references / obs_subject / obs_comments / obs_keywords / obs_resent_date / obs_resent_from / obs_resent_send / obs_resent_rply / obs_resent_to / obs_resent_cc / obs_resent_bcc / obs_resent_mid / obs_optional)* end rule obs_orig_date "Date" WSP* ":" date_time CRLF end rule obs_from "From" WSP* ":" mailbox_list CRLF end rule obs_sender "Sender" WSP* ":" mailbox CRLF end rule obs_reply_to "Reply-To" WSP* ":" mailbox_list CRLF end rule obs_to "To" WSP* ":" address_list CRLF end rule obs_cc "Cc" WSP* ":" address_list CRLF end rule obs_bcc "Bcc" WSP* ":" (address_list / CFWS?) CRLF end rule obs_message_id "Message-ID" WSP* ":" msg_id CRLF end rule obs_in_reply_to "In-Reply-To" WSP* ":" (phrase / msg_id)* CRLF end rule obs_references "References" WSP* ":" (phrase / msg_id)* CRLF end rule obs_id_left local_part end rule obs_id_right domain end rule obs_subject "Subject" WSP* ":" unstructured CRLF end rule obs_comments "Comments" WSP* ":" unstructured CRLF end rule obs_keywords "Keywords" WSP* ":" obs_phrase_list CRLF end rule obs_resent_from "Resent-From" WSP* ":" mailbox_list CRLF end rule obs_resent_send "Resent-Sender" WSP* ":" mailbox CRLF end rule obs_resent_date "Resent-Date" WSP* ":" date_time CRLF end rule obs_resent_to "Resent-To" WSP* ":" address_list CRLF end rule obs_resent_cc "Resent-Cc" WSP* ":" address_list CRLF end rule obs_resent_bcc "Resent-Bcc" WSP* ":" (address_list / CFWS?) CRLF end rule obs_resent_mid "Resent-Message-ID" WSP* ":" msg_id CRLF end rule obs_resent_rply "Resent-Reply-To" WSP* ":" address_list CRLF end rule obs_return "Return-Path" WSP* ":" path CRLF end rule obs_received "Received" WSP* ":" name_val_list CRLF end rule obs_path obs_angle_addr end rule obs_optional field_name WSP* ":" unstructured CRLF end end end mail-2.5.4/lib/mail/part.rb000066400000000000000000000060041214434061600154300ustar00rootroot00000000000000# encoding: utf-8 module Mail class Part < Message # Creates a new empty Content-ID field and inserts it in the correct order # into the Header. The ContentIdField object will automatically generate # a unique content ID if you try and encode it or output it to_s without # specifying a content id. # # It will preserve the content ID you specify if you do. def add_content_id(content_id_val = '') header['content-id'] = content_id_val end # Returns true if the part has a content ID field, the field may or may # not have a value, but the field exists or not. def has_content_id? header.has_content_id? end def inline_content_id # TODO: Deprecated in 2.2.2 - Remove in 2.3 STDERR.puts("Part#inline_content_id is deprecated, please call Part#cid instead") cid end def cid add_content_id unless has_content_id? uri_escape(unbracket(content_id)) end def url "cid:#{cid}" end def inline? header[:content_disposition].disposition_type == 'inline' if header[:content_disposition] end def add_required_fields super add_content_id if !has_content_id? && inline? end def add_required_message_fields # Override so we don't add Date, MIME-Version, or Message-ID. end def delivery_status_report_part? (main_type =~ /message/i && sub_type =~ /delivery-status/i) && body =~ /Status:/ end def delivery_status_data delivery_status_report_part? ? parse_delivery_status_report : {} end def bounced? if action.is_a?(Array) !!(action.first =~ /failed/i) else !!(action =~ /failed/i) end end # Either returns the action if the message has just a single report, or an # array of all the actions, one for each report def action get_return_values('action') end def final_recipient get_return_values('final-recipient') end def error_status get_return_values('status') end def diagnostic_code get_return_values('diagnostic-code') end def remote_mta get_return_values('remote-mta') end def retryable? !(error_status =~ /^5/) end private def get_return_values(key) if delivery_status_data[key].is_a?(Array) delivery_status_data[key].map { |a| a.value } else delivery_status_data[key].value end end # A part may not have a header.... so, just init a body if no header def parse_message header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}/m, 2) if header_part =~ HEADER_LINE self.header = header_part self.body = body_part else self.header = "Content-Type: text/plain\r\n" self.body = raw_source end end def parse_delivery_status_report @delivery_status_data ||= Header.new(body.to_s.gsub("\r\n\r\n", "\r\n")) end end end mail-2.5.4/lib/mail/parts_list.rb000066400000000000000000000023421214434061600166470ustar00rootroot00000000000000module Mail class PartsList < Array def attachments Mail::AttachmentsList.new(self) end def collect if block_given? ary = PartsList.new each { |o| ary << yield(o) } ary else to_a end end undef :map alias_method :map, :collect def map! raise NoMethodError, "#map! is not defined, please call #collect and create a new PartsList" end def collect! raise NoMethodError, "#collect! is not defined, please call #collect and create a new PartsList" end def sort self.class.new(super) end def sort!(order) sorted = self.sort do |a, b| # OK, 10000 is arbitrary... if anyone actually wants to explicitly sort 10000 parts of a # single email message... please show me a use case and I'll put more work into this method, # in the meantime, it works :) get_order_value(a, order) <=> get_order_value(b, order) end self.clear sorted.each { |p| self << p } end private def get_order_value(part, order) if part.respond_to?(:content_type) order.index(part[:content_type].string.downcase) || 10000 else 10000 end end end end mail-2.5.4/lib/mail/patterns.rb000066400000000000000000000022271214434061600163250ustar00rootroot00000000000000# encoding: us-ascii module Mail module Patterns white_space = %Q|\x9\x20| text = %Q|\x1-\x8\xB\xC\xE-\x7f| field_name = %Q|\x21-\x39\x3b-\x7e| qp_safe = %Q|\x20-\x3c\x3e-\x7e| aspecial = %Q|()<>[]:;@\\,."| # RFC5322 tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045 sp = %Q| | control = %Q|\x00-\x1f\x7f-\xff| if control.respond_to?(:force_encoding) control = control.force_encoding(Encoding::BINARY) end CRLF = /\r\n/ WSP = /[#{white_space}]/ FWS = /#{CRLF}#{WSP}*/ TEXT = /[#{text}]/ # + obs-text FIELD_NAME = /[#{field_name}]+/ FIELD_BODY = /.+/ FIELD_LINE = /^[#{field_name}]+:\s*.+$/ FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/ HEADER_LINE = /^([#{field_name}]+:\s*.+)$/ QP_UNSAFE = /[^#{qp_safe}]/ QP_SAFE = /[#{qp_safe}]/ CONTROL_CHAR = /[#{control}]/n ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n end end mail-2.5.4/lib/mail/utilities.rb000066400000000000000000000133061214434061600165000ustar00rootroot00000000000000# encoding: utf-8 module Mail module Utilities include Patterns # Returns true if the string supplied is free from characters not allowed as an ATOM def atom_safe?( str ) not ATOM_UNSAFE === str end # If the string supplied has ATOM unsafe characters in it, will return the string quoted # in double quotes, otherwise returns the string unmodified def quote_atom( str ) atom_safe?( str ) ? str : dquote(str) end # If the string supplied has PHRASE unsafe characters in it, will return the string quoted # in double quotes, otherwise returns the string unmodified def quote_phrase( str ) if RUBY_VERSION >= '1.9' original_encoding = str.encoding str.force_encoding('ASCII-8BIT') if (PHRASE_UNSAFE === str) dquote(str).force_encoding(original_encoding) else str.force_encoding(original_encoding) end else (PHRASE_UNSAFE === str) ? dquote(str) : str end end # Returns true if the string supplied is free from characters not allowed as a TOKEN def token_safe?( str ) not TOKEN_UNSAFE === str end # If the string supplied has TOKEN unsafe characters in it, will return the string quoted # in double quotes, otherwise returns the string unmodified def quote_token( str ) token_safe?( str ) ? str : dquote(str) end # Wraps supplied string in double quotes and applies \-escaping as necessary, # unless it is already wrapped. # # Example: # # string = 'This is a string' # dquote(string) #=> '"This is a string"' # # string = 'This is "a string"' # dquote(string #=> '"This is \"a string\"' def dquote( str ) '"' + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + '"' end # Unwraps supplied string from inside double quotes and # removes any \-escaping. # # Example: # # string = '"This is a string"' # unquote(string) #=> 'This is a string' # # string = '"This is \"a string\""' # unqoute(string) #=> 'This is "a string"' def unquote( str ) if str =~ /^"(.*?)"$/ $1.gsub(/\\(.)/, '\1') else str end end # Wraps a string in parenthesis and escapes any that are in the string itself. # # Example: # # paren( 'This is a string' ) #=> '(This is a string)' def paren( str ) RubyVer.paren( str ) end # Unwraps a string from being wrapped in parenthesis # # Example: # # str = '(This is a string)' # unparen( str ) #=> 'This is a string' def unparen( str ) match = str.match(/^\((.*?)\)$/) match ? match[1] : str end # Wraps a string in angle brackets and escapes any that are in the string itself # # Example: # # bracket( 'This is a string' ) #=> '' def bracket( str ) RubyVer.bracket( str ) end # Unwraps a string from being wrapped in parenthesis # # Example: # # str = '' # unbracket( str ) #=> 'This is a string' def unbracket( str ) match = str.match(/^\<(.*?)\>$/) match ? match[1] : str end # Escape parenthesies in a string # # Example: # # str = 'This is (a) string' # escape_paren( str ) #=> 'This is \(a\) string' def escape_paren( str ) RubyVer.escape_paren( str ) end def uri_escape( str ) uri_parser.escape(str) end def uri_unescape( str ) uri_parser.unescape(str) end def uri_parser @uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI end # Matches two objects with their to_s values case insensitively # # Example: # # obj2 = "This_is_An_object" # obj1 = :this_IS_an_object # match_to_s( obj1, obj2 ) #=> true def match_to_s( obj1, obj2 ) obj1.to_s.casecmp(obj2.to_s) == 0 end # Capitalizes a string that is joined by hyphens correctly. # # Example: # # string = 'resent-from-field' # capitalize_field( string ) #=> 'Resent-From-Field' def capitalize_field( str ) str.to_s.split("-").map { |v| v.capitalize }.join("-") end # Takes an underscored word and turns it into a class name # # Example: # # constantize("hello") #=> "Hello" # constantize("hello-there") #=> "HelloThere" # constantize("hello-there-mate") #=> "HelloThereMate" def constantize( str ) str.to_s.split(/[-_]/).map { |v| v.capitalize }.to_s end # Swaps out all underscores (_) for hyphens (-) good for stringing from symbols # a field name. # # Example: # # string = :resent_from_field # dasherize ( string ) #=> 'resent_from_field' def dasherize( str ) str.to_s.gsub('_', '-') end # Swaps out all hyphens (-) for underscores (_) good for stringing to symbols # a field name. # # Example: # # string = :resent_from_field # underscoreize ( string ) #=> 'resent_from_field' def underscoreize( str ) str.to_s.downcase.gsub('-', '_') end if RUBY_VERSION <= '1.8.6' def map_lines( str, &block ) results = [] str.each_line do |line| results << yield(line) end results end def map_with_index( enum, &block ) results = [] enum.each_with_index do |token, i| results[i] = yield(token, i) end results end else def map_lines( str, &block ) str.each_line.map(&block) end def map_with_index( enum, &block ) enum.each_with_index.map(&block) end end end end mail-2.5.4/lib/mail/values/000077500000000000000000000000001214434061600154345ustar00rootroot00000000000000mail-2.5.4/lib/mail/values/unicode_tables.dat000066400000000000000000033463301214434061600211220ustar00rootroot00000000000000[ }l_io:1ActiveSupport::Multibyte::Unicode::Codepoint :@combining_classi:@uppercase_mappingi:@lowercase_mappingi: @codei:@decomp_type0:@decomp_mapping0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;if; iF; 0; 0iGo; ;i;i;ig; iG; 0; 0iHo; ;i;i;ih; iH; 0; 0iIo; ;i;i;ii; iI; 0; 0iJo; ;i;i;ij; iJ; 0; 0iKo; ;i;i;ik; iK; 0; 0iLo; ;i;i;il; iL; 0; 0iMo; ;i;i;im; iM; 0; 0iNo; ;i;i;in; iN; 0; 0iOo; ;i;i;io; iO; 0; 0iPo; ;i;i;ip; iP; 0; 0iQo; ;i;i;iq; iQ; 0; 0iRo; ;i;i;ir; iR; 0; 0iSo; ;i;i;is; iS; 0; 0iTo; ;i;i;it; iT; 0; 0iUo; ;i;i;iu; iU; 0; 0iVo; ;i;i;iv; iV; 0; 0iWo; ;i;i;iw; iW; 0; 0iXo; ;i;i;ix; iX; 0; 0iYo; ;i;i;iy; iY; 0; 0iZo; ;i;i;iz; iZ; 0; 0i[o; ;i;i;i{; i[; 0; 0i\o; ;i;i;i|; i\; 0; 0i]o; ;i;i;i}; i]; 0; 0i^o; ;i;i;i~; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;iF;i; if; 0; 0igo; ;i;iG;i; ig; 0; 0iho; ;i;iH;i; ih; 0; 0iio; ;i;iI;i; ii; 0; 0ijo; ;i;iJ;i; ij; 0; 0iko; ;i;iK;i; ik; 0; 0ilo; ;i;iL;i; il; 0; 0imo; ;i;iM;i; im; 0; 0ino; ;i;iN;i; in; 0; 0ioo; ;i;iO;i; io; 0; 0ipo; ;i;iP;i; ip; 0; 0iqo; ;i;iQ;i; iq; 0; 0iro; ;i;iR;i; ir; 0; 0iso; ;i;iS;i; is; 0; 0ito; ;i;iT;i; it; 0; 0iuo; ;i;iU;i; iu; 0; 0ivo; ;i;iV;i; iv; 0; 0iwo; ;i;iW;i; iw; 0; 0ixo; ;i;iX;i; ix; 0; 0iyo; ;i;iY;i; iy; 0; 0izo; ;i;iZ;i; iz; 0; 0i{o; ;i;i[;i; i{; 0; 0i|o; ;i;i\;i; i|; 0; 0i}o; ;i;i];i; i}; 0; 0i~o; ;i;i^;i; i~; 0; 0io; ;i;i_;i; i; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" noBreak:ET; [i%io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [ifio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [i7io; ;i;i;i; i; I" super; T; [i8io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [i%i'io; ;i;i;i; i; I" super; T; [i6io; ;i;i;i; i; I" super; T; [itio; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" fraction; T; [i6iD i9io; ;i;i;i; i; I" fraction; T; [i6iD i7io; ;i;i;i; i; I" fraction; T; [i8iD i9io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [iFi io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iHi'io; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [iNiio; ;i;i;i; i; 0; [iNiio; ;i;i;i; i; 0; [iNiio; ;i;i;i; i; 0; [iNiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iSiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [i^iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [ifi io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [ihi'io; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iniio; ;i;i;i; i; 0; [iniio; ;i;i;i; i; 0; [iniio; ;i;i;i; i; 0; [iniio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [isiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [i~iio; ;i;i;i; i; 0; 0io; ;i;ix;i; i; 0; [i~iio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [iFi(io; ;i;i;i; i; 0; [ifi(io; ;i;i;i; i; 0; [iHiio; ;i;i;i; i; 0; [ihiio; ;i;i;i ; i; 0; [iHii o; ;i;i;i; i ; 0; [ihii o; ;i;i;i ; i ; 0; [iHii o; ;i;i ;i; i ; 0; [ihii o; ;i;i;i ; i ; 0; [iHi i o; ;i;i ;i; i ; 0; [ihi io; ;i;i;i; i; 0; [iIi io; ;i;i;i; i; 0; [iii io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iJi(io; ;i;i;i; i; 0; [iji(io; ;i;i;i; i; 0; [iJi io; ;i;i;i; i; 0; [iji io; ;i;i;i; i; 0; [iLiio; ;i;i;i; i; 0; [iliio; ;i;i;i; i; 0; [iLiio; ;i;i;i; i; 0; [ilii o; ;i;i;i!; i ; 0; [iLii!o; ;i;i ;i; i!; 0; [ilii"o; ;i;i;i#; i"; 0; [iLi'i#o; ;i;i";i; i#; 0; [ili'i$o; ;i;i;i%; i$; 0; [iMii%o; ;i;i$;i; i%; 0; [imii&o; ;i;i;i'; i&; 0; 0i'o; ;i;i&;i; i'; 0; 0i(o; ;i;i;i); i(; 0; [iNii)o; ;i;i(;i; i); 0; [inii*o; ;i;i;i+; i*; 0; [iNii+o; ;i;i*;i; i+; 0; [inii,o; ;i;i;i-; i,; 0; [iNii-o; ;i;i,;i; i-; 0; [inii.o; ;i;i;i/; i.; 0; [iNi(i/o; ;i;i.;i; i/; 0; [ini(i0o; ;i;i;in; i0; 0; [iNii1o; ;i;iN;i; i1; 0; 0i2o; ;i;i;i3; i2; I" compat; T; [iNiOi3o; ;i;i2;i; i3; I" compat; T; [inioi4o; ;i;i;i5; i4; 0; [iOii5o; ;i;i4;i; i5; 0; [ioii6o; ;i;i;i7; i6; 0; [iPi'i7o; ;i;i6;i; i7; 0; [ipi'i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i:; i9; 0; [iQii:o; ;i;i9;i; i:; 0; [iqii;o; ;i;i;i<; i;; 0; [iQi'i<o; ;i;i;;i; i<; 0; [iqi'i=o; ;i;i;i>; i=; 0; [iQi i>o; ;i;i=;i; i>; 0; [iqi i?o; ;i;i;i@; i?; I" compat; T; [iQii@o; ;i;i?;i; i@; I" compat; T; [iqiiAo; ;i;i;iB; iA; 0; 0iBo; ;i;iA;i; iB; 0; 0iCo; ;i;i;iD; iC; 0; [iSiiDo; ;i;iC;i; iD; 0; [isiiEo; ;i;i;iF; iE; 0; [iSi'iFo; ;i;iE;i; iF; 0; [isi'iGo; ;i;i;iH; iG; 0; [iSi iHo; ;i;iG;i; iH; 0; [isi iIo; ;i;i;i; iI; I" compat; T; [iisiJo; ;i;i;iK; iJ; 0; 0iKo; ;i;iJ;i; iK; 0; 0iLo; ;i;i;iM; iL; 0; [iTiiMo; ;i;iL;i; iM; 0; [itiiNo; ;i;i;iO; iN; 0; [iTiiOo; ;i;iN;i; iO; 0; [itiiPo; ;i;i;iQ; iP; 0; [iTi iQo; ;i;iP;i; iQ; 0; [iti iRo; ;i;i;iS; iR; 0; 0iSo; ;i;iR;i; iS; 0; 0iTo; ;i;i;iU; iT; 0; [iWiiUo; ;i;iT;i; iU; 0; [iwiiVo; ;i;i;iW; iV; 0; [iWi'iWo; ;i;iV;i; iW; 0; [iwi'iXo; ;i;i;iY; iX; 0; [iWi iYo; ;i;iX;i; iY; 0; [iwi iZo; ;i;i;i[; iZ; 0; [iXii[o; ;i;iZ;i; i[; 0; [ixii\o; ;i;i;i]; i\; 0; [iXii]o; ;i;i\;i; i]; 0; [ixii^o; ;i;i;i_; i^; 0; [iXi'i_o; ;i;i^;i; i_; 0; [ixi'i`o; ;i;i;ia; i`; 0; [iXi iao; ;i;i`;i; ia; 0; [ixi ibo; ;i;i;ic; ib; 0; [iYi'ico; ;i;ib;i; ic; 0; [iyi'ido; ;i;i;ie; id; 0; [iYi ieo; ;i;id;i; ie; 0; [iyi ifo; ;i;i;ig; if; 0; 0igo; ;i;if;i; ig; 0; 0iho; ;i;i;ii; ih; 0; [iZiiio; ;i;ih;i; ii; 0; [iziijo; ;i;i;ik; ij; 0; [iZiiko; ;i;ij;i; ik; 0; [iziilo; ;i;i;im; il; 0; [iZiimo; ;i;il;i; im; 0; [iziino; ;i;i;io; in; 0; [iZi ioo; ;i;in;i; io; 0; [izi ipo; ;i;i;iq; ip; 0; [iZi iqo; ;i;ip;i; iq; 0; [izi iro; ;i;i;is; ir; 0; [iZi(iso; ;i;ir;i; is; 0; [izi(ito; ;i;i;iu; it; 0; [i\iiuo; ;i;it;i; iu; 0; [i|iivo; ;i;i;iw; iv; 0; [i^iiwo; ;i;iv;i; iw; 0; [i~iixo; ;i;i;i; ix; 0; [i^iiyo; ;i;i;iz; iy; 0; [i_iizo; ;i;iy;i; iz; 0; [iii{o; ;i;i;i|; i{; 0; [i_ii|o; ;i;i{;i; i|; 0; [iii}o; ;i;i;i~; i}; 0; [i_i i~o; ;i;i};i; i~; 0; [ii io; ;i;iX;i; i; I" compat; T; [ixio; ;i;iC;i; i; 0; 0io; ;i;i;iS; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;iT; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;iV; i; 0; 0io; ;i;i;iW; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;iY; i; 0; 0io; ;i;i;i[; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i`; i; 0; 0io; ;i;i;ic; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;ii; i; 0; 0io; ;i;i;ih; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i=;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;io; i; 0; 0io; ;i;i;ir; i; 0; 0io; ;i;i ;i; i; 0; 0io; ;i;i;iu; i; 0; 0io; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iIi}io; ;i;i;i; i; I" compat; T; [iIi~io; ;i;i;i; i; I" compat; T; [iii~io; ;i;i;i; i; I" compat; T; [iQiOio; ;i;i;i; i; I" compat; T; [iQioio; ;i;i;i; i; I" compat; T; [iqioio; ;i;i;i; i; I" compat; T; [iSiOio; ;i;i;i; i; I" compat; T; [iSioio; ;i;i;i; i; I" compat; T; [isioio; ;i;i;i; i; 0; [iFi io; ;i;i;i; i; 0; [ifi io; ;i;i;i; i; 0; [iNi io; ;i;i;i; i; 0; [ini io; ;i;i;i; i; 0; [iTi io; ;i;i;i; i; 0; [iti io; ;i;i;i; i; 0; [iZi io; ;i;i;i; i; 0; [izi io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i&iio; ;i;i;i; i; 0; [i'iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iLi io; ;i;i;i; i; 0; [ili io; ;i;i;i; i; 0; [iPi io; ;i;i;i; i; 0; [ipi io; ;i;i;i; i; 0; [iTi(io; ;i;i;i; i; 0; [iti(io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ioi io; ;i;i;i; i; I" compat; T; [iIi_io; ;i;i;i; i; I" compat; T; [iIiio; ;i;i;i; i; I" compat; T; [iiiio; ;i;i;i; i; 0; [iLiio; ;i;i;i; i; 0; [iliio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iSiio; ;i;i;i; i; 0; [isiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [iFiio; ;i;i;i; i; 0; [ifiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i ; i; 0; [iNii o; ;i;i;i; i ; 0; [inii o; ;i;i;i ; i ; 0; [iNii o; ;i;i ;i; i ; 0; [inii o; ;i;i;i ; i ; 0; [iTii o; ;i;i ;i; i ; 0; [itiio; ;i;i;i; i; 0; [iTiio; ;i;i;i; i; 0; [itiio; ;i;i;i; i; 0; [iWiio; ;i;i;i; i; 0; [iwiio; ;i;i;i; i; 0; [iWiio; ;i;i;i; i; 0; [iwiio; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [iZiio; ;i;i;i; i; 0; [iziio; ;i;i;i; i; 0; [iXi&io; ;i;i;i; i; 0; [ixi&io; ;i;i;i; i; 0; [iYi&io; ;i;i;i; i; 0; [iyi&io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iMi io; ;i;i;i; i; 0; [imi i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i#; i"; 0; 0i#o; ;i;i";i; i#; 0; 0i$o; ;i;i;i%; i$; 0; 0i%o; ;i;i$;i; i%; 0; 0i&o; ;i;i;i'; i&; 0; [iFii'o; ;i;i&;i; i'; 0; [ifii(o; ;i;i;i); i(; 0; [iJi'i)o; ;i;i(;i; i); 0; [iji'i*o; ;i;i;i+; i*; 0; [iii+o; ;i;i*;i; i+; 0; [iii,o; ;i;i;i-; i,; 0; [iii-o; ;i;i,;i; i-; 0; [iii.o; ;i;i;i/; i.; 0; [iTii/o; ;i;i.;i; i/; 0; [itii0o; ;i;i;i1; i0; 0; [i.ii1o; ;i;i0;i; i1; 0; [i/ii2o; ;i;i;i3; i2; 0; [i^ii3o; ;i;i2;i; i3; 0; [i~ii4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;ie,; i:; 0; 0i;o; ;i;i;i<; i;; 0; 0i<o; ;i;i;;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;if,; i>; 0; 0i?o; ;i;i~,;i; i?; 0; 0i@o; ;i;i,;i; i@; 0; 0iAo; ;i;i;iB; iA; 0; 0iBo; ;i;iA;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;iG; iF; 0; 0iGo; ;i;iF;i; iG; 0; 0iHo; ;i;i;iI; iH; 0; 0iIo; ;i;iH;i; iI; 0; 0iJo; ;i;i;iK; iJ; 0; 0iKo; ;i;iJ;i; iK; 0; 0iLo; ;i;i;iM; iL; 0; 0iMo; ;i;iL;i; iM; 0; 0iNo; ;i;i;iO; iN; 0; 0iOo; ;i;iN;i; iO; 0; 0iPo; ;i;io,;i; iP; 0; 0iQo; ;i;im,;i; iQ; 0; 0iRo; ;i;ip,;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;ib,;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;in,;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;id,;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;iD;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;iE;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [imio; ;i;i;i; i; I" super; T; [ifio; ;i;i;i; i; I" super; T; [ioio; ;i;i;i; i; I" super; T; [iwio; ;i;i;i; i; I" super; T; [iyio; ;i;i;i; i; I" super; T; [i{io; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [i|io; ;i;i;i; i; I" super; T; [i~io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; I" compat; T; [i%i io; ;i;i;i; i; I" compat; T; [i%i(io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; I" compat; T; [i%i io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [icio; ;i;i;i; i; I" super; T; [iqio; ;i;i;i; i; I" super; T; [ixio; ;i;i;i; i; I" super; T; [i}io; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; [iiAo; ;i;i;i; iA; 0; [iiBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; [iiDo; ;i;i;i; iD; 0; [iiiEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;iq; ip; 0; 0iqo; ;i;ip;i; iq; 0; 0iro; ;i;i;is; ir; 0; 0iso; ;i;ir;i; is; 0; 0ito; ;i;i;i; it; 0; [iiuo; ;i;i;i; iu; 0; 0ivo; ;i;i;iw; iv; 0; 0iwo; ;i;iv;i; iw; 0; 0izo; ;i;i;i; iz; I" compat; T; [i%iEi{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; [i@io; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i{; i; 0; 0io; ;i;i;i|; i; 0; 0io; ;i;i;i}; i; 0; 0io; ;i;i;iP; i; 0; [iiio; ;i;i;iQ; i; 0; [iiio; ;i;i;iR; i; 0; 0io; ;i;i;iS; i; 0; [iiio; ;i;i;iT; i; 0; 0io; ;i;i;iU; i; 0; 0io; ;i;i;iV; i; 0; 0io; ;i;i;iW; i; 0; [iiio; ;i;i;iX; i; 0; 0i o; ;i;i;iY; i ; 0; 0i o; ;i;i;iZ; i ; 0; 0i o; ;i;i;i[; i ; 0; 0i o; ;i;i;i\; i ; 0; [iii o; ;i;i;i]; i ; 0; [iiio; ;i;i;i^; i; 0; [i#iio; ;i;i;i_; i; 0; 0io; ;i;i;i0; i; 0; 0io; ;i;i;i1; i; 0; 0io; ;i;i;i2; i; 0; 0io; ;i;i;i3; i; 0; 0io; ;i;i;i4; i; 0; 0io; ;i;i;i5; i; 0; 0io; ;i;i;i6; i; 0; 0io; ;i;i;i7; i; 0; 0io; ;i;i;i8; i; 0; 0io; ;i;i;i9; i; 0; [iiio; ;i;i;i:; i; 0; 0io; ;i;i;i;; i; 0; 0io; ;i;i;i<; i; 0; 0io; ;i;i;i=; i; 0; 0io; ;i;i;i>; i; 0; 0io; ;i;i;i?; i; 0; 0i o; ;i;i;i@; i ; 0; 0i!o; ;i;i;iA; i!; 0; 0i"o; ;i;i;iB; i"; 0; 0i#o; ;i;i;iC; i#; 0; 0i$o; ;i;i;iD; i$; 0; 0i%o; ;i;i;iE; i%; 0; 0i&o; ;i;i;iF; i&; 0; 0i'o; ;i;i;iG; i'; 0; 0i(o; ;i;i;iH; i(; 0; 0i)o; ;i;i;iI; i); 0; 0i*o; ;i;i;iJ; i*; 0; 0i+o; ;i;i;iK; i+; 0; 0i,o; ;i;i;iL; i,; 0; 0i-o; ;i;i;iM; i-; 0; 0i.o; ;i;i;iN; i.; 0; 0i/o; ;i;i;iO; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; [i8ii:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i ;i; i@; 0; 0iAo; ;i;i!;i; iA; 0; 0iBo; ;i;i";i; iB; 0; 0iCo; ;i;i#;i; iC; 0; 0iDo; ;i;i$;i; iD; 0; 0iEo; ;i;i%;i; iE; 0; 0iFo; ;i;i&;i; iF; 0; 0iGo; ;i;i';i; iG; 0; 0iHo; ;i;i(;i; iH; 0; 0iIo; ;i;i);i; iI; 0; 0iJo; ;i;i*;i; iJ; 0; 0iKo; ;i;i+;i; iK; 0; 0iLo; ;i;i,;i; iL; 0; 0iMo; ;i;i-;i; iM; 0; 0iNo; ;i;i.;i; iN; 0; 0iOo; ;i;i/;i; iO; 0; 0iPo; ;i;i;i; iP; 0; [i5iiQo; ;i;i;i; iQ; 0; [i5iiRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; [i3iiTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; [iViiXo; ;i;i;i; iX; 0; 0iYo; ;i;i ;i; iY; 0; 0iZo; ;i;i ;i; iZ; 0; 0i[o; ;i;i ;i; i[; 0; 0i\o; ;i;i ;i; i\; 0; [i:ii]o; ;i;i ;i; i]; 0; [i8ii^o; ;i;i;i; i^; 0; [iCii_o; ;i;i;i; i_; 0; 0i`o; ;i;i;ia; i`; 0; 0iao; ;i;i`;i; ia; 0; 0ibo; ;i;i;ic; ib; 0; 0ico; ;i;ib;i; ic; 0; 0ido; ;i;i;ie; id; 0; 0ieo; ;i;id;i; ie; 0; 0ifo; ;i;i;ig; if; 0; 0igo; ;i;if;i; ig; 0; 0iho; ;i;i;ii; ih; 0; 0iio; ;i;ih;i; ii; 0; 0ijo; ;i;i;ik; ij; 0; 0iko; ;i;ij;i; ik; 0; 0ilo; ;i;i;im; il; 0; 0imo; ;i;il;i; im; 0; 0ino; ;i;i;io; in; 0; 0ioo; ;i;in;i; io; 0; 0ipo; ;i;i;iq; ip; 0; 0iqo; ;i;ip;i; iq; 0; 0iro; ;i;i;is; ir; 0; 0iso; ;i;ir;i; is; 0; 0ito; ;i;i;iu; it; 0; 0iuo; ;i;it;i; iu; 0; 0ivo; ;i;i;iw; iv; 0; [itiiwo; ;i;iv;i; iw; 0; [iuiixo; ;i;i;iy; ix; 0; 0iyo; ;i;ix;i; iy; 0; 0izo; ;i;i;i{; iz; 0; 0i{o; ;i;iz;i; i{; 0; 0i|o; ;i;i;i}; i|; 0; 0i}o; ;i;i|;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i~;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i6iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i0iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i0iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i5iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i6iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i7iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i8iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i8iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i>iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i-iio; ;i;i;i; i; 0; [iMiio; ;i;i;i; i; 0; [i#iio; ;i;i;i; i; 0; [iCiio; ;i;i;i; i; 0; [i#iio; ;i;i;i; i; 0; [iCiio; ;i;i;i; i; 0; [i#i io; ;i;i;i; i; 0; [iCi io; ;i;i;i; i; 0; [i'iio; ;i;i;i; i; 0; [iGiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [i+iio; ;i;i;i; i; 0; [iKiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i ; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i ; i ; 0; 0i o; ;i;i ;i; i ; 0; 0i o; ;i;i;i ; i ; 0; 0i o; ;i;i ;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i!; i ; 0; 0i!o; ;i;i ;i; i!; 0; 0i"o; ;i;i;i#; i"; 0; 0i#o; ;i;i";i; i#; 0; 0i$o; ;i;i;i%; i$; 0; 0i%o; ;i;i$;i; i%; 0; 0i&o; ;i;i;i'; i&; 0; 0i'o; ;i;i&;i; i'; 0; 0i1o; ;i;i;ia; i1; 0; 0i2o; ;i;i;ib; i2; 0; 0i3o; ;i;i;ic; i3; 0; 0i4o; ;i;i;id; i4; 0; 0i5o; ;i;i;ie; i5; 0; 0i6o; ;i;i;if; i6; 0; 0i7o; ;i;i;ig; i7; 0; 0i8o; ;i;i;ih; i8; 0; 0i9o; ;i;i;ii; i9; 0; 0i:o; ;i;i;ij; i:; 0; 0i;o; ;i;i;ik; i;; 0; 0i<o; ;i;i;il; i<; 0; 0i=o; ;i;i;im; i=; 0; 0i>o; ;i;i;in; i>; 0; 0i?o; ;i;i;io; i?; 0; 0i@o; ;i;i;ip; i@; 0; 0iAo; ;i;i;iq; iA; 0; 0iBo; ;i;i;ir; iB; 0; 0iCo; ;i;i;is; iC; 0; 0iDo; ;i;i;it; iD; 0; 0iEo; ;i;i;iu; iE; 0; 0iFo; ;i;i;iv; iF; 0; 0iGo; ;i;i;iw; iG; 0; 0iHo; ;i;i;ix; iH; 0; 0iIo; ;i;i;iy; iI; 0; 0iJo; ;i;i;iz; iJ; 0; 0iKo; ;i;i;i{; iK; 0; 0iLo; ;i;i;i|; iL; 0; 0iMo; ;i;i;i}; iM; 0; 0iNo; ;i;i;i~; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0iao; ;i;i1;i; ia; 0; 0ibo; ;i;i2;i; ib; 0; 0ico; ;i;i3;i; ic; 0; 0ido; ;i;i4;i; id; 0; 0ieo; ;i;i5;i; ie; 0; 0ifo; ;i;i6;i; if; 0; 0igo; ;i;i7;i; ig; 0; 0iho; ;i;i8;i; ih; 0; 0iio; ;i;i9;i; ii; 0; 0ijo; ;i;i:;i; ij; 0; 0iko; ;i;i;;i; ik; 0; 0ilo; ;i;i<;i; il; 0; 0imo; ;i;i=;i; im; 0; 0ino; ;i;i>;i; in; 0; 0ioo; ;i;i?;i; io; 0; 0ipo; ;i;i@;i; ip; 0; 0iqo; ;i;iA;i; iq; 0; 0iro; ;i;iB;i; ir; 0; 0iso; ;i;iC;i; is; 0; 0ito; ;i;iD;i; it; 0; 0iuo; ;i;iE;i; iu; 0; 0ivo; ;i;iF;i; iv; 0; 0iwo; ;i;iG;i; iw; 0; 0ixo; ;i;iH;i; ix; 0; 0iyo; ;i;iI;i; iy; 0; 0izo; ;i;iJ;i; iz; 0; 0i{o; ;i;iK;i; i{; 0; 0i|o; ;i;iL;i; i|; 0; 0i}o; ;i;iM;i; i}; 0; 0i~o; ;i;iN;i; i~; 0; 0io; ;i;iO;i; i; 0; 0io; ;i;iP;i; i; 0; 0io; ;i;iQ;i; i; 0; 0io; ;i;iR;i; i; 0; 0io; ;i;iS;i; i; 0; 0io; ;i;iT;i; i; 0; 0io; ;i;iU;i; i; 0; 0io; ;i;iV;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [ieiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i#;i;i; i; 0; 0io; ;i$;i;i; i; 0; 0io; ;i%;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; [i'iSi#o; ;i;i;i; i#; 0; [i'iTi$o; ;i;i;i; i$; 0; [iHiTi%o; ;i;i;i; i%; 0; [i'iUi&o; ;i;i;i; i&; 0; [iJiTi'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i ;i;i; iK; 0; 0iLo; ;i!;i;i; iL; 0; 0iMo; ;i";i;i; iM; 0; 0iNo; ;i#;i;i; iN; 0; 0iOo; ;i$;i;i; iO; 0; 0iPo; ;i%;i;i; iP; 0; 0iQo; ;i&;i;i; iQ; 0; 0iRo; ;i';i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i(;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; I" compat; T; [i'itivo; ;i;i;i; iv; I" compat; T; [iHitiwo; ;i;i;i; iw; I" compat; T; [iitixo; ;i;i;i; ix; I" compat; T; [iJitiyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiTio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiTio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiTio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i);i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i^o; ;i;i;i; i^; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i ;i;i; i; 0; 0io; ;i!;i;i; i; 0; 0io; ;i";i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; [i( i< i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; [i0 i< i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; [i3 i< i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i; o; ;i;i;i; i; ; 0; 0i< o; ;i ;i;i; i< ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0iI o; ;i;i;i; iI ; 0; 0iJ o; ;i;i;i; iJ ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iN o; ;i;i;i; iN ; 0; 0iO o; ;i;i;i; iO ; 0; 0iP o; ;i;i;i; iP ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iR o; ;i;i;i; iR ; 0; 0iS o; ;i;i;i; iS ; 0; 0iT o; ;i;i;i; iT ; 0; 0iU o; ;i;i;i; iU ; 0; 0iV o; ;i;i;i; iV ; 0; 0iW o; ;i;i;i; iW ; 0; 0iX o; ;i;i;i; iX ; 0; [i i< iY o; ;i;i;i; iY ; 0; [i i< iZ o; ;i;i;i; iZ ; 0; [i i< i[ o; ;i;i;i; i[ ; 0; [i i< i\ o; ;i;i;i; i\ ; 0; [i! i< i] o; ;i;i;i; i] ; 0; [i" i< i^ o; ;i;i;i; i^ ; 0; [i+ i< i_ o; ;i;i;i; i_ ; 0; [i/ i< i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0id o; ;i;i;i; id ; 0; 0ie o; ;i;i;i; ie ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0iv o; ;i;i;i; iv ; 0; 0iw o; ;i;i;i; iw ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i ;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; [i2 i< i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; [i8 i< i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i< o; ;i ;i;i; i< ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iY o; ;i;i;i; iY ; 0; [i i< iZ o; ;i;i;i; iZ ; 0; [i i< i[ o; ;i;i;i; i[ ; 0; [i i< i\ o; ;i;i;i; i\ ; 0; 0i^ o; ;i;i;i; i^ ; 0; [i+ i< if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i ;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i< o; ;i ;i;i; i< ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; [iG iV iK o; ;i;i;i; iK ; 0; [iG i> iL o; ;i;i;i; iL ; 0; [iG iW iM o; ;i;i;i; iM ; 0; 0iV o; ;i;i;i; iV ; 0; 0iW o; ;i;i;i; iW ; 0; 0i\ o; ;i;i;i; i\ ; 0; [i! i< i] o; ;i;i;i; i] ; 0; [i" i< i_ o; ;i;i;i; i_ ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0iv o; ;i;i;i; iv ; 0; 0iw o; ;i;i;i; iw ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; [iF iV iJ o; ;i;i;i; iJ ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iU o; ;iY;i;i; iU ; 0; 0iV o; ;i`;i;i; iV ; 0; 0iX o; ;i;i;i; iX ; 0; 0iY o; ;i;i;i; iY ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ix o; ;i;i;i; ix ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i ;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0iJ o; ;i;i;i; iJ ; 0; [iF i> iK o; ;i;i;i; iK ; 0; [iG i> iL o; ;i;i;i; iL ; 0; [iF iW iM o; ;i;i;i; iM ; 0; 0iN o; ;i;i;i; iN ; 0; 0iW o; ;i;i;i; iW ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; [i i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; I" compat; T; [iMi2i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;il;i;i; i8; 0; 0i9o; ;il;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;ip;i;i; iH; 0; 0iIo; ;ip;i;i; iI; 0; 0iJo; ;ip;i;i; iJ; 0; 0iKo; ;ip;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i{;i;i; i; 0; 0io; ;i{;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [iiio; ;i;i;i; i; I" compat; T; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; I" noBreak; T; [i i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; [iBiiDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; [iLiiNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; [iQiiSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; [iViiXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; [i[ii]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; [i@iijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; [iqirito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; [iqitivo; ;i;i;i; iv; 0; [iiiwo; ;i;i;i; iw; I" compat; T; [iiixo; ;i;i;i; ix; 0; [iiiyo; ;i;i;i; iy; I" compat; T; [iiizo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iqiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; [i%i.i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i ;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i -; i; 0; 0io; ;i;i;i!-; i; 0; 0io; ;i;i;i"-; i; 0; 0io; ;i;i;i#-; i; 0; 0io; ;i;i;i$-; i; 0; 0io; ;i;i;i%-; i; 0; 0io; ;i;i;i'-; i; 0; 0io; ;i;i;i--; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iXo; ;i;i;i; iX; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i@o; ;i;i;i; i@; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [ii5io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [ii5i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i5i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; [i i5i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; [i i5io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [ii5io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i ;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; [i:i5i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; [i<i5i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; [i>i5iAo; ;i;i;i; iA; 0; [i?i5iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; [iBi5iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i ;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i ;i;i; i7; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; I" super; T; [iFi-o; ;i;i;i; i-; I" super; T; [ii.o; ;i;i;i; i.; I" super; T; [iGi/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; I" super; T; [iIi1o; ;i;i;i; i1; I" super; T; [iJi2o; ;i;i;i; i2; I" super; T; [ii3o; ;i;i;i; i3; I" super; T; [iLi4o; ;i;i;i; i4; I" super; T; [iMi5o; ;i;i;i; i5; I" super; T; [iNi6o; ;i;i;i; i6; I" super; T; [iOi7o; ;i;i;i; i7; I" super; T; [iPi8o; ;i;i;i; i8; I" super; T; [iQi9o; ;i;i;i; i9; I" super; T; [iRi:o; ;i;i;i; i:; I" super; T; [iSi;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; I" super; T; [iTi=o; ;i;i;i; i=; I" super; T; [i"i>o; ;i;i;i; i>; I" super; T; [iUi?o; ;i;i;i; i?; I" super; T; [iWi@o; ;i;i;i; i@; I" super; T; [iYiAo; ;i;i;i; iA; I" super; T; [iZiBo; ;i;i;i; iB; I" super; T; [i\iCo; ;i;i;i; iC; I" super; T; [ifiDo; ;i;i;i; iD; I" super; T; [iPiEo; ;i;i;i; iE; I" super; T; [iQiFo; ;i;i;i; iF; I" super; T; [iiGo; ;i;i;i; iG; I" super; T; [igiHo; ;i;i;i; iH; I" super; T; [iiiIo; ;i;i;i; iI; I" super; T; [ijiJo; ;i;i;i; iJ; I" super; T; [iYiKo; ;i;i;i; iK; I" super; T; [i[iLo; ;i;i;i; iL; I" super; T; [i\iMo; ;i;i;i; iM; I" super; T; [iliNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; I" super; T; [ipiPo; ;i;i;i; iP; I" super; T; [iriQo; ;i;i;i; iQ; I" super; T; [iKiRo; ;i;i;i; iR; I" super; T; [itiSo; ;i;i;i; iS; I" super; T; [iTiTo; ;i;i;i; iT; I" super; T; [iiUo; ;i;i;i; iU; I" super; T; [iiVo; ;i;i;i; iV; I" super; T; [iuiWo; ;i;i;i; iW; I" super; T; [iyiXo; ;i;i;i; iX; I" super; T; [iziYo; ;i;i;i; iY; I" super; T; [iiZo; ;i;i;i; iZ; I" super; T; [ioi[o; ;i;i;i; i[; I" super; T; [i{i\o; ;i;i;i; i\; I" super; T; [i%i]o; ;i;i;i; i]; I" super; T; [ii^o; ;i;i;i; i^; I" super; T; [ii_o; ;i;i;i; i_; I" super; T; [ii`o; ;i;i;i; i`; I" super; T; [iiao; ;i;i;i; ia; I" super; T; [iibo; ;i;i;i; ib; I"sub; T; [inico; ;i;i;i; ic; I"sub; T; [iwido; ;i;i;i; id; I"sub; T; [izieo; ;i;i;i; ie; I"sub; T; [i{ifo; ;i;i;i; if; I"sub; T; [iigo; ;i;i;i; ig; I"sub; T; [iiho; ;i;i;i; ih; I"sub; T; [iiio; ;i;i;i; ii; I"sub; T; [iijo; ;i;i;i; ij; I"sub; T; [iiko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; I" super; T; [i=iyo; ;i;i};i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;ic,;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" super; T; [iRio; ;i;i;i; i; I" super; T; [ihio; ;i;i;i; i; I" super; T; [iUio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [i\io; ;i;i;i; i; I" super; T; [ikio; ;i;i;i; i; I" super; T; [i_io; ;i;i;i; i; I" super; T; [iaio; ;i;i;i; i; I" super; T; [ieio; ;i;i;i; i; I" super; T; [ihio; ;i;i;i; i; I" super; T; [iiio; ;i;i;i; i; I" super; T; [ijio; ;i;i;i; i; I" super; T; [i{io; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [imio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iqio; ;i;i;i; i; I" super; T; [ipio; ;i;i;i; i; I" super; T; [irio; ;i;i;i; i; I" super; T; [isio; ;i;i;i; i; I" super; T; [itio; ;i;i;i; i; I" super; T; [iuio; ;i;i;i; i; I" super; T; [ixio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; I" super; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iFi%io; ;i;i;i; i; 0; [ifi%io; ;i;i;i; i; 0; [iGiio; ;i;i;i; i; 0; [igiio; ;i;i;i; i; 0; [iGi#io; ;i;i;i; i; 0; [igi#io; ;i;i;i; i; 0; [iGi1io; ;i;i;i; i; 0; [igi1io; ;i;i;i ; i; 0; [iii o; ;i;i;i; i ; 0; [iii o; ;i;i;i ; i ; 0; [iIii o; ;i;i ;i; i ; 0; [iiii o; ;i;i;i ; i ; 0; [iIi#i o; ;i;i ;i; i ; 0; [iii#io; ;i;i;i; i; 0; [iIi1io; ;i;i;i; i; 0; [iii1io; ;i;i;i; i; 0; [iIi'io; ;i;i;i; i; 0; [iii'io; ;i;i;i; i; 0; [iIi-io; ;i;i;i; i; 0; [iii-io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iJi-io; ;i;i;i; i; 0; [iji-io; ;i;i;i; i; 0; [iJi0io; ;i;i;i; i; 0; [iji0io; ;i;i;i; i; 0; [i(iio; ;i;i;i; i; 0; [i)iio; ;i;i;i; i; 0; [iKiio; ;i;i;i; i; 0; [ikii o; ;i;i;i!; i ; 0; [iLii!o; ;i;i ;i; i!; 0; [ilii"o; ;i;i;i#; i"; 0; [iMii#o; ;i;i";i; i#; 0; [imii$o; ;i;i;i%; i$; 0; [iMi#i%o; ;i;i$;i; i%; 0; [imi#i&o; ;i;i;i'; i&; 0; [iMii'o; ;i;i&;i; i'; 0; [imii(o; ;i;i;i); i(; 0; [iMi'i)o; ;i;i(;i; i); 0; [imi'i*o; ;i;i;i+; i*; 0; [iMi.i+o; ;i;i*;i; i+; 0; [imi.i,o; ;i;i;i-; i,; 0; [iNi0i-o; ;i;i,;i; i-; 0; [ini0i.o; ;i;i;i/; i.; 0; [iii/o; ;i;i.;i; i/; 0; [iii0o; ;i;i;i1; i0; 0; [iPii1o; ;i;i0;i; i1; 0; [ipii2o; ;i;i;i3; i2; 0; [iPi#i3o; ;i;i2;i; i3; 0; [ipi#i4o; ;i;i;i5; i4; 0; [iPi1i5o; ;i;i4;i; i5; 0; [ipi1i6o; ;i;i;i7; i6; 0; [iQi#i7o; ;i;i6;i; i7; 0; [iqi#i8o; ;i;i;i9; i8; 0; [i6ii9o; ;i;i8;i; i9; 0; [i7ii:o; ;i;i;i;; i:; 0; [iQi1i;o; ;i;i:;i; i;; 0; [iqi1i<o; ;i;i;i=; i<; 0; [iQi-i=o; ;i;i<;i; i=; 0; [iqi-i>o; ;i;i;i?; i>; 0; [iRii?o; ;i;i>;i; i?; 0; [irii@o; ;i;i;iA; i@; 0; [iRiiAo; ;i;i@;i; iA; 0; [iriiBo; ;i;i;iC; iB; 0; [iRi#iCo; ;i;iB;i; iC; 0; [iri#iDo; ;i;i;iE; iD; 0; [iSiiEo; ;i;iD;i; iE; 0; [isiiFo; ;i;i;iG; iF; 0; [iSi#iGo; ;i;iF;i; iG; 0; [isi#iHo; ;i;i;iI; iH; 0; [iSi1iIo; ;i;iH;i; iI; 0; [isi1iJo; ;i;i;iK; iJ; 0; [iSi-iKo; ;i;iJ;i; iK; 0; [isi-iLo; ;i;i;iM; iL; 0; [iiiMo; ;i;iL;i; iM; 0; [iiiNo; ;i;i;iO; iN; 0; [iiiOo; ;i;iN;i; iO; 0; [iiiPo; ;i;i;iQ; iP; 0; [iLiiQo; ;i;iP;i; iQ; 0; [iMiiRo; ;i;i;iS; iR; 0; [iLiiSo; ;i;iR;i; iS; 0; [iMiiTo; ;i;i;iU; iT; 0; [iUiiUo; ;i;iT;i; iU; 0; [iuiiVo; ;i;i;iW; iV; 0; [iUiiWo; ;i;iV;i; iW; 0; [iuiiXo; ;i;i;iY; iX; 0; [iWiiYo; ;i;iX;i; iY; 0; [iwiiZo; ;i;i;i[; iZ; 0; [iWi#i[o; ;i;iZ;i; i[; 0; [iwi#i\o; ;i;i;i]; i\; 0; [iZii]o; ;i;i\;i; i]; 0; [i[ii^o; ;i;i;i_; i^; 0; [iWi1i_o; ;i;i^;i; i_; 0; [iwi1i`o; ;i;i;ia; i`; 0; [iXiiao; ;i;i`;i; ia; 0; [ixiibo; ;i;i;ic; ib; 0; [iXi#ico; ;i;ib;i; ic; 0; [ixi#ido; ;i;i;ie; id; 0; [iZiieo; ;i;id;i; ie; 0; [i[iifo; ;i;i;ig; if; 0; [i`iigo; ;i;if;i; ig; 0; [iaiiho; ;i;i;ii; ih; 0; [ibiiio; ;i;ih;i; ii; 0; [iciijo; ;i;i;ik; ij; 0; [iYiiko; ;i;ij;i; ik; 0; [iyiilo; ;i;i;im; il; 0; [iYi#imo; ;i;il;i; im; 0; [iyi#ino; ;i;i;io; in; 0; [iYi1ioo; ;i;in;i; io; 0; [iyi1ipo; ;i;i;iq; ip; 0; [iYi-iqo; ;i;ip;i; iq; 0; [iyi-iro; ;i;i;is; ir; 0; [iZi$iso; ;i;ir;i; is; 0; [izi$ito; ;i;i;iu; it; 0; [iZi0iuo; ;i;it;i; iu; 0; [izi0ivo; ;i;i;iw; iv; 0; [iZi-iwo; ;i;iv;i; iw; 0; [izi-ixo; ;i;i;iy; ix; 0; [ihiiyo; ;i;ix;i; iy; 0; [iiiizo; ;i;i;i{; iz; 0; [ijii{o; ;i;iz;i; i{; 0; [ikii|o; ;i;i;i}; i|; 0; [i[ii}o; ;i;i|;i; i}; 0; [i{ii~o; ;i;i;i; i~; 0; [i[i#io; ;i;i~;i; i; 0; [i{i#io; ;i;i;i; i; 0; [i\iio; ;i;i;i; i; 0; [i|iio; ;i;i;i; i; 0; [i\iio; ;i;i;i; i; 0; [i|iio; ;i;i;i; i; 0; [i\iio; ;i;i;i; i; 0; [i|iio; ;i;i;i; i; 0; [i\iio; ;i;i;i; i; 0; [i|iio; ;i;i;i; i; 0; [i\i#io; ;i;i;i; i; 0; [i|i#io; ;i;i;i; i; 0; [i]iio; ;i;i;i; i; 0; [i}iio; ;i;i;i; i; 0; [i]iio; ;i;i;i; i; 0; [i}iio; ;i;i;i; i; 0; [i^iio; ;i;i;i; i; 0; [i~iio; ;i;i;i; i; 0; [i_iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i_i#io; ;i;i;i; i; 0; [ii#io; ;i;i;i; i; 0; [i_i1io; ;i;i;i; i; 0; [ii1io; ;i;i;i; i; 0; [imi1io; ;i;i;i; i; 0; [iyiio; ;i;i;i; i; 0; [i|i io; ;i;i;i; i; 0; [i~i io; ;i;i;i; i; I" compat; T; [ifiio; ;i;i`;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iFi#io; ;i;i;i; i; 0; [ifi#io; ;i;i;i; i; 0; [iFi io; ;i;i;i; i; 0; [ifi io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iJi#io; ;i;i;i; i; 0; [iji#io; ;i;i;i; i; 0; [iJi io; ;i;i;i; i; 0; [iji io; ;i;i;i; i; 0; [iJiio; ;i;i;i; i; 0; [ijiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iNi io; ;i;i;i; i; 0; [ini io; ;i;i;i; i; 0; [iNi#io; ;i;i;i; i; 0; [ini#io; ;i;i;i; i; 0; [iTi#io; ;i;i;i; i; 0; [iti#io; ;i;i;i; i; 0; [iTi io; ;i;i;i; i; 0; [iti io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii#io; ;i;i;i; i; 0; [ii#io; ;i;i;i; i; 0; [iZi#io; ;i;i;i; i; 0; [izi#io; ;i;i;i; i; 0; [iZi io; ;i;i;i; i; 0; [izi io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [ii io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ii#io; ;i;i;i; i; 0; [ii#io; ;i;i;i; i; 0; [i^iio; ;i;i;i; i; 0; [i~iio; ;i;i;i; i; 0; [i^i#io; ;i;i;i; i; 0; [i~i#io; ;i;i;i; i; 0; [i^i io; ;i;i;i; i; 0; [i~i io; ;i;i;i; i; 0; [i^iio; ;i;i;i; i; 0; [i~iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i ;i; i; 0; [iiio; ;i;i ;i; i; 0; [iiio; ;i;i ;i; i; 0; [iiio; ;i;i ;i; i; 0; [iiio; ;i;i ;i; i; 0; [iiio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iii o; ;i;i;i; i ; 0; [iii o; ;i;i;i; i ; 0; [iii o; ;i;i;i; i ; 0; [i ii o; ;i;i;i; i ; 0; [iii o; ;i;i;i; i ; 0; [i iio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [i iBio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iii o; ;i;i(;i; i ; 0; [iii!o; ;i;i);i; i!; 0; [iii"o; ;i;i*;i; i"; 0; [i ii#o; ;i;i+;i; i#; 0; [i!ii$o; ;i;i,;i; i$; 0; [i ii%o; ;i;i-;i; i%; 0; [i!ii&o; ;i;i.;i; i&; 0; [i iBi'o; ;i;i/;i; i'; 0; [i!iBi(o; ;i;i;i ; i(; 0; [iii)o; ;i;i;i!; i); 0; [iii*o; ;i;i;i"; i*; 0; [i(ii+o; ;i;i;i#; i+; 0; [i)ii,o; ;i;i;i$; i,; 0; [i(ii-o; ;i;i;i%; i-; 0; [i)ii.o; ;i;i;i&; i.; 0; [i(iBi/o; ;i;i;i'; i/; 0; [i)iBi0o; ;i;i8;i; i0; 0; [iii1o; ;i;i9;i; i1; 0; [iii2o; ;i;i:;i; i2; 0; [i0ii3o; ;i;i;;i; i3; 0; [i1ii4o; ;i;i<;i; i4; 0; [i0ii5o; ;i;i=;i; i5; 0; [i1ii6o; ;i;i>;i; i6; 0; [i0iBi7o; ;i;i?;i; i7; 0; [i1iBi8o; ;i;i;i0; i8; 0; [iii9o; ;i;i;i1; i9; 0; [iii:o; ;i;i;i2; i:; 0; [i8ii;o; ;i;i;i3; i;; 0; [i9ii<o; ;i;i;i4; i<; 0; [i8ii=o; ;i;i;i5; i=; 0; [i9ii>o; ;i;i;i6; i>; 0; [i8iBi?o; ;i;i;i7; i?; 0; [i9iBi@o; ;i;iH;i; i@; 0; [iiiAo; ;i;iI;i; iA; 0; [iiiBo; ;i;iJ;i; iB; 0; [i@iiCo; ;i;iK;i; iC; 0; [iAiiDo; ;i;iL;i; iD; 0; [i@iiEo; ;i;iM;i; iE; 0; [iAiiHo; ;i;i;i@; iH; 0; [iiiIo; ;i;i;iA; iI; 0; [iiiJo; ;i;i;iB; iJ; 0; [iHiiKo; ;i;i;iC; iK; 0; [iIiiLo; ;i;i;iD; iL; 0; [iHiiMo; ;i;i;iE; iM; 0; [iIiiPo; ;i;i;i; iP; 0; [iiiQo; ;i;iY;i; iQ; 0; [iiiRo; ;i;i;i; iR; 0; [iPiiSo; ;i;i[;i; iS; 0; [iQiiTo; ;i;i;i; iT; 0; [iPiiUo; ;i;i];i; iU; 0; [iQiiVo; ;i;i;i; iV; 0; [iPiBiWo; ;i;i_;i; iW; 0; [iQiBiYo; ;i;i;iQ; iY; 0; [iii[o; ;i;i;iS; i[; 0; [iYii]o; ;i;i;iU; i]; 0; [iYii_o; ;i;i;iW; i_; 0; [iYiBi`o; ;i;ih;i; i`; 0; [iiiao; ;i;ii;i; ia; 0; [iiibo; ;i;ij;i; ib; 0; [i`iico; ;i;ik;i; ic; 0; [iaiido; ;i;il;i; id; 0; [i`iieo; ;i;im;i; ie; 0; [iaiifo; ;i;in;i; if; 0; [i`iBigo; ;i;io;i; ig; 0; [iaiBiho; ;i;i;i`; ih; 0; [iiiio; ;i;i;ia; ii; 0; [iiijo; ;i;i;ib; ij; 0; [ihiiko; ;i;i;ic; ik; 0; [iiiilo; ;i;i;id; il; 0; [ihiimo; ;i;i;ie; im; 0; [iiiino; ;i;i;if; in; 0; [ihiBioo; ;i;i;ig; io; 0; [iiiBipo; ;i;i;i; ip; 0; [iiiqo; ;i;i;i; iq; 0; [iiro; ;i;i;i; ir; 0; [iiiso; ;i;i;i; is; 0; [iito; ;i;i;i; it; 0; [iiiuo; ;i;i;i; iu; 0; [iivo; ;i;i;i; iv; 0; [iiiwo; ;i;i;i; iw; 0; [iixo; ;i;i;i; ix; 0; [iiiyo; ;i;i;i; iy; 0; [iizo; ;i;i;i; iz; 0; [iii{o; ;i;i;i; i{; 0; [ii|o; ;i;i;i; i|; 0; [iii}o; ;i;i;i; i}; 0; [iio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [i iEio; ;i;i;i; i; 0; [i!iEio; ;i;i;i; i; 0; [i"iEio; ;i;i;i; i; 0; [i#iEio; ;i;i;i; i; 0; [i$iEio; ;i;i;i; i; 0; [i%iEio; ;i;i;i; i; 0; [i&iEio; ;i;i;i; i; 0; [i'iEio; ;i;i;i; i; 0; [i(iEio; ;i;i;i; i; 0; [i)iEio; ;i;i;i; i; 0; [i*iEio; ;i;i;i; i; 0; [i+iEio; ;i;i;i; i; 0; [i,iEio; ;i;i;i; i; 0; [i-iEio; ;i;i;i; i; 0; [i.iEio; ;i;i;i; i; 0; [i/iEio; ;i;i;i; i; 0; [i`iEio; ;i;i;i; i; 0; [iaiEio; ;i;i;i; i; 0; [ibiEio; ;i;i;i; i; 0; [iciEio; ;i;i;i; i; 0; [idiEio; ;i;i;i; i; 0; [ieiEio; ;i;i;i; i; 0; [ifiEio; ;i;i;i; i; 0; [igiEio; ;i;i;i; i; 0; [ihiEio; ;i;i;i; i; 0; [iiiEio; ;i;i;i; i; 0; [ijiEio; ;i;i;i; i; 0; [ikiEio; ;i;i;i; i; 0; [iliEio; ;i;i;i; i; 0; [imiEio; ;i;i;i; i; 0; [iniEio; ;i;i;i; i; 0; [ioiEio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ipiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;ip; i; 0; [iiio; ;i;i;iq; i; 0; [iio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; I" compat; T; [i%iio; ;i;i;i; i; I" compat; T; [i%iBio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [itiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiEio; ;i;i;ir; i; 0; [iiio; ;i;i;is; i; 0; [iio; ;i;i;it; i; 0; [iiio; ;i;i;iu; i; 0; [iio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;iv; i; 0; [iiio; ;i;i;iw; i; 0; [iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;iz; i; 0; [iiio; ;i;i;i{; i; 0; [iio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ieio; ;i;i;i; i; 0; [i|iEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iiBio; ;i;i;i; i; 0; [iiEio; ;i;i;ix; i; 0; [iiio; ;i;i;iy; i; 0; [iio; ;i;i;i|; i; 0; [iiio; ;i;i;i}; i; 0; [iio; ;i;i;i; i; 0; [iiEio; ;i;i;i; i; 0; [iio; ;i;i;i; i; I" compat; T; [i%ii o; ;i;i;i; i ; 0; [i i o; ;i;i;i; i ; 0; [i i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" noBreak; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; I" compat; T; [i%i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; I" noBreak; T; [i i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; I" compat; T; [i%i3i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; I" compat; T; [i3i% o; ;i;i;i; i% ; I" compat; T; [i3i3i& o; ;i;i;i; i& ; I" compat; T; [i3i3i3i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; I" noBreak; T; [i%i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; I" compat; T; [i2 i2 i4 o; ;i;i;i; i4 ; I" compat; T; [i2 i2 i2 i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; I" compat; T; [i5 i5 i7 o; ;i;i;i; i7 ; I" compat; T; [i5 i5 i5 i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i; o; ;i;i;i; i; ; 0; 0i< o; ;i;i;i; i< ; I" compat; T; [i&i&i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; I" compat; T; [i%ii? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; I" compat; T; [iDiDiH o; ;i;i;i; iH ; I" compat; T; [iDi&iI o; ;i;i;i; iI ; I" compat; T; [i&iDiJ o; ;i;i;i; iJ ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iN o; ;i;i;i; iN ; 0; 0iO o; ;i;i;i; iO ; 0; 0iP o; ;i;i;i; iP ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iR o; ;i;i;i; iR ; 0; 0iS o; ;i;i;i; iS ; 0; 0iT o; ;i;i;i; iT ; 0; 0iU o; ;i;i;i; iU ; 0; 0iV o; ;i;i;i; iV ; 0; 0iW o; ;i;i;i; iW ; I" compat; T; [ i2 i2 i2 i2 iX o; ;i;i;i; iX ; 0; 0iY o; ;i;i;i; iY ; 0; 0iZ o; ;i;i;i; iZ ; 0; 0i[ o; ;i;i;i; i[ ; 0; 0i\ o; ;i;i;i; i\ ; 0; 0i] o; ;i;i;i; i] ; 0; 0i^ o; ;i;i;i; i^ ; 0; 0i_ o; ;i;i;i; i_ ; I" compat; T; [i%i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0id o; ;i;i;i; id ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; I" super; T; [i5iq o; ;i;i;i; iq ; I" super; T; [init o; ;i;i;i; it ; I" super; T; [i9iu o; ;i;i;i; iu ; I" super; T; [i:iv o; ;i;i;i; iv ; I" super; T; [i;iw o; ;i;i;i; iw ; I" super; T; [iiz o; ;i;i;i; iz ; I" super; T; [i0i{ o; ;i;i;i; i{ ; I" super; T; [i"i| o; ;i;i;i; i| ; I" super; T; [iBi} o; ;i;i;i; i} ; I" super; T; [i-i~ o; ;i;i;i; i~ ; I" super; T; [i.i o; ;i;i;i; i ; I" super; T; [isi o; ;i;i;i; i ; I"sub; T; [i5i o; ;i;i;i; i ; I"sub; T; [i6i o; ;i;i;i; i ; I"sub; T; [i7i o; ;i;i;i; i ; I"sub; T; [i8i o; ;i;i;i; i ; I"sub; T; [i9i o; ;i;i;i; i ; I"sub; T; [i:i o; ;i;i;i; i ; I"sub; T; [i;i o; ;i;i;i; i ; I"sub; T; [ii o; ;i;i;i; i ; I"sub; T; [i0i o; ;i;i;i; i ; I"sub; T; [i"i o; ;i;i;i; i ; I"sub; T; [iBi o; ;i;i;i; i ; I"sub; T; [i-i o; ;i;i;i; i ; I"sub; T; [i.i o; ;i;i;i; i ; I"sub; T; [ifi o; ;i;i;i; i ; I"sub; T; [iji o; ;i;i;i; i ; I"sub; T; [iti o; ;i;i;i; i ; I"sub; T; [i}i o; ;i;i;i; i ; I"sub; T; [iYi o; ;i;i;i; i ; I"sub; T; [imi o; ;i;i;i; i ; I"sub; T; [ipi o; ;i;i;i; i ; I"sub; T; [iqi o; ;i;i;i; i ; I"sub; T; [iri o; ;i;i;i; i ; I"sub; T; [isi o; ;i;i;i; i ; I"sub; T; [iui o; ;i;i;i; i ; I"sub; T; [ixi o; ;i;i;i; i ; I"sub; T; [iyi o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; I" compat; T; [iWixi o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; I" compat; T; [ifi4ihi!o; ;i;i;i; i!; I" compat; T; [ifi4ixi!o; ;i;i;i; i!; I" font; T; [iHi!o; ;i;i;i; i!; I" compat; T; [iiHi!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; I" compat; T; [ihi4iti!o; ;i;i;i; i!; I" compat; T; [ihi4izi!o; ;i;i;i; i!; I" compat; T; [ii!o; ;i;i;i; i!; 0; 0i !o; ;i;i;i; i !; I" compat; T; [iiKi !o; ;i;i;i; i !; I" font; T; [ili !o; ;i;i;i; i !; I" font; T; [iMi !o; ;i;i;i; i !; I" font; T; [iMi !o; ;i;i;i; i !; I" font; T; [iMi!o; ;i;i;i; i!; I" font; T; [imi!o; ;i;i;i; i!; I" font; T; [i'i!o; ;i;i;i; i!; I" font; T; [iNi!o; ;i;i;i; i!; I" font; T; [iNi!o; ;i;i;i; i!; I" font; T; [iQi!o; ;i;i;i; i!; I" font; T; [iqi!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; I" font; T; [iSi!o; ;i;i;i; i!; I" compat; T; [iSiti!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; I" font; T; [iUi!o; ;i;i;i; i!; I" font; T; [iVi!o; ;i;i;i; i!; I" font; T; [iWi!o; ;i;i;i; i!; I" font; T; [iWi!o; ;i;i;i; i!; I" font; T; [iWi!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i !o; ;i;i;i; i !; I" super; T; [iXiRi!!o; ;i;i;i; i!!; I" compat; T; [iYiJiQi"!o; ;i;i;i; i"!; I" super; T; [iYiRi#!o; ;i;i;i; i#!; 0; 0i$!o; ;i;i;i; i$!; I" font; T; [i_i%!o; ;i;i;i; i%!; 0; 0i&!o; ;i;i;i; i&!; 0; [ii'!o; ;i;i;i; i'!; 0; 0i(!o; ;i;i;i; i(!; I" font; T; [i_i)!o; ;i;i;i; i)!; 0; 0i*!o; ;i;i;ip; i*!; 0; [iPi+!o; ;i;i;i; i+!; 0; [ii,!o; ;i;i;i; i,!; I" font; T; [iGi-!o; ;i;i;i; i-!; I" font; T; [iHi.!o; ;i;i;i; i.!; 0; 0i/!o; ;i;i;i; i/!; I" font; T; [iji0!o; ;i;i;i; i0!; I" font; T; [iJi1!o; ;i;i;i; i1!; I" font; T; [iKi2!o; ;i;i;iN!; i2!; 0; 0i3!o; ;i;i;i; i3!; I" font; T; [iRi4!o; ;i;i;i; i4!; I" font; T; [iti5!o; ;i;i;i; i5!; I" compat; T; [ii6!o; ;i;i;i; i6!; I" compat; T; [ii7!o; ;i;i;i; i7!; I" compat; T; [ii8!o; ;i;i;i; i8!; I" compat; T; [ii9!o; ;i;i;i; i9!; I" font; T; [ini:!o; ;i;i;i; i:!; 0; 0i;!o; ;i;i;i; i;!; I" compat; T; [iKiFi]i!o; ;i;i;i; i>!; I" font; T; [ii?!o; ;i;i;i; i?!; I" font; T; [ii@!o; ;i;i;i; i@!; I" font; T; [i"iA!o; ;i;i;i; iA!; 0; 0iB!o; ;i;i;i; iB!; 0; 0iC!o; ;i;i;i; iC!; 0; 0iD!o; ;i;i;i; iD!; 0; 0iE!o; ;i;i;i; iE!; I" font; T; [iIiF!o; ;i;i;i; iF!; I" font; T; [iiiG!o; ;i;i;i; iG!; I" font; T; [ijiH!o; ;i;i;i; iH!; I" font; T; [iniI!o; ;i;i;i; iI!; I" font; T; [ioiJ!o; ;i;i;i; iJ!; 0; 0iK!o; ;i;i;i; iK!; 0; 0iL!o; ;i;i;i; iL!; 0; 0iM!o; ;i;i;i; iM!; 0; 0iN!o; ;i;i2!;i; iN!; 0; 0iO!o; ;i;i;i; iO!; 0; 0iP!o; ;i;i;i; iP!; I" fraction; T; [i6iD iiR!o; ;i;i;i; iR!; I" fraction; T; [ i6iD i6i5iS!o; ;i;i;i; iS!; I" fraction; T; [i6iD i8iT!o; ;i;i;i; iT!; I" fraction; T; [i7iD i8iU!o; ;i;i;i; iU!; I" fraction; T; [i6iD i:iV!o; ;i;i;i; iV!; I" fraction; T; [i7iD i:iW!o; ;i;i;i; iW!; I" fraction; T; [i8iD i:iX!o; ;i;i;i; iX!; I" fraction; T; [i9iD i:iY!o; ;i;i;i; iY!; I" fraction; T; [i6iD i;iZ!o; ;i;i;i; iZ!; I" fraction; T; [i:iD i;i[!o; ;i;i;i; i[!; I" fraction; T; [i6iD i=i\!o; ;i;i;i; i\!; I" fraction; T; [i8iD i=i]!o; ;i;i;i; i]!; I" fraction; T; [i:iD i=i^!o; ;i;i;i; i^!; I" fraction; T; [i"o; ;i;i;i; i>"; 0; 0i?"o; ;i;i;i; i?"; 0; 0i@"o; ;i;i;i; i@"; 0; 0iA"o; ;i;i;i; iA"; 0; [i<"i8iB"o; ;i;i;i; iB"; 0; 0iC"o; ;i;i;i; iC"; 0; 0iD"o; ;i;i;i; iD"; 0; [iC"i8iE"o; ;i;i;i; iE"; 0; 0iF"o; ;i;i;i; iF"; 0; 0iG"o; ;i;i;i; iG"; 0; [iE"i8iH"o; ;i;i;i; iH"; 0; 0iI"o; ;i;i;i; iI"; 0; [iH"i8iJ"o; ;i;i;i; iJ"; 0; 0iK"o; ;i;i;i; iK"; 0; 0iL"o; ;i;i;i; iL"; 0; 0iM"o; ;i;i;i; iM"; 0; 0iN"o; ;i;i;i; iN"; 0; 0iO"o; ;i;i;i; iO"; 0; 0iP"o; ;i;i;i; iP"; 0; 0iQ"o; ;i;i;i; iQ"; 0; 0iR"o; ;i;i;i; iR"; 0; 0iS"o; ;i;i;i; iS"; 0; 0iT"o; ;i;i;i; iT"; 0; 0iU"o; ;i;i;i; iU"; 0; 0iV"o; ;i;i;i; iV"; 0; 0iW"o; ;i;i;i; iW"; 0; 0iX"o; ;i;i;i; iX"; 0; 0iY"o; ;i;i;i; iY"; 0; 0iZ"o; ;i;i;i; iZ"; 0; 0i["o; ;i;i;i; i["; 0; 0i\"o; ;i;i;i; i\"; 0; 0i]"o; ;i;i;i; i]"; 0; 0i^"o; ;i;i;i; i^"; 0; 0i_"o; ;i;i;i; i_"; 0; 0i`"o; ;i;i;i; i`"; 0; [iBi8ia"o; ;i;i;i; ia"; 0; 0ib"o; ;i;i;i; ib"; 0; [ia"i8ic"o; ;i;i;i; ic"; 0; 0id"o; ;i;i;i; id"; 0; 0ie"o; ;i;i;i; ie"; 0; 0if"o; ;i;i;i; if"; 0; 0ig"o; ;i;i;i; ig"; 0; 0ih"o; ;i;i;i; ih"; 0; 0ii"o; ;i;i;i; ii"; 0; 0ij"o; ;i;i;i; ij"; 0; 0ik"o; ;i;i;i; ik"; 0; 0il"o; ;i;i;i; il"; 0; 0im"o; ;i;i;i; im"; 0; [iM"i8in"o; ;i;i;i; in"; 0; [iAi8io"o; ;i;i;i; io"; 0; [iCi8ip"o; ;i;i;i; ip"; 0; [id"i8iq"o; ;i;i;i; iq"; 0; [ie"i8ir"o; ;i;i;i; ir"; 0; 0is"o; ;i;i;i; is"; 0; 0it"o; ;i;i;i; it"; 0; [ir"i8iu"o; ;i;i;i; iu"; 0; [is"i8iv"o; ;i;i;i; iv"; 0; 0iw"o; ;i;i;i; iw"; 0; 0ix"o; ;i;i;i; ix"; 0; [iv"i8iy"o; ;i;i;i; iy"; 0; [iw"i8iz"o; ;i;i;i; iz"; 0; 0i{"o; ;i;i;i; i{"; 0; 0i|"o; ;i;i;i; i|"; 0; 0i}"o; ;i;i;i; i}"; 0; 0i~"o; ;i;i;i; i~"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [iz"i8i"o; ;i;i;i; i"; 0; [i{"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [i|"i8i"o; ;i;i;i; i"; 0; [i}"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; [i"i8i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i #o; ;i;i;i; i #; 0; 0i!#o; ;i;i;i; i!#; 0; 0i"#o; ;i;i;i; i"#; 0; 0i##o; ;i;i;i; i##; 0; 0i$#o; ;i;i;i; i$#; 0; 0i%#o; ;i;i;i; i%#; 0; 0i&#o; ;i;i;i; i&#; 0; 0i'#o; ;i;i;i; i'#; 0; 0i(#o; ;i;i;i; i(#; 0; 0i)#o; ;i;i;i; i)#; 0; [i0i*#o; ;i;i;i; i*#; 0; [i 0i+#o; ;i;i;i; i+#; 0; 0i,#o; ;i;i;i; i,#; 0; 0i-#o; ;i;i;i; i-#; 0; 0i.#o; ;i;i;i; i.#; 0; 0i/#o; ;i;i;i; i/#; 0; 0i0#o; ;i;i;i; i0#; 0; 0i1#o; ;i;i;i; i1#; 0; 0i2#o; ;i;i;i; i2#; 0; 0i3#o; ;i;i;i; i3#; 0; 0i4#o; ;i;i;i; i4#; 0; 0i5#o; ;i;i;i; i5#; 0; 0i6#o; ;i;i;i; i6#; 0; 0i7#o; ;i;i;i; i7#; 0; 0i8#o; ;i;i;i; i8#; 0; 0i9#o; ;i;i;i; i9#; 0; 0i:#o; ;i;i;i; i:#; 0; 0i;#o; ;i;i;i; i;#; 0; 0i<#o; ;i;i;i; i<#; 0; 0i=#o; ;i;i;i; i=#; 0; 0i>#o; ;i;i;i; i>#; 0; 0i?#o; ;i;i;i; i?#; 0; 0i@#o; ;i;i;i; i@#; 0; 0iA#o; ;i;i;i; iA#; 0; 0iB#o; ;i;i;i; iB#; 0; 0iC#o; ;i;i;i; iC#; 0; 0iD#o; ;i;i;i; iD#; 0; 0iE#o; ;i;i;i; iE#; 0; 0iF#o; ;i;i;i; iF#; 0; 0iG#o; ;i;i;i; iG#; 0; 0iH#o; ;i;i;i; iH#; 0; 0iI#o; ;i;i;i; iI#; 0; 0iJ#o; ;i;i;i; iJ#; 0; 0iK#o; ;i;i;i; iK#; 0; 0iL#o; ;i;i;i; iL#; 0; 0iM#o; ;i;i;i; iM#; 0; 0iN#o; ;i;i;i; iN#; 0; 0iO#o; ;i;i;i; iO#; 0; 0iP#o; ;i;i;i; iP#; 0; 0iQ#o; ;i;i;i; iQ#; 0; 0iR#o; ;i;i;i; iR#; 0; 0iS#o; ;i;i;i; iS#; 0; 0iT#o; ;i;i;i; iT#; 0; 0iU#o; ;i;i;i; iU#; 0; 0iV#o; ;i;i;i; iV#; 0; 0iW#o; ;i;i;i; iW#; 0; 0iX#o; ;i;i;i; iX#; 0; 0iY#o; ;i;i;i; iY#; 0; 0iZ#o; ;i;i;i; iZ#; 0; 0i[#o; ;i;i;i; i[#; 0; 0i\#o; ;i;i;i; i\#; 0; 0i]#o; ;i;i;i; i]#; 0; 0i^#o; ;i;i;i; i^#; 0; 0i_#o; ;i;i;i; i_#; 0; 0i`#o; ;i;i;i; i`#; 0; 0ia#o; ;i;i;i; ia#; 0; 0ib#o; ;i;i;i; ib#; 0; 0ic#o; ;i;i;i; ic#; 0; 0id#o; ;i;i;i; id#; 0; 0ie#o; ;i;i;i; ie#; 0; 0if#o; ;i;i;i; if#; 0; 0ig#o; ;i;i;i; ig#; 0; 0ih#o; ;i;i;i; ih#; 0; 0ii#o; ;i;i;i; ii#; 0; 0ij#o; ;i;i;i; ij#; 0; 0ik#o; ;i;i;i; ik#; 0; 0il#o; ;i;i;i; il#; 0; 0im#o; ;i;i;i; im#; 0; 0in#o; ;i;i;i; in#; 0; 0io#o; ;i;i;i; io#; 0; 0ip#o; ;i;i;i; ip#; 0; 0iq#o; ;i;i;i; iq#; 0; 0ir#o; ;i;i;i; ir#; 0; 0is#o; ;i;i;i; is#; 0; 0it#o; ;i;i;i; it#; 0; 0iu#o; ;i;i;i; iu#; 0; 0iv#o; ;i;i;i; iv#; 0; 0iw#o; ;i;i;i; iw#; 0; 0ix#o; ;i;i;i; ix#; 0; 0iy#o; ;i;i;i; iy#; 0; 0iz#o; ;i;i;i; iz#; 0; 0i{#o; ;i;i;i; i{#; 0; 0i|#o; ;i;i;i; i|#; 0; 0i}#o; ;i;i;i; i}#; 0; 0i~#o; ;i;i;i; i~#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i $o; ;i;i;i; i $; 0; 0i!$o; ;i;i;i; i!$; 0; 0i"$o; ;i;i;i; i"$; 0; 0i#$o; ;i;i;i; i#$; 0; 0i$$o; ;i;i;i; i$$; 0; 0i%$o; ;i;i;i; i%$; 0; 0i&$o; ;i;i;i; i&$; 0; 0i@$o; ;i;i;i; i@$; 0; 0iA$o; ;i;i;i; iA$; 0; 0iB$o; ;i;i;i; iB$; 0; 0iC$o; ;i;i;i; iC$; 0; 0iD$o; ;i;i;i; iD$; 0; 0iE$o; ;i;i;i; iE$; 0; 0iF$o; ;i;i;i; iF$; 0; 0iG$o; ;i;i;i; iG$; 0; 0iH$o; ;i;i;i; iH$; 0; 0iI$o; ;i;i;i; iI$; 0; 0iJ$o; ;i;i;i; iJ$; 0; 0i`$o; ;i;i;i; i`$; I" circle; T; [i6ia$o; ;i;i;i; ia$; I" circle; T; [i7ib$o; ;i;i;i; ib$; I" circle; T; [i8ic$o; ;i;i;i; ic$; I" circle; T; [i9id$o; ;i;i;i; id$; I" circle; T; [i:ie$o; ;i;i;i; ie$; I" circle; T; [i;if$o; ;i;i;i; if$; I" circle; T; [iii$o; ;i;i;i; ii$; I" circle; T; [i6i5ij$o; ;i;i;i; ij$; I" circle; T; [i6i6ik$o; ;i;i;i; ik$; I" circle; T; [i6i7il$o; ;i;i;i; il$; I" circle; T; [i6i8im$o; ;i;i;i; im$; I" circle; T; [i6i9in$o; ;i;i;i; in$; I" circle; T; [i6i:io$o; ;i;i;i; io$; I" circle; T; [i6i;ip$o; ;i;i;i; ip$; I" circle; T; [i6iis$o; ;i;i;i; is$; I" circle; T; [i7i5it$o; ;i;i;i; it$; I" compat; T; [i-i6i.iu$o; ;i;i;i; iu$; I" compat; T; [i-i7i.iv$o; ;i;i;i; iv$; I" compat; T; [i-i8i.iw$o; ;i;i;i; iw$; I" compat; T; [i-i9i.ix$o; ;i;i;i; ix$; I" compat; T; [i-i:i.iy$o; ;i;i;i; iy$; I" compat; T; [i-i;i.iz$o; ;i;i;i; iz$; I" compat; T; [i-ii.i}$o; ;i;i;i; i}$; I" compat; T; [ i-i6i5i.i~$o; ;i;i;i; i~$; I" compat; T; [ i-i6i6i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6i7i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6i8i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6i9i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6i:i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6i;i.i$o; ;i;i;i; i$; I" compat; T; [ i-i6ii.i$o; ;i;i;i; i$; I" compat; T; [ i-i7i5i.i$o; ;i;i;i; i$; I" compat; T; [i6i3i$o; ;i;i;i; i$; I" compat; T; [i7i3i$o; ;i;i;i; i$; I" compat; T; [i8i3i$o; ;i;i;i; i$; I" compat; T; [i9i3i$o; ;i;i;i; i$; I" compat; T; [i:i3i$o; ;i;i;i; i$; I" compat; T; [i;i3i$o; ;i;i;i; i$; I" compat; T; [ii3i$o; ;i;i;i; i$; I" compat; T; [i6i5i3i$o; ;i;i;i; i$; I" compat; T; [i6i6i3i$o; ;i;i;i; i$; I" compat; T; [i6i7i3i$o; ;i;i;i; i$; I" compat; T; [i6i8i3i$o; ;i;i;i; i$; I" compat; T; [i6i9i3i$o; ;i;i;i; i$; I" compat; T; [i6i:i3i$o; ;i;i;i; i$; I" compat; T; [i6i;i3i$o; ;i;i;i; i$; I" compat; T; [i6ii3i$o; ;i;i;i; i$; I" compat; T; [i7i5i3i$o; ;i;i;i; i$; I" compat; T; [i-ifi.i$o; ;i;i;i; i$; I" compat; T; [i-igi.i$o; ;i;i;i; i$; I" compat; T; [i-ihi.i$o; ;i;i;i; i$; I" compat; T; [i-iii.i$o; ;i;i;i; i$; I" compat; T; [i-iji.i$o; ;i;i;i; i$; I" compat; T; [i-iki.i$o; ;i;i;i; i$; I" compat; T; [i-ili.i$o; ;i;i;i; i$; I" compat; T; [i-imi.i$o; ;i;i;i; i$; I" compat; T; [i-ini.i$o; ;i;i;i; i$; I" compat; T; [i-ioi.i$o; ;i;i;i; i$; I" compat; T; [i-ipi.i$o; ;i;i;i; i$; I" compat; T; [i-iqi.i$o; ;i;i;i; i$; I" compat; T; [i-iri.i$o; ;i;i;i; i$; I" compat; T; [i-isi.i$o; ;i;i;i; i$; I" compat; T; [i-iti.i$o; ;i;i;i; i$; I" compat; T; [i-iui.i$o; ;i;i;i; i$; I" compat; T; [i-ivi.i$o; ;i;i;i; i$; I" compat; T; [i-iwi.i$o; ;i;i;i; i$; I" compat; T; [i-ixi.i$o; ;i;i;i; i$; I" compat; T; [i-iyi.i$o; ;i;i;i; i$; I" compat; T; [i-izi.i$o; ;i;i;i; i$; I" compat; T; [i-i{i.i$o; ;i;i;i; i$; I" compat; T; [i-i|i.i$o; ;i;i;i; i$; I" compat; T; [i-i}i.i$o; ;i;i;i; i$; I" compat; T; [i-i~i.i$o; ;i;i;i; i$; I" compat; T; [i-ii.i$o; ;i;i;i$; i$; I" circle; T; [iFi$o; ;i;i;i$; i$; I" circle; T; [iGi$o; ;i;i;i$; i$; I" circle; T; [iHi$o; ;i;i;i$; i$; I" circle; T; [iIi$o; ;i;i;i$; i$; I" circle; T; [iJi$o; ;i;i;i$; i$; I" circle; T; [iKi$o; ;i;i;i$; i$; I" circle; T; [iLi$o; ;i;i;i$; i$; I" circle; T; [iMi$o; ;i;i;i$; i$; I" circle; T; [iNi$o; ;i;i;i$; i$; I" circle; T; [iOi$o; ;i;i;i$; i$; I" circle; T; [iPi$o; ;i;i;i$; i$; I" circle; T; [iQi$o; ;i;i;i$; i$; I" circle; T; [iRi$o; ;i;i;i$; i$; I" circle; T; [iSi$o; ;i;i;i$; i$; I" circle; T; [iTi$o; ;i;i;i$; i$; I" circle; T; [iUi$o; ;i;i;i$; i$; I" circle; T; [iVi$o; ;i;i;i$; i$; I" circle; T; [iWi$o; ;i;i;i$; i$; I" circle; T; [iXi$o; ;i;i;i$; i$; I" circle; T; [iYi$o; ;i;i;i$; i$; I" circle; T; [iZi$o; ;i;i;i$; i$; I" circle; T; [i[i$o; ;i;i;i$; i$; I" circle; T; [i\i$o; ;i;i;i$; i$; I" circle; T; [i]i$o; ;i;i;i$; i$; I" circle; T; [i^i$o; ;i;i;i$; i$; I" circle; T; [i_i$o; ;i;i$;i; i$; I" circle; T; [ifi$o; ;i;i$;i; i$; I" circle; T; [igi$o; ;i;i$;i; i$; I" circle; T; [ihi$o; ;i;i$;i; i$; I" circle; T; [iii$o; ;i;i$;i; i$; I" circle; T; [iji$o; ;i;i$;i; i$; I" circle; T; [iki$o; ;i;i$;i; i$; I" circle; T; [ili$o; ;i;i$;i; i$; I" circle; T; [imi$o; ;i;i$;i; i$; I" circle; T; [ini$o; ;i;i$;i; i$; I" circle; T; [ioi$o; ;i;i$;i; i$; I" circle; T; [ipi$o; ;i;i$;i; i$; I" circle; T; [iqi$o; ;i;i$;i; i$; I" circle; T; [iri$o; ;i;i$;i; i$; I" circle; T; [isi$o; ;i;i$;i; i$; I" circle; T; [iti$o; ;i;i$;i; i$; I" circle; T; [iui$o; ;i;i$;i; i$; I" circle; T; [ivi$o; ;i;i$;i; i$; I" circle; T; [iwi$o; ;i;i$;i; i$; I" circle; T; [ixi$o; ;i;i$;i; i$; I" circle; T; [iyi$o; ;i;i$;i; i$; I" circle; T; [izi$o; ;i;i$;i; i$; I" circle; T; [i{i$o; ;i;i$;i; i$; I" circle; T; [i|i$o; ;i;i$;i; i$; I" circle; T; [i}i$o; ;i;i$;i; i$; I" circle; T; [i~i$o; ;i;i$;i; i$; I" circle; T; [ii$o; ;i;i;i; i$; I" circle; T; [i5i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i %o; ;i;i;i; i %; 0; 0i %o; ;i;i;i; i %; 0; 0i %o; ;i;i;i; i %; 0; 0i %o; ;i;i;i; i %; 0; 0i %o; ;i;i;i; i %; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i %o; ;i;i;i; i %; 0; 0i!%o; ;i;i;i; i!%; 0; 0i"%o; ;i;i;i; i"%; 0; 0i#%o; ;i;i;i; i#%; 0; 0i$%o; ;i;i;i; i$%; 0; 0i%%o; ;i;i;i; i%%; 0; 0i&%o; ;i;i;i; i&%; 0; 0i'%o; ;i;i;i; i'%; 0; 0i(%o; ;i;i;i; i(%; 0; 0i)%o; ;i;i;i; i)%; 0; 0i*%o; ;i;i;i; i*%; 0; 0i+%o; ;i;i;i; i+%; 0; 0i,%o; ;i;i;i; i,%; 0; 0i-%o; ;i;i;i; i-%; 0; 0i.%o; ;i;i;i; i.%; 0; 0i/%o; ;i;i;i; i/%; 0; 0i0%o; ;i;i;i; i0%; 0; 0i1%o; ;i;i;i; i1%; 0; 0i2%o; ;i;i;i; i2%; 0; 0i3%o; ;i;i;i; i3%; 0; 0i4%o; ;i;i;i; i4%; 0; 0i5%o; ;i;i;i; i5%; 0; 0i6%o; ;i;i;i; i6%; 0; 0i7%o; ;i;i;i; i7%; 0; 0i8%o; ;i;i;i; i8%; 0; 0i9%o; ;i;i;i; i9%; 0; 0i:%o; ;i;i;i; i:%; 0; 0i;%o; ;i;i;i; i;%; 0; 0i<%o; ;i;i;i; i<%; 0; 0i=%o; ;i;i;i; i=%; 0; 0i>%o; ;i;i;i; i>%; 0; 0i?%o; ;i;i;i; i?%; 0; 0i@%o; ;i;i;i; i@%; 0; 0iA%o; ;i;i;i; iA%; 0; 0iB%o; ;i;i;i; iB%; 0; 0iC%o; ;i;i;i; iC%; 0; 0iD%o; ;i;i;i; iD%; 0; 0iE%o; ;i;i;i; iE%; 0; 0iF%o; ;i;i;i; iF%; 0; 0iG%o; ;i;i;i; iG%; 0; 0iH%o; ;i;i;i; iH%; 0; 0iI%o; ;i;i;i; iI%; 0; 0iJ%o; ;i;i;i; iJ%; 0; 0iK%o; ;i;i;i; iK%; 0; 0iL%o; ;i;i;i; iL%; 0; 0iM%o; ;i;i;i; iM%; 0; 0iN%o; ;i;i;i; iN%; 0; 0iO%o; ;i;i;i; iO%; 0; 0iP%o; ;i;i;i; iP%; 0; 0iQ%o; ;i;i;i; iQ%; 0; 0iR%o; ;i;i;i; iR%; 0; 0iS%o; ;i;i;i; iS%; 0; 0iT%o; ;i;i;i; iT%; 0; 0iU%o; ;i;i;i; iU%; 0; 0iV%o; ;i;i;i; iV%; 0; 0iW%o; ;i;i;i; iW%; 0; 0iX%o; ;i;i;i; iX%; 0; 0iY%o; ;i;i;i; iY%; 0; 0iZ%o; ;i;i;i; iZ%; 0; 0i[%o; ;i;i;i; i[%; 0; 0i\%o; ;i;i;i; i\%; 0; 0i]%o; ;i;i;i; i]%; 0; 0i^%o; ;i;i;i; i^%; 0; 0i_%o; ;i;i;i; i_%; 0; 0i`%o; ;i;i;i; i`%; 0; 0ia%o; ;i;i;i; ia%; 0; 0ib%o; ;i;i;i; ib%; 0; 0ic%o; ;i;i;i; ic%; 0; 0id%o; ;i;i;i; id%; 0; 0ie%o; ;i;i;i; ie%; 0; 0if%o; ;i;i;i; if%; 0; 0ig%o; ;i;i;i; ig%; 0; 0ih%o; ;i;i;i; ih%; 0; 0ii%o; ;i;i;i; ii%; 0; 0ij%o; ;i;i;i; ij%; 0; 0ik%o; ;i;i;i; ik%; 0; 0il%o; ;i;i;i; il%; 0; 0im%o; ;i;i;i; im%; 0; 0in%o; ;i;i;i; in%; 0; 0io%o; ;i;i;i; io%; 0; 0ip%o; ;i;i;i; ip%; 0; 0iq%o; ;i;i;i; iq%; 0; 0ir%o; ;i;i;i; ir%; 0; 0is%o; ;i;i;i; is%; 0; 0it%o; ;i;i;i; it%; 0; 0iu%o; ;i;i;i; iu%; 0; 0iv%o; ;i;i;i; iv%; 0; 0iw%o; ;i;i;i; iw%; 0; 0ix%o; ;i;i;i; ix%; 0; 0iy%o; ;i;i;i; iy%; 0; 0iz%o; ;i;i;i; iz%; 0; 0i{%o; ;i;i;i; i{%; 0; 0i|%o; ;i;i;i; i|%; 0; 0i}%o; ;i;i;i; i}%; 0; 0i~%o; ;i;i;i; i~%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i &o; ;i;i;i; i &; 0; 0i &o; ;i;i;i; i &; 0; 0i &o; ;i;i;i; i &; 0; 0i &o; ;i;i;i; i &; 0; 0i &o; ;i;i;i; i &; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i &o; ;i;i;i; i &; 0; 0i!&o; ;i;i;i; i!&; 0; 0i"&o; ;i;i;i; i"&; 0; 0i#&o; ;i;i;i; i#&; 0; 0i$&o; ;i;i;i; i$&; 0; 0i%&o; ;i;i;i; i%&; 0; 0i&&o; ;i;i;i; i&&; 0; 0i'&o; ;i;i;i; i'&; 0; 0i(&o; ;i;i;i; i(&; 0; 0i)&o; ;i;i;i; i)&; 0; 0i*&o; ;i;i;i; i*&; 0; 0i+&o; ;i;i;i; i+&; 0; 0i,&o; ;i;i;i; i,&; 0; 0i-&o; ;i;i;i; i-&; 0; 0i.&o; ;i;i;i; i.&; 0; 0i/&o; ;i;i;i; i/&; 0; 0i0&o; ;i;i;i; i0&; 0; 0i1&o; ;i;i;i; i1&; 0; 0i2&o; ;i;i;i; i2&; 0; 0i3&o; ;i;i;i; i3&; 0; 0i4&o; ;i;i;i; i4&; 0; 0i5&o; ;i;i;i; i5&; 0; 0i6&o; ;i;i;i; i6&; 0; 0i7&o; ;i;i;i; i7&; 0; 0i8&o; ;i;i;i; i8&; 0; 0i9&o; ;i;i;i; i9&; 0; 0i:&o; ;i;i;i; i:&; 0; 0i;&o; ;i;i;i; i;&; 0; 0i<&o; ;i;i;i; i<&; 0; 0i=&o; ;i;i;i; i=&; 0; 0i>&o; ;i;i;i; i>&; 0; 0i?&o; ;i;i;i; i?&; 0; 0i@&o; ;i;i;i; i@&; 0; 0iA&o; ;i;i;i; iA&; 0; 0iB&o; ;i;i;i; iB&; 0; 0iC&o; ;i;i;i; iC&; 0; 0iD&o; ;i;i;i; iD&; 0; 0iE&o; ;i;i;i; iE&; 0; 0iF&o; ;i;i;i; iF&; 0; 0iG&o; ;i;i;i; iG&; 0; 0iH&o; ;i;i;i; iH&; 0; 0iI&o; ;i;i;i; iI&; 0; 0iJ&o; ;i;i;i; iJ&; 0; 0iK&o; ;i;i;i; iK&; 0; 0iL&o; ;i;i;i; iL&; 0; 0iM&o; ;i;i;i; iM&; 0; 0iN&o; ;i;i;i; iN&; 0; 0iO&o; ;i;i;i; iO&; 0; 0iP&o; ;i;i;i; iP&; 0; 0iQ&o; ;i;i;i; iQ&; 0; 0iR&o; ;i;i;i; iR&; 0; 0iS&o; ;i;i;i; iS&; 0; 0iT&o; ;i;i;i; iT&; 0; 0iU&o; ;i;i;i; iU&; 0; 0iV&o; ;i;i;i; iV&; 0; 0iW&o; ;i;i;i; iW&; 0; 0iX&o; ;i;i;i; iX&; 0; 0iY&o; ;i;i;i; iY&; 0; 0iZ&o; ;i;i;i; iZ&; 0; 0i[&o; ;i;i;i; i[&; 0; 0i\&o; ;i;i;i; i\&; 0; 0i]&o; ;i;i;i; i]&; 0; 0i^&o; ;i;i;i; i^&; 0; 0i_&o; ;i;i;i; i_&; 0; 0i`&o; ;i;i;i; i`&; 0; 0ia&o; ;i;i;i; ia&; 0; 0ib&o; ;i;i;i; ib&; 0; 0ic&o; ;i;i;i; ic&; 0; 0id&o; ;i;i;i; id&; 0; 0ie&o; ;i;i;i; ie&; 0; 0if&o; ;i;i;i; if&; 0; 0ig&o; ;i;i;i; ig&; 0; 0ih&o; ;i;i;i; ih&; 0; 0ii&o; ;i;i;i; ii&; 0; 0ij&o; ;i;i;i; ij&; 0; 0ik&o; ;i;i;i; ik&; 0; 0il&o; ;i;i;i; il&; 0; 0im&o; ;i;i;i; im&; 0; 0in&o; ;i;i;i; in&; 0; 0io&o; ;i;i;i; io&; 0; 0ip&o; ;i;i;i; ip&; 0; 0iq&o; ;i;i;i; iq&; 0; 0ir&o; ;i;i;i; ir&; 0; 0is&o; ;i;i;i; is&; 0; 0it&o; ;i;i;i; it&; 0; 0iu&o; ;i;i;i; iu&; 0; 0iv&o; ;i;i;i; iv&; 0; 0iw&o; ;i;i;i; iw&; 0; 0ix&o; ;i;i;i; ix&; 0; 0iy&o; ;i;i;i; iy&; 0; 0iz&o; ;i;i;i; iz&; 0; 0i{&o; ;i;i;i; i{&; 0; 0i|&o; ;i;i;i; i|&; 0; 0i}&o; ;i;i;i; i}&; 0; 0i~&o; ;i;i;i; i~&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i 'o; ;i;i;i; i '; 0; 0i 'o; ;i;i;i; i '; 0; 0i 'o; ;i;i;i; i '; 0; 0i 'o; ;i;i;i; i '; 0; 0i 'o; ;i;i;i; i '; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i 'o; ;i;i;i; i '; 0; 0i!'o; ;i;i;i; i!'; 0; 0i"'o; ;i;i;i; i"'; 0; 0i#'o; ;i;i;i; i#'; 0; 0i$'o; ;i;i;i; i$'; 0; 0i%'o; ;i;i;i; i%'; 0; 0i&'o; ;i;i;i; i&'; 0; 0i''o; ;i;i;i; i''; 0; 0i('o; ;i;i;i; i('; 0; 0i)'o; ;i;i;i; i)'; 0; 0i*'o; ;i;i;i; i*'; 0; 0i+'o; ;i;i;i; i+'; 0; 0i,'o; ;i;i;i; i,'; 0; 0i-'o; ;i;i;i; i-'; 0; 0i.'o; ;i;i;i; i.'; 0; 0i/'o; ;i;i;i; i/'; 0; 0i0'o; ;i;i;i; i0'; 0; 0i1'o; ;i;i;i; i1'; 0; 0i2'o; ;i;i;i; i2'; 0; 0i3'o; ;i;i;i; i3'; 0; 0i4'o; ;i;i;i; i4'; 0; 0i5'o; ;i;i;i; i5'; 0; 0i6'o; ;i;i;i; i6'; 0; 0i7'o; ;i;i;i; i7'; 0; 0i8'o; ;i;i;i; i8'; 0; 0i9'o; ;i;i;i; i9'; 0; 0i:'o; ;i;i;i; i:'; 0; 0i;'o; ;i;i;i; i;'; 0; 0i<'o; ;i;i;i; i<'; 0; 0i='o; ;i;i;i; i='; 0; 0i>'o; ;i;i;i; i>'; 0; 0i?'o; ;i;i;i; i?'; 0; 0i@'o; ;i;i;i; i@'; 0; 0iA'o; ;i;i;i; iA'; 0; 0iB'o; ;i;i;i; iB'; 0; 0iC'o; ;i;i;i; iC'; 0; 0iD'o; ;i;i;i; iD'; 0; 0iE'o; ;i;i;i; iE'; 0; 0iF'o; ;i;i;i; iF'; 0; 0iG'o; ;i;i;i; iG'; 0; 0iH'o; ;i;i;i; iH'; 0; 0iI'o; ;i;i;i; iI'; 0; 0iJ'o; ;i;i;i; iJ'; 0; 0iK'o; ;i;i;i; iK'; 0; 0iL'o; ;i;i;i; iL'; 0; 0iM'o; ;i;i;i; iM'; 0; 0iN'o; ;i;i;i; iN'; 0; 0iO'o; ;i;i;i; iO'; 0; 0iP'o; ;i;i;i; iP'; 0; 0iQ'o; ;i;i;i; iQ'; 0; 0iR'o; ;i;i;i; iR'; 0; 0iS'o; ;i;i;i; iS'; 0; 0iT'o; ;i;i;i; iT'; 0; 0iU'o; ;i;i;i; iU'; 0; 0iV'o; ;i;i;i; iV'; 0; 0iW'o; ;i;i;i; iW'; 0; 0iX'o; ;i;i;i; iX'; 0; 0iY'o; ;i;i;i; iY'; 0; 0iZ'o; ;i;i;i; iZ'; 0; 0i['o; ;i;i;i; i['; 0; 0i\'o; ;i;i;i; i\'; 0; 0i]'o; ;i;i;i; i]'; 0; 0i^'o; ;i;i;i; i^'; 0; 0i_'o; ;i;i;i; i_'; 0; 0i`'o; ;i;i;i; i`'; 0; 0ia'o; ;i;i;i; ia'; 0; 0ib'o; ;i;i;i; ib'; 0; 0ic'o; ;i;i;i; ic'; 0; 0id'o; ;i;i;i; id'; 0; 0ie'o; ;i;i;i; ie'; 0; 0if'o; ;i;i;i; if'; 0; 0ig'o; ;i;i;i; ig'; 0; 0ih'o; ;i;i;i; ih'; 0; 0ii'o; ;i;i;i; ii'; 0; 0ij'o; ;i;i;i; ij'; 0; 0ik'o; ;i;i;i; ik'; 0; 0il'o; ;i;i;i; il'; 0; 0im'o; ;i;i;i; im'; 0; 0in'o; ;i;i;i; in'; 0; 0io'o; ;i;i;i; io'; 0; 0ip'o; ;i;i;i; ip'; 0; 0iq'o; ;i;i;i; iq'; 0; 0ir'o; ;i;i;i; ir'; 0; 0is'o; ;i;i;i; is'; 0; 0it'o; ;i;i;i; it'; 0; 0iu'o; ;i;i;i; iu'; 0; 0iv'o; ;i;i;i; iv'; 0; 0iw'o; ;i;i;i; iw'; 0; 0ix'o; ;i;i;i; ix'; 0; 0iy'o; ;i;i;i; iy'; 0; 0iz'o; ;i;i;i; iz'; 0; 0i{'o; ;i;i;i; i{'; 0; 0i|'o; ;i;i;i; i|'; 0; 0i}'o; ;i;i;i; i}'; 0; 0i~'o; ;i;i;i; i~'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i (o; ;i;i;i; i (; 0; 0i (o; ;i;i;i; i (; 0; 0i (o; ;i;i;i; i (; 0; 0i (o; ;i;i;i; i (; 0; 0i (o; ;i;i;i; i (; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i (o; ;i;i;i; i (; 0; 0i!(o; ;i;i;i; i!(; 0; 0i"(o; ;i;i;i; i"(; 0; 0i#(o; ;i;i;i; i#(; 0; 0i$(o; ;i;i;i; i$(; 0; 0i%(o; ;i;i;i; i%(; 0; 0i&(o; ;i;i;i; i&(; 0; 0i'(o; ;i;i;i; i'(; 0; 0i((o; ;i;i;i; i((; 0; 0i)(o; ;i;i;i; i)(; 0; 0i*(o; ;i;i;i; i*(; 0; 0i+(o; ;i;i;i; i+(; 0; 0i,(o; ;i;i;i; i,(; 0; 0i-(o; ;i;i;i; i-(; 0; 0i.(o; ;i;i;i; i.(; 0; 0i/(o; ;i;i;i; i/(; 0; 0i0(o; ;i;i;i; i0(; 0; 0i1(o; ;i;i;i; i1(; 0; 0i2(o; ;i;i;i; i2(; 0; 0i3(o; ;i;i;i; i3(; 0; 0i4(o; ;i;i;i; i4(; 0; 0i5(o; ;i;i;i; i5(; 0; 0i6(o; ;i;i;i; i6(; 0; 0i7(o; ;i;i;i; i7(; 0; 0i8(o; ;i;i;i; i8(; 0; 0i9(o; ;i;i;i; i9(; 0; 0i:(o; ;i;i;i; i:(; 0; 0i;(o; ;i;i;i; i;(; 0; 0i<(o; ;i;i;i; i<(; 0; 0i=(o; ;i;i;i; i=(; 0; 0i>(o; ;i;i;i; i>(; 0; 0i?(o; ;i;i;i; i?(; 0; 0i@(o; ;i;i;i; i@(; 0; 0iA(o; ;i;i;i; iA(; 0; 0iB(o; ;i;i;i; iB(; 0; 0iC(o; ;i;i;i; iC(; 0; 0iD(o; ;i;i;i; iD(; 0; 0iE(o; ;i;i;i; iE(; 0; 0iF(o; ;i;i;i; iF(; 0; 0iG(o; ;i;i;i; iG(; 0; 0iH(o; ;i;i;i; iH(; 0; 0iI(o; ;i;i;i; iI(; 0; 0iJ(o; ;i;i;i; iJ(; 0; 0iK(o; ;i;i;i; iK(; 0; 0iL(o; ;i;i;i; iL(; 0; 0iM(o; ;i;i;i; iM(; 0; 0iN(o; ;i;i;i; iN(; 0; 0iO(o; ;i;i;i; iO(; 0; 0iP(o; ;i;i;i; iP(; 0; 0iQ(o; ;i;i;i; iQ(; 0; 0iR(o; ;i;i;i; iR(; 0; 0iS(o; ;i;i;i; iS(; 0; 0iT(o; ;i;i;i; iT(; 0; 0iU(o; ;i;i;i; iU(; 0; 0iV(o; ;i;i;i; iV(; 0; 0iW(o; ;i;i;i; iW(; 0; 0iX(o; ;i;i;i; iX(; 0; 0iY(o; ;i;i;i; iY(; 0; 0iZ(o; ;i;i;i; iZ(; 0; 0i[(o; ;i;i;i; i[(; 0; 0i\(o; ;i;i;i; i\(; 0; 0i](o; ;i;i;i; i](; 0; 0i^(o; ;i;i;i; i^(; 0; 0i_(o; ;i;i;i; i_(; 0; 0i`(o; ;i;i;i; i`(; 0; 0ia(o; ;i;i;i; ia(; 0; 0ib(o; ;i;i;i; ib(; 0; 0ic(o; ;i;i;i; ic(; 0; 0id(o; ;i;i;i; id(; 0; 0ie(o; ;i;i;i; ie(; 0; 0if(o; ;i;i;i; if(; 0; 0ig(o; ;i;i;i; ig(; 0; 0ih(o; ;i;i;i; ih(; 0; 0ii(o; ;i;i;i; ii(; 0; 0ij(o; ;i;i;i; ij(; 0; 0ik(o; ;i;i;i; ik(; 0; 0il(o; ;i;i;i; il(; 0; 0im(o; ;i;i;i; im(; 0; 0in(o; ;i;i;i; in(; 0; 0io(o; ;i;i;i; io(; 0; 0ip(o; ;i;i;i; ip(; 0; 0iq(o; ;i;i;i; iq(; 0; 0ir(o; ;i;i;i; ir(; 0; 0is(o; ;i;i;i; is(; 0; 0it(o; ;i;i;i; it(; 0; 0iu(o; ;i;i;i; iu(; 0; 0iv(o; ;i;i;i; iv(; 0; 0iw(o; ;i;i;i; iw(; 0; 0ix(o; ;i;i;i; ix(; 0; 0iy(o; ;i;i;i; iy(; 0; 0iz(o; ;i;i;i; iz(; 0; 0i{(o; ;i;i;i; i{(; 0; 0i|(o; ;i;i;i; i|(; 0; 0i}(o; ;i;i;i; i}(; 0; 0i~(o; ;i;i;i; i~(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i )o; ;i;i;i; i ); 0; 0i )o; ;i;i;i; i ); 0; 0i )o; ;i;i;i; i ); 0; 0i )o; ;i;i;i; i ); 0; 0i )o; ;i;i;i; i ); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i )o; ;i;i;i; i ); 0; 0i!)o; ;i;i;i; i!); 0; 0i")o; ;i;i;i; i"); 0; 0i#)o; ;i;i;i; i#); 0; 0i$)o; ;i;i;i; i$); 0; 0i%)o; ;i;i;i; i%); 0; 0i&)o; ;i;i;i; i&); 0; 0i')o; ;i;i;i; i'); 0; 0i()o; ;i;i;i; i(); 0; 0i))o; ;i;i;i; i)); 0; 0i*)o; ;i;i;i; i*); 0; 0i+)o; ;i;i;i; i+); 0; 0i,)o; ;i;i;i; i,); 0; 0i-)o; ;i;i;i; i-); 0; 0i.)o; ;i;i;i; i.); 0; 0i/)o; ;i;i;i; i/); 0; 0i0)o; ;i;i;i; i0); 0; 0i1)o; ;i;i;i; i1); 0; 0i2)o; ;i;i;i; i2); 0; 0i3)o; ;i;i;i; i3); 0; 0i4)o; ;i;i;i; i4); 0; 0i5)o; ;i;i;i; i5); 0; 0i6)o; ;i;i;i; i6); 0; 0i7)o; ;i;i;i; i7); 0; 0i8)o; ;i;i;i; i8); 0; 0i9)o; ;i;i;i; i9); 0; 0i:)o; ;i;i;i; i:); 0; 0i;)o; ;i;i;i; i;); 0; 0i<)o; ;i;i;i; i<); 0; 0i=)o; ;i;i;i; i=); 0; 0i>)o; ;i;i;i; i>); 0; 0i?)o; ;i;i;i; i?); 0; 0i@)o; ;i;i;i; i@); 0; 0iA)o; ;i;i;i; iA); 0; 0iB)o; ;i;i;i; iB); 0; 0iC)o; ;i;i;i; iC); 0; 0iD)o; ;i;i;i; iD); 0; 0iE)o; ;i;i;i; iE); 0; 0iF)o; ;i;i;i; iF); 0; 0iG)o; ;i;i;i; iG); 0; 0iH)o; ;i;i;i; iH); 0; 0iI)o; ;i;i;i; iI); 0; 0iJ)o; ;i;i;i; iJ); 0; 0iK)o; ;i;i;i; iK); 0; 0iL)o; ;i;i;i; iL); 0; 0iM)o; ;i;i;i; iM); 0; 0iN)o; ;i;i;i; iN); 0; 0iO)o; ;i;i;i; iO); 0; 0iP)o; ;i;i;i; iP); 0; 0iQ)o; ;i;i;i; iQ); 0; 0iR)o; ;i;i;i; iR); 0; 0iS)o; ;i;i;i; iS); 0; 0iT)o; ;i;i;i; iT); 0; 0iU)o; ;i;i;i; iU); 0; 0iV)o; ;i;i;i; iV); 0; 0iW)o; ;i;i;i; iW); 0; 0iX)o; ;i;i;i; iX); 0; 0iY)o; ;i;i;i; iY); 0; 0iZ)o; ;i;i;i; iZ); 0; 0i[)o; ;i;i;i; i[); 0; 0i\)o; ;i;i;i; i\); 0; 0i])o; ;i;i;i; i]); 0; 0i^)o; ;i;i;i; i^); 0; 0i_)o; ;i;i;i; i_); 0; 0i`)o; ;i;i;i; i`); 0; 0ia)o; ;i;i;i; ia); 0; 0ib)o; ;i;i;i; ib); 0; 0ic)o; ;i;i;i; ic); 0; 0id)o; ;i;i;i; id); 0; 0ie)o; ;i;i;i; ie); 0; 0if)o; ;i;i;i; if); 0; 0ig)o; ;i;i;i; ig); 0; 0ih)o; ;i;i;i; ih); 0; 0ii)o; ;i;i;i; ii); 0; 0ij)o; ;i;i;i; ij); 0; 0ik)o; ;i;i;i; ik); 0; 0il)o; ;i;i;i; il); 0; 0im)o; ;i;i;i; im); 0; 0in)o; ;i;i;i; in); 0; 0io)o; ;i;i;i; io); 0; 0ip)o; ;i;i;i; ip); 0; 0iq)o; ;i;i;i; iq); 0; 0ir)o; ;i;i;i; ir); 0; 0is)o; ;i;i;i; is); 0; 0it)o; ;i;i;i; it); 0; 0iu)o; ;i;i;i; iu); 0; 0iv)o; ;i;i;i; iv); 0; 0iw)o; ;i;i;i; iw); 0; 0ix)o; ;i;i;i; ix); 0; 0iy)o; ;i;i;i; iy); 0; 0iz)o; ;i;i;i; iz); 0; 0i{)o; ;i;i;i; i{); 0; 0i|)o; ;i;i;i; i|); 0; 0i})o; ;i;i;i; i}); 0; 0i~)o; ;i;i;i; i~); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i *o; ;i;i;i; i *; 0; 0i *o; ;i;i;i; i *; 0; 0i *o; ;i;i;i; i *; 0; 0i *o; ;i;i;i; i *; I" compat; T; [ i+"i+"i+"i+"i *o; ;i;i;i; i *; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i *o; ;i;i;i; i *; 0; 0i!*o; ;i;i;i; i!*; 0; 0i"*o; ;i;i;i; i"*; 0; 0i#*o; ;i;i;i; i#*; 0; 0i$*o; ;i;i;i; i$*; 0; 0i%*o; ;i;i;i; i%*; 0; 0i&*o; ;i;i;i; i&*; 0; 0i'*o; ;i;i;i; i'*; 0; 0i(*o; ;i;i;i; i(*; 0; 0i)*o; ;i;i;i; i)*; 0; 0i**o; ;i;i;i; i**; 0; 0i+*o; ;i;i;i; i+*; 0; 0i,*o; ;i;i;i; i,*; 0; 0i-*o; ;i;i;i; i-*; 0; 0i.*o; ;i;i;i; i.*; 0; 0i/*o; ;i;i;i; i/*; 0; 0i0*o; ;i;i;i; i0*; 0; 0i1*o; ;i;i;i; i1*; 0; 0i2*o; ;i;i;i; i2*; 0; 0i3*o; ;i;i;i; i3*; 0; 0i4*o; ;i;i;i; i4*; 0; 0i5*o; ;i;i;i; i5*; 0; 0i6*o; ;i;i;i; i6*; 0; 0i7*o; ;i;i;i; i7*; 0; 0i8*o; ;i;i;i; i8*; 0; 0i9*o; ;i;i;i; i9*; 0; 0i:*o; ;i;i;i; i:*; 0; 0i;*o; ;i;i;i; i;*; 0; 0i<*o; ;i;i;i; i<*; 0; 0i=*o; ;i;i;i; i=*; 0; 0i>*o; ;i;i;i; i>*; 0; 0i?*o; ;i;i;i; i?*; 0; 0i@*o; ;i;i;i; i@*; 0; 0iA*o; ;i;i;i; iA*; 0; 0iB*o; ;i;i;i; iB*; 0; 0iC*o; ;i;i;i; iC*; 0; 0iD*o; ;i;i;i; iD*; 0; 0iE*o; ;i;i;i; iE*; 0; 0iF*o; ;i;i;i; iF*; 0; 0iG*o; ;i;i;i; iG*; 0; 0iH*o; ;i;i;i; iH*; 0; 0iI*o; ;i;i;i; iI*; 0; 0iJ*o; ;i;i;i; iJ*; 0; 0iK*o; ;i;i;i; iK*; 0; 0iL*o; ;i;i;i; iL*; 0; 0iM*o; ;i;i;i; iM*; 0; 0iN*o; ;i;i;i; iN*; 0; 0iO*o; ;i;i;i; iO*; 0; 0iP*o; ;i;i;i; iP*; 0; 0iQ*o; ;i;i;i; iQ*; 0; 0iR*o; ;i;i;i; iR*; 0; 0iS*o; ;i;i;i; iS*; 0; 0iT*o; ;i;i;i; iT*; 0; 0iU*o; ;i;i;i; iU*; 0; 0iV*o; ;i;i;i; iV*; 0; 0iW*o; ;i;i;i; iW*; 0; 0iX*o; ;i;i;i; iX*; 0; 0iY*o; ;i;i;i; iY*; 0; 0iZ*o; ;i;i;i; iZ*; 0; 0i[*o; ;i;i;i; i[*; 0; 0i\*o; ;i;i;i; i\*; 0; 0i]*o; ;i;i;i; i]*; 0; 0i^*o; ;i;i;i; i^*; 0; 0i_*o; ;i;i;i; i_*; 0; 0i`*o; ;i;i;i; i`*; 0; 0ia*o; ;i;i;i; ia*; 0; 0ib*o; ;i;i;i; ib*; 0; 0ic*o; ;i;i;i; ic*; 0; 0id*o; ;i;i;i; id*; 0; 0ie*o; ;i;i;i; ie*; 0; 0if*o; ;i;i;i; if*; 0; 0ig*o; ;i;i;i; ig*; 0; 0ih*o; ;i;i;i; ih*; 0; 0ii*o; ;i;i;i; ii*; 0; 0ij*o; ;i;i;i; ij*; 0; 0ik*o; ;i;i;i; ik*; 0; 0il*o; ;i;i;i; il*; 0; 0im*o; ;i;i;i; im*; 0; 0in*o; ;i;i;i; in*; 0; 0io*o; ;i;i;i; io*; 0; 0ip*o; ;i;i;i; ip*; 0; 0iq*o; ;i;i;i; iq*; 0; 0ir*o; ;i;i;i; ir*; 0; 0is*o; ;i;i;i; is*; 0; 0it*o; ;i;i;i; it*; I" compat; T; [i?i?iBiu*o; ;i;i;i; iu*; I" compat; T; [iBiBiv*o; ;i;i;i; iv*; I" compat; T; [iBiBiBiw*o; ;i;i;i; iw*; 0; 0ix*o; ;i;i;i; ix*; 0; 0iy*o; ;i;i;i; iy*; 0; 0iz*o; ;i;i;i; iz*; 0; 0i{*o; ;i;i;i; i{*; 0; 0i|*o; ;i;i;i; i|*; 0; 0i}*o; ;i;i;i; i}*; 0; 0i~*o; ;i;i;i; i~*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; [i*i8i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i +o; ;i;i;i; i +; 0; 0i +o; ;i;i;i; i +; 0; 0i +o; ;i;i;i; i +; 0; 0i +o; ;i;i;i; i +; 0; 0i +o; ;i;i;i; i +; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i+o; ;i;i;i; i+; 0; 0i +o; ;i;i;i; i +; 0; 0i!+o; ;i;i;i; i!+; 0; 0i"+o; ;i;i;i; i"+; 0; 0i#+o; ;i;i;i; i#+; 0; 0i$+o; ;i;i;i; i$+; 0; 0i%+o; ;i;i;i; i%+; 0; 0i&+o; ;i;i;i; i&+; 0; 0i'+o; ;i;i;i; i'+; 0; 0i(+o; ;i;i;i; i(+; 0; 0i)+o; ;i;i;i; i)+; 0; 0i*+o; ;i;i;i; i*+; 0; 0i++o; ;i;i;i; i++; 0; 0i,+o; ;i;i;i; i,+; 0; 0i-+o; ;i;i;i; i-+; 0; 0i.+o; ;i;i;i; i.+; 0; 0i/+o; ;i;i;i; i/+; 0; 0i0+o; ;i;i;i; i0+; 0; 0i1+o; ;i;i;i; i1+; 0; 0i2+o; ;i;i;i; i2+; 0; 0i3+o; ;i;i;i; i3+; 0; 0i4+o; ;i;i;i; i4+; 0; 0i5+o; ;i;i;i; i5+; 0; 0i6+o; ;i;i;i; i6+; 0; 0i7+o; ;i;i;i; i7+; 0; 0i8+o; ;i;i;i; i8+; 0; 0i9+o; ;i;i;i; i9+; 0; 0i:+o; ;i;i;i; i:+; 0; 0i;+o; ;i;i;i; i;+; 0; 0i<+o; ;i;i;i; i<+; 0; 0i=+o; ;i;i;i; i=+; 0; 0i>+o; ;i;i;i; i>+; 0; 0i?+o; ;i;i;i; i?+; 0; 0i@+o; ;i;i;i; i@+; 0; 0iA+o; ;i;i;i; iA+; 0; 0iB+o; ;i;i;i; iB+; 0; 0iC+o; ;i;i;i; iC+; 0; 0iD+o; ;i;i;i; iD+; 0; 0iE+o; ;i;i;i; iE+; 0; 0iF+o; ;i;i;i; iF+; 0; 0iG+o; ;i;i;i; iG+; 0; 0iH+o; ;i;i;i; iH+; 0; 0iI+o; ;i;i;i; iI+; 0; 0iJ+o; ;i;i;i; iJ+; 0; 0iK+o; ;i;i;i; iK+; 0; 0iL+o; ;i;i;i; iL+; 0; 0iP+o; ;i;i;i; iP+; 0; 0iQ+o; ;i;i;i; iQ+; 0; 0iR+o; ;i;i;i; iR+; 0; 0iS+o; ;i;i;i; iS+; 0; 0iT+o; ;i;i;i; iT+; 0; 0iU+o; ;i;i;i; iU+; 0; 0iV+o; ;i;i;i; iV+; 0; 0iW+o; ;i;i;i; iW+; 0; 0iX+o; ;i;i;i; iX+; 0; 0iY+o; ;i;i;i; iY+; 0; 0i,o; ;i;i;i0,; i,; 0; 0i,o; ;i;i;i1,; i,; 0; 0i,o; ;i;i;i2,; i,; 0; 0i,o; ;i;i;i3,; i,; 0; 0i,o; ;i;i;i4,; i,; 0; 0i,o; ;i;i;i5,; i,; 0; 0i,o; ;i;i;i6,; i,; 0; 0i,o; ;i;i;i7,; i,; 0; 0i,o; ;i;i;i8,; i,; 0; 0i ,o; ;i;i;i9,; i ,; 0; 0i ,o; ;i;i;i:,; i ,; 0; 0i ,o; ;i;i;i;,; i ,; 0; 0i ,o; ;i;i;i<,; i ,; 0; 0i ,o; ;i;i;i=,; i ,; 0; 0i,o; ;i;i;i>,; i,; 0; 0i,o; ;i;i;i?,; i,; 0; 0i,o; ;i;i;i@,; i,; 0; 0i,o; ;i;i;iA,; i,; 0; 0i,o; ;i;i;iB,; i,; 0; 0i,o; ;i;i;iC,; i,; 0; 0i,o; ;i;i;iD,; i,; 0; 0i,o; ;i;i;iE,; i,; 0; 0i,o; ;i;i;iF,; i,; 0; 0i,o; ;i;i;iG,; i,; 0; 0i,o; ;i;i;iH,; i,; 0; 0i,o; ;i;i;iI,; i,; 0; 0i,o; ;i;i;iJ,; i,; 0; 0i,o; ;i;i;iK,; i,; 0; 0i,o; ;i;i;iL,; i,; 0; 0i,o; ;i;i;iM,; i,; 0; 0i,o; ;i;i;iN,; i,; 0; 0i,o; ;i;i;iO,; i,; 0; 0i ,o; ;i;i;iP,; i ,; 0; 0i!,o; ;i;i;iQ,; i!,; 0; 0i",o; ;i;i;iR,; i",; 0; 0i#,o; ;i;i;iS,; i#,; 0; 0i$,o; ;i;i;iT,; i$,; 0; 0i%,o; ;i;i;iU,; i%,; 0; 0i&,o; ;i;i;iV,; i&,; 0; 0i',o; ;i;i;iW,; i',; 0; 0i(,o; ;i;i;iX,; i(,; 0; 0i),o; ;i;i;iY,; i),; 0; 0i*,o; ;i;i;iZ,; i*,; 0; 0i+,o; ;i;i;i[,; i+,; 0; 0i,,o; ;i;i;i\,; i,,; 0; 0i-,o; ;i;i;i],; i-,; 0; 0i.,o; ;i;i;i^,; i.,; 0; 0i0,o; ;i;i,;i; i0,; 0; 0i1,o; ;i;i,;i; i1,; 0; 0i2,o; ;i;i,;i; i2,; 0; 0i3,o; ;i;i,;i; i3,; 0; 0i4,o; ;i;i,;i; i4,; 0; 0i5,o; ;i;i,;i; i5,; 0; 0i6,o; ;i;i,;i; i6,; 0; 0i7,o; ;i;i,;i; i7,; 0; 0i8,o; ;i;i,;i; i8,; 0; 0i9,o; ;i;i ,;i; i9,; 0; 0i:,o; ;i;i ,;i; i:,; 0; 0i;,o; ;i;i ,;i; i;,; 0; 0i<,o; ;i;i ,;i; i<,; 0; 0i=,o; ;i;i ,;i; i=,; 0; 0i>,o; ;i;i,;i; i>,; 0; 0i?,o; ;i;i,;i; i?,; 0; 0i@,o; ;i;i,;i; i@,; 0; 0iA,o; ;i;i,;i; iA,; 0; 0iB,o; ;i;i,;i; iB,; 0; 0iC,o; ;i;i,;i; iC,; 0; 0iD,o; ;i;i,;i; iD,; 0; 0iE,o; ;i;i,;i; iE,; 0; 0iF,o; ;i;i,;i; iF,; 0; 0iG,o; ;i;i,;i; iG,; 0; 0iH,o; ;i;i,;i; iH,; 0; 0iI,o; ;i;i,;i; iI,; 0; 0iJ,o; ;i;i,;i; iJ,; 0; 0iK,o; ;i;i,;i; iK,; 0; 0iL,o; ;i;i,;i; iL,; 0; 0iM,o; ;i;i,;i; iM,; 0; 0iN,o; ;i;i,;i; iN,; 0; 0iO,o; ;i;i,;i; iO,; 0; 0iP,o; ;i;i ,;i; iP,; 0; 0iQ,o; ;i;i!,;i; iQ,; 0; 0iR,o; ;i;i",;i; iR,; 0; 0iS,o; ;i;i#,;i; iS,; 0; 0iT,o; ;i;i$,;i; iT,; 0; 0iU,o; ;i;i%,;i; iU,; 0; 0iV,o; ;i;i&,;i; iV,; 0; 0iW,o; ;i;i',;i; iW,; 0; 0iX,o; ;i;i(,;i; iX,; 0; 0iY,o; ;i;i),;i; iY,; 0; 0iZ,o; ;i;i*,;i; iZ,; 0; 0i[,o; ;i;i+,;i; i[,; 0; 0i\,o; ;i;i,,;i; i\,; 0; 0i],o; ;i;i-,;i; i],; 0; 0i^,o; ;i;i.,;i; i^,; 0; 0i`,o; ;i;i;ia,; i`,; 0; 0ia,o; ;i;i`,;i; ia,; 0; 0ib,o; ;i;i;ik; ib,; 0; 0ic,o; ;i;i;i}; ic,; 0; 0id,o; ;i;i;i}; id,; 0; 0ie,o; ;i;i:;i; ie,; 0; 0if,o; ;i;i>;i; if,; 0; 0ig,o; ;i;i;ih,; ig,; 0; 0ih,o; ;i;ig,;i; ih,; 0; 0ii,o; ;i;i;ij,; ii,; 0; 0ij,o; ;i;ii,;i; ij,; 0; 0ik,o; ;i;i;il,; ik,; 0; 0il,o; ;i;ik,;i; il,; 0; 0im,o; ;i;i;iQ; im,; 0; 0in,o; ;i;i;iq; in,; 0; 0io,o; ;i;i;iP; io,; 0; 0ip,o; ;i;i;iR; ip,; 0; 0iq,o; ;i;i;i; iq,; 0; 0ir,o; ;i;i;is,; ir,; 0; 0is,o; ;i;ir,;i; is,; 0; 0it,o; ;i;i;i; it,; 0; 0iu,o; ;i;i;iv,; iu,; 0; 0iv,o; ;i;iu,;i; iv,; 0; 0iw,o; ;i;i;i; iw,; 0; 0ix,o; ;i;i;i; ix,; 0; 0iy,o; ;i;i;i; iy,; 0; 0iz,o; ;i;i;i; iz,; 0; 0i{,o; ;i;i;i; i{,; 0; 0i|,o; ;i;i;i; i|,; I"sub; T; [ioi},o; ;i;i;i; i},; I" super; T; [i[i~,o; ;i;i;i?; i~,; 0; 0i,o; ;i;i;i@; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i,; i,; 0; 0i,o; ;i;i,;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i -o; ;i;i;i; i -; 0; 0i -o; ;i;i;i; i -; 0; 0i -o; ;i;i;i; i -; 0; 0i -o; ;i;i;i; i -; 0; 0i -o; ;i;i;i; i -; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i -o; ;i;i;i; i -; 0; 0i!-o; ;i;i;i; i!-; 0; 0i"-o; ;i;i;i; i"-; 0; 0i#-o; ;i;i;i; i#-; 0; 0i$-o; ;i;i;i; i$-; 0; 0i%-o; ;i;i;i; i%-; 0; 0i'-o; ;i;i;i; i'-; 0; 0i--o; ;i;i;i; i--; 0; 0i0-o; ;i;i;i; i0-; 0; 0i1-o; ;i;i;i; i1-; 0; 0i2-o; ;i;i;i; i2-; 0; 0i3-o; ;i;i;i; i3-; 0; 0i4-o; ;i;i;i; i4-; 0; 0i5-o; ;i;i;i; i5-; 0; 0i6-o; ;i;i;i; i6-; 0; 0i7-o; ;i;i;i; i7-; 0; 0i8-o; ;i;i;i; i8-; 0; 0i9-o; ;i;i;i; i9-; 0; 0i:-o; ;i;i;i; i:-; 0; 0i;-o; ;i;i;i; i;-; 0; 0i<-o; ;i;i;i; i<-; 0; 0i=-o; ;i;i;i; i=-; 0; 0i>-o; ;i;i;i; i>-; 0; 0i?-o; ;i;i;i; i?-; 0; 0i@-o; ;i;i;i; i@-; 0; 0iA-o; ;i;i;i; iA-; 0; 0iB-o; ;i;i;i; iB-; 0; 0iC-o; ;i;i;i; iC-; 0; 0iD-o; ;i;i;i; iD-; 0; 0iE-o; ;i;i;i; iE-; 0; 0iF-o; ;i;i;i; iF-; 0; 0iG-o; ;i;i;i; iG-; 0; 0iH-o; ;i;i;i; iH-; 0; 0iI-o; ;i;i;i; iI-; 0; 0iJ-o; ;i;i;i; iJ-; 0; 0iK-o; ;i;i;i; iK-; 0; 0iL-o; ;i;i;i; iL-; 0; 0iM-o; ;i;i;i; iM-; 0; 0iN-o; ;i;i;i; iN-; 0; 0iO-o; ;i;i;i; iO-; 0; 0iP-o; ;i;i;i; iP-; 0; 0iQ-o; ;i;i;i; iQ-; 0; 0iR-o; ;i;i;i; iR-; 0; 0iS-o; ;i;i;i; iS-; 0; 0iT-o; ;i;i;i; iT-; 0; 0iU-o; ;i;i;i; iU-; 0; 0iV-o; ;i;i;i; iV-; 0; 0iW-o; ;i;i;i; iW-; 0; 0iX-o; ;i;i;i; iX-; 0; 0iY-o; ;i;i;i; iY-; 0; 0iZ-o; ;i;i;i; iZ-; 0; 0i[-o; ;i;i;i; i[-; 0; 0i\-o; ;i;i;i; i\-; 0; 0i]-o; ;i;i;i; i]-; 0; 0i^-o; ;i;i;i; i^-; 0; 0i_-o; ;i;i;i; i_-; 0; 0i`-o; ;i;i;i; i`-; 0; 0ia-o; ;i;i;i; ia-; 0; 0ib-o; ;i;i;i; ib-; 0; 0ic-o; ;i;i;i; ic-; 0; 0id-o; ;i;i;i; id-; 0; 0ie-o; ;i;i;i; ie-; 0; 0if-o; ;i;i;i; if-; 0; 0ig-o; ;i;i;i; ig-; 0; 0io-o; ;i;i;i; io-; I" super; T; [ia-ip-o; ;i;i;i; ip-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i .o; ;i;i;i; i .; 0; 0i .o; ;i;i;i; i .; 0; 0i .o; ;i;i;i; i .; 0; 0i .o; ;i;i;i; i .; 0; 0i .o; ;i;i;i; i .; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i .o; ;i;i;i; i .; 0; 0i!.o; ;i;i;i; i!.; 0; 0i".o; ;i;i;i; i".; 0; 0i#.o; ;i;i;i; i#.; 0; 0i$.o; ;i;i;i; i$.; 0; 0i%.o; ;i;i;i; i%.; 0; 0i&.o; ;i;i;i; i&.; 0; 0i'.o; ;i;i;i; i'.; 0; 0i(.o; ;i;i;i; i(.; 0; 0i).o; ;i;i;i; i).; 0; 0i*.o; ;i;i;i; i*.; 0; 0i+.o; ;i;i;i; i+.; 0; 0i,.o; ;i;i;i; i,.; 0; 0i-.o; ;i;i;i; i-.; 0; 0i..o; ;i;i;i; i..; 0; 0i/.o; ;i;i;i; i/.; 0; 0i0.o; ;i;i;i; i0.; 0; 0i1.o; ;i;i;i; i1.; 0; 0i2.o; ;i;i;i; i2.; 0; 0i3.o; ;i;i;i; i3.; 0; 0i4.o; ;i;i;i; i4.; 0; 0i5.o; ;i;i;i; i5.; 0; 0i6.o; ;i;i;i; i6.; 0; 0i7.o; ;i;i;i; i7.; 0; 0i8.o; ;i;i;i; i8.; 0; 0i9.o; ;i;i;i; i9.; 0; 0i:.o; ;i;i;i; i:.; 0; 0i;.o; ;i;i;i; i;.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; I" compat; T; [iki.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; 0; 0i.o; ;i;i;i; i.; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iNi/o; ;i;i;i; i/; I" compat; T; [i(Ni/o; ;i;i;i; i/; I" compat; T; [i6Ni/o; ;i;i;i; i/; I" compat; T; [i?Ni/o; ;i;i;i; i/; I" compat; T; [iYNi/o; ;i;i;i; i/; I" compat; T; [iNi/o; ;i;i;i; i/; I" compat; T; [iNi/o; ;i;i;i; i/; I" compat; T; [iNi/o; ;i;i;i; i/; I" compat; T; [iNi /o; ;i;i;i; i /; I" compat; T; [i?Qi /o; ;i;i;i; i /; I" compat; T; [ieQi /o; ;i;i;i; i /; I" compat; T; [ikQi /o; ;i;i;i; i /; I" compat; T; [iQi /o; ;i;i;i; i /; I" compat; T; [iQi/o; ;i;i;i; i/; I" compat; T; [iQi/o; ;i;i;i; i/; I" compat; T; [iQi/o; ;i;i;i; i/; I" compat; T; [iQi/o; ;i;i;i; i/; I" compat; T; [iRi/o; ;i;i;i; i/; I" compat; T; [iRi/o; ;i;i;i; i/; I" compat; T; [iRi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [i8Si/o; ;i;i;i; i/; I" compat; T; [iASi/o; ;i;i;i; i/; I" compat; T; [i\Si/o; ;i;i;i; i/; I" compat; T; [iiSi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [iSi/o; ;i;i;i; i/; I" compat; T; [iVi/o; ;i;i;i; i/; I" compat; T; [iWi /o; ;i;i;i; i /; I" compat; T; [iXi!/o; ;i;i;i; i!/; I" compat; T; [iYi"/o; ;i;i;i; i"/; I" compat; T; [i Yi#/o; ;i;i;i; i#/; I" compat; T; [iYi$/o; ;i;i;i; i$/; I" compat; T; [i'Yi%/o; ;i;i;i; i%/; I" compat; T; [isYi&/o; ;i;i;i; i&/; I" compat; T; [iP[i'/o; ;i;i;i; i'/; I" compat; T; [i[i(/o; ;i;i;i; i(/; I" compat; T; [i[i)/o; ;i;i;i; i)/; I" compat; T; [i\i*/o; ;i;i;i; i*/; I" compat; T; [i"\i+/o; ;i;i;i; i+/; I" compat; T; [i8\i,/o; ;i;i;i; i,/; I" compat; T; [in\i-/o; ;i;i;i; i-/; I" compat; T; [iq\i./o; ;i;i;i; i./; I" compat; T; [i]i//o; ;i;i;i; i//; I" compat; T; [i]i0/o; ;i;i;i; i0/; I" compat; T; [i]i1/o; ;i;i;i; i1/; I" compat; T; [i]i2/o; ;i;i;i; i2/; I" compat; T; [ir^i3/o; ;i;i;i; i3/; I" compat; T; [iz^i4/o; ;i;i;i; i4/; I" compat; T; [i^i5/o; ;i;i;i; i5/; I" compat; T; [i^i6/o; ;i;i;i; i6/; I" compat; T; [i^i7/o; ;i;i;i; i7/; I" compat; T; [i _i8/o; ;i;i;i; i8/; I" compat; T; [i_i9/o; ;i;i;i; i9/; I" compat; T; [iP_i:/o; ;i;i;i; i:/; I" compat; T; [ia_i;/o; ;i;i;i; i;/; I" compat; T; [is_i/o; ;i;i;i; i>/; I" compat; T; [i6bi?/o; ;i;i;i; i?/; I" compat; T; [iKbi@/o; ;i;i;i; i@/; I" compat; T; [i/eiA/o; ;i;i;i; iA/; I" compat; T; [i4eiB/o; ;i;i;i; iB/; I" compat; T; [ieiC/o; ;i;i;i; iC/; I" compat; T; [ieiD/o; ;i;i;i; iD/; I" compat; T; [ieiE/o; ;i;i;i; iE/; I" compat; T; [ieiF/o; ;i;i;i; iF/; I" compat; T; [ieiG/o; ;i;i;i; iG/; I" compat; T; [ieiH/o; ;i;i;i; iH/; I" compat; T; [ifiI/o; ;i;i;i; iI/; I" compat; T; [igiJ/o; ;i;i;i; iJ/; I" compat; T; [i(giK/o; ;i;i;i; iK/; I" compat; T; [i kiL/o; ;i;i;i; iL/; I" compat; T; [ibkiM/o; ;i;i;i; iM/; I" compat; T; [iykiN/o; ;i;i;i; iN/; I" compat; T; [ikiO/o; ;i;i;i; iO/; I" compat; T; [ikiP/o; ;i;i;i; iP/; I" compat; T; [ikiQ/o; ;i;i;i; iQ/; I" compat; T; [ikiR/o; ;i;i;i; iR/; I" compat; T; [iliS/o; ;i;i;i; iS/; I" compat; T; [iliT/o; ;i;i;i; iT/; I" compat; T; [i4liU/o; ;i;i;i; iU/; I" compat; T; [ikpiV/o; ;i;i;i; iV/; I" compat; T; [i*riW/o; ;i;i;i; iW/; I" compat; T; [i6riX/o; ;i;i;i; iX/; I" compat; T; [i;riY/o; ;i;i;i; iY/; I" compat; T; [i?riZ/o; ;i;i;i; iZ/; I" compat; T; [iGri[/o; ;i;i;i; i[/; I" compat; T; [iYri\/o; ;i;i;i; i\/; I" compat; T; [i[ri]/o; ;i;i;i; i]/; I" compat; T; [iri^/o; ;i;i;i; i^/; I" compat; T; [isi_/o; ;i;i;i; i_/; I" compat; T; [isi`/o; ;i;i;i; i`/; I" compat; T; [itia/o; ;i;i;i; ia/; I" compat; T; [itib/o; ;i;i;i; ib/; I" compat; T; [iuic/o; ;i;i;i; ic/; I" compat; T; [iuid/o; ;i;i;i; id/; I" compat; T; [i(uie/o; ;i;i;i; ie/; I" compat; T; [i0uif/o; ;i;i;i; if/; I" compat; T; [iuig/o; ;i;i;i; ig/; I" compat; T; [iuih/o; ;i;i;i; ih/; I" compat; T; [ivvii/o; ;i;i;i; ii/; I" compat; T; [i}vij/o; ;i;i;i; ij/; I" compat; T; [ivik/o; ;i;i;i; ik/; I" compat; T; [ivil/o; ;i;i;i; il/; I" compat; T; [ivim/o; ;i;i;i; im/; I" compat; T; [iwin/o; ;i;i;i; in/; I" compat; T; [iwio/o; ;i;i;i; io/; I" compat; T; [iwip/o; ;i;i;i; ip/; I" compat; T; [i:yiq/o; ;i;i;i; iq/; I" compat; T; [iyir/o; ;i;i;i; ir/; I" compat; T; [iyis/o; ;i;i;i; is/; I" compat; T; [itzit/o; ;i;i;i; it/; I" compat; T; [iziu/o; ;i;i;i; iu/; I" compat; T; [iziv/o; ;i;i;i; iv/; I" compat; T; [is|iw/o; ;i;i;i; iw/; I" compat; T; [i|ix/o; ;i;i;i; ix/; I" compat; T; [i6iy/o; ;i;i;i; iy/; I" compat; T; [iQiz/o; ;i;i;i; iz/; I" compat; T; [ii{/o; ;i;i;i; i{/; I" compat; T; [ii|/o; ;i;i;i; i|/; I" compat; T; [ii}/o; ;i;i;i; i}/; I" compat; T; [i i~/o; ;i;i;i; i~/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [i3i/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [i i/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ini/o; ;i;i;i; i/; I" compat; T; [iri/o; ;i;i;i; i/; I" compat; T; [ixi/o; ;i;i;i; i/; I" compat; T; [iMi/o; ;i;i;i; i/; I" compat; T; [iki/o; ;i;i;i; i/; I" compat; T; [i@i/o; ;i;i;i; i/; I" compat; T; [iLi/o; ;i;i;i; i/; I" compat; T; [ici/o; ;i;i;i; i/; I" compat; T; [i~i/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [i҉i/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [i7i/o; ;i;i;i; i/; I" compat; T; [iFi/o; ;i;i;i; i/; I" compat; T; [iUi/o; ;i;i;i; i/; I" compat; T; [ixi/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [idi/o; ;i;i;i; i/; I" compat; T; [ipi/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iʎi/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iIi/o; ;i;i;i; i/; I" compat; T; [iƑi/o; ;i;i;i; i/; I" compat; T; [ȋi/o; ;i;i;i; i/; I" compat; T; [iёi/o; ;i;i;i; i/; I" compat; T; [iwi/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iQi/o; ;i;i;i; i/; I" compat; T; [i^i/o; ;i;i;i; i/; I" compat; T; [ibi/o; ;i;i;i; i/; I" compat; T; [iii/o; ;i;i;i; i/; I" compat; T; [i˗i/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iۘi/o; ;i;i;i; i/; I" compat; T; [iߘi/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [ii/o; ;i;i;i; i/; I" compat; T; [iؚi/o; ;i;i;i; i/; I" compat; T; [iߚi/o; ;i;i;i; i/; I" compat; T; [i%i/o; ;i;i;i; i/; I" compat; T; [i/i/o; ;i;i;i; i/; I" compat; T; [i2i/o; ;i;i;i; i/; I" compat; T; [i0o; ;i;i;i; i>0; 0; 0i?0o; ;i;i;i; i?0; 0; 0iA0o; ;i;i;i; iA0; 0; 0iB0o; ;i;i;i; iB0; 0; 0iC0o; ;i;i;i; iC0; 0; 0iD0o; ;i;i;i; iD0; 0; 0iE0o; ;i;i;i; iE0; 0; 0iF0o; ;i;i;i; iF0; 0; 0iG0o; ;i;i;i; iG0; 0; 0iH0o; ;i;i;i; iH0; 0; 0iI0o; ;i;i;i; iI0; 0; 0iJ0o; ;i;i;i; iJ0; 0; 0iK0o; ;i;i;i; iK0; 0; 0iL0o; ;i;i;i; iL0; 0; [iK0i0iM0o; ;i;i;i; iM0; 0; 0iN0o; ;i;i;i; iN0; 0; [iM0i0iO0o; ;i;i;i; iO0; 0; 0iP0o; ;i;i;i; iP0; 0; [iO0i0iQ0o; ;i;i;i; iQ0; 0; 0iR0o; ;i;i;i; iR0; 0; [iQ0i0iS0o; ;i;i;i; iS0; 0; 0iT0o; ;i;i;i; iT0; 0; [iS0i0iU0o; ;i;i;i; iU0; 0; 0iV0o; ;i;i;i; iV0; 0; [iU0i0iW0o; ;i;i;i; iW0; 0; 0iX0o; ;i;i;i; iX0; 0; [iW0i0iY0o; ;i;i;i; iY0; 0; 0iZ0o; ;i;i;i; iZ0; 0; [iY0i0i[0o; ;i;i;i; i[0; 0; 0i\0o; ;i;i;i; i\0; 0; [i[0i0i]0o; ;i;i;i; i]0; 0; 0i^0o; ;i;i;i; i^0; 0; [i]0i0i_0o; ;i;i;i; i_0; 0; 0i`0o; ;i;i;i; i`0; 0; [i_0i0ia0o; ;i;i;i; ia0; 0; 0ib0o; ;i;i;i; ib0; 0; [ia0i0ic0o; ;i;i;i; ic0; 0; 0id0o; ;i;i;i; id0; 0; 0ie0o; ;i;i;i; ie0; 0; [id0i0if0o; ;i;i;i; if0; 0; 0ig0o; ;i;i;i; ig0; 0; [if0i0ih0o; ;i;i;i; ih0; 0; 0ii0o; ;i;i;i; ii0; 0; [ih0i0ij0o; ;i;i;i; ij0; 0; 0ik0o; ;i;i;i; ik0; 0; 0il0o; ;i;i;i; il0; 0; 0im0o; ;i;i;i; im0; 0; 0in0o; ;i;i;i; in0; 0; 0io0o; ;i;i;i; io0; 0; 0ip0o; ;i;i;i; ip0; 0; [io0i0iq0o; ;i;i;i; iq0; 0; [io0i0ir0o; ;i;i;i; ir0; 0; 0is0o; ;i;i;i; is0; 0; [ir0i0it0o; ;i;i;i; it0; 0; [ir0i0iu0o; ;i;i;i; iu0; 0; 0iv0o; ;i;i;i; iv0; 0; [iu0i0iw0o; ;i;i;i; iw0; 0; [iu0i0ix0o; ;i;i;i; ix0; 0; 0iy0o; ;i;i;i; iy0; 0; [ix0i0iz0o; ;i;i;i; iz0; 0; [ix0i0i{0o; ;i;i;i; i{0; 0; 0i|0o; ;i;i;i; i|0; 0; [i{0i0i}0o; ;i;i;i; i}0; 0; [i{0i0i~0o; ;i;i;i; i~0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [iF0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i ;i;i; i0; 0; 0i0o; ;i ;i;i; i0; 0; 0i0o; ;i;i;i; i0; I" compat; T; [i%i0i0o; ;i;i;i; i0; I" compat; T; [i%i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; I" vertical; T; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; [i0i0i0o; ;i;i;i; i0; I" vertical; T; [i0i0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i!1o; ;i;i;i; i!1; 0; 0i"1o; ;i;i;i; i"1; 0; 0i#1o; ;i;i;i; i#1; 0; 0i$1o; ;i;i;i; i$1; 0; 0i%1o; ;i;i;i; i%1; 0; 0i&1o; ;i;i;i; i&1; 0; 0i'1o; ;i;i;i; i'1; 0; 0i(1o; ;i;i;i; i(1; 0; 0i)1o; ;i;i;i; i)1; 0; 0i*1o; ;i;i;i; i*1; 0; 0i+1o; ;i;i;i; i+1; 0; 0i,1o; ;i;i;i; i,1; 0; 0i-1o; ;i;i;i; i-1; 0; 0i11o; ;i;i;i; i11; I" compat; T; [ii21o; ;i;i;i; i21; I" compat; T; [ii31o; ;i;i;i; i31; I" compat; T; [ii41o; ;i;i;i; i41; I" compat; T; [ii51o; ;i;i;i; i51; I" compat; T; [ii61o; ;i;i;i; i61; I" compat; T; [ii71o; ;i;i;i; i71; I" compat; T; [ii81o; ;i;i;i; i81; I" compat; T; [ii91o; ;i;i;i; i91; I" compat; T; [ii:1o; ;i;i;i; i:1; I" compat; T; [ii;1o; ;i;i;i; i;1; I" compat; T; [ii<1o; ;i;i;i; i<1; I" compat; T; [ii=1o; ;i;i;i; i=1; I" compat; T; [ii>1o; ;i;i;i; i>1; I" compat; T; [ii?1o; ;i;i;i; i?1; I" compat; T; [ii@1o; ;i;i;i; i@1; I" compat; T; [iiA1o; ;i;i;i; iA1; I" compat; T; [iiB1o; ;i;i;i; iB1; I" compat; T; [iiC1o; ;i;i;i; iC1; I" compat; T; [iiD1o; ;i;i;i; iD1; I" compat; T; [i!iE1o; ;i;i;i; iE1; I" compat; T; [i iF1o; ;i;i;i; iF1; I" compat; T; [i iG1o; ;i;i;i; iG1; I" compat; T; [i iH1o; ;i;i;i; iH1; I" compat; T; [i iI1o; ;i;i;i; iI1; I" compat; T; [i iJ1o; ;i;i;i; iJ1; I" compat; T; [iiK1o; ;i;i;i; iK1; I" compat; T; [iiL1o; ;i;i;i; iL1; I" compat; T; [iiM1o; ;i;i;i; iM1; I" compat; T; [iiN1o; ;i;i;i; iN1; I" compat; T; [iiO1o; ;i;i;i; iO1; I" compat; T; [iaiP1o; ;i;i;i; iP1; I" compat; T; [ibiQ1o; ;i;i;i; iQ1; I" compat; T; [iciR1o; ;i;i;i; iR1; I" compat; T; [idiS1o; ;i;i;i; iS1; I" compat; T; [ieiT1o; ;i;i;i; iT1; I" compat; T; [ifiU1o; ;i;i;i; iU1; I" compat; T; [igiV1o; ;i;i;i; iV1; I" compat; T; [ihiW1o; ;i;i;i; iW1; I" compat; T; [iiiX1o; ;i;i;i; iX1; I" compat; T; [ijiY1o; ;i;i;i; iY1; I" compat; T; [ikiZ1o; ;i;i;i; iZ1; I" compat; T; [ili[1o; ;i;i;i; i[1; I" compat; T; [imi\1o; ;i;i;i; i\1; I" compat; T; [ini]1o; ;i;i;i; i]1; I" compat; T; [ioi^1o; ;i;i;i; i^1; I" compat; T; [ipi_1o; ;i;i;i; i_1; I" compat; T; [iqi`1o; ;i;i;i; i`1; I" compat; T; [iria1o; ;i;i;i; ia1; I" compat; T; [isib1o; ;i;i;i; ib1; I" compat; T; [itic1o; ;i;i;i; ic1; I" compat; T; [iuid1o; ;i;i;i; id1; I" compat; T; [i`ie1o; ;i;i;i; ie1; I" compat; T; [iif1o; ;i;i;i; if1; I" compat; T; [iig1o; ;i;i;i; ig1; I" compat; T; [iih1o; ;i;i;i; ih1; I" compat; T; [iii1o; ;i;i;i; ii1; I" compat; T; [iij1o; ;i;i;i; ij1; I" compat; T; [iik1o; ;i;i;i; ik1; I" compat; T; [iil1o; ;i;i;i; il1; I" compat; T; [iim1o; ;i;i;i; im1; I" compat; T; [iin1o; ;i;i;i; in1; I" compat; T; [iio1o; ;i;i;i; io1; I" compat; T; [iip1o; ;i;i;i; ip1; I" compat; T; [iiq1o; ;i;i;i; iq1; I" compat; T; [iir1o; ;i;i;i; ir1; I" compat; T; [iis1o; ;i;i;i; is1; I" compat; T; [i it1o; ;i;i;i; it1; I" compat; T; [i"iu1o; ;i;i;i; iu1; I" compat; T; [i#iv1o; ;i;i;i; iv1; I" compat; T; [i'iw1o; ;i;i;i; iw1; I" compat; T; [i)ix1o; ;i;i;i; ix1; I" compat; T; [i+iy1o; ;i;i;i; iy1; I" compat; T; [i,iz1o; ;i;i;i; iz1; I" compat; T; [i-i{1o; ;i;i;i; i{1; I" compat; T; [i.i|1o; ;i;i;i; i|1; I" compat; T; [i/i}1o; ;i;i;i; i}1; I" compat; T; [i2i~1o; ;i;i;i; i~1; I" compat; T; [i6i1o; ;i;i;i; i1; I" compat; T; [i@i1o; ;i;i;i; i1; I" compat; T; [iGi1o; ;i;i;i; i1; I" compat; T; [iLi1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [iWi1o; ;i;i;i; i1; I" compat; T; [iXi1o; ;i;i;i; i1; I" compat; T; [iYi1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; I" compat; T; [ii1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; I" super; T; [iNi1o; ;i;i;i; i1; I" super; T; [iNi1o; ;i;i;i; i1; I" super; T; [i Ni1o; ;i;i;i; i1; I" super; T; [iVi1o; ;i;i;i; i1; I" super; T; [i Ni1o; ;i;i;i; i1; I" super; T; [i-Ni1o; ;i;i;i; i1; I" super; T; [i Ni1o; ;i;i;i; i1; I" super; T; [i2ui1o; ;i;i;i; i1; I" super; T; [iYNi1o; ;i;i;i; i1; I" super; T; [iNi1o; ;i;i;i; i1; I" super; T; [iNi1o; ;i;i;i; i1; I" super; T; [i)Yi1o; ;i;i;i; i1; I" super; T; [i0Wi1o; ;i;i;i; i1; I" super; T; [iNi1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [i-i i.i2o; ;i;i;i; i2; I" compat; T; [i-i i.i2o; ;i;i;i; i2; I" compat; T; [i-i i.i 2o; ;i;i;i; i 2; I" compat; T; [i-ii.i 2o; ;i;i;i; i 2; I" compat; T; [i-ii.i 2o; ;i;i;i; i 2; I" compat; T; [i-ii.i 2o; ;i;i;i; i 2; I" compat; T; [i-ii.i 2o; ;i;i;i; i 2; I" compat; T; [i-ii.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-i iai.i2o; ;i;i;i; i2; I" compat; T; [ i-i iai.i2o; ;i;i;i; i2; I" compat; T; [ i-i iai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-iiai.i2o; ;i;i;i; i2; I" compat; T; [ i-i ini.i2o; ;i;i;i; i2; I" compat; T; [ i-i iii ieii.i2o; ;i;i;i; i2; I" compat; T; [ i-i iiiini.i 2o; ;i;i;i; i 2; I" compat; T; [i-iNi.i!2o; ;i;i;i; i!2; I" compat; T; [i-iNi.i"2o; ;i;i;i; i"2; I" compat; T; [i-i Ni.i#2o; ;i;i;i; i#2; I" compat; T; [i-iVi.i$2o; ;i;i;i; i$2; I" compat; T; [i-iNi.i%2o; ;i;i;i; i%2; I" compat; T; [i-imQi.i&2o; ;i;i;i; i&2; I" compat; T; [i-iNi.i'2o; ;i;i;i; i'2; I" compat; T; [i-ikQi.i(2o; ;i;i;i; i(2; I" compat; T; [i-i]Ni.i)2o; ;i;i;i; i)2; I" compat; T; [i-iASi.i*2o; ;i;i;i; i*2; I" compat; T; [i-igi.i+2o; ;i;i;i; i+2; I" compat; T; [i-ikpi.i,2o; ;i;i;i; i,2; I" compat; T; [i-i4li.i-2o; ;i;i;i; i-2; I" compat; T; [i-i(gi.i.2o; ;i;i;i; i.2; I" compat; T; [i-iёi.i/2o; ;i;i;i; i/2; I" compat; T; [i-iWi.i02o; ;i;i;i; i02; I" compat; T; [i-iei.i12o; ;i;i;i; i12; I" compat; T; [i-i*hi.i22o; ;i;i;i; i22; I" compat; T; [i-i gi.i32o; ;i;i;i; i32; I" compat; T; [i-i>yi.i42o; ;i;i;i; i42; I" compat; T; [i-i Ti.i52o; ;i;i;i; i52; I" compat; T; [i-iyri.i62o; ;i;i;i; i62; I" compat; T; [i-ii.i72o; ;i;i;i; i72; I" compat; T; [i-i]yi.i82o; ;i;i;i; i82; I" compat; T; [i-iRi.i92o; ;i;i;i; i92; I" compat; T; [i-iNi.i:2o; ;i;i;i; i:2; I" compat; T; [i-i|Ti.i;2o; ;i;i;i; i;2; I" compat; T; [i-if[i.i<2o; ;i;i;i; i<2; I" compat; T; [i-ivi.i=2o; ;i;i;i; i=2; I" compat; T; [i-iOi.i>2o; ;i;i;i; i>2; I" compat; T; [i-inji.i?2o; ;i;i;i; i?2; I" compat; T; [i-iTSi.i@2o; ;i;i;i; i@2; I" compat; T; [i-imyi.iA2o; ;i;i;i; iA2; I" compat; T; [i-iOi.iB2o; ;i;i;i; iB2; I" compat; T; [i-ii.iC2o; ;i;i;i; iC2; I" compat; T; [i-ii.iD2o; ;i;i;i; iD2; I" circle; T; [iOUiE2o; ;i;i;i; iE2; I" circle; T; [i|^iF2o; ;i;i;i; iF2; I" circle; T; [ieiG2o; ;i;i;i; iG2; I" circle; T; [i{iH2o; ;i;i;i; iH2; 0; 0iI2o; ;i;i;i; iI2; 0; 0iJ2o; ;i;i;i; iJ2; 0; 0iK2o; ;i;i;i; iK2; 0; 0iL2o; ;i;i;i; iL2; 0; 0iM2o; ;i;i;i; iM2; 0; 0iN2o; ;i;i;i; iN2; 0; 0iO2o; ;i;i;i; iO2; 0; 0iP2o; ;i;i;i; iP2; I" square; T; [iUiYiJiQ2o; ;i;i;i; iQ2; I" circle; T; [i7i6iR2o; ;i;i;i; iR2; I" circle; T; [i7i7iS2o; ;i;i;i; iS2; I" circle; T; [i7i8iT2o; ;i;i;i; iT2; I" circle; T; [i7i9iU2o; ;i;i;i; iU2; I" circle; T; [i7i:iV2o; ;i;i;i; iV2; I" circle; T; [i7i;iW2o; ;i;i;i; iW2; I" circle; T; [i7iiZ2o; ;i;i;i; iZ2; I" circle; T; [i8i5i[2o; ;i;i;i; i[2; I" circle; T; [i8i6i\2o; ;i;i;i; i\2; I" circle; T; [i8i7i]2o; ;i;i;i; i]2; I" circle; T; [i8i8i^2o; ;i;i;i; i^2; I" circle; T; [i8i9i_2o; ;i;i;i; i_2; I" circle; T; [i8i:i`2o; ;i;i;i; i`2; I" circle; T; [iia2o; ;i;i;i; ia2; I" circle; T; [iib2o; ;i;i;i; ib2; I" circle; T; [iic2o; ;i;i;i; ic2; I" circle; T; [iid2o; ;i;i;i; id2; I" circle; T; [iie2o; ;i;i;i; ie2; I" circle; T; [iif2o; ;i;i;i; if2; I" circle; T; [i ig2o; ;i;i;i; ig2; I" circle; T; [i ih2o; ;i;i;i; ih2; I" circle; T; [i ii2o; ;i;i;i; ii2; I" circle; T; [iij2o; ;i;i;i; ij2; I" circle; T; [iik2o; ;i;i;i; ik2; I" circle; T; [iil2o; ;i;i;i; il2; I" circle; T; [iim2o; ;i;i;i; im2; I" circle; T; [iin2o; ;i;i;i; in2; I" circle; T; [iiaio2o; ;i;i;i; io2; I" circle; T; [iiaip2o; ;i;i;i; ip2; I" circle; T; [iiaiq2o; ;i;i;i; iq2; I" circle; T; [iiair2o; ;i;i;i; ir2; I" circle; T; [iiais2o; ;i;i;i; is2; I" circle; T; [iiait2o; ;i;i;i; it2; I" circle; T; [i iaiu2o; ;i;i;i; iu2; I" circle; T; [i iaiv2o; ;i;i;i; iv2; I" circle; T; [i iaiw2o; ;i;i;i; iw2; I" circle; T; [iiaix2o; ;i;i;i; ix2; I" circle; T; [iiaiy2o; ;i;i;i; iy2; I" circle; T; [iiaiz2o; ;i;i;i; iz2; I" circle; T; [iiai{2o; ;i;i;i; i{2; I" circle; T; [iiai|2o; ;i;i;i; i|2; I" circle; T; [ iiaiiiii}2o; ;i;i;i; i}2; I" circle; T; [ i ini iti~2o; ;i;i;i; i~2; I" circle; T; [i ini2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; I" circle; T; [iNi2o; ;i;i;i; i2; I" circle; T; [iNi2o; ;i;i;i; i2; I" circle; T; [i Ni2o; ;i;i;i; i2; I" circle; T; [iVi2o; ;i;i;i; i2; I" circle; T; [iNi2o; ;i;i;i; i2; I" circle; T; [imQi2o; ;i;i;i; i2; I" circle; T; [iNi2o; ;i;i;i; i2; I" circle; T; [ikQi2o; ;i;i;i; i2; I" circle; T; [i]Ni2o; ;i;i;i; i2; I" circle; T; [iASi2o; ;i;i;i; i2; I" circle; T; [igi2o; ;i;i;i; i2; I" circle; T; [ikpi2o; ;i;i;i; i2; I" circle; T; [i4li2o; ;i;i;i; i2; I" circle; T; [i(gi2o; ;i;i;i; i2; I" circle; T; [iёi2o; ;i;i;i; i2; I" circle; T; [iWi2o; ;i;i;i; i2; I" circle; T; [iei2o; ;i;i;i; i2; I" circle; T; [i*hi2o; ;i;i;i; i2; I" circle; T; [i gi2o; ;i;i;i; i2; I" circle; T; [i>yi2o; ;i;i;i; i2; I" circle; T; [i Ti2o; ;i;i;i; i2; I" circle; T; [iyri2o; ;i;i;i; i2; I" circle; T; [ii2o; ;i;i;i; i2; I" circle; T; [i]yi2o; ;i;i;i; i2; I" circle; T; [iRi2o; ;i;i;i; i2; I" circle; T; [iyi2o; ;i;i;i; i2; I" circle; T; [i7ui2o; ;i;i;i; i2; I" circle; T; [isYi2o; ;i;i;i; i2; I" circle; T; [iii2o; ;i;i;i; i2; I" circle; T; [i*Qi2o; ;i;i;i; i2; I" circle; T; [ipSi2o; ;i;i;i; i2; I" circle; T; [ili2o; ;i;i;i; i2; I" circle; T; [ii2o; ;i;i;i; i2; I" circle; T; [iOi2o; ;i;i;i; i2; I" circle; T; [iQi2o; ;i;i;i; i2; I" circle; T; [icki2o; ;i;i;i; i2; I" circle; T; [i Ni2o; ;i;i;i; i2; I" circle; T; [i-Ni2o; ;i;i;i; i2; I" circle; T; [i Ni2o; ;i;i;i; i2; I" circle; T; [i]i2o; ;i;i;i; i2; I" circle; T; [iSi2o; ;i;i;i; i2; I" circle; T; [i;Si2o; ;i;i;i; i2; I" circle; T; [i[i2o; ;i;i;i; i2; I" circle; T; [if[i2o; ;i;i;i; i2; I" circle; T; [ivi2o; ;i;i;i; i2; I" circle; T; [iOi2o; ;i;i;i; i2; I" circle; T; [inji2o; ;i;i;i; i2; I" circle; T; [iTSi2o; ;i;i;i; i2; I" circle; T; [iYi2o; ;i;i;i; i2; I" circle; T; [i8i;i2o; ;i;i;i; i2; I" circle; T; [i8ii2o; ;i;i;i; i2; I" circle; T; [i9i5i2o; ;i;i;i; i2; I" circle; T; [i9i6i2o; ;i;i;i; i2; I" circle; T; [i9i7i2o; ;i;i;i; i2; I" circle; T; [i9i8i2o; ;i;i;i; i2; I" circle; T; [i9i9i2o; ;i;i;i; i2; I" circle; T; [i9i:i2o; ;i;i;i; i2; I" circle; T; [i9i;i2o; ;i;i;i; i2; I" circle; T; [i9ii2o; ;i;i;i; i2; I" circle; T; [i:i5i2o; ;i;i;i; i2; I" compat; T; [i6igi2o; ;i;i;i; i2; I" compat; T; [i7igi2o; ;i;i;i; i2; I" compat; T; [i8igi2o; ;i;i;i; i2; I" compat; T; [i9igi2o; ;i;i;i; i2; I" compat; T; [i:igi2o; ;i;i;i; i2; I" compat; T; [i;igi2o; ;i;i;i; i2; I" compat; T; [iigi2o; ;i;i;i; i2; I" compat; T; [i6i5igi2o; ;i;i;i; i2; I" compat; T; [i6i6igi2o; ;i;i;i; i2; I" compat; T; [i6i7igi2o; ;i;i;i; i2; I" square; T; [iMili2o; ;i;i;i; i2; I" square; T; [ijiwili2o; ;i;i;i; i2; I" square; T; [iji[i2o; ;i;i;i; i2; I" square; T; [iQiYiIi2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i2o; ;i;i;i; i2; I" circle; T; [i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [ i0i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [i0i0i0i3o; ;i;i;i; i3; I" square; T; [ i0i0i0i0i 3o; ;i;i;i; i 3; I" square; T; [ i0i0i0i0i0i!3o; ;i;i;i; i!3; I" square; T; [ i0i0i0i0i"3o; ;i;i;i; i"3; I" square; T; [i0i0i0i#3o; ;i;i;i; i#3; I" square; T; [i0i0i0i$3o; ;i;i;i; i$3; I" square; T; [i0i0i0i%3o; ;i;i;i; i%3; I" square; T; [i0i0i&3o; ;i;i;i; i&3; I" square; T; [i0i0i'3o; ;i;i;i; i'3; I" square; T; [i0i0i(3o; ;i;i;i; i(3; I" square; T; [i0i0i)3o; ;i;i;i; i)3; I" square; T; [i0i0i0i*3o; ;i;i;i; i*3; I" square; T; [i0i0i0i+3o; ;i;i;i; i+3; I" square; T; [ i0i0i0i0i0i,3o; ;i;i;i; i,3; I" square; T; [i0i0i0i-3o; ;i;i;i; i-3; I" square; T; [ i0i0i0i0i.3o; ;i;i;i; i.3; I" square; T; [ i0i0i0i0i0i/3o; ;i;i;i; i/3; I" square; T; [i0i0i0i03o; ;i;i;i; i03; I" square; T; [i0i0i13o; ;i;i;i; i13; I" square; T; [i0i0i23o; ;i;i;i; i23; I" square; T; [ i0i0i0i0i0i33o; ;i;i;i; i33; I" square; T; [ i0i0i0i0i43o; ;i;i;i; i43; I" square; T; [ i0i0i0i0i0i53o; ;i;i;i; i53; I" square; T; [i0i0i0i63o; ;i;i;i; i63; I" square; T; [ i0i0i0i0i0i73o; ;i;i;i; i73; I" square; T; [i0i0i83o; ;i;i;i; i83; I" square; T; [i0i0i0i93o; ;i;i;i; i93; I" square; T; [i0i0i0i:3o; ;i;i;i; i:3; I" square; T; [i0i0i0i;3o; ;i;i;i; i;3; I" square; T; [i0i0i0i<3o; ;i;i;i; i<3; I" square; T; [i0i0i0i=3o; ;i;i;i; i=3; I" square; T; [ i0i0i0i0i>3o; ;i;i;i; i>3; I" square; T; [i0i0i0i?3o; ;i;i;i; i?3; I" square; T; [i0i0i@3o; ;i;i;i; i@3; I" square; T; [i0i0i0iA3o; ;i;i;i; iA3; I" square; T; [i0i0i0iB3o; ;i;i;i; iB3; I" square; T; [i0i0i0iC3o; ;i;i;i; iC3; I" square; T; [ i0i0i0i0iD3o; ;i;i;i; iD3; I" square; T; [i0i0i0iE3o; ;i;i;i; iE3; I" square; T; [i0i0i0iF3o; ;i;i;i; iF3; I" square; T; [i0i0i0iG3o; ;i;i;i; iG3; I" square; T; [ i0i0i0i0i0iH3o; ;i;i;i; iH3; I" square; T; [ i0i0i0i0iI3o; ;i;i;i; iI3; I" square; T; [i0i0iJ3o; ;i;i;i; iJ3; I" square; T; [ i0i0i0i0i0iK3o; ;i;i;i; iK3; I" square; T; [i0i0iL3o; ;i;i;i; iL3; I" square; T; [ i0i0i0i0iM3o; ;i;i;i; iM3; I" square; T; [ i0i0i0i0iN3o; ;i;i;i; iN3; I" square; T; [i0i0i0iO3o; ;i;i;i; iO3; I" square; T; [i0i0i0iP3o; ;i;i;i; iP3; I" square; T; [i0i0i0iQ3o; ;i;i;i; iQ3; I" square; T; [ i0i0i0i0iR3o; ;i;i;i; iR3; I" square; T; [i0i0iS3o; ;i;i;i; iS3; I" square; T; [i0i0i0iT3o; ;i;i;i; iT3; I" square; T; [ i0i0i0i0iU3o; ;i;i;i; iU3; I" square; T; [i0i0iV3o; ;i;i;i; iV3; I" square; T; [ i0i0i0i0i0iW3o; ;i;i;i; iW3; I" square; T; [i0i0i0iX3o; ;i;i;i; iX3; I" compat; T; [i5ipiY3o; ;i;i;i; iY3; I" compat; T; [i6ipiZ3o; ;i;i;i; iZ3; I" compat; T; [i7ipi[3o; ;i;i;i; i[3; I" compat; T; [i8ipi\3o; ;i;i;i; i\3; I" compat; T; [i9ipi]3o; ;i;i;i; i]3; I" compat; T; [i:ipi^3o; ;i;i;i; i^3; I" compat; T; [i;ipi_3o; ;i;i;i; i_3; I" compat; T; [iipib3o; ;i;i;i; ib3; I" compat; T; [i6i5ipic3o; ;i;i;i; ic3; I" compat; T; [i6i6ipid3o; ;i;i;i; id3; I" compat; T; [i6i7ipie3o; ;i;i;i; ie3; I" compat; T; [i6i8ipif3o; ;i;i;i; if3; I" compat; T; [i6i9ipig3o; ;i;i;i; ig3; I" compat; T; [i6i:ipih3o; ;i;i;i; ih3; I" compat; T; [i6i;ipii3o; ;i;i;i; ii3; I" compat; T; [i6iipil3o; ;i;i;i; il3; I" compat; T; [i7i5ipim3o; ;i;i;i; im3; I" compat; T; [i7i6ipin3o; ;i;i;i; in3; I" compat; T; [i7i7ipio3o; ;i;i;i; io3; I" compat; T; [i7i8ipip3o; ;i;i;i; ip3; I" compat; T; [i7i9ipiq3o; ;i;i;i; iq3; I" square; T; [imiUifir3o; ;i;i;i; ir3; I" square; T; [iiifis3o; ;i;i;i; is3; I" square; T; [iFiZit3o; ;i;i;i; it3; I" square; T; [igifiwiu3o; ;i;i;i; iu3; I" square; T; [iti[iv3o; ;i;i;i; iv3; I" square; T; [iuihiw3o; ;i;i;i; iw3; I" square; T; [iiirix3o; ;i;i;i; ix3; I" square; T; [iiiriiy3o; ;i;i;i; iy3; I" square; T; [iiiriiz3o; ;i;i;i; iz3; I" square; T; [iNiZi{3o; ;i;i;i; i{3; I" square; T; [is^ibi|3o; ;i;i;i; i|3; I" square; T; [i-fiTi}3o; ;i;i;i; i}3; I" square; T; [i'Yicki~3o; ;i;i;i; i~3; I" square; T; [ifili3o; ;i;i;i; i3; I" square; T; [ i*hi_iOi>yi3o; ;i;i;i; i3; I" square; T; [iuiFi3o; ;i;i;i; i3; I" square; T; [isiFi3o; ;i;i;i; i3; I" square; T; [iiFi3o; ;i;i;i; i3; I" square; T; [iriFi3o; ;i;i;i; i3; I" square; T; [ipiFi3o; ;i;i;i; i3; I" square; T; [iPiGi3o; ;i;i;i; i3; I" square; T; [iRiGi3o; ;i;i;i; i3; I" square; T; [iLiGi3o; ;i;i;i; i3; I" square; T; [ihifiqi3o; ;i;i;i; i3; I" square; T; [ ipihifiqi3o; ;i;i;i; i3; I" square; T; [iuiKi3o; ;i;i;i; i3; I" square; T; [isiKi3o; ;i;i;i; i3; I" square; T; [iiKi3o; ;i;i;i; i3; I" square; T; [iili3o; ;i;i;i; i3; I" square; T; [irili3o; ;i;i;i; i3; I" square; T; [ipili3o; ;i;i;i; i3; I" square; T; [iMii3o; ;i;i;i; i3; I" square; T; [ipiMii3o; ;i;i;i; i3; I" square; T; [iRiMii3o; ;i;i;i; i3; I" square; T; [iLiMii3o; ;i;i;i; i3; I" square; T; [iYiMii3o; ;i;i;i; i3; I" square; T; [ii!i3o; ;i;i;i; i3; I" square; T; [iri!i3o; ;i;i;i; i3; I" square; T; [iii!i3o; ;i;i;i; i3; I" square; T; [ipi!i3o; ;i;i;i; i3; I" square; T; [ikiri3o; ;i;i;i; i3; I" square; T; [isiri3o; ;i;i;i; i3; I" square; T; [iiri3o; ;i;i;i; i3; I" square; T; [iriri3o; ;i;i;i; i3; I" square; T; [ihiri3o; ;i;i;i; i3; I" square; T; [ipiri3o; ;i;i;i; i3; I" square; T; [iririi3o; ;i;i;i; i3; I" square; T; [ihirii3o; ;i;i;i; i3; I" square; T; [irii3o; ;i;i;i; i3; I" square; T; [ipirii3o; ;i;i;i; i3; I" square; T; [iririi3o; ;i;i;i; i3; I" square; T; [ihirii3o; ;i;i;i; i3; I" square; T; [irii3o; ;i;i;i; i3; I" square; T; [ipirii3o; ;i;i;i; i3; I" square; T; [iri"ixi3o; ;i;i;i; i3; I" square; T; [ iri"ixii3o; ;i;i;i; i3; I" square; T; [iUifi3o; ;i;i;i; i3; I" square; T; [ipiUifi3o; ;i;i;i; i3; I" square; T; [iRiUifi3o; ;i;i;i; i3; I" square; T; [iLiUifi3o; ;i;i;i; i3; I" square; T; [iwifiii3o; ;i;i;i; i3; I" square; T; [ iwifiii"ixi3o; ;i;i;i; i3; I" square; T; [ iwifiii"ixii3o; ;i;i;i; i3; I" square; T; [iuixi3o; ;i;i;i; i3; I" square; T; [isixi3o; ;i;i;i; i3; I" square; T; [iixi3o; ;i;i;i; i3; I" square; T; [irixi3o; ;i;i;i; i3; I" square; T; [iui[i3o; ;i;i;i; i3; I" square; T; [isi[i3o; ;i;i;i; i3; I" square; T; [ii[i3o; ;i;i;i; i3; I" square; T; [iri[i3o; ;i;i;i; i3; I" square; T; [ipi[i3o; ;i;i;i; i3; I" square; T; [iRi[i3o; ;i;i;i; i3; I" square; T; [iui\i3o; ;i;i;i; i3; I" square; T; [isi\i3o; ;i;i;i; i3; I" square; T; [ii\i3o; ;i;i;i; i3; I" square; T; [iri\i3o; ;i;i;i; i3; I" square; T; [ipi\i3o; ;i;i;i; i3; I" square; T; [iRi\i3o; ;i;i;i; i3; I" square; T; [ipii3o; ;i;i;i; i3; I" square; T; [iRii3o; ;i;i;i; i3; I" square; T; [ ifi3iri3i3o; ;i;i;i; i3; I" square; T; [iGivi3o; ;i;i;i; i3; I" square; T; [ihihi3o; ;i;i;i; i3; I" square; T; [ihiii3o; ;i;i;i; i3; I" square; T; [ iHi"ipili3o; ;i;i;i; i3; I" square; T; [iHiti3i3o; ;i;i;i; i3; I" square; T; [iiiGi3o; ;i;i;i; i3; I" square; T; [iLi~i3o; ;i;i;i; i3; I" square; T; [imifi3o; ;i;i;i; i3; I" square; T; [iMiUi3o; ;i;i;i; i3; I" square; T; [inisi3o; ;i;i;i; i3; I" square; T; [iPiPi3o; ;i;i;i; i3; I" square; T; [iPiRi3o; ;i;i;i; i3; I" square; T; [ipiyi3o; ;i;i;i; i3; I" square; T; [iqiri3o; ;i;i;i; i3; I" square; T; [iqisi3o; ;i;i;i; i3; I" square; T; [iqitili3o; ;i;i;i; i3; I" square; T; [iqi}i3o; ;i;i;i; i3; I" square; T; [irigi3o; ;i;i;i; i3; I" square; T; [iriniqi3o; ;i;i;i; i3; I" square; T; [iritiqi3o; ;i;i;i; i3; I" square; T; [iUiMi3o; ;i;i;i; i3; I" square; T; [ iui3iri3i3o; ;i;i;i; i3; I" square; T; [iUiUiRi3o; ;i;i;i; i3; I" square; T; [iUiWi3o; ;i;i;i; i3; I" square; T; [ixiwi3o; ;i;i;i; i3; I" square; T; [iXi{i3o; ;i;i;i; i3; I" square; T; [i\igi3o; ;i;i;i; i3; I" square; T; [i[i"iri3o; ;i;i;i; i3; I" square; T; [iFi"iri3o; ;i;i;i; i3; I" compat; T; [i6iei3o; ;i;i;i; i3; I" compat; T; [i7iei3o; ;i;i;i; i3; I" compat; T; [i8iei3o; ;i;i;i; i3; I" compat; T; [i9iei3o; ;i;i;i; i3; I" compat; T; [i:iei3o; ;i;i;i; i3; I" compat; T; [i;iei3o; ;i;i;i; i3; I" compat; T; [iiei3o; ;i;i;i; i3; I" compat; T; [i6i5iei3o; ;i;i;i; i3; I" compat; T; [i6i6iei3o; ;i;i;i; i3; I" compat; T; [i6i7iei3o; ;i;i;i; i3; I" compat; T; [i6i8iei3o; ;i;i;i; i3; I" compat; T; [i6i9iei3o; ;i;i;i; i3; I" compat; T; [i6i:iei3o; ;i;i;i; i3; I" compat; T; [i6i;iei3o; ;i;i;i; i3; I" compat; T; [i6iiei3o; ;i;i;i; i3; I" compat; T; [i7i5iei3o; ;i;i;i; i3; I" compat; T; [i7i6iei3o; ;i;i;i; i3; I" compat; T; [i7i7iei3o; ;i;i;i; i3; I" compat; T; [i7i8iei3o; ;i;i;i; i3; I" compat; T; [i7i9iei3o; ;i;i;i; i3; I" compat; T; [i7i:iei3o; ;i;i;i; i3; I" compat; T; [i7i;iei3o; ;i;i;i; i3; I" compat; T; [i7iiei3o; ;i;i;i; i3; I" compat; T; [i8i5iei3o; ;i;i;i; i3; I" compat; T; [i8i6iei3o; ;i;i;i; i3; I" square; T; [ilifiqi4o; ;i;i;i; i4; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0i̟o; ;i;i;i; i̟; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0iào; ;i;i;i; ià; 0; 0iĠo; ;i;i;i; iĠ; 0; 0iŠo; ;i;i;i; iŠ; 0; 0iƠo; ;i;i;i; iƠ; 0; 0iǠo; ;i;i;i; iǠ; 0; 0iȠo; ;i;i;i; iȠ; 0; 0iɠo; ;i;i;i; iɠ; 0; 0iʠo; ;i;i;i; iʠ; 0; 0iˠo; ;i;i;i; iˠ; 0; 0i̠o; ;i;i;i; i̠; 0; 0i͠o; ;i;i;i; i͠; 0; 0iΠo; ;i;i;i; iΠ; 0; 0iϠo; ;i;i;i; iϠ; 0; 0iРo; ;i;i;i; iР; 0; 0iѠo; ;i;i;i; iѠ; 0; 0iҠo; ;i;i;i; iҠ; 0; 0iӠo; ;i;i;i; iӠ; 0; 0iԠo; ;i;i;i; iԠ; 0; 0iՠo; ;i;i;i; iՠ; 0; 0i֠o; ;i;i;i; i֠; 0; 0iנo; ;i;i;i; iנ; 0; 0iؠo; ;i;i;i; iؠ; 0; 0i٠o; ;i;i;i; i٠; 0; 0iڠo; ;i;i;i; iڠ; 0; 0i۠o; ;i;i;i; i۠; 0; 0iܠo; ;i;i;i; iܠ; 0; 0iݠo; ;i;i;i; iݠ; 0; 0iޠo; ;i;i;i; iޠ; 0; 0iߠo; ;i;i;i; iߠ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¡o; ;i;i;i; i¡; 0; 0iáo; ;i;i;i; iá; 0; 0iġo; ;i;i;i; iġ; 0; 0išo; ;i;i;i; iš; 0; 0iơo; ;i;i;i; iơ; 0; 0iǡo; ;i;i;i; iǡ; 0; 0iȡo; ;i;i;i; iȡ; 0; 0iɡo; ;i;i;i; iɡ; 0; 0iʡo; ;i;i;i; iʡ; 0; 0iˡo; ;i;i;i; iˡ; 0; 0i̡o; ;i;i;i; i̡; 0; 0i͡o; ;i;i;i; i͡; 0; 0iΡo; ;i;i;i; iΡ; 0; 0iϡo; ;i;i;i; iϡ; 0; 0iСo; ;i;i;i; iС; 0; 0iѡo; ;i;i;i; iѡ; 0; 0iҡo; ;i;i;i; iҡ; 0; 0iӡo; ;i;i;i; iӡ; 0; 0iԡo; ;i;i;i; iԡ; 0; 0iաo; ;i;i;i; iա; 0; 0i֡o; ;i;i;i; i֡; 0; 0iסo; ;i;i;i; iס; 0; 0iءo; ;i;i;i; iء; 0; 0i١o; ;i;i;i; i١; 0; 0iڡo; ;i;i;i; iڡ; 0; 0iۡo; ;i;i;i; iۡ; 0; 0iܡo; ;i;i;i; iܡ; 0; 0iݡo; ;i;i;i; iݡ; 0; 0iޡo; ;i;i;i; iޡ; 0; 0iߡo; ;i;i;i; iߡ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¢o; ;i;i;i; i¢; 0; 0iâo; ;i;i;i; iâ; 0; 0iĢo; ;i;i;i; iĢ; 0; 0iŢo; ;i;i;i; iŢ; 0; 0iƢo; ;i;i;i; iƢ; 0; 0iǢo; ;i;i;i; iǢ; 0; 0iȢo; ;i;i;i; iȢ; 0; 0iɢo; ;i;i;i; iɢ; 0; 0iʢo; ;i;i;i; iʢ; 0; 0iˢo; ;i;i;i; iˢ; 0; 0i̢o; ;i;i;i; i̢; 0; 0i͢o; ;i;i;i; i͢; 0; 0i΢o; ;i;i;i; i΢; 0; 0iϢo; ;i;i;i; iϢ; 0; 0iТo; ;i;i;i; iТ; 0; 0iѢo; ;i;i;i; iѢ; 0; 0iҢo; ;i;i;i; iҢ; 0; 0iӢo; ;i;i;i; iӢ; 0; 0iԢo; ;i;i;i; iԢ; 0; 0iբo; ;i;i;i; iբ; 0; 0i֢o; ;i;i;i; i֢; 0; 0iעo; ;i;i;i; iע; 0; 0iآo; ;i;i;i; iآ; 0; 0i٢o; ;i;i;i; i٢; 0; 0iڢo; ;i;i;i; iڢ; 0; 0iۢo; ;i;i;i; iۢ; 0; 0iܢo; ;i;i;i; iܢ; 0; 0iݢo; ;i;i;i; iݢ; 0; 0iޢo; ;i;i;i; iޢ; 0; 0iߢo; ;i;i;i; iߢ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i£o; ;i;i;i; i£; 0; 0ião; ;i;i;i; iã; 0; 0iģo; ;i;i;i; iģ; 0; 0iţo; ;i;i;i; iţ; 0; 0iƣo; ;i;i;i; iƣ; 0; 0iǣo; ;i;i;i; iǣ; 0; 0iȣo; ;i;i;i; iȣ; 0; 0iɣo; ;i;i;i; iɣ; 0; 0iʣo; ;i;i;i; iʣ; 0; 0iˣo; ;i;i;i; iˣ; 0; 0ịo; ;i;i;i; ị; 0; 0iͣo; ;i;i;i; iͣ; 0; 0iΣo; ;i;i;i; iΣ; 0; 0iϣo; ;i;i;i; iϣ; 0; 0iУo; ;i;i;i; iУ; 0; 0iѣo; ;i;i;i; iѣ; 0; 0iңo; ;i;i;i; iң; 0; 0iӣo; ;i;i;i; iӣ; 0; 0iԣo; ;i;i;i; iԣ; 0; 0iգo; ;i;i;i; iգ; 0; 0i֣o; ;i;i;i; i֣; 0; 0iףo; ;i;i;i; iף; 0; 0iأo; ;i;i;i; iأ; 0; 0i٣o; ;i;i;i; i٣; 0; 0iڣo; ;i;i;i; iڣ; 0; 0iۣo; ;i;i;i; iۣ; 0; 0iܣo; ;i;i;i; iܣ; 0; 0iݣo; ;i;i;i; iݣ; 0; 0iޣo; ;i;i;i; iޣ; 0; 0iߣo; ;i;i;i; iߣ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¤o; ;i;i;i; i¤; 0; 0iäo; ;i;i;i; iä; 0; 0iĤo; ;i;i;i; iĤ; 0; 0iŤo; ;i;i;i; iŤ; 0; 0iƤo; ;i;i;i; iƤ; 0; 0iФo; ;i;i;i; iФ; 0; 0iѤo; ;i;i;i; iѤ; 0; 0iҤo; ;i;i;i; iҤ; 0; 0iӤo; ;i;i;i; iӤ; 0; 0iԤo; ;i;i;i; iԤ; 0; 0iդo; ;i;i;i; iդ; 0; 0i֤o; ;i;i;i; i֤; 0; 0iפo; ;i;i;i; iפ; 0; 0iؤo; ;i;i;i; iؤ; 0; 0i٤o; ;i;i;i; i٤; 0; 0iڤo; ;i;i;i; iڤ; 0; 0iۤo; ;i;i;i; iۤ; 0; 0iܤo; ;i;i;i; iܤ; 0; 0iݤo; ;i;i;i; iݤ; 0; 0iޤo; ;i;i;i; iޤ; 0; 0iߤo; ;i;i;i; iߤ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¥o; ;i;i;i; i¥; 0; 0iåo; ;i;i;i; iå; 0; 0iĥo; ;i;i;i; iĥ; 0; 0iťo; ;i;i;i; iť; 0; 0iƥo; ;i;i;i; iƥ; 0; 0iǥo; ;i;i;i; iǥ; 0; 0iȥo; ;i;i;i; iȥ; 0; 0iɥo; ;i;i;i; iɥ; 0; 0iʥo; ;i;i;i; iʥ; 0; 0i˥o; ;i;i;i; i˥; 0; 0i̥o; ;i;i;i; i̥; 0; 0iͥo; ;i;i;i; iͥ; 0; 0iΥo; ;i;i;i; iΥ; 0; 0iϥo; ;i;i;i; iϥ; 0; 0iХo; ;i;i;i; iХ; 0; 0iѥo; ;i;i;i; iѥ; 0; 0iҥo; ;i;i;i; iҥ; 0; 0iӥo; ;i;i;i; iӥ; 0; 0iԥo; ;i;i;i; iԥ; 0; 0iեo; ;i;i;i; iե; 0; 0i֥o; ;i;i;i; i֥; 0; 0iץo; ;i;i;i; iץ; 0; 0iإo; ;i;i;i; iإ; 0; 0i٥o; ;i;i;i; i٥; 0; 0iڥo; ;i;i;i; iڥ; 0; 0iۥo; ;i;i;i; iۥ; 0; 0iܥo; ;i;i;i; iܥ; 0; 0iݥo; ;i;i;i; iݥ; 0; 0iޥo; ;i;i;i; iޥ; 0; 0iߥo; ;i;i;i; iߥ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i@o; ;i;i;iA; i@; 0; 0iAo; ;i;i@;i; iA; 0; 0iBo; ;i;i;iC; iB; 0; 0iCo; ;i;iB;i; iC; 0; 0iDo; ;i;i;iE; iD; 0; 0iEo; ;i;iD;i; iE; 0; 0iFo; ;i;i;iG; iF; 0; 0iGo; ;i;iF;i; iG; 0; 0iHo; ;i;i;iI; iH; 0; 0iIo; ;i;iH;i; iI; 0; 0iJo; ;i;i;iK; iJ; 0; 0iKo; ;i;iJ;i; iK; 0; 0iLo; ;i;i;iM; iL; 0; 0iMo; ;i;iL;i; iM; 0; 0iNo; ;i;i;iO; iN; 0; 0iOo; ;i;iN;i; iO; 0; 0iPo; ;i;i;iQ; iP; 0; 0iQo; ;i;iP;i; iQ; 0; 0iRo; ;i;i;iS; iR; 0; 0iSo; ;i;iR;i; iS; 0; 0iTo; ;i;i;iU; iT; 0; 0iUo; ;i;iT;i; iU; 0; 0iVo; ;i;i;iW; iV; 0; 0iWo; ;i;iV;i; iW; 0; 0iXo; ;i;i;iY; iX; 0; 0iYo; ;i;iX;i; iY; 0; 0iZo; ;i;i;i[; iZ; 0; 0i[o; ;i;iZ;i; i[; 0; 0i\o; ;i;i;i]; i\; 0; 0i]o; ;i;i\;i; i]; 0; 0i^o; ;i;i;i_; i^; 0; 0i_o; ;i;i^;i; i_; 0; 0i`o; ;i;i;ia; i`; 0; 0iao; ;i;i`;i; ia; 0; 0ibo; ;i;i;ic; ib; 0; 0ico; ;i;ib;i; ic; 0; 0ido; ;i;i;ie; id; 0; 0ieo; ;i;id;i; ie; 0; 0ifo; ;i;i;ig; if; 0; 0igo; ;i;if;i; ig; 0; 0iho; ;i;i;ii; ih; 0; 0iio; ;i;ih;i; ii; 0; 0ijo; ;i;i;ik; ij; 0; 0iko; ;i;ij;i; ik; 0; 0ilo; ;i;i;im; il; 0; 0imo; ;i;il;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¦o; ;i;i;i; i¦; 0; 0iæo; ;i;i;i; iæ; 0; 0iĦo; ;i;i;i; iĦ; 0; 0iŦo; ;i;i;i; iŦ; 0; 0iƦo; ;i;i;i; iƦ; 0; 0iǦo; ;i;i;i; iǦ; 0; 0iȦo; ;i;i;i; iȦ; 0; 0iɦo; ;i;i;i; iɦ; 0; 0iʦo; ;i;i;i; iʦ; 0; 0i˦o; ;i;i;i; i˦; 0; 0i̦o; ;i;i;i; i̦; 0; 0iͦo; ;i;i;i; iͦ; 0; 0iΦo; ;i;i;i; iΦ; 0; 0iϦo; ;i;i;i; iϦ; 0; 0iЦo; ;i;i;i; iЦ; 0; 0iѦo; ;i;i;i; iѦ; 0; 0iҦo; ;i;i;i; iҦ; 0; 0iӦo; ;i;i;i; iӦ; 0; 0iԦo; ;i;i;i; iԦ; 0; 0iզo; ;i;i;i; iզ; 0; 0i֦o; ;i;i;i; i֦; 0; 0iצo; ;i;i;i; iצ; 0; 0iئo; ;i;i;i; iئ; 0; 0i٦o; ;i;i;i; i٦; 0; 0iڦo; ;i;i;i; iڦ; 0; 0iۦo; ;i;i;i; iۦ; 0; 0iܦo; ;i;i;i; iܦ; 0; 0iݦo; ;i;i;i; iݦ; 0; 0iަo; ;i;i;i; iަ; 0; 0iߦo; ;i;i;i; iߦ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i#; i"; 0; 0i#o; ;i;i";i; i#; 0; 0i$o; ;i;i;i%; i$; 0; 0i%o; ;i;i$;i; i%; 0; 0i&o; ;i;i;i'; i&; 0; 0i'o; ;i;i&;i; i'; 0; 0i(o; ;i;i;i); i(; 0; 0i)o; ;i;i(;i; i); 0; 0i*o; ;i;i;i+; i*; 0; 0i+o; ;i;i*;i; i+; 0; 0i,o; ;i;i;i-; i,; 0; 0i-o; ;i;i,;i; i-; 0; 0i.o; ;i;i;i/; i.; 0; 0i/o; ;i;i.;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i3; i2; 0; 0i3o; ;i;i2;i; i3; 0; 0i4o; ;i;i;i5; i4; 0; 0i5o; ;i;i4;i; i5; 0; 0i6o; ;i;i;i7; i6; 0; 0i7o; ;i;i6;i; i7; 0; 0i8o; ;i;i;i9; i8; 0; 0i9o; ;i;i8;i; i9; 0; 0i:o; ;i;i;i;; i:; 0; 0i;o; ;i;i:;i; i;; 0; 0io; ;i;i;i?; i>; 0; 0i?o; ;i;i>;i; i?; 0; 0i@o; ;i;i;iA; i@; 0; 0iAo; ;i;i@;i; iA; 0; 0iBo; ;i;i;iC; iB; 0; 0iCo; ;i;iB;i; iC; 0; 0iDo; ;i;i;iE; iD; 0; 0iEo; ;i;iD;i; iE; 0; 0iFo; ;i;i;iG; iF; 0; 0iGo; ;i;iF;i; iG; 0; 0iHo; ;i;i;iI; iH; 0; 0iIo; ;i;iH;i; iI; 0; 0iJo; ;i;i;iK; iJ; 0; 0iKo; ;i;iJ;i; iK; 0; 0iLo; ;i;i;iM; iL; 0; 0iMo; ;i;iL;i; iM; 0; 0iNo; ;i;i;iO; iN; 0; 0iOo; ;i;iN;i; iO; 0; 0iPo; ;i;i;iQ; iP; 0; 0iQo; ;i;iP;i; iQ; 0; 0iRo; ;i;i;iS; iR; 0; 0iSo; ;i;iR;i; iS; 0; 0iTo; ;i;i;iU; iT; 0; 0iUo; ;i;iT;i; iU; 0; 0iVo; ;i;i;iW; iV; 0; 0iWo; ;i;iV;i; iW; 0; 0iXo; ;i;i;iY; iX; 0; 0iYo; ;i;iX;i; iY; 0; 0iZo; ;i;i;i[; iZ; 0; 0i[o; ;i;iZ;i; i[; 0; 0i\o; ;i;i;i]; i\; 0; 0i]o; ;i;i\;i; i]; 0; 0i^o; ;i;i;i_; i^; 0; 0i_o; ;i;i^;i; i_; 0; 0i`o; ;i;i;ia; i`; 0; 0iao; ;i;i`;i; ia; 0; 0ibo; ;i;i;ic; ib; 0; 0ico; ;i;ib;i; ic; 0; 0ido; ;i;i;ie; id; 0; 0ieo; ;i;id;i; ie; 0; 0ifo; ;i;i;ig; if; 0; 0igo; ;i;if;i; ig; 0; 0iho; ;i;i;ii; ih; 0; 0iio; ;i;ih;i; ii; 0; 0ijo; ;i;i;ik; ij; 0; 0iko; ;i;ij;i; ik; 0; 0ilo; ;i;i;im; il; 0; 0imo; ;i;il;i; im; 0; 0ino; ;i;i;io; in; 0; 0ioo; ;i;in;i; io; 0; 0ipo; ;i;i;i; ip; I" super; T; [ioiqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;iz; iy; 0; 0izo; ;i;iy;i; iz; 0; 0i{o; ;i;i;i|; i{; 0; 0i|o; ;i;i{;i; i|; 0; 0i}o; ;i;i;iy; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i~;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;ie; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;if; i; 0; 0io; ;i;i;i; i; I" super; T; [i&io; ;i;i;i; i; I" super; T; [iSio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i¨o; ;i;i;i; i¨; 0; 0ièo; ;i;i;i; iè; 0; 0iĨo; ;i;i;i; iĨ; 0; 0iΨo; ;i;i;i; iΨ; 0; 0iϨo; ;i;i;i; iϨ; 0; 0iШo; ;i;i;i; iШ; 0; 0iѨo; ;i;i;i; iѨ; 0; 0iҨo; ;i;i;i; iҨ; 0; 0iӨo; ;i;i;i; iӨ; 0; 0iԨo; ;i;i;i; iԨ; 0; 0iըo; ;i;i;i; iը; 0; 0i֨o; ;i;i;i; i֨; 0; 0iרo; ;i;i;i; iר; 0; 0iبo; ;i;i;i; iب; 0; 0i٨o; ;i;i;i; i٨; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i ;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i©o; ;i;i;i; i©; 0; 0iéo; ;i;i;i; ié; 0; 0iĩo; ;i;i;i; iĩ; 0; 0iũo; ;i;i;i; iũ; 0; 0iƩo; ;i;i;i; iƩ; 0; 0iǩo; ;i;i;i; iǩ; 0; 0iȩo; ;i;i;i; iȩ; 0; 0iɩo; ;i;i;i; iɩ; 0; 0iʩo; ;i;i;i; iʩ; 0; 0i˩o; ;i;i;i; i˩; 0; 0i̩o; ;i;i;i; i̩; 0; 0iͩo; ;i;i;i; iͩ; 0; 0iϩo; ;i;i;i; iϩ; 0; 0iЩo; ;i;i;i; iЩ; 0; 0iѩo; ;i;i;i; iѩ; 0; 0iҩo; ;i;i;i; iҩ; 0; 0iөo; ;i;i;i; iө; 0; 0iԩo; ;i;i;i; iԩ; 0; 0iթo; ;i;i;i; iթ; 0; 0i֩o; ;i;i;i; i֩; 0; 0iשo; ;i;i;i; iש; 0; 0iةo; ;i;i;i; iة; 0; 0i٩o; ;i;i;i; i٩; 0; 0iީo; ;i;i;i; iީ; 0; 0iߩo; ;i;i;i; iߩ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0iªo; ;i;i;i; iª; 0; 0i۪o; ;i;i;i; i۪; 0; 0iܪo; ;i;i;i; iܪ; 0; 0iݪo; ;i;i;i; iݪ; 0; 0iުo; ;i;i;i; iު; 0; 0iߪo; ;i;i;i; iߪ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i«o; ;i;i;i; i«; 0; 0iëo; ;i;i;i; ië; 0; 0iīo; ;i;i;i; iī; 0; 0iūo; ;i;i;i; iū; 0; 0iƫo; ;i;i;i; iƫ; 0; 0iǫo; ;i;i;i; iǫ; 0; 0iȫo; ;i;i;i; iȫ; 0; 0iɫo; ;i;i;i; iɫ; 0; 0iʫo; ;i;i;i; iʫ; 0; 0i˫o; ;i;i;i; i˫; 0; 0i̫o; ;i;i;i; i̫; 0; 0iͫo; ;i;i;i; iͫ; 0; 0iΫo; ;i;i;i; iΫ; 0; 0iϫo; ;i;i;i; iϫ; 0; 0iЫo; ;i;i;i; iЫ; 0; 0iѫo; ;i;i;i; iѫ; 0; 0iҫo; ;i;i;i; iҫ; 0; 0iӫo; ;i;i;i; iӫ; 0; 0iԫo; ;i;i;i; iԫ; 0; 0iիo; ;i;i;i; iի; 0; 0i֫o; ;i;i;i; i֫; 0; 0i׫o; ;i;i;i; i׫; 0; 0iثo; ;i;i;i; iث; 0; 0i٫o; ;i;i;i; i٫; 0; 0iګo; ;i;i;i; iګ; 0; 0i۫o; ;i;i;i; i۫; 0; 0iܫo; ;i;i;i; iܫ; 0; 0iݫo; ;i;i;i; iݫ; 0; 0iޫo; ;i;i;i; iޫ; 0; 0i߫o; ;i;i;i; i߫; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iHio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [iʎio; ;i;i;i; i; 0; [iȌio; ;i;i;i; i; 0; [inio; ;i;i;i; i; 0; [i2Nio; ;i;i;i; i; 0; [iSio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ii o; ;i;i;i; i ; 0; [iQYi o; ;i;i;i; i ; 0; [iёi o; ;i;i;i; i ; 0; [iUi o; ;i;i;i; i ; 0; [iHYi o; ;i;i;i; i ; 0; [iaio; ;i;i;i; i; 0; [iivio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i?io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [isio; ;i;i;i; i; 0; [i=io; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iNio; ;i;i;i; i; 0; [iuSio; ;i;i;i; i; 0; [ikio; ;i;i;i; i; 0; [irio; ;i;i;i; i; 0; [i-i o; ;i;i;i; i ; 0; [ii!o; ;i;i;i; i!; 0; [iP]i"o; ;i;i;i; i"; 0; [ioi#o; ;i;i;i; i#; 0; [iͅi$o; ;i;i;i; i$; 0; [idi%o; ;i;i;i; i%; 0; [ibi&o; ;i;i;i; i&; 0; [i؁i'o; ;i;i;i; i'; 0; [ii(o; ;i;i;i; i(; 0; [i^i)o; ;i;i;i; i); 0; [igi*o; ;i;i;i; i*; 0; [ijmi+o; ;i;i;i; i+; 0; [iri,o; ;i;i;i; i,; 0; [iΐi-o; ;i;i;i; i-; 0; [iOi.o; ;i;i;i; i.; 0; [iQi/o; ;i;i;i; i/; 0; [iRi0o; ;i;i;i; i0; 0; [idi1o; ;i;i;i; i1; 0; [iji2o; ;i;i;i; i2; 0; [iri3o; ;i;i;i; i3; 0; [ivi4o; ;i;i;i; i4; 0; [ii5o; ;i;i;i; i5; 0; [ii6o; ;i;i;i; i6; 0; [i\i7o; ;i;i;i; i7; 0; [ii8o; ;i;i;i; i8; 0; [i2i9o; ;i;i;i; i9; 0; [ioi:o; ;i;i;i; i:; 0; [ii;o; ;i;i;i; i;; 0; [ixio; ;i;i;i; i>; 0; [iɃi?o; ;i;i;i; i?; 0; [ii@o; ;i;i;i; i@; 0; [iiAo; ;i;i;i; iA; 0; [i֊iBo; ;i;i;i; iB; 0; [iXiCo; ;i;i;i; iC; 0; [i_iDo; ;i;i;i; iD; 0; [i`|iEo; ;i;i;i; iE; 0; [i~iFo; ;i;i;i; iF; 0; [ibriGo; ;i;i;i; iG; 0; [ixiHo; ;i;i;i; iH; 0; [iŒiIo; ;i;i;i; iI; 0; [iiJo; ;i;i;i; iJ; 0; [iXiKo; ;i;i;i; iK; 0; [ib\iLo; ;i;i;i; iL; 0; [ijiMo; ;i;i;i; iM; 0; [imiNo; ;i;i;i; iN; 0; [ioiOo; ;i;i;i; iO; 0; [i/}iPo; ;i;i;i; iP; 0; [i7~iQo; ;i;i;i; iQ; 0; [iKiRo; ;i;i;i; iR; 0; [iRiSo; ;i;i;i; iS; 0; [iiTo; ;i;i;i; iT; 0; [iQiUo; ;i;i;i; iU; 0; [iQiVo; ;i;i;i; iV; 0; [iziWo; ;i;i;i; iW; 0; [i}iXo; ;i;i;i; iX; 0; [iiYo; ;i;i;i; iY; 0; [iuiZo; ;i;i;i; iZ; 0; [ii[o; ;i;i;i; i[; 0; [ibi\o; ;i;i;i; i\; 0; [iji]o; ;i;i;i; i]; 0; [ii^o; ;i;i;i; i^; 0; [i9Ni_o; ;i;i;i; i_; 0; [i[i`o; ;i;i;i; i`; 0; [i`iao; ;i;i;i; ia; 0; [isibo; ;i;i;i; ib; 0; [ipuico; ;i;i;i; ic; 0; [iSido; ;i;i;i; id; 0; [ixieo; ;i;i;i; ie; 0; [iOifo; ;i;i;i; if; 0; [i_igo; ;i;i;i; ig; 0; [i Niho; ;i;i;i; ih; 0; [iliio; ;i;i;i; ii; 0; [ixeijo; ;i;i;i; ij; 0; [i"}iko; ;i;i;i; ik; 0; [iSilo; ;i;i;i; il; 0; [i^Ximo; ;i;i;i; im; 0; [iwino; ;i;i;i; in; 0; [iIioo; ;i;i;i; io; 0; [iipo; ;i;i;i; ip; 0; [ikiqo; ;i;i;i; iq; 0; [iiro; ;i;i;i; ir; 0; [iliso; ;i;i;i; is; 0; [ibito; ;i;i;i; it; 0; [iiuo; ;i;i;i; iu; 0; [icivo; ;i;i;i; iv; 0; [ieuiwo; ;i;i;i; iw; 0; [iNixo; ;i;i;i; ix; 0; [iiQiyo; ;i;i;i; iy; 0; [iQizo; ;i;i;i; iz; 0; [ihi{o; ;i;i;i; i{; 0; [i|i|o; ;i;i;i; i|; 0; [ioi}o; ;i;i;i; i}; 0; [iҊi~o; ;i;i;i; i~; 0; [iϑio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [iBTio; ;i;i;i; i; 0; [isYio; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [ieio; ;i;i;i; i; 0; [ioio; ;i;i;i; i; 0; [i*yio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iΞio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [iwkio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [it^io; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [idio; ;i;i;i; i; 0; [i#oio; ;i;i;i; i; 0; [iIqio; ;i;i;i; i; 0; [itio; ;i;i;i; i; 0; [iyio; ;i;i;i; i; 0; [i}io; ;i;i;i; i; 0; [ioio; ;i;i;i; i; 0; [i&io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i#io; ;i;i;i; i; 0; [iJio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [iTio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [iˆio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i{cio; ;i;i;i; i; 0; [ikio; ;i;i;i; i; 0; [i>|io; ;i;i;i; i; 0; [iusio; ;i;i;i; i; 0; [iNio; ;i;i;i; i; 0; [iVio; ;i;i;i; i; 0; [i[io; ;i;i;i; i; 0; [i]io; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [isio; ;i;i;i; i; 0; [iitio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iFio; ;i;i;i; i; 0; [i4io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iHio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iOio; ;i;i;i; i; 0; [iyio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [iNio; ;i;i;i; i; 0; [iPio; ;i;i;i; i; 0; [i[io; ;i;i;i; i; 0; [i?\io; ;i;i;i; i; 0; [ieio; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [iqio; ;i;i;i; i; 0; [iBvio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i|io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [i.io; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [i{gio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [iAmio; ;i;i;i; i; 0; [inio; ;i;i;i; i; 0; [i tio; ;i;i;i; i; 0; [iYuio; ;i;i;i; i; 0; [ikxio; ;i;i;i; i; 0; [i}io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [imQio; ;i;i;i; i; 0; [i.bio; ;i;i;i; i; 0; [ixio; ;i;i;i; i; 0; [i+Pio; ;i;i;i; i; 0; [i]io; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [i*io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [iDaio; ;i;i;i; i; 0; [ihio; ;i;i;i; i; 0; [isio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i)Rio; ;i;i;i; i; 0; [iTio; ;i;i;i; i; 0; [ie\io; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [iNgio; ;i;i;i; i; 0; [ihio; ;i;i;i; i; 0; [ilio; ;i;i;i; i; 0; [itio; ;i;i;i; i; 0; [iuio; ;i;i;i; i; 0; [iyio; ;i;i;i; i; 0; [iψio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ȋio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i?Sio; ;i;i;i; i; 0; [inio; ;i;i;i; i; 0; [iTio; ;i;i;i; i; 0; [iqio; ;i;i;i; i; 0; [itio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iWio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [izio; ;i;i;i; i; 0; [i {io; ;i;i;i; i; 0; [i|io; ;i;i;i; i; 0; [irio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [iXio; ;i;i;i; i; 0; [iNio; ;i;i;i; i; 0; [i6io; ;i;i;i; i; 0; [i:Rio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [i|io; ;i;i;i; i; 0; [i[io; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [iLi o; ;i;i;i; i ; 0; [iMi o; ;i;i;i; i ; 0; [ii o; ;i;i;i; i ; 0; [i^i o; ;i;i;i; i ; 0; [i@Qi o; ;i;i;i; i ; 0; [iUio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iZXio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [itfio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [i*sio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [io; ;i;i;i; i>; 0; [ihai?o; ;i;i;i; i?; 0; [iai@o; ;i;i;i; i@; 0; [iaiAo; ;i;i;i; iA; 0; [iOeiBo; ;i;i;i; iB; 0; [ieiCo; ;i;i;i; iC; 0; [ifiDo; ;i;i;i; iD; 0; [ihiEo; ;i;i;i; iE; 0; [iwmiFo; ;i;i;i; iF; 0; [iniGo; ;i;i;i; iG; 0; [i"oiHo; ;i;i;i; iH; 0; [inqiIo; ;i;i;i; iI; 0; [i+riJo; ;i;i;i; iJ; 0; [i"tiKo; ;i;i;i; iK; 0; [ixiLo; ;i;i;i; iL; 0; [i>yiMo; ;i;i;i; iM; 0; [iIyiNo; ;i;i;i; iN; 0; [iHyiOo; ;i;i;i; iO; 0; [iPyiPo; ;i;i;i; iP; 0; [iVyiQo; ;i;i;i; iQ; 0; [i]yiRo; ;i;i;i; iR; 0; [iyiSo; ;i;i;i; iS; 0; [iyiTo; ;i;i;i; iT; 0; [i@ziUo; ;i;i;i; iU; 0; [iziVo; ;i;i;i; iV; 0; [i{iWo; ;i;i;i; iW; 0; [i}iXo; ;i;i;i; iX; 0; [i ~iYo; ;i;i;i; iY; 0; [iA~iZo; ;i;i;i; iZ; 0; [iri[o; ;i;i;i; i[; 0; [ii\o; ;i;i;i; i\; 0; [ii]o; ;i;i;i; i]; 0; [iyi^o; ;i;i;i; i^; 0; [iyi_o; ;i;i;i; i_; 0; [iWi`o; ;i;i;i; i`; 0; [iiao; ;i;i;i; ia; 0; [iibo; ;i;i;i; ib; 0; [iico; ;i;i;i; ic; 0; [i9ido; ;i;i;i; id; 0; [iӌieo; ;i;i;i; ie; 0; [iifo; ;i;i;i; if; 0; [iigo; ;i;i;i; ig; 0; [i8iho; ;i;i;i; ih; 0; [iiio; ;i;i;i; ii; 0; [iijo; ;i;i;i; ij; 0; [i;iko; ;i;i;i; ik; 0; [iu`ilo; ;i;i;i; il; 0; [iBimo; ;i;i;i; im; 0; [iipo; ;i;i;i; ip; 0; [i&Niqo; ;i;i;i; iq; 0; [iQiro; ;i;i;i; ir; 0; [ihQiso; ;i;i;i; is; 0; [iOito; ;i;i;i; it; 0; [iEQiuo; ;i;i;i; iu; 0; [iQivo; ;i;i;i; iv; 0; [iRiwo; ;i;i;i; iw; 0; [iRixo; ;i;i;i; ix; 0; [iUiyo; ;i;i;i; iy; 0; [iUUizo; ;i;i;i; iz; 0; [iUi{o; ;i;i;i; i{; 0; [iUi|o; ;i;i;i; i|; 0; [iZXi}o; ;i;i;i; i}; 0; [iXi~o; ;i;i;i; i~; 0; [iDYio; ;i;i;i; i; 0; [iTYio; ;i;i;i; i; 0; [ibZio; ;i;i;i; i; 0; [i([io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [ii_io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [iNaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [i`aio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [i4bio; ;i;i;i; i; 0; [icio; ;i;i;i; i; 0; [idio; ;i;i;i; i; 0; [iRdio; ;i;i;i; i; 0; [iVeio; ;i;i;i; i; 0; [itfio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [iVgio; ;i;i;i; i; 0; [iykio; ;i;i;i; i; 0; [ikio; ;i;i;i; i; 0; [iAmio; ;i;i;i; i; 0; [inio; ;i;i;i; i; 0; [inio; ;i;i;i; i; 0; [i"oio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [inqio; ;i;i;i; i; 0; [iwio; ;i;i;i; i; 0; [i5rio; ;i;i;i; i; 0; [irio; ;i;i;i; i; 0; [i*sio; ;i;i;i; i; 0; [iqtio; ;i;i;i; i; 0; [iuio; ;i;i;i; i; 0; [i;uio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [iJwio; ;i;i;i; i; 0; [i@wio; ;i;i;i; i; 0; [ixio; ;i;i;i; i; 0; [izio; ;i;i;i; i; 0; [i{io; ;i;i;i; i; 0; [i{|io; ;i;i;i; i; 0; [i[}io; ;i;i;i; i; 0; [i}io; ;i;i;i; i; 0; [i>io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iyio; ;i;i;i; i; 0; [iAio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iˊio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i9io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i8io; ;i;i;i; i; 0; [irio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ivio; ;i;i;i; i; 0; [i|io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iVio; ;i;i;i; i; 0; [iۗio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i io; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iJ(io; ;i;i;i; i; 0; [iD(io; ;i;i;i; i; 0; [i3io; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [i@io; ;i;i;i; i; 0; [i9@io; ;i;i;i; i; 0; [iIRio; ;i;i;i; i; 0; [i\io; ;i;i;i; i; 0; [i~io; ;i;i;i; i; 0; [iCio; ;i;i;i; i; 0; [iio; ;i;i;i; i; I" compat; T; [ikikio; ;i;i;i; i; I" compat; T; [ikinio; ;i;i;i; i; I" compat; T; [ikiqio; ;i;i;i; i; I" compat; T; [ikikinio; ;i;i;i; i; I" compat; T; [ikikiqio; ;i;i;i; i; I" compat; T; [iiyio; ;i;i;i; i; I" compat; T; [ixiyio; ;i;i;i; i; I" compat; T; [itivio; ;i;i;i; i; I" compat; T; [itieio; ;i;i;i; i; I" compat; T; [itikio; ;i;i;i; i; I" compat; T; [i~ivio; ;i;i;i; i; I" compat; T; [itimio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iii o; ;i;i;i; i ; I" font; T; [ii!o; ;i;i;i; i!; I" font; T; [ii"o; ;i;i;i; i"; I" font; T; [ii#o; ;i;i;i; i#; I" font; T; [ii$o; ;i;i;i; i$; I" font; T; [ii%o; ;i;i;i; i%; I" font; T; [ii&o; ;i;i;i; i&; I" font; T; [ii'o; ;i;i;i; i'; I" font; T; [ii(o; ;i;i;i; i(; I" font; T; [ii)o; ;i;i;i; i); I" font; T; [i0i*o; ;i;i;i; i*; 0; [iii+o; ;i;i;i; i+; 0; [iii,o; ;i;i;i; i,; 0; [iIii-o; ;i;i;i; i-; 0; [iIii.o; ;i;i;i; i.; 0; [iii/o; ;i;i;i; i/; 0; [iii0o; ;i;i;i; i0; 0; [iii1o; ;i;i;i; i1; 0; [iii2o; ;i;i;i; i2; 0; [iii3o; ;i;i;i; i3; 0; [iii4o; ;i;i;i; i4; 0; [iii5o; ;i;i;i; i5; 0; [iii6o; ;i;i;i; i6; 0; [iii8o; ;i;i;i; i8; 0; [iii9o; ;i;i;i; i9; 0; [iii:o; ;i;i;i; i:; 0; [iii;o; ;i;i;i; i;; 0; [iiio; ;i;i;i; i>; 0; [iii@o; ;i;i;i; i@; 0; [iiiAo; ;i;i;i; iA; 0; [iiiCo; ;i;i;i; iC; 0; [iiiDo; ;i;i;i; iD; 0; [iiiFo; ;i;i;i; iF; 0; [iiiGo; ;i;i;i; iG; 0; [iiiHo; ;i;i;i; iH; 0; [iiiIo; ;i;i;i; iI; 0; [iiiJo; ;i;i;i; iJ; 0; [iiiKo; ;i;i;i; iK; 0; [iiiLo; ;i;i;i; iL; 0; [iiiMo; ;i;i;i; iM; 0; [iiiNo; ;i;i;i; iN; 0; [iiiOo; ;i;i;i; iO; I" compat; T; [iiiPo; ;i;i;i; iP; I" isolated; T; [iqiQo; ;i;i;i; iQ; I" final; T; [iqiRo; ;i;i;i; iR; I" isolated; T; [i{iSo; ;i;i;i; iS; I" final; T; [i{iTo; ;i;i;i; iT; I" initial; T; [i{iUo; ;i;i;i; iU; I" medial; T; [i{iVo; ;i;i;i; iV; I" isolated; T; [i~iWo; ;i;i;i; iW; I" final; T; [i~iXo; ;i;i;i; iX; I" initial; T; [i~iYo; ;i;i;i; iY; I" medial; T; [i~iZo; ;i;i;i; iZ; I" isolated; T; [ii[o; ;i;i;i; i[; I" final; T; [ii\o; ;i;i;i; i\; I" initial; T; [ii]o; ;i;i;i; i]; I" medial; T; [ii^o; ;i;i;i; i^; I" isolated; T; [izi_o; ;i;i;i; i_; I" final; T; [izi`o; ;i;i;i; i`; I" initial; T; [iziao; ;i;i;i; ia; I" medial; T; [izibo; ;i;i;i; ib; I" isolated; T; [iico; ;i;i;i; ic; I" final; T; [iido; ;i;i;i; id; I" initial; T; [iieo; ;i;i;i; ie; I" medial; T; [iifo; ;i;i;i; if; I" isolated; T; [iyigo; ;i;i;i; ig; I" final; T; [iyiho; ;i;i;i; ih; I" initial; T; [iyiio; ;i;i;i; ii; I" medial; T; [iyijo; ;i;i;i; ij; I" isolated; T; [iiko; ;i;i;i; ik; I" final; T; [iilo; ;i;i;i; il; I" initial; T; [iimo; ;i;i;i; im; I" medial; T; [iino; ;i;i;i; in; I" isolated; T; [iioo; ;i;i;i; io; I" final; T; [iipo; ;i;i;i; ip; I" initial; T; [iiqo; ;i;i;i; iq; I" medial; T; [iiro; ;i;i;i; ir; I" isolated; T; [iiso; ;i;i;i; is; I" final; T; [iito; ;i;i;i; it; I" initial; T; [iiuo; ;i;i;i; iu; I" medial; T; [iivo; ;i;i;i; iv; I" isolated; T; [iiwo; ;i;i;i; iw; I" final; T; [iixo; ;i;i;i; ix; I" initial; T; [iiyo; ;i;i;i; iy; I" medial; T; [iizo; ;i;i;i; iz; I" isolated; T; [ii{o; ;i;i;i; i{; I" final; T; [ii|o; ;i;i;i; i|; I" initial; T; [ii}o; ;i;i;i; i}; I" medial; T; [ii~o; ;i;i;i; i~; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iwio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" initial; T; [iIio; ;i;i;i; i; I" medial; T; [iIio; ;i;i;i; i; I" isolated; T; [i&i'io; ;i;i;i; i; I" final; T; [i&i'io; ;i;i;i; i; I" isolated; T; [i&iio; ;i;i;i; i; I" final; T; [i&iio; ;i;i;i; i; I" isolated; T; [i&iHio; ;i;i;i; i; I" final; T; [i&iHio; ;i;i;i; i; I" isolated; T; [i&iio; ;i;i;i; i; I" final; T; [i&iio; ;i;i;i; i; I" isolated; T; [i&iio; ;i;i;i; i; I" final; T; [i&iio; ;i;i;i; i; I" isolated; T; [i&iio; ;i;i;i; i; I" final; T; [i&iio; ;i;i;i; i; I" isolated; T; [i&iio; ;i;i;i; i; I" final; T; [i&iio; ;i;i;i; i; I" initial; T; [i&iio; ;i;i;i; i; I" isolated; T; [i&iIio; ;i;i;i; i; I" final; T; [i&iIio; ;i;i;i; i; I" initial; T; [i&iIio; ;i;i;i; i; I" isolated; T; [iio; ;i;i;i; i; I" final; T; [iio; ;i;i;i; i; I" initial; T; [iio; ;i;i;i; i; I" medial; T; [iio; ;i;i;i; i; I" isolated; T; [i&i,io; ;i;i;i; i; I" isolated; T; [i&i-io; ;i;i;i; i; I" isolated; T; [i&iEio; ;i;i;i; i; I" isolated; T; [i&iIio; ;i;i;i; i; I" isolated; T; [i&iJio; ;i;i;i; i; I" isolated; T; [i(i,io; ;i;i;i; i; I" isolated; T; [i(i-io; ;i;i;i; i; I" isolated; T; [i(i.io; ;i;i;i; i; I" isolated; T; [i(iEi o; ;i;i;i; i ; I" isolated; T; [i(iIi o; ;i;i;i; i ; I" isolated; T; [i(iJi o; ;i;i;i; i ; I" isolated; T; [i*i,i o; ;i;i;i; i ; I" isolated; T; [i*i-i o; ;i;i;i; i ; I" isolated; T; [i*i.io; ;i;i;i; i; I" isolated; T; [i*iEio; ;i;i;i; i; I" isolated; T; [i*iIio; ;i;i;i; i; I" isolated; T; [i*iJio; ;i;i;i; i; I" isolated; T; [i+i,io; ;i;i;i; i; I" isolated; T; [i+iEio; ;i;i;i; i; I" isolated; T; [i+iIio; ;i;i;i; i; I" isolated; T; [i+iJio; ;i;i;i; i; I" isolated; T; [i,i-io; ;i;i;i; i; I" isolated; T; [i,iEio; ;i;i;i; i; I" isolated; T; [i-i,io; ;i;i;i; i; I" isolated; T; [i-iEio; ;i;i;i; i; I" isolated; T; [i.i,io; ;i;i;i; i; I" isolated; T; [i.i-io; ;i;i;i; i; I" isolated; T; [i.iEio; ;i;i;i; i; I" isolated; T; [i3i,io; ;i;i;i; i; I" isolated; T; [i3i-io; ;i;i;i; i; I" isolated; T; [i3i.io; ;i;i;i; i; I" isolated; T; [i3iEi o; ;i;i;i; i ; I" isolated; T; [i5i-i!o; ;i;i;i; i!; I" isolated; T; [i5iEi"o; ;i;i;i; i"; I" isolated; T; [i6i,i#o; ;i;i;i; i#; I" isolated; T; [i6i-i$o; ;i;i;i; i$; I" isolated; T; [i6i.i%o; ;i;i;i; i%; I" isolated; T; [i6iEi&o; ;i;i;i; i&; I" isolated; T; [i7i-i'o; ;i;i;i; i'; I" isolated; T; [i7iEi(o; ;i;i;i; i(; I" isolated; T; [i8iEi)o; ;i;i;i; i); I" isolated; T; [i9i,i*o; ;i;i;i; i*; I" isolated; T; [i9iEi+o; ;i;i;i; i+; I" isolated; T; [i:i,i,o; ;i;i;i; i,; I" isolated; T; [i:iEi-o; ;i;i;i; i-; I" isolated; T; [iAi,i.o; ;i;i;i; i.; I" isolated; T; [iAi-i/o; ;i;i;i; i/; I" isolated; T; [iAi.i0o; ;i;i;i; i0; I" isolated; T; [iAiEi1o; ;i;i;i; i1; I" isolated; T; [iAiIi2o; ;i;i;i; i2; I" isolated; T; [iAiJi3o; ;i;i;i; i3; I" isolated; T; [iBi-i4o; ;i;i;i; i4; I" isolated; T; [iBiEi5o; ;i;i;i; i5; I" isolated; T; [iBiIi6o; ;i;i;i; i6; I" isolated; T; [iBiJi7o; ;i;i;i; i7; I" isolated; T; [iCi'i8o; ;i;i;i; i8; I" isolated; T; [iCi,i9o; ;i;i;i; i9; I" isolated; T; [iCi-i:o; ;i;i;i; i:; I" isolated; T; [iCi.i;o; ;i;i;i; i;; I" isolated; T; [iCiDio; ;i;i;i; i>; I" isolated; T; [iCiJi?o; ;i;i;i; i?; I" isolated; T; [iDi,i@o; ;i;i;i; i@; I" isolated; T; [iDi-iAo; ;i;i;i; iA; I" isolated; T; [iDi.iBo; ;i;i;i; iB; I" isolated; T; [iDiEiCo; ;i;i;i; iC; I" isolated; T; [iDiIiDo; ;i;i;i; iD; I" isolated; T; [iDiJiEo; ;i;i;i; iE; I" isolated; T; [iEi,iFo; ;i;i;i; iF; I" isolated; T; [iEi-iGo; ;i;i;i; iG; I" isolated; T; [iEi.iHo; ;i;i;i; iH; I" isolated; T; [iEiEiIo; ;i;i;i; iI; I" isolated; T; [iEiIiJo; ;i;i;i; iJ; I" isolated; T; [iEiJiKo; ;i;i;i; iK; I" isolated; T; [iFi,iLo; ;i;i;i; iL; I" isolated; T; [iFi-iMo; ;i;i;i; iM; I" isolated; T; [iFi.iNo; ;i;i;i; iN; I" isolated; T; [iFiEiOo; ;i;i;i; iO; I" isolated; T; [iFiIiPo; ;i;i;i; iP; I" isolated; T; [iFiJiQo; ;i;i;i; iQ; I" isolated; T; [iGi,iRo; ;i;i;i; iR; I" isolated; T; [iGiEiSo; ;i;i;i; iS; I" isolated; T; [iGiIiTo; ;i;i;i; iT; I" isolated; T; [iGiJiUo; ;i;i;i; iU; I" isolated; T; [iJi,iVo; ;i;i;i; iV; I" isolated; T; [iJi-iWo; ;i;i;i; iW; I" isolated; T; [iJi.iXo; ;i;i;i; iX; I" isolated; T; [iJiEiYo; ;i;i;i; iY; I" isolated; T; [iJiIiZo; ;i;i;i; iZ; I" isolated; T; [iJiJi[o; ;i;i;i; i[; I" isolated; T; [i0ipi\o; ;i;i;i; i\; I" isolated; T; [i1ipi]o; ;i;i;i; i]; I" isolated; T; [iIipi^o; ;i;i;i; i^; I" isolated; T; [i%iLiQi_o; ;i;i;i; i_; I" isolated; T; [i%iMiQi`o; ;i;i;i; i`; I" isolated; T; [i%iNiQiao; ;i;i;i; ia; I" isolated; T; [i%iOiQibo; ;i;i;i; ib; I" isolated; T; [i%iPiQico; ;i;i;i; ic; I" isolated; T; [i%iQipido; ;i;i;i; id; I" final; T; [i&i1ieo; ;i;i;i; ie; I" final; T; [i&i2ifo; ;i;i;i; if; I" final; T; [i&iEigo; ;i;i;i; ig; I" final; T; [i&iFiho; ;i;i;i; ih; I" final; T; [i&iIiio; ;i;i;i; ii; I" final; T; [i&iJijo; ;i;i;i; ij; I" final; T; [i(i1iko; ;i;i;i; ik; I" final; T; [i(i2ilo; ;i;i;i; il; I" final; T; [i(iEimo; ;i;i;i; im; I" final; T; [i(iFino; ;i;i;i; in; I" final; T; [i(iIioo; ;i;i;i; io; I" final; T; [i(iJipo; ;i;i;i; ip; I" final; T; [i*i1iqo; ;i;i;i; iq; I" final; T; [i*i2iro; ;i;i;i; ir; I" final; T; [i*iEiso; ;i;i;i; is; I" final; T; [i*iFito; ;i;i;i; it; I" final; T; [i*iIiuo; ;i;i;i; iu; I" final; T; [i*iJivo; ;i;i;i; iv; I" final; T; [i+i1iwo; ;i;i;i; iw; I" final; T; [i+i2ixo; ;i;i;i; ix; I" final; T; [i+iEiyo; ;i;i;i; iy; I" final; T; [i+iFizo; ;i;i;i; iz; I" final; T; [i+iIi{o; ;i;i;i; i{; I" final; T; [i+iJi|o; ;i;i;i; i|; I" final; T; [iAiIi}o; ;i;i;i; i}; I" final; T; [iAiJi~o; ;i;i;i; i~; I" final; T; [iBiIio; ;i;i;i; i; I" final; T; [iBiJio; ;i;i;i; i; I" final; T; [iCi'io; ;i;i;i; i; I" final; T; [iCiDio; ;i;i;i; i; I" final; T; [iCiEio; ;i;i;i; i; I" final; T; [iCiIio; ;i;i;i; i; I" final; T; [iCiJio; ;i;i;i; i; I" final; T; [iDiEio; ;i;i;i; i; I" final; T; [iDiIio; ;i;i;i; i; I" final; T; [iDiJio; ;i;i;i; i; I" final; T; [iEi'io; ;i;i;i; i; I" final; T; [iEiEio; ;i;i;i; i; I" final; T; [iFi1io; ;i;i;i; i; I" final; T; [iFi2io; ;i;i;i; i; I" final; T; [iFiEio; ;i;i;i; i; I" final; T; [iFiFio; ;i;i;i; i; I" final; T; [iFiIio; ;i;i;i; i; I" final; T; [iFiJio; ;i;i;i; i; I" final; T; [iIipio; ;i;i;i; i; I" final; T; [iJi1io; ;i;i;i; i; I" final; T; [iJi2io; ;i;i;i; i; I" final; T; [iJiEio; ;i;i;i; i; I" final; T; [iJiFio; ;i;i;i; i; I" final; T; [iJiIio; ;i;i;i; i; I" final; T; [iJiJio; ;i;i;i; i; I" initial; T; [i&i,io; ;i;i;i; i; I" initial; T; [i&i-io; ;i;i;i; i; I" initial; T; [i&i.io; ;i;i;i; i; I" initial; T; [i&iEio; ;i;i;i; i; I" initial; T; [i&iGio; ;i;i;i; i; I" initial; T; [i(i,io; ;i;i;i; i; I" initial; T; [i(i-io; ;i;i;i; i; I" initial; T; [i(i.io; ;i;i;i; i; I" initial; T; [i(iEio; ;i;i;i; i; I" initial; T; [i(iGio; ;i;i;i; i; I" initial; T; [i*i,io; ;i;i;i; i; I" initial; T; [i*i-io; ;i;i;i; i; I" initial; T; [i*i.io; ;i;i;i; i; I" initial; T; [i*iEio; ;i;i;i; i; I" initial; T; [i*iGio; ;i;i;i; i; I" initial; T; [i+iEio; ;i;i;i; i; I" initial; T; [i,i-io; ;i;i;i; i; I" initial; T; [i,iEio; ;i;i;i; i; I" initial; T; [i-i,io; ;i;i;i; i; I" initial; T; [i-iEio; ;i;i;i; i; I" initial; T; [i.i,io; ;i;i;i; i; I" initial; T; [i.iEio; ;i;i;i; i; I" initial; T; [i3i,io; ;i;i;i; i; I" initial; T; [i3i-io; ;i;i;i; i; I" initial; T; [i3i.io; ;i;i;i; i; I" initial; T; [i3iEio; ;i;i;i; i; I" initial; T; [i5i-io; ;i;i;i; i; I" initial; T; [i5i.io; ;i;i;i; i; I" initial; T; [i5iEio; ;i;i;i; i; I" initial; T; [i6i,io; ;i;i;i; i; I" initial; T; [i6i-io; ;i;i;i; i; I" initial; T; [i6i.io; ;i;i;i; i; I" initial; T; [i6iEio; ;i;i;i; i; I" initial; T; [i7i-io; ;i;i;i; i; I" initial; T; [i8iEio; ;i;i;i; i; I" initial; T; [i9i,io; ;i;i;i; i; I" initial; T; [i9iEio; ;i;i;i; i; I" initial; T; [i:i,io; ;i;i;i; i; I" initial; T; [i:iEio; ;i;i;i; i; I" initial; T; [iAi,io; ;i;i;i; i; I" initial; T; [iAi-io; ;i;i;i; i; I" initial; T; [iAi.io; ;i;i;i; i; I" initial; T; [iAiEio; ;i;i;i; i; I" initial; T; [iBi-io; ;i;i;i; i; I" initial; T; [iBiEio; ;i;i;i; i; I" initial; T; [iCi,io; ;i;i;i; i; I" initial; T; [iCi-io; ;i;i;i; i; I" initial; T; [iCi.io; ;i;i;i; i; I" initial; T; [iCiDio; ;i;i;i; i; I" initial; T; [iCiEio; ;i;i;i; i; I" initial; T; [iDi,io; ;i;i;i; i; I" initial; T; [iDi-io; ;i;i;i; i; I" initial; T; [iDi.io; ;i;i;i; i; I" initial; T; [iDiEio; ;i;i;i; i; I" initial; T; [iDiGio; ;i;i;i; i; I" initial; T; [iEi,io; ;i;i;i; i; I" initial; T; [iEi-io; ;i;i;i; i; I" initial; T; [iEi.io; ;i;i;i; i; I" initial; T; [iEiEio; ;i;i;i; i; I" initial; T; [iFi,io; ;i;i;i; i; I" initial; T; [iFi-io; ;i;i;i; i; I" initial; T; [iFi.io; ;i;i;i; i; I" initial; T; [iFiEio; ;i;i;i; i; I" initial; T; [iFiGio; ;i;i;i; i; I" initial; T; [iGi,io; ;i;i;i; i; I" initial; T; [iGiEio; ;i;i;i; i; I" initial; T; [iGipio; ;i;i;i; i; I" initial; T; [iJi,io; ;i;i;i; i; I" initial; T; [iJi-io; ;i;i;i; i; I" initial; T; [iJi.io; ;i;i;i; i; I" initial; T; [iJiEio; ;i;i;i; i; I" initial; T; [iJiGio; ;i;i;i; i; I" medial; T; [i&iEio; ;i;i;i; i; I" medial; T; [i&iGio; ;i;i;i; i; I" medial; T; [i(iEio; ;i;i;i; i; I" medial; T; [i(iGio; ;i;i;i; i; I" medial; T; [i*iEio; ;i;i;i; i; I" medial; T; [i*iGio; ;i;i;i; i; I" medial; T; [i+iEio; ;i;i;i; i; I" medial; T; [i+iGio; ;i;i;i; i; I" medial; T; [i3iEio; ;i;i;i; i; I" medial; T; [i3iGio; ;i;i;i; i; I" medial; T; [i4iEio; ;i;i;i; i; I" medial; T; [i4iGio; ;i;i;i; i; I" medial; T; [iCiDio; ;i;i;i; i; I" medial; T; [iCiEio; ;i;i;i; i; I" medial; T; [iDiEio; ;i;i;i; i; I" medial; T; [iFiEio; ;i;i;i; i; I" medial; T; [iFiGio; ;i;i;i; i; I" medial; T; [iJiEio; ;i;i;i; i; I" medial; T; [iJiGio; ;i;i;i; i; I" medial; T; [i@iNiQio; ;i;i;i; i; I" medial; T; [i@iOiQio; ;i;i;i; i; I" medial; T; [i@iPiQio; ;i;i;i; i; I" isolated; T; [i7iIio; ;i;i;i; i; I" isolated; T; [i7iJio; ;i;i;i; i; I" isolated; T; [i9iIio; ;i;i;i; i; I" isolated; T; [i9iJio; ;i;i;i; i; I" isolated; T; [i:iIio; ;i;i;i; i; I" isolated; T; [i:iJio; ;i;i;i; i; I" isolated; T; [i3iIio; ;i;i;i; i; I" isolated; T; [i3iJio; ;i;i;i; i; I" isolated; T; [i4iIio; ;i;i;i; i; I" isolated; T; [i4iJio; ;i;i;i; i; I" isolated; T; [i-iIio; ;i;i;i; i; I" isolated; T; [i-iJio; ;i;i;i; i; I" isolated; T; [i,iIio; ;i;i;i; i; I" isolated; T; [i,iJio; ;i;i;i; i; I" isolated; T; [i.iIio; ;i;i;i; i; I" isolated; T; [i.iJio; ;i;i;i; i; I" isolated; T; [i5iIio; ;i;i;i; i; I" isolated; T; [i5iJio; ;i;i;i; i; I" isolated; T; [i6iIio; ;i;i;i; i; I" isolated; T; [i6iJi o; ;i;i;i; i ; I" isolated; T; [i4i,i o; ;i;i;i; i ; I" isolated; T; [i4i-i o; ;i;i;i; i ; I" isolated; T; [i4i.i o; ;i;i;i; i ; I" isolated; T; [i4iEi o; ;i;i;i; i ; I" isolated; T; [i4i1io; ;i;i;i; i; I" isolated; T; [i3i1io; ;i;i;i; i; I" isolated; T; [i5i1io; ;i;i;i; i; I" isolated; T; [i6i1io; ;i;i;i; i; I" final; T; [i7iIio; ;i;i;i; i; I" final; T; [i7iJio; ;i;i;i; i; I" final; T; [i9iIio; ;i;i;i; i; I" final; T; [i9iJio; ;i;i;i; i; I" final; T; [i:iIio; ;i;i;i; i; I" final; T; [i:iJio; ;i;i;i; i; I" final; T; [i3iIio; ;i;i;i; i; I" final; T; [i3iJio; ;i;i;i; i; I" final; T; [i4iIio; ;i;i;i; i; I" final; T; [i4iJio; ;i;i;i; i; I" final; T; [i-iIio; ;i;i;i; i; I" final; T; [i-iJio; ;i;i;i; i; I" final; T; [i,iIio; ;i;i;i; i; I" final; T; [i,iJio; ;i;i;i; i; I" final; T; [i.iIi o; ;i;i;i; i ; I" final; T; [i.iJi!o; ;i;i;i; i!; I" final; T; [i5iIi"o; ;i;i;i; i"; I" final; T; [i5iJi#o; ;i;i;i; i#; I" final; T; [i6iIi$o; ;i;i;i; i$; I" final; T; [i6iJi%o; ;i;i;i; i%; I" final; T; [i4i,i&o; ;i;i;i; i&; I" final; T; [i4i-i'o; ;i;i;i; i'; I" final; T; [i4i.i(o; ;i;i;i; i(; I" final; T; [i4iEi)o; ;i;i;i; i); I" final; T; [i4i1i*o; ;i;i;i; i*; I" final; T; [i3i1i+o; ;i;i;i; i+; I" final; T; [i5i1i,o; ;i;i;i; i,; I" final; T; [i6i1i-o; ;i;i;i; i-; I" initial; T; [i4i,i.o; ;i;i;i; i.; I" initial; T; [i4i-i/o; ;i;i;i; i/; I" initial; T; [i4i.i0o; ;i;i;i; i0; I" initial; T; [i4iEi1o; ;i;i;i; i1; I" initial; T; [i3iGi2o; ;i;i;i; i2; I" initial; T; [i4iGi3o; ;i;i;i; i3; I" initial; T; [i7iEi4o; ;i;i;i; i4; I" medial; T; [i3i,i5o; ;i;i;i; i5; I" medial; T; [i3i-i6o; ;i;i;i; i6; I" medial; T; [i3i.i7o; ;i;i;i; i7; I" medial; T; [i4i,i8o; ;i;i;i; i8; I" medial; T; [i4i-i9o; ;i;i;i; i9; I" medial; T; [i4i.i:o; ;i;i;i; i:; I" medial; T; [i7iEi;o; ;i;i;i; i;; I" medial; T; [i8iEio; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0iPo; ;i;i;i; iP; I" initial; T; [i*i,iEiQo; ;i;i;i; iQ; I" final; T; [i*i-i,iRo; ;i;i;i; iR; I" initial; T; [i*i-i,iSo; ;i;i;i; iS; I" initial; T; [i*i-iEiTo; ;i;i;i; iT; I" initial; T; [i*i.iEiUo; ;i;i;i; iU; I" initial; T; [i*iEi,iVo; ;i;i;i; iV; I" initial; T; [i*iEi-iWo; ;i;i;i; iW; I" initial; T; [i*iEi.iXo; ;i;i;i; iX; I" final; T; [i,iEi-iYo; ;i;i;i; iY; I" initial; T; [i,iEi-iZo; ;i;i;i; iZ; I" final; T; [i-iEiJi[o; ;i;i;i; i[; I" final; T; [i-iEiIi\o; ;i;i;i; i\; I" initial; T; [i3i-i,i]o; ;i;i;i; i]; I" initial; T; [i3i,i-i^o; ;i;i;i; i^; I" final; T; [i3i,iIi_o; ;i;i;i; i_; I" final; T; [i3iEi-i`o; ;i;i;i; i`; I" initial; T; [i3iEi-iao; ;i;i;i; ia; I" initial; T; [i3iEi,ibo; ;i;i;i; ib; I" final; T; [i3iEiEico; ;i;i;i; ic; I" initial; T; [i3iEiEido; ;i;i;i; id; I" final; T; [i5i-i-ieo; ;i;i;i; ie; I" initial; T; [i5i-i-ifo; ;i;i;i; if; I" final; T; [i5iEiEigo; ;i;i;i; ig; I" final; T; [i4i-iEiho; ;i;i;i; ih; I" initial; T; [i4i-iEiio; ;i;i;i; ii; I" final; T; [i4i,iJijo; ;i;i;i; ij; I" final; T; [i4iEi.iko; ;i;i;i; ik; I" initial; T; [i4iEi.ilo; ;i;i;i; il; I" final; T; [i4iEiEimo; ;i;i;i; im; I" initial; T; [i4iEiEino; ;i;i;i; in; I" final; T; [i6i-iIioo; ;i;i;i; io; I" final; T; [i6i.iEipo; ;i;i;i; ip; I" initial; T; [i6i.iEiqo; ;i;i;i; iq; I" final; T; [i7iEi-iro; ;i;i;i; ir; I" initial; T; [i7iEi-iso; ;i;i;i; is; I" initial; T; [i7iEiEito; ;i;i;i; it; I" final; T; [i7iEiJiuo; ;i;i;i; iu; I" final; T; [i9i,iEivo; ;i;i;i; iv; I" final; T; [i9iEiEiwo; ;i;i;i; iw; I" initial; T; [i9iEiEixo; ;i;i;i; ix; I" final; T; [i9iEiIiyo; ;i;i;i; iy; I" final; T; [i:iEiEizo; ;i;i;i; iz; I" final; T; [i:iEiJi{o; ;i;i;i; i{; I" final; T; [i:iEiIi|o; ;i;i;i; i|; I" final; T; [iAi.iEi}o; ;i;i;i; i}; I" initial; T; [iAi.iEi~o; ;i;i;i; i~; I" final; T; [iBiEi-io; ;i;i;i; i; I" final; T; [iBiEiEio; ;i;i;i; i; I" final; T; [iDi-iEio; ;i;i;i; i; I" final; T; [iDi-iJio; ;i;i;i; i; I" final; T; [iDi-iIio; ;i;i;i; i; I" initial; T; [iDi,i,io; ;i;i;i; i; I" final; T; [iDi,i,io; ;i;i;i; i; I" final; T; [iDi.iEio; ;i;i;i; i; I" initial; T; [iDi.iEio; ;i;i;i; i; I" final; T; [iDiEi-io; ;i;i;i; i; I" initial; T; [iDiEi-io; ;i;i;i; i; I" initial; T; [iEi-i,io; ;i;i;i; i; I" initial; T; [iEi-iEio; ;i;i;i; i; I" final; T; [iEi-iJio; ;i;i;i; i; I" initial; T; [iEi,i-io; ;i;i;i; i; I" initial; T; [iEi,iEio; ;i;i;i; i; I" initial; T; [iEi.i,io; ;i;i;i; i; I" initial; T; [iEi.iEio; ;i;i;i; i; I" initial; T; [iEi,i.io; ;i;i;i; i; I" initial; T; [iGiEi,io; ;i;i;i; i; I" initial; T; [iGiEiEio; ;i;i;i; i; I" initial; T; [iFi-iEio; ;i;i;i; i; I" final; T; [iFi-iIio; ;i;i;i; i; I" final; T; [iFi,iEio; ;i;i;i; i; I" initial; T; [iFi,iEio; ;i;i;i; i; I" final; T; [iFi,iIio; ;i;i;i; i; I" final; T; [iFiEiJio; ;i;i;i; i; I" final; T; [iFiEiIio; ;i;i;i; i; I" final; T; [iJiEiEio; ;i;i;i; i; I" initial; T; [iJiEiEio; ;i;i;i; i; I" final; T; [i(i.iJio; ;i;i;i; i; I" final; T; [i*i,iJio; ;i;i;i; i; I" final; T; [i*i,iIio; ;i;i;i; i; I" final; T; [i*i.iJio; ;i;i;i; i; I" final; T; [i*i.iIio; ;i;i;i; i; I" final; T; [i*iEiJio; ;i;i;i; i; I" final; T; [i*iEiIio; ;i;i;i; i; I" final; T; [i,iEiJio; ;i;i;i; i; I" final; T; [i,i-iIio; ;i;i;i; i; I" final; T; [i,iEiIio; ;i;i;i; i; I" final; T; [i3i.iIio; ;i;i;i; i; I" final; T; [i5i-iJio; ;i;i;i; i; I" final; T; [i4i-iJio; ;i;i;i; i; I" final; T; [i6i-iJio; ;i;i;i; i; I" final; T; [iDi,iJio; ;i;i;i; i; I" final; T; [iDiEiJio; ;i;i;i; i; I" final; T; [iJi-iJio; ;i;i;i; i; I" final; T; [iJi,iJio; ;i;i;i; i; I" final; T; [iJiEiJio; ;i;i;i; i; I" final; T; [iEiEiJio; ;i;i;i; i; I" final; T; [iBiEiJio; ;i;i;i; i; I" final; T; [iFi-iJio; ;i;i;i; i; I" initial; T; [iBiEi-io; ;i;i;i; i; I" initial; T; [iDi-iEio; ;i;i;i; i; I" final; T; [i9iEiJio; ;i;i;i; i; I" final; T; [iCiEiJio; ;i;i;i; i; I" initial; T; [iFi,i-io; ;i;i;i; i; I" final; T; [iEi.iJio; ;i;i;i; i; I" initial; T; [iDi,iEio; ;i;i;i; i; I" final; T; [iCiEiEio; ;i;i;i; i; I" final; T; [iDi,iEio; ;i;i;i; i; I" final; T; [iFi,i-io; ;i;i;i; i; I" final; T; [i,i-iJio; ;i;i;i; i; I" final; T; [i-i,iJio; ;i;i;i; i; I" final; T; [iEi,iJio; ;i;i;i; i; I" final; T; [iAiEiJio; ;i;i;i; i; I" final; T; [i(i-iJio; ;i;i;i; i; I" initial; T; [iCiEiEio; ;i;i;i; i; I" initial; T; [i9i,iEio; ;i;i;i; i; I" initial; T; [i5iEiEio; ;i;i;i; i; I" final; T; [i3i.iJio; ;i;i;i; i; I" final; T; [iFi,iJio; ;i;i;i; i; I" isolated; T; [i5iDiio; ;i;i;i; i; I" isolated; T; [iBiDiio; ;i;i;i; i; I" isolated; T; [ i'iDiDiGio; ;i;i;i; i; I" isolated; T; [ i'iCi(i1io; ;i;i;i; i; I" isolated; T; [ iEi-iEi/io; ;i;i;i; i; I" isolated; T; [ i5iDi9iEio; ;i;i;i; i; I" isolated; T; [ i1i3iHiDio; ;i;i;i; i; I" isolated; T; [ i9iDiJiGio; ;i;i;i; i; I" isolated; T; [ iHi3iDiEio; ;i;i;i; i; I" isolated; T; [i5iDiIio; ;i;i;i; i; I" isolated; T; [i5iDiIi%i'iDiDiGi%i9iDiJiGi%iHi3iDiEio; ;i;i;i; i; I" isolated; T; [ i,iDi%i,iDi'iDiGio; ;i;i;i; i; I" isolated; T; [ i1ii'iDio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" vertical; T; [i1io; ;i;i;i; i; I" vertical; T; [i0io; ;i;i;i; i; I" vertical; T; [i0io; ;i;i;i; i; I" vertical; T; [i?io; ;i;i;i; i; I" vertical; T; [i@io; ;i;i;i; i; I" vertical; T; [i&io; ;i;i;i; i; I" vertical; T; [iDio; ;i;i;i; i; I" vertical; T; [i0io; ;i;i;i; i; I" vertical; T; [i0io; ;i;i;i; i; I" vertical; T; [i& i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i0o; ;i;i;i; i0; I" vertical; T; [i% i1o; ;i;i;i; i1; I" vertical; T; [i i2o; ;i;i;i; i2; I" vertical; T; [i i3o; ;i;i;i; i3; I" vertical; T; [idi4o; ;i;i;i; i4; I" vertical; T; [idi5o; ;i;i;i; i5; I" vertical; T; [i-i6o; ;i;i;i; i6; I" vertical; T; [i.i7o; ;i;i;i; i7; I" vertical; T; [i{i8o; ;i;i;i; i8; I" vertical; T; [i}i9o; ;i;i;i; i9; I" vertical; T; [i0i:o; ;i;i;i; i:; I" vertical; T; [i0i;o; ;i;i;i; i;; I" vertical; T; [i0io; ;i;i;i; i>; I" vertical; T; [i 0i?o; ;i;i;i; i?; I" vertical; T; [i0i@o; ;i;i;i; i@; I" vertical; T; [i 0iAo; ;i;i;i; iA; I" vertical; T; [i 0iBo; ;i;i;i; iB; I" vertical; T; [i 0iCo; ;i;i;i; iC; I" vertical; T; [i0iDo; ;i;i;i; iD; I" vertical; T; [i0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; I" vertical; T; [i`iHo; ;i;i;i; iH; I" vertical; T; [ibiIo; ;i;i;i; iI; I" compat; T; [i> iJo; ;i;i;i; iJ; I" compat; T; [i> iKo; ;i;i;i; iK; I" compat; T; [i> iLo; ;i;i;i; iL; I" compat; T; [i> iMo; ;i;i;i; iM; I" compat; T; [idiNo; ;i;i;i; iN; I" compat; T; [idiOo; ;i;i;i; iO; I" compat; T; [idiPo; ;i;i;i; iP; I" small; T; [i1iQo; ;i;i;i; iQ; I" small; T; [i0iRo; ;i;i;i; iR; I" small; T; [i3iTo; ;i;i;i; iT; I" small; T; [i@iUo; ;i;i;i; iU; I" small; T; [i?iVo; ;i;i;i; iV; I" small; T; [iDiWo; ;i;i;i; iW; I" small; T; [i&iXo; ;i;i;i; iX; I" small; T; [i iYo; ;i;i;i; iY; I" small; T; [i-iZo; ;i;i;i; iZ; I" small; T; [i.i[o; ;i;i;i; i[; I" small; T; [i{i\o; ;i;i;i; i\; I" small; T; [i}i]o; ;i;i;i; i]; I" small; T; [i0i^o; ;i;i;i; i^; I" small; T; [i0i_o; ;i;i;i; i_; I" small; T; [i(i`o; ;i;i;i; i`; I" small; T; [i+iao; ;i;i;i; ia; I" small; T; [i/ibo; ;i;i;i; ib; I" small; T; [i0ico; ;i;i;i; ic; I" small; T; [i2ido; ;i;i;i; id; I" small; T; [iAieo; ;i;i;i; ie; I" small; T; [iCifo; ;i;i;i; if; I" small; T; [iBiho; ;i;i;i; ih; I" small; T; [iaiio; ;i;i;i; ii; I" small; T; [i)ijo; ;i;i;i; ij; I" small; T; [i*iko; ;i;i;i; ik; I" small; T; [iEipo; ;i;i;i; ip; I" isolated; T; [i%iKiqo; ;i;i;i; iq; I" medial; T; [i@iKiro; ;i;i;i; ir; I" isolated; T; [i%iLiso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; I" isolated; T; [i%iMivo; ;i;i;i; iv; I" isolated; T; [i%iNiwo; ;i;i;i; iw; I" medial; T; [i@iNixo; ;i;i;i; ix; I" isolated; T; [i%iOiyo; ;i;i;i; iy; I" medial; T; [i@iOizo; ;i;i;i; iz; I" isolated; T; [i%iPi{o; ;i;i;i; i{; I" medial; T; [i@iPi|o; ;i;i;i; i|; I" isolated; T; [i%iQi}o; ;i;i;i; i}; I" medial; T; [i@iQi~o; ;i;i;i; i~; I" isolated; T; [i%iRio; ;i;i;i; i; I" medial; T; [i@iRio; ;i;i;i; i; I" isolated; T; [i!io; ;i;i;i; i; I" isolated; T; [i"io; ;i;i;i; i; I" final; T; [i"io; ;i;i;i; i; I" isolated; T; [i#io; ;i;i;i; i; I" final; T; [i#io; ;i;i;i; i; I" isolated; T; [i$io; ;i;i;i; i; I" final; T; [i$io; ;i;i;i; i; I" isolated; T; [i%io; ;i;i;i; i; I" final; T; [i%io; ;i;i;i; i; I" isolated; T; [i&io; ;i;i;i; i; I" final; T; [i&io; ;i;i;i; i; I" initial; T; [i&io; ;i;i;i; i; I" medial; T; [i&io; ;i;i;i; i; I" isolated; T; [i'io; ;i;i;i; i; I" final; T; [i'io; ;i;i;i; i; I" isolated; T; [i(io; ;i;i;i; i; I" final; T; [i(io; ;i;i;i; i; I" initial; T; [i(io; ;i;i;i; i; I" medial; T; [i(io; ;i;i;i; i; I" isolated; T; [i)io; ;i;i;i; i; I" final; T; [i)io; ;i;i;i; i; I" isolated; T; [i*io; ;i;i;i; i; I" final; T; [i*io; ;i;i;i; i; I" initial; T; [i*io; ;i;i;i; i; I" medial; T; [i*io; ;i;i;i; i; I" isolated; T; [i+io; ;i;i;i; i; I" final; T; [i+io; ;i;i;i; i; I" initial; T; [i+io; ;i;i;i; i; I" medial; T; [i+io; ;i;i;i; i; I" isolated; T; [i,io; ;i;i;i; i; I" final; T; [i,io; ;i;i;i; i; I" initial; T; [i,io; ;i;i;i; i; I" medial; T; [i,io; ;i;i;i; i; I" isolated; T; [i-io; ;i;i;i; i; I" final; T; [i-io; ;i;i;i; i; I" initial; T; [i-io; ;i;i;i; i; I" medial; T; [i-io; ;i;i;i; i; I" isolated; T; [i.io; ;i;i;i; i; I" final; T; [i.io; ;i;i;i; i; I" initial; T; [i.io; ;i;i;i; i; I" medial; T; [i.io; ;i;i;i; i; I" isolated; T; [i/io; ;i;i;i; i; I" final; T; [i/io; ;i;i;i; i; I" isolated; T; [i0io; ;i;i;i; i; I" final; T; [i0io; ;i;i;i; i; I" isolated; T; [i1io; ;i;i;i; i; I" final; T; [i1io; ;i;i;i; i; I" isolated; T; [i2io; ;i;i;i; i; I" final; T; [i2io; ;i;i;i; i; I" isolated; T; [i3io; ;i;i;i; i; I" final; T; [i3io; ;i;i;i; i; I" initial; T; [i3io; ;i;i;i; i; I" medial; T; [i3io; ;i;i;i; i; I" isolated; T; [i4io; ;i;i;i; i; I" final; T; [i4io; ;i;i;i; i; I" initial; T; [i4io; ;i;i;i; i; I" medial; T; [i4io; ;i;i;i; i; I" isolated; T; [i5io; ;i;i;i; i; I" final; T; [i5io; ;i;i;i; i; I" initial; T; [i5io; ;i;i;i; i; I" medial; T; [i5io; ;i;i;i; i; I" isolated; T; [i6io; ;i;i;i; i; I" final; T; [i6io; ;i;i;i; i; I" initial; T; [i6io; ;i;i;i; i; I" medial; T; [i6io; ;i;i;i; i; I" isolated; T; [i7io; ;i;i;i; i; I" final; T; [i7io; ;i;i;i; i; I" initial; T; [i7io; ;i;i;i; i; I" medial; T; [i7io; ;i;i;i; i; I" isolated; T; [i8io; ;i;i;i; i; I" final; T; [i8io; ;i;i;i; i; I" initial; T; [i8io; ;i;i;i; i; I" medial; T; [i8io; ;i;i;i; i; I" isolated; T; [i9io; ;i;i;i; i; I" final; T; [i9io; ;i;i;i; i; I" initial; T; [i9io; ;i;i;i; i; I" medial; T; [i9io; ;i;i;i; i; I" isolated; T; [i:io; ;i;i;i; i; I" final; T; [i:io; ;i;i;i; i; I" initial; T; [i:io; ;i;i;i; i; I" medial; T; [i:io; ;i;i;i; i; I" isolated; T; [iAio; ;i;i;i; i; I" final; T; [iAio; ;i;i;i; i; I" initial; T; [iAio; ;i;i;i; i; I" medial; T; [iAio; ;i;i;i; i; I" isolated; T; [iBio; ;i;i;i; i; I" final; T; [iBio; ;i;i;i; i; I" initial; T; [iBio; ;i;i;i; i; I" medial; T; [iBio; ;i;i;i; i; I" isolated; T; [iCio; ;i;i;i; i; I" final; T; [iCio; ;i;i;i; i; I" initial; T; [iCio; ;i;i;i; i; I" medial; T; [iCio; ;i;i;i; i; I" isolated; T; [iDio; ;i;i;i; i; I" final; T; [iDio; ;i;i;i; i; I" initial; T; [iDio; ;i;i;i; i; I" medial; T; [iDio; ;i;i;i; i; I" isolated; T; [iEio; ;i;i;i; i; I" final; T; [iEio; ;i;i;i; i; I" initial; T; [iEio; ;i;i;i; i; I" medial; T; [iEio; ;i;i;i; i; I" isolated; T; [iFio; ;i;i;i; i; I" final; T; [iFio; ;i;i;i; i; I" initial; T; [iFio; ;i;i;i; i; I" medial; T; [iFio; ;i;i;i; i; I" isolated; T; [iGio; ;i;i;i; i; I" final; T; [iGio; ;i;i;i; i; I" initial; T; [iGio; ;i;i;i; i; I" medial; T; [iGio; ;i;i;i; i; I" isolated; T; [iHio; ;i;i;i; i; I" final; T; [iHio; ;i;i;i; i; I" isolated; T; [iIio; ;i;i;i; i; I" final; T; [iIio; ;i;i;i; i; I" isolated; T; [iJio; ;i;i;i; i; I" final; T; [iJio; ;i;i;i; i; I" initial; T; [iJio; ;i;i;i; i; I" medial; T; [iJio; ;i;i;i; i; I" isolated; T; [iDi"io; ;i;i;i; i; I" final; T; [iDi"io; ;i;i;i; i; I" isolated; T; [iDi#io; ;i;i;i; i; I" final; T; [iDi#io; ;i;i;i; i; I" isolated; T; [iDi%io; ;i;i;i; i; I" final; T; [iDi%io; ;i;i;i; i; I" isolated; T; [iDi'io; ;i;i;i; i; I" final; T; [iDi'io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" wide; T; [i&io; ;i;i;i; i; I" wide; T; [i'io; ;i;i;i; i; I" wide; T; [i(io; ;i;i;i; i; I" wide; T; [i)io; ;i;i;i; i; I" wide; T; [i*io; ;i;i;i; i; I" wide; T; [i+io; ;i;i;i; i; I" wide; T; [i,io; ;i;i;i; i; I" wide; T; [i-i o; ;i;i;i; i ; I" wide; T; [i.i o; ;i;i;i; i ; I" wide; T; [i/i o; ;i;i;i; i ; I" wide; T; [i0i o; ;i;i;i; i ; I" wide; T; [i1i o; ;i;i;i; i ; I" wide; T; [i2io; ;i;i;i; i; I" wide; T; [i3io; ;i;i;i; i; I" wide; T; [i4io; ;i;i;i; i; I" wide; T; [i5io; ;i;i;i; i; I" wide; T; [i6io; ;i;i;i; i; I" wide; T; [i7io; ;i;i;i; i; I" wide; T; [i8io; ;i;i;i; i; I" wide; T; [i9io; ;i;i;i; i; I" wide; T; [i:io; ;i;i;i; i; I" wide; T; [i;io; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [i?io; ;i;i;i; i; I" wide; T; [i@io; ;i;i;i; i; I" wide; T; [iAio; ;i;i;i; i; I" wide; T; [iBio; ;i;i;i; i; I" wide; T; [iCio; ;i;i;i; i; I" wide; T; [iDi o; ;i;i;i; i ; I" wide; T; [iEi!o; ;i;i;iA; i!; I" wide; T; [iFi"o; ;i;i;iB; i"; I" wide; T; [iGi#o; ;i;i;iC; i#; I" wide; T; [iHi$o; ;i;i;iD; i$; I" wide; T; [iIi%o; ;i;i;iE; i%; I" wide; T; [iJi&o; ;i;i;iF; i&; I" wide; T; [iKi'o; ;i;i;iG; i'; I" wide; T; [iLi(o; ;i;i;iH; i(; I" wide; T; [iMi)o; ;i;i;iI; i); I" wide; T; [iNi*o; ;i;i;iJ; i*; I" wide; T; [iOi+o; ;i;i;iK; i+; I" wide; T; [iPi,o; ;i;i;iL; i,; I" wide; T; [iQi-o; ;i;i;iM; i-; I" wide; T; [iRi.o; ;i;i;iN; i.; I" wide; T; [iSi/o; ;i;i;iO; i/; I" wide; T; [iTi0o; ;i;i;iP; i0; I" wide; T; [iUi1o; ;i;i;iQ; i1; I" wide; T; [iVi2o; ;i;i;iR; i2; I" wide; T; [iWi3o; ;i;i;iS; i3; I" wide; T; [iXi4o; ;i;i;iT; i4; I" wide; T; [iYi5o; ;i;i;iU; i5; I" wide; T; [iZi6o; ;i;i;iV; i6; I" wide; T; [i[i7o; ;i;i;iW; i7; I" wide; T; [i\i8o; ;i;i;iX; i8; I" wide; T; [i]i9o; ;i;i;iY; i9; I" wide; T; [i^i:o; ;i;i;iZ; i:; I" wide; T; [i_i;o; ;i;i;i; i;; I" wide; T; [i`io; ;i;i;i; i>; I" wide; T; [ici?o; ;i;i;i; i?; I" wide; T; [idi@o; ;i;i;i; i@; I" wide; T; [ieiAo; ;i;i!;i; iA; I" wide; T; [ifiBo; ;i;i";i; iB; I" wide; T; [igiCo; ;i;i#;i; iC; I" wide; T; [ihiDo; ;i;i$;i; iD; I" wide; T; [iiiEo; ;i;i%;i; iE; I" wide; T; [ijiFo; ;i;i&;i; iF; I" wide; T; [ikiGo; ;i;i';i; iG; I" wide; T; [iliHo; ;i;i(;i; iH; I" wide; T; [imiIo; ;i;i);i; iI; I" wide; T; [iniJo; ;i;i*;i; iJ; I" wide; T; [ioiKo; ;i;i+;i; iK; I" wide; T; [ipiLo; ;i;i,;i; iL; I" wide; T; [iqiMo; ;i;i-;i; iM; I" wide; T; [iriNo; ;i;i.;i; iN; I" wide; T; [isiOo; ;i;i/;i; iO; I" wide; T; [itiPo; ;i;i0;i; iP; I" wide; T; [iuiQo; ;i;i1;i; iQ; I" wide; T; [iviRo; ;i;i2;i; iR; I" wide; T; [iwiSo; ;i;i3;i; iS; I" wide; T; [ixiTo; ;i;i4;i; iT; I" wide; T; [iyiUo; ;i;i5;i; iU; I" wide; T; [iziVo; ;i;i6;i; iV; I" wide; T; [i{iWo; ;i;i7;i; iW; I" wide; T; [i|iXo; ;i;i8;i; iX; I" wide; T; [i}iYo; ;i;i9;i; iY; I" wide; T; [i~iZo; ;i;i:;i; iZ; I" wide; T; [ii[o; ;i;i;i; i[; I" wide; T; [i{i\o; ;i;i;i; i\; I" wide; T; [i|i]o; ;i;i;i; i]; I" wide; T; [i}i^o; ;i;i;i; i^; I" wide; T; [i~i_o; ;i;i;i; i_; I" wide; T; [i)i`o; ;i;i;i; i`; I" wide; T; [i)iao; ;i;i;i; ia; I" narrow; T; [i0ibo; ;i;i;i; ib; I" narrow; T; [i 0ico; ;i;i;i; ic; I" narrow; T; [i 0ido; ;i;i;i; id; I" narrow; T; [i0ieo; ;i;i;i; ie; I" narrow; T; [i0ifo; ;i;i;i; if; I" narrow; T; [i0igo; ;i;i;i; ig; I" narrow; T; [i0iho; ;i;i;i; ih; I" narrow; T; [i0iio; ;i;i;i; ii; I" narrow; T; [i0ijo; ;i;i;i; ij; I" narrow; T; [i0iko; ;i;i;i; ik; I" narrow; T; [i0ilo; ;i;i;i; il; I" narrow; T; [i0imo; ;i;i;i; im; I" narrow; T; [i0ino; ;i;i;i; in; I" narrow; T; [i0ioo; ;i;i;i; io; I" narrow; T; [i0ipo; ;i;i;i; ip; I" narrow; T; [i0iqo; ;i;i;i; iq; I" narrow; T; [i0iro; ;i;i;i; ir; I" narrow; T; [i0iso; ;i;i;i; is; I" narrow; T; [i0ito; ;i;i;i; it; I" narrow; T; [i0iuo; ;i;i;i; iu; I" narrow; T; [i0ivo; ;i;i;i; iv; I" narrow; T; [i0iwo; ;i;i;i; iw; I" narrow; T; [i0ixo; ;i;i;i; ix; I" narrow; T; [i0iyo; ;i;i;i; iy; I" narrow; T; [i0izo; ;i;i;i; iz; I" narrow; T; [i0i{o; ;i;i;i; i{; I" narrow; T; [i0i|o; ;i;i;i; i|; I" narrow; T; [i0i}o; ;i;i;i; i}; I" narrow; T; [i0i~o; ;i;i;i; i~; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [i0io; ;i;i;i; i; I" narrow; T; [id1io; ;i;i;i; i; I" narrow; T; [i11io; ;i;i;i; i; I" narrow; T; [i21io; ;i;i;i; i; I" narrow; T; [i31io; ;i;i;i; i; I" narrow; T; [i41io; ;i;i;i; i; I" narrow; T; [i51io; ;i;i;i; i; I" narrow; T; [i61io; ;i;i;i; i; I" narrow; T; [i71io; ;i;i;i; i; I" narrow; T; [i81io; ;i;i;i; i; I" narrow; T; [i91io; ;i;i;i; i; I" narrow; T; [i:1io; ;i;i;i; i; I" narrow; T; [i;1io; ;i;i;i; i; I" narrow; T; [i<1io; ;i;i;i; i; I" narrow; T; [i=1io; ;i;i;i; i; I" narrow; T; [i>1io; ;i;i;i; i; I" narrow; T; [i?1io; ;i;i;i; i; I" narrow; T; [i@1io; ;i;i;i; i; I" narrow; T; [iA1io; ;i;i;i; i; I" narrow; T; [iB1io; ;i;i;i; i; I" narrow; T; [iC1io; ;i;i;i; i; I" narrow; T; [iD1io; ;i;i;i; i; I" narrow; T; [iE1io; ;i;i;i; i; I" narrow; T; [iF1io; ;i;i;i; i; I" narrow; T; [iG1io; ;i;i;i; i; I" narrow; T; [iH1io; ;i;i;i; i; I" narrow; T; [iI1io; ;i;i;i; i; I" narrow; T; [iJ1io; ;i;i;i; i; I" narrow; T; [iK1io; ;i;i;i; i; I" narrow; T; [iL1io; ;i;i;i; i; I" narrow; T; [iM1io; ;i;i;i; i; I" narrow; T; [iN1io; ;i;i;i; i; I" narrow; T; [iO1io; ;i;i;i; i; I" narrow; T; [iP1io; ;i;i;i; i; I" narrow; T; [iQ1io; ;i;i;i; i; I" narrow; T; [iR1io; ;i;i;i; i; I" narrow; T; [iS1io; ;i;i;i; i; I" narrow; T; [iT1io; ;i;i;i; i; I" narrow; T; [iU1io; ;i;i;i; i; I" narrow; T; [iV1io; ;i;i;i; i; I" narrow; T; [iW1io; ;i;i;i; i; I" narrow; T; [iX1io; ;i;i;i; i; I" narrow; T; [iY1io; ;i;i;i; i; I" narrow; T; [iZ1io; ;i;i;i; i; I" narrow; T; [i[1io; ;i;i;i; i; I" narrow; T; [i\1io; ;i;i;i; i; I" narrow; T; [i]1io; ;i;i;i; i; I" narrow; T; [i^1io; ;i;i;i; i; I" narrow; T; [i_1io; ;i;i;i; i; I" narrow; T; [i`1io; ;i;i;i; i; I" narrow; T; [ia1io; ;i;i;i; i; I" narrow; T; [ib1io; ;i;i;i; i; I" narrow; T; [ic1io; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [iio; ;i;i;i; i; I" wide; T; [i io; ;i;i;i; i; I" narrow; T; [i%io; ;i;i;i; i; I" narrow; T; [i!io; ;i;i;i; i; I" narrow; T; [i!io; ;i;i;i; i; I" narrow; T; [i!io; ;i;i;i; i; I" narrow; T; [i!io; ;i;i;i; i; I" narrow; T; [i%io; ;i;i;i; i; I" narrow; T; [i%io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i(; i; 0; 0io; ;i;i;i); i; 0; 0io; ;i;i;i*; i; 0; 0io; ;i;i;i+; i; 0; 0io; ;i;i;i,; i; 0; 0io; ;i;i;i-; i; 0; 0io; ;i;i;i.; i; 0; 0io; ;i;i;i/; i; 0; 0io; ;i;i;i0; i; 0; 0i o; ;i;i;i1; i ; 0; 0i o; ;i;i;i2; i ; 0; 0i o; ;i;i;i3; i ; 0; 0i o; ;i;i;i4; i ; 0; 0i o; ;i;i;i5; i ; 0; 0io; ;i;i;i6; i; 0; 0io; ;i;i;i7; i; 0; 0io; ;i;i;i8; i; 0; 0io; ;i;i;i9; i; 0; 0io; ;i;i;i:; i; 0; 0io; ;i;i;i;; i; 0; 0io; ;i;i;i<; i; 0; 0io; ;i;i;i=; i; 0; 0io; ;i;i;i>; i; 0; 0io; ;i;i;i?; i; 0; 0io; ;i;i;i@; i; 0; 0io; ;i;i;iA; i; 0; 0io; ;i;i;iB; i; 0; 0io; ;i;i;iC; i; 0; 0io; ;i;i;iD; i; 0; 0io; ;i;i;iE; i; 0; 0io; ;i;i;iF; i; 0; 0io; ;i;i;iG; i; 0; 0i o; ;i;i;iH; i ; 0; 0i!o; ;i;i;iI; i!; 0; 0i"o; ;i;i;iJ; i"; 0; 0i#o; ;i;i;iK; i#; 0; 0i$o; ;i;i;iL; i$; 0; 0i%o; ;i;i;iM; i%; 0; 0i&o; ;i;i;iN; i&; 0; 0i'o; ;i;i;iO; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i ;i; i1; 0; 0i2o; ;i;i ;i; i2; 0; 0i3o; ;i;i ;i; i3; 0; 0i4o; ;i;i ;i; i4; 0; 0i5o; ;i;i ;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i ;i; iH; 0; 0iIo; ;i;i!;i; iI; 0; 0iJo; ;i;i";i; iJ; 0; 0iKo; ;i;i#;i; iK; 0; 0iLo; ;i;i$;i; iL; 0; 0iMo; ;i;i%;i; iM; 0; 0iNo; ;i;i&;i; iN; 0; 0iOo; ;i;i';i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i<o; ;i;i;i; i<; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i? o; ;i;i;i; i? ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iP o; ;i;i;i; iP ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iR o; ;i;i;i; iR ; 0; 0iS o; ;i;i;i; iS ; 0; 0iT o; ;i;i;i; iT ; 0; 0iU o; ;i;i;i; iU ; 0; 0iV o; ;i;i;i; iV ; 0; 0iW o; ;i;i;i; iW ; 0; 0iX o; ;i;i;i; iX ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0id o; ;i;i;i; id ; 0; 0ie o; ;i;i;i; ie ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0iv o; ;i;i;i; iv ; 0; 0iw o; ;i;i;i; iw ; 0; 0ix o; ;i;i;i; ix ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i; o; ;i;i;i; i; ; 0; 0i< o; ;i;i;i; i< ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0iI o; ;i;i;i; iI ; 0; 0iJ o; ;i;i;i; iJ ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iN o; ;i;i;i; iN ; 0; 0iO o; ;i;i;i; iO ; 0; 0iP o; ;i;i;i; iP ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iR o; ;i;i;i; iR ; 0; 0iS o; ;i;i;i; iS ; 0; 0iT o; ;i;i;i; iT ; 0; 0iU o; ;i;i;i; iU ; 0; 0iX o; ;i;i;i; iX ; 0; 0iY o; ;i;i;i; iY ; 0; 0iZ o; ;i;i;i; iZ ; 0; 0i[ o; ;i;i;i; i[ ; 0; 0i\ o; ;i;i;i; i\ ; 0; 0i] o; ;i;i;i; i] ; 0; 0i^ o; ;i;i;i; i^ ; 0; 0i_ o; ;i;i;i; i_ ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0id o; ;i;i;i; id ; 0; 0ie o; ;i;i;i; ie ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0ix o; ;i;i;i; ix ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i; o; ;i;i;i; i; ; 0; 0i< o; ;i;i;i; i< ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i ;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; [i1i'i/o; ;i;i;i; i/; 0; [i2i'i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i ;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i! o; ;i;i;i; i! ; 0; 0i" o; ;i;i;i; i" ; 0; 0i# o; ;i;i;i; i# ; 0; 0i$ o; ;i;i;i; i$ ; 0; 0i% o; ;i;i;i; i% ; 0; 0i& o; ;i;i;i; i& ; 0; 0i' o; ;i;i;i; i' ; 0; 0i( o; ;i;i;i; i( ; 0; 0i) o; ;i;i;i; i) ; 0; 0i* o; ;i;i;i; i* ; 0; 0i+ o; ;i;i;i; i+ ; 0; 0i, o; ;i;i;i; i, ; 0; 0i- o; ;i;i;i; i- ; 0; 0i. o; ;i;i;i; i. ; 0; 0i/ o; ;i;i;i; i/ ; 0; 0i0 o; ;i;i;i; i0 ; 0; 0i1 o; ;i;i;i; i1 ; 0; 0i2 o; ;i;i;i; i2 ; 0; 0i3 o; ;i;i;i; i3 ; 0; 0i4 o; ;i;i;i; i4 ; 0; 0i5 o; ;i;i;i; i5 ; 0; 0i6 o; ;i;i;i; i6 ; 0; 0i7 o; ;i;i;i; i7 ; 0; 0i8 o; ;i;i;i; i8 ; 0; 0i9 o; ;i;i;i; i9 ; 0; 0i: o; ;i;i;i; i: ; 0; 0i; o; ;i;i;i; i; ; 0; 0i< o; ;i;i;i; i< ; 0; 0i= o; ;i;i;i; i= ; 0; 0i> o; ;i;i;i; i> ; 0; 0i? o; ;i;i;i; i? ; 0; 0i@ o; ;i;i;i; i@ ; 0; 0iA o; ;i;i;i; iA ; 0; 0iB o; ;i;i;i; iB ; 0; 0iC o; ;i;i;i; iC ; 0; 0iD o; ;i;i;i; iD ; 0; 0iE o; ;i;i;i; iE ; 0; 0iF o; ;i;i;i; iF ; 0; 0iG o; ;i;i;i; iG ; 0; 0iH o; ;i;i;i; iH ; 0; 0iI o; ;i;i;i; iI ; 0; 0iJ o; ;i;i;i; iJ ; 0; 0iK o; ;i;i;i; iK ; 0; 0iL o; ;i;i;i; iL ; 0; 0iM o; ;i;i;i; iM ; 0; 0iN o; ;i;i;i; iN ; 0; 0iO o; ;i;i;i; iO ; 0; 0iP o; ;i;i;i; iP ; 0; 0iQ o; ;i;i;i; iQ ; 0; 0iR o; ;i;i;i; iR ; 0; 0iS o; ;i;i;i; iS ; 0; 0iT o; ;i;i;i; iT ; 0; 0iU o; ;i;i;i; iU ; 0; 0iV o; ;i;i;i; iV ; 0; 0iW o; ;i;i;i; iW ; 0; 0iX o; ;i;i;i; iX ; 0; 0iY o; ;i;i;i; iY ; 0; 0iZ o; ;i;i;i; iZ ; 0; 0i[ o; ;i;i;i; i[ ; 0; 0i\ o; ;i;i;i; i\ ; 0; 0i] o; ;i;i;i; i] ; 0; 0i^ o; ;i;i;i; i^ ; 0; 0i_ o; ;i;i;i; i_ ; 0; 0i` o; ;i;i;i; i` ; 0; 0ia o; ;i;i;i; ia ; 0; 0ib o; ;i;i;i; ib ; 0; 0ic o; ;i;i;i; ic ; 0; 0id o; ;i;i;i; id ; 0; 0ie o; ;i;i;i; ie ; 0; 0if o; ;i;i;i; if ; 0; 0ig o; ;i;i;i; ig ; 0; 0ih o; ;i;i;i; ih ; 0; 0ii o; ;i;i;i; ii ; 0; 0ij o; ;i;i;i; ij ; 0; 0ik o; ;i;i;i; ik ; 0; 0il o; ;i;i;i; il ; 0; 0im o; ;i;i;i; im ; 0; 0in o; ;i;i;i; in ; 0; 0io o; ;i;i;i; io ; 0; 0ip o; ;i;i;i; ip ; 0; 0iq o; ;i;i;i; iq ; 0; 0ir o; ;i;i;i; ir ; 0; 0is o; ;i;i;i; is ; 0; 0it o; ;i;i;i; it ; 0; 0iu o; ;i;i;i; iu ; 0; 0iv o; ;i;i;i; iv ; 0; 0iw o; ;i;i;i; iw ; 0; 0ix o; ;i;i;i; ix ; 0; 0iy o; ;i;i;i; iy ; 0; 0iz o; ;i;i;i; iz ; 0; 0i{ o; ;i;i;i; i{ ; 0; 0i| o; ;i;i;i; i| ; 0; 0i} o; ;i;i;i; i} ; 0; 0i~ o; ;i;i;i; i~ ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i !o; ;i;i;i; i !; 0; 0i !o; ;i;i;i; i !; 0; 0i !o; ;i;i;i; i !; 0; 0i !o; ;i;i;i; i !; 0; 0i !o; ;i;i;i; i !; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i !o; ;i;i;i; i !; 0; 0i!!o; ;i;i;i; i!!; 0; 0i"!o; ;i;i;i; i"!; 0; 0i#!o; ;i;i;i; i#!; 0; 0i$!o; ;i;i;i; i$!; 0; 0i%!o; ;i;i;i; i%!; 0; 0i&!o; ;i;i;i; i&!; 0; 0i'!o; ;i;i;i; i'!; 0; 0i(!o; ;i;i;i; i(!; 0; 0i)!o; ;i;i;i; i)!; 0; 0i*!o; ;i;i;i; i*!; 0; 0i+!o; ;i;i;i; i+!; 0; 0i,!o; ;i;i;i; i,!; 0; 0i-!o; ;i;i;i; i-!; 0; 0i.!o; ;i;i;i; i.!; 0; 0i/!o; ;i;i;i; i/!; 0; 0i0!o; ;i;i;i; i0!; 0; 0i1!o; ;i;i;i; i1!; 0; 0i2!o; ;i;i;i; i2!; 0; 0i3!o; ;i;i;i; i3!; 0; 0i4!o; ;i;i;i; i4!; 0; 0i5!o; ;i;i;i; i5!; 0; 0i6!o; ;i;i;i; i6!; 0; 0i7!o; ;i;i;i; i7!; 0; 0i8!o; ;i;i;i; i8!; 0; 0i9!o; ;i;i;i; i9!; 0; 0i:!o; ;i;i;i; i:!; 0; 0i;!o; ;i;i;i; i;!; 0; 0i!o; ;i;i;i; i>!; 0; 0i?!o; ;i;i;i; i?!; 0; 0i@!o; ;i;i;i; i@!; 0; 0iA!o; ;i;i;i; iA!; 0; 0iB!o; ;i;i;i; iB!; 0; 0iC!o; ;i;i;i; iC!; 0; 0iD!o; ;i;i;i; iD!; 0; 0iE!o; ;i;i;i; iE!; 0; 0iF!o; ;i;i;i; iF!; 0; 0iG!o; ;i;i;i; iG!; 0; 0iH!o; ;i;i;i; iH!; 0; 0iI!o; ;i;i;i; iI!; 0; 0iJ!o; ;i;i;i; iJ!; 0; 0iK!o; ;i;i;i; iK!; 0; 0iL!o; ;i;i;i; iL!; 0; 0iM!o; ;i;i;i; iM!; 0; 0iN!o; ;i;i;i; iN!; 0; 0iO!o; ;i;i;i; iO!; 0; 0iP!o; ;i;i;i; iP!; 0; 0iQ!o; ;i;i;i; iQ!; 0; 0iR!o; ;i;i;i; iR!; 0; 0iS!o; ;i;i;i; iS!; 0; 0iT!o; ;i;i;i; iT!; 0; 0iU!o; ;i;i;i; iU!; 0; 0iV!o; ;i;i;i; iV!; 0; 0iW!o; ;i;i;i; iW!; 0; 0iX!o; ;i;i;i; iX!; 0; 0iY!o; ;i;i;i; iY!; 0; 0iZ!o; ;i;i;i; iZ!; 0; 0i[!o; ;i;i;i; i[!; 0; 0i\!o; ;i;i;i; i\!; 0; 0i]!o; ;i;i;i; i]!; 0; 0i^!o; ;i;i;i; i^!; 0; 0i_!o; ;i;i;i; i_!; 0; 0i`!o; ;i;i;i; i`!; 0; 0ia!o; ;i;i;i; ia!; 0; 0ib!o; ;i;i;i; ib!; 0; 0ic!o; ;i;i;i; ic!; 0; 0id!o; ;i;i;i; id!; 0; 0ie!o; ;i;i;i; ie!; 0; 0if!o; ;i;i;i; if!; 0; 0ig!o; ;i;i;i; ig!; 0; 0ih!o; ;i;i;i; ih!; 0; 0ii!o; ;i;i;i; ii!; 0; 0ij!o; ;i;i;i; ij!; 0; 0ik!o; ;i;i;i; ik!; 0; 0il!o; ;i;i;i; il!; 0; 0im!o; ;i;i;i; im!; 0; 0in!o; ;i;i;i; in!; 0; 0io!o; ;i;i;i; io!; 0; 0ip!o; ;i;i;i; ip!; 0; 0iq!o; ;i;i;i; iq!; 0; 0ir!o; ;i;i;i; ir!; 0; 0is!o; ;i;i;i; is!; 0; 0it!o; ;i;i;i; it!; 0; 0iu!o; ;i;i;i; iu!; 0; 0iv!o; ;i;i;i; iv!; 0; 0iw!o; ;i;i;i; iw!; 0; 0ix!o; ;i;i;i; ix!; 0; 0iy!o; ;i;i;i; iy!; 0; 0iz!o; ;i;i;i; iz!; 0; 0i{!o; ;i;i;i; i{!; 0; 0i|!o; ;i;i;i; i|!; 0; 0i}!o; ;i;i;i; i}!; 0; 0i~!o; ;i;i;i; i~!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i "o; ;i;i;i; i "; 0; 0i "o; ;i;i;i; i "; 0; 0i "o; ;i;i;i; i "; 0; 0i "o; ;i;i;i; i "; 0; 0i "o; ;i;i;i; i "; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i "o; ;i;i;i; i "; 0; 0i!"o; ;i;i;i; i!"; 0; 0i""o; ;i;i;i; i""; 0; 0i#"o; ;i;i;i; i#"; 0; 0i$"o; ;i;i;i; i$"; 0; 0i%"o; ;i;i;i; i%"; 0; 0i&"o; ;i;i;i; i&"; 0; 0i'"o; ;i;i;i; i'"; 0; 0i("o; ;i;i;i; i("; 0; 0i)"o; ;i;i;i; i)"; 0; 0i*"o; ;i;i;i; i*"; 0; 0i+"o; ;i;i;i; i+"; 0; 0i,"o; ;i;i;i; i,"; 0; 0i-"o; ;i;i;i; i-"; 0; 0i."o; ;i;i;i; i."; 0; 0i/"o; ;i;i;i; i/"; 0; 0i0"o; ;i;i;i; i0"; 0; 0i1"o; ;i;i;i; i1"; 0; 0i2"o; ;i;i;i; i2"; 0; 0i3"o; ;i;i;i; i3"; 0; 0i4"o; ;i;i;i; i4"; 0; 0i5"o; ;i;i;i; i5"; 0; 0i6"o; ;i;i;i; i6"; 0; 0i7"o; ;i;i;i; i7"; 0; 0i8"o; ;i;i;i; i8"; 0; 0i9"o; ;i;i;i; i9"; 0; 0i:"o; ;i;i;i; i:"; 0; 0i;"o; ;i;i;i; i;"; 0; 0i<"o; ;i;i;i; i<"; 0; 0i="o; ;i;i;i; i="; 0; 0i>"o; ;i;i;i; i>"; 0; 0i?"o; ;i;i;i; i?"; 0; 0i@"o; ;i;i;i; i@"; 0; 0iA"o; ;i;i;i; iA"; 0; 0iB"o; ;i;i;i; iB"; 0; 0iC"o; ;i;i;i; iC"; 0; 0iD"o; ;i;i;i; iD"; 0; 0iE"o; ;i;i;i; iE"; 0; 0iF"o; ;i;i;i; iF"; 0; 0iG"o; ;i;i;i; iG"; 0; 0iH"o; ;i;i;i; iH"; 0; 0iI"o; ;i;i;i; iI"; 0; 0iJ"o; ;i;i;i; iJ"; 0; 0iK"o; ;i;i;i; iK"; 0; 0iL"o; ;i;i;i; iL"; 0; 0iM"o; ;i;i;i; iM"; 0; 0iN"o; ;i;i;i; iN"; 0; 0iO"o; ;i;i;i; iO"; 0; 0iP"o; ;i;i;i; iP"; 0; 0iQ"o; ;i;i;i; iQ"; 0; 0iR"o; ;i;i;i; iR"; 0; 0iS"o; ;i;i;i; iS"; 0; 0iT"o; ;i;i;i; iT"; 0; 0iU"o; ;i;i;i; iU"; 0; 0iV"o; ;i;i;i; iV"; 0; 0iW"o; ;i;i;i; iW"; 0; 0iX"o; ;i;i;i; iX"; 0; 0iY"o; ;i;i;i; iY"; 0; 0iZ"o; ;i;i;i; iZ"; 0; 0i["o; ;i;i;i; i["; 0; 0i\"o; ;i;i;i; i\"; 0; 0i]"o; ;i;i;i; i]"; 0; 0i^"o; ;i;i;i; i^"; 0; 0i_"o; ;i;i;i; i_"; 0; 0i`"o; ;i;i;i; i`"; 0; 0ia"o; ;i;i;i; ia"; 0; 0ib"o; ;i;i;i; ib"; 0; 0ic"o; ;i;i;i; ic"; 0; 0id"o; ;i;i;i; id"; 0; 0ie"o; ;i;i;i; ie"; 0; 0if"o; ;i;i;i; if"; 0; 0ig"o; ;i;i;i; ig"; 0; 0ih"o; ;i;i;i; ih"; 0; 0ii"o; ;i;i;i; ii"; 0; 0ij"o; ;i;i;i; ij"; 0; 0ik"o; ;i;i;i; ik"; 0; 0il"o; ;i;i;i; il"; 0; 0im"o; ;i;i;i; im"; 0; 0in"o; ;i;i;i; in"; 0; 0io"o; ;i;i;i; io"; 0; 0ip"o; ;i;i;i; ip"; 0; 0iq"o; ;i;i;i; iq"; 0; 0ir"o; ;i;i;i; ir"; 0; 0is"o; ;i;i;i; is"; 0; 0it"o; ;i;i;i; it"; 0; 0iu"o; ;i;i;i; iu"; 0; 0iv"o; ;i;i;i; iv"; 0; 0iw"o; ;i;i;i; iw"; 0; 0ix"o; ;i;i;i; ix"; 0; 0iy"o; ;i;i;i; iy"; 0; 0iz"o; ;i;i;i; iz"; 0; 0i{"o; ;i;i;i; i{"; 0; 0i|"o; ;i;i;i; i|"; 0; 0i}"o; ;i;i;i; i}"; 0; 0i~"o; ;i;i;i; i~"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i #o; ;i;i;i; i #; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i#o; ;i;i;i; i#; 0; 0i #o; ;i;i;i; i #; 0; 0i!#o; ;i;i;i; i!#; 0; 0i"#o; ;i;i;i; i"#; 0; 0i##o; ;i;i;i; i##; 0; 0i$#o; ;i;i;i; i$#; 0; 0i%#o; ;i;i;i; i%#; 0; 0i&#o; ;i;i;i; i&#; 0; 0i'#o; ;i;i;i; i'#; 0; 0i(#o; ;i;i;i; i(#; 0; 0i)#o; ;i;i;i; i)#; 0; 0i*#o; ;i;i;i; i*#; 0; 0i+#o; ;i;i;i; i+#; 0; 0i,#o; ;i;i;i; i,#; 0; 0i-#o; ;i;i;i; i-#; 0; 0i.#o; ;i;i;i; i.#; 0; 0i/#o; ;i;i;i; i/#; 0; 0i0#o; ;i;i;i; i0#; 0; 0i1#o; ;i;i;i; i1#; 0; 0i2#o; ;i;i;i; i2#; 0; 0i3#o; ;i;i;i; i3#; 0; 0i4#o; ;i;i;i; i4#; 0; 0i5#o; ;i;i;i; i5#; 0; 0i6#o; ;i;i;i; i6#; 0; 0i7#o; ;i;i;i; i7#; 0; 0i8#o; ;i;i;i; i8#; 0; 0i9#o; ;i;i;i; i9#; 0; 0i:#o; ;i;i;i; i:#; 0; 0i;#o; ;i;i;i; i;#; 0; 0i<#o; ;i;i;i; i<#; 0; 0i=#o; ;i;i;i; i=#; 0; 0i>#o; ;i;i;i; i>#; 0; 0i?#o; ;i;i;i; i?#; 0; 0i@#o; ;i;i;i; i@#; 0; 0iA#o; ;i;i;i; iA#; 0; 0iB#o; ;i;i;i; iB#; 0; 0iC#o; ;i;i;i; iC#; 0; 0iD#o; ;i;i;i; iD#; 0; 0iE#o; ;i;i;i; iE#; 0; 0iF#o; ;i;i;i; iF#; 0; 0iG#o; ;i;i;i; iG#; 0; 0iH#o; ;i;i;i; iH#; 0; 0iI#o; ;i;i;i; iI#; 0; 0iJ#o; ;i;i;i; iJ#; 0; 0iK#o; ;i;i;i; iK#; 0; 0iL#o; ;i;i;i; iL#; 0; 0iM#o; ;i;i;i; iM#; 0; 0iN#o; ;i;i;i; iN#; 0; 0iO#o; ;i;i;i; iO#; 0; 0iP#o; ;i;i;i; iP#; 0; 0iQ#o; ;i;i;i; iQ#; 0; 0iR#o; ;i;i;i; iR#; 0; 0iS#o; ;i;i;i; iS#; 0; 0iT#o; ;i;i;i; iT#; 0; 0iU#o; ;i;i;i; iU#; 0; 0iV#o; ;i;i;i; iV#; 0; 0iW#o; ;i;i;i; iW#; 0; 0iX#o; ;i;i;i; iX#; 0; 0iY#o; ;i;i;i; iY#; 0; 0iZ#o; ;i;i;i; iZ#; 0; 0i[#o; ;i;i;i; i[#; 0; 0i\#o; ;i;i;i; i\#; 0; 0i]#o; ;i;i;i; i]#; 0; 0i^#o; ;i;i;i; i^#; 0; 0i_#o; ;i;i;i; i_#; 0; 0i`#o; ;i;i;i; i`#; 0; 0ia#o; ;i;i;i; ia#; 0; 0ib#o; ;i;i;i; ib#; 0; 0ic#o; ;i;i;i; ic#; 0; 0id#o; ;i;i;i; id#; 0; 0ie#o; ;i;i;i; ie#; 0; 0if#o; ;i;i;i; if#; 0; 0ig#o; ;i;i;i; ig#; 0; 0ih#o; ;i;i;i; ih#; 0; 0ii#o; ;i;i;i; ii#; 0; 0ij#o; ;i;i;i; ij#; 0; 0ik#o; ;i;i;i; ik#; 0; 0il#o; ;i;i;i; il#; 0; 0im#o; ;i;i;i; im#; 0; 0in#o; ;i;i;i; in#; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i $o; ;i;i;i; i $; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i$o; ;i;i;i; i$; 0; 0i $o; ;i;i;i; i $; 0; 0i!$o; ;i;i;i; i!$; 0; 0i"$o; ;i;i;i; i"$; 0; 0i#$o; ;i;i;i; i#$; 0; 0i$$o; ;i;i;i; i$$; 0; 0i%$o; ;i;i;i; i%$; 0; 0i&$o; ;i;i;i; i&$; 0; 0i'$o; ;i;i;i; i'$; 0; 0i($o; ;i;i;i; i($; 0; 0i)$o; ;i;i;i; i)$; 0; 0i*$o; ;i;i;i; i*$; 0; 0i+$o; ;i;i;i; i+$; 0; 0i,$o; ;i;i;i; i,$; 0; 0i-$o; ;i;i;i; i-$; 0; 0i.$o; ;i;i;i; i.$; 0; 0i/$o; ;i;i;i; i/$; 0; 0i0$o; ;i;i;i; i0$; 0; 0i1$o; ;i;i;i; i1$; 0; 0i2$o; ;i;i;i; i2$; 0; 0i3$o; ;i;i;i; i3$; 0; 0i4$o; ;i;i;i; i4$; 0; 0i5$o; ;i;i;i; i5$; 0; 0i6$o; ;i;i;i; i6$; 0; 0i7$o; ;i;i;i; i7$; 0; 0i8$o; ;i;i;i; i8$; 0; 0i9$o; ;i;i;i; i9$; 0; 0i:$o; ;i;i;i; i:$; 0; 0i;$o; ;i;i;i; i;$; 0; 0i<$o; ;i;i;i; i<$; 0; 0i=$o; ;i;i;i; i=$; 0; 0i>$o; ;i;i;i; i>$; 0; 0i?$o; ;i;i;i; i?$; 0; 0i@$o; ;i;i;i; i@$; 0; 0iA$o; ;i;i;i; iA$; 0; 0iB$o; ;i;i;i; iB$; 0; 0iC$o; ;i;i;i; iC$; 0; 0iD$o; ;i;i;i; iD$; 0; 0iE$o; ;i;i;i; iE$; 0; 0iF$o; ;i;i;i; iF$; 0; 0iG$o; ;i;i;i; iG$; 0; 0iH$o; ;i;i;i; iH$; 0; 0iI$o; ;i;i;i; iI$; 0; 0iJ$o; ;i;i;i; iJ$; 0; 0iK$o; ;i;i;i; iK$; 0; 0iL$o; ;i;i;i; iL$; 0; 0iM$o; ;i;i;i; iM$; 0; 0iN$o; ;i;i;i; iN$; 0; 0iO$o; ;i;i;i; iO$; 0; 0iP$o; ;i;i;i; iP$; 0; 0iQ$o; ;i;i;i; iQ$; 0; 0iR$o; ;i;i;i; iR$; 0; 0iS$o; ;i;i;i; iS$; 0; 0iT$o; ;i;i;i; iT$; 0; 0iU$o; ;i;i;i; iU$; 0; 0iV$o; ;i;i;i; iV$; 0; 0iW$o; ;i;i;i; iW$; 0; 0iX$o; ;i;i;i; iX$; 0; 0iY$o; ;i;i;i; iY$; 0; 0iZ$o; ;i;i;i; iZ$; 0; 0i[$o; ;i;i;i; i[$; 0; 0i\$o; ;i;i;i; i\$; 0; 0i]$o; ;i;i;i; i]$; 0; 0i^$o; ;i;i;i; i^$; 0; 0i_$o; ;i;i;i; i_$; 0; 0i`$o; ;i;i;i; i`$; 0; 0ia$o; ;i;i;i; ia$; 0; 0ib$o; ;i;i;i; ib$; 0; 0ip$o; ;i;i;i; ip$; 0; 0iq$o; ;i;i;i; iq$; 0; 0ir$o; ;i;i;i; ir$; 0; 0is$o; ;i;i;i; is$; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i 0o; ;i;i;i; i 0; 0; 0i!0o; ;i;i;i; i!0; 0; 0i"0o; ;i;i;i; i"0; 0; 0i#0o; ;i;i;i; i#0; 0; 0i$0o; ;i;i;i; i$0; 0; 0i%0o; ;i;i;i; i%0; 0; 0i&0o; ;i;i;i; i&0; 0; 0i'0o; ;i;i;i; i'0; 0; 0i(0o; ;i;i;i; i(0; 0; 0i)0o; ;i;i;i; i)0; 0; 0i*0o; ;i;i;i; i*0; 0; 0i+0o; ;i;i;i; i+0; 0; 0i,0o; ;i;i;i; i,0; 0; 0i-0o; ;i;i;i; i-0; 0; 0i.0o; ;i;i;i; i.0; 0; 0i/0o; ;i;i;i; i/0; 0; 0i00o; ;i;i;i; i00; 0; 0i10o; ;i;i;i; i10; 0; 0i20o; ;i;i;i; i20; 0; 0i30o; ;i;i;i; i30; 0; 0i40o; ;i;i;i; i40; 0; 0i50o; ;i;i;i; i50; 0; 0i60o; ;i;i;i; i60; 0; 0i70o; ;i;i;i; i70; 0; 0i80o; ;i;i;i; i80; 0; 0i90o; ;i;i;i; i90; 0; 0i:0o; ;i;i;i; i:0; 0; 0i;0o; ;i;i;i; i;0; 0; 0i<0o; ;i;i;i; i<0; 0; 0i=0o; ;i;i;i; i=0; 0; 0i>0o; ;i;i;i; i>0; 0; 0i?0o; ;i;i;i; i?0; 0; 0i@0o; ;i;i;i; i@0; 0; 0iA0o; ;i;i;i; iA0; 0; 0iB0o; ;i;i;i; iB0; 0; 0iC0o; ;i;i;i; iC0; 0; 0iD0o; ;i;i;i; iD0; 0; 0iE0o; ;i;i;i; iE0; 0; 0iF0o; ;i;i;i; iF0; 0; 0iG0o; ;i;i;i; iG0; 0; 0iH0o; ;i;i;i; iH0; 0; 0iI0o; ;i;i;i; iI0; 0; 0iJ0o; ;i;i;i; iJ0; 0; 0iK0o; ;i;i;i; iK0; 0; 0iL0o; ;i;i;i; iL0; 0; 0iM0o; ;i;i;i; iM0; 0; 0iN0o; ;i;i;i; iN0; 0; 0iO0o; ;i;i;i; iO0; 0; 0iP0o; ;i;i;i; iP0; 0; 0iQ0o; ;i;i;i; iQ0; 0; 0iR0o; ;i;i;i; iR0; 0; 0iS0o; ;i;i;i; iS0; 0; 0iT0o; ;i;i;i; iT0; 0; 0iU0o; ;i;i;i; iU0; 0; 0iV0o; ;i;i;i; iV0; 0; 0iW0o; ;i;i;i; iW0; 0; 0iX0o; ;i;i;i; iX0; 0; 0iY0o; ;i;i;i; iY0; 0; 0iZ0o; ;i;i;i; iZ0; 0; 0i[0o; ;i;i;i; i[0; 0; 0i\0o; ;i;i;i; i\0; 0; 0i]0o; ;i;i;i; i]0; 0; 0i^0o; ;i;i;i; i^0; 0; 0i_0o; ;i;i;i; i_0; 0; 0i`0o; ;i;i;i; i`0; 0; 0ia0o; ;i;i;i; ia0; 0; 0ib0o; ;i;i;i; ib0; 0; 0ic0o; ;i;i;i; ic0; 0; 0id0o; ;i;i;i; id0; 0; 0ie0o; ;i;i;i; ie0; 0; 0if0o; ;i;i;i; if0; 0; 0ig0o; ;i;i;i; ig0; 0; 0ih0o; ;i;i;i; ih0; 0; 0ii0o; ;i;i;i; ii0; 0; 0ij0o; ;i;i;i; ij0; 0; 0ik0o; ;i;i;i; ik0; 0; 0il0o; ;i;i;i; il0; 0; 0im0o; ;i;i;i; im0; 0; 0in0o; ;i;i;i; in0; 0; 0io0o; ;i;i;i; io0; 0; 0ip0o; ;i;i;i; ip0; 0; 0iq0o; ;i;i;i; iq0; 0; 0ir0o; ;i;i;i; ir0; 0; 0is0o; ;i;i;i; is0; 0; 0it0o; ;i;i;i; it0; 0; 0iu0o; ;i;i;i; iu0; 0; 0iv0o; ;i;i;i; iv0; 0; 0iw0o; ;i;i;i; iw0; 0; 0ix0o; ;i;i;i; ix0; 0; 0iy0o; ;i;i;i; iy0; 0; 0iz0o; ;i;i;i; iz0; 0; 0i{0o; ;i;i;i; i{0; 0; 0i|0o; ;i;i;i; i|0; 0; 0i}0o; ;i;i;i; i}0; 0; 0i~0o; ;i;i;i; i~0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i 1o; ;i;i;i; i 1; 0; 0i!1o; ;i;i;i; i!1; 0; 0i"1o; ;i;i;i; i"1; 0; 0i#1o; ;i;i;i; i#1; 0; 0i$1o; ;i;i;i; i$1; 0; 0i%1o; ;i;i;i; i%1; 0; 0i&1o; ;i;i;i; i&1; 0; 0i'1o; ;i;i;i; i'1; 0; 0i(1o; ;i;i;i; i(1; 0; 0i)1o; ;i;i;i; i)1; 0; 0i*1o; ;i;i;i; i*1; 0; 0i+1o; ;i;i;i; i+1; 0; 0i,1o; ;i;i;i; i,1; 0; 0i-1o; ;i;i;i; i-1; 0; 0i.1o; ;i;i;i; i.1; 0; 0i/1o; ;i;i;i; i/1; 0; 0i01o; ;i;i;i; i01; 0; 0i11o; ;i;i;i; i11; 0; 0i21o; ;i;i;i; i21; 0; 0i31o; ;i;i;i; i31; 0; 0i41o; ;i;i;i; i41; 0; 0i51o; ;i;i;i; i51; 0; 0i61o; ;i;i;i; i61; 0; 0i71o; ;i;i;i; i71; 0; 0i81o; ;i;i;i; i81; 0; 0i91o; ;i;i;i; i91; 0; 0i:1o; ;i;i;i; i:1; 0; 0i;1o; ;i;i;i; i;1; 0; 0i<1o; ;i;i;i; i<1; 0; 0i=1o; ;i;i;i; i=1; 0; 0i>1o; ;i;i;i; i>1; 0; 0i?1o; ;i;i;i; i?1; 0; 0i@1o; ;i;i;i; i@1; 0; 0iA1o; ;i;i;i; iA1; 0; 0iB1o; ;i;i;i; iB1; 0; 0iC1o; ;i;i;i; iC1; 0; 0iD1o; ;i;i;i; iD1; 0; 0iE1o; ;i;i;i; iE1; 0; 0iF1o; ;i;i;i; iF1; 0; 0iG1o; ;i;i;i; iG1; 0; 0iH1o; ;i;i;i; iH1; 0; 0iI1o; ;i;i;i; iI1; 0; 0iJ1o; ;i;i;i; iJ1; 0; 0iK1o; ;i;i;i; iK1; 0; 0iL1o; ;i;i;i; iL1; 0; 0iM1o; ;i;i;i; iM1; 0; 0iN1o; ;i;i;i; iN1; 0; 0iO1o; ;i;i;i; iO1; 0; 0iP1o; ;i;i;i; iP1; 0; 0iQ1o; ;i;i;i; iQ1; 0; 0iR1o; ;i;i;i; iR1; 0; 0iS1o; ;i;i;i; iS1; 0; 0iT1o; ;i;i;i; iT1; 0; 0iU1o; ;i;i;i; iU1; 0; 0iV1o; ;i;i;i; iV1; 0; 0iW1o; ;i;i;i; iW1; 0; 0iX1o; ;i;i;i; iX1; 0; 0iY1o; ;i;i;i; iY1; 0; 0iZ1o; ;i;i;i; iZ1; 0; 0i[1o; ;i;i;i; i[1; 0; 0i\1o; ;i;i;i; i\1; 0; 0i]1o; ;i;i;i; i]1; 0; 0i^1o; ;i;i;i; i^1; 0; 0i_1o; ;i;i;i; i_1; 0; 0i`1o; ;i;i;i; i`1; 0; 0ia1o; ;i;i;i; ia1; 0; 0ib1o; ;i;i;i; ib1; 0; 0ic1o; ;i;i;i; ic1; 0; 0id1o; ;i;i;i; id1; 0; 0ie1o; ;i;i;i; ie1; 0; 0if1o; ;i;i;i; if1; 0; 0ig1o; ;i;i;i; ig1; 0; 0ih1o; ;i;i;i; ih1; 0; 0ii1o; ;i;i;i; ii1; 0; 0ij1o; ;i;i;i; ij1; 0; 0ik1o; ;i;i;i; ik1; 0; 0il1o; ;i;i;i; il1; 0; 0im1o; ;i;i;i; im1; 0; 0in1o; ;i;i;i; in1; 0; 0io1o; ;i;i;i; io1; 0; 0ip1o; ;i;i;i; ip1; 0; 0iq1o; ;i;i;i; iq1; 0; 0ir1o; ;i;i;i; ir1; 0; 0is1o; ;i;i;i; is1; 0; 0it1o; ;i;i;i; it1; 0; 0iu1o; ;i;i;i; iu1; 0; 0iv1o; ;i;i;i; iv1; 0; 0iw1o; ;i;i;i; iw1; 0; 0ix1o; ;i;i;i; ix1; 0; 0iy1o; ;i;i;i; iy1; 0; 0iz1o; ;i;i;i; iz1; 0; 0i{1o; ;i;i;i; i{1; 0; 0i|1o; ;i;i;i; i|1; 0; 0i}1o; ;i;i;i; i}1; 0; 0i~1o; ;i;i;i; i~1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i 2o; ;i;i;i; i 2; 0; 0i!2o; ;i;i;i; i!2; 0; 0i"2o; ;i;i;i; i"2; 0; 0i#2o; ;i;i;i; i#2; 0; 0i$2o; ;i;i;i; i$2; 0; 0i%2o; ;i;i;i; i%2; 0; 0i&2o; ;i;i;i; i&2; 0; 0i'2o; ;i;i;i; i'2; 0; 0i(2o; ;i;i;i; i(2; 0; 0i)2o; ;i;i;i; i)2; 0; 0i*2o; ;i;i;i; i*2; 0; 0i+2o; ;i;i;i; i+2; 0; 0i,2o; ;i;i;i; i,2; 0; 0i-2o; ;i;i;i; i-2; 0; 0i.2o; ;i;i;i; i.2; 0; 0i/2o; ;i;i;i; i/2; 0; 0i02o; ;i;i;i; i02; 0; 0i12o; ;i;i;i; i12; 0; 0i22o; ;i;i;i; i22; 0; 0i32o; ;i;i;i; i32; 0; 0i42o; ;i;i;i; i42; 0; 0i52o; ;i;i;i; i52; 0; 0i62o; ;i;i;i; i62; 0; 0i72o; ;i;i;i; i72; 0; 0i82o; ;i;i;i; i82; 0; 0i92o; ;i;i;i; i92; 0; 0i:2o; ;i;i;i; i:2; 0; 0i;2o; ;i;i;i; i;2; 0; 0i<2o; ;i;i;i; i<2; 0; 0i=2o; ;i;i;i; i=2; 0; 0i>2o; ;i;i;i; i>2; 0; 0i?2o; ;i;i;i; i?2; 0; 0i@2o; ;i;i;i; i@2; 0; 0iA2o; ;i;i;i; iA2; 0; 0iB2o; ;i;i;i; iB2; 0; 0iC2o; ;i;i;i; iC2; 0; 0iD2o; ;i;i;i; iD2; 0; 0iE2o; ;i;i;i; iE2; 0; 0iF2o; ;i;i;i; iF2; 0; 0iG2o; ;i;i;i; iG2; 0; 0iH2o; ;i;i;i; iH2; 0; 0iI2o; ;i;i;i; iI2; 0; 0iJ2o; ;i;i;i; iJ2; 0; 0iK2o; ;i;i;i; iK2; 0; 0iL2o; ;i;i;i; iL2; 0; 0iM2o; ;i;i;i; iM2; 0; 0iN2o; ;i;i;i; iN2; 0; 0iO2o; ;i;i;i; iO2; 0; 0iP2o; ;i;i;i; iP2; 0; 0iQ2o; ;i;i;i; iQ2; 0; 0iR2o; ;i;i;i; iR2; 0; 0iS2o; ;i;i;i; iS2; 0; 0iT2o; ;i;i;i; iT2; 0; 0iU2o; ;i;i;i; iU2; 0; 0iV2o; ;i;i;i; iV2; 0; 0iW2o; ;i;i;i; iW2; 0; 0iX2o; ;i;i;i; iX2; 0; 0iY2o; ;i;i;i; iY2; 0; 0iZ2o; ;i;i;i; iZ2; 0; 0i[2o; ;i;i;i; i[2; 0; 0i\2o; ;i;i;i; i\2; 0; 0i]2o; ;i;i;i; i]2; 0; 0i^2o; ;i;i;i; i^2; 0; 0i_2o; ;i;i;i; i_2; 0; 0i`2o; ;i;i;i; i`2; 0; 0ia2o; ;i;i;i; ia2; 0; 0ib2o; ;i;i;i; ib2; 0; 0ic2o; ;i;i;i; ic2; 0; 0id2o; ;i;i;i; id2; 0; 0ie2o; ;i;i;i; ie2; 0; 0if2o; ;i;i;i; if2; 0; 0ig2o; ;i;i;i; ig2; 0; 0ih2o; ;i;i;i; ih2; 0; 0ii2o; ;i;i;i; ii2; 0; 0ij2o; ;i;i;i; ij2; 0; 0ik2o; ;i;i;i; ik2; 0; 0il2o; ;i;i;i; il2; 0; 0im2o; ;i;i;i; im2; 0; 0in2o; ;i;i;i; in2; 0; 0io2o; ;i;i;i; io2; 0; 0ip2o; ;i;i;i; ip2; 0; 0iq2o; ;i;i;i; iq2; 0; 0ir2o; ;i;i;i; ir2; 0; 0is2o; ;i;i;i; is2; 0; 0it2o; ;i;i;i; it2; 0; 0iu2o; ;i;i;i; iu2; 0; 0iv2o; ;i;i;i; iv2; 0; 0iw2o; ;i;i;i; iw2; 0; 0ix2o; ;i;i;i; ix2; 0; 0iy2o; ;i;i;i; iy2; 0; 0iz2o; ;i;i;i; iz2; 0; 0i{2o; ;i;i;i; i{2; 0; 0i|2o; ;i;i;i; i|2; 0; 0i}2o; ;i;i;i; i}2; 0; 0i~2o; ;i;i;i; i~2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i 3o; ;i;i;i; i 3; 0; 0i!3o; ;i;i;i; i!3; 0; 0i"3o; ;i;i;i; i"3; 0; 0i#3o; ;i;i;i; i#3; 0; 0i$3o; ;i;i;i; i$3; 0; 0i%3o; ;i;i;i; i%3; 0; 0i&3o; ;i;i;i; i&3; 0; 0i'3o; ;i;i;i; i'3; 0; 0i(3o; ;i;i;i; i(3; 0; 0i)3o; ;i;i;i; i)3; 0; 0i*3o; ;i;i;i; i*3; 0; 0i+3o; ;i;i;i; i+3; 0; 0i,3o; ;i;i;i; i,3; 0; 0i-3o; ;i;i;i; i-3; 0; 0i.3o; ;i;i;i; i.3; 0; 0i/3o; ;i;i;i; i/3; 0; 0i03o; ;i;i;i; i03; 0; 0i13o; ;i;i;i; i13; 0; 0i23o; ;i;i;i; i23; 0; 0i33o; ;i;i;i; i33; 0; 0i43o; ;i;i;i; i43; 0; 0i53o; ;i;i;i; i53; 0; 0i63o; ;i;i;i; i63; 0; 0i73o; ;i;i;i; i73; 0; 0i83o; ;i;i;i; i83; 0; 0i93o; ;i;i;i; i93; 0; 0i:3o; ;i;i;i; i:3; 0; 0i;3o; ;i;i;i; i;3; 0; 0i<3o; ;i;i;i; i<3; 0; 0i=3o; ;i;i;i; i=3; 0; 0i>3o; ;i;i;i; i>3; 0; 0i?3o; ;i;i;i; i?3; 0; 0i@3o; ;i;i;i; i@3; 0; 0iA3o; ;i;i;i; iA3; 0; 0iB3o; ;i;i;i; iB3; 0; 0iC3o; ;i;i;i; iC3; 0; 0iD3o; ;i;i;i; iD3; 0; 0iE3o; ;i;i;i; iE3; 0; 0iF3o; ;i;i;i; iF3; 0; 0iG3o; ;i;i;i; iG3; 0; 0iH3o; ;i;i;i; iH3; 0; 0iI3o; ;i;i;i; iI3; 0; 0iJ3o; ;i;i;i; iJ3; 0; 0iK3o; ;i;i;i; iK3; 0; 0iL3o; ;i;i;i; iL3; 0; 0iM3o; ;i;i;i; iM3; 0; 0iN3o; ;i;i;i; iN3; 0; 0iO3o; ;i;i;i; iO3; 0; 0iP3o; ;i;i;i; iP3; 0; 0iQ3o; ;i;i;i; iQ3; 0; 0iR3o; ;i;i;i; iR3; 0; 0iS3o; ;i;i;i; iS3; 0; 0iT3o; ;i;i;i; iT3; 0; 0iU3o; ;i;i;i; iU3; 0; 0iV3o; ;i;i;i; iV3; 0; 0iW3o; ;i;i;i; iW3; 0; 0iX3o; ;i;i;i; iX3; 0; 0iY3o; ;i;i;i; iY3; 0; 0iZ3o; ;i;i;i; iZ3; 0; 0i[3o; ;i;i;i; i[3; 0; 0i\3o; ;i;i;i; i\3; 0; 0i]3o; ;i;i;i; i]3; 0; 0i^3o; ;i;i;i; i^3; 0; 0i_3o; ;i;i;i; i_3; 0; 0i`3o; ;i;i;i; i`3; 0; 0ia3o; ;i;i;i; ia3; 0; 0ib3o; ;i;i;i; ib3; 0; 0ic3o; ;i;i;i; ic3; 0; 0id3o; ;i;i;i; id3; 0; 0ie3o; ;i;i;i; ie3; 0; 0if3o; ;i;i;i; if3; 0; 0ig3o; ;i;i;i; ig3; 0; 0ih3o; ;i;i;i; ih3; 0; 0ii3o; ;i;i;i; ii3; 0; 0ij3o; ;i;i;i; ij3; 0; 0ik3o; ;i;i;i; ik3; 0; 0il3o; ;i;i;i; il3; 0; 0im3o; ;i;i;i; im3; 0; 0in3o; ;i;i;i; in3; 0; 0io3o; ;i;i;i; io3; 0; 0ip3o; ;i;i;i; ip3; 0; 0iq3o; ;i;i;i; iq3; 0; 0ir3o; ;i;i;i; ir3; 0; 0is3o; ;i;i;i; is3; 0; 0it3o; ;i;i;i; it3; 0; 0iu3o; ;i;i;i; iu3; 0; 0iv3o; ;i;i;i; iv3; 0; 0iw3o; ;i;i;i; iw3; 0; 0ix3o; ;i;i;i; ix3; 0; 0iy3o; ;i;i;i; iy3; 0; 0iz3o; ;i;i;i; iz3; 0; 0i{3o; ;i;i;i; i{3; 0; 0i|3o; ;i;i;i; i|3; 0; 0i}3o; ;i;i;i; i}3; 0; 0i~3o; ;i;i;i; i~3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i4o; ;i;i;i; i4; 0; 0i 4o; ;i;i;i; i 4; 0; 0i!4o; ;i;i;i; i!4; 0; 0i"4o; ;i;i;i; i"4; 0; 0i#4o; ;i;i;i; i#4; 0; 0i$4o; ;i;i;i; i$4; 0; 0i%4o; ;i;i;i; i%4; 0; 0i&4o; ;i;i;i; i&4; 0; 0i'4o; ;i;i;i; i'4; 0; 0i(4o; ;i;i;i; i(4; 0; 0i)4o; ;i;i;i; i)4; 0; 0i*4o; ;i;i;i; i*4; 0; 0i+4o; ;i;i;i; i+4; 0; 0i,4o; ;i;i;i; i,4; 0; 0i-4o; ;i;i;i; i-4; 0; 0i.4o; ;i;i;i; i.4; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0i ho; ;i;i;i; i h; 0; 0i ho; ;i;i;i; i h; 0; 0i ho; ;i;i;i; i h; 0; 0i ho; ;i;i;i; i h; 0; 0i ho; ;i;i;i; i h; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0i ho; ;i;i;i; i h; 0; 0i!ho; ;i;i;i; i!h; 0; 0i"ho; ;i;i;i; i"h; 0; 0i#ho; ;i;i;i; i#h; 0; 0i$ho; ;i;i;i; i$h; 0; 0i%ho; ;i;i;i; i%h; 0; 0i&ho; ;i;i;i; i&h; 0; 0i'ho; ;i;i;i; i'h; 0; 0i(ho; ;i;i;i; i(h; 0; 0i)ho; ;i;i;i; i)h; 0; 0i*ho; ;i;i;i; i*h; 0; 0i+ho; ;i;i;i; i+h; 0; 0i,ho; ;i;i;i; i,h; 0; 0i-ho; ;i;i;i; i-h; 0; 0i.ho; ;i;i;i; i.h; 0; 0i/ho; ;i;i;i; i/h; 0; 0i0ho; ;i;i;i; i0h; 0; 0i1ho; ;i;i;i; i1h; 0; 0i2ho; ;i;i;i; i2h; 0; 0i3ho; ;i;i;i; i3h; 0; 0i4ho; ;i;i;i; i4h; 0; 0i5ho; ;i;i;i; i5h; 0; 0i6ho; ;i;i;i; i6h; 0; 0i7ho; ;i;i;i; i7h; 0; 0i8ho; ;i;i;i; i8h; 0; 0i9ho; ;i;i;i; i9h; 0; 0i:ho; ;i;i;i; i:h; 0; 0i;ho; ;i;i;i; i;h; 0; 0iho; ;i;i;i; i>h; 0; 0i?ho; ;i;i;i; i?h; 0; 0i@ho; ;i;i;i; i@h; 0; 0iAho; ;i;i;i; iAh; 0; 0iBho; ;i;i;i; iBh; 0; 0iCho; ;i;i;i; iCh; 0; 0iDho; ;i;i;i; iDh; 0; 0iEho; ;i;i;i; iEh; 0; 0iFho; ;i;i;i; iFh; 0; 0iGho; ;i;i;i; iGh; 0; 0iHho; ;i;i;i; iHh; 0; 0iIho; ;i;i;i; iIh; 0; 0iJho; ;i;i;i; iJh; 0; 0iKho; ;i;i;i; iKh; 0; 0iLho; ;i;i;i; iLh; 0; 0iMho; ;i;i;i; iMh; 0; 0iNho; ;i;i;i; iNh; 0; 0iOho; ;i;i;i; iOh; 0; 0iPho; ;i;i;i; iPh; 0; 0iQho; ;i;i;i; iQh; 0; 0iRho; ;i;i;i; iRh; 0; 0iSho; ;i;i;i; iSh; 0; 0iTho; ;i;i;i; iTh; 0; 0iUho; ;i;i;i; iUh; 0; 0iVho; ;i;i;i; iVh; 0; 0iWho; ;i;i;i; iWh; 0; 0iXho; ;i;i;i; iXh; 0; 0iYho; ;i;i;i; iYh; 0; 0iZho; ;i;i;i; iZh; 0; 0i[ho; ;i;i;i; i[h; 0; 0i\ho; ;i;i;i; i\h; 0; 0i]ho; ;i;i;i; i]h; 0; 0i^ho; ;i;i;i; i^h; 0; 0i_ho; ;i;i;i; i_h; 0; 0i`ho; ;i;i;i; i`h; 0; 0iaho; ;i;i;i; iah; 0; 0ibho; ;i;i;i; ibh; 0; 0icho; ;i;i;i; ich; 0; 0idho; ;i;i;i; idh; 0; 0ieho; ;i;i;i; ieh; 0; 0ifho; ;i;i;i; ifh; 0; 0igho; ;i;i;i; igh; 0; 0ihho; ;i;i;i; ihh; 0; 0iiho; ;i;i;i; iih; 0; 0ijho; ;i;i;i; ijh; 0; 0ikho; ;i;i;i; ikh; 0; 0ilho; ;i;i;i; ilh; 0; 0imho; ;i;i;i; imh; 0; 0inho; ;i;i;i; inh; 0; 0ioho; ;i;i;i; ioh; 0; 0ipho; ;i;i;i; iph; 0; 0iqho; ;i;i;i; iqh; 0; 0irho; ;i;i;i; irh; 0; 0isho; ;i;i;i; ish; 0; 0itho; ;i;i;i; ith; 0; 0iuho; ;i;i;i; iuh; 0; 0ivho; ;i;i;i; ivh; 0; 0iwho; ;i;i;i; iwh; 0; 0ixho; ;i;i;i; ixh; 0; 0iyho; ;i;i;i; iyh; 0; 0izho; ;i;i;i; izh; 0; 0i{ho; ;i;i;i; i{h; 0; 0i|ho; ;i;i;i; i|h; 0; 0i}ho; ;i;i;i; i}h; 0; 0i~ho; ;i;i;i; i~h; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0i io; ;i;i;i; i i; 0; 0i io; ;i;i;i; i i; 0; 0i io; ;i;i;i; i i; 0; 0i io; ;i;i;i; i i; 0; 0i io; ;i;i;i; i i; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0i io; ;i;i;i; i i; 0; 0i!io; ;i;i;i; i!i; 0; 0i"io; ;i;i;i; i"i; 0; 0i#io; ;i;i;i; i#i; 0; 0i$io; ;i;i;i; i$i; 0; 0i%io; ;i;i;i; i%i; 0; 0i&io; ;i;i;i; i&i; 0; 0i'io; ;i;i;i; i'i; 0; 0i(io; ;i;i;i; i(i; 0; 0i)io; ;i;i;i; i)i; 0; 0i*io; ;i;i;i; i*i; 0; 0i+io; ;i;i;i; i+i; 0; 0i,io; ;i;i;i; i,i; 0; 0i-io; ;i;i;i; i-i; 0; 0i.io; ;i;i;i; i.i; 0; 0i/io; ;i;i;i; i/i; 0; 0i0io; ;i;i;i; i0i; 0; 0i1io; ;i;i;i; i1i; 0; 0i2io; ;i;i;i; i2i; 0; 0i3io; ;i;i;i; i3i; 0; 0i4io; ;i;i;i; i4i; 0; 0i5io; ;i;i;i; i5i; 0; 0i6io; ;i;i;i; i6i; 0; 0i7io; ;i;i;i; i7i; 0; 0i8io; ;i;i;i; i8i; 0; 0i9io; ;i;i;i; i9i; 0; 0i:io; ;i;i;i; i:i; 0; 0i;io; ;i;i;i; i;i; 0; 0iio; ;i;i;i; i>i; 0; 0i?io; ;i;i;i; i?i; 0; 0i@io; ;i;i;i; i@i; 0; 0iAio; ;i;i;i; iAi; 0; 0iBio; ;i;i;i; iBi; 0; 0iCio; ;i;i;i; iCi; 0; 0iDio; ;i;i;i; iDi; 0; 0iEio; ;i;i;i; iEi; 0; 0iFio; ;i;i;i; iFi; 0; 0iGio; ;i;i;i; iGi; 0; 0iHio; ;i;i;i; iHi; 0; 0iIio; ;i;i;i; iIi; 0; 0iJio; ;i;i;i; iJi; 0; 0iKio; ;i;i;i; iKi; 0; 0iLio; ;i;i;i; iLi; 0; 0iMio; ;i;i;i; iMi; 0; 0iNio; ;i;i;i; iNi; 0; 0iOio; ;i;i;i; iOi; 0; 0iPio; ;i;i;i; iPi; 0; 0iQio; ;i;i;i; iQi; 0; 0iRio; ;i;i;i; iRi; 0; 0iSio; ;i;i;i; iSi; 0; 0iTio; ;i;i;i; iTi; 0; 0iUio; ;i;i;i; iUi; 0; 0iVio; ;i;i;i; iVi; 0; 0iWio; ;i;i;i; iWi; 0; 0iXio; ;i;i;i; iXi; 0; 0iYio; ;i;i;i; iYi; 0; 0iZio; ;i;i;i; iZi; 0; 0i[io; ;i;i;i; i[i; 0; 0i\io; ;i;i;i; i\i; 0; 0i]io; ;i;i;i; i]i; 0; 0i^io; ;i;i;i; i^i; 0; 0i_io; ;i;i;i; i_i; 0; 0i`io; ;i;i;i; i`i; 0; 0iaio; ;i;i;i; iai; 0; 0ibio; ;i;i;i; ibi; 0; 0icio; ;i;i;i; ici; 0; 0idio; ;i;i;i; idi; 0; 0ieio; ;i;i;i; iei; 0; 0ifio; ;i;i;i; ifi; 0; 0igio; ;i;i;i; igi; 0; 0ihio; ;i;i;i; ihi; 0; 0iiio; ;i;i;i; iii; 0; 0ijio; ;i;i;i; iji; 0; 0ikio; ;i;i;i; iki; 0; 0ilio; ;i;i;i; ili; 0; 0imio; ;i;i;i; imi; 0; 0inio; ;i;i;i; ini; 0; 0ioio; ;i;i;i; ioi; 0; 0ipio; ;i;i;i; ipi; 0; 0iqio; ;i;i;i; iqi; 0; 0irio; ;i;i;i; iri; 0; 0isio; ;i;i;i; isi; 0; 0itio; ;i;i;i; iti; 0; 0iuio; ;i;i;i; iui; 0; 0ivio; ;i;i;i; ivi; 0; 0iwio; ;i;i;i; iwi; 0; 0ixio; ;i;i;i; ixi; 0; 0iyio; ;i;i;i; iyi; 0; 0izio; ;i;i;i; izi; 0; 0i{io; ;i;i;i; i{i; 0; 0i|io; ;i;i;i; i|i; 0; 0i}io; ;i;i;i; i}i; 0; 0i~io; ;i;i;i; i~i; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0i jo; ;i;i;i; i j; 0; 0i jo; ;i;i;i; i j; 0; 0i jo; ;i;i;i; i j; 0; 0i jo; ;i;i;i; i j; 0; 0i jo; ;i;i;i; i j; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0ijo; ;i;i;i; ij; 0; 0i jo; ;i;i;i; i j; 0; 0i!jo; ;i;i;i; i!j; 0; 0i"jo; ;i;i;i; i"j; 0; 0i#jo; ;i;i;i; i#j; 0; 0i$jo; ;i;i;i; i$j; 0; 0i%jo; ;i;i;i; i%j; 0; 0i&jo; ;i;i;i; i&j; 0; 0i'jo; ;i;i;i; i'j; 0; 0i(jo; ;i;i;i; i(j; 0; 0i)jo; ;i;i;i; i)j; 0; 0i*jo; ;i;i;i; i*j; 0; 0i+jo; ;i;i;i; i+j; 0; 0i,jo; ;i;i;i; i,j; 0; 0i-jo; ;i;i;i; i-j; 0; 0i.jo; ;i;i;i; i.j; 0; 0i/jo; ;i;i;i; i/j; 0; 0i0jo; ;i;i;i; i0j; 0; 0i1jo; ;i;i;i; i1j; 0; 0i2jo; ;i;i;i; i2j; 0; 0i3jo; ;i;i;i; i3j; 0; 0i4jo; ;i;i;i; i4j; 0; 0i5jo; ;i;i;i; i5j; 0; 0i6jo; ;i;i;i; i6j; 0; 0i7jo; ;i;i;i; i7j; 0; 0i8jo; ;i;i;i; i8j; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0i oo; ;i;i;i; i o; 0; 0i oo; ;i;i;i; i o; 0; 0i oo; ;i;i;i; i o; 0; 0i oo; ;i;i;i; i o; 0; 0i oo; ;i;i;i; i o; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0i oo; ;i;i;i; i o; 0; 0i!oo; ;i;i;i; i!o; 0; 0i"oo; ;i;i;i; i"o; 0; 0i#oo; ;i;i;i; i#o; 0; 0i$oo; ;i;i;i; i$o; 0; 0i%oo; ;i;i;i; i%o; 0; 0i&oo; ;i;i;i; i&o; 0; 0i'oo; ;i;i;i; i'o; 0; 0i(oo; ;i;i;i; i(o; 0; 0i)oo; ;i;i;i; i)o; 0; 0i*oo; ;i;i;i; i*o; 0; 0i+oo; ;i;i;i; i+o; 0; 0i,oo; ;i;i;i; i,o; 0; 0i-oo; ;i;i;i; i-o; 0; 0i.oo; ;i;i;i; i.o; 0; 0i/oo; ;i;i;i; i/o; 0; 0i0oo; ;i;i;i; i0o; 0; 0i1oo; ;i;i;i; i1o; 0; 0i2oo; ;i;i;i; i2o; 0; 0i3oo; ;i;i;i; i3o; 0; 0i4oo; ;i;i;i; i4o; 0; 0i5oo; ;i;i;i; i5o; 0; 0i6oo; ;i;i;i; i6o; 0; 0i7oo; ;i;i;i; i7o; 0; 0i8oo; ;i;i;i; i8o; 0; 0i9oo; ;i;i;i; i9o; 0; 0i:oo; ;i;i;i; i:o; 0; 0i;oo; ;i;i;i; i;o; 0; 0ioo; ;i;i;i; i>o; 0; 0i?oo; ;i;i;i; i?o; 0; 0i@oo; ;i;i;i; i@o; 0; 0iAoo; ;i;i;i; iAo; 0; 0iBoo; ;i;i;i; iBo; 0; 0iCoo; ;i;i;i; iCo; 0; 0iDoo; ;i;i;i; iDo; 0; 0iPoo; ;i;i;i; iPo; 0; 0iQoo; ;i;i;i; iQo; 0; 0iRoo; ;i;i;i; iRo; 0; 0iSoo; ;i;i;i; iSo; 0; 0iToo; ;i;i;i; iTo; 0; 0iUoo; ;i;i;i; iUo; 0; 0iVoo; ;i;i;i; iVo; 0; 0iWoo; ;i;i;i; iWo; 0; 0iXoo; ;i;i;i; iXo; 0; 0iYoo; ;i;i;i; iYo; 0; 0iZoo; ;i;i;i; iZo; 0; 0i[oo; ;i;i;i; i[o; 0; 0i\oo; ;i;i;i; i\o; 0; 0i]oo; ;i;i;i; i]o; 0; 0i^oo; ;i;i;i; i^o; 0; 0i_oo; ;i;i;i; i_o; 0; 0i`oo; ;i;i;i; i`o; 0; 0iaoo; ;i;i;i; iao; 0; 0iboo; ;i;i;i; ibo; 0; 0icoo; ;i;i;i; ico; 0; 0idoo; ;i;i;i; ido; 0; 0ieoo; ;i;i;i; ieo; 0; 0ifoo; ;i;i;i; ifo; 0; 0igoo; ;i;i;i; igo; 0; 0ihoo; ;i;i;i; iho; 0; 0iioo; ;i;i;i; iio; 0; 0ijoo; ;i;i;i; ijo; 0; 0ikoo; ;i;i;i; iko; 0; 0iloo; ;i;i;i; ilo; 0; 0imoo; ;i;i;i; imo; 0; 0inoo; ;i;i;i; ino; 0; 0iooo; ;i;i;i; ioo; 0; 0ipoo; ;i;i;i; ipo; 0; 0iqoo; ;i;i;i; iqo; 0; 0iroo; ;i;i;i; iro; 0; 0isoo; ;i;i;i; iso; 0; 0itoo; ;i;i;i; ito; 0; 0iuoo; ;i;i;i; iuo; 0; 0ivoo; ;i;i;i; ivo; 0; 0iwoo; ;i;i;i; iwo; 0; 0ixoo; ;i;i;i; ixo; 0; 0iyoo; ;i;i;i; iyo; 0; 0izoo; ;i;i;i; izo; 0; 0i{oo; ;i;i;i; i{o; 0; 0i|oo; ;i;i;i; i|o; 0; 0i}oo; ;i;i;i; i}o; 0; 0i~oo; ;i;i;i; i~o; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0ioo; ;i;i;i; io; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; [iWiei_o; ;i;i;i; i_; 0; [iXiei`o; ;i;i;i; i`; 0; [i_iniao; ;i;i;i; ia; 0; [i_ioibo; ;i;i;i; ib; 0; [i_ipico; ;i;i;i; ic; 0; [i_iqido; ;i;i;i; id; 0; [i_irieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [iieio; ;i;i;i; i; 0; [iieio; ;i;i;i; i; 0; [iinio; ;i;i;i; i; 0; [iinio; ;i;i;i; i; 0; [iioio; ;i;i;i; i; 0; [iioio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0io; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iKio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iMio; ;i;i;i; i; I" font; T; [iNi o; ;i;i;i; i ; I" font; T; [iOi o; ;i;i;i; i ; I" font; T; [iPi o; ;i;i;i; i ; I" font; T; [iQi o; ;i;i;i; i ; I" font; T; [iRi o; ;i;i;i; i ; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [iki o; ;i;i;i; i ; I" font; T; [ili!o; ;i;i;i; i!; I" font; T; [imi"o; ;i;i;i; i"; I" font; T; [ini#o; ;i;i;i; i#; I" font; T; [ioi$o; ;i;i;i; i$; I" font; T; [ipi%o; ;i;i;i; i%; I" font; T; [iqi&o; ;i;i;i; i&; I" font; T; [iri'o; ;i;i;i; i'; I" font; T; [isi(o; ;i;i;i; i(; I" font; T; [iti)o; ;i;i;i; i); I" font; T; [iui*o; ;i;i;i; i*; I" font; T; [ivi+o; ;i;i;i; i+; I" font; T; [iwi,o; ;i;i;i; i,; I" font; T; [ixi-o; ;i;i;i; i-; I" font; T; [iyi.o; ;i;i;i; i.; I" font; T; [izi/o; ;i;i;i; i/; I" font; T; [i{i0o; ;i;i;i; i0; I" font; T; [i|i1o; ;i;i;i; i1; I" font; T; [i}i2o; ;i;i;i; i2; I" font; T; [i~i3o; ;i;i;i; i3; I" font; T; [ii4o; ;i;i;i; i4; I" font; T; [iFi5o; ;i;i;i; i5; I" font; T; [iGi6o; ;i;i;i; i6; I" font; T; [iHi7o; ;i;i;i; i7; I" font; T; [iIi8o; ;i;i;i; i8; I" font; T; [iJi9o; ;i;i;i; i9; I" font; T; [iKi:o; ;i;i;i; i:; I" font; T; [iLi;o; ;i;i;i; i;; I" font; T; [iMi<o; ;i;i;i; i<; I" font; T; [iNi=o; ;i;i;i; i=; I" font; T; [iOi>o; ;i;i;i; i>; I" font; T; [iPi?o; ;i;i;i; i?; I" font; T; [iQi@o; ;i;i;i; i@; I" font; T; [iRiAo; ;i;i;i; iA; I" font; T; [iSiBo; ;i;i;i; iB; I" font; T; [iTiCo; ;i;i;i; iC; I" font; T; [iUiDo; ;i;i;i; iD; I" font; T; [iViEo; ;i;i;i; iE; I" font; T; [iWiFo; ;i;i;i; iF; I" font; T; [iXiGo; ;i;i;i; iG; I" font; T; [iYiHo; ;i;i;i; iH; I" font; T; [iZiIo; ;i;i;i; iI; I" font; T; [i[iJo; ;i;i;i; iJ; I" font; T; [i\iKo; ;i;i;i; iK; I" font; T; [i]iLo; ;i;i;i; iL; I" font; T; [i^iMo; ;i;i;i; iM; I" font; T; [i_iNo; ;i;i;i; iN; I" font; T; [ifiOo; ;i;i;i; iO; I" font; T; [igiPo; ;i;i;i; iP; I" font; T; [ihiQo; ;i;i;i; iQ; I" font; T; [iiiRo; ;i;i;i; iR; I" font; T; [ijiSo; ;i;i;i; iS; I" font; T; [ikiTo; ;i;i;i; iT; I" font; T; [iliVo; ;i;i;i; iV; I" font; T; [iniWo; ;i;i;i; iW; I" font; T; [ioiXo; ;i;i;i; iX; I" font; T; [ipiYo; ;i;i;i; iY; I" font; T; [iqiZo; ;i;i;i; iZ; I" font; T; [iri[o; ;i;i;i; i[; I" font; T; [isi\o; ;i;i;i; i\; I" font; T; [iti]o; ;i;i;i; i]; I" font; T; [iui^o; ;i;i;i; i^; I" font; T; [ivi_o; ;i;i;i; i_; I" font; T; [iwi`o; ;i;i;i; i`; I" font; T; [ixiao; ;i;i;i; ia; I" font; T; [iyibo; ;i;i;i; ib; I" font; T; [izico; ;i;i;i; ic; I" font; T; [i{ido; ;i;i;i; id; I" font; T; [i|ieo; ;i;i;i; ie; I" font; T; [i}ifo; ;i;i;i; if; I" font; T; [i~igo; ;i;i;i; ig; I" font; T; [iiho; ;i;i;i; ih; I" font; T; [iFiio; ;i;i;i; ii; I" font; T; [iGijo; ;i;i;i; ij; I" font; T; [iHiko; ;i;i;i; ik; I" font; T; [iIilo; ;i;i;i; il; I" font; T; [iJimo; ;i;i;i; im; I" font; T; [iKino; ;i;i;i; in; I" font; T; [iLioo; ;i;i;i; io; I" font; T; [iMipo; ;i;i;i; ip; I" font; T; [iNiqo; ;i;i;i; iq; I" font; T; [iOiro; ;i;i;i; ir; I" font; T; [iPiso; ;i;i;i; is; I" font; T; [iQito; ;i;i;i; it; I" font; T; [iRiuo; ;i;i;i; iu; I" font; T; [iSivo; ;i;i;i; iv; I" font; T; [iTiwo; ;i;i;i; iw; I" font; T; [iUixo; ;i;i;i; ix; I" font; T; [iViyo; ;i;i;i; iy; I" font; T; [iWizo; ;i;i;i; iz; I" font; T; [iXi{o; ;i;i;i; i{; I" font; T; [iYi|o; ;i;i;i; i|; I" font; T; [iZi}o; ;i;i;i; i}; I" font; T; [i[i~o; ;i;i;i; i~; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iKio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iMio; ;i;i;i; i; I" font; T; [iNio; ;i;i;i; i; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iQio; ;i;i;i; i; I" font; T; [iRio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iJi o; ;i;i;i; i ; I" font; T; [iKi o; ;i;i;i; i ; I" font; T; [iLi o; ;i;i;i; i ; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iQio; ;i;i;i; i; I" font; T; [iRio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igi o; ;i;i;i; i ; I" font; T; [ihi!o; ;i;i;i; i!; I" font; T; [iii"o; ;i;i;i; i"; I" font; T; [iji#o; ;i;i;i; i#; I" font; T; [iki$o; ;i;i;i; i$; I" font; T; [ili%o; ;i;i;i; i%; I" font; T; [imi&o; ;i;i;i; i&; I" font; T; [ini'o; ;i;i;i; i'; I" font; T; [ioi(o; ;i;i;i; i(; I" font; T; [ipi)o; ;i;i;i; i); I" font; T; [iqi*o; ;i;i;i; i*; I" font; T; [iri+o; ;i;i;i; i+; I" font; T; [isi,o; ;i;i;i; i,; I" font; T; [iti-o; ;i;i;i; i-; I" font; T; [iui.o; ;i;i;i; i.; I" font; T; [ivi/o; ;i;i;i; i/; I" font; T; [iwi0o; ;i;i;i; i0; I" font; T; [ixi1o; ;i;i;i; i1; I" font; T; [iyi2o; ;i;i;i; i2; I" font; T; [izi3o; ;i;i;i; i3; I" font; T; [i{i4o; ;i;i;i; i4; I" font; T; [i|i5o; ;i;i;i; i5; I" font; T; [i}i6o; ;i;i;i; i6; I" font; T; [i~i7o; ;i;i;i; i7; I" font; T; [ii8o; ;i;i;i; i8; I" font; T; [iFi9o; ;i;i;i; i9; I" font; T; [iGi;o; ;i;i;i; i;; I" font; T; [iIi<o; ;i;i;i; i<; I" font; T; [iJi=o; ;i;i;i; i=; I" font; T; [iKi>o; ;i;i;i; i>; I" font; T; [iLi@o; ;i;i;i; i@; I" font; T; [iNiAo; ;i;i;i; iA; I" font; T; [iOiBo; ;i;i;i; iB; I" font; T; [iPiCo; ;i;i;i; iC; I" font; T; [iQiDo; ;i;i;i; iD; I" font; T; [iRiFo; ;i;i;i; iF; I" font; T; [iTiJo; ;i;i;i; iJ; I" font; T; [iXiKo; ;i;i;i; iK; I" font; T; [iYiLo; ;i;i;i; iL; I" font; T; [iZiMo; ;i;i;i; iM; I" font; T; [i[iNo; ;i;i;i; iN; I" font; T; [i\iOo; ;i;i;i; iO; I" font; T; [i]iPo; ;i;i;i; iP; I" font; T; [i^iRo; ;i;i;i; iR; I" font; T; [ifiSo; ;i;i;i; iS; I" font; T; [igiTo; ;i;i;i; iT; I" font; T; [ihiUo; ;i;i;i; iU; I" font; T; [iiiVo; ;i;i;i; iV; I" font; T; [ijiWo; ;i;i;i; iW; I" font; T; [ikiXo; ;i;i;i; iX; I" font; T; [iliYo; ;i;i;i; iY; I" font; T; [imiZo; ;i;i;i; iZ; I" font; T; [ini[o; ;i;i;i; i[; I" font; T; [ioi\o; ;i;i;i; i\; I" font; T; [ipi]o; ;i;i;i; i]; I" font; T; [iqi^o; ;i;i;i; i^; I" font; T; [iri_o; ;i;i;i; i_; I" font; T; [isi`o; ;i;i;i; i`; I" font; T; [itiao; ;i;i;i; ia; I" font; T; [iuibo; ;i;i;i; ib; I" font; T; [ivico; ;i;i;i; ic; I" font; T; [iwido; ;i;i;i; id; I" font; T; [ixieo; ;i;i;i; ie; I" font; T; [iyifo; ;i;i;i; if; I" font; T; [izigo; ;i;i;i; ig; I" font; T; [i{iho; ;i;i;i; ih; I" font; T; [i|iio; ;i;i;i; ii; I" font; T; [i}ijo; ;i;i;i; ij; I" font; T; [i~iko; ;i;i;i; ik; I" font; T; [iilo; ;i;i;i; il; I" font; T; [iFimo; ;i;i;i; im; I" font; T; [iGino; ;i;i;i; in; I" font; T; [iHioo; ;i;i;i; io; I" font; T; [iIipo; ;i;i;i; ip; I" font; T; [iJiqo; ;i;i;i; iq; I" font; T; [iKiro; ;i;i;i; ir; I" font; T; [iLiso; ;i;i;i; is; I" font; T; [iMito; ;i;i;i; it; I" font; T; [iNiuo; ;i;i;i; iu; I" font; T; [iOivo; ;i;i;i; iv; I" font; T; [iPiwo; ;i;i;i; iw; I" font; T; [iQixo; ;i;i;i; ix; I" font; T; [iRiyo; ;i;i;i; iy; I" font; T; [iSizo; ;i;i;i; iz; I" font; T; [iTi{o; ;i;i;i; i{; I" font; T; [iUi|o; ;i;i;i; i|; I" font; T; [iVi}o; ;i;i;i; i}; I" font; T; [iWi~o; ;i;i;i; i~; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iKio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iMio; ;i;i;i; i; I" font; T; [iNio; ;i;i;i; i; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iQio; ;i;i;i; i; I" font; T; [iRio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [iIio; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iKio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iMio; ;i;i;i; i; I" font; T; [iNio; ;i;i;i; i; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iQio; ;i;i;i; i; I" font; T; [iRio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iFi o; ;i;i;i; i ; I" font; T; [iGi o; ;i;i;i; i ; I" font; T; [iHi o; ;i;i;i; i ; I" font; T; [iIi o; ;i;i;i; i ; I" font; T; [iJi o; ;i;i;i; i ; I" font; T; [iKio; ;i;i;i; i; I" font; T; [iLio; ;i;i;i; i; I" font; T; [iMio; ;i;i;i; i; I" font; T; [iNio; ;i;i;i; i; I" font; T; [iOio; ;i;i;i; i; I" font; T; [iPio; ;i;i;i; i; I" font; T; [iQio; ;i;i;i; i; I" font; T; [iRio; ;i;i;i; i; I" font; T; [iSio; ;i;i;i; i; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]i o; ;i;i;i; i ; I" font; T; [i^i!o; ;i;i;i; i!; I" font; T; [i_i"o; ;i;i;i; i"; I" font; T; [ifi#o; ;i;i;i; i#; I" font; T; [igi$o; ;i;i;i; i$; I" font; T; [ihi%o; ;i;i;i; i%; I" font; T; [iii&o; ;i;i;i; i&; I" font; T; [iji'o; ;i;i;i; i'; I" font; T; [iki(o; ;i;i;i; i(; I" font; T; [ili)o; ;i;i;i; i); I" font; T; [imi*o; ;i;i;i; i*; I" font; T; [ini+o; ;i;i;i; i+; I" font; T; [ioi,o; ;i;i;i; i,; I" font; T; [ipi-o; ;i;i;i; i-; I" font; T; [iqi.o; ;i;i;i; i.; I" font; T; [iri/o; ;i;i;i; i/; I" font; T; [isi0o; ;i;i;i; i0; I" font; T; [iti1o; ;i;i;i; i1; I" font; T; [iui2o; ;i;i;i; i2; I" font; T; [ivi3o; ;i;i;i; i3; I" font; T; [iwi4o; ;i;i;i; i4; I" font; T; [ixi5o; ;i;i;i; i5; I" font; T; [iyi6o; ;i;i;i; i6; I" font; T; [izi7o; ;i;i;i; i7; I" font; T; [i{i8o; ;i;i;i; i8; I" font; T; [i|i9o; ;i;i;i; i9; I" font; T; [i}i:o; ;i;i;i; i:; I" font; T; [i~i;o; ;i;i;i; i;; I" font; T; [ii<o; ;i;i;i; i<; I" font; T; [iFi=o; ;i;i;i; i=; I" font; T; [iGi>o; ;i;i;i; i>; I" font; T; [iHi?o; ;i;i;i; i?; I" font; T; [iIi@o; ;i;i;i; i@; I" font; T; [iJiAo; ;i;i;i; iA; I" font; T; [iKiBo; ;i;i;i; iB; I" font; T; [iLiCo; ;i;i;i; iC; I" font; T; [iMiDo; ;i;i;i; iD; I" font; T; [iNiEo; ;i;i;i; iE; I" font; T; [iOiFo; ;i;i;i; iF; I" font; T; [iPiGo; ;i;i;i; iG; I" font; T; [iQiHo; ;i;i;i; iH; I" font; T; [iRiIo; ;i;i;i; iI; I" font; T; [iSiJo; ;i;i;i; iJ; I" font; T; [iTiKo; ;i;i;i; iK; I" font; T; [iUiLo; ;i;i;i; iL; I" font; T; [iViMo; ;i;i;i; iM; I" font; T; [iWiNo; ;i;i;i; iN; I" font; T; [iXiOo; ;i;i;i; iO; I" font; T; [iYiPo; ;i;i;i; iP; I" font; T; [iZiQo; ;i;i;i; iQ; I" font; T; [i[iRo; ;i;i;i; iR; I" font; T; [i\iSo; ;i;i;i; iS; I" font; T; [i]iTo; ;i;i;i; iT; I" font; T; [i^iUo; ;i;i;i; iU; I" font; T; [i_iVo; ;i;i;i; iV; I" font; T; [ifiWo; ;i;i;i; iW; I" font; T; [igiXo; ;i;i;i; iX; I" font; T; [ihiYo; ;i;i;i; iY; I" font; T; [iiiZo; ;i;i;i; iZ; I" font; T; [iji[o; ;i;i;i; i[; I" font; T; [iki\o; ;i;i;i; i\; I" font; T; [ili]o; ;i;i;i; i]; I" font; T; [imi^o; ;i;i;i; i^; I" font; T; [ini_o; ;i;i;i; i_; I" font; T; [ioi`o; ;i;i;i; i`; I" font; T; [ipiao; ;i;i;i; ia; I" font; T; [iqibo; ;i;i;i; ib; I" font; T; [irico; ;i;i;i; ic; I" font; T; [isido; ;i;i;i; id; I" font; T; [itieo; ;i;i;i; ie; I" font; T; [iuifo; ;i;i;i; if; I" font; T; [ivigo; ;i;i;i; ig; I" font; T; [iwiho; ;i;i;i; ih; I" font; T; [ixiio; ;i;i;i; ii; I" font; T; [iyijo; ;i;i;i; ij; I" font; T; [iziko; ;i;i;i; ik; I" font; T; [i{ilo; ;i;i;i; il; I" font; T; [i|imo; ;i;i;i; im; I" font; T; [i}ino; ;i;i;i; in; I" font; T; [i~ioo; ;i;i;i; io; I" font; T; [iipo; ;i;i;i; ip; I" font; T; [iFiqo; ;i;i;i; iq; I" font; T; [iGiro; ;i;i;i; ir; I" font; T; [iHiso; ;i;i;i; is; I" font; T; [iIito; ;i;i;i; it; I" font; T; [iJiuo; ;i;i;i; iu; I" font; T; [iKivo; ;i;i;i; iv; I" font; T; [iLiwo; ;i;i;i; iw; I" font; T; [iMixo; ;i;i;i; ix; I" font; T; [iNiyo; ;i;i;i; iy; I" font; T; [iOizo; ;i;i;i; iz; I" font; T; [iPi{o; ;i;i;i; i{; I" font; T; [iQi|o; ;i;i;i; i|; I" font; T; [iRi}o; ;i;i;i; i}; I" font; T; [iSi~o; ;i;i;i; i~; I" font; T; [iTio; ;i;i;i; i; I" font; T; [iUio; ;i;i;i; i; I" font; T; [iVio; ;i;i;i; i; I" font; T; [iWio; ;i;i;i; i; I" font; T; [iXio; ;i;i;i; i; I" font; T; [iYio; ;i;i;i; i; I" font; T; [iZio; ;i;i;i; i; I" font; T; [i[io; ;i;i;i; i; I" font; T; [i\io; ;i;i;i; i; I" font; T; [i]io; ;i;i;i; i; I" font; T; [i^io; ;i;i;i; i; I" font; T; [i_io; ;i;i;i; i; I" font; T; [ifio; ;i;i;i; i; I" font; T; [igio; ;i;i;i; i; I" font; T; [ihio; ;i;i;i; i; I" font; T; [iiio; ;i;i;i; i; I" font; T; [ijio; ;i;i;i; i; I" font; T; [ikio; ;i;i;i; i; I" font; T; [ilio; ;i;i;i; i; I" font; T; [imio; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [ioio; ;i;i;i; i; I" font; T; [ipio; ;i;i;i; i; I" font; T; [iqio; ;i;i;i; i; I" font; T; [irio; ;i;i;i; i; I" font; T; [isio; ;i;i;i; i; I" font; T; [itio; ;i;i;i; i; I" font; T; [iuio; ;i;i;i; i; I" font; T; [ivio; ;i;i;i; i; I" font; T; [iwio; ;i;i;i; i; I" font; T; [ixio; ;i;i;i; i; I" font; T; [iyio; ;i;i;i; i; I" font; T; [izio; ;i;i;i; i; I" font; T; [i{io; ;i;i;i; i; I" font; T; [i|io; ;i;i;i; i; I" font; T; [i}io; ;i;i;i; i; I" font; T; [i~io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i1io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [ii o; ;i;i;i; i ; I" font; T; [ii!o; ;i;i;i; i!; I" font; T; [ii"o; ;i;i;i; i"; I" font; T; [ii#o; ;i;i;i; i#; I" font; T; [ii$o; ;i;i;i; i$; I" font; T; [ii%o; ;i;i;i; i%; I" font; T; [ii&o; ;i;i;i; i&; I" font; T; [ii'o; ;i;i;i; i'; I" font; T; [ii(o; ;i;i;i; i(; I" font; T; [ii)o; ;i;i;i; i); I" font; T; [ii*o; ;i;i;i; i*; I" font; T; [ii+o; ;i;i;i; i+; I" font; T; [ii,o; ;i;i;i; i,; I" font; T; [ii-o; ;i;i;i; i-; I" font; T; [ii.o; ;i;i;i; i.; I" font; T; [ii/o; ;i;i;i; i/; I" font; T; [ii0o; ;i;i;i; i0; I" font; T; [ii1o; ;i;i;i; i1; I" font; T; [ii2o; ;i;i;i; i2; I" font; T; [ii3o; ;i;i;i; i3; I" font; T; [ii4o; ;i;i;i; i4; I" font; T; [ii5o; ;i;i;i; i5; I" font; T; [i"i6o; ;i;i;i; i6; I" font; T; [ii7o; ;i;i;i; i7; I" font; T; [ii8o; ;i;i;i; i8; I" font; T; [ii9o; ;i;i;i; i9; I" font; T; [ii:o; ;i;i;i; i:; I" font; T; [ii;o; ;i;i;i; i;; I" font; T; [ii<o; ;i;i;i; i<; I" font; T; [ii=o; ;i;i;i; i=; I" font; T; [ii>o; ;i;i;i; i>; I" font; T; [ii?o; ;i;i;i; i?; I" font; T; [ii@o; ;i;i;i; i@; I" font; T; [iiAo; ;i;i;i; iA; I" font; T; [iiBo; ;i;i;i; iB; I" font; T; [iiCo; ;i;i;i; iC; I" font; T; [iiDo; ;i;i;i; iD; I" font; T; [iiEo; ;i;i;i; iE; I" font; T; [iiFo; ;i;i;i; iF; I" font; T; [iiGo; ;i;i;i; iG; I" font; T; [iiHo; ;i;i;i; iH; I" font; T; [iiIo; ;i;i;i; iI; I" font; T; [iiJo; ;i;i;i; iJ; I" font; T; [iiKo; ;i;i;i; iK; I" font; T; [iiLo; ;i;i;i; iL; I" font; T; [iiMo; ;i;i;i; iM; I" font; T; [iiNo; ;i;i;i; iN; I" font; T; [iiOo; ;i;i;i; iO; I" font; T; [i"iPo; ;i;i;i; iP; I" font; T; [iiQo; ;i;i;i; iQ; I" font; T; [iiRo; ;i;i;i; iR; I" font; T; [iiSo; ;i;i;i; iS; I" font; T; [iiTo; ;i;i;i; iT; I" font; T; [iiUo; ;i;i;i; iU; I" font; T; [iiVo; ;i;i;i; iV; I" font; T; [iiWo; ;i;i;i; iW; I" font; T; [iiXo; ;i;i;i; iX; I" font; T; [iiYo; ;i;i;i; iY; I" font; T; [iiZo; ;i;i;i; iZ; I" font; T; [ii[o; ;i;i;i; i[; I" font; T; [ii\o; ;i;i;i; i\; I" font; T; [ii]o; ;i;i;i; i]; I" font; T; [ii^o; ;i;i;i; i^; I" font; T; [ii_o; ;i;i;i; i_; I" font; T; [ii`o; ;i;i;i; i`; I" font; T; [iiao; ;i;i;i; ia; I" font; T; [iibo; ;i;i;i; ib; I" font; T; [iico; ;i;i;i; ic; I" font; T; [iido; ;i;i;i; id; I" font; T; [iieo; ;i;i;i; ie; I" font; T; [iifo; ;i;i;i; if; I" font; T; [iigo; ;i;i;i; ig; I" font; T; [iiho; ;i;i;i; ih; I" font; T; [iiio; ;i;i;i; ii; I" font; T; [iijo; ;i;i;i; ij; I" font; T; [iiko; ;i;i;i; ik; I" font; T; [iilo; ;i;i;i; il; I" font; T; [iimo; ;i;i;i; im; I" font; T; [iino; ;i;i;i; in; I" font; T; [iioo; ;i;i;i; io; I" font; T; [i"ipo; ;i;i;i; ip; I" font; T; [iiqo; ;i;i;i; iq; I" font; T; [iiro; ;i;i;i; ir; I" font; T; [iiso; ;i;i;i; is; I" font; T; [iito; ;i;i;i; it; I" font; T; [iiuo; ;i;i;i; iu; I" font; T; [iivo; ;i;i;i; iv; I" font; T; [iiwo; ;i;i;i; iw; I" font; T; [iixo; ;i;i;i; ix; I" font; T; [iiyo; ;i;i;i; iy; I" font; T; [iizo; ;i;i;i; iz; I" font; T; [ii{o; ;i;i;i; i{; I" font; T; [ii|o; ;i;i;i; i|; I" font; T; [ii}o; ;i;i;i; i}; I" font; T; [ii~o; ;i;i;i; i~; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i"io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i;io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i;io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i;io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i;io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i;io; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [i'io; ;i;i;i; i; I" font; T; [i(io; ;i;i;i; i; I" font; T; [i,io; ;i;i;i; i; I" font; T; [i/io; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [i2io; ;i;i;i; i; I" font; T; [i-io; ;i;i;i; i; I" font; T; [i7i o; ;i;i;i; i ; I" font; T; [iJi o; ;i;i;i; i ; I" font; T; [iCi o; ;i;i;i; i ; I" font; T; [iDi o; ;i;i;i; i ; I" font; T; [iEi o; ;i;i;i; i ; I" font; T; [iFio; ;i;i;i; i; I" font; T; [i3io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [iAio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [iBio; ;i;i;i; i; I" font; T; [i1io; ;i;i;i; i; I" font; T; [i4io; ;i;i;i; i; I" font; T; [i*io; ;i;i;i; i; I" font; T; [i+io; ;i;i;i; i; I" font; T; [i.io; ;i;i;i; i; I" font; T; [i0io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [inio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [iio; ;i;i;i; i; I" font; T; [ioi!o; ;i;i;i; i!; I" font; T; [i(i"o; ;i;i;i; i"; I" font; T; [i,i$o; ;i;i;i; i$; I" font; T; [iGi'o; ;i;i;i; i'; I" font; T; [i-i)o; ;i;i;i; i); I" font; T; [iJi*o; ;i;i;i; i*; I" font; T; [iCi+o; ;i;i;i; i+; I" font; T; [iDi,o; ;i;i;i; i,; I" font; T; [iEi-o; ;i;i;i; i-; I" font; T; [iFi.o; ;i;i;i; i.; I" font; T; [i3i/o; ;i;i;i; i/; I" font; T; [i9i0o; ;i;i;i; i0; I" font; T; [iAi1o; ;i;i;i; i1; I" font; T; [i5i2o; ;i;i;i; i2; I" font; T; [iBi4o; ;i;i;i; i4; I" font; T; [i4i5o; ;i;i;i; i5; I" font; T; [i*i6o; ;i;i;i; i6; I" font; T; [i+i7o; ;i;i;i; i7; I" font; T; [i.i9o; ;i;i;i; i9; I" font; T; [i6i;o; ;i;i;i; i;; I" font; T; [i:iBo; ;i;i;i; iB; I" font; T; [i,iGo; ;i;i;i; iG; I" font; T; [i-iIo; ;i;i;i; iI; I" font; T; [iJiKo; ;i;i;i; iK; I" font; T; [iDiMo; ;i;i;i; iM; I" font; T; [iFiNo; ;i;i;i; iN; I" font; T; [i3iOo; ;i;i;i; iO; I" font; T; [i9iQo; ;i;i;i; iQ; I" font; T; [i5iRo; ;i;i;i; iR; I" font; T; [iBiTo; ;i;i;i; iT; I" font; T; [i4iWo; ;i;i;i; iW; I" font; T; [i.iYo; ;i;i;i; iY; I" font; T; [i6i[o; ;i;i;i; i[; I" font; T; [i:i]o; ;i;i;i; i]; I" font; T; [ii_o; ;i;i;i; i_; I" font; T; [ioiao; ;i;i;i; ia; I" font; T; [i(ibo; ;i;i;i; ib; I" font; T; [i,ido; ;i;i;i; id; I" font; T; [iGigo; ;i;i;i; ig; I" font; T; [i-iho; ;i;i;i; ih; I" font; T; [i7iio; ;i;i;i; ii; I" font; T; [iJijo; ;i;i;i; ij; I" font; T; [iCilo; ;i;i;i; il; I" font; T; [iEimo; ;i;i;i; im; I" font; T; [iFino; ;i;i;i; in; I" font; T; [i3ioo; ;i;i;i; io; I" font; T; [i9ipo; ;i;i;i; ip; I" font; T; [iAiqo; ;i;i;i; iq; I" font; T; [i5iro; ;i;i;i; ir; I" font; T; [iBito; ;i;i;i; it; I" font; T; [i4iuo; ;i;i;i; iu; I" font; T; [i*ivo; ;i;i;i; iv; I" font; T; [i+iwo; ;i;i;i; iw; I" font; T; [i.iyo; ;i;i;i; iy; I" font; T; [i6izo; ;i;i;i; iz; I" font; T; [i8i{o; ;i;i;i; i{; I" font; T; [i:i|o; ;i;i;i; i|; I" font; T; [ini~o; ;i;i;i; i~; I" font; T; [iio; ;i;i;i; i; I" font; T; [i'io; ;i;i;i; i; I" font; T; [i(io; ;i;i;i; i; I" font; T; [i,io; ;i;i;i; i; I" font; T; [i/io; ;i;i;i; i; I" font; T; [iGio; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [i2io; ;i;i;i; i; I" font; T; [i-io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iDio; ;i;i;i; i; I" font; T; [iEio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [i3io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [iAio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [iBio; ;i;i;i; i; I" font; T; [i1io; ;i;i;i; i; I" font; T; [i4io; ;i;i;i; i; I" font; T; [i*io; ;i;i;i; i; I" font; T; [i+io; ;i;i;i; i; I" font; T; [i.io; ;i;i;i; i; I" font; T; [i0io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; I" font; T; [i(io; ;i;i;i; i; I" font; T; [i,io; ;i;i;i; i; I" font; T; [i/io; ;i;i;i; i; I" font; T; [iHio; ;i;i;i; i; I" font; T; [i2io; ;i;i;i; i; I" font; T; [i-io; ;i;i;i; i; I" font; T; [i7io; ;i;i;i; i; I" font; T; [iJio; ;i;i;i; i; I" font; T; [iDio; ;i;i;i; i; I" font; T; [iEio; ;i;i;i; i; I" font; T; [iFio; ;i;i;i; i; I" font; T; [i3io; ;i;i;i; i; I" font; T; [i9io; ;i;i;i; i; I" font; T; [iAio; ;i;i;i; i; I" font; T; [i5io; ;i;i;i; i; I" font; T; [iBio; ;i;i;i; i; I" font; T; [i1io; ;i;i;i; i; I" font; T; [i4io; ;i;i;i; i; I" font; T; [i*io; ;i;i;i; i; I" font; T; [i+io; ;i;i;i; i; I" font; T; [i.io; ;i;i;i; i; I" font; T; [i0io; ;i;i;i; i; I" font; T; [i6io; ;i;i;i; i; I" font; T; [i8io; ;i;i;i; i; I" font; T; [i:io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" compat; T; [i5i3io; ;i;i;i; i; I" compat; T; [i5i1io; ;i;i;i; i; I" compat; T; [i6i1io; ;i;i;i; i; I" compat; T; [i7i1io; ;i;i;i; i; I" compat; T; [i8i1io; ;i;i;i; i; I" compat; T; [i9i1io; ;i;i;i; i; I" compat; T; [i:i1io; ;i;i;i; i; I" compat; T; [i;i1io; ;i;i;i; i; I" compat; T; [ii1io; ;i;i;i; i; I" compat; T; [i-iFi.io; ;i;i;i; i; I" compat; T; [i-iGi.io; ;i;i;i; i; I" compat; T; [i-iHi.io; ;i;i;i; i; I" compat; T; [i-iIi.io; ;i;i;i; i; I" compat; T; [i-iJi.io; ;i;i;i; i; I" compat; T; [i-iKi.io; ;i;i;i; i; I" compat; T; [i-iLi.io; ;i;i;i; i; I" compat; T; [i-iMi.io; ;i;i;i; i; I" compat; T; [i-iNi.io; ;i;i;i; i; I" compat; T; [i-iOi.io; ;i;i;i; i; I" compat; T; [i-iPi.io; ;i;i;i; i; I" compat; T; [i-iQi.io; ;i;i;i; i; I" compat; T; [i-iRi.io; ;i;i;i; i; I" compat; T; [i-iSi.io; ;i;i;i; i; I" compat; T; [i-iTi.io; ;i;i;i; i; I" compat; T; [i-iUi.i o; ;i;i;i; i ; I" compat; T; [i-iVi.i!o; ;i;i;i; i!; I" compat; T; [i-iWi.i"o; ;i;i;i; i"; I" compat; T; [i-iXi.i#o; ;i;i;i; i#; I" compat; T; [i-iYi.i$o; ;i;i;i; i$; I" compat; T; [i-iZi.i%o; ;i;i;i; i%; I" compat; T; [i-i[i.i&o; ;i;i;i; i&; I" compat; T; [i-i\i.i'o; ;i;i;i; i'; I" compat; T; [i-i]i.i(o; ;i;i;i; i(; I" compat; T; [i-i^i.i)o; ;i;i;i; i); I" compat; T; [i-i_i.i*o; ;i;i;i; i*; I" compat; T; [i0iXi0i+o; ;i;i;i; i+; I" circle; T; [iHi,o; ;i;i;i; i,; I" circle; T; [iWi-o; ;i;i;i; i-; I" circle; T; [iHiIi.o; ;i;i;i; i.; I" circle; T; [i\i_i0o; ;i;i;i; i0; I" square; T; [iFi1o; ;i;i;i; i1; I" square; T; [iGi2o; ;i;i;i; i2; I" square; T; [iHi3o; ;i;i;i; i3; I" square; T; [iIi4o; ;i;i;i; i4; I" square; T; [iJi5o; ;i;i;i; i5; I" square; T; [iKi6o; ;i;i;i; i6; I" square; T; [iLi7o; ;i;i;i; i7; I" square; T; [iMi8o; ;i;i;i; i8; I" square; T; [iNi9o; ;i;i;i; i9; I" square; T; [iOi:o; ;i;i;i; i:; I" square; T; [iPi;o; ;i;i;i; i;; I" square; T; [iQi<o; ;i;i;i; i<; I" square; T; [iRi=o; ;i;i;i; i=; I" square; T; [iSi>o; ;i;i;i; i>; I" square; T; [iTi?o; ;i;i;i; i?; I" square; T; [iUi@o; ;i;i;i; i@; I" square; T; [iViAo; ;i;i;i; iA; I" square; T; [iWiBo; ;i;i;i; iB; I" square; T; [iXiCo; ;i;i;i; iC; I" square; T; [iYiDo; ;i;i;i; iD; I" square; T; [iZiEo; ;i;i;i; iE; I" square; T; [i[iFo; ;i;i;i; iF; I" square; T; [i\iGo; ;i;i;i; iG; I" square; T; [i]iHo; ;i;i;i; iH; I" square; T; [i^iIo; ;i;i;i; iI; I" square; T; [i_iJo; ;i;i;i; iJ; I" square; T; [iMi[iKo; ;i;i;i; iK; I" square; T; [iRi[iLo; ;i;i;i; iL; I" square; T; [iXiIiMo; ;i;i;i; iM; I" square; T; [iXiXiNo; ;i;i;i; iN; I" square; T; [iUiUi[iOo; ;i;i;i; iO; I" square; T; [i\iHiPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; I" super; T; [iRiHiko; ;i;i;i; ik; I" super; T; [iRiIipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" square; T; [iIiOio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; I" square; T; [i{0iK0io; ;i;i;i; i; I" square; T; [i0i0io; ;i;i;i; i; I" square; T; [i0io; ;i;i;i; i; I" square; T; [iKbio; ;i;i;i; i; I" square; T; [iW[io; ;i;i;i; i; I" square; T; [iSio; ;i;i;i; i; I" square; T; [i0io; ;i;i;i; i; I" square; T; [iNio; ;i;i;i; i; I" square; T; [iYio; ;i;i;i; i; I" square; T; [iio; ;i;i;i; i; I" square; T; [i)Yio; ;i;i;i; i; I" square; T; [iNio; ;i;i;i; i; I" square; T; [i fio; ;i;i;i; i; I" square; T; [i!qio; ;i;i;i; i; I" square; T; [ieio; ;i;i;i; i; I" square; T; [iMRio; ;i;i;i; i; I" square; T; [i_io; ;i;i;i; i; I" square; T; [iQio; ;i;i;i; i; I" square; T; [iei o; ;i;i;i; i ; I" square; T; [iRi!o; ;i;i;i; i!; I" square; T; [iB}i"o; ;i;i;i; i"; I" square; T; [iui#o; ;i;i;i; i#; I" square; T; [ii$o; ;i;i;i; i$; I" square; T; [iXi%o; ;i;i;i; i%; I" square; T; [i9Ti&o; ;i;i;i; i&; I" square; T; [ioi'o; ;i;i;i; i'; I" square; T; [ibi(o; ;i;i;i; i(; I" square; T; [iUci)o; ;i;i;i; i); I" square; T; [iNi*o; ;i;i;i; i*; I" square; T; [i Ni+o; ;i;i;i; i+; I" square; T; [iJi,o; ;i;i;i; i,; I" square; T; [i]i-o; ;i;i;i; i-; I" square; T; [i-Ni.o; ;i;i;i; i.; I" square; T; [iSi/o; ;i;i;i; i/; I" square; T; [ici0o; ;i;i;i; i0; I" square; T; [ipi1o; ;i;i;i; i1; I" square; T; [iSbi2o; ;i;i;i; i2; I" square; T; [iyi3o; ;i;i;i; i3; I" square; T; [izzi4o; ;i;i;i; i4; I" square; T; [iTi5o; ;i;i;i; i5; I" square; T; [ini6o; ;i;i;i; i6; I" square; T; [i gi7o; ;i;i;i; i7; I" square; T; [igi8o; ;i;i;i; i8; I" square; T; [i3ui9o; ;i;i;i; i9; I" square; T; [irRi:o; ;i;i;i; i:; I" square; T; [iUi@o; ;i;i;i; i@; I" compat; T; [i0i,gi0iAo; ;i;i;i; iA; I" compat; T; [i0i Ni0iBo; ;i;i;i; iB; I" compat; T; [i0iNi0iCo; ;i;i;i; iC; I" compat; T; [i0i[i0iDo; ;i;i;i; iD; I" compat; T; [i0ipi0iEo; ;i;i;i; iE; I" compat; T; [i0iSbi0iFo; ;i;i;i; iF; I" compat; T; [i0ivi0iGo; ;i;i;i; iG; I" compat; T; [i0iRi0iHo; ;i;i;i; iH; I" compat; T; [i0iWei0iPo; ;i;i;i; iP; I" circle; T; [i_iQo; ;i;i;i; iQ; I" circle; T; [iSio; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i@o; ;i;i;i; i@; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0io; ;i;i;i; i; 0; 0i֦o; ;i;i;i; i֦; 0; 0io; ;i;i;i; i; 0; 0i4o; ;i;i;i; i4; 0; 0i@o; ;i;i;i; i@; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; [i=Nio; ;i;i;i; i; 0; [i8Nio; ;i;i;i; i; 0; [iANio; ;i;i;i; i; 0; [i"io; ;i;i;i; i; 0; [i`Oio; ;i;i;i; i; 0; [iOio; ;i;i;i; i; 0; [iOio; ;i;i;i; i; 0; [iPio; ;i;i;i; i; 0; [izPi o; ;i;i;i; i ; 0; [iPi o; ;i;i;i; i ; 0; [iPi o; ;i;i;i; i ; 0; [iPi o; ;i;i;i; i ; 0; [i4i o; ;i;i;i; i ; 0; [i:io; ;i;i;i; i; 0; [iMQio; ;i;i;i; i; 0; [iTQio; ;i;i;i; i; 0; [idQio; ;i;i;i; i; 0; [iwQio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i4io; ;i;i;i; i; 0; [igQio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iKio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iNio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iߑio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [i4i o; ;i;i;i; i ; 0; [i;Ri!o; ;i;i;i; i!; 0; [iFRi"o; ;i;i;i; i"; 0; [irRi#o; ;i;i;i; i#; 0; [iwRi$o; ;i;i;i; i$; 0; [i5i%o; ;i;i;i; i%; 0; [iRi&o; ;i;i;i; i&; 0; [iRi'o; ;i;i;i; i'; 0; [iRi(o; ;i;i;i; i(; 0; [iRi)o; ;i;i;i; i); 0; [iSi*o; ;i;i;i; i*; 0; [iSi+o; ;i;i;i; i+; 0; [iSi,o; ;i;i;i; i,; 0; [iISi-o; ;i;i;i; i-; 0; [iQSi.o; ;i;i;i; i.; 0; [iZSi/o; ;i;i;i; i/; 0; [isSi0o; ;i;i;i; i0; 0; [i}Si1o; ;i;i;i; i1; 0; [iSi2o; ;i;i;i; i2; 0; [iSi3o; ;i;i;i; i3; 0; [iSi4o; ;i;i;i; i4; 0; [i, i5o; ;i;i;i; i5; 0; [ippi6o; ;i;i;i; i6; 0; [iSi7o; ;i;i;i; i7; 0; [iSi8o; ;i;i;i; i8; 0; [ic i9o; ;i;i;i; i9; 0; [iSi:o; ;i;i;i; i:; 0; [iSi;o; ;i;i;i; i;; 0; [iTi<o; ;i;i;i; i<; 0; [iTi=o; ;i;i;i; i=; 0; [i8Ti>o; ;i;i;i; i>; 0; [iHTi?o; ;i;i;i; i?; 0; [ihTi@o; ;i;i;i; i@; 0; [iTiAo; ;i;i;i; iA; 0; [iTiBo; ;i;i;i; iB; 0; [iUiCo; ;i;i;i; iC; 0; [iSUiDo; ;i;i;i; iD; 0; [icUiEo; ;i;i;i; iE; 0; [iUiFo; ;i;i;i; iF; 0; [iUiGo; ;i;i;i; iG; 0; [iUiHo; ;i;i;i; iH; 0; [iUiIo; ;i;i;i; iI; 0; [iUiJo; ;i;i;i; iJ; 0; [iUiKo; ;i;i;i; iK; 0; [iWiLo; ;i;i;i; iL; 0; [iViMo; ;i;i;i; iM; 0; [iWiNo; ;i;i;i; iN; 0; [iQViOo; ;i;i;i; iO; 0; [itViPo; ;i;i;i; iP; 0; [iRiQo; ;i;i;i; iQ; 0; [iXiRo; ;i;i;i; iR; 0; [iWiSo; ;i;i;i; iS; 0; [iWiTo; ;i;i;i; iT; 0; [i XiUo; ;i;i;i; iU; 0; [iWiVo; ;i;i;i; iV; 0; [i2XiWo; ;i;i;i; iW; 0; [i1XiXo; ;i;i;i; iX; 0; [iXiYo; ;i;i;i; iY; 0; [iiZo; ;i;i;i; iZ; 0; [iXi[o; ;i;i;i; i[; 0; [iXi\o; ;i;i;i; i\; 0; [iYi]o; ;i;i;i; i]; 0; [iYi^o; ;i;i;i; i^; 0; [i"Yi_o; ;i;i;i; i_; 0; [ibYi`o; ;i;i;i; i`; 0; [iiao; ;i;i;i; ia; 0; [iibo; ;i;i;i; ib; 0; [iYico; ;i;i;i; ic; 0; [iZido; ;i;i;i; id; 0; [i'Zieo; ;i;i;i; ie; 0; [iYifo; ;i;i;i; if; 0; [ifZigo; ;i;i;i; ig; 0; [i6iho; ;i;i;i; ih; 0; [i6iio; ;i;i;i; ii; 0; [i[ijo; ;i;i;i; ij; 0; [i>[iko; ;i;i;i; ik; 0; [i>[ilo; ;i;i;i; il; 0; [iimo; ;i;i;i; im; 0; [i[ino; ;i;i;i; in; 0; [i[ioo; ;i;i;i; io; 0; [i[ipo; ;i;i;i; ip; 0; [i[iqo; ;i;i;i; iq; 0; [iiro; ;i;i;i; ir; 0; [i[iso; ;i;i;i; is; 0; [i\ito; ;i;i;i; it; 0; [iS_iuo; ;i;i;i; iu; 0; [i"\ivo; ;i;i;i; iv; 0; [i7iwo; ;i;i;i; iw; 0; [i`\ixo; ;i;i;i; ix; 0; [in\iyo; ;i;i;i; iy; 0; [i\izo; ;i;i;i; iz; 0; [i\i{o; ;i;i;i; i{; 0; [ii|o; ;i;i;i; i|; 0; [iC]i}o; ;i;i;i; i}; 0; [ii~o; ;i;i;i; i~; 0; [in]io; ;i;i;i; i; 0; [ik]io; ;i;i;i; i; 0; [i|]io; ;i;i;i; i; 0; [i]io; ;i;i;i; i; 0; [i]io; ;i;i;i; i; 0; [i/8io; ;i;i;i; i; 0; [i]io; ;i;i;i; i; 0; [i(^io; ;i;i;i; i; 0; [i=^io; ;i;i;i; i; 0; [ii^io; ;i;i;i; i; 0; [ib8io; ;i;i;i; i; 0; [i!io; ;i;i;i; i; 0; [i|8io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i^io; ;i;i;i; i; 0; [i1#io; ;i;i;i; i; 0; [i1#io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i"_io; ;i;i;i; i; 0; [i"_io; ;i;i;i; i; 0; [i8io; ;i;i;i; i; 0; [i2io; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [ib_io; ;i;i;i; i; 0; [ik_io; ;i;i;i; i; 0; [i8io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i_io; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [i:9io; ;i;i;i; i; 0; [i9io; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [i&io; ;i;i;i; i; 0; [i`io; ;i;i;i; i; 0; [iHaio; ;i;i;i; i; 0; [iLaio; ;i;i;i; i; 0; [iNaio; ;i;i;i; i; 0; [iLaio; ;i;i;i; i; 0; [izaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [iaio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [i]bio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [iPcio; ;i;i;i; i; 0; [i +io; ;i;i;i; i; 0; [i=cio; ;i;i;i; i; 0; [ibio; ;i;i;i; i; 0; [ihcio; ;i;i;i; i; 0; [icio; ;i;i;i; i; 0; [icio; ;i;i;i; i; 0; [i+io; ;i;i;i; i; 0; [i"dio; ;i;i;i; i; 0; [icio; ;i;i;i; i; 0; [icio; ;i;i;i; i; 0; [i.:io; ;i;i;i; i; 0; [iidio; ;i;i;i; i; 0; [i~dio; ;i;i;i; i; 0; [idio; ;i;i;i; i; 0; [iwdio; ;i;i;i; i; 0; [il:io; ;i;i;i; i; 0; [iOeio; ;i;i;i; i; 0; [ileio; ;i;i;i; i; 0; [i 0io; ;i;i;i; i; 0; [ieio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [iIfio; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [i:io; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [iQio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [ifio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iCio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [i!gio; ;i;i;i; i; 0; [i^gio; ;i;i;i; i; 0; [iSgio; ;i;i;i; i; 0; [i3io; ;i;i;i; i; 0; [iI;io; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [iRhio; ;i;i;i; i; 0; [ihio; ;i;i;i; i; 0; [im4io; ;i;i;i; i; 0; [ihio; ;i;i;i; i; 0; [ihio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [i;io; ;i;i;i; i; 0; [iBiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [iiio; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [i6io; ;i;i;i; i; 0; [ijio; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [iwmio; ;i;i;i; i; 0; [iAmio; ;i;i;i; i; 0; [iimio; ;i;i;i; i; 0; [ixmio; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [i=io; ;i;i;i; i; 0; [i4mio; ;i;i;i; i; 0; [i/ni o; ;i;i;i; i ; 0; [inni o; ;i;i;i; i ; 0; [i3=i o; ;i;i;i; i ; 0; [ini o; ;i;i;i; i ; 0; [ini o; ;i;i;i; i ; 0; [i>io; ;i;i;i; i; 0; [imio; ;i;i;i; i; 0; [inoio; ;i;i;i; i; 0; [i^?io; ;i;i;i; i; 0; [i?io; ;i;i;i; i; 0; [ioio; ;i;i;i; i; 0; [i9pio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [i=io; ;i;i;i; i; 0; [iJpio; ;i;i;i; i; 0; [i}pio; ;i;i;i; i; 0; [iwpio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [i%io; ;i;i;i; i; 0; [iEqio; ;i;i;i; i; 0; [icBio; ;i;i;i; i; 0; [iqio; ;i;i;i; i; 0; [iCi o; ;i;i;i; i ; 0; [i(ri!o; ;i;i;i; i!; 0; [i5ri"o; ;i;i;i; i"; 0; [iPri#o; ;i;i;i; i#; 0; [iFi$o; ;i;i;i; i$; 0; [iri%o; ;i;i;i; i%; 0; [iri&o; ;i;i;i; i&; 0; [i5Gi'o; ;i;i;i; i'; 0; [iHi(o; ;i;i;i; i(; 0; [izsi)o; ;i;i;i; i); 0; [isi*o; ;i;i;i; i*; 0; [i>i+o; ;i;i;i; i+; 0; [isi,o; ;i;i;i; i,; 0; [i>i-o; ;i;i;i; i-; 0; [i>i.o; ;i;i;i; i.; 0; [iGti/o; ;i;i;i; i/; 0; [i\ti0o; ;i;i;i; i0; 0; [iqti1o; ;i;i;i; i1; 0; [iti2o; ;i;i;i; i2; 0; [iti3o; ;i;i;i; i3; 0; [i?i4o; ;i;i;i; i4; 0; [i$ui5o; ;i;i;i; i5; 0; [i6Li6o; ;i;i;i; i6; 0; [i>ui7o; ;i;i;i; i7; 0; [iLi8o; ;i;i;i; i8; 0; [ipui9o; ;i;i;i; i9; 0; [i!i:o; ;i;i;i; i:; 0; [ivi;o; ;i;i;i; i;; 0; [iOi<o; ;i;i;i; i<; 0; [iOi=o; ;i;i;i; i=; 0; [iDPi>o; ;i;i;i; i>; 0; [i?i?o; ;i;i;i; i?; 0; [i@i@o; ;i;i;i; i@; 0; [iviAo; ;i;i;i; iA; 0; [iPiBo; ;i;i;i; iB; 0; [iPiCo; ;i;i;i; iC; 0; [iQiDo; ;i;i;i; iD; 0; [i3QiEo; ;i;i;i; iE; 0; [iwiFo; ;i;i;i; iF; 0; [iwiGo; ;i;i;i; iG; 0; [iwiHo; ;i;i;i; iH; 0; [iJwiIo; ;i;i;i; iI; 0; [i9@iJo; ;i;i;i; iJ; 0; [iwiKo; ;i;i;i; iK; 0; [iF@iLo; ;i;i;i; iL; 0; [i@iMo; ;i;i;i; iM; 0; [iTiNo; ;i;i;i; iN; 0; [iNxiOo; ;i;i;i; iO; 0; [ixiPo; ;i;i;i; iP; 0; [ixiQo; ;i;i;i; iQ; 0; [i@iRo; ;i;i;i; iR; 0; [i&ViSo; ;i;i;i; iS; 0; [iVyiTo; ;i;i;i; iT; 0; [iViUo; ;i;i;i; iU; 0; [iViVo; ;i;i;i; iV; 0; [iyiWo; ;i;i;i; iW; 0; [iyiXo; ;i;i;i; iX; 0; [i/AiYo; ;i;i;i; iY; 0; [i@ziZo; ;i;i;i; iZ; 0; [iJzi[o; ;i;i;i; i[; 0; [iOzi\o; ;i;i;i; i\; 0; [i|Yi]o; ;i;i;i; i]; 0; [iZi^o; ;i;i;i; i^; 0; [iZi_o; ;i;i;i; i_; 0; [izi`o; ;i;i;i; i`; 0; [iBiao; ;i;i;i; ia; 0; [i[ibo; ;i;i;i; ib; 0; [i{ico; ;i;i;i; ic; 0; [i{ido; ;i;i;i; id; 0; [i'Bieo; ;i;i;i; ie; 0; [i\ifo; ;i;i;i; if; 0; [i|igo; ;i;i;i; ig; 0; [iBiho; ;i;i;i; ih; 0; [i|iio; ;i;i;i; ii; 0; [i|ijo; ;i;i;i; ij; 0; [i}iko; ;i;i;i; ik; 0; [i_ilo; ;i;i;i; il; 0; [ic}imo; ;i;i;i; im; 0; [iCino; ;i;i;i; in; 0; [i}ioo; ;i;i;i; io; 0; [i~ipo; ;i;i;i; ip; 0; [iE~iqo; ;i;i;i; iq; 0; [i4Ciro; ;i;i;i; ir; 0; [i(biso; ;i;i;i; is; 0; [iGbito; ;i;i;i; it; 0; [iYCiuo; ;i;i;i; iu; 0; [ibivo; ;i;i;i; iv; 0; [iziwo; ;i;i;i; iw; 0; [i>cixo; ;i;i;i; ix; 0; [iiyo; ;i;i;i; iy; 0; [iizo; ;i;i;i; iz; 0; [ii{o; ;i;i;i; i{; 0; [idi|o; ;i;i;i; i|; 0; [i#ei}o; ;i;i;i; i}; 0; [i`i~o; ;i;i;i; i~; 0; [ieio; ;i;i;i; i; 0; [ipio; ;i;i;i; i; 0; [i_3io; ;i;i;i; i; 0; [iCio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [i Dio; ;i;i;i; i; 0; [i>io; ;i;i;i; i; 0; [iZio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [igio; ;i;i;i; i; 0; [i3io; ;i;i;i; i; 0; [i3io; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [ikDio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iRio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [iio; ;i;i;i; i; 0; [io; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0i o; ;i;i;i; i ; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0i o; ;i;i;i; i ; 0; 0i!o; ;i;i;i; i!; 0; 0i"o; ;i;i;i; i"; 0; 0i#o; ;i;i;i; i#; 0; 0i$o; ;i;i;i; i$; 0; 0i%o; ;i;i;i; i%; 0; 0i&o; ;i;i;i; i&; 0; 0i'o; ;i;i;i; i'; 0; 0i(o; ;i;i;i; i(; 0; 0i)o; ;i;i;i; i); 0; 0i*o; ;i;i;i; i*; 0; 0i+o; ;i;i;i; i+; 0; 0i,o; ;i;i;i; i,; 0; 0i-o; ;i;i;i; i-; 0; 0i.o; ;i;i;i; i.; 0; 0i/o; ;i;i;i; i/; 0; 0i0o; ;i;i;i; i0; 0; 0i1o; ;i;i;i; i1; 0; 0i2o; ;i;i;i; i2; 0; 0i3o; ;i;i;i; i3; 0; 0i4o; ;i;i;i; i4; 0; 0i5o; ;i;i;i; i5; 0; 0i6o; ;i;i;i; i6; 0; 0i7o; ;i;i;i; i7; 0; 0i8o; ;i;i;i; i8; 0; 0i9o; ;i;i;i; i9; 0; 0i:o; ;i;i;i; i:; 0; 0i;o; ;i;i;i; i;; 0; 0i<o; ;i;i;i; i<; 0; 0i=o; ;i;i;i; i=; 0; 0i>o; ;i;i;i; i>; 0; 0i?o; ;i;i;i; i?; 0; 0i@o; ;i;i;i; i@; 0; 0iAo; ;i;i;i; iA; 0; 0iBo; ;i;i;i; iB; 0; 0iCo; ;i;i;i; iC; 0; 0iDo; ;i;i;i; iD; 0; 0iEo; ;i;i;i; iE; 0; 0iFo; ;i;i;i; iF; 0; 0iGo; ;i;i;i; iG; 0; 0iHo; ;i;i;i; iH; 0; 0iIo; ;i;i;i; iI; 0; 0iJo; ;i;i;i; iJ; 0; 0iKo; ;i;i;i; iK; 0; 0iLo; ;i;i;i; iL; 0; 0iMo; ;i;i;i; iM; 0; 0iNo; ;i;i;i; iN; 0; 0iOo; ;i;i;i; iO; 0; 0iPo; ;i;i;i; iP; 0; 0iQo; ;i;i;i; iQ; 0; 0iRo; ;i;i;i; iR; 0; 0iSo; ;i;i;i; iS; 0; 0iTo; ;i;i;i; iT; 0; 0iUo; ;i;i;i; iU; 0; 0iVo; ;i;i;i; iV; 0; 0iWo; ;i;i;i; iW; 0; 0iXo; ;i;i;i; iX; 0; 0iYo; ;i;i;i; iY; 0; 0iZo; ;i;i;i; iZ; 0; 0i[o; ;i;i;i; i[; 0; 0i\o; ;i;i;i; i\; 0; 0i]o; ;i;i;i; i]; 0; 0i^o; ;i;i;i; i^; 0; 0i_o; ;i;i;i; i_; 0; 0i`o; ;i;i;i; i`; 0; 0iao; ;i;i;i; ia; 0; 0ibo; ;i;i;i; ib; 0; 0ico; ;i;i;i; ic; 0; 0ido; ;i;i;i; id; 0; 0ieo; ;i;i;i; ie; 0; 0ifo; ;i;i;i; if; 0; 0igo; ;i;i;i; ig; 0; 0iho; ;i;i;i; ih; 0; 0iio; ;i;i;i; ii; 0; 0ijo; ;i;i;i; ij; 0; 0iko; ;i;i;i; ik; 0; 0ilo; ;i;i;i; il; 0; 0imo; ;i;i;i; im; 0; 0ino; ;i;i;i; in; 0; 0ioo; ;i;i;i; io; 0; 0ipo; ;i;i;i; ip; 0; 0iqo; ;i;i;i; iq; 0; 0iro; ;i;i;i; ir; 0; 0iso; ;i;i;i; is; 0; 0ito; ;i;i;i; it; 0; 0iuo; ;i;i;i; iu; 0; 0ivo; ;i;i;i; iv; 0; 0iwo; ;i;i;i; iw; 0; 0ixo; ;i;i;i; ix; 0; 0iyo; ;i;i;i; iy; 0; 0izo; ;i;i;i; iz; 0; 0i{o; ;i;i;i; i{; 0; 0i|o; ;i;i;i; i|; 0; 0i}o; ;i;i;i; i}; 0; 0i~o; ;i;i;i; i~; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0io; ;i;i;i; i; 0; 0o;;i;i;i[ViX iY iZ i[ i\ i] i^ i_ i i i i3 i6 iY iZ i[ i^ i\ i] iCiMiRiWi\iiivixiiiiiiiii*i+i,i-i.i/i0i1i2i3i4i5i6i8i9i:i;ii@iAiCiDiFiGiHiIiJiKiLiMiNi*i^i_i`iaibicidiiiiii{tiF{iiiiiiiiiii iiiiii(ii iiiiiii&i%ii#ii iiH{ i'iiiiiii i i iJ{iiiiiiiiiiiiiii(ii iiiiii'i(i-ii0ii#ii iiiiN{iiiiiiiiii(ii*ii,i(i.ii0i iiiii i0i,i ii#iiS{iiiiCi'iEi iGiiiiDi#iFi1iHi-iJiT{iiiiiiiiiiiiLiiNi iPiii ii(iii iiii.i#ii iiZ{iiiiiiiiiihiijiili ini ipi(iriii iiiiii$iri0iti-ivi#ii ii^{iiiiviixii2iiiii#ii iiiif{iiiiiiiiiii iiiiii(ii iiiiiii'i%ii#ii iih{ i'iiiii ii i i ij{iiiiiiiiiiiiiii(ii iiiiii'i)i-ii0ii#ii iiiin{iiiiiiiiii)ii+ii-i(i/i iii ii i0i-i ii#iis{iiiiDi'iFi iHiiiiEi#iGi1iIi-iKit{iiiiiiiiiiiiMiiOi iQiii ii(iii iiii/i#ii iiz{iiiiiiiiiiiiikiimi ioi iqi(isiii iiiiii$isi0iui-iwi#ii ii~{iiiiiiwii3iii iiii#ii iiiiI{ i iii i#i i1ii'ii-iii{ i iii i#i i1ii'ii-iiL{ iiiiii i'i"i iiiii il{ iiiiii!i'i#i iiiii!iM{ ii$i iii"i#i$ii&i'i(i.i*im{ ii%i iii#i#i%ii'i'i)i.i+i1iiO{ii4io{ii5i iiP{ i'i6i iii0i#i2i1i4ip{ i'i7i iii1i#i3i1i5iQ{ ii9i'i;i i=i#i6i1i:i-i<iq{ ii:i'i<i i>i#i7i1i;i-i=iW{ iiTi'iVi iXiiiiiiXi#iZi1i^iw{ iiUi'iWi iYiiiiiiYi#i[i1i_iX{ iiZii\i'i^i i`i&iii`i#ibix{ ii[ii]i'i_i iai&iiiai#iciY{ i'ibi idi&iiiji#ili1ini-ipiy{ i'ici iei&iiiki#imi1ioi-iqiii\{ iitiiiiiiiii#ii|{ iiuiiiiiiiii#ii ii_{ iiyii{i i}iii#ii1ii{ iizii|i i~iii#ii1ii{ iiiii iiii{ iiiii iiii{iii{iii&{iii'{iii{iiiii{iiiii{iii{iii{i ii{i ii{iii{iii{iii{iii{ii*i{ii+i{ii,iiLiiNi{ii-iiMiiOi.{ii0i/{ii1i{iiiBiiii{ iiiiii iiiiiiiEii{ iiiiiiiii{ iiii(ii)iiiEii{ iiiiii8ii9iiiiiii{ iiiiHiiIiii{ iiiiiiYiiiiiii{ iiiihiiiiiiEii{iiiiiBii{ iiiiiiiipiiiiiEiiBii{ iiiiiiiiri{ iiii ii!iitiEiiBii{ iiiiii0ii1iiviiiiiBii{iiiiiBii{ iiiiiiPiiQiiziiiiiBii{ iiii@iiAiixi{ iiii`iiaii|iEiiBii{iiiii{iiiiiii{iii{iii{ii i{ ii iiiiiii#{ iiiiiii ii8{ ii9ii]iiiii5{iiPiiQiii3{iiSiV{iiWi:{ii\iC{ ii^iiiii iit{iiviu{iiwi{iiiii6{iiiii{iiiii0{iiiii{iii{iii{iii7{iii{iii>{iii{iii{iii-{iiiM{iii'{iiiG{iii+{iiiK{iii'{iSi"iTi#iUi%iH{iTi$iJ{iTi&i{iTii{iTii{iTii( {i< i) i0 {i< i1 i3 {i< i4 i {i i i i iG {iV iH i> iK iW iL i {i i i {i i i i i {i i iF {iV iH i {i i i {i i i i i i i {i i iF {i> iJ iW iL iG {i> iK i {i i i i i i i {i i i%{i.i&i{i5ii{i5ii {i5i i {i5i i {i5ii{i5ii:{i5i;i<{i5i=i>{i5i@i?{i5iAiB{i5iCiG{iii#ii1iig{iii#ii1ii{iii{ii i{iiiii{iiiii({iii){iiiK{iiik{iii{ii.i{ii/i6{ii8i7{ii9iR{ii>ii@i#iBir{ii?iiAi#iCiL{iiPiiRiM{iiQiiSiU{iiTiiViu{iiUiiWiZ{ii\i[{ii]iZ{iidi[{iiei`{iifia{iigib{iihic{iiiih{iixii{iiyij{iizik{ii{i[{ii|i#i~i{{ii}i#ii]{iiiii}{iiiii{iii{ iiiii iiii{ iiiii iiii{iiiii{iiiii{ iiiii iiii{ iiiii iiii{ iiiii iiii{ iiiii iiii{iii{iii{ iiiii iiii{ iiiii iiii{iii{iii{ iiiii iiii#ii{ iiiii iiii#ii{ iiiii iiii#ii{ iiiii iiii#ii{ iiiiiBiiEii{ iiiiiBiiEii{ ii ii iBiiEii { ii ii iBiiEii{iiiii{iiiii{iiiii{iiiii { ii"ii$iBi&iEii!{ ii#ii%iBi'iEii({ ii*ii,iBi.iEii){ ii+ii-iBi/iEii0{ii2ii4iBi6i1{ii3ii5iBi7i8{ii:ii<iBi>i9{ii;ii=iBi?i@{iiBiiDiA{iiCiiEiH{iiJiiLiI{iiKiiMiP{iiRiiTiBiViQ{iiSiiUiBiWiY{ii[ii]iBi_i`{ iibiidiBifiEiia{ iiciieiBigiEiih{ iijiiliBiniEiii{ iikiimiBioiEii{iEii{iEii{iEii{iEii{iEii{iEii {iEii {iEii {iEii {iEii{iEii{iEii"{iEii#{iEii${iEii%{iEii&{iEii'{iEii*{iEii+{iEii,{iEii-{iEii.{iEii/{iEiib{iEiic{iEiid{iEiie{iEiif{iEiig{iEiij{iEiik{iEiil{iEiim{iEiin{iEiio{iEiip{iEii{iEii{iEiit{iEii{iEii{iEii{iiiiiBii{iiiiiBii{iiiii{iii|{iEii{iEii{iEii!{i8i!i!{i8i!i!{i8i!i!{i8i!i!{i8i!i!{i8i!i"{i8i"i"{i8i "i "{i8i "i#"{i8i$"i%"{i8i&"i<"{i8iA"iC"{i8iD"iE"{i8iG"iH"{i8iI"iB{i8i`"ia"{i8ib"iM"{i8im"iA{i8in"iC{i8io"id"{i8ip"ie"{i8iq"ir"{i8it"is"{i8iu"iv"{i8ix"iw"{i8iy"iz"{i8i"i{"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i|"{i8i"i}"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"i"{i8i"iK0{i0iL0iM0{i0iN0iO0{i0iP0iQ0{i0iR0iS0{i0iT0iU0{i0iV0iW0{i0iX0iY0{i0iZ0i[0{i0i\0i]0{i0i^0i_0{i0i`0ia0{i0ib0id0{i0ie0if0{i0ig0ih0{i0ii0io0{i0ip0i0iq0ir0{i0is0i0it0iu0{i0iv0i0iw0ix0{i0iy0i0iz0i{0{i0i|0i0i}0iF0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0i0i0{i0i0i0i0i0{i0i0i0i0i0{i0i0i0i0i0{i0i0i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i0{i0i0i{iii{iii{iii1{i'i.i2{i'i/{:cri:lfi: control[!o: Range: exclF: begini:endio;;F;i;io;;F;i;i$o;;F;i;iio;;F;i;iiii o;;F;i ;i i( i) o;;F;i* ;i. o;;F;i` ;id o;;F;ie ;ii o;;F;ij ;io o;;F;i;iio;;F;i;io;;F;i;iio;;F;is;iziio;;F;i;io;;F;i ;io;;F;i;io;;F;i;i: extend[o;;F;i;ioo;;F;i;io;;F;i;io;;F;i;iio;;F;i;io;;F;i;iio;;F;i;io;;F;iK;i_ipo;;F;i;io;;F;i;io;;F;i;io;;F;i;iio;;F;i0;iJo;;F;i;io;;F;i;io;;F;i;io;;F;i;i#o;;F;i%;i'o;;F;i);i-o;;F;iY;i[o;;F;i;io;;F;i ;i i: i< o;;F;iA ;iH iM o;;F;iQ ;iW o;;F;ib ;ic i i i o;;F;i ;i i i o;;F;i ;i o;;F;i ;i i< o;;F;iA ;iB o;;F;iG ;iH o;;F;iK ;iM iQ o;;F;ip ;iq iu o;;F;i ;i i o;;F;i ;i o;;F;i ;i i o;;F;i ;i i i< i> i? o;;F;iA ;iD iM iV iW o;;F;ib ;ic i i i i i o;;F;i> ;i@ o;;F;iF ;iH o;;F;iJ ;iM o;;F;iU ;iV o;;F;ib ;ic i i i i o;;F;i ;i o;;F;i ;i o;;F;i ;i i> o;;F;iA ;iD iM iW o;;F;ib ;ic i i o;;F;i ;i i i i1o;;F;i4;i:o;;F;iG;iNio;;F;i;io;;F;i;io;;F;i;io;;F;i;ii5i7i9o;;F;iq;i~o;;F;i;io;;F;i;io;;F;i;io;;F;i;iio;;F;i-;i0o;;F;i2;i7o;;F;i9;i:o;;F;i=;i>o;;F;iX;iYo;;F;i^;i`o;;F;iq;itio;;F;i;iiio;;F;i];i_o;;F;i;io;;F;i2;i4o;;F;iR;iSo;;F;ir;iso;;F;i;io;;F;i;iio;;F;i;iio;;F;i ;i io;;F;i ;i"o;;F;i';i(i2o;;F;i9;i;o;;F;i;iiVo;;F;iX;i^i`ibo;;F;ie;ilo;;F;is;i|io;;F;i;ii4o;;F;i6;i:i<iBo;;F;ik;iso;;F;i;io;;F;i;io;;F;i;iiio;;F;i;iio;;F;i;io;;F;i,;i3o;;F;i6;i7o;;F;i;io;;F;i;io;;F;i;iiio;;F;i;io;;F;i;io;;F;i ;i o;;F;i ;i o;;F;i ;i i o;;F;i ;i o;;F;i ;i o;;F;i,;i,i-o;;F;i-;i-o;;F;i*0;i-0o;;F;i.0;i/0o;;F;i0;i0ioo;;F;ip;iro;;F;it;i}io;;F;i;iiii o;;F;i%;i&iĨo;;F;i;io;;F;i&;i-o;;F;iG;iQo;;F;i;iio;;F;i;iio;;F;i);i.o;;F;i1;i2o;;F;i5;i6iCiLio;;F;i;io;;F;i;io;;F;i;iio;;F;i;iiiiiio;;F;i;io;;F;i ;i&o;;F;i;iio;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i8 ;i: i? io;;F;i8;iFo;;F;i;io;;F;i;io;;F;i;io;;F;i;io;;F;i';i+o;;F;i-;i4o;;F;i;io;;F;i;iiio;;F;i;iio;;F;io;ioieo;;F;ig;iio;;F;in;iro;;F;i{;io;;F;i;io;;F;i;io;;F;iB;iDo;;F;i;i:spacingmark[ui i; o;;F;i> ;i@ o;;F;iI ;iL o;;F;iN ;iO o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i ;i i o;;F;i> ;i@ i o;;F;i ;i i o;;F;i ;i o;;F;i ;i i@ o;;F;iG ;iH o;;F;iK ;iL i o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;iA ;iD o;;F;i ;i i o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i? ;i@ o;;F;iF ;iH o;;F;iJ ;iL o;;F;i ;i o;;F;i ;i o;;F;i ;i o;;F;i ;i i3io;;F;i>;i?ii1o;;F;i;;i<o;;F;iV;iWiio;;F;i;io;;F;i;io;;F;i#;i&o;;F;i);i+o;;F;i0;i1o;;F;i3;i8o;;F;i;iio;;F;i;iiUiWo;;F;im;irii5i;o;;F;i=;iAo;;F;iC;iDiio;;F;i;iio;;F;i;iio;;F;i;iio;;F;i;io;;F;i$;i+o;;F;i4;i5io;;F;i;io;;F;i#;i$i'o;;F;i;io;;F;i;ièo;;F;iR;iSio;;F;i;io;;F;i;io;;F;i;io;;F;i/;i0o;;F;i3;i4iMio;;F;i;iio;;F;i;io;;F;i;io;;F;i;iiiiio;;F;i;io;;F;i;ii,io;;F;i;io;;F;i;iio;;F;i;iio;;F;iQo;i~oifim:l[o;;F;i;i_o;;F;i`;i|:v[o;;F;i`;io;;F;i;i:t[o;;F;i;io;;F;i;i:lv[iii8iTipiiiĬiiii4iPiliiiiܭiii0iLihiiiiخiii,iHidiiiiԯii i(iDi`i|iiiаiii$i@i\ixiii̱iii ii>i?i?i@i@iAiAiBiBiCiCiDiDiEiEiFiFiGiGiHiHiIiIiJiJiKiKiLiLiMiMiNiNiOiOiPiPiQiQiRiRiSiSiTiTiUiUiViViWiWiXiXiYiYiZiZi[i[i\i\i]i]i^i^i_i_i`i`iaiaibibicicididieieififigigihihiiiiijijikikililimimininioioipipiqiqiririsisititiuiuiviviwiwixixiyiyizizi{i{i|i|i}i}i~i~iii{i{i|i|i}i}i~i~iiii ii iiii ii& ii ii! iiii0 ii`ii9 iiRii}ii ii ii ii ii" ii ii iiii"!iiaii: iiSii~iixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiimail-2.5.4/lib/mail/version.rb000066400000000000000000000010211214434061600161410ustar00rootroot00000000000000# encoding: utf-8 module Mail module VERSION version = {} File.read(File.join(File.dirname(__FILE__), '../', 'VERSION')).each_line do |line| type, value = line.chomp.split(":") next if type =~ /^\s+$/ || value =~ /^\s+$/ version[type] = value end MAJOR = version['major'] MINOR = version['minor'] PATCH = version['patch'] BUILD = version['build'] STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.') def self.version STRING end end end mail-2.5.4/lib/mail/version_specific/000077500000000000000000000000001214434061600174675ustar00rootroot00000000000000mail-2.5.4/lib/mail/version_specific/ruby_1_8.rb000066400000000000000000000062031214434061600214450ustar00rootroot00000000000000# encoding: utf-8 module Mail class Ruby18 require 'base64' require 'iconv' # Escapes any parenthesis in a string that are unescaped. This can't # use the Ruby 1.9.1 regexp feature of negative look behind so we have # to do two replacement, first unescape everything, then re-escape it def Ruby18.escape_paren( str ) re = /\\\)/ str = str.gsub(re) { |s| ')'} re = /\\\(/ str = str.gsub(re) { |s| '('} re = /([\(\)])/ # Only match unescaped parens str.gsub(re) { |s| '\\' + s } end def Ruby18.paren( str ) str = $1 if str =~ /^\((.*)?\)$/ str = escape_paren( str ) '(' + str + ')' end def Ruby18.escape_bracket( str ) re = /\\\>/ str = str.gsub(re) { |s| '>'} re = /\\\])/ # Only match unescaped parens str.gsub(re) { |s| '\\' + s } end def Ruby18.bracket( str ) str = $1 if str =~ /^\<(.*)?\>$/ str = escape_bracket( str ) '<' + str + '>' end def Ruby18.decode_base64(str) Base64.decode64(str) if str end def Ruby18.encode_base64(str) Base64.encode64(str) end def Ruby18.has_constant?(klass, string) klass.constants.include?( string ) end def Ruby18.get_constant(klass, string) klass.const_get( string ) end def Ruby18.b_value_encode(str, encoding) # Ruby 1.8 requires an encoding to work raise ArgumentError, "Must supply an encoding" if encoding.nil? encoding = encoding.to_s.upcase.gsub('_', '-') [Encodings::Base64.encode(str), fix_encoding(encoding)] end def Ruby18.b_value_decode(str) match = str.match(/\=\?(.+)?\?[Bb]\?(.+)?\?\=/m) if match encoding = match[1] str = Ruby18.decode_base64(match[2]) str = Iconv.conv('UTF-8//IGNORE', fix_encoding(encoding), str) end str end def Ruby18.q_value_encode(str, encoding) # Ruby 1.8 requires an encoding to work raise ArgumentError, "Must supply an encoding" if encoding.nil? encoding = encoding.to_s.upcase.gsub('_', '-') [Encodings::QuotedPrintable.encode(str), encoding] end def Ruby18.q_value_decode(str) match = str.match(/\=\?(.+)?\?[Qq]\?(.+)?\?\=/m) if match encoding = match[1] string = match[2].gsub(/_/, '=20') # Remove trailing = if it exists in a Q encoding string = string.sub(/\=$/, '') str = Encodings::QuotedPrintable.decode(string) str = Iconv.conv('UTF-8//IGNORE', fix_encoding(encoding), str) end str end def Ruby18.param_decode(str, encoding) URI.unescape(str) end def Ruby18.param_encode(str) encoding = $KCODE.to_s.downcase language = Configuration.instance.param_encode_language "#{encoding}'#{language}'#{URI.escape(str)}" end private def Ruby18.fix_encoding(encoding) case encoding.upcase when 'UTF8' 'UTF-8' when 'UTF16', 'UTF-16' 'UTF-16BE' when 'UTF32', 'UTF-32' 'UTF-32BE' else encoding end end end end mail-2.5.4/lib/mail/version_specific/ruby_1_9.rb000066400000000000000000000102301214434061600214410ustar00rootroot00000000000000# encoding: utf-8 module Mail class Ruby19 # Escapes any parenthesis in a string that are unescaped this uses # a Ruby 1.9.1 regexp feature of negative look behind def Ruby19.escape_paren( str ) re = /(?])/ # Only match unescaped brackets str.gsub(re) { |s| '\\' + s } end def Ruby19.bracket( str ) str = $1 if str =~ /^\<(.*)?\>$/ str = escape_bracket( str ) '<' + str + '>' end def Ruby19.decode_base64(str) str.unpack( 'm' ).first end def Ruby19.encode_base64(str) [str].pack( 'm' ) end def Ruby19.has_constant?(klass, string) klass.const_defined?( string, false ) end def Ruby19.get_constant(klass, string) klass.const_get( string ) end def Ruby19.b_value_encode(str, encoding = nil) encoding = str.encoding.to_s [Ruby19.encode_base64(str), encoding] end def Ruby19.b_value_decode(str) match = str.match(/\=\?(.+)?\?[Bb]\?(.+)?\?\=/m) if match charset = match[1] str = Ruby19.decode_base64(match[2]) str.force_encoding(pick_encoding(charset)) end decoded = str.encode("utf-8", :invalid => :replace, :replace => "") decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", :invalid => :replace, :replace => "").encode("utf-8") end def Ruby19.q_value_encode(str, encoding = nil) encoding = str.encoding.to_s [Encodings::QuotedPrintable.encode(str), encoding] end def Ruby19.q_value_decode(str) match = str.match(/\=\?(.+)?\?[Qq]\?(.+)?\?\=/m) if match charset = match[1] string = match[2].gsub(/_/, '=20') # Remove trailing = if it exists in a Q encoding string = string.sub(/\=$/, '') str = Encodings::QuotedPrintable.decode(string) str.force_encoding(pick_encoding(charset)) end decoded = str.encode("utf-8", :invalid => :replace, :replace => "") decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", :invalid => :replace, :replace => "").encode("utf-8") rescue Encoding::UndefinedConversionError str.dup.force_encoding("utf-8") end def Ruby19.param_decode(str, encoding) string = uri_parser.unescape(str) string.force_encoding(encoding) if encoding string end def Ruby19.param_encode(str) encoding = str.encoding.to_s.downcase language = Configuration.instance.param_encode_language "#{encoding}'#{language}'#{uri_parser.escape(str)}" end def Ruby19.uri_parser @uri_parser ||= URI::Parser.new end # Pick a Ruby encoding corresponding to the message charset. Most # charsets have a Ruby encoding, but some need manual aliasing here. # # TODO: add this as a test somewhere: # Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b} # Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b} def Ruby19.pick_encoding(charset) case charset # ISO-8859-15, ISO-2022-JP and alike when /iso-?(\d{4})-?(\w{1,2})/i "ISO-#{$1}-#{$2}" # "ISO-2022-JP-KDDI" and alike when /iso-?(\d{4})-?(\w{1,2})-?(\w*)/i "ISO-#{$1}-#{$2}-#{$3}" # UTF-8, UTF-32BE and alike when /utf-?(\d{1,2})?(\w{1,2})/i "UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE') # Windows-1252 and alike when /Windows-?(.*)/i "Windows-#{$1}" when /^8bit$/ Encoding::ASCII_8BIT # Microsoft-specific alias for CP949 (Korean) when 'ks_c_5601-1987' Encoding::CP949 # Wrongly written Shift_JIS (Japanese) when 'shift-jis' Encoding::Shift_JIS # GB2312 (Chinese charset) is a subset of GB18030 (its replacement) when /gb2312/i Encoding::GB18030 else charset end end end end mail-2.5.4/lib/tasks/000077500000000000000000000000001214434061600143405ustar00rootroot00000000000000mail-2.5.4/lib/tasks/corpus.rake000066400000000000000000000062501214434061600165220ustar00rootroot00000000000000namespace :corpus do task :load_mail do require File.expand_path('../../../spec/environment') require 'mail' end # Used to run parsing against an arbitrary corpus of email. # For example: http://plg.uwaterloo.ca/~gvcormac/treccorpus/ desc "Provide a LOCATION=/some/dir to verify parsing in bulk, otherwise defaults" task :verify_all => :load_mail do root_of_corpus = ENV['LOCATION'] || 'corpus/spam' @save_failures_to = ENV['SAVE_TO'] || 'spec/fixtures/emails/failed_emails' @failed_emails = [] @checked_count = 0 if root_of_corpus root_of_corpus = File.expand_path(root_of_corpus) if not File.directory?(root_of_corpus) raise "\n\tPath '#{root_of_corpus}' is not a directory.\n\n" end else raise "\n\tSupply path to corpus: LOCATION=/path/to/corpus\n\n" end if @save_failures_to if not File.directory?(@save_failures_to) raise "\n\tPath '#{@save_failures_to}' is not a directory.\n\n" end @save_failures_to = File.expand_path(@save_failures_to) puts "Mail which fails to parse will be saved in '#{@save_failures_to}'" end puts "Checking '#{root_of_corpus}' directory (recursively)" # we're tracking all the errors separately, don't clutter terminal $stderr_backup = $stderr.dup $stderr.reopen("/dev/null", "w") STDERR = $stderr dir_node(root_of_corpus) # put our toys back now that we're done with them $stderr = $stderr_backup.dup STDERR = $stderr puts "\n\n" if @failed_emails.any? report_failures_to_stdout end puts "Out of Total: #{@checked_count}" if @save_failures_to puts "Add SAVE_TO=/some/dir to save failed emails to for review.," puts "May result in a lot of saved files. Do a dry run first!\n\n" else puts "There are no errors" end end def dir_node(path) puts "\n\n" puts "Checking emails in '#{path}':" entries = Dir.entries(path) entries.each do |entry| next if ['.', '..'].include?(entry) full_path = File.join(path, entry) if File.file?(full_path) file_node(full_path) elsif File.directory?(full_path) dir_node(full_path) end end end def file_node(path) verify(path) end def verify(path) result, message = parse_as_mail(path) if result print '.' $stdout.flush else save_failure(path, message) print 'x' end end def save_failure(path, message) @failed_emails << [path, message] if @save_failures_to email_basename = File.basename(path) failure_as_filename = message.gsub(/\W/, '_') new_email_name = [failure_as_filename, email_basename].join("_") File.open(File.join(@save_failures_to, new_email_name), 'w+') do |fh| fh << File.read(path) end end end def parse_as_mail(path) @checked_count += 1 begin parsed_mail = Mail.read(path) [true, nil] rescue => e [false, e.message] end end def report_failures_to_stdout @failed_emails.each do |failed| puts "#{failed[0]} : #{failed[1]}" end puts "Failed: #{@failed_emails.size}" end end mail-2.5.4/lib/tasks/treetop.rake000066400000000000000000000003711214434061600166670ustar00rootroot00000000000000namespace :treetop do desc "Pre-generate all the .treetop files into .rb files" task :generate do Dir.glob(File.expand_path('../../mail/parsers/*.treetop', __FILE__)).each do |filename| `bundle exec tt #{filename}` end end end mail-2.5.4/mail.gemspec000066400000000000000000000023361214434061600147400ustar00rootroot00000000000000lib_dir = File.expand_path('../lib', __FILE__) $:.unshift lib_dir unless $:.include? lib_dir require 'mail/version' Gem::Specification.new do |s| s.name = "mail" s.version = Mail::VERSION::STRING s.author = "Mikel Lindsaar" s.email = "raasdnil@gmail.com" s.homepage = "http://github.com/mikel/mail" s.description = "A really Ruby Mail handler." s.summary = "Mail provides a nice Ruby DSL for making, sending and reading emails." s.license = "MIT" s.platform = Gem::Platform::RUBY s.has_rdoc = true s.extra_rdoc_files = ["README.md", "CONTRIBUTING.md", "CHANGELOG.rdoc", "TODO.rdoc"] s.add_dependency('mime-types', "~> 1.16") s.add_dependency('treetop', '~> 1.4.8') s.add_dependency('jruby-openssl') if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' s.add_dependency('tlsmail', '~> 0.0.1') if RUBY_VERSION == '1.8.6' s.add_development_dependency('bundler', '>= 1.0.3') s.add_development_dependency('rake', '> 0.8.7') s.add_development_dependency('rspec', '~> 2.12.0') s.add_development_dependency('rdoc') s.require_path = 'lib' s.files = %w(README.md MIT-LICENSE CONTRIBUTING.md CHANGELOG.rdoc Dependencies.txt Gemfile Rakefile TODO.rdoc) + Dir.glob("lib/**/*") end mail-2.5.4/patches/000077500000000000000000000000001214434061600140745ustar00rootroot00000000000000mail-2.5.4/patches/20110126_sendmail.patch000066400000000000000000000060611214434061600176700ustar00rootroot00000000000000diff --git a/lib/mail.rb b/lib/mail.rb index 1ac8614..6d13a24 100644 --- a/lib/mail.rb +++ b/lib/mail.rb @@ -2,6 +2,7 @@ module Mail # :doc: require 'date' + require 'shellwords' require 'active_support' require 'active_support/core_ext/class/attribute_accessors' @@ -33,6 +34,7 @@ module Mail # :doc: require 'mail/core_extensions/nil' require 'mail/core_extensions/string' + require 'mail/core_extensions/shellwords' unless String.new.respond_to?(:shellescape) require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3' require 'mail/patterns' diff --git a/lib/mail/core_extensions/shellwords.rb b/lib/mail/core_extensions/shellwords.rb new file mode 100644 index 0000000..aa87f31 --- /dev/null +++ b/lib/mail/core_extensions/shellwords.rb @@ -0,0 +1,55 @@ +# The following is imported from ruby 1.9.2 shellwords.rb +# +module Shellwords + # Escapes a string so that it can be safely used in a Bourne shell + # command line. + # + # Note that a resulted string should be used unquoted and is not + # intended for use in double quotes nor in single quotes. + # + # open("| grep #{Shellwords.escape(pattern)} file") { |pipe| + # # ... + # } + # + # +String#shellescape+ is a shorthand for this function. + # + # open("| grep #{pattern.shellescape} file") { |pipe| + # # ... + # } + # + def shellescape(str) + # An empty argument will be skipped, so return empty quotes. + return "''" if str.empty? + + str = str.dup + + # Process as a single byte sequence because not all shell + # implementations are multibyte aware. + str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1") + + # A LF cannot be escaped with a backslash because a backslash + LF + # combo is regarded as line continuation and simply ignored. + str.gsub!(/\n/, "'\n'") + + return str + end + + module_function :shellescape + + class << self + alias escape shellescape + end + +end + +class String + # call-seq: + # str.shellescape => string + # + # Escapes +str+ so that it can be safely used in a Bourne shell + # command line. See +Shellwords::shellescape+ for details. + # + def shellescape + Shellwords.escape(self) + end +end \ No newline at end of file diff --git a/lib/mail/network/delivery_methods/sendmail.rb b/lib/mail/network/delivery_methods/sendmail.rb index 6ae419a..29f1876 100644 --- a/lib/mail/network/delivery_methods/sendmail.rb +++ b/lib/mail/network/delivery_methods/sendmail.rb @@ -45,11 +45,11 @@ module Mail def deliver!(mail) envelope_from = mail.return_path || mail.sender || mail.from_addrs.first - return_path = "-f \"#{envelope_from}\"" if envelope_from + return_path = "-f \"#{envelope_from.to_s.shellescape}\"" if envelope_from arguments = [settings[:arguments], return_path].compact.join(" ") - Sendmail.call(settings[:location], arguments, mail.destinations.join(" "), mail) + Sendmail.call(settings[:location], arguments, mail.destinations.collect(&:shellescape).join(" "), mail) end def Sendmail.call(path, arguments, destinations, mail)mail-2.5.4/reference/000077500000000000000000000000001214434061600144035ustar00rootroot00000000000000mail-2.5.4/reference/US ASCII Table.txt000066400000000000000000000125631214434061600173230ustar00rootroot00000000000000CHAR HEX DESCRIPTION ====================================================== 00 NULL (U+0000) 01 START OF HEADING (U+0001) 02 START OF TEXT (U+0002) 03 END OF TEXT (U+0003) 04 END OF TRANSMISSION (U+0004) 05 ENQUIRY (U+0005) 06 ACKNOWLEDGE (U+0006) 07 BELL (U+0007) 08 BACKSPACE (U+0008) 09 CHARACTER TABULATION (U+0009) 0a LINE FEED (LF) (U+000A) 0b LINE TABULATION (U+000B) 0c FORM FEED (FF) (U+000C) 0d CARRIAGE RETURN (CR) (U+000D) 0e SHIFT OUT (U+000E) 0f SHIFT IN (U+000F) 10 DATA LINK ESCAPE (U+0010) 11 DEVICE CONTROL ONE (U+0011) 12 DEVICE CONTROL TWO (U+0012) 13 DEVICE CONTROL THREE (U+0013) 14 DEVICE CONTROL FOUR (U+0014) 15 NEGATIVE ACKNOWLEDGE (U+0015) 16 SYNCHRONOUS IDLE (U+0016) 17 END OF TRANSMISSION BLOCK (U+0017) 18 CANCEL (U+0018) 19 END OF MEDIUM (U+0019) 1a SUBSTITUTE (U+001A) 1b ESCAPE (U+001B) 1c INFORMATION SEPARATOR FOUR (U+001C) 1d INFORMATION SEPARATOR THREE (U+001D) 1e INFORMATION SEPARATOR TWO (U+001E) 1f INFORMATION SEPARATOR ONE (U+001F) 20 SPACE (U+0020) ! 21 EXCLAMATION MARK (U+0021) " 22 QUOTATION MARK (U+0022) # 23 NUMBER SIGN (U+0023) $ 24 DOLLAR SIGN (U+0024) % 25 PERCENT SIGN (U+0025) & 26 AMPERSAND (U+0026) ' 27 APOSTROPHE (U+0027) ( 28 LEFT PARENTHESIS (U+0028) ) 29 RIGHT PARENTHESIS (U+0029) * 2a ASTERISK (U+002A) + 2b PLUS SIGN (U+002B) , 2c COMMA (U+002C) - 2d HYPHEN-MINUS (U+002D) . 2e FULL STOP (U+002E) / 2f SOLIDUS (U+002F) 0 30 DIGIT ZERO (U+0030) 1 31 DIGIT ONE (U+0031) 2 32 DIGIT TWO (U+0032) 3 33 DIGIT THREE (U+0033) 4 34 DIGIT FOUR (U+0034) 5 35 DIGIT FIVE (U+0035) 6 36 DIGIT SIX (U+0036) 7 37 DIGIT SEVEN (U+0037) 8 38 DIGIT EIGHT (U+0038) 9 39 DIGIT NINE (U+0039) : 3a COLON (U+003A) ; 3b SEMICOLON (U+003B) < 3c LESS-THAN SIGN (U+003C) = 3d EQUALS SIGN (U+003D) > 3e GREATER-THAN SIGN (U+003E) ? 3f QUESTION MARK (U+003F) @ 40 COMMERCIAL AT (U+0040) A 41 LATIN CAPITAL LETTER A (U+0041) B 42 LATIN CAPITAL LETTER B (U+0042) C 43 LATIN CAPITAL LETTER C (U+0043) D 44 LATIN CAPITAL LETTER D (U+0044) E 45 LATIN CAPITAL LETTER E (U+0045) F 46 LATIN CAPITAL LETTER F (U+0046) G 47 LATIN CAPITAL LETTER G (U+0047) H 48 LATIN CAPITAL LETTER H (U+0048) I 49 LATIN CAPITAL LETTER I (U+0049) J 4a LATIN CAPITAL LETTER J (U+004A) K 4b LATIN CAPITAL LETTER K (U+004B) L 4c LATIN CAPITAL LETTER L (U+004C) M 4d LATIN CAPITAL LETTER M (U+004D) N 4e LATIN CAPITAL LETTER N (U+004E) O 4f LATIN CAPITAL LETTER O (U+004F) P 50 LATIN CAPITAL LETTER P (U+0050) Q 51 LATIN CAPITAL LETTER Q (U+0051) R 52 LATIN CAPITAL LETTER R (U+0052) S 53 LATIN CAPITAL LETTER S (U+0053) T 54 LATIN CAPITAL LETTER T (U+0054) U 55 LATIN CAPITAL LETTER U (U+0055) V 56 LATIN CAPITAL LETTER V (U+0056) W 57 LATIN CAPITAL LETTER W (U+0057) X 58 LATIN CAPITAL LETTER X (U+0058) Y 59 LATIN CAPITAL LETTER Y (U+0059) Z 5a LATIN CAPITAL LETTER Z (U+005A) [ 5b LEFT SQUARE BRACKET (U+005B) \ 5c REVERSE SOLIDUS (U+005C) ] 5d RIGHT SQUARE BRACKET (U+005D) ^ 5e CIRCUMFLEX ACCENT (U+005E) _ 5f LOW LINE (U+005F) ` 60 GRAVE ACCENT (U+0060) a 61 LATIN SMALL LETTER A (U+0061) b 62 LATIN SMALL LETTER B (U+0062) c 63 LATIN SMALL LETTER C (U+0063) d 64 LATIN SMALL LETTER D (U+0064) e 65 LATIN SMALL LETTER E (U+0065) f 66 LATIN SMALL LETTER F (U+0066) g 67 LATIN SMALL LETTER G (U+0067) h 68 LATIN SMALL LETTER H (U+0068) i 69 LATIN SMALL LETTER I (U+0069) j 6a LATIN SMALL LETTER J (U+006A) k 6b LATIN SMALL LETTER K (U+006B) l 6c LATIN SMALL LETTER L (U+006C) m 6d LATIN SMALL LETTER M (U+006D) n 6e LATIN SMALL LETTER N (U+006E) o 6f LATIN SMALL LETTER O (U+006F) p 70 LATIN SMALL LETTER P (U+0070) q 71 LATIN SMALL LETTER Q (U+0071) r 72 LATIN SMALL LETTER R (U+0072) s 73 LATIN SMALL LETTER S (U+0073) t 74 LATIN SMALL LETTER T (U+0074) u 75 LATIN SMALL LETTER U (U+0075) v 76 LATIN SMALL LETTER V (U+0076) w 77 LATIN SMALL LETTER W (U+0077) x 78 LATIN SMALL LETTER X (U+0078) y 79 LATIN SMALL LETTER Y (U+0079) z 7a LATIN SMALL LETTER Z (U+007A) { 7b LEFT CURLY BRACKET (U+007B) | 7c VERTICAL LINE (U+007C) } 7d RIGHT CURLY BRACKET (U+007D) ~ 7e TILDE (U+007E) 7f DELETE (U+007F)mail-2.5.4/reference/rfc1035 Domain Implementation and Specification.txt000066400000000000000000003600651214434061600256630ustar00rootroot00000000000000Updated by: 1101, 1183, 1348, 1876, 1982, 1995, STANDARD 1996, 2065, 2136, 2137, 2181, 2308, 2535, 2845, 3425, 3658, 4033, 4034, 4035, 4343 Errata Network Working Group P. Mockapetris Request for Comments: 1035 ISI November 1987 Obsoletes: RFCs 882, 883, 973 DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION 1. STATUS OF THIS MEMO This RFC describes the details of the domain system and protocol, and assumes that the reader is familiar with the concepts discussed in a companion RFC, "Domain Names - Concepts and Facilities" [RFC-1034]. The domain system is a mixture of functions and data types which are an official protocol and functions and data types which are still experimental. Since the domain system is intentionally extensible, new data types and experimental behavior should always be expected in parts of the system beyond the official protocol. The official protocol parts include standard queries, responses and the Internet class RR data formats (e.g., host addresses). Since the previous RFC set, several definitions have changed, so some previous definitions are obsolete. Experimental or obsolete features are clearly marked in these RFCs, and such information should be used with caution. The reader is especially cautioned not to depend on the values which appear in examples to be current or complete, since their purpose is primarily pedagogical. Distribution of this memo is unlimited. Table of Contents 1. STATUS OF THIS MEMO 1 2. INTRODUCTION 3 2.1. Overview 3 2.2. Common configurations 4 2.3. Conventions 7 2.3.1. Preferred name syntax 7 2.3.2. Data Transmission Order 8 2.3.3. Character Case 9 2.3.4. Size limits 10 3. DOMAIN NAME SPACE AND RR DEFINITIONS 10 3.1. Name space definitions 10 3.2. RR definitions 11 3.2.1. Format 11 3.2.2. TYPE values 12 3.2.3. QTYPE values 12 3.2.4. CLASS values 13 Mockapetris [Page 1] RFC 1035 Domain Implementation and Specification November 1987 3.2.5. QCLASS values 13 3.3. Standard RRs 13 3.3.1. CNAME RDATA format 14 3.3.2. HINFO RDATA format 14 3.3.3. MB RDATA format (EXPERIMENTAL) 14 3.3.4. MD RDATA format (Obsolete) 15 3.3.5. MF RDATA format (Obsolete) 15 3.3.6. MG RDATA format (EXPERIMENTAL) 16 3.3.7. MINFO RDATA format (EXPERIMENTAL) 16 3.3.8. MR RDATA format (EXPERIMENTAL) 17 3.3.9. MX RDATA format 17 3.3.10. NULL RDATA format (EXPERIMENTAL) 17 3.3.11. NS RDATA format 18 3.3.12. PTR RDATA format 18 3.3.13. SOA RDATA format 19 3.3.14. TXT RDATA format 20 3.4. ARPA Internet specific RRs 20 3.4.1. A RDATA format 20 3.4.2. WKS RDATA format 21 3.5. IN-ADDR.ARPA domain 22 3.6. Defining new types, classes, and special namespaces 24 4. MESSAGES 25 4.1. Format 25 4.1.1. Header section format 26 4.1.2. Question section format 28 4.1.3. Resource record format 29 4.1.4. Message compression 30 4.2. Transport 32 4.2.1. UDP usage 32 4.2.2. TCP usage 32 5. MASTER FILES 33 5.1. Format 33 5.2. Use of master files to define zones 35 5.3. Master file example 36 6. NAME SERVER IMPLEMENTATION 37 6.1. Architecture 37 6.1.1. Control 37 6.1.2. Database 37 6.1.3. Time 39 6.2. Standard query processing 39 6.3. Zone refresh and reload processing 39 6.4. Inverse queries (Optional) 40 6.4.1. The contents of inverse queries and responses 40 6.4.2. Inverse query and response example 41 6.4.3. Inverse query processing 42 Mockapetris [Page 2] RFC 1035 Domain Implementation and Specification November 1987 6.5. Completion queries and responses 42 7. RESOLVER IMPLEMENTATION 43 7.1. Transforming a user request into a query 43 7.2. Sending the queries 44 7.3. Processing responses 46 7.4. Using the cache 47 8. MAIL SUPPORT 47 8.1. Mail exchange binding 48 8.2. Mailbox binding (Experimental) 48 9. REFERENCES and BIBLIOGRAPHY 50 Index 54 2. INTRODUCTION 2.1. Overview The goal of domain names is to provide a mechanism for naming resources in such a way that the names are usable in different hosts, networks, protocol families, internets, and administrative organizations. From the user's point of view, domain names are useful as arguments to a local agent, called a resolver, which retrieves information associated with the domain name. Thus a user might ask for the host address or mail information associated with a particular domain name. To enable the user to request a particular type of information, an appropriate query type is passed to the resolver with the domain name. To the user, the domain tree is a single information space; the resolver is responsible for hiding the distribution of data among name servers from the user. From the resolver's point of view, the database that makes up the domain space is distributed among various name servers. Different parts of the domain space are stored in different name servers, although a particular data item will be stored redundantly in two or more name servers. The resolver starts with knowledge of at least one name server. When the resolver processes a user query it asks a known name server for the information; in return, the resolver either receives the desired information or a referral to another name server. Using these referrals, resolvers learn the identities and contents of other name servers. Resolvers are responsible for dealing with the distribution of the domain space and dealing with the effects of name server failure by consulting redundant databases in other servers. Name servers manage two kinds of data. The first kind of data held in sets called zones; each zone is the complete database for a particular "pruned" subtree of the domain space. This data is called authoritative. A name server periodically checks to make sure that its zones are up to date, and if not, obtains a new copy of updated zones Mockapetris [Page 3] RFC 1035 Domain Implementation and Specification November 1987 from master files stored locally or in another name server. The second kind of data is cached data which was acquired by a local resolver. This data may be incomplete, but improves the performance of the retrieval process when non-local data is repeatedly accessed. Cached data is eventually discarded by a timeout mechanism. This functional structure isolates the problems of user interface, failure recovery, and distribution in the resolvers and isolates the database update and refresh problems in the name servers. 2.2. Common configurations A host can participate in the domain name system in a number of ways, depending on whether the host runs programs that retrieve information from the domain system, name servers that answer queries from other hosts, or various combinations of both functions. The simplest, and perhaps most typical, configuration is shown below: Local Host | Foreign | +---------+ +----------+ | +--------+ | | user queries | |queries | | | | User |-------------->| |---------|->|Foreign | | Program | | Resolver | | | Name | | |<--------------| |<--------|--| Server | | | user responses| |responses| | | +---------+ +----------+ | +--------+ | A | cache additions | | references | V | | +----------+ | | cache | | +----------+ | User programs interact with the domain name space through resolvers; the format of user queries and user responses is specific to the host and its operating system. User queries will typically be operating system calls, and the resolver and its cache will be part of the host operating system. Less capable hosts may choose to implement the resolver as a subroutine to be linked in with every program that needs its services. Resolvers answer user queries with information they acquire via queries to foreign name servers and the local cache. Note that the resolver may have to make several queries to several different foreign name servers to answer a particular user query, and hence the resolution of a user query may involve several network accesses and an arbitrary amount of time. The queries to foreign name servers and the corresponding responses have a standard format described Mockapetris [Page 4] RFC 1035 Domain Implementation and Specification November 1987 in this memo, and may be datagrams. Depending on its capabilities, a name server could be a stand alone program on a dedicated machine or a process or processes on a large timeshared host. A simple configuration might be: Local Host | Foreign | +---------+ | / /| | +---------+ | +----------+ | +--------+ | | | | |responses| | | | | | | Name |---------|->|Foreign | | Master |-------------->| Server | | |Resolver| | files | | | |<--------|--| | | |/ | | queries | +--------+ +---------+ +----------+ | Here a primary name server acquires information about one or more zones by reading master files from its local file system, and answers queries about those zones that arrive from foreign resolvers. The DNS requires that all zones be redundantly supported by more than one name server. Designated secondary servers can acquire zones and check for updates from the primary server using the zone transfer protocol of the DNS. This configuration is shown below: Local Host | Foreign | +---------+ | / /| | +---------+ | +----------+ | +--------+ | | | | |responses| | | | | | | Name |---------|->|Foreign | | Master |-------------->| Server | | |Resolver| | files | | | |<--------|--| | | |/ | | queries | +--------+ +---------+ +----------+ | A |maintenance | +--------+ | +------------|->| | | queries | |Foreign | | | | Name | +------------------|--| Server | maintenance responses | +--------+ In this configuration, the name server periodically establishes a virtual circuit to a foreign name server to acquire a copy of a zone or to check that an existing copy has not changed. The messages sent for Mockapetris [Page 5] RFC 1035 Domain Implementation and Specification November 1987 these maintenance activities follow the same form as queries and responses, but the message sequences are somewhat different. The information flow in a host that supports all aspects of the domain name system is shown below: Local Host | Foreign | +---------+ +----------+ | +--------+ | | user queries | |queries | | | | User |-------------->| |---------|->|Foreign | | Program | | Resolver | | | Name | | |<--------------| |<--------|--| Server | | | user responses| |responses| | | +---------+ +----------+ | +--------+ | A | cache additions | | references | V | | +----------+ | | Shared | | | database | | +----------+ | A | | +---------+ refreshes | | references | / /| | V | +---------+ | +----------+ | +--------+ | | | | |responses| | | | | | | Name |---------|->|Foreign | | Master |-------------->| Server | | |Resolver| | files | | | |<--------|--| | | |/ | | queries | +--------+ +---------+ +----------+ | A |maintenance | +--------+ | +------------|->| | | queries | |Foreign | | | | Name | +------------------|--| Server | maintenance responses | +--------+ The shared database holds domain space data for the local name server and resolver. The contents of the shared database will typically be a mixture of authoritative data maintained by the periodic refresh operations of the name server and cached data from previous resolver requests. The structure of the domain data and the necessity for synchronization between name servers and resolvers imply the general characteristics of this database, but the actual format is up to the local implementor. Mockapetris [Page 6] RFC 1035 Domain Implementation and Specification November 1987 Information flow can also be tailored so that a group of hosts act together to optimize activities. Sometimes this is done to offload less capable hosts so that they do not have to implement a full resolver. This can be appropriate for PCs or hosts which want to minimize the amount of new network code which is required. This scheme can also allow a group of hosts can share a small number of caches rather than maintaining a large number of separate caches, on the premise that the centralized caches will have a higher hit ratio. In either case, resolvers are replaced with stub resolvers which act as front ends to resolvers located in a recursive server in one or more name servers known to perform that service: Local Hosts | Foreign | +---------+ | | | responses | | Stub |<--------------------+ | | Resolver| | | | |----------------+ | | +---------+ recursive | | | queries | | | V | | +---------+ recursive +----------+ | +--------+ | | queries | |queries | | | | Stub |-------------->| Recursive|---------|->|Foreign | | Resolver| | Server | | | Name | | |<--------------| |<--------|--| Server | +---------+ responses | |responses| | | +----------+ | +--------+ | Central | | | cache | | +----------+ | In any case, note that domain components are always replicated for reliability whenever possible. 2.3. Conventions The domain system has several conventions dealing with low-level, but fundamental, issues. While the implementor is free to violate these conventions WITHIN HIS OWN SYSTEM, he must observe these conventions in ALL behavior observed from other hosts. 2.3.1. Preferred name syntax The DNS specifications attempt to be as general as possible in the rules for constructing domain names. The idea is that the name of any existing object can be expressed as a domain name with minimal changes. Mockapetris [Page 7] RFC 1035 Domain Implementation and Specification November 1987 However, when assigning a domain name for an object, the prudent user will select a name which satisfies both the rules of the domain system and any existing rules for the object, whether these rules are published or implied by existing programs. For example, when naming a mail domain, the user should satisfy both the rules of this memo and those in RFC-822. When creating a new host name, the old rules for HOSTS.TXT should be followed. This avoids problems when old software is converted to use domain names. The following syntax will result in fewer problems with many applications that use domain names (e.g., mail, TELNET). ::= | " " ::= parameter := attribute "=" value attribute := token ; Matching of attributes ; is ALWAYS case-insensitive. value := token / quoted-string token := 1* tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> "/" / "[" / "]" / "?" / "=" ; Must be in quoted-string, ; to use within parameter values Freed & Borenstein Standards Track [Page 12] RFC 2045 Internet Message Bodies November 1996 Note that the definition of "tspecials" is the same as the RFC 822 definition of "specials" with the addition of the three characters "/", "?", and "=", and the removal of ".". Note also that a subtype specification is MANDATORY -- it may not be omitted from a Content-Type header field. As such, there are no default subtypes. The type, subtype, and parameter names are not case sensitive. For example, TEXT, Text, and TeXt are all equivalent top-level media types. Parameter values are normally case sensitive, but sometimes are interpreted in a case-insensitive fashion, depending on the intended use. (For example, multipart boundaries are case-sensitive, but the "access-type" parameter for message/External-body is not case-sensitive.) Note that the value of a quoted string parameter does not include the quotes. That is, the quotation marks in a quoted-string are not a part of the value of the parameter, but are merely used to delimit that parameter value. In addition, comments are allowed in accordance with RFC 822 rules for structured header fields. Thus the following two forms Content-type: text/plain; charset=us-ascii (Plain text) Content-type: text/plain; charset="us-ascii" are completely equivalent. Beyond this syntax, the only syntactic constraint on the definition of subtype names is the desire that their uses must not conflict. That is, it would be undesirable to have two different communities using "Content-Type: application/foobar" to mean two different things. The process of defining new media subtypes, then, is not intended to be a mechanism for imposing restrictions, but simply a mechanism for publicizing their definition and usage. There are, therefore, two acceptable mechanisms for defining new media subtypes: (1) Private values (starting with "X-") may be defined bilaterally between two cooperating agents without outside registration or standardization. Such values cannot be registered or standardized. (2) New standard values should be registered with IANA as described in RFC 2048. The second document in this set, RFC 2046, defines the initial set of media types for MIME. Freed & Borenstein Standards Track [Page 13] RFC 2045 Internet Message Bodies November 1996 5.2. Content-Type Defaults Default RFC 822 messages without a MIME Content-Type header are taken by this protocol to be plain text in the US-ASCII character set, which can be explicitly specified as: Content-type: text/plain; charset=us-ascii This default is assumed if no Content-Type header field is specified. It is also recommend that this default be assumed when a syntactically invalid Content-Type header field is encountered. In the presence of a MIME-Version header field and the absence of any Content-Type header field, a receiving User Agent can also assume that plain US-ASCII text was the sender's intent. Plain US-ASCII text may still be assumed in the absence of a MIME-Version or the presence of an syntactically invalid Content-Type header field, but the sender's intent might have been otherwise. 6. Content-Transfer-Encoding Header Field Many media types which could be usefully transported via email are represented, in their "natural" format, as 8bit character or binary data. Such data cannot be transmitted over some transfer protocols. For example, RFC 821 (SMTP) restricts mail messages to 7bit US-ASCII data with lines no longer than 1000 characters including any trailing CRLF line separator. It is necessary, therefore, to define a standard mechanism for encoding such data into a 7bit short line format. Proper labelling of unencoded material in less restrictive formats for direct use over less restrictive transports is also desireable. This document specifies that such encodings will be indicated by a new "Content- Transfer-Encoding" header field. This field has not been defined by any previous standard. 6.1. Content-Transfer-Encoding Syntax The Content-Transfer-Encoding field's value is a single token specifying the type of encoding, as enumerated below. Formally: encoding := "Content-Transfer-Encoding" ":" mechanism mechanism := "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" / ietf-token / x-token These values are not case sensitive -- Base64 and BASE64 and bAsE64 are all equivalent. An encoding type of 7BIT requires that the body Freed & Borenstein Standards Track [Page 14] RFC 2045 Internet Message Bodies November 1996 is already in a 7bit mail-ready representation. This is the default value -- that is, "Content-Transfer-Encoding: 7BIT" is assumed if the Content-Transfer-Encoding header field is not present. 6.2. Content-Transfer-Encodings Semantics This single Content-Transfer-Encoding token actually provides two pieces of information. It specifies what sort of encoding transformation the body was subjected to and hence what decoding operation must be used to restore it to its original form, and it specifies what the domain of the result is. The transformation part of any Content-Transfer-Encodings specifies, either explicitly or implicitly, a single, well-defined decoding algorithm, which for any sequence of encoded octets either transforms it to the original sequence of octets which was encoded, or shows that it is illegal as an encoded sequence. Content-Transfer- Encodings transformations never depend on any additional external profile information for proper operation. Note that while decoders must produce a single, well-defined output for a valid encoding no such restrictions exist for encoders: Encoding a given sequence of octets to different, equivalent encoded sequences is perfectly legal. Three transformations are currently defined: identity, the "quoted- printable" encoding, and the "base64" encoding. The domains are "binary", "8bit" and "7bit". The Content-Transfer-Encoding values "7bit", "8bit", and "binary" all mean that the identity (i.e. NO) encoding transformation has been performed. As such, they serve simply as indicators of the domain of the body data, and provide useful information about the sort of encoding that might be needed for transmission in a given transport system. The terms "7bit data", "8bit data", and "binary data" are all defined in Section 2. The quoted-printable and base64 encodings transform their input from an arbitrary domain into material in the "7bit" range, thus making it safe to carry over restricted transports. The specific definition of the transformations are given below. The proper Content-Transfer-Encoding label must always be used. Labelling unencoded data containing 8bit characters as "7bit" is not allowed, nor is labelling unencoded non-line-oriented data as anything other than "binary" allowed. Unlike media subtypes, a proliferation of Content-Transfer-Encoding values is both undesirable and unnecessary. However, establishing only a single transformation into the "7bit" domain does not seem Freed & Borenstein Standards Track [Page 15] RFC 2045 Internet Message Bodies November 1996 possible. There is a tradeoff between the desire for a compact and efficient encoding of largely- binary data and the desire for a somewhat readable encoding of data that is mostly, but not entirely, 7bit. For this reason, at least two encoding mechanisms are necessary: a more or less readable encoding (quoted-printable) and a "dense" or "uniform" encoding (base64). Mail transport for unencoded 8bit data is defined in RFC 1652. As of the initial publication of this document, there are no standardized Internet mail transports for which it is legitimate to include unencoded binary data in mail bodies. Thus there are no circumstances in which the "binary" Content-Transfer-Encoding is actually valid in Internet mail. However, in the event that binary mail transport becomes a reality in Internet mail, or when MIME is used in conjunction with any other binary-capable mail transport mechanism, binary bodies must be labelled as such using this mechanism. NOTE: The five values defined for the Content-Transfer-Encoding field imply nothing about the media type other than the algorithm by which it was encoded or the transport system requirements if unencoded. 6.3. New Content-Transfer-Encodings Implementors may, if necessary, define private Content-Transfer- Encoding values, but must use an x-token, which is a name prefixed by "X-", to indicate its non-standard status, e.g., "Content-Transfer- Encoding: x-my-new-encoding". Additional standardized Content- Transfer-Encoding values must be specified by a standards-track RFC. The requirements such specifications must meet are given in RFC 2048. As such, all content-transfer-encoding namespace except that beginning with "X-" is explicitly reserved to the IETF for future use. Unlike media types and subtypes, the creation of new Content- Transfer-Encoding values is STRONGLY discouraged, as it seems likely to hinder interoperability with little potential benefit 6.4. Interpretation and Use If a Content-Transfer-Encoding header field appears as part of a message header, it applies to the entire body of that message. If a Content-Transfer-Encoding header field appears as part of an entity's headers, it applies only to the body of that entity. If an entity is of type "multipart" the Content-Transfer-Encoding is not permitted to have any value other than "7bit", "8bit" or "binary". Even more severe restrictions apply to some subtypes of the "message" type. Freed & Borenstein Standards Track [Page 16] RFC 2045 Internet Message Bodies November 1996 It should be noted that most media types are defined in terms of octets rather than bits, so that the mechanisms described here are mechanisms for encoding arbitrary octet streams, not bit streams. If a bit stream is to be encoded via one of these mechanisms, it must first be converted to an 8bit byte stream using the network standard bit order ("big-endian"), in which the earlier bits in a stream become the higher-order bits in a 8bit byte. A bit stream not ending at an 8bit boundary must be padded with zeroes. RFC 2046 provides a mechanism for noting the addition of such padding in the case of the application/octet-stream media type, which has a "padding" parameter. The encoding mechanisms defined here explicitly encode all data in US-ASCII. Thus, for example, suppose an entity has header fields such as: Content-Type: text/plain; charset=ISO-8859-1 Content-transfer-encoding: base64 This must be interpreted to mean that the body is a base64 US-ASCII encoding of data that was originally in ISO-8859-1, and will be in that character set again after decoding. Certain Content-Transfer-Encoding values may only be used on certain media types. In particular, it is EXPRESSLY FORBIDDEN to use any encodings other than "7bit", "8bit", or "binary" with any composite media type, i.e. one that recursively includes other Content-Type fields. Currently the only composite media types are "multipart" and "message". All encodings that are desired for bodies of type multipart or message must be done at the innermost level, by encoding the actual body that needs to be encoded. It should also be noted that, by definition, if a composite entity has a transfer-encoding value such as "7bit", but one of the enclosed entities has a less restrictive value such as "8bit", then either the outer "7bit" labelling is in error, because 8bit data are included, or the inner "8bit" labelling placed an unnecessarily high demand on the transport system because the actual included data were actually 7bit-safe. NOTE ON ENCODING RESTRICTIONS: Though the prohibition against using content-transfer-encodings on composite body data may seem overly restrictive, it is necessary to prevent nested encodings, in which data are passed through an encoding algorithm multiple times, and must be decoded multiple times in order to be properly viewed. Nested encodings add considerable complexity to user agents: Aside from the obvious efficiency problems with such multiple encodings, they can obscure the basic structure of a message. In particular, they can imply that several decoding operations are necessary simply Freed & Borenstein Standards Track [Page 17] RFC 2045 Internet Message Bodies November 1996 to find out what types of bodies a message contains. Banning nested encodings may complicate the job of certain mail gateways, but this seems less of a problem than the effect of nested encodings on user agents. Any entity with an unrecognized Content-Transfer-Encoding must be treated as if it has a Content-Type of "application/octet-stream", regardless of what the Content-Type header field actually says. NOTE ON THE RELATIONSHIP BETWEEN CONTENT-TYPE AND CONTENT-TRANSFER- ENCODING: It may seem that the Content-Transfer-Encoding could be inferred from the characteristics of the media that is to be encoded, or, at the very least, that certain Content-Transfer-Encodings could be mandated for use with specific media types. There are several reasons why this is not the case. First, given the varying types of transports used for mail, some encodings may be appropriate for some combinations of media types and transports but not for others. (For example, in an 8bit transport, no encoding would be required for text in certain character sets, while such encodings are clearly required for 7bit SMTP.) Second, certain media types may require different types of transfer encoding under different circumstances. For example, many PostScript bodies might consist entirely of short lines of 7bit data and hence require no encoding at all. Other PostScript bodies (especially those using Level 2 PostScript's binary encoding mechanism) may only be reasonably represented using a binary transport encoding. Finally, since the Content-Type field is intended to be an open-ended specification mechanism, strict specification of an association between media types and encodings effectively couples the specification of an application protocol with a specific lower-level transport. This is not desirable since the developers of a media type should not have to be aware of all the transports in use and what their limitations are. 6.5. Translating Encodings The quoted-printable and base64 encodings are designed so that conversion between them is possible. The only issue that arises in such a conversion is the handling of hard line breaks in quoted- printable encoding output. When converting from quoted-printable to base64 a hard line break in the quoted-printable form represents a CRLF sequence in the canonical form of the data. It must therefore be converted to a corresponding encoded CRLF in the base64 form of the data. Similarly, a CRLF sequence in the canonical form of the data obtained after base64 decoding must be converted to a quoted- printable hard line break, but ONLY when converting text data. Freed & Borenstein Standards Track [Page 18] RFC 2045 Internet Message Bodies November 1996 6.6. Canonical Encoding Model There was some confusion, in the previous versions of this RFC, regarding the model for when email data was to be converted to canonical form and encoded, and in particular how this process would affect the treatment of CRLFs, given that the representation of newlines varies greatly from system to system, and the relationship between content-transfer-encodings and character sets. A canonical model for encoding is presented in RFC 2049 for this reason. 6.7. Quoted-Printable Content-Transfer-Encoding The Quoted-Printable encoding is intended to represent data that largely consists of octets that correspond to printable characters in the US-ASCII character set. It encodes the data in such a way that the resulting octets are unlikely to be modified by mail transport. If the data being encoded are mostly US-ASCII text, the encoded form of the data remains largely recognizable by humans. A body which is entirely US-ASCII may also be encoded in Quoted-Printable to ensure the integrity of the data should the message pass through a character-translating, and/or line-wrapping gateway. In this encoding, octets are to be represented as determined by the following rules: (1) (General 8bit representation) Any octet, except a CR or LF that is part of a CRLF line break of the canonical (standard) form of the data being encoded, may be represented by an "=" followed by a two digit hexadecimal representation of the octet's value. The digits of the hexadecimal alphabet, for this purpose, are "0123456789ABCDEF". Uppercase letters must be used; lowercase letters are not allowed. Thus, for example, the decimal value 12 (US-ASCII form feed) can be represented by "=0C", and the decimal value 61 (US- ASCII EQUAL SIGN) can be represented by "=3D". This rule must be followed except when the following rules allow an alternative encoding. (2) (Literal representation) Octets with decimal values of 33 through 60 inclusive, and 62 through 126, inclusive, MAY be represented as the US-ASCII characters which correspond to those octets (EXCLAMATION POINT through LESS THAN, and GREATER THAN through TILDE, respectively). (3) (White Space) Octets with values of 9 and 32 MAY be represented as US-ASCII TAB (HT) and SPACE characters, Freed & Borenstein Standards Track [Page 19] RFC 2045 Internet Message Bodies November 1996 respectively, but MUST NOT be so represented at the end of an encoded line. Any TAB (HT) or SPACE characters on an encoded line MUST thus be followed on that line by a printable character. In particular, an "=" at the end of an encoded line, indicating a soft line break (see rule #5) may follow one or more TAB (HT) or SPACE characters. It follows that an octet with decimal value 9 or 32 appearing at the end of an encoded line must be represented according to Rule #1. This rule is necessary because some MTAs (Message Transport Agents, programs which transport messages from one user to another, or perform a portion of such transfers) are known to pad lines of text with SPACEs, and others are known to remove "white space" characters from the end of a line. Therefore, when decoding a Quoted-Printable body, any trailing white space on a line must be deleted, as it will necessarily have been added by intermediate transport agents. (4) (Line Breaks) A line break in a text body, represented as a CRLF sequence in the text canonical form, must be represented by a (RFC 822) line break, which is also a CRLF sequence, in the Quoted-Printable encoding. Since the canonical representation of media types other than text do not generally include the representation of line breaks as CRLF sequences, no hard line breaks (i.e. line breaks that are intended to be meaningful and to be displayed to the user) can occur in the quoted-printable encoding of such types. Sequences like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely appear in non-text data represented in quoted- printable, of course. Note that many implementations may elect to encode the local representation of various content types directly rather than converting to canonical form first, encoding, and then converting back to local representation. In particular, this may apply to plain text material on systems that use newline conventions other than a CRLF terminator sequence. Such an implementation optimization is permissible, but only when the combined canonicalization-encoding step is equivalent to performing the three steps separately. (5) (Soft Line Breaks) The Quoted-Printable encoding REQUIRES that encoded lines be no more than 76 characters long. If longer lines are to be encoded with the Quoted-Printable encoding, "soft" line breaks Freed & Borenstein Standards Track [Page 20] RFC 2045 Internet Message Bodies November 1996 must be used. An equal sign as the last character on a encoded line indicates such a non-significant ("soft") line break in the encoded text. Thus if the "raw" form of the line is a single unencoded line that says: Now's the time for all folk to come to the aid of their country. This can be represented, in the Quoted-Printable encoding, as: Now's the time = for all folk to come= to the aid of their country. This provides a mechanism with which long lines are encoded in such a way as to be restored by the user agent. The 76 character limit does not count the trailing CRLF, but counts all other characters, including any equal signs. Since the hyphen character ("-") may be represented as itself in the Quoted-Printable encoding, care must be taken, when encapsulating a quoted-printable encoded body inside one or more multipart entities, to ensure that the boundary delimiter does not appear anywhere in the encoded body. (A good strategy is to choose a boundary that includes a character sequence such as "=_" which can never appear in a quoted-printable body. See the definition of multipart messages in RFC 2046.) NOTE: The quoted-printable encoding represents something of a compromise between readability and reliability in transport. Bodies encoded with the quoted-printable encoding will work reliably over most mail gateways, but may not work perfectly over a few gateways, notably those involving translation into EBCDIC. A higher level of confidence is offered by the base64 Content-Transfer-Encoding. A way to get reasonably reliable transport through EBCDIC gateways is to also quote the US-ASCII characters !"#$@[\]^`{|}~ according to rule #1. Because quoted-printable data is generally assumed to be line- oriented, it is to be expected that the representation of the breaks between the lines of quoted-printable data may be altered in transport, in the same manner that plain text mail has always been altered in Internet mail when passing between systems with differing newline conventions. If such alterations are likely to constitute a Freed & Borenstein Standards Track [Page 21] RFC 2045 Internet Message Bodies November 1996 corruption of the data, it is probably more sensible to use the base64 encoding rather than the quoted-printable encoding. NOTE: Several kinds of substrings cannot be generated according to the encoding rules for the quoted-printable content-transfer- encoding, and hence are formally illegal if they appear in the output of a quoted-printable encoder. This note enumerates these cases and suggests ways to handle such illegal substrings if any are encountered in quoted-printable data that is to be decoded. (1) An "=" followed by two hexadecimal digits, one or both of which are lowercase letters in "abcdef", is formally illegal. A robust implementation might choose to recognize them as the corresponding uppercase letters. (2) An "=" followed by a character that is neither a hexadecimal digit (including "abcdef") nor the CR character of a CRLF pair is illegal. This case can be the result of US-ASCII text having been included in a quoted-printable part of a message without itself having been subjected to quoted-printable encoding. A reasonable approach by a robust implementation might be to include the "=" character and the following character in the decoded data without any transformation and, if possible, indicate to the user that proper decoding was not possible at this point in the data. (3) An "=" cannot be the ultimate or penultimate character in an encoded object. This could be handled as in case (2) above. (4) Control characters other than TAB, or CR and LF as parts of CRLF pairs, must not appear. The same is true for octets with decimal values greater than 126. If found in incoming quoted-printable data by a decoder, a robust implementation might exclude them from the decoded data and warn the user that illegal characters were discovered. (5) Encoded lines must not be longer than 76 characters, not counting the trailing CRLF. If longer lines are found in incoming, encoded data, a robust implementation might nevertheless decode the lines, and might report the erroneous encoding to the user. Freed & Borenstein Standards Track [Page 22] RFC 2045 Internet Message Bodies November 1996 WARNING TO IMPLEMENTORS: If binary data is encoded in quoted- printable, care must be taken to encode CR and LF characters as "=0D" and "=0A", respectively. In particular, a CRLF sequence in binary data should be encoded as "=0D=0A". Otherwise, if CRLF were represented as a hard line break, it might be incorrectly decoded on platforms with different line break conventions. For formalists, the syntax of quoted-printable data is described by the following grammar: quoted-printable := qp-line *(CRLF qp-line) qp-line := *(qp-segment transport-padding CRLF) qp-part transport-padding qp-part := qp-section ; Maximum length of 76 characters qp-segment := qp-section *(SPACE / TAB) "=" ; Maximum length of 76 characters qp-section := [*(ptext / SPACE / TAB) ptext] ptext := hex-octet / safe-char safe-char := ; Characters not listed as "mail-safe" in ; RFC 2049 are also not recommended. hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F") ; Octet must be used for characters > 127, =, ; SPACEs or TABs at the ends of lines, and is ; recommended for any character not listed in ; RFC 2049 as "mail-safe". transport-padding := *LWSP-char ; Composers MUST NOT generate ; non-zero length transport ; padding, but receivers MUST ; be able to handle padding ; added by message transports. IMPORTANT: The addition of LWSP between the elements shown in this BNF is NOT allowed since this BNF does not specify a structured header field. Freed & Borenstein Standards Track [Page 23] RFC 2045 Internet Message Bodies November 1996 6.8. Base64 Content-Transfer-Encoding The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable. The encoding and decoding algorithms are simple, but the encoded data are consistently only about 33 percent larger than the unencoded data. This encoding is virtually identical to the one used in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421. A 65-character subset of US-ASCII is used, enabling 6 bits to be represented per printable character. (The extra 65th character, "=", is used to signify a special processing function.) NOTE: This subset has the important property that it is represented identically in all versions of ISO 646, including US-ASCII, and all characters in the subset are also represented identically in all versions of EBCDIC. Other popular encodings, such as the encoding used by the uuencode utility, Macintosh binhex 4.0 [RFC-1741], and the base85 encoding specified as part of Level 2 PostScript, do not share these properties, and thus do not fulfill the portability requirements a binary transport encoding for mail must meet. The encoding process represents 24-bit groups of input bits as output strings of 4 encoded characters. Proceeding from left to right, a 24-bit input group is formed by concatenating 3 8bit input groups. These 24 bits are then treated as 4 concatenated 6-bit groups, each of which is translated into a single digit in the base64 alphabet. When encoding a bit stream via the base64 encoding, the bit stream must be presumed to be ordered with the most-significant-bit first. That is, the first bit in the stream will be the high-order bit in the first 8bit byte, and the eighth bit will be the low-order bit in the first 8bit byte, and so on. Each 6-bit group is used as an index into an array of 64 printable characters. The character referenced by the index is placed in the output string. These characters, identified in Table 1, below, are selected so as to be universally representable, and the set excludes characters with particular significance to SMTP (e.g., ".", CR, LF) and to the multipart boundary delimiters defined in RFC 2046 (e.g., "-"). Freed & Borenstein Standards Track [Page 24] RFC 2045 Internet Message Bodies November 1996 Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 + 12 M 29 d 46 u 63 / 13 N 30 e 47 v 14 O 31 f 48 w (pad) = 15 P 32 g 49 x 16 Q 33 h 50 y The encoded output stream must be represented in lines of no more than 76 characters each. All line breaks or other characters not found in Table 1 must be ignored by decoding software. In base64 data, characters other than those in Table 1, line breaks, and other white space probably indicate a transmission error, about which a warning message or even a message rejection might be appropriate under some circumstances. Special processing is performed if fewer than 24 bits are available at the end of the data being encoded. A full encoding quantum is always completed at the end of a body. When fewer than 24 input bits are available in an input group, zero bits are added (on the right) to form an integral number of 6-bit groups. Padding at the end of the data is performed using the "=" character. Since all base64 input is an integral number of octets, only the following cases can arise: (1) the final quantum of encoding input is an integral multiple of 24 bits; here, the final unit of encoded output will be an integral multiple of 4 characters with no "=" padding, (2) the final quantum of encoding input is exactly 8 bits; here, the final unit of encoded output will be two characters followed by two "=" padding characters, or (3) the final quantum of encoding input is exactly 16 bits; here, the final unit of encoded output will be three characters followed by one "=" padding character. Because it is used only for padding at the end of the data, the occurrence of any "=" characters may be taken as evidence that the end of the data has been reached (without truncation in transit). No Freed & Borenstein Standards Track [Page 25] RFC 2045 Internet Message Bodies November 1996 such assurance is possible, however, when the number of octets transmitted was a multiple of three and no "=" characters are present. Any characters outside of the base64 alphabet are to be ignored in base64-encoded data. Care must be taken to use the proper octets for line breaks if base64 encoding is applied directly to text material that has not been converted to canonical form. In particular, text line breaks must be converted into CRLF sequences prior to base64 encoding. The important thing to note is that this may be done directly by the encoder rather than in a prior canonicalization step in some implementations. NOTE: There is no need to worry about quoting potential boundary delimiters within base64-encoded bodies within multipart entities because no hyphen characters are used in the base64 encoding. 7. Content-ID Header Field In constructing a high-level user agent, it may be desirable to allow one body to make reference to another. Accordingly, bodies may be labelled using the "Content-ID" header field, which is syntactically identical to the "Message-ID" header field: id := "Content-ID" ":" msg-id Like the Message-ID values, Content-ID values must be generated to be world-unique. The Content-ID value may be used for uniquely identifying MIME entities in several contexts, particularly for caching data referenced by the message/external-body mechanism. Although the Content-ID header is generally optional, its use is MANDATORY in implementations which generate data of the optional MIME media type "message/external-body". That is, each message/external-body entity must have a Content-ID field to permit caching of such data. It is also worth noting that the Content-ID value has special semantics in the case of the multipart/alternative media type. This is explained in the section of RFC 2046 dealing with multipart/alternative. Freed & Borenstein Standards Track [Page 26] RFC 2045 Internet Message Bodies November 1996 8. Content-Description Header Field The ability to associate some descriptive information with a given body is often desirable. For example, it may be useful to mark an "image" body as "a picture of the Space Shuttle Endeavor." Such text may be placed in the Content-Description header field. This header field is always optional. description := "Content-Description" ":" *text The description is presumed to be given in the US-ASCII character set, although the mechanism specified in RFC 2047 may be used for non-US-ASCII Content-Description values. 9. Additional MIME Header Fields Future documents may elect to define additional MIME header fields for various purposes. Any new header field that further describes the content of a message should begin with the string "Content-" to allow such fields which appear in a message header to be distinguished from ordinary RFC 822 message header fields. MIME-extension-field := 10. Summary Using the MIME-Version, Content-Type, and Content-Transfer-Encoding header fields, it is possible to include, in a standardized way, arbitrary types of data with RFC 822 conformant mail messages. No restrictions imposed by either RFC 821 or RFC 822 are violated, and care has been taken to avoid problems caused by additional restrictions imposed by the characteristics of some Internet mail transport mechanisms (see RFC 2049). The next document in this set, RFC 2046, specifies the initial set of media types that can be labelled and transported using these headers. 11. Security Considerations Security issues are discussed in the second document in this set, RFC 2046. Freed & Borenstein Standards Track [Page 27] RFC 2045 Internet Message Bodies November 1996 12. Authors' Addresses For more information, the authors of this document are best contacted via Internet mail: Ned Freed Innosoft International, Inc. 1050 East Garvey Avenue South West Covina, CA 91790 USA Phone: +1 818 919 3600 Fax: +1 818 919 3614 EMail: ned@innosoft.com Nathaniel S. Borenstein First Virtual Holdings 25 Washington Avenue Morristown, NJ 07960 USA Phone: +1 201 540 8967 Fax: +1 201 993 3032 EMail: nsb@nsb.fv.com MIME is a result of the work of the Internet Engineering Task Force Working Group on RFC 822 Extensions. The chairman of that group, Greg Vaudreuil, may be reached at: Gregory M. Vaudreuil Octel Network Services 17080 Dallas Parkway Dallas, TX 75248-1905 USA EMail: Greg.Vaudreuil@Octel.Com Freed & Borenstein Standards Track [Page 28] RFC 2045 Internet Message Bodies November 1996 Appendix A -- Collected Grammar This appendix contains the complete BNF grammar for all the syntax specified by this document. By itself, however, this grammar is incomplete. It refers by name to several syntax rules that are defined by RFC 822. Rather than reproduce those definitions here, and risk unintentional differences between the two, this document simply refers the reader to RFC 822 for the remaining definitions. Wherever a term is undefined, it refers to the RFC 822 definition. attribute := token ; Matching of attributes ; is ALWAYS case-insensitive. composite-type := "message" / "multipart" / extension-token content := "Content-Type" ":" type "/" subtype *(";" parameter) ; Matching of media type and subtype ; is ALWAYS case-insensitive. description := "Content-Description" ":" *text discrete-type := "text" / "image" / "audio" / "video" / "application" / extension-token encoding := "Content-Transfer-Encoding" ":" mechanism entity-headers := [ content CRLF ] [ encoding CRLF ] [ id CRLF ] [ description CRLF ] *( MIME-extension-field CRLF ) extension-token := ietf-token / x-token hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F") ; Octet must be used for characters > 127, =, ; SPACEs or TABs at the ends of lines, and is ; recommended for any character not listed in ; RFC 2049 as "mail-safe". iana-token := Freed & Borenstein Standards Track [Page 29] RFC 2045 Internet Message Bodies November 1996 ietf-token := id := "Content-ID" ":" msg-id mechanism := "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" / ietf-token / x-token MIME-extension-field := MIME-message-headers := entity-headers fields version CRLF ; The ordering of the header ; fields implied by this BNF ; definition should be ignored. MIME-part-headers := entity-headers [fields] ; Any field not beginning with ; "content-" can have no defined ; meaning and may be ignored. ; The ordering of the header ; fields implied by this BNF ; definition should be ignored. parameter := attribute "=" value ptext := hex-octet / safe-char qp-line := *(qp-segment transport-padding CRLF) qp-part transport-padding qp-part := qp-section ; Maximum length of 76 characters qp-section := [*(ptext / SPACE / TAB) ptext] qp-segment := qp-section *(SPACE / TAB) "=" ; Maximum length of 76 characters quoted-printable := qp-line *(CRLF qp-line) Freed & Borenstein Standards Track [Page 30] RFC 2045 Internet Message Bodies November 1996 safe-char := ; Characters not listed as "mail-safe" in ; RFC 2049 are also not recommended. subtype := extension-token / iana-token token := 1* transport-padding := *LWSP-char ; Composers MUST NOT generate ; non-zero length transport ; padding, but receivers MUST ; be able to handle padding ; added by message transports. tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> "/" / "[" / "]" / "?" / "=" ; Must be in quoted-string, ; to use within parameter values type := discrete-type / composite-type value := token / quoted-string version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT x-token := Freed & Borenstein Standards Track [Page 31] mail-2.5.4/reference/rfc2046 Multipurpose Internet Mail Extensions (2).txt000066400000000000000000003234411214434061600257310ustar00rootroot00000000000000 Network Working Group N. Freed Request for Comments: 2046 Innosoft Obsoletes: 1521, 1522, 1590 N. Borenstein Category: Standards Track First Virtual November 1996 Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types 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. Abstract STD 11, RFC 822 defines a message representation protocol specifying considerable detail about US-ASCII message headers, but which leaves the message content, or message body, as flat US-ASCII text. This set of documents, collectively called the Multipurpose Internet Mail Extensions, or MIME, redefines the format of messages to allow for (1) textual message bodies in character sets other than US-ASCII, (2) an extensible set of different formats for non-textual message bodies, (3) multi-part message bodies, and (4) textual header information in character sets other than US-ASCII. These documents are based on earlier work documented in RFC 934, STD 11, and RFC 1049, but extends and revises them. Because RFC 822 said so little about message bodies, these documents are largely orthogonal to (rather than a revision of) RFC 822. The initial document in this set, RFC 2045, specifies the various headers used to describe the structure of MIME messages. This second document defines the general structure of the MIME media typing system and defines an initial set of media types. The third document, RFC 2047, describes extensions to RFC 822 to allow non-US-ASCII text Freed & Borenstein Standards Track [Page 1] RFC 2046 Media Types November 1996 data in Internet mail header fields. The fourth document, RFC 2048, specifies various IANA registration procedures for MIME-related facilities. The fifth and final document, RFC 2049, describes MIME conformance criteria as well as providing some illustrative examples of MIME message formats, acknowledgements, and the bibliography. These documents are revisions of RFCs 1521 and 1522, which themselves were revisions of RFCs 1341 and 1342. An appendix in RFC 2049 describes differences and changes from previous versions. Table of Contents 1. Introduction ......................................... 3 2. Definition of a Top-Level Media Type ................. 4 3. Overview Of The Initial Top-Level Media Types ........ 4 4. Discrete Media Type Values ........................... 6 4.1 Text Media Type ..................................... 6 4.1.1 Representation of Line Breaks ..................... 7 4.1.2 Charset Parameter ................................. 7 4.1.3 Plain Subtype ..................................... 11 4.1.4 Unrecognized Subtypes ............................. 11 4.2 Image Media Type .................................... 11 4.3 Audio Media Type .................................... 11 4.4 Video Media Type .................................... 12 4.5 Application Media Type .............................. 12 4.5.1 Octet-Stream Subtype .............................. 13 4.5.2 PostScript Subtype ................................ 14 4.5.3 Other Application Subtypes ........................ 17 5. Composite Media Type Values .......................... 17 5.1 Multipart Media Type ................................ 17 5.1.1 Common Syntax ..................................... 19 5.1.2 Handling Nested Messages and Multiparts ........... 24 5.1.3 Mixed Subtype ..................................... 24 5.1.4 Alternative Subtype ............................... 24 5.1.5 Digest Subtype .................................... 26 5.1.6 Parallel Subtype .................................. 27 5.1.7 Other Multipart Subtypes .......................... 28 5.2 Message Media Type .................................. 28 5.2.1 RFC822 Subtype .................................... 28 5.2.2 Partial Subtype ................................... 29 5.2.2.1 Message Fragmentation and Reassembly ............ 30 5.2.2.2 Fragmentation and Reassembly Example ............ 31 5.2.3 External-Body Subtype ............................. 33 5.2.4 Other Message Subtypes ............................ 40 6. Experimental Media Type Values ....................... 40 7. Summary .............................................. 41 8. Security Considerations .............................. 41 9. Authors' Addresses ................................... 42 Freed & Borenstein Standards Track [Page 2] RFC 2046 Media Types November 1996 A. Collected Grammar .................................... 43 1. Introduction The first document in this set, RFC 2045, defines a number of header fields, including Content-Type. The Content-Type field is used to specify the nature of the data in the body of a MIME entity, by giving media type and subtype identifiers, and by providing auxiliary information that may be required for certain media types. After the type and subtype names, the remainder of the header field is simply a set of parameters, specified in an attribute/value notation. The ordering of parameters is not significant. In general, the top-level media type is used to declare the general type of data, while the subtype specifies a specific format for that type of data. Thus, a media type of "image/xyz" is enough to tell a user agent that the data is an image, even if the user agent has no knowledge of the specific image format "xyz". Such information can be used, for example, to decide whether or not to show a user the raw data from an unrecognized subtype -- such an action might be reasonable for unrecognized subtypes of "text", but not for unrecognized subtypes of "image" or "audio". For this reason, registered subtypes of "text", "image", "audio", and "video" should not contain embedded information that is really of a different type. Such compound formats should be represented using the "multipart" or "application" types. Parameters are modifiers of the media subtype, and as such do not fundamentally affect the nature of the content. The set of meaningful parameters depends on the media type and subtype. Most parameters are associated with a single specific subtype. However, a given top-level media type may define parameters which are applicable to any subtype of that type. Parameters may be required by their defining media type or subtype or they may be optional. MIME implementations must also ignore any parameters whose names they do not recognize. MIME's Content-Type header field and media type mechanism has been carefully designed to be extensible, and it is expected that the set of media type/subtype pairs and their associated parameters will grow significantly over time. Several other MIME facilities, such as transfer encodings and "message/external-body" access types, are likely to have new values defined over time. In order to ensure that the set of such values is developed in an orderly, well-specified, and public manner, MIME sets up a registration process which uses the Internet Assigned Numbers Authority (IANA) as a central registry for MIME's various areas of extensibility. The registration process for these areas is described in a companion document, RFC 2048. Freed & Borenstein Standards Track [Page 3] RFC 2046 Media Types November 1996 The initial seven standard top-level media type are defined and described in the remainder of this document. 2. Definition of a Top-Level Media Type The definition of a top-level media type consists of: (1) a name and a description of the type, including criteria for whether a particular type would qualify under that type, (2) the names and definitions of parameters, if any, which are defined for all subtypes of that type (including whether such parameters are required or optional), (3) how a user agent and/or gateway should handle unknown subtypes of this type, (4) general considerations on gatewaying entities of this top-level type, if any, and (5) any restrictions on content-transfer-encodings for entities of this top-level type. 3. Overview Of The Initial Top-Level Media Types The five discrete top-level media types are: (1) text -- textual information. The subtype "plain" in particular indicates plain text containing no formatting commands or directives of any sort. Plain text is intended to be displayed "as-is". No special software is required to get the full meaning of the text, aside from support for the indicated character set. Other subtypes are to be used for enriched text in forms where application software may enhance the appearance of the text, but such software must not be required in order to get the general idea of the content. Possible subtypes of "text" thus include any word processor format that can be read without resorting to software that understands the format. In particular, formats that employ embeddded binary formatting information are not considered directly readable. A very simple and portable subtype, "richtext", was defined in RFC 1341, with a further revision in RFC 1896 under the name "enriched". Freed & Borenstein Standards Track [Page 4] RFC 2046 Media Types November 1996 (2) image -- image data. "Image" requires a display device (such as a graphical display, a graphics printer, or a FAX machine) to view the information. An initial subtype is defined for the widely-used image format JPEG. . subtypes are defined for two widely-used image formats, jpeg and gif. (3) audio -- audio data. "Audio" requires an audio output device (such as a speaker or a telephone) to "display" the contents. An initial subtype "basic" is defined in this document. (4) video -- video data. "Video" requires the capability to display moving images, typically including specialized hardware and software. An initial subtype "mpeg" is defined in this document. (5) application -- some other kind of data, typically either uninterpreted binary data or information to be processed by an application. The subtype "octet- stream" is to be used in the case of uninterpreted binary data, in which case the simplest recommended action is to offer to write the information into a file for the user. The "PostScript" subtype is also defined for the transport of PostScript material. Other expected uses for "application" include spreadsheets, data for mail-based scheduling systems, and languages for "active" (computational) messaging, and word processing formats that are not directly readable. Note that security considerations may exist for some types of application data, most notably "application/PostScript" and any form of active messaging. These issues are discussed later in this document. The two composite top-level media types are: (1) multipart -- data consisting of multiple entities of independent data types. Four subtypes are initially defined, including the basic "mixed" subtype specifying a generic mixed set of parts, "alternative" for representing the same data in multiple formats, "parallel" for parts intended to be viewed simultaneously, and "digest" for multipart entities in which each part has a default type of "message/rfc822". Freed & Borenstein Standards Track [Page 5] RFC 2046 Media Types November 1996 (2) message -- an encapsulated message. A body of media type "message" is itself all or a portion of some kind of message object. Such objects may or may not in turn contain other entities. The "rfc822" subtype is used when the encapsulated content is itself an RFC 822 message. The "partial" subtype is defined for partial RFC 822 messages, to permit the fragmented transmission of bodies that are thought to be too large to be passed through transport facilities in one piece. Another subtype, "external-body", is defined for specifying large bodies by reference to an external data source. It should be noted that the list of media type values given here may be augmented in time, via the mechanisms described above, and that the set of subtypes is expected to grow substantially. 4. Discrete Media Type Values Five of the seven initial media type values refer to discrete bodies. The content of these types must be handled by non-MIME mechanisms; they are opaque to MIME processors. 4.1. Text Media Type The "text" media type is intended for sending material which is principally textual in form. A "charset" parameter may be used to indicate the character set of the body text for "text" subtypes, notably including the subtype "text/plain", which is a generic subtype for plain text. Plain text does not provide for or allow formatting commands, font attribute specifications, processing instructions, interpretation directives, or content markup. Plain text is seen simply as a linear sequence of characters, possibly interrupted by line breaks or page breaks. Plain text may allow the stacking of several characters in the same position in the text. Plain text in scripts like Arabic and Hebrew may also include facilitites that allow the arbitrary mixing of text segments with opposite writing directions. Beyond plain text, there are many formats for representing what might be known as "rich text". An interesting characteristic of many such representations is that they are to some extent readable even without the software that interprets them. It is useful, then, to distinguish them, at the highest level, from such unreadable data as images, audio, or text represented in an unreadable form. In the absence of appropriate interpretation software, it is reasonable to show subtypes of "text" to the user, while it is not reasonable to do so with most nontextual data. Such formatted textual data should be represented using subtypes of "text". Freed & Borenstein Standards Track [Page 6] RFC 2046 Media Types November 1996 4.1.1. Representation of Line Breaks The canonical form of any MIME "text" subtype MUST always represent a line break as a CRLF sequence. Similarly, any occurrence of CRLF in MIME "text" MUST represent a line break. Use of CR and LF outside of line break sequences is also forbidden. This rule applies regardless of format or character set or sets involved. NOTE: The proper interpretation of line breaks when a body is displayed depends on the media type. In particular, while it is appropriate to treat a line break as a transition to a new line when displaying a "text/plain" body, this treatment is actually incorrect for other subtypes of "text" like "text/enriched" [RFC-1896]. Similarly, whether or not line breaks should be added during display operations is also a function of the media type. It should not be necessary to add any line breaks to display "text/plain" correctly, whereas proper display of "text/enriched" requires the appropriate addition of line breaks. NOTE: Some protocols defines a maximum line length. E.g. SMTP [RFC- 821] allows a maximum of 998 octets before the next CRLF sequence. To be transported by such protocols, data which includes too long segments without CRLF sequences must be encoded with a suitable content-transfer-encoding. 4.1.2. Charset Parameter A critical parameter that may be specified in the Content-Type field for "text/plain" data is the character set. This is specified with a "charset" parameter, as in: Content-type: text/plain; charset=iso-8859-1 Unlike some other parameter values, the values of the charset parameter are NOT case sensitive. The default character set, which must be assumed in the absence of a charset parameter, is US-ASCII. The specification for any future subtypes of "text" must specify whether or not they will also utilize a "charset" parameter, and may possibly restrict its values as well. For other subtypes of "text" than "text/plain", the semantics of the "charset" parameter should be defined to be identical to those specified here for "text/plain", i.e., the body consists entirely of characters in the given charset. In particular, definers of future "text" subtypes should pay close attention to the implications of multioctet character sets for their subtype definitions. Freed & Borenstein Standards Track [Page 7] RFC 2046 Media Types November 1996 The charset parameter for subtypes of "text" gives a name of a character set, as "character set" is defined in RFC 2045. The rules regarding line breaks detailed in the previous section must also be observed -- a character set whose definition does not conform to these rules cannot be used in a MIME "text" subtype. An initial list of predefined character set names can be found at the end of this section. Additional character sets may be registered with IANA. Other media types than subtypes of "text" might choose to employ the charset parameter as defined here, but with the CRLF/line break restriction removed. Therefore, all character sets that conform to the general definition of "character set" in RFC 2045 can be registered for MIME use. Note that if the specified character set includes 8-bit characters and such characters are used in the body, a Content-Transfer-Encoding header field and a corresponding encoding on the data are required in order to transmit the body via some mail transfer protocols, such as SMTP [RFC-821]. The default character set, US-ASCII, has been the subject of some confusion and ambiguity in the past. Not only were there some ambiguities in the definition, there have been wide variations in practice. In order to eliminate such ambiguity and variations in the future, it is strongly recommended that new user agents explicitly specify a character set as a media type parameter in the Content-Type header field. "US-ASCII" does not indicate an arbitrary 7-bit character set, but specifies that all octets in the body must be interpreted as characters according to the US-ASCII character set. National and application-oriented versions of ISO 646 [ISO-646] are usually NOT identical to US-ASCII, and in that case their use in Internet mail is explicitly discouraged. The omission of the ISO 646 character set from this document is deliberate in this regard. The character set name of "US-ASCII" explicitly refers to the character set defined in ANSI X3.4-1986 [US- ASCII]. The new international reference version (IRV) of the 1991 edition of ISO 646 is identical to US-ASCII. The character set name "ASCII" is reserved and must not be used for any purpose. NOTE: RFC 821 explicitly specifies "ASCII", and references an earlier version of the American Standard. Insofar as one of the purposes of specifying a media type and character set is to permit the receiver to unambiguously determine how the sender intended the coded message to be interpreted, assuming anything other than "strict ASCII" as the default would risk unintentional and incompatible changes to the semantics of messages now being transmitted. This also implies that Freed & Borenstein Standards Track [Page 8] RFC 2046 Media Types November 1996 messages containing characters coded according to other versions of ISO 646 than US-ASCII and the 1991 IRV, or using code-switching procedures (e.g., those of ISO 2022), as well as 8bit or multiple octet character encodings MUST use an appropriate character set specification to be consistent with MIME. The complete US-ASCII character set is listed in ANSI X3.4- 1986. Note that the control characters including DEL (0-31, 127) have no defined meaning in apart from the combination CRLF (US-ASCII values 13 and 10) indicating a new line. Two of the characters have de facto meanings in wide use: FF (12) often means "start subsequent text on the beginning of a new page"; and TAB or HT (9) often (though not always) means "move the cursor to the next available column after the current position where the column number is a multiple of 8 (counting the first column as column 0)." Aside from these conventions, any use of the control characters or DEL in a body must either occur (1) because a subtype of text other than "plain" specifically assigns some additional meaning, or (2) within the context of a private agreement between the sender and recipient. Such private agreements are discouraged and should be replaced by the other capabilities of this document. NOTE: An enormous proliferation of character sets exist beyond US- ASCII. A large number of partially or totally overlapping character sets is NOT a good thing. A SINGLE character set that can be used universally for representing all of the world's languages in Internet mail would be preferrable. Unfortunately, existing practice in several communities seems to point to the continued use of multiple character sets in the near future. A small number of standard character sets are, therefore, defined for Internet use in this document. The defined charset values are: (1) US-ASCII -- as defined in ANSI X3.4-1986 [US-ASCII]. (2) ISO-8859-X -- where "X" is to be replaced, as necessary, for the parts of ISO-8859 [ISO-8859]. Note that the ISO 646 character sets have deliberately been omitted in favor of their 8859 replacements, which are the designated character sets for Internet mail. As of the publication of this document, the legitimate values for "X" are the digits 1 through 10. Freed & Borenstein Standards Track [Page 9] RFC 2046 Media Types November 1996 Characters in the range 128-159 has no assigned meaning in ISO-8859- X. Characters with values below 128 in ISO-8859-X have the same assigned meaning as they do in US-ASCII. Part 6 of ISO 8859 (Latin/Arabic alphabet) and part 8 (Latin/Hebrew alphabet) includes both characters for which the normal writing direction is right to left and characters for which it is left to right, but do not define a canonical ordering method for representing bi-directional text. The charset values "ISO-8859-6" and "ISO-8859- 8", however, specify that the visual method is used [RFC-1556]. All of these character sets are used as pure 7bit or 8bit sets without any shift or escape functions. The meaning of shift and escape sequences in these character sets is not defined. The character sets specified above are the ones that were relatively uncontroversial during the drafting of MIME. This document does not endorse the use of any particular character set other than US-ASCII, and recognizes that the future evolution of world character sets remains unclear. Note that the character set used, if anything other than US- ASCII, must always be explicitly specified in the Content-Type field. No character set name other than those defined above may be used in Internet mail without the publication of a formal specification and its registration with IANA, or by private agreement, in which case the character set name must begin with "X-". Implementors are discouraged from defining new character sets unless absolutely necessary. The "charset" parameter has been defined primarily for the purpose of textual data, and is described in this section for that reason. However, it is conceivable that non-textual data might also wish to specify a charset value for some purpose, in which case the same syntax and values should be used. In general, composition software should always use the "lowest common denominator" character set possible. For example, if a body contains only US-ASCII characters, it SHOULD be marked as being in the US- ASCII character set, not ISO-8859-1, which, like all the ISO-8859 family of character sets, is a superset of US-ASCII. More generally, if a widely-used character set is a subset of another character set, and a body contains only characters in the widely-used subset, it should be labelled as being in that subset. This will increase the chances that the recipient will be able to view the resulting entity correctly. Freed & Borenstein Standards Track [Page 10] RFC 2046 Media Types November 1996 4.1.3. Plain Subtype The simplest and most important subtype of "text" is "plain". This indicates plain text that does not contain any formatting commands or directives. Plain text is intended to be displayed "as-is", that is, no interpretation of embedded formatting commands, font attribute specifications, processing instructions, interpretation directives, or content markup should be necessary for proper display. The default media type of "text/plain; charset=us-ascii" for Internet mail describes existing Internet practice. That is, it is the type of body defined by RFC 822. No other "text" subtype is defined by this document. 4.1.4. Unrecognized Subtypes Unrecognized subtypes of "text" should be treated as subtype "plain" as long as the MIME implementation knows how to handle the charset. Unrecognized subtypes which also specify an unrecognized charset should be treated as "application/octet- stream". 4.2. Image Media Type A media type of "image" indicates that the body contains an image. The subtype names the specific image format. These names are not case sensitive. An initial subtype is "jpeg" for the JPEG format using JFIF encoding [JPEG]. The list of "image" subtypes given here is neither exclusive nor exhaustive, and is expected to grow as more types are registered with IANA, as described in RFC 2048. Unrecognized subtypes of "image" should at a miniumum be treated as "application/octet-stream". Implementations may optionally elect to pass subtypes of "image" that they do not specifically recognize to a secure and robust general-purpose image viewing application, if such an application is available. NOTE: Using of a generic-purpose image viewing application this way inherits the security problems of the most dangerous type supported by the application. 4.3. Audio Media Type A media type of "audio" indicates that the body contains audio data. Although there is not yet a consensus on an "ideal" audio format for use with computers, there is a pressing need for a format capable of providing interoperable behavior. Freed & Borenstein Standards Track [Page 11] RFC 2046 Media Types November 1996 The initial subtype of "basic" is specified to meet this requirement by providing an absolutely minimal lowest common denominator audio format. It is expected that richer formats for higher quality and/or lower bandwidth audio will be defined by a later document. The content of the "audio/basic" subtype is single channel audio encoded using 8bit ISDN mu-law [PCM] at a sample rate of 8000 Hz. Unrecognized subtypes of "audio" should at a miniumum be treated as "application/octet-stream". Implementations may optionally elect to pass subtypes of "audio" that they do not specifically recognize to a robust general-purpose audio playing application, if such an application is available. 4.4. Video Media Type A media type of "video" indicates that the body contains a time- varying-picture image, possibly with color and coordinated sound. The term 'video' is used in its most generic sense, rather than with reference to any particular technology or format, and is not meant to preclude subtypes such as animated drawings encoded compactly. The subtype "mpeg" refers to video coded according to the MPEG standard [MPEG]. Note that although in general this document strongly discourages the mixing of multiple media in a single body, it is recognized that many so-called video formats include a representation for synchronized audio, and this is explicitly permitted for subtypes of "video". Unrecognized subtypes of "video" should at a minumum be treated as "application/octet-stream". Implementations may optionally elect to pass subtypes of "video" that they do not specifically recognize to a robust general-purpose video display application, if such an application is available. 4.5. Application Media Type The "application" media type is to be used for discrete data which do not fit in any of the other categories, and particularly for data to be processed by some type of application program. This is information which must be processed by an application before it is viewable or usable by a user. Expected uses for the "application" media type include file transfer, spreadsheets, data for mail-based scheduling systems, and languages for "active" (computational) material. (The latter, in particular, can pose security problems which must be understood by implementors, and are considered in detail in the discussion of the "application/PostScript" media type.) Freed & Borenstein Standards Track [Page 12] RFC 2046 Media Types November 1996 For example, a meeting scheduler might define a standard representation for information about proposed meeting dates. An intelligent user agent would use this information to conduct a dialog with the user, and might then send additional material based on that dialog. More generally, there have been several "active" messaging languages developed in which programs in a suitably specialized language are transported to a remote location and automatically run in the recipient's environment. Such applications may be defined as subtypes of the "application" media type. This document defines two subtypes: octet-stream, and PostScript. The subtype of "application" will often be either the name or include part of the name of the application for which the data are intended. This does not mean, however, that any application program name may be used freely as a subtype of "application". 4.5.1. Octet-Stream Subtype The "octet-stream" subtype is used to indicate that a body contains arbitrary binary data. The set of currently defined parameters is: (1) TYPE -- the general type or category of binary data. This is intended as information for the human recipient rather than for any automatic processing. (2) PADDING -- the number of bits of padding that were appended to the bit-stream comprising the actual contents to produce the enclosed 8bit byte-oriented data. This is useful for enclosing a bit-stream in a body when the total number of bits is not a multiple of 8. Both of these parameters are optional. An additional parameter, "CONVERSIONS", was defined in RFC 1341 but has since been removed. RFC 1341 also defined the use of a "NAME" parameter which gave a suggested file name to be used if the data were to be written to a file. This has been deprecated in anticipation of a separate Content-Disposition header field, to be defined in a subsequent RFC. The recommended action for an implementation that receives an "application/octet-stream" entity is to simply offer to put the data in a file, with any Content-Transfer-Encoding undone, or perhaps to use it as input to a user-specified process. Freed & Borenstein Standards Track [Page 13] RFC 2046 Media Types November 1996 To reduce the danger of transmitting rogue programs, it is strongly recommended that implementations NOT implement a path-search mechanism whereby an arbitrary program named in the Content-Type parameter (e.g., an "interpreter=" parameter) is found and executed using the message body as input. 4.5.2. PostScript Subtype A media type of "application/postscript" indicates a PostScript program. Currently two variants of the PostScript language are allowed; the original level 1 variant is described in [POSTSCRIPT] and the more recent level 2 variant is described in [POSTSCRIPT2]. PostScript is a registered trademark of Adobe Systems, Inc. Use of the MIME media type "application/postscript" implies recognition of that trademark and all the rights it entails. The PostScript language definition provides facilities for internal labelling of the specific language features a given program uses. This labelling, called the PostScript document structuring conventions, or DSC, is very general and provides substantially more information than just the language level. The use of document structuring conventions, while not required, is strongly recommended as an aid to interoperability. Documents which lack proper structuring conventions cannot be tested to see whether or not they will work in a given environment. As such, some systems may assume the worst and refuse to process unstructured documents. The execution of general-purpose PostScript interpreters entails serious security risks, and implementors are discouraged from simply sending PostScript bodies to "off- the-shelf" interpreters. While it is usually safe to send PostScript to a printer, where the potential for harm is greatly constrained by typical printer environments, implementors should consider all of the following before they add interactive display of PostScript bodies to their MIME readers. The remainder of this section outlines some, though probably not all, of the possible problems with the transport of PostScript entities. (1) Dangerous operations in the PostScript language include, but may not be limited to, the PostScript operators "deletefile", "renamefile", "filenameforall", and "file". "File" is only dangerous when applied to something other than standard input or output. Implementations may also define additional nonstandard file operators; these may also pose a threat to security. "Filenameforall", the wildcard file search operator, may appear at first glance to be harmless. Freed & Borenstein Standards Track [Page 14] RFC 2046 Media Types November 1996 Note, however, that this operator has the potential to reveal information about what files the recipient has access to, and this information may itself be sensitive. Message senders should avoid the use of potentially dangerous file operators, since these operators are quite likely to be unavailable in secure PostScript implementations. Message receiving and displaying software should either completely disable all potentially dangerous file operators or take special care not to delegate any special authority to their operation. These operators should be viewed as being done by an outside agency when interpreting PostScript documents. Such disabling and/or checking should be done completely outside of the reach of the PostScript language itself; care should be taken to insure that no method exists for re-enabling full- function versions of these operators. (2) The PostScript language provides facilities for exiting the normal interpreter, or server, loop. Changes made in this "outer" environment are customarily retained across documents, and may in some cases be retained semipermanently in nonvolatile memory. The operators associated with exiting the interpreter loop have the potential to interfere with subsequent document processing. As such, their unrestrained use constitutes a threat of service denial. PostScript operators that exit the interpreter loop include, but may not be limited to, the exitserver and startjob operators. Message sending software should not generate PostScript that depends on exiting the interpreter loop to operate, since the ability to exit will probably be unavailable in secure PostScript implementations. Message receiving and displaying software should completely disable the ability to make retained changes to the PostScript environment by eliminating or disabling the "startjob" and "exitserver" operations. If these operations cannot be eliminated or completely disabled the password associated with them should at least be set to a hard- to-guess value. (3) PostScript provides operators for setting system-wide and device-specific parameters. These parameter settings may be retained across jobs and may potentially pose a threat to the correct operation of the interpreter. The PostScript operators that set system and device parameters include, but may not be Freed & Borenstein Standards Track [Page 15] RFC 2046 Media Types November 1996 limited to, the "setsystemparams" and "setdevparams" operators. Message sending software should not generate PostScript that depends on the setting of system or device parameters to operate correctly. The ability to set these parameters will probably be unavailable in secure PostScript implementations. Message receiving and displaying software should disable the ability to change system and device parameters. If these operators cannot be completely disabled the password associated with them should at least be set to a hard-to-guess value. (4) Some PostScript implementations provide nonstandard facilities for the direct loading and execution of machine code. Such facilities are quite obviously open to substantial abuse. Message sending software should not make use of such features. Besides being totally hardware-specific, they are also likely to be unavailable in secure implementations of PostScript. Message receiving and displaying software should not allow such operators to be used if they exist. (5) PostScript is an extensible language, and many, if not most, implementations of it provide a number of their own extensions. This document does not deal with such extensions explicitly since they constitute an unknown factor. Message sending software should not make use of nonstandard extensions; they are likely to be missing from some implementations. Message receiving and displaying software should make sure that any nonstandard PostScript operators are secure and don't present any kind of threat. (6) It is possible to write PostScript that consumes huge amounts of various system resources. It is also possible to write PostScript programs that loop indefinitely. Both types of programs have the potential to cause damage if sent to unsuspecting recipients. Message-sending software should avoid the construction and dissemination of such programs, which is antisocial. Message receiving and displaying software should provide appropriate mechanisms to abort processing after a reasonable amount of time has elapsed. In addition, PostScript interpreters should be limited to the consumption of only a reasonable amount of any given system resource. Freed & Borenstein Standards Track [Page 16] RFC 2046 Media Types November 1996 (7) It is possible to include raw binary information inside PostScript in various forms. This is not recommended for use in Internet mail, both because it is not supported by all PostScript interpreters and because it significantly complicates the use of a MIME Content- Transfer-Encoding. (Without such binary, PostScript may typically be viewed as line-oriented data. The treatment of CRLF sequences becomes extremely problematic if binary and line-oriented data are mixed in a single Postscript data stream.) (8) Finally, bugs may exist in some PostScript interpreters which could possibly be exploited to gain unauthorized access to a recipient's system. Apart from noting this possibility, there is no specific action to take to prevent this, apart from the timely correction of such bugs if any are found. 4.5.3. Other Application Subtypes It is expected that many other subtypes of "application" will be defined in the future. MIME implementations must at a minimum treat any unrecognized subtypes as being equivalent to "application/octet- stream". 5. Composite Media Type Values The remaining two of the seven initial Content-Type values refer to composite entities. Composite entities are handled using MIME mechanisms -- a MIME processor typically handles the body directly. 5.1. Multipart Media Type In the case of multipart entities, in which one or more different sets of data are combined in a single body, a "multipart" media type field must appear in the entity's header. The body must then contain one or more body parts, each preceded by a boundary delimiter line, and the last one followed by a closing boundary delimiter line. After its boundary delimiter line, each body part then consists of a header area, a blank line, and a body area. Thus a body part is similar to an RFC 822 message in syntax, but different in meaning. A body part is an entity and hence is NOT to be interpreted as actually being an RFC 822 message. To begin with, NO header fields are actually required in body parts. A body part that starts with a blank line, therefore, is allowed and is a body part for which all default values are to be assumed. In such a case, the absence of a Content-Type header usually indicates that the corresponding body has Freed & Borenstein Standards Track [Page 17] RFC 2046 Media Types November 1996 a content-type of "text/plain; charset=US-ASCII". The only header fields that have defined meaning for body parts are those the names of which begin with "Content-". All other header fields may be ignored in body parts. Although they should generally be retained if at all possible, they may be discarded by gateways if necessary. Such other fields are permitted to appear in body parts but must not be depended on. "X-" fields may be created for experimental or private purposes, with the recognition that the information they contain may be lost at some gateways. NOTE: The distinction between an RFC 822 message and a body part is subtle, but important. A gateway between Internet and X.400 mail, for example, must be able to tell the difference between a body part that contains an image and a body part that contains an encapsulated message, the body of which is a JPEG image. In order to represent the latter, the body part must have "Content-Type: message/rfc822", and its body (after the blank line) must be the encapsulated message, with its own "Content-Type: image/jpeg" header field. The use of similar syntax facilitates the conversion of messages to body parts, and vice versa, but the distinction between the two must be understood by implementors. (For the special case in which parts actually are messages, a "digest" subtype is also defined.) As stated previously, each body part is preceded by a boundary delimiter line that contains the boundary delimiter. The boundary delimiter MUST NOT appear inside any of the encapsulated parts, on a line by itself or as the prefix of any line. This implies that it is crucial that the composing agent be able to choose and specify a unique boundary parameter value that does not contain the boundary parameter value of an enclosing multipart as a prefix. All present and future subtypes of the "multipart" type must use an identical syntax. Subtypes may differ in their semantics, and may impose additional restrictions on syntax, but must conform to the required syntax for the "multipart" type. This requirement ensures that all conformant user agents will at least be able to recognize and separate the parts of any multipart entity, even those of an unrecognized subtype. As stated in the definition of the Content-Transfer-Encoding field [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is permitted for entities of type "multipart". The "multipart" boundary delimiters and header fields are always represented as 7bit US-ASCII in any case (though the header fields may encode non-US-ASCII header text as per RFC 2047) and data within the body parts can be encoded on a part-by-part basis, with Content-Transfer-Encoding fields for each appropriate body part. Freed & Borenstein Standards Track [Page 18] RFC 2046 Media Types November 1996 5.1.1. Common Syntax This section defines a common syntax for subtypes of "multipart". All subtypes of "multipart" must use this syntax. A simple example of a multipart message also appears in this section. An example of a more complex multipart message is given in RFC 2049. The Content-Type field for multipart entities requires one parameter, "boundary". The boundary delimiter line is then defined as a line consisting entirely of two hyphen characters ("-", decimal value 45) followed by the boundary parameter value from the Content-Type header field, optional linear whitespace, and a terminating CRLF. NOTE: The hyphens are for rough compatibility with the earlier RFC 934 method of message encapsulation, and for ease of searching for the boundaries in some implementations. However, it should be noted that multipart messages are NOT completely compatible with RFC 934 encapsulations; in particular, they do not obey RFC 934 quoting conventions for embedded lines that begin with hyphens. This mechanism was chosen over the RFC 934 mechanism because the latter causes lines to grow with each level of quoting. The combination of this growth with the fact that SMTP implementations sometimes wrap long lines made the RFC 934 mechanism unsuitable for use in the event that deeply-nested multipart structuring is ever desired. WARNING TO IMPLEMENTORS: The grammar for parameters on the Content- type field is such that it is often necessary to enclose the boundary parameter values in quotes on the Content-type line. This is not always necessary, but never hurts. Implementors should be sure to study the grammar carefully in order to avoid producing invalid Content-type fields. Thus, a typical "multipart" Content-Type header field might look like this: Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p But the following is not valid: Content-Type: multipart/mixed; boundary=gc0pJq0M:08jU534c0p (because of the colon) and must instead be represented as Content-Type: multipart/mixed; boundary="gc0pJq0M:08jU534c0p" This Content-Type value indicates that the content consists of one or more parts, each with a structure that is syntactically identical to an RFC 822 message, except that the header area is allowed to be completely empty, and that the parts are each preceded by the line Freed & Borenstein Standards Track [Page 19] RFC 2046 Media Types November 1996 --gc0pJq0M:08jU534c0p The boundary delimiter MUST occur at the beginning of a line, i.e., following a CRLF, and the initial CRLF is considered to be attached to the boundary delimiter line rather than part of the preceding part. The boundary may be followed by zero or more characters of linear whitespace. It is then terminated by either another CRLF and the header fields for the next part, or by two CRLFs, in which case there are no header fields for the next part. If no Content-Type field is present it is assumed to be "message/rfc822" in a "multipart/digest" and "text/plain" otherwise. NOTE: The CRLF preceding the boundary delimiter line is conceptually attached to the boundary so that it is possible to have a part that does not end with a CRLF (line break). Body parts that must be considered to end with line breaks, therefore, must have two CRLFs preceding the boundary delimiter line, the first of which is part of the preceding body part, and the second of which is part of the encapsulation boundary. Boundary delimiters must not appear within the encapsulated material, and must be no longer than 70 characters, not counting the two leading hyphens. The boundary delimiter line following the last body part is a distinguished delimiter that indicates that no further body parts will follow. Such a delimiter line is identical to the previous delimiter lines, with the addition of two more hyphens after the boundary parameter value. --gc0pJq0M:08jU534c0p-- NOTE TO IMPLEMENTORS: Boundary string comparisons must compare the boundary value with the beginning of each candidate line. An exact match of the entire candidate line is not required; it is sufficient that the boundary appear in its entirety following the CRLF. There appears to be room for additional information prior to the first boundary delimiter line and following the final boundary delimiter line. These areas should generally be left blank, and implementations must ignore anything that appears before the first boundary delimiter line or after the last one. NOTE: These "preamble" and "epilogue" areas are generally not used because of the lack of proper typing of these parts and the lack of clear semantics for handling these areas at gateways, particularly X.400 gateways. However, rather than leaving the preamble area blank, many MIME implementations have found this to be a convenient Freed & Borenstein Standards Track [Page 20] RFC 2046 Media Types November 1996 place to insert an explanatory note for recipients who read the message with pre-MIME software, since such notes will be ignored by MIME-compliant software. NOTE: Because boundary delimiters must not appear in the body parts being encapsulated, a user agent must exercise care to choose a unique boundary parameter value. The boundary parameter value in the example above could have been the result of an algorithm designed to produce boundary delimiters with a very low probability of already existing in the data to be encapsulated without having to prescan the data. Alternate algorithms might result in more "readable" boundary delimiters for a recipient with an old user agent, but would require more attention to the possibility that the boundary delimiter might appear at the beginning of some line in the encapsulated part. The simplest boundary delimiter line possible is something like "---", with a closing boundary delimiter line of "-----". As a very simple example, the following multipart message has two parts, both of them plain text, one of them explicitly typed and one of them implicitly typed: From: Nathaniel Borenstein To: Ned Freed Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST) Subject: Sample message MIME-Version: 1.0 Content-type: multipart/mixed; boundary="simple boundary" This is the preamble. It is to be ignored, though it is a handy place for composition agents to include an explanatory note to non-MIME conformant readers. --simple boundary This is implicitly typed plain US-ASCII text. It does NOT end with a linebreak. --simple boundary Content-type: text/plain; charset=us-ascii This is explicitly typed plain US-ASCII text. It DOES end with a linebreak. --simple boundary-- This is the epilogue. It is also to be ignored. Freed & Borenstein Standards Track [Page 21] RFC 2046 Media Types November 1996 The use of a media type of "multipart" in a body part within another "multipart" entity is explicitly allowed. In such cases, for obvious reasons, care must be taken to ensure that each nested "multipart" entity uses a different boundary delimiter. See RFC 2049 for an example of nested "multipart" entities. The use of the "multipart" media type with only a single body part may be useful in certain contexts, and is explicitly permitted. NOTE: Experience has shown that a "multipart" media type with a single body part is useful for sending non-text media types. It has the advantage of providing the preamble as a place to include decoding instructions. In addition, a number of SMTP gateways move or remove the MIME headers, and a clever MIME decoder can take a good guess at multipart boundaries even in the absence of the Content-Type header and thereby successfully decode the message. The only mandatory global parameter for the "multipart" media type is the boundary parameter, which consists of 1 to 70 characters from a set of characters known to be very robust through mail gateways, and NOT ending with white space. (If a boundary delimiter line appears to end with white space, the white space must be presumed to have been added by a gateway, and must be deleted.) It is formally specified by the following BNF: boundary := 0*69 bcharsnospace bchars := bcharsnospace / " " bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" / "_" / "," / "-" / "." / "/" / ":" / "=" / "?" Overall, the body of a "multipart" entity may be specified as follows: dash-boundary := "--" boundary ; boundary taken from the value of ; boundary parameter of the ; Content-Type field. multipart-body := [preamble CRLF] dash-boundary transport-padding CRLF body-part *encapsulation close-delimiter transport-padding [CRLF epilogue] Freed & Borenstein Standards Track [Page 22] RFC 2046 Media Types November 1996 transport-padding := *LWSP-char ; Composers MUST NOT generate ; non-zero length transport ; padding, but receivers MUST ; be able to handle padding ; added by message transports. encapsulation := delimiter transport-padding CRLF body-part delimiter := CRLF dash-boundary close-delimiter := delimiter "--" preamble := discard-text epilogue := discard-text discard-text := *(*text CRLF) *text ; May be ignored or discarded. body-part := MIME-part-headers [CRLF *OCTET] ; Lines in a body-part must not start ; with the specified dash-boundary and ; the delimiter must not appear anywhere ; in the body part. Note that the ; semantics of a body-part differ from ; the semantics of a message, as ; described in the text. OCTET := IMPORTANT: The free insertion of linear-white-space and RFC 822 comments between the elements shown in this BNF is NOT allowed since this BNF does not specify a structured header field. NOTE: In certain transport enclaves, RFC 822 restrictions such as the one that limits bodies to printable US-ASCII characters may not be in force. (That is, the transport domains may exist that resemble standard Internet mail transport as specified in RFC 821 and assumed by RFC 822, but without certain restrictions.) The relaxation of these restrictions should be construed as locally extending the definition of bodies, for example to include octets outside of the US-ASCII range, as long as these extensions are supported by the transport and adequately documented in the Content- Transfer-Encoding header field. However, in no event are headers (either message headers or body part headers) allowed to contain anything other than US-ASCII characters. Freed & Borenstein Standards Track [Page 23] RFC 2046 Media Types November 1996 NOTE: Conspicuously missing from the "multipart" type is a notion of structured, related body parts. It is recommended that those wishing to provide more structured or integrated multipart messaging facilities should define subtypes of multipart that are syntactically identical but define relationships between the various parts. For example, subtypes of multipart could be defined that include a distinguished part which in turn is used to specify the relationships between the other parts, probably referring to them by their Content-ID field. Old implementations will not recognize the new subtype if this approach is used, but will treat it as multipart/mixed and will thus be able to show the user the parts that are recognized. 5.1.2. Handling Nested Messages and Multiparts The "message/rfc822" subtype defined in a subsequent section of this document has no terminating condition other than running out of data. Similarly, an improperly truncated "multipart" entity may not have any terminating boundary marker, and can turn up operationally due to mail system malfunctions. It is essential that such entities be handled correctly when they are themselves imbedded inside of another "multipart" structure. MIME implementations are therefore required to recognize outer level boundary markers at ANY level of inner nesting. It is not sufficient to only check for the next expected marker or other terminating condition. 5.1.3. Mixed Subtype The "mixed" subtype of "multipart" is intended for use when the body parts are independent and need to be bundled in a particular order. Any "multipart" subtypes that an implementation does not recognize must be treated as being of subtype "mixed". 5.1.4. Alternative Subtype The "multipart/alternative" type is syntactically identical to "multipart/mixed", but the semantics are different. In particular, each of the body parts is an "alternative" version of the same information. Systems should recognize that the content of the various parts are interchangeable. Systems should choose the "best" type based on the local environment and references, in some cases even through user interaction. As with "multipart/mixed", the order of body parts is significant. In this case, the alternatives appear in an order of increasing faithfulness to the original content. In general, the Freed & Borenstein Standards Track [Page 24] RFC 2046 Media Types November 1996 best choice is the LAST part of a type supported by the recipient system's local environment. "Multipart/alternative" may be used, for example, to send a message in a fancy text format in such a way that it can easily be displayed anywhere: From: Nathaniel Borenstein To: Ned Freed Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST) Subject: Formatted text mail MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=boundary42 --boundary42 Content-Type: text/plain; charset=us-ascii ... plain text version of message goes here ... --boundary42 Content-Type: text/enriched ... RFC 1896 text/enriched version of same message goes here ... --boundary42 Content-Type: application/x-whatever ... fanciest version of same message goes here ... --boundary42-- In this example, users whose mail systems understood the "application/x-whatever" format would see only the fancy version, while other users would see only the enriched or plain text version, depending on the capabilities of their system. In general, user agents that compose "multipart/alternative" entities must place the body parts in increasing order of preference, that is, with the preferred format last. For fancy text, the sending user agent should put the plainest format first and the richest format last. Receiving user agents should pick and display the last format they are capable of displaying. In the case where one of the alternatives is itself of type "multipart" and contains unrecognized sub-parts, the user agent may choose either to show that alternative, an earlier alternative, or both. Freed & Borenstein Standards Track [Page 25] RFC 2046 Media Types November 1996 NOTE: From an implementor's perspective, it might seem more sensible to reverse this ordering, and have the plainest alternative last. However, placing the plainest alternative first is the friendliest possible option when "multipart/alternative" entities are viewed using a non-MIME-conformant viewer. While this approach does impose some burden on conformant MIME viewers, interoperability with older mail readers was deemed to be more important in this case. It may be the case that some user agents, if they can recognize more than one of the formats, will prefer to offer the user the choice of which format to view. This makes sense, for example, if a message includes both a nicely- formatted image version and an easily-edited text version. What is most critical, however, is that the user not automatically be shown multiple versions of the same data. Either the user should be shown the last recognized version or should be given the choice. THE SEMANTICS OF CONTENT-ID IN MULTIPART/ALTERNATIVE: Each part of a "multipart/alternative" entity represents the same data, but the mappings between the two are not necessarily without information loss. For example, information is lost when translating ODA to PostScript or plain text. It is recommended that each part should have a different Content-ID value in the case where the information content of the two parts is not identical. And when the information content is identical -- for example, where several parts of type "message/external-body" specify alternate ways to access the identical data -- the same Content-ID field value should be used, to optimize any caching mechanisms that might be present on the recipient's end. However, the Content-ID values used by the parts should NOT be the same Content-ID value that describes the "multipart/alternative" as a whole, if there is any such Content-ID field. That is, one Content-ID value will refer to the "multipart/alternative" entity, while one or more other Content-ID values will refer to the parts inside it. 5.1.5. Digest Subtype This document defines a "digest" subtype of the "multipart" Content- Type. This type is syntactically identical to "multipart/mixed", but the semantics are different. In particular, in a digest, the default Content-Type value for a body part is changed from "text/plain" to "message/rfc822". This is done to allow a more readable digest format that is largely compatible (except for the quoting convention) with RFC 934. Note: Though it is possible to specify a Content-Type value for a body part in a digest which is other than "message/rfc822", such as a "text/plain" part containing a description of the material in the Freed & Borenstein Standards Track [Page 26] RFC 2046 Media Types November 1996 digest, actually doing so is undesireble. The "multipart/digest" Content-Type is intended to be used to send collections of messages. If a "text/plain" part is needed, it should be included as a seperate part of a "multipart/mixed" message. A digest in this format might, then, look something like this: From: Moderator-Address To: Recipient-List Date: Mon, 22 Mar 1994 13:34:51 +0000 Subject: Internet Digest, volume 42 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="---- main boundary ----" ------ main boundary ---- ...Introductory text or table of contents... ------ main boundary ---- Content-Type: multipart/digest; boundary="---- next message ----" ------ next message ---- From: someone-else Date: Fri, 26 Mar 1993 11:13:32 +0200 Subject: my opinion ...body goes here ... ------ next message ---- From: someone-else-again Date: Fri, 26 Mar 1993 10:07:13 -0500 Subject: my different opinion ... another body goes here ... ------ next message ------ ------ main boundary ------ 5.1.6. Parallel Subtype This document defines a "parallel" subtype of the "multipart" Content-Type. This type is syntactically identical to "multipart/mixed", but the semantics are different. In particular, Freed & Borenstein Standards Track [Page 27] RFC 2046 Media Types November 1996 in a parallel entity, the order of body parts is not significant. A common presentation of this type is to display all of the parts simultaneously on hardware and software that are capable of doing so. However, composing agents should be aware that many mail readers will lack this capability and will show the parts serially in any event. 5.1.7. Other Multipart Subtypes Other "multipart" subtypes are expected in the future. MIME implementations must in general treat unrecognized subtypes of "multipart" as being equivalent to "multipart/mixed". 5.2. Message Media Type It is frequently desirable, in sending mail, to encapsulate another mail message. A special media type, "message", is defined to facilitate this. In particular, the "rfc822" subtype of "message" is used to encapsulate RFC 822 messages. NOTE: It has been suggested that subtypes of "message" might be defined for forwarded or rejected messages. However, forwarded and rejected messages can be handled as multipart messages in which the first part contains any control or descriptive information, and a second part, of type "message/rfc822", is the forwarded or rejected message. Composing rejection and forwarding messages in this manner will preserve the type information on the original message and allow it to be correctly presented to the recipient, and hence is strongly encouraged. Subtypes of "message" often impose restrictions on what encodings are allowed. These restrictions are described in conjunction with each specific subtype. Mail gateways, relays, and other mail handling agents are commonly known to alter the top-level header of an RFC 822 message. In particular, they frequently add, remove, or reorder header fields. These operations are explicitly forbidden for the encapsulated headers embedded in the bodies of messages of type "message." 5.2.1. RFC822 Subtype A media type of "message/rfc822" indicates that the body contains an encapsulated message, with the syntax of an RFC 822 message. However, unlike top-level RFC 822 messages, the restriction that each "message/rfc822" body must include a "From", "Date", and at least one destination header is removed and replaced with the requirement that at least one of "From", "Subject", or "Date" must be present. Freed & Borenstein Standards Track [Page 28] RFC 2046 Media Types November 1996 It should be noted that, despite the use of the numbers "822", a "message/rfc822" entity isn't restricted to material in strict conformance to RFC822, nor are the semantics of "message/rfc822" objects restricted to the semantics defined in RFC822. More specifically, a "message/rfc822" message could well be a News article or a MIME message. No encoding other than "7bit", "8bit", or "binary" is permitted for the body of a "message/rfc822" entity. The message header fields are always US-ASCII in any case, and data within the body can still be encoded, in which case the Content-Transfer-Encoding header field in the encapsulated message will reflect this. Non-US-ASCII text in the headers of an encapsulated message can be specified using the mechanisms described in RFC 2047. 5.2.2. Partial Subtype The "partial" subtype is defined to allow large entities to be delivered as several separate pieces of mail and automatically reassembled by a receiving user agent. (The concept is similar to IP fragmentation and reassembly in the basic Internet Protocols.) This mechanism can be used when intermediate transport agents limit the size of individual messages that can be sent. The media type "message/partial" thus indicates that the body contains a fragment of a larger entity. Because data of type "message" may never be encoded in base64 or quoted-printable, a problem might arise if "message/partial" entities are constructed in an environment that supports binary or 8bit transport. The problem is that the binary data would be split into multiple "message/partial" messages, each of them requiring binary transport. If such messages were encountered at a gateway into a 7bit transport environment, there would be no way to properly encode them for the 7bit world, aside from waiting for all of the fragments, reassembling the inner message, and then encoding the reassembled data in base64 or quoted-printable. Since it is possible that different fragments might go through different gateways, even this is not an acceptable solution. For this reason, it is specified that entities of type "message/partial" must always have a content- transfer-encoding of 7bit (the default). In particular, even in environments that support binary or 8bit transport, the use of a content- transfer-encoding of "8bit" or "binary" is explicitly prohibited for MIME entities of type "message/partial". This in turn implies that the inner message must not use "8bit" or "binary" encoding. Freed & Borenstein Standards Track [Page 29] RFC 2046 Media Types November 1996 Because some message transfer agents may choose to automatically fragment large messages, and because such agents may use very different fragmentation thresholds, it is possible that the pieces of a partial message, upon reassembly, may prove themselves to comprise a partial message. This is explicitly permitted. Three parameters must be specified in the Content-Type field of type "message/partial": The first, "id", is a unique identifier, as close to a world-unique identifier as possible, to be used to match the fragments together. (In general, the identifier is essentially a message-id; if placed in double quotes, it can be ANY message-id, in accordance with the BNF for "parameter" given in RFC 2045.) The second, "number", an integer, is the fragment number, which indicates where this fragment fits into the sequence of fragments. The third, "total", another integer, is the total number of fragments. This third subfield is required on the final fragment, and is optional (though encouraged) on the earlier fragments. Note also that these parameters may be given in any order. Thus, the second piece of a 3-piece message may have either of the following header fields: Content-Type: Message/Partial; number=2; total=3; id="oc=jpbe0M2Yt4s@thumper.bellcore.com" Content-Type: Message/Partial; id="oc=jpbe0M2Yt4s@thumper.bellcore.com"; number=2 But the third piece MUST specify the total number of fragments: Content-Type: Message/Partial; number=3; total=3; id="oc=jpbe0M2Yt4s@thumper.bellcore.com" Note that fragment numbering begins with 1, not 0. When the fragments of an entity broken up in this manner are put together, the result is always a complete MIME entity, which may have its own Content-Type header field, and thus may contain any other data type. 5.2.2.1. Message Fragmentation and Reassembly The semantics of a reassembled partial message must be those of the "inner" message, rather than of a message containing the inner message. This makes it possible, for example, to send a large audio message as several partial messages, and still have it appear to the recipient as a simple audio message rather than as an encapsulated Freed & Borenstein Standards Track [Page 30] RFC 2046 Media Types November 1996 message containing an audio message. That is, the encapsulation of the message is considered to be "transparent". When generating and reassembling the pieces of a "message/partial" message, the headers of the encapsulated message must be merged with the headers of the enclosing entities. In this process the following rules must be observed: (1) Fragmentation agents must split messages at line boundaries only. This restriction is imposed because splits at points other than the ends of lines in turn depends on message transports being able to preserve the semantics of messages that don't end with a CRLF sequence. Many transports are incapable of preserving such semantics. (2) 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. (3) The header fields in the enclosed message which start with "Content-", plus the "Subject", "Message-ID", "Encrypted", and "MIME-Version" fields, must be appended, in order, to the header fields of the new message. 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. (4) All of the header fields from the second and any subsequent enclosing messages are discarded by the reassembly process. 5.2.2.2. Fragmentation and Reassembly Example If an audio message is broken into two pieces, the first piece might look something like this: 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"; Freed & Borenstein Standards Track [Page 31] RFC 2046 Media Types November 1996 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 ... and the second half might look something like this: 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 ... Then, when the fragmented message is reassembled, the resulting message to be displayed to the user should look something like this: 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 ... The inclusion of a "References" field in the headers of the second and subsequent pieces of a fragmented message that references the Message-Id on the previous piece may be of benefit to mail readers that understand and track references. However, the generation of such "References" fields is entirely optional. Freed & Borenstein Standards Track [Page 32] RFC 2046 Media Types November 1996 Finally, it should be noted that the "Encrypted" header field has been made obsolete by Privacy Enhanced Messaging (PEM) [RFC-1421, RFC-1422, RFC-1423, RFC-1424], but the rules above are nevertheless believed to describe the correct way to treat it if it is encountered in the context of conversion to and from "message/partial" fragments. 5.2.3. External-Body Subtype The external-body subtype indicates that the actual body data are not included, but merely referenced. In this case, the parameters describe a mechanism for accessing the external data. When a MIME entity is of type "message/external-body", it consists of a header, two consecutive CRLFs, and the message header for the encapsulated message. If another pair of consecutive CRLFs appears, this of course ends the message header for the encapsulated message. However, since the encapsulated message's body is itself external, it does NOT appear in the area that follows. For example, consider the following message: Content-type: message/external-body; access-type=local-file; name="/u/nsb/Me.jpeg" Content-type: image/jpeg Content-ID: Content-Transfer-Encoding: binary THIS IS NOT REALLY THE BODY! The area at the end, which might be called the "phantom body", is ignored for most external-body messages. However, it may be used to contain auxiliary information for some such messages, as indeed it is when the access-type is "mail- server". The only access-type defined in this document that uses the phantom body is "mail-server", but other access-types may be defined in the future in other specifications that use this area. The encapsulated headers in ALL "message/external-body" entities MUST include a Content-ID header field to give a unique identifier by which to reference the data. This identifier may be used for caching mechanisms, and for recognizing the receipt of the data when the access-type is "mail-server". Note that, as specified here, the tokens that describe external-body data, such as file names and mail server commands, are required to be in the US-ASCII character set. Freed & Borenstein Standards Track [Page 33] RFC 2046 Media Types November 1996 If this proves problematic in practice, a new mechanism may be required as a future extension to MIME, either as newly defined access-types for "message/external-body" or by some other mechanism. As with "message/partial", MIME entities of type "message/external- body" MUST have a content-transfer-encoding of 7bit (the default). In particular, even in environments that support binary or 8bit transport, the use of a content- transfer-encoding of "8bit" or "binary" is explicitly prohibited for entities of type "message/external-body". 5.2.3.1. General External-Body Parameters The parameters that may be used with any "message/external- body" are: (1) ACCESS-TYPE -- A word indicating the supported access mechanism by which the file or data may be obtained. This word is not case sensitive. Values include, but are not limited to, "FTP", "ANON-FTP", "TFTP", "LOCAL- FILE", and "MAIL-SERVER". Future values, except for experimental values beginning with "X-", must be registered with IANA, as described in RFC 2048. This parameter is unconditionally mandatory and MUST be present on EVERY "message/external-body". (2) EXPIRATION -- The date (in the RFC 822 "date-time" syntax, as extended by RFC 1123 to permit 4 digits in the year field) after which the existence of the external data is not guaranteed. This parameter may be used with ANY access-type and is ALWAYS optional. (3) SIZE -- The size (in octets) of the data. The intent of this parameter is to help the recipient decide whether or not to expend the necessary resources to retrieve the external data. Note that this describes the size of the data in its canonical form, that is, before any Content-Transfer-Encoding has been applied or after the data have been decoded. This parameter may be used with ANY access-type and is ALWAYS optional. (4) PERMISSION -- A case-insensitive field that indicates whether or not it is expected that clients might also attempt to overwrite the data. By default, or if permission is "read", the assumption is that they are not, and that if the data is retrieved once, it is never needed again. If PERMISSION is "read-write", Freed & Borenstein Standards Track [Page 34] RFC 2046 Media Types November 1996 this assumption is invalid, and any local copy must be considered no more than a cache. "Read" and "Read- write" are the only defined values of permission. This parameter may be used with ANY access-type and is ALWAYS optional. The precise semantics of the access-types defined here are described in the sections that follow. 5.2.3.2. The 'ftp' and 'tftp' Access-Types An access-type of FTP or TFTP indicates that the message body is accessible as a file using the FTP [RFC-959] or TFTP [RFC- 783] protocols, respectively. For these access-types, the following additional parameters are mandatory: (1) NAME -- The name of the file that contains the actual body data. (2) SITE -- A machine from which the file may be obtained, using the given protocol. This must be a fully qualified domain name, not a nickname. (3) Before any data are retrieved, using FTP, the user will generally need to be asked to provide a login id and a password for the machine named by the site parameter. For security reasons, such an id and password are not specified as content-type parameters, but must be obtained from the user. In addition, the following parameters are optional: (1) DIRECTORY -- A directory from which the data named by NAME should be retrieved. (2) MODE -- A case-insensitive string indicating the mode to be used when retrieving the information. The valid values for access-type "TFTP" are "NETASCII", "OCTET", and "MAIL", as specified by the TFTP protocol [RFC- 783]. The valid values for access-type "FTP" are "ASCII", "EBCDIC", "IMAGE", and "LOCALn" where "n" is a decimal integer, typically 8. These correspond to the representation types "A" "E" "I" and "L n" as specified by the FTP protocol [RFC-959]. Note that "BINARY" and "TENEX" are not valid values for MODE and that "OCTET" or "IMAGE" or "LOCAL8" should be used instead. IF MODE is not specified, the default value is "NETASCII" for TFTP and "ASCII" otherwise. Freed & Borenstein Standards Track [Page 35] RFC 2046 Media Types November 1996 5.2.3.3. The 'anon-ftp' Access-Type The "anon-ftp" access-type is identical to the "ftp" access type, except that the user need not be asked to provide a name and password for the specified site. Instead, the ftp protocol will be used with login "anonymous" and a password that corresponds to the user's mail address. 5.2.3.4. The 'local-file' Access-Type An access-type of "local-file" indicates that the actual body is accessible as a file on the local machine. Two additional parameters are defined for this access type: (1) NAME -- The name of the file that contains the actual body data. This parameter is mandatory for the "local-file" access-type. (2) SITE -- A domain specifier for a machine or set of machines that are known to have access to the data file. This optional parameter is used to describe the locality of reference for the data, that is, the site or sites at which the file is expected to be visible. Asterisks may be used for wildcard matching to a part of a domain name, such as "*.bellcore.com", to indicate a set of machines on which the data should be directly visible, while a single asterisk may be used to indicate a file that is expected to be universally available, e.g., via a global file system. 5.2.3.5. The 'mail-server' Access-Type The "mail-server" access-type indicates that the actual body is available from a mail server. Two additional parameters are defined for this access-type: (1) SERVER -- The addr-spec of the mail server from which the actual body data can be obtained. This parameter is mandatory for the "mail-server" access-type. (2) SUBJECT -- The subject that is to be used in the mail that is sent to obtain the data. Note that keying mail servers on Subject lines is NOT recommended, but such mail servers are known to exist. This is an optional parameter. Freed & Borenstein Standards Track [Page 36] RFC 2046 Media Types November 1996 Because mail servers accept a variety of syntaxes, some of which is multiline, the full command to be sent to a mail server is not included as a parameter in the content-type header field. Instead, it is provided as the "phantom body" when the media type is "message/external-body" and the access-type is mail-server. Note that MIME does not define a mail server syntax. Rather, it allows the inclusion of arbitrary mail server commands in the phantom body. Implementations must include the phantom body in the body of the message it sends to the mail server address to retrieve the relevant data. Unlike other access-types, mail-server access is asynchronous and will happen at an unpredictable time in the future. For this reason, it is important that there be a mechanism by which the returned data can be matched up with the original "message/external-body" entity. MIME mail servers must use the same Content-ID field on the returned message that was used in the original "message/external-body" entities, to facilitate such matching. 5.2.3.6. External-Body Security Issues "Message/external-body" entities give rise to two important security issues: (1) Accessing data via a "message/external-body" reference effectively results in the message recipient performing an operation that was specified by the message originator. It is therefore possible for the message originator to trick a recipient into doing something they would not have done otherwise. For example, an originator could specify a action that attempts retrieval of material that the recipient is not authorized to obtain, causing the recipient to unwittingly violate some security policy. For this reason, user agents capable of resolving external references must always take steps to describe the action they are to take to the recipient and ask for explicit permisssion prior to performing it. The 'mail-server' access-type is particularly vulnerable, in that it causes the recipient to send a new message whose contents are specified by the original message's originator. Given the potential for abuse, any such request messages that are constructed should contain a clear indication that they were generated automatically (e.g. in a Comments: header field) in an attempt to resolve a MIME Freed & Borenstein Standards Track [Page 37] RFC 2046 Media Types November 1996 "message/external-body" reference. (2) MIME will sometimes be used in environments that provide some guarantee of message integrity and authenticity. If present, such guarantees may apply only to the actual direct content of messages -- they may or may not apply to data accessed through MIME's "message/external-body" mechanism. In particular, it may be possible to subvert certain access mechanisms even when the messaging system itself is secure. It should be noted that this problem exists either with or without the availabilty of MIME mechanisms. A casual reference to an FTP site containing a document in the text of a secure message brings up similar issues -- the only difference is that MIME provides for automatic retrieval of such material, and users may place unwarranted trust is such automatic retrieval mechanisms. 5.2.3.7. Examples and Further Explanations When the external-body mechanism is used in conjunction with the "multipart/alternative" media type it extends the functionality of "multipart/alternative" to include the case where the same entity is provided in the same format but via different accces mechanisms. When this is done the originator of the message must order the parts first in terms of preferred formats and then by preferred access mechanisms. The recipient's viewer should then evaluate the list both in terms of format and access mechanisms. With the emerging possibility of very wide-area file systems, it becomes very hard to know in advance the set of machines where a file will and will not be accessible directly from the file system. Therefore it may make sense to provide both a file name, to be tried directly, and the name of one or more sites from which the file is known to be accessible. An implementation can try to retrieve remote files using FTP or any other protocol, using anonymous file retrieval or prompting the user for the necessary name and password. If an external body is accessible via multiple mechanisms, the sender may include multiple entities of type "message/external-body" within the body parts of an enclosing "multipart/alternative" entity. However, the external-body mechanism is not intended to be limited to file retrieval, as shown by the mail-server access-type. Beyond this, one can imagine, for example, using a video server for external references to video clips. Freed & Borenstein Standards Track [Page 38] RFC 2046 Media Types November 1996 The embedded message header fields which appear in the body of the "message/external-body" data must be used to declare the media type of the external body if it is anything other than plain US-ASCII text, since the external body does not have a header section to declare its type. Similarly, any Content-transfer-encoding other than "7bit" must also be declared here. Thus a complete "message/external-body" message, referring to an object in PostScript format, might look like this: From: Whomever To: Someone Date: Whenever Subject: whatever MIME-Version: 1.0 Message-ID: Content-Type: multipart/alternative; boundary=42 Content-ID: --42 Content-Type: message/external-body; name="BodyFormats.ps"; site="thumper.bellcore.com"; mode="image"; access-type=ANON-FTP; directory="pub"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: --42 Content-Type: message/external-body; access-type=local-file; name="/u/nsb/writing/rfcs/RFC-MIME.ps"; site="thumper.bellcore.com"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: --42 Content-Type: message/external-body; access-type=mail-server server="listserv@bogus.bitnet"; expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" Content-type: application/postscript Content-ID: get RFC-MIME.DOC --42-- Freed & Borenstein Standards Track [Page 39] RFC 2046 Media Types November 1996 Note that in the above examples, the default Content-transfer- encoding of "7bit" is assumed for the external postscript data. Like the "message/partial" type, the "message/external-body" media type is intended to be transparent, that is, to convey the data type in the external body rather than to convey a message with a body of that type. Thus the headers on the outer and inner parts must be merged using the same rules as for "message/partial". In particular, this means that the Content-type and Subject fields are overridden, but the From field is preserved. Note that since the external bodies are not transported along with the external body reference, they need not conform to transport limitations that apply to the reference itself. In particular, Internet mail transports may impose 7bit and line length limits, but these do not automatically apply to binary external body references. Thus a Content-Transfer-Encoding is not generally necessary, though it is permitted. Note that the body of a message of type "message/external-body" is governed by the basic syntax for an RFC 822 message. In particular, anything before the first consecutive pair of CRLFs is header information, while anything after it is body information, which is ignored for most access-types. 5.2.4. Other Message Subtypes MIME implementations must in general treat unrecognized subtypes of "message" as being equivalent to "application/octet-stream". Future subtypes of "message" intended for use with email should be restricted to "7bit" encoding. A type other than "message" should be used if restriction to "7bit" is not possible. 6. Experimental Media Type Values A media type value beginning with the characters "X-" is a private value, to be used by consenting systems by mutual agreement. Any format without a rigorous and public definition must be named with an "X-" prefix, and publicly specified values shall never begin with "X-". (Older versions of the widely used Andrew system use the "X- BE2" name, so new systems should probably choose a different name.) In general, the use of "X-" top-level types is strongly discouraged. Implementors should invent subtypes of the existing types whenever possible. In many cases, a subtype of "application" will be more appropriate than a new top-level type. Freed & Borenstein Standards Track [Page 40] RFC 2046 Media Types November 1996 7. Summary The five discrete media types provide provide a standardized mechanism for tagging entities as "audio", "image", or several other kinds of data. The composite "multipart" and "message" media types allow mixing and hierarchical structuring of entities of different types in a single message. A distinguished parameter syntax allows further specification of data format details, particularly the specification of alternate character sets. Additional optional header fields provide mechanisms for certain extensions deemed desirable by many implementors. Finally, a number of useful media types are defined for general use by consenting user agents, notably "message/partial" and "message/external-body". 9. Security Considerations Security issues are discussed in the context of the "application/postscript" type, the "message/external-body" type, and in RFC 2048. Implementors should pay special attention to the security implications of any media types that can cause the remote execution of any actions in the recipient's environment. In such cases, the discussion of the "application/postscript" type may serve as a model for considering other media types with remote execution capabilities. Freed & Borenstein Standards Track [Page 41] RFC 2046 Media Types November 1996 9. Authors' Addresses For more information, the authors of this document are best contacted via Internet mail: Ned Freed Innosoft International, Inc. 1050 East Garvey Avenue South West Covina, CA 91790 USA Phone: +1 818 919 3600 Fax: +1 818 919 3614 EMail: ned@innosoft.com Nathaniel S. Borenstein First Virtual Holdings 25 Washington Avenue Morristown, NJ 07960 USA Phone: +1 201 540 8967 Fax: +1 201 993 3032 EMail: nsb@nsb.fv.com MIME is a result of the work of the Internet Engineering Task Force Working Group on RFC 822 Extensions. The chairman of that group, Greg Vaudreuil, may be reached at: Gregory M. Vaudreuil Octel Network Services 17080 Dallas Parkway Dallas, TX 75248-1905 USA EMail: Greg.Vaudreuil@Octel.Com Freed & Borenstein Standards Track [Page 42] RFC 2046 Media Types November 1996 Appendix A -- Collected Grammar This appendix contains the complete BNF grammar for all the syntax specified by this document. By itself, however, this grammar is incomplete. It refers by name to several syntax rules that are defined by RFC 822. Rather than reproduce those definitions here, and risk unintentional differences between the two, this document simply refers the reader to RFC 822 for the remaining definitions. Wherever a term is undefined, it refers to the RFC 822 definition. boundary := 0*69 bcharsnospace bchars := bcharsnospace / " " bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" / "_" / "," / "-" / "." / "/" / ":" / "=" / "?" body-part := <"message" as defined in RFC 822, with all header fields optional, not starting with the specified dash-boundary, and with the delimiter not occurring anywhere in the body part. Note that the semantics of a part differ from the semantics of a message, as described in the text.> close-delimiter := delimiter "--" dash-boundary := "--" boundary ; boundary taken from the value of ; boundary parameter of the ; Content-Type field. delimiter := CRLF dash-boundary discard-text := *(*text CRLF) ; May be ignored or discarded. encapsulation := delimiter transport-padding CRLF body-part epilogue := discard-text multipart-body := [preamble CRLF] dash-boundary transport-padding CRLF body-part *encapsulation Freed & Borenstein Standards Track [Page 43] RFC 2046 Media Types November 1996 close-delimiter transport-padding [CRLF epilogue] preamble := discard-text transport-padding := *LWSP-char ; Composers MUST NOT generate ; non-zero length transport ; padding, but receivers MUST ; be able to handle padding ; added by message transports. Freed & Borenstein Standards Track [Page 44] mail-2.5.4/reference/rfc2047 Multipurpose Internet Mail Extensions (3).txt000066400000000000000000001024711214434061600257310ustar00rootroot00000000000000 Network Working Group K. Moore Request for Comments: 2047 University of Tennessee Obsoletes: 1521, 1522, 1590 November 1996 Category: Standards Track MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text 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. Abstract STD 11, RFC 822, defines a message representation protocol specifying considerable detail about US-ASCII message headers, and leaves the message content, or message body, as flat US-ASCII text. This set of documents, collectively called the Multipurpose Internet Mail Extensions, or MIME, redefines the format of messages to allow for (1) textual message bodies in character sets other than US-ASCII, (2) an extensible set of different formats for non-textual message bodies, (3) multi-part message bodies, and (4) textual header information in character sets other than US-ASCII. These documents are based on earlier work documented in RFC 934, STD 11, and RFC 1049, but extends and revises them. Because RFC 822 said so little about message bodies, these documents are largely orthogonal to (rather than a revision of) RFC 822. This particular document is the third document in the series. It describes extensions to RFC 822 to allow non-US-ASCII text data in Internet mail header fields. Moore Standards Track [Page 1] RFC 2047 Message Header Extensions November 1996 Other documents in this series include: + RFC 2045, which specifies the various headers used to describe the structure of MIME messages. + RFC 2046, which defines the general structure of the MIME media typing system and defines an initial set of media types, + RFC 2048, which specifies various IANA registration procedures for MIME-related facilities, and + RFC 2049, which describes MIME conformance criteria and provides some illustrative examples of MIME message formats, acknowledgements, and the bibliography. These documents are revisions of RFCs 1521, 1522, and 1590, which themselves were revisions of RFCs 1341 and 1342. An appendix in RFC 2049 describes differences and changes from previous versions. 1. Introduction RFC 2045 describes a mechanism for denoting textual body parts which are coded in various character sets, as well as methods for encoding such body parts as sequences of printable US-ASCII characters. This memo describes similar techniques to allow the encoding of non-ASCII text in various portions of a RFC 822 [2] message header, in a manner which is unlikely to confuse existing message handling software. Like the encoding techniques described in RFC 2045, the techniques outlined here were designed to allow the use of non-ASCII characters in message headers in a way which is unlikely to be disturbed by the quirks of existing Internet mail handling programs. In particular, some mail relaying programs are known to (a) delete some message header fields while retaining others, (b) rearrange the order of addresses in To or Cc fields, (c) rearrange the (vertical) order of header fields, and/or (d) "wrap" message headers at different places than those in the original message. In addition, some mail reading programs are known to have difficulty correctly parsing message headers which, while legal according to RFC 822, make use of backslash-quoting to "hide" special characters such as "<", ",", or ":", or which exploit other infrequently-used features of that specification. While it is unfortunate that these programs do not correctly interpret RFC 822 headers, to "break" these programs would cause severe operational problems for the Internet mail system. The extensions described in this memo therefore do not rely on little- used features of RFC 822. Moore Standards Track [Page 2] RFC 2047 Message Header Extensions November 1996 Instead, certain sequences of "ordinary" printable ASCII characters (known as "encoded-words") are reserved for use as encoded data. The syntax of encoded-words is such that they are unlikely to "accidentally" appear as normal text in message headers. Furthermore, the characters used in encoded-words are restricted to those which do not have special meanings in the context in which the encoded-word appears. Generally, an "encoded-word" is a sequence of printable ASCII characters that begins with "=?", ends with "?=", and has two "?"s in between. It specifies a character set and an encoding method, and also includes the original text encoded as graphic ASCII characters, according to the rules for that encoding method. A mail composer that implements this specification will provide a means of inputting non-ASCII text in header fields, but will translate these fields (or appropriate portions of these fields) into encoded-words before inserting them into the message header. A mail reader that implements this specification will recognize encoded-words when they appear in certain portions of the message header. Instead of displaying the encoded-word "as is", it will reverse the encoding and display the original text in the designated character set. NOTES This memo relies heavily on notation and terms defined RFC 822 and RFC 2045. In particular, the syntax for the ABNF used in this memo is defined in RFC 822, as well as many of the terminal or nonterminal symbols from RFC 822 are used in the grammar for the header extensions defined here. Among the symbols defined in RFC 822 and referenced in this memo are: 'addr-spec', 'atom', 'CHAR', 'comment', 'CTLs', 'ctext', 'linear-white-space', 'phrase', 'quoted-pair'. 'quoted-string', 'SPACE', and 'word'. Successful implementation of this protocol extension requires careful attention to the RFC 822 definitions of these terms. When the term "ASCII" appears in this memo, it refers to the "7-Bit American Standard Code for Information Interchange", ANSI X3.4-1986. The MIME charset name for this character set is "US-ASCII". When not specifically referring to the MIME charset name, this document uses the term "ASCII", both for brevity and for consistency with RFC 822. However, implementors are warned that the character set name must be spelled "US-ASCII" in MIME message and body part headers. Moore Standards Track [Page 3] RFC 2047 Message Header Extensions November 1996 This memo specifies a protocol for the representation of non-ASCII text in message headers. It specifically DOES NOT define any translation between "8-bit headers" and pure ASCII headers, nor is any such translation assumed to be possible. 2. Syntax of encoded-words An 'encoded-word' is defined by the following ABNF grammar. The notation of RFC 822 is used, with the exception that white space characters MUST NOT appear between components of an 'encoded-word'. encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" charset = token ; see section 3 encoding = token ; see section 4 token = 1* especials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / " <"> / "/" / "[" / "]" / "?" / "." / "=" encoded-text = 1* ; (but see "Use of encoded-words in message ; headers", section 5) Both 'encoding' and 'charset' names are case-independent. Thus the charset name "ISO-8859-1" is equivalent to "iso-8859-1", and the encoding named "Q" may be spelled either "Q" or "q". An 'encoded-word' may not be more than 75 characters long, including 'charset', 'encoding', 'encoded-text', and delimiters. If it is desirable to encode more text than will fit in an 'encoded-word' of 75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may be used. While there is no limit to the length of a multiple-line header field, each line of a header field that contains one or more 'encoded-word's is limited to 76 characters. The length restrictions are included both to ease interoperability through internetwork mail gateways, and to impose a limit on the amount of lookahead a header parser must employ (while looking for a final ?= delimiter) before it can decide whether a token is an "encoded-word" or something else. Moore Standards Track [Page 4] RFC 2047 Message Header Extensions November 1996 IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's by an RFC 822 parser. As a consequence, unencoded white space characters (such as SPACE and HTAB) are FORBIDDEN within an 'encoded-word'. For example, the character sequence =?iso-8859-1?q?this is some text?= would be parsed as four 'atom's, rather than as a single 'atom' (by an RFC 822 parser) or 'encoded-word' (by a parser which understands 'encoded-words'). The correct way to encode the string "this is some text" is to encode the SPACE characters as well, e.g. =?iso-8859-1?q?this=20is=20some=20text?= The characters which may appear in 'encoded-text' are further restricted by the rules in section 5. 3. Character sets The 'charset' portion of an 'encoded-word' specifies the character set associated with the unencoded text. A 'charset' can be any of the character set names allowed in an MIME "charset" parameter of a "text/plain" body part, or any character set name registered with IANA for use with the MIME text/plain content-type. Some character sets use code-switching techniques to switch between "ASCII mode" and other modes. If unencoded text in an 'encoded-word' contains a sequence which causes the charset interpreter to switch out of ASCII mode, it MUST contain additional control codes such that ASCII mode is again selected at the end of the 'encoded-word'. (This rule applies separately to each 'encoded-word', including adjacent 'encoded-word's within a single header field.) When there is a possibility of using more than one character set to represent the text in an 'encoded-word', and in the absence of private agreements between sender and recipients of a message, it is recommended that members of the ISO-8859-* series be used in preference to other character sets. 4. Encodings Initially, the legal values for "encoding" are "Q" and "B". These encodings are described below. The "Q" encoding is recommended for use when most of the characters to be encoded are in the ASCII character set; otherwise, the "B" encoding should be used. Nevertheless, a mail reader which claims to recognize 'encoded-word's MUST be able to accept either encoding for any character set which it supports. Moore Standards Track [Page 5] RFC 2047 Message Header Extensions November 1996 Only a subset of the printable ASCII characters may be used in 'encoded-text'. Space and tab characters are not allowed, so that the beginning and end of an 'encoded-word' are obvious. The "?" character is used within an 'encoded-word' to separate the various portions of the 'encoded-word' from one another, and thus cannot appear in the 'encoded-text' portion. Other characters are also illegal in certain contexts. For example, an 'encoded-word' in a 'phrase' preceding an address in a From header field may not contain any of the "specials" defined in RFC 822. Finally, certain other characters are disallowed in some contexts, to ensure reliability for messages that pass through internetwork mail gateways. The "B" encoding automatically meets these requirements. The "Q" encoding allows a wide range of printable characters to be used in non-critical locations in the message header (e.g., Subject), with fewer characters available for use in other locations. 4.1. The "B" encoding The "B" encoding is identical to the "BASE64" encoding defined by RFC 2045. 4.2. The "Q" encoding The "Q" encoding is similar to the "Quoted-Printable" content- transfer-encoding defined in RFC 2045. It is designed to allow text containing mostly ASCII characters to be decipherable on an ASCII terminal without decoding. (1) Any 8-bit value may be represented by a "=" followed by two hexadecimal digits. For example, if the character set in use were ISO-8859-1, the "=" character would thus be encoded as "=3D", and a SPACE by "=20". (Upper case should be used for hexadecimal digits "A" through "F".) (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be represented as "_" (underscore, ASCII 95.). (This character may not pass through some internetwork mail gateways, but its use will greatly enhance readability of "Q" encoded data with mail readers that do not support this encoding.) Note that the "_" always represents hexadecimal 20, even if the SPACE character occupies a different code position in the character set in use. (3) 8-bit values which correspond to printable ASCII characters other than "=", "?", and "_" (underscore), MAY be represented as those characters. (But see section 5 for restrictions.) In particular, SPACE and TAB MUST NOT be represented as themselves within encoded words. Moore Standards Track [Page 6] RFC 2047 Message Header Extensions November 1996 5. Use of encoded-words in message headers An 'encoded-word' may appear in a message header or body part header according to the following rules: (1) An 'encoded-word' may replace a 'text' token (as defined by RFC 822) in any Subject or Comments header field, any extension message header field, or any MIME body part field for which the field body is defined as '*text'. An 'encoded-word' may also appear in any user-defined ("X-") message or body part header field. Ordinary ASCII text and 'encoded-word's may appear together in the same header field. However, an 'encoded-word' that appears in a header field defined as '*text' MUST be separated from any adjacent 'encoded-word' or 'text' by 'linear-white-space'. (2) An 'encoded-word' may appear within a 'comment' delimited by "(" and ")", i.e., wherever a 'ctext' is allowed. More precisely, the RFC 822 ABNF definition for 'comment' is amended as follows: comment = "(" *(ctext / quoted-pair / comment / encoded-word) ")" A "Q"-encoded 'encoded-word' which appears in a 'comment' MUST NOT contain the characters "(", ")" or " 'encoded-word' that appears in a 'comment' MUST be separated from any adjacent 'encoded-word' or 'ctext' by 'linear-white-space'. It is important to note that 'comment's are only recognized inside "structured" field bodies. In fields whose bodies are defined as '*text', "(" and ")" are treated as ordinary characters rather than comment delimiters, and rule (1) of this section applies. (See RFC 822, sections 3.1.2 and 3.1.3) (3) As a replacement for a 'word' entity within a 'phrase', for example, one that precedes an address in a From, To, or Cc header. The ABNF definition for 'phrase' from RFC 822 thus becomes: phrase = 1*( encoded-word / word ) In this case the set of characters that may be used in a "Q"-encoded 'encoded-word' is restricted to: . An 'encoded-word' that appears within a 'phrase' MUST be separated from any adjacent 'word', 'text' or 'special' by 'linear-white-space'. Moore Standards Track [Page 7] RFC 2047 Message Header Extensions November 1996 These are the ONLY locations where an 'encoded-word' may appear. In particular: + An 'encoded-word' MUST NOT appear in any portion of an 'addr-spec'. + An 'encoded-word' MUST NOT appear within a 'quoted-string'. + An 'encoded-word' MUST NOT be used in a Received header field. + An 'encoded-word' MUST NOT be used in parameter of a MIME Content-Type or Content-Disposition field, or in any structured field body except within a 'comment' or 'phrase'. The 'encoded-text' in an 'encoded-word' must be self-contained; 'encoded-text' MUST NOT be continued from one 'encoded-word' to another. This implies that the 'encoded-text' portion of a "B" 'encoded-word' will be a multiple of 4 characters long; for a "Q" 'encoded-word', any "=" character that appears in the 'encoded-text' portion will be followed by two hexadecimal characters. Each 'encoded-word' MUST encode an integral number of octets. The 'encoded-text' in each 'encoded-word' must be well-formed according to the encoding specified; the 'encoded-text' may not be continued in the next 'encoded-word'. (For example, "=?charset?Q?=?= =?charset?Q?AB?=" would be illegal, because the two hex digits "AB" must follow the "=" in the same 'encoded-word'.) Each 'encoded-word' MUST represent an integral number of characters. A multi-octet character may not be split across adjacent 'encoded- word's. Only printable and white space character data should be encoded using this scheme. However, since these encoding schemes allow the encoding of arbitrary octet values, mail readers that implement this decoding should also ensure that display of the decoded data on the recipient's terminal will not cause unwanted side-effects. Use of these methods to encode non-textual data (e.g., pictures or sounds) is not defined by this memo. Use of 'encoded-word's to represent strings of purely ASCII characters is allowed, but discouraged. In rare cases it may be necessary to encode ordinary text that looks like an 'encoded-word'. Moore Standards Track [Page 8] RFC 2047 Message Header Extensions November 1996 6. Support of 'encoded-word's by mail readers 6.1. Recognition of 'encoded-word's in message headers A mail reader must parse the message and body part headers according to the rules in RFC 822 to correctly recognize 'encoded-word's. 'encoded-word's are to be recognized as follows: (1) Any message or body part header field defined as '*text', or any user-defined header field, should be parsed as follows: Beginning at the start of the field-body and immediately following each occurrence of 'linear-white-space', each sequence of up to 75 printable characters (not containing any 'linear-white-space') should be examined to see if it is an 'encoded-word' according to the syntax rules in section 2. Any other sequence of printable characters should be treated as ordinary ASCII text. (2) Any header field not defined as '*text' should be parsed according to the syntax rules for that header field. However, any 'word' that appears within a 'phrase' should be treated as an 'encoded-word' if it meets the syntax rules in section 2. Otherwise it should be treated as an ordinary 'word'. (3) Within a 'comment', any sequence of up to 75 printable characters (not containing 'linear-white-space'), that meets the syntax rules in section 2, should be treated as an 'encoded-word'. Otherwise it should be treated as normal comment text. (4) A MIME-Version header field is NOT required to be present for 'encoded-word's to be interpreted according to this specification. One reason for this is that the mail reader is not expected to parse the entire message header before displaying lines that may contain 'encoded-word's. 6.2. Display of 'encoded-word's Any 'encoded-word's so recognized are decoded, and if possible, the resulting unencoded text is displayed in the original character set. NOTE: Decoding and display of encoded-words occurs *after* a structured field body is parsed into tokens. It is therefore possible to hide 'special' characters in encoded-words which, when displayed, will be indistinguishable from 'special' characters in the surrounding text. For this and other reasons, it is NOT generally possible to translate a message header containing 'encoded-word's to an unencoded form which can be parsed by an RFC 822 mail reader. Moore Standards Track [Page 9] RFC 2047 Message Header Extensions November 1996 When displaying a particular header field that contains multiple 'encoded-word's, any 'linear-white-space' that separates a pair of adjacent 'encoded-word's is ignored. (This is to allow the use of multiple 'encoded-word's to represent long strings of unencoded text, without having to separate 'encoded-word's where spaces occur in the unencoded text.) In the event other encodings are defined in the future, and the mail reader does not support the encoding used, it may either (a) display the 'encoded-word' as ordinary text, or (b) substitute an appropriate message indicating that the text could not be decoded. If the mail reader does not support the character set used, it may (a) display the 'encoded-word' as ordinary text (i.e., as it appears in the header), (b) make a "best effort" to display using such characters as are available, or (c) substitute an appropriate message indicating that the decoded text could not be displayed. If the character set being used employs code-switching techniques, display of the encoded text implicitly begins in "ASCII mode". In addition, the mail reader must ensure that the output device is once again in "ASCII mode" after the 'encoded-word' is displayed. 6.3. Mail reader handling of incorrectly formed 'encoded-word's It is possible that an 'encoded-word' that is legal according to the syntax defined in section 2, is incorrectly formed according to the rules for the encoding being used. For example: (1) An 'encoded-word' which contains characters which are not legal for a particular encoding (for example, a "-" in the "B" encoding, or a SPACE or HTAB in either the "B" or "Q" encoding), is incorrectly formed. (2) Any 'encoded-word' which encodes a non-integral number of characters or octets is incorrectly formed. A mail reader need not attempt to display the text associated with an 'encoded-word' that is incorrectly formed. However, a mail reader MUST NOT prevent the display or handling of a message because an 'encoded-word' is incorrectly formed. 7. Conformance A mail composing program claiming compliance with this specification MUST ensure that any string of non-white-space printable ASCII characters within a '*text' or '*ctext' that begins with "=?" and ends with "?=" be a valid 'encoded-word'. ("begins" means: at the Moore Standards Track [Page 10] RFC 2047 Message Header Extensions November 1996 start of the field-body, immediately following 'linear-white-space', or immediately following a "(" for an 'encoded-word' within '*ctext'; "ends" means: at the end of the field-body, immediately preceding 'linear-white-space', or immediately preceding a ")" for an 'encoded-word' within '*ctext'.) In addition, any 'word' within a 'phrase' that begins with "=?" and ends with "?=" must be a valid 'encoded-word'. A mail reading program claiming compliance with this specification must be able to distinguish 'encoded-word's from 'text', 'ctext', or 'word's, according to the rules in section 6, anytime they appear in appropriate places in message headers. It must support both the "B" and "Q" encodings for any character set which it supports. The program must be able to display the unencoded text if the character set is "US-ASCII". For the ISO-8859-* character sets, the mail reading program must at least be able to display the characters which are also in the ASCII set. 8. Examples The following are examples of message headers containing 'encoded- word's: From: =?US-ASCII?Q?Keith_Moore?= To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= CC: =?ISO-8859-1?Q?Andr=E9?= Pirard Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?= Note: In the first 'encoded-word' of the Subject field above, the last "=" at the end of the 'encoded-text' is necessary because each 'encoded-word' must be self-contained (the "=" character completes a group of 4 base64 characters representing 2 octets). An additional octet could have been encoded in the first 'encoded-word' (so that the encoded-word would contain an exact multiple of 3 encoded octets), except that the second 'encoded-word' uses a different 'charset' than the first one. From: =?ISO-8859-1?Q?Olle_J=E4rnefors?= To: ietf-822@dimacs.rutgers.edu, ojarnef@admin.kth.se Subject: Time for ISO 10646? To: Dave Crocker Cc: ietf-822@dimacs.rutgers.edu, paf@comsol.se From: =?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= Subject: Re: RFC-HDR care and feeding Moore Standards Track [Page 11] RFC 2047 Message Header Extensions November 1996 From: Nathaniel Borenstein (=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=) To: Greg Vaudreuil , Ned Freed , Keith Moore Subject: Test of new header generator MIME-Version: 1.0 Content-type: text/plain; charset=ISO-8859-1 The following examples illustrate how text containing 'encoded-word's which appear in a structured field body. The rules are slightly different for fields defined as '*text' because "(" and ")" are not recognized as 'comment' delimiters. [Section 5, paragraph (1)]. In each of the following examples, if the same sequence were to occur in a '*text' field, the "displayed as" form would NOT be treated as encoded words, but be identical to the "encoded form". This is because each of the encoded-words in the following examples is adjacent to a "(" or ")" character. encoded form displayed as --------------------------------------------------------------------- (=?ISO-8859-1?Q?a?=) (a) (=?ISO-8859-1?Q?a?= b) (a b) Within a 'comment', white space MUST appear between an 'encoded-word' and surrounding text. [Section 5, paragraph (2)]. However, white space is not needed between the initial "(" that begins the 'comment', and the 'encoded-word'. (=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (ab) White space between adjacent 'encoded-word's is not displayed. (=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (ab) Even multiple SPACEs between 'encoded-word's are ignored for the purpose of display. (=?ISO-8859-1?Q?a?= (ab) =?ISO-8859-1?Q?b?=) Any amount of linear-space-white between 'encoded-word's, even if it includes a CRLF followed by one or more SPACEs, is ignored for the purposes of display. Moore Standards Track [Page 12] RFC 2047 Message Header Extensions November 1996 (=?ISO-8859-1?Q?a_b?=) (a b) In order to cause a SPACE to be displayed within a portion of encoded text, the SPACE MUST be encoded as part of the 'encoded-word'. (=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=) (a b) In order to cause a SPACE to be displayed between two strings of encoded text, the SPACE MAY be encoded as part of one of the 'encoded-word's. 9. References [RFC 822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, UDEL, August 1982. [RFC 2049] Borenstein, N., and N. Freed, "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples", RFC 2049, November 1996. [RFC 2045] Borenstein, N., and N. Freed, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. [RFC 2046] Borenstein N., and N. Freed, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, November 1996. [RFC 2048] Freed, N., Klensin, J., and J. Postel, "Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures", RFC 2048, November 1996. Moore Standards Track [Page 13] RFC 2047 Message Header Extensions November 1996 10. Security Considerations Security issues are not discussed in this memo. 11. Acknowledgements The author wishes to thank Nathaniel Borenstein, Issac Chan, Lutz Donnerhacke, Paul Eggert, Ned Freed, Andreas M. Kirchwitz, Olle Jarnefors, Mike Rosin, Yutaka Sato, Bart Schaefer, and Kazuhiko Yamamoto, for their helpful advice, insightful comments, and illuminating questions in response to earlier versions of this specification. 12. Author's Address Keith Moore University of Tennessee 107 Ayres Hall Knoxville TN 37996-1301 EMail: moore@cs.utk.edu Moore Standards Track [Page 14] RFC 2047 Message Header Extensions November 1996 Appendix - changes since RFC 1522 (in no particular order) + explicitly state that the MIME-Version is not requried to use 'encoded-word's. + add explicit note that SPACEs and TABs are not allowed within 'encoded-word's, explaining that an 'encoded-word' must look like an 'atom' to an RFC822 parser.values, to be precise). + add examples from Olle Jarnefors (thanks!) which illustrate how encoded-words with adjacent linear-white-space are displayed. + explicitly list terms defined in RFC822 and referenced in this memo + fix transcription typos that caused one or two lines and a couple of characters to disappear in the resulting text, due to nroff quirks. + clarify that encoded-words are allowed in '*text' fields in both RFC822 headers and MIME body part headers, but NOT as parameter values. + clarify the requirement to switch back to ASCII within the encoded portion of an 'encoded-word', for any charset that uses code switching sequences. + add a note about 'encoded-word's being delimited by "(" and ")" within a comment, but not in a *text (how bizarre!). + fix the Andre Pirard example to get rid of the trailing "_" after the =E9. (no longer needed post-1342). + clarification: an 'encoded-word' may appear immediately following the initial "(" or immediately before the final ")" that delimits a comment, not just adjacent to "(" and ")" *within* *ctext. + add a note to explain that a "B" 'encoded-word' will always have a multiple of 4 characters in the 'encoded-text' portion. + add note about the "=" in the examples + note that processing of 'encoded-word's occurs *after* parsing, and some of the implications thereof. + explicitly state that you can't expect to translate between 1522 and either vanilla 822 or so-called "8-bit headers". + explicitly state that 'encoded-word's are not valid within a 'quoted-string'. Moore Standards Track [Page 15] mail-2.5.4/reference/rfc2048 Multipurpose Internet Mail Extensions (4).txt000066400000000000000000001277511214434061600257430ustar00rootroot00000000000000 Network Working Group N. Freed Request for Comments: 2048 Innosoft BCP: 13 J. Klensin Obsoletes: 1521, 1522, 1590 MCI Category: Best Current Practice J. Postel ISI November 1996 Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures Status of this Memo This document specifies an Internet Best Current Practices for the Internet Community, and requests discussion and suggestions for improvements. Distribution of this memo is unlimited. Abstract STD 11, RFC 822, defines a message representation protocol specifying considerable detail about US-ASCII message headers, and leaves the message content, or message body, as flat US-ASCII text. This set of documents, collectively called the Multipurpose Internet Mail Extensions, or MIME, redefines the format of messages to allow for (1) textual message bodies in character sets other than US-ASCII, (2) an extensible set of different formats for non-textual message bodies, (3) multi-part message bodies, and (4) textual header information in character sets other than US-ASCII. These documents are based on earlier work documented in RFC 934, STD 11, and RFC 1049, but extends and revises them. Because RFC 822 said so little about message bodies, these documents are largely orthogonal to (rather than a revision of) RFC 822. Freed, et. al. Best Current Practice [Page 1] RFC 2048 MIME Registration Procedures November 1996 This fourth document, RFC 2048, specifies various IANA registration procedures for the following MIME facilities: (1) media types, (2) external body access types, (3) content-transfer-encodings. Registration of character sets for use in MIME is covered elsewhere and is no longer addressed by this document. These documents are revisions of RFCs 1521 and 1522, which themselves were revisions of RFCs 1341 and 1342. An appendix in RFC 2049 describes differences and changes from previous versions. Table of Contents 1. Introduction ......................................... 3 2. Media Type Registration .............................. 4 2.1 Registration Trees and Subtype Names ................ 4 2.1.1 IETF Tree ......................................... 4 2.1.2 Vendor Tree ....................................... 4 2.1.3 Personal or Vanity Tree ........................... 5 2.1.4 Special `x.' Tree ................................. 5 2.1.5 Additional Registration Trees ..................... 6 2.2 Registration Requirements ........................... 6 2.2.1 Functionality Requirement ......................... 6 2.2.2 Naming Requirements ............................... 6 2.2.3 Parameter Requirements ............................ 7 2.2.4 Canonicalization and Format Requirements .......... 7 2.2.5 Interchange Recommendations ....................... 8 2.2.6 Security Requirements ............................. 8 2.2.7 Usage and Implementation Non-requirements ......... 9 2.2.8 Publication Requirements .......................... 10 2.2.9 Additional Information ............................ 10 2.3 Registration Procedure .............................. 11 2.3.1 Present the Media Type to the Community for Review 11 2.3.2 IESG Approval ..................................... 12 2.3.3 IANA Registration ................................. 12 2.4 Comments on Media Type Registrations ................ 12 2.5 Location of Registered Media Type List .............. 12 2.6 IANA Procedures for Registering Media Types ......... 12 2.7 Change Control ...................................... 13 2.8 Registration Template ............................... 14 3. External Body Access Types ........................... 14 3.1 Registration Requirements ........................... 15 3.1.1 Naming Requirements ............................... 15 Freed, et. al. Best Current Practice [Page 2] RFC 2048 MIME Registration Procedures November 1996 3.1.2 Mechanism Specification Requirements .............. 15 3.1.3 Publication Requirements .......................... 15 3.1.4 Security Requirements ............................. 15 3.2 Registration Procedure .............................. 15 3.2.1 Present the Access Type to the Community .......... 16 3.2.2 Access Type Reviewer .............................. 16 3.2.3 IANA Registration ................................. 16 3.3 Location of Registered Access Type List ............. 16 3.4 IANA Procedures for Registering Access Types ........ 16 4. Transfer Encodings ................................... 17 4.1 Transfer Encoding Requirements ...................... 17 4.1.1 Naming Requirements ............................... 17 4.1.2 Algorithm Specification Requirements .............. 18 4.1.3 Input Domain Requirements ......................... 18 4.1.4 Output Range Requirements ......................... 18 4.1.5 Data Integrity and Generality Requirements ........ 18 4.1.6 New Functionality Requirements .................... 18 4.2 Transfer Encoding Definition Procedure .............. 19 4.3 IANA Procedures for Transfer Encoding Registration... 19 4.4 Location of Registered Transfer Encodings List ...... 19 5. Authors' Addresses ................................... 20 A. Grandfathered Media Types ............................ 21 1. Introduction Recent Internet protocols have been carefully designed to be easily extensible in certain areas. In particular, MIME [RFC 2045] is an open-ended framework and can accommodate additional object types, character sets, and access methods without any changes to the basic protocol. A registration process is needed, however, to ensure that the set of such values is developed in an orderly, well-specified, and public manner. This document defines registration procedures which use the Internet Assigned Numbers Authority (IANA) as a central registry for such values. Historical Note: The registration process for media types was initially defined in the context of the asynchronous Internet mail environment. In this mail environment there is a need to limit the number of possible media types to increase the likelihood of interoperability when the capabilities of the remote mail system are not known. As media types are used in new environments, where the proliferation of media types is not a hindrance to interoperability, the original procedure was excessively restrictive and had to be generalized. Freed, et. al. Best Current Practice [Page 3] RFC 2048 MIME Registration Procedures November 1996 2. Media Type Registration Registration of a new media type or types starts with the construction of a registration proposal. Registration may occur in several different registration trees, which have different requirements as discussed below. In general, the new registration proposal is circulated and reviewed in a fashion appropriate to the tree involved. The media type is then registered if the proposal is acceptable. The following sections describe the requirements and procedures used for each of the different registration trees. 2.1. Registration Trees and Subtype Names In order to increase the efficiency and flexibility of the registration process, different structures of subtype names may be registered to accomodate the different natural requirements for, e.g., a subtype that will be recommended for wide support and implementation by the Internet Community or a subtype that is used to move files associated with proprietary software. The following subsections define registration "trees", distinguished by the use of faceted names (e.g., names of the form "tree.subtree...type"). Note that some media types defined prior to this document do not conform to the naming conventions described below. See Appendix A for a discussion of them. 2.1.1. IETF Tree The IETF tree is intended for types of general interest to the Internet Community. Registration in the IETF tree requires approval by the IESG and publication of the media type registration as some form of RFC. Media types in the IETF tree are normally denoted by names that are not explicitly faceted, i.e., do not contain period (".", full stop) characters. The "owner" of a media type registration in the IETF tree is assumed to be the IETF itself. Modification or alteration of the specification requires the same level of processing (e.g. standards track) required for the initial registration. 2.1.2. Vendor Tree The vendor tree is used for media types associated with commercially available products. "Vendor" or "producer" are construed as equivalent and very broadly in this context. Freed, et. al. Best Current Practice [Page 4] RFC 2048 MIME Registration Procedures November 1996 A registration may be placed in the vendor tree by anyone who has need to interchange files associated with the particular product. However, the registration formally belongs to the vendor or organization producing the software or file format. Changes to the specification will be made at their request, as discussed in subsequent sections. Registrations in the vendor tree will be distinguished by the leading facet "vnd.". That may be followed, at the discretion of the registration, by either a media type name from a well-known producer (e.g., "vnd.mudpie") or by an IANA-approved designation of the producer's name which is then followed by a media type or product designation (e.g., vnd.bigcompany.funnypictures). While public exposure and review of media types to be registered in the vendor tree is not required, using the ietf-types list for review is strongly encouraged to improve the quality of those specifications. Registrations in the vendor tree may be submitted directly to the IANA. 2.1.3. Personal or Vanity Tree Registrations for media types created experimentally or as part of products that are not distributed commercially may be registered in the personal or vanity tree. The registrations are distinguished by the leading facet "prs.". The owner of "personal" registrations and associated specifications is the person or entity making the registration, or one to whom responsibility has been transferred as described below. While public exposure and review of media types to be registered in the personal tree is not required, using the ietf-types list for review is strongly encouraged to improve the quality of those specifications. Registrations in the personl tree may be submitted directly to the IANA. 2.1.4. Special `x.' Tree For convenience and symmetry with this registration scheme, media type names with "x." as the first facet may be used for the same purposes for which names starting in "x-" are normally used. These types are unregistered, experimental, and should be used only with the active agreement of the parties exchanging them. Freed, et. al. Best Current Practice [Page 5] RFC 2048 MIME Registration Procedures November 1996 However, with the simplified registration procedures described above for vendor and personal trees, it should rarely, if ever, be necessary to use unregistered experimental types, and as such use of both "x-" and "x." forms is discouraged. 2.1.5. Additional Registration Trees From time to time and as required by the community, the IANA may, with the advice and consent of the IESG, create new top-level registration trees. It is explicitly assumed that these trees may be created for external registration and management by well-known permanent bodies, such as scientific societies for media types specific to the sciences they cover. In general, the quality of review of specifications for one of these additional registration trees is expected to be equivalent to that which IETF would give to registrations in its own tree. Establishment of these new trees will be announced through RFC publication approved by the IESG. 2.2. Registration Requirements Media type registration proposals are all expected to conform to various requirements laid out in the following sections. Note that requirement specifics sometimes vary depending on the registration tree, again as detailed in the following sections. 2.2.1. Functionality Requirement Media types must function as an actual media format: Registration of things that are better thought of as a transfer encoding, as a character set, or as a collection of separate entities of another type, is not allowed. For example, although applications exist to decode the base64 transfer encoding [RFC 2045], base64 cannot be registered as a media type. This requirement applies regardless of the registration tree involved. 2.2.2. Naming Requirements All registered media types must be assigned MIME type and subtype names. The combination of these names then serves to uniquely identify the media type and the format of the subtype name identifies the registration tree. The choice of top-level type name must take the nature of media type involved into account. For example, media normally used for representing still images should be a subtype of the image content type, whereas media capable of representing audio information belongs Freed, et. al. Best Current Practice [Page 6] RFC 2048 MIME Registration Procedures November 1996 under the audio content type. See RFC 2046 for additional information on the basic set of top-level types and their characteristics. New subtypes of top-level types must conform to the restrictions of the top-level type, if any. For example, all subtypes of the multipart content type must use the same encapsulation syntax. In some cases a new media type may not "fit" under any currently defined top-level content type. Such cases are expected to be quite rare. However, if such a case arises a new top-level type can be defined to accommodate it. Such a definition must be done via standards-track RFC; no other mechanism can be used to define additional top-level content types. These requirements apply regardless of the registration tree involved. 2.2.3. Parameter Requirements Media types may elect to use one or more MIME content type parameters, or some parameters may be automatically made available to the media type by virtue of being a subtype of a content type that defines a set of parameters applicable to any of its subtypes. In either case, the names, values, and meanings of any parameters must be fully specified when a media type is registered in the IETF tree, and should be specified as completely as possible when media types are registered in the vendor or personal trees. New parameters must not be defined as a way to introduce new functionality in types registered in the IETF tree, although new parameters may be added to convey additional information that does not otherwise change existing functionality. An example of this would be a "revision" parameter to indicate a revision level of an external specification such as JPEG. Similar behavior is encouraged for media types registered in the vendor or personal trees but is not required. 2.2.4. Canonicalization and Format Requirements All registered media types must employ a single, canonical data format, regardless of registration tree. A precise and openly available specification of the format of each media type is required for all types registered in the IETF tree and must at a minimum be referenced by, if it isn't actually included in, the media type registration proposal itself. Freed, et. al. Best Current Practice [Page 7] RFC 2048 MIME Registration Procedures November 1996 The specifications of format and processing particulars may or may not be publically available for media types registered in the vendor tree, and such registration proposals are explicitly permitted to include only a specification of which software and version produce or process such media types. References to or inclusion of format specifications in registration proposals is encouraged but not required. Format specifications are still required for registration in the personal tree, but may be either published as RFCs or otherwise deposited with IANA. The deposited specifications will meet the same criteria as those required to register a well-known TCP port and, in particular, need not be made public. Some media types involve the use of patented technology. The registration of media types involving patented technology is specifically permitted. However, the restrictions set forth in RFC 1602 on the use of patented technology in standards-track protocols must be respected when the specification of a media type is part of a standards-track protocol. 2.2.5. Interchange Recommendations Media types should, whenever possible, interoperate across as many systems and applications as possible. However, some media types will inevitably have problems interoperating across different platforms. Problems with different versions, byte ordering, and specifics of gateway handling can and will arise. Universal interoperability of media types is not required, but known interoperability issues should be identified whenever possible. Publication of a media type does not require an exhaustive review of interoperability, and the interoperability considerations section is subject to continuing evaluation. These recommendations apply regardless of the registration tree involved. 2.2.6. Security Requirements An analysis of security issues is required for for all types registered in the IETF Tree. (This is in accordance with the basic requirements for all IETF protocols.) A similar analysis for media types registered in the vendor or personal trees is encouraged but not required. However, regardless of what security analysis has or has not been done, all descriptions of security issues must be as accurate as possible regardless of registration tree. In particular, a statement that there are "no security issues associated with this Freed, et. al. Best Current Practice [Page 8] RFC 2048 MIME Registration Procedures November 1996 type" must not be confused with "the security issues associates with this type have not been assessed". There is absolutely no requirement that media types registered in any tree be secure or completely free from risks. Nevertheless, all known security risks must be identified in the registration of a media type, again regardless of registration tree. The security considerations section of all registrations is subject to continuing evaluation and modification, and in particular may be extended by use of the "comments on media types" mechanism described in subsequent sections. Some of the issues that should be looked at in a security analysis of a media type are: (1) Complex media types may include provisions for directives that institute actions on a recipient's files or other resources. In many cases provision is made for originators to specify arbitrary actions in an unrestricted fashion which may then have devastating effects. See the registration of the application/postscript media type in RFC 2046 for an example of such directives and how to handle them. (2) Complex media types may include provisions for directives that institute actions which, while not directly harmful to the recipient, may result in disclosure of information that either facilitates a subsequent attack or else violates a recipient's privacy in some way. Again, the registration of the application/postscript media type illustrates how such directives can be handled. (3) A media type might be targeted for applications that require some sort of security assurance but not provide the necessary security mechanisms themselves. For example, a media type could be defined for storage of confidential medical information which in turn requires an external confidentiality service. 2.2.7. Usage and Implementation Non-requirements In the asynchronous mail environment, where information on the capabilities of the remote mail agent is frequently not available to the sender, maximum interoperability is attained by restricting the number of media types used to those "common" formats expected to be widely implemented. This was asserted in the past as a reason to Freed, et. al. Best Current Practice [Page 9] RFC 2048 MIME Registration Procedures November 1996 limit the number of possible media types and resulted in a registration process with a significant hurdle and delay for those registering media types. However, the need for "common" media types does not require limiting the registration of new media types. If a limited set of media types is recommended for a particular application, that should be asserted by a separate applicability statement specific for the application and/or environment. As such, universal support and implementation of a media type is NOT a requirement for registration. If, however, a media type is explicitly intended for limited use, this should be noted in its registration. 2.2.8. Publication Requirements Proposals for media types registered in the IETF tree must be published as RFCs. RFC publication of vendor and personal media type proposals is encouraged but not required. In all cases IANA will retain copies of all media type proposals and "publish" them as part of the media types registration tree itself. Other than in the IETF tree, the registration of a data type does not imply endorsement, approval, or recommendation by IANA or IETF or even certification that the specification is adequate. To become Internet Standards, protocol, data objects, or whatever must go through the IETF standards process. This is too difficult and too lengthy a process for the convenient registration of media types. The IETF tree exists for media types that do require require a substantive review and approval process with the vendor and personal trees exist for those that do not. It is expected that applicability statements for particular applications will be published from time to time that recommend implementation of, and support for, media types that have proven particularly useful in those contexts. As discussed above, registration of a top-level type requires standards-track processing and, hence, RFC publication. 2.2.9. Additional Information Various sorts of optional information may be included in the specification of a media type if it is available: (1) Magic number(s) (length, octet values). Magic numbers are byte sequences that are always present and thus can be used to identify entities as being of a given media Freed, et. al. Best Current Practice [Page 10] RFC 2048 MIME Registration Procedures November 1996 type. (2) File extension(s) commonly used on one or more platforms to indicate that some file containing a given type of media. (3) Macintosh File Type code(s) (4 octets) used to label files containing a given type of media. Such information is often quite useful to implementors and if available should be provided. 2.3. Registration Procedure The following procedure has been implemented by the IANA for review and approval of new media types. This is not a formal standards process, but rather an administrative procedure intended to allow community comment and sanity checking without excessive time delay. For registration in the IETF tree, the normal IETF processes should be followed, treating posting of an internet-draft and announcement on the ietf-types list (as described in the next subsection) as a first step. For registrations in the vendor or personal tree, the initial review step described below may be omitted and the type registered directly by submitting the template and an explanation directly to IANA (at iana@iana.org). However, authors of vendor or personal media type specifications are encouraged to seek community review and comment whenever that is feasible. 2.3.1. Present the Media Type to the Community for Review Send a proposed media type registration to the "ietf-types@iana.org" mailing list for a two week review period. This mailing list has been established for the purpose of reviewing proposed media and access types. Proposed media types are not formally registered and must not be used; the "x-" prefix specified in RFC 2045 can be used until registration is complete. The intent of the public posting is to solicit comments and feedback on the choice of type/subtype name, the unambiguity of the references with respect to versions and external profiling information, and a review of any interoperability or security considerations. The submitter may submit a revised registration, or withdraw the registration completely, at any time. Freed, et. al. Best Current Practice [Page 11] RFC 2048 MIME Registration Procedures November 1996 2.3.2. IESG Approval Media types registered in the IETF tree must be submitted to the IESG for approval. 2.3.3. IANA Registration Provided that the media type meets the requirements for media types and has obtained approval that is necessary, the author may submit the registration request to the IANA, which will register the media type and make the media type registration available to the community. 2.4. Comments on Media Type Registrations Comments on registered media types may be submitted by members of the community to IANA. These comments will be passed on to the "owner" of the media type if possible. Submitters of comments may request that their comment be attached to the media type registration itself, and if IANA approves of this the comment will be made accessible in conjunction with the type registration itself. 2.5. Location of Registered Media Type List Media type registrations will be posted in the anonymous FTP directory "ftp://ftp.isi.edu/in-notes/iana/assignments/media-types/" and all registered media types will be listed in the periodically issued "Assigned Numbers" RFC [currently STD 2, RFC 1700]. The media type description and other supporting material may also be published as an Informational RFC by sending it to "rfc-editor@isi.edu" (please follow the instructions to RFC authors [RFC-1543]). 2.6. IANA Procedures for Registering Media Types The IANA will only register media types in the IETF tree in response to a communication from the IESG stating that a given registration has been approved. Vendor and personal types will be registered by the IANA automatically and without any formal review as long as the following minimal conditions are met: (1) Media types must function as an actual media format. In particular, character sets and transfer encodings may not be registered as media types. (2) All media types must have properly formed type and subtype names. All type names must be defined by a standards-track RFC. All subtype names must be unique, must conform to the MIME grammar for such names, and must contain the proper tree prefix. Freed, et. al. Best Current Practice [Page 12] RFC 2048 MIME Registration Procedures November 1996 (3) Types registered in the personal tree must either provide a format specification or a pointer to one. (4) Any security considerations given must not be obviously bogus. (It is neither possible nor necessary for the IANA to conduct a comprehensive security review of media type registrations. Nevertheless, IANA has the authority to identify obviously incompetent material and exclude it.) 2.7. Change Control Once a media type has been published by IANA, the author may request a change to its definition. The descriptions of the different registration trees above designate the "owners" of each type of registration. The change request follows the same procedure as the registration request: (1) Publish the revised template on the ietf-types list. (2) Leave at least two weeks for comments. (3) Publish using IANA after formal review if required. Changes should be requested only when there are serious omission or errors in the published specification. When review is required, a change request may be denied if it renders entities that were valid under the previous definition invalid under the new definition. The owner of a content type may pass responsibility for the content type to another person or agency by informing IANA and the ietf-types list; this can be done without discussion or review. The IESG may reassign responsibility for a media type. The most common case of this will be to enable changes to be made to types where the author of the registration has died, moved out of contact or is otherwise unable to make changes that are important to the community. Media type registrations may not be deleted; media types which are no longer believed appropriate for use can be declared OBSOLETE by a change to their "intended use" field; such media types will be clearly marked in the lists published by IANA. Freed, et. al. Best Current Practice [Page 13] RFC 2048 MIME Registration Procedures November 1996 2.8. Registration Template To: ietf-types@iana.org Subject: Registration of MIME media type XXX/YYY MIME media type name: MIME subtype name: Required parameters: Optional parameters: Encoding considerations: Security considerations: Interoperability considerations: Published specification: Applications which use this media type: Additional information: Magic number(s): File extension(s): Macintosh File Type Code(s): Person & email address to contact for further information: Intended usage: (One of COMMON, LIMITED USE or OBSOLETE) Author/Change controller: (Any other information that the author deems interesting may be added below this line.) 3. External Body Access Types RFC 2046 defines the message/external-body media type, whereby a MIME entity can act as pointer to the actual body data in lieu of including the data directly in the entity body. Each message/external-body reference specifies an access type, which determines the mechanism used to retrieve the actual body data. RFC 2046 defines an initial set of access types, but allows for the Freed, et. al. Best Current Practice [Page 14] RFC 2048 MIME Registration Procedures November 1996 registration of additional access types to accommodate new retrieval mechanisms. 3.1. Registration Requirements New access type specifications must conform to a number of requirements as described below. 3.1.1. Naming Requirements Each access type must have a unique name. This name appears in the access-type parameter in the message/external-body content-type header field, and must conform to MIME content type parameter syntax. 3.1.2. Mechanism Specification Requirements All of the protocols, transports, and procedures used by a given access type must be described, either in the specification of the access type itself or in some other publicly available specification, in sufficient detail for the access type to be implemented by any competent implementor. Use of secret and/or proprietary methods in access types are expressly prohibited. The restrictions imposed by RFC 1602 on the standardization of patented algorithms must be respected as well. 3.1.3. Publication Requirements All access types must be described by an RFC. The RFC may be informational rather than standards-track, although standard-track review and approval are encouraged for all access types. 3.1.4. Security Requirements Any known security issues that arise from the use of the access type must be completely and fully described. It is not required that the access type be secure or that it be free from risks, but that the known risks be identified. Publication of a new access type does not require an exhaustive security review, and the security considerations section is subject to continuing evaluation. Additional security considerations should be addressed by publishing revised versions of the access type specification. 3.2. Registration Procedure Registration of a new access type starts with the construction of a draft of an RFC. Freed, et. al. Best Current Practice [Page 15] RFC 2048 MIME Registration Procedures November 1996 3.2.1. Present the Access Type to the Community Send a proposed access type specification to the "ietf- types@iana.org" mailing list for a two week review period. This mailing list has been established for the purpose of reviewing proposed access and media types. Proposed access types are not formally registered and must not be used. The intent of the public posting is to solicit comments and feedback on the access type specification and a review of any security considerations. 3.2.2. Access Type Reviewer When the two week period has passed, the access type reviewer, who is appointed by the IETF Applications Area Director, either forwards the request to iana@isi.edu, or rejects it because of significant objections raised on the list. Decisions made by the reviewer must be posted to the ietf-types mailing list within 14 days. Decisions made by the reviewer may be appealed to the IESG. 3.2.3. IANA Registration Provided that the access type has either passed review or has been successfully appealed to the IESG, the IANA will register the access type and make the registration available to the community. The specification of the access type must also be published as an RFC. Informational RFCs are published by sending them to "rfc- editor@isi.edu" (please follow the instructions to RFC authors [RFC- 1543]). 3.3. Location of Registered Access Type List Access type registrations will be posted in the anonymous FTP directory "ftp://ftp.isi.edu/in-notes/iana/assignments/access-types/" and all registered access types will be listed in the periodically issued "Assigned Numbers" RFC [currently RFC-1700]. 3.4. IANA Procedures for Registering Access Types The identity of the access type reviewer is communicated to the IANA by the IESG. The IANA then only acts in response to access type definitions that either are approved by the access type reviewer and forwarded by the reviewer to the IANA for registration, or in response to a communication from the IESG that an access type definition appeal has overturned the access type reviewer's ruling. Freed, et. al. Best Current Practice [Page 16] RFC 2048 MIME Registration Procedures November 1996 4. Transfer Encodings Transfer encodings are tranformations applied to MIME media types after conversion to the media type's canonical form. Transfer encodings are used for several purposes: (1) Many transports, especially message transports, can only handle data consisting of relatively short lines of text. There can also be severe restrictions on what characters can be used in these lines of text -- some transports are restricted to a small subset of US-ASCII and others cannot handle certain character sequences. Transfer encodings are used to transform binary data into textual form that can survive such transports. Examples of this sort of transfer encoding include the base64 and quoted-printable transfer encodings defined in RFC 2045. (2) Image, audio, video, and even application entities are sometimes quite large. Compression algorithms are often quite effective in reducing the size of large entities. Transfer encodings can be used to apply general-purpose non-lossy compression algorithms to MIME entities. (3) Transport encodings can be defined as a means of representing existing encoding formats in a MIME context. IMPORTANT: The standardization of a large numbers of different transfer encodings is seen as a significant barrier to widespread interoperability and is expressely discouraged. Nevertheless, the following procedure has been defined to provide a means of defining additional transfer encodings, should standardization actually be justified. 4.1. Transfer Encoding Requirements Transfer encoding specifications must conform to a number of requirements as described below. 4.1.1. Naming Requirements Each transfer encoding must have a unique name. This name appears in the Content-Transfer-Encoding header field and must conform to the syntax of that field. Freed, et. al. Best Current Practice [Page 17] RFC 2048 MIME Registration Procedures November 1996 4.1.2. Algorithm Specification Requirements All of the algorithms used in a transfer encoding (e.g. conversion to printable form, compression) must be described in their entirety in the transfer encoding specification. Use of secret and/or proprietary algorithms in standardized transfer encodings are expressly prohibited. The restrictions imposed by RFC 1602 on the standardization of patented algorithms must be respected as well. 4.1.3. Input Domain Requirements All transfer encodings must be applicable to an arbitrary sequence of octets of any length. Dependence on particular input forms is not allowed. It should be noted that the 7bit and 8bit encodings do not conform to this requirement. Aside from the undesireability of having specialized encodings, the intent here is to forbid the addition of additional encodings along the lines of 7bit and 8bit. 4.1.4. Output Range Requirements There is no requirement that a particular tranfer encoding produce a particular form of encoded output. However, the output format for each transfer encoding must be fully and completely documented. In particular, each specification must clearly state whether the output format always lies within the confines of 7bit data, 8bit data, or is simply pure binary data. 4.1.5. Data Integrity and Generality Requirements All transfer encodings must be fully invertible on any platform; it must be possible for anyone to recover the original data by performing the corresponding decoding operation. Note that this requirement effectively excludes all forms of lossy compression as well as all forms of encryption from use as a transfer encoding. 4.1.6. New Functionality Requirements All transfer encodings must provide some sort of new functionality. Some degree of functionality overlap with previously defined transfer encodings is acceptable, but any new transfer encoding must also offer something no other transfer encoding provides. Freed, et. al. Best Current Practice [Page 18] RFC 2048 MIME Registration Procedures November 1996 4.2. Transfer Encoding Definition Procedure Definition of a new transfer encoding starts with the construction of a draft of a standards-track RFC. The RFC must define the transfer encoding precisely and completely, and must also provide substantial justification for defining and standardizing a new transfer encoding. This specification must then be presented to the IESG for consideration. The IESG can (1) reject the specification outright as being inappropriate for standardization, (2) approve the formation of an IETF working group to work on the specification in accordance with IETF procedures, or, (3) accept the specification as-is and put it directly on the standards track. Transfer encoding specifications on the standards track follow normal IETF rules for standards track documents. A transfer encoding is considered to be defined and available for use once it is on the standards track. 4.3. IANA Procedures for Transfer Encoding Registration There is no need for a special procedure for registering Transfer Encodings with the IANA. All legitimate transfer encoding registrations must appear as a standards-track RFC, so it is the IESG's responsibility to notify the IANA when a new transfer encoding has been approved. 4.4. Location of Registered Transfer Encodings List Transfer encoding registrations will be posted in the anonymous FTP directory "ftp://ftp.isi.edu/in-notes/iana/assignments/transfer- encodings/" and all registered transfer encodings will be listed in the periodically issued "Assigned Numbers" RFC [currently RFC-1700]. Freed, et. al. Best Current Practice [Page 19] RFC 2048 MIME Registration Procedures November 1996 5. Authors' Addresses For more information, the authors of this document are best contacted via Internet mail: Ned Freed Innosoft International, Inc. 1050 East Garvey Avenue South West Covina, CA 91790 USA Phone: +1 818 919 3600 Fax: +1 818 919 3614 EMail: ned@innosoft.com John Klensin MCI 2100 Reston Parkway Reston, VA 22091 Phone: +1 703 715-7361 Fax: +1 703 715-7436 EMail: klensin@mci.net Jon Postel USC/Information Sciences Institute 4676 Admiralty Way Marina del Rey, CA 90292 USA Phone: +1 310 822 1511 Fax: +1 310 823 6714 EMail: Postel@ISI.EDU Freed, et. al. Best Current Practice [Page 20] RFC 2048 MIME Registration Procedures November 1996 Appendix A -- Grandfathered Media Types A number of media types, registered prior to 1996, would, if registered under the guidelines in this document, be placed into either the vendor or personal trees. Reregistration of those types to reflect the appropriate trees is encouraged, but not required. Ownership and change control principles outlined in this document apply to those types as if they had been registered in the trees described above. Freed, et. al. Best Current Practice [Page 21] mail-2.5.4/reference/rfc2049 Multipurpose Internet Mail Extensions (5).txt000066400000000000000000001440061214434061600257350ustar00rootroot00000000000000 Network Working Group N. Freed Request for Comments: 2049 Innosoft Obsoletes: 1521, 1522, 1590 N. Borenstein Category: Standards Track First Virtual November 1996 Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples 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. Abstract STD 11, RFC 822, defines a message representation protocol specifying considerable detail about US-ASCII message headers, and leaves the message content, or message body, as flat US-ASCII text. This set of documents, collectively called the Multipurpose Internet Mail Extensions, or MIME, redefines the format of messages to allow for (1) textual message bodies in character sets other than US-ASCII, (2) an extensible set of different formats for non-textual message bodies, (3) multi-part message bodies, and (4) textual header information in character sets other than US-ASCII. These documents are based on earlier work documented in RFC 934, STD 11, and RFC 1049, but extends and revises them. Because RFC 822 said so little about message bodies, these documents are largely orthogonal to (rather than a revision of) RFC 822. The initial document in this set, RFC 2045, specifies the various headers used to describe the structure of MIME messages. The second document defines the general structure of the MIME media typing system and defines an initial set of media types. The third document, RFC 2047, describes extensions to RFC 822 to allow non-US- Freed & Borenstein Standards Track [Page 1] RFC 2049 MIME Conformance November 1996 ASCII text data in Internet mail header fields. The fourth document, RFC 2048, specifies various IANA registration procedures for MIME- related facilities. This fifth and final document describes MIME conformance criteria as well as providing some illustrative examples of MIME message formats, acknowledgements, and the bibliography. These documents are revisions of RFCs 1521, 1522, and 1590, which themselves were revisions of RFCs 1341 and 1342. Appendix B of this document describes differences and changes from previous versions. Table of Contents 1. Introduction .......................................... 2 2. MIME Conformance ...................................... 2 3. Guidelines for Sending Email Data ..................... 6 4. Canonical Encoding Model .............................. 9 5. Summary ............................................... 12 6. Security Considerations ............................... 12 7. Authors' Addresses .................................... 12 8. Acknowledgements ...................................... 13 A. A Complex Multipart Example ........................... 15 B. Changes from RFC 1521, 1522, and 1590 ................. 16 C. References ............................................ 20 1. Introduction The first and second documents in this set define MIME header fields and the initial set of MIME media types. The third document describes extensions to RFC822 formats to allow for character sets other than US-ASCII. This document describes what portions of MIME must be supported by a conformant MIME implementation. It also describes various pitfalls of contemporary messaging systems as well as the canonical encoding model MIME is based on. 2. MIME Conformance The mechanisms described in these documents are open-ended. It is definitely not expected that all implementations will support all available media types, nor that they will all share the same extensions. In order to promote interoperability, however, it is useful to define the concept of "MIME-conformance" to define a certain level of implementation that allows the useful interworking of messages with content that differs from US-ASCII text. In this section, we specify the requirements for such conformance. Freed & Borenstein Standards Track [Page 2] RFC 2049 MIME Conformance November 1996 A mail user agent that is MIME-conformant MUST: (1) Always generate a "MIME-Version: 1.0" header field in any message it creates. (2) Recognize the Content-Transfer-Encoding header field and decode all received data encoded by either quoted- printable or base64 implementations. The identity transformations 7bit, 8bit, and binary must also be recognized. Any non-7bit data that is sent without encoding must be properly labelled with a content-transfer-encoding of 8bit or binary, as appropriate. If the underlying transport does not support 8bit or binary (as SMTP [RFC-821] does not), the sender is required to both encode and label data using an appropriate Content- Transfer-Encoding such as quoted-printable or base64. (3) Must treat any unrecognized Content-Transfer-Encoding as if it had a Content-Type of "application/octet- stream", regardless of whether or not the actual Content-Type is recognized. (4) Recognize and interpret the Content-Type header field, and avoid showing users raw data with a Content-Type field other than text. Implementations must be able to send at least text/plain messages, with the character set specified with the charset parameter if it is not US-ASCII. (5) Ignore any content type parameters whose names they do not recognize. (6) Explicitly handle the following media type values, to at least the following extents: Text: -- Recognize and display "text" mail with the character set "US-ASCII." -- Recognize other character sets at least to the extent of being able to inform the user about what character set the message uses. Freed & Borenstein Standards Track [Page 3] RFC 2049 MIME Conformance November 1996 -- Recognize the "ISO-8859-*" character sets to the extent of being able to display those characters that are common to ISO-8859-* and US-ASCII, namely all characters represented by octet values 1-127. -- For unrecognized subtypes in a known character set, show or offer to show the user the "raw" version of the data after conversion of the content from canonical form to local form. -- Treat material in an unknown character set as if it were "application/octet-stream". Image, audio, and video: -- At a minumum provide facilities to treat any unrecognized subtypes as if they were "application/octet-stream". Application: -- Offer the ability to remove either of the quoted- printable or base64 encodings defined in this document if they were used and put the resulting information in a user file. Multipart: -- Recognize the mixed subtype. Display all relevant information on the message level and the body part header level and then display or offer to display each of the body parts individually. -- Recognize the "alternative" subtype, and avoid showing the user redundant parts of multipart/alternative mail. -- Recognize the "multipart/digest" subtype, specifically using "message/rfc822" rather than "text/plain" as the default media type for body parts inside "multipart/digest" entities. -- Treat any unrecognized subtypes as if they were "mixed". Freed & Borenstein Standards Track [Page 4] RFC 2049 MIME Conformance November 1996 Message: -- Recognize and display at least the RFC822 message encapsulation (message/rfc822) in such a way as to preserve any recursive structure, that is, displaying or offering to display the encapsulated data in accordance with its media type. -- Treat any unrecognized subtypes as if they were "application/octet-stream". (7) Upon encountering any unrecognized Content-Type field, an implementation must treat it as if it had a media type of "application/octet-stream" with no parameter sub-arguments. How such data are handled is up to an implementation, but likely options for handling such unrecognized data include offering the user to write it into a file (decoded from its mail transport format) or offering the user to name a program to which the decoded data should be passed as input. (8) Conformant user agents are required, if they provide non-standard support for non-MIME messages employing character sets other than US-ASCII, to do so on received messages only. Conforming user agents must not send non-MIME messages containing anything other than US-ASCII text. In particular, the use of non-US-ASCII text in mail messages without a MIME-Version field is strongly discouraged as it impedes interoperability when sending messages between regions with different localization conventions. Conforming user agents MUST include proper MIME labelling when sending anything other than plain text in the US-ASCII character set. In addition, non-MIME user agents should be upgraded if at all possible to include appropriate MIME header information in the messages they send even if nothing else in MIME is supported. This upgrade will have little, if any, effect on non-MIME recipients and will aid MIME in correctly displaying such messages. It also provides a smooth transition path to eventual adoption of other MIME capabilities. (9) Conforming user agents must ensure that any string of non-white-space printable US-ASCII characters within a "*text" or "*ctext" that begins with "=?" and ends with Freed & Borenstein Standards Track [Page 5] RFC 2049 MIME Conformance November 1996 "?=" be a valid encoded-word. ("begins" means: At the start of the field-body or immediately following linear-white-space; "ends" means: At the end of the field-body or immediately preceding linear-white- space.) In addition, any "word" within a "phrase" that begins with "=?" and ends with "?=" must be a valid encoded-word. (10) Conforming user agents must be able to distinguish encoded-words from "text", "ctext", or "word"s, according to the rules in section 4, anytime they appear in appropriate places in message headers. It must support both the "B" and "Q" encodings for any character set which it supports. The program must be able to display the unencoded text if the character set is "US-ASCII". For the ISO-8859-* character sets, the mail reading program must at least be able to display the characters which are also in the US-ASCII set. A user agent that meets the above conditions is said to be MIME- conformant. The meaning of this phrase is that it is assumed to be "safe" to send virtually any kind of properly-marked data to users of such mail systems, because such systems will at least be able to treat the data as undifferentiated binary, and will not simply splash it onto the screen of unsuspecting users. There is another sense in which it is always "safe" to send data in a format that is MIME-conformant, which is that such data will not break or be broken by any known systems that are conformant with RFC 821 and RFC 822. User agents that are MIME-conformant have the additional guarantee that the user will not be shown data that were never intended to be viewed as text. 3. Guidelines for Sending Email Data Internet email is not a perfect, homogeneous system. Mail may become corrupted at several stages in its travel to a final destination. Specifically, email sent throughout the Internet may travel across many networking technologies. Many networking and mail technologies do not support the full functionality possible in the SMTP transport environment. Mail traversing these systems is likely to be modified in order that it can be transported. There exist many widely-deployed non-conformant MTAs in the Internet. These MTAs, speaking the SMTP protocol, alter messages on the fly to take advantage of the internal data structure of the hosts they are implemented on, or are just plain broken. Freed & Borenstein Standards Track [Page 6] RFC 2049 MIME Conformance November 1996 The following guidelines may be useful to anyone devising a data format (media type) that is supposed to survive the widest range of networking technologies and known broken MTAs unscathed. Note that anything encoded in the base64 encoding will satisfy these rules, but that some well-known mechanisms, notably the UNIX uuencode facility, will not. Note also that anything encoded in the Quoted-Printable encoding will survive most gateways intact, but possibly not some gateways to systems that use the EBCDIC character set. (1) Under some circumstances the encoding used for data may change as part of normal gateway or user agent operation. In particular, conversion from base64 to quoted-printable and vice versa may be necessary. This may result in the confusion of CRLF sequences with line breaks in text bodies. As such, the persistence of CRLF as something other than a line break must not be relied on. (2) Many systems may elect to represent and store text data using local newline conventions. Local newline conventions may not match the RFC822 CRLF convention -- systems are known that use plain CR, plain LF, CRLF, or counted records. The result is that isolated CR and LF characters are not well tolerated in general; they may be lost or converted to delimiters on some systems, and hence must not be relied on. (3) The transmission of NULs (US-ASCII value 0) is problematic in Internet mail. (This is largely the result of NULs being used as a termination character by many of the standard runtime library routines in the C programming language.) The practice of using NULs as termination characters is so entrenched now that messages should not rely on them being preserved. (4) TAB (HT) characters may be misinterpreted or may be automatically converted to variable numbers of spaces. This is unavoidable in some environments, notably those not based on the US-ASCII character set. Such conversion is STRONGLY DISCOURAGED, but it may occur, and mail formats must not rely on the persistence of TAB (HT) characters. (5) Lines longer than 76 characters may be wrapped or truncated in some environments. Line wrapping or line truncation imposed by mail transports is STRONGLY DISCOURAGED, but unavoidable in some cases. Applications which require long lines must somehow Freed & Borenstein Standards Track [Page 7] RFC 2049 MIME Conformance November 1996 differentiate between soft and hard line breaks. (A simple way to do this is to use the quoted-printable encoding.) (6) Trailing "white space" characters (SPACE, TAB (HT)) on a line may be discarded by some transport agents, while other transport agents may pad lines with these characters so that all lines in a mail file are of equal length. The persistence of trailing white space, therefore, must not be relied on. (7) Many mail domains use variations on the US-ASCII character set, or use character sets such as EBCDIC which contain most but not all of the US-ASCII characters. The correct translation of characters not in the "invariant" set cannot be depended on across character converting gateways. For example, this situation is a problem when sending uuencoded information across BITNET, an EBCDIC system. Similar problems can occur without crossing a gateway, since many Internet hosts use character sets other than US- ASCII internally. The definition of Printable Strings in X.400 adds further restrictions in certain special cases. In particular, the only characters that are known to be consistent across all gateways are the 73 characters that correspond to the upper and lower case letters A-Z and a-z, the 10 digits 0-9, and the following eleven special characters: "'" (US-ASCII decimal value 39) "(" (US-ASCII decimal value 40) ")" (US-ASCII decimal value 41) "+" (US-ASCII decimal value 43) "," (US-ASCII decimal value 44) "-" (US-ASCII decimal value 45) "." (US-ASCII decimal value 46) "/" (US-ASCII decimal value 47) ":" (US-ASCII decimal value 58) "=" (US-ASCII decimal value 61) "?" (US-ASCII decimal value 63) A maximally portable mail representation will confine itself to relatively short lines of text in which the only meaningful characters are taken from this set of 73 characters. The base64 encoding follows this rule. (8) Some mail transport agents will corrupt data that includes certain literal strings. In particular, a Freed & Borenstein Standards Track [Page 8] RFC 2049 MIME Conformance November 1996 period (".") alone on a line is known to be corrupted by some (incorrect) SMTP implementations, and a line that starts with the five characters "From " (the fifth character is a SPACE) are commonly corrupted as well. A careful composition agent can prevent these corruptions by encoding the data (e.g., in the quoted- printable encoding using "=46rom " in place of "From " at the start of a line, and "=2E" in place of "." alone on a line). Please note that the above list is NOT a list of recommended practices for MTAs. RFC 821 MTAs are prohibited from altering the character of white space or wrapping long lines. These BAD and invalid practices are known to occur on established networks, and implementations should be robust in dealing with the bad effects they can cause. 4. Canonical Encoding Model There was some confusion, in earlier versions of these documents, regarding the model for when email data was to be converted to canonical form and encoded, and in particular how this process would affect the treatment of CRLFs, given that the representation of newlines varies greatly from system to system. For this reason, a canonical model for encoding is presented below. The process of composing a MIME entity can be modeled as being done in a number of steps. Note that these steps are roughly similar to those steps used in PEM [RFC-1421] and are performed for each "innermost level" body: (1) Creation of local form. The body to be transmitted is created in the system's native format. The native character set is used and, where appropriate, local end of line conventions are used as well. The body may be a UNIX-style text file, or a Sun raster image, or a VMS indexed file, or audio data in a system-dependent format stored only in memory, or anything else that corresponds to the local model for the representation of some form of information. Fundamentally, the data is created in the "native" form that corresponds to the type specified by the media type. Freed & Borenstein Standards Track [Page 9] RFC 2049 MIME Conformance November 1996 (2) Conversion to canonical form. The entire body, including "out-of-band" information such as record lengths and possibly file attribute information, is converted to a universal canonical form. The specific media type of the body as well as its associated attributes dictate the nature of the canonical form that is used. Conversion to the proper canonical form may involve character set conversion, transformation of audio data, compression, or various other operations specific to the various media types. If character set conversion is involved, however, care must be taken to understand the semantics of the media type, which may have strong implications for any character set conversion, e.g. with regard to syntactically meaningful characters in a text subtype other than "plain". For example, in the case of text/plain data, the text must be converted to a supported character set and lines must be delimited with CRLF delimiters in accordance with RFC 822. Note that the restriction on line lengths implied by RFC 822 is eliminated if the next step employs either quoted-printable or base64 encoding. (3) Apply transfer encoding. A Content-Transfer-Encoding appropriate for this body is applied. Note that there is no fixed relationship between the media type and the transfer encoding. In particular, it may be appropriate to base the choice of base64 or quoted-printable on character frequency counts which are specific to a given instance of a body. (4) Insertion into entity. The encoded body is inserted into a MIME entity with appropriate headers. The entity is then inserted into the body of a higher-level entity (message or multipart) as needed. Conversion from entity form to local form is accomplished by reversing these steps. Note that reversal of these steps may produce differing results since there is no guarantee that the original and final local forms are the same. Freed & Borenstein Standards Track [Page 10] RFC 2049 MIME Conformance November 1996 It is vital to note that these steps are only a model; they are specifically NOT a blueprint for how an actual system would be built. In particular, the model fails to account for two common designs: (1) In many cases the conversion to a canonical form prior to encoding will be subsumed into the encoder itself, which understands local formats directly. For example, the local newline convention for text bodies might be carried through to the encoder itself along with knowledge of what that format is. (2) The output of the encoders may have to pass through one or more additional steps prior to being transmitted as a message. As such, the output of the encoder may not be conformant with the formats specified by RFC 822. In particular, once again it may be appropriate for the converter's output to be expressed using local newline conventions rather than using the standard RFC 822 CRLF delimiters. Other implementation variations are conceivable as well. The vital aspect of this discussion is that, in spite of any optimizations, collapsings of required steps, or insertion of additional processing, the resulting messages must be consistent with those produced by the model described here. For example, a message with the following header fields: Content-type: text/foo; charset=bar Content-Transfer-Encoding: base64 must be first represented in the text/foo form, then (if necessary) represented in the "bar" character set, and finally transformed via the base64 algorithm into a mail-safe form. NOTE: Some confusion has been caused by systems that represent messages in a format which uses local newline conventions which differ from the RFC822 CRLF convention. It is important to note that these formats are not canonical RFC822/MIME. These formats are instead *encodings* of RFC822, where CRLF sequences in the canonical representation of the message are encoded as the local newline convention. Note that formats which encode CRLF sequences as, for example, LF are not capable of representing MIME messages containing binary data which contains LF octets not part of CRLF line separation sequences. Freed & Borenstein Standards Track [Page 11] RFC 2049 MIME Conformance November 1996 5. Summary This document defines what is meant by MIME Conformance. It also details various problems known to exist in the Internet email system and how to use MIME to overcome them. Finally, it describes MIME's canonical encoding model. 6. Security Considerations Security issues are discussed in the second document in this set, RFC 2046. 7. Authors' Addresses For more information, the authors of this document are best contacted via Internet mail: Ned Freed Innosoft International, Inc. 1050 East Garvey Avenue South West Covina, CA 91790 USA Phone: +1 818 919 3600 Fax: +1 818 919 3614 EMail: ned@innosoft.com Nathaniel S. Borenstein First Virtual Holdings 25 Washington Avenue Morristown, NJ 07960 USA Phone: +1 201 540 8967 Fax: +1 201 993 3032 EMail: nsb@nsb.fv.com MIME is a result of the work of the Internet Engineering Task Force Working Group on RFC 822 Extensions. The chairman of that group, Greg Vaudreuil, may be reached at: Gregory M. Vaudreuil Octel Network Services 17080 Dallas Parkway Dallas, TX 75248-1905 USA EMail: Greg.Vaudreuil@Octel.Com Freed & Borenstein Standards Track [Page 12] RFC 2049 MIME Conformance November 1996 8. Acknowledgements This document is the result of the collective effort of a large number of people, at several IETF meetings, on the IETF-SMTP and IETF-822 mailing lists, and elsewhere. Although any enumeration seems doomed to suffer from egregious omissions, the following are among the many contributors to this effort: Harald Tveit Alvestrand Marc Andreessen Randall Atkinson Bob Braden Philippe Brandon Brian Capouch Kevin Carosso Uhhyung Choi Peter Clitherow Dave Collier-Brown Cristian Constantinof John Coonrod Mark Crispin Dave Crocker Stephen Crocker Terry Crowley Walt Daniels Jim Davis Frank Dawson Axel Deininger Hitoshi Doi Kevin Donnelly Steve Dorner Keith Edwards Chris Eich Dana S. Emery Johnny Eriksson Craig Everhart Patrik Faltstrom Erik E. Fair Roger Fajman Alain Fontaine Martin Forssen James M. Galvin Stephen Gildea Philip Gladstone Thomas Gordon Keld Simonsen Terry Gray Phill Gross James Hamilton David Herron Mark Horton Bruce Howard Bill Janssen Olle Jarnefors Risto Kankkunen Phil Karn Alan Katz Tim Kehres Neil Katin Steve Kille Kyuho Kim Anders Klemets John Klensin Valdis Kletniek Jim Knowles Stev Knowles Bob Kummerfeld Pekka Kytolaakso Stellan Lagerstrom Vincent Lau Timo Lehtinen Donald Lindsay Warner Losh Carlyn Lowery Laurence Lundblade Charles Lynn John R. MacMillan Larry Masinter Rick McGowan Michael J. McInerny Leo Mclaughlin Goli Montaser-Kohsari Tom Moore John Gardiner Myers Erik Naggum Mark Needleman Chris Newman John Noerenberg Freed & Borenstein Standards Track [Page 13] RFC 2049 MIME Conformance November 1996 Mats Ohrman Julian Onions Michael Patton David J. Pepper Erik van der Poel Blake C. Ramsdell Christer Romson Luc Rooijakkers Marshall T. Rose Jonathan Rosenberg Guido van Rossum Jan Rynning Harri Salminen Michael Sanderson Yutaka Sato Markku Savela Richard Alan Schafer Masahiro Sekiguchi Mark Sherman Bob Smart Peter Speck Henry Spencer Einar Stefferud Michael Stein Klaus Steinberger Peter Svanberg James Thompson Steve Uhler Stuart Vance Peter Vanderbilt Greg Vaudreuil Ed Vielmetti Larry W. Virden Ryan Waldron Rhys Weatherly Jay Weber Dave Wecker Wally Wedel Sven-Ove Westberg Brian Wideen John Wobus Glenn Wright Rayan Zachariassen David Zimmerman The authors apologize for any omissions from this list, which are certainly unintentional. Freed & Borenstein Standards Track [Page 14] RFC 2049 MIME Conformance November 1996 Appendix A -- A Complex Multipart Example What follows is the outline of a complex multipart message. This message contains five parts that are to be displayed serially: two introductory plain text objects, an embedded multipart message, a text/enriched object, and a closing encapsulated text message in a non-ASCII character set. The embedded multipart message itself contains two objects to be displayed in parallel, a picture and an audio fragment. MIME-Version: 1.0 From: Nathaniel Borenstein To: Ned Freed Date: Fri, 07 Oct 1994 16:15:05 -0700 (PDT) Subject: A multipart example Content-Type: multipart/mixed; boundary=unique-boundary-1 This is the preamble area of a multipart message. Mail readers that understand multipart format should ignore this preamble. If you are reading this text, you might want to consider changing to a mail reader that understands how to properly display multipart messages. --unique-boundary-1 ... Some text appears here ... [Note that the blank between the boundary and the start of the text in this part means no header fields were given and this is text in the US-ASCII character set. It could have been done with explicit typing as in the next part.] --unique-boundary-1 Content-type: text/plain; charset=US-ASCII This could have been part of the previous part, but illustrates explicit versus implicit typing of body parts. --unique-boundary-1 Content-Type: multipart/parallel; boundary=unique-boundary-2 --unique-boundary-2 Content-Type: audio/basic Freed & Borenstein Standards Track [Page 15] RFC 2049 MIME Conformance November 1996 Content-Transfer-Encoding: base64 ... base64-encoded 8000 Hz single-channel mu-law-format audio data goes here ... --unique-boundary-2 Content-Type: image/jpeg Content-Transfer-Encoding: base64 ... base64-encoded image data goes here ... --unique-boundary-2-- --unique-boundary-1 Content-type: text/enriched This is enriched. as defined in RFC 1896 Isn't it cool? --unique-boundary-1 Content-Type: message/rfc822 From: (mailbox in US-ASCII) To: (address in US-ASCII) Subject: (subject in US-ASCII) Content-Type: Text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: Quoted-printable ... Additional text in ISO-8859-1 goes here ... --unique-boundary-1-- Appendix B -- Changes from RFC 1521, 1522, and 1590 These documents are a revision of RFC 1521, 1522, and 1590. For the convenience of those familiar with the earlier documents, the changes from those documents are summarized in this appendix. For further history, note that Appendix H in RFC 1521 specified how that document differed from its predecessor, RFC 1341. (1) This document has been completely reformatted and split into multiple documents. This was done to improve the quality of the plain text version of this document, which is required to be the reference copy. Freed & Borenstein Standards Track [Page 16] RFC 2049 MIME Conformance November 1996 (2) BNF describing the overall structure of MIME object headers has been added. This is a documentation change only -- the underlying syntax has not changed in any way. (3) The specific BNF for the seven media types in MIME has been removed. This BNF was incorrect, incomplete, amd inconsistent with the type-indendependent BNF. And since the type-independent BNF already fully specifies the syntax of the various MIME headers, the type- specific BNF was, in the final analysis, completely unnecessary and caused more problems than it solved. (4) The more specific "US-ASCII" character set name has replaced the use of the informal term ASCII in many parts of these documents. (5) The informal concept of a primary subtype has been removed. (6) The term "object" was being used inconsistently. The definition of this term has been clarified, along with the related terms "body", "body part", and "entity", and usage has been corrected where appropriate. (7) The BNF for the multipart media type has been rearranged to make it clear that the CRLF preceeding the boundary marker is actually part of the marker itself rather than the preceeding body part. (8) The prose and BNF describing the multipart media type have been changed to make it clear that the body parts within a multipart object MUST NOT contain any lines beginning with the boundary parameter string. (9) In the rules on reassembling "message/partial" MIME entities, "Subject" is added to the list of headers to take from the inner message, and the example is modified to clarify this point. (10) "Message/partial" fragmenters are restricted to splitting MIME objects only at line boundaries. (11) In the discussion of the application/postscript type, an additional paragraph has been added warning about possible interoperability problems caused by embedding of binary data inside a PostScript MIME entity. Freed & Borenstein Standards Track [Page 17] RFC 2049 MIME Conformance November 1996 (12) Added a clarifying note to the basic syntax rules for the Content-Type header field to make it clear that the following two forms: Content-type: text/plain; charset=us-ascii (comment) Content-type: text/plain; charset="us-ascii" are completely equivalent. (13) The following sentence has been removed from the discussion of the MIME-Version header: "However, conformant software is encouraged to check the version number and at least warn the user if an unrecognized MIME-version is encountered." (14) A typo was fixed that said "application/external-body" instead of "message/external-body". (15) The definition of a character set has been reorganized to make the requirements clearer. (16) The definition of the "image/gif" media type has been moved to a separate document. This change was made because of potential conflicts with IETF rules governing the standardization of patented technology. (17) The definitions of "7bit" and "8bit" have been tightened so that use of bare CR, LF can only be used as end-of-line sequences. The document also no longer requires that NUL characters be preserved, which brings MIME into alignment with real-world implementations. (18) The definition of canonical text in MIME has been tightened so that line breaks must be represented by a CRLF sequence. CR and LF characters are not allowed outside of this usage. The definition of quoted- printable encoding has been altered accordingly. (19) The definition of the quoted-printable encoding now includes a number of suggestions for how quoted- printable encoders might best handle improperly encoded material. (20) Prose was added to clarify the use of the "7bit", "8bit", and "binary" transfer-encodings on multipart or message entities encapsulating "8bit" or "binary" data. Freed & Borenstein Standards Track [Page 18] RFC 2049 MIME Conformance November 1996 (21) In the section on MIME Conformance, "multipart/digest" support was added to the list of requirements for minimal MIME conformance. Also, the requirement for "message/rfc822" support were strengthened to clarify the importance of recognizing recursive structure. (22) The various restrictions on subtypes of "message" are now specified entirely on a subtype by subtype basis. (23) The definition of "message/rfc822" was changed to indicate that at least one of the "From", "Subject", or "Date" headers must be present. (24) The required handling of unrecognized subtypes as "application/octet-stream" has been made more explicit in both the type definitions sections and the conformance guidelines. (25) Examples using text/richtext were changed to text/enriched. (26) The BNF definition of subtype has been changed to make it clear that either an IANA registered subtype or a nonstandard "X-" subtype must be used in a Content-Type header field. (27) MIME media types that are simply registered for use and those that are standardized by the IETF are now distinguished in the MIME BNF. (28) All of the various MIME registration procedures have been extensively revised. IANA registration procedures for character sets have been moved to a separate document that is no included in this set of documents. (29) The use of escape and shift mechanisms in the US-ASCII and ISO-8859-X character sets these documents define have been clarified: Such mechanisms should never be used in conjunction with these character sets and their effect if they are used is undefined. (30) The definition of the AFS access-type for message/external-body has been removed. (31) The handling of the combination of multipart/alternative and message/external-body is now specifically addressed. Freed & Borenstein Standards Track [Page 19] RFC 2049 MIME Conformance November 1996 (32) Security issues specific to message/external-body are now discussed in some detail. Appendix C -- References [ATK] Borenstein, Nathaniel S., Multimedia Applications Development with the Andrew Toolkit, Prentice-Hall, 1990. [ISO-2022] International Standard -- Information Processing -- Character Code Structure and Extension Techniques, ISO/IEC 2022:1994, 4th ed. [ISO-8859] International Standard -- Information Processing -- 8-bit Single-Byte Coded Graphic Character Sets - Part 1: Latin Alphabet No. 1, ISO 8859-1:1987, 1st ed. - Part 2: Latin Alphabet No. 2, ISO 8859-2:1987, 1st ed. - Part 3: Latin Alphabet No. 3, ISO 8859-3:1988, 1st ed. - Part 4: Latin Alphabet No. 4, ISO 8859-4:1988, 1st ed. - Part 5: Latin/Cyrillic Alphabet, ISO 8859-5:1988, 1st ed. - Part 6: Latin/Arabic Alphabet, ISO 8859-6:1987, 1st ed. - Part 7: Latin/Greek Alphabet, ISO 8859-7:1987, 1st ed. - Part 8: Latin/Hebrew Alphabet, ISO 8859-8:1988, 1st ed. - Part 9: Latin Alphabet No. 5, ISO/IEC 8859-9:1989, 1st ed. International Standard -- Information Technology -- 8-bit Single-Byte Coded Graphic Character Sets - Part 10: Latin Alphabet No. 6, ISO/IEC 8859-10:1992, 1st ed. [ISO-646] International Standard -- Information Technology -- ISO 7-bit Coded Character Set for Information Interchange, ISO 646:1991, 3rd ed.. [JPEG] JPEG Draft Standard ISO 10918-1 CD. [MPEG] Video Coding Draft Standard ISO 11172 CD, ISO IEC/JTC1/SC2/WG11 (Motion Picture Experts Group), May, 1991. Freed & Borenstein Standards Track [Page 20] RFC 2049 MIME Conformance November 1996 [PCM] CCITT, Fascicle III.4 - Recommendation G.711, "Pulse Code Modulation (PCM) of Voice Frequencies", Geneva, 1972. [POSTSCRIPT] Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, 1985. [POSTSCRIPT2] Adobe Systems, Inc., PostScript Language Reference Manual, Addison-Wesley, Second Ed., 1990. [RFC-783] Sollins, K.R., "TFTP Protocol (revision 2)", RFC-783, MIT, June 1981. [RFC-821] Postel, J.B., "Simple Mail Transfer Protocol", STD 10, RFC 821, USC/Information Sciences Institute, August 1982. [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, UDEL, August 1982. [RFC-934] Rose, M. and E. Stefferud, "Proposed Standard for Message Encapsulation", RFC 934, Delaware and NMA, January 1985. [RFC-959] Postel, J. and J. Reynolds, "File Transfer Protocol", STD 9, RFC 959, USC/Information Sciences Institute, October 1985. [RFC-1049] Sirbu, M., "Content-Type Header Field for Internet Messages", RFC 1049, CMU, March 1988. [RFC-1154] Robinson, D., and R. Ullmann, "Encoding Header Field for Internet Messages", RFC 1154, Prime Computer, Inc., April 1990. [RFC-1341] Borenstein, N., and N. Freed, "MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies", RFC 1341, Bellcore, Innosoft, June 1992. Freed & Borenstein Standards Track [Page 21] RFC 2049 MIME Conformance November 1996 [RFC-1342] Moore, K., "Representation of Non-Ascii Text in Internet Message Headers", RFC 1342, University of Tennessee, June 1992. [RFC-1344] Borenstein, N., "Implications of MIME for Internet Mail Gateways", RFC 1344, Bellcore, June 1992. [RFC-1345] Simonsen, K., "Character Mnemonics & Character Sets", RFC 1345, Rationel Almen Planlaegning, June 1992. [RFC-1421] Linn, J., "Privacy Enhancement for Internet Electronic Mail: Part I -- Message Encryption and Authentication Procedures", RFC 1421, IAB IRTF PSRG, IETF PEM WG, February 1993. [RFC-1422] Kent, S., "Privacy Enhancement for Internet Electronic Mail: Part II -- Certificate-Based Key Management", RFC 1422, IAB IRTF PSRG, IETF PEM WG, February 1993. [RFC-1423] Balenson, D., "Privacy Enhancement for Internet Electronic Mail: Part III -- Algorithms, Modes, and Identifiers", IAB IRTF PSRG, IETF PEM WG, February 1993. [RFC-1424] Kaliski, B., "Privacy Enhancement for Internet Electronic Mail: Part IV -- Key Certification and Related Services", IAB IRTF PSRG, IETF PEM WG, February 1993. [RFC-1521] Borenstein, N., and Freed, N., "MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies", RFC 1521, Bellcore, Innosoft, September, 1993. [RFC-1522] Moore, K., "Representation of Non-ASCII Text in Internet Message Headers", RFC 1522, University of Tennessee, September 1993. Freed & Borenstein Standards Track [Page 22] RFC 2049 MIME Conformance November 1996 [RFC-1524] Borenstein, N., "A User Agent Configuration Mechanism for Multimedia Mail Format Information", RFC 1524, Bellcore, September 1993. [RFC-1543] Postel, J., "Instructions to RFC Authors", RFC 1543, USC/Information Sciences Institute, October 1993. [RFC-1556] Nussbacher, H., "Handling of Bi-directional Texts in MIME", RFC 1556, Israeli Inter-University Computer Center, December 1993. [RFC-1590] Postel, J., "Media Type Registration Procedure", RFC 1590, USC/Information Sciences Institute, March 1994. [RFC-1602] Internet Architecture Board, Internet Engineering Steering Group, Huitema, C., Gross, P., "The Internet Standards Process -- Revision 2", March 1994. [RFC-1652] Klensin, J., (WG Chair), Freed, N., (Editor), Rose, M., Stefferud, E., and Crocker, D., "SMTP Service Extension for 8bit-MIME transport", RFC 1652, United Nations University, Innosoft, Dover Beach Consulting, Inc., Network Management Associates, Inc., The Branch Office, March 1994. [RFC-1700] Reynolds, J. and J. Postel, "Assigned Numbers", STD 2, RFC 1700, USC/Information Sciences Institute, October 1994. [RFC-1741] Faltstrom, P., Crocker, D., and Fair, E., "MIME Content Type for BinHex Encoded Files", December 1994. [RFC-1896] Resnick, P., and A. Walker, "The text/enriched MIME Content-type", RFC 1896, February, 1996. Freed & Borenstein Standards Track [Page 23] RFC 2049 MIME Conformance November 1996 [RFC-2045] Freed, N., and and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, Innosoft, First Virtual Holdings, November 1996. [RFC-2046] Freed, N., and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, Innosoft, First Virtual Holdings, November 1996. [RFC-2047] Moore, K., "Multipurpose Internet Mail Extensions (MIME) Part Three: Representation of Non-ASCII Text in Internet Message Headers", RFC 2047, University of Tennessee, November 1996. [RFC-2048] Freed, N., Klensin, J., and J. Postel, "Multipurpose Internet Mail Extensions (MIME) Part Four: MIME Registration Procedures", RFC 2048, Innosoft, MCI, ISI, November 1996. [RFC-2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples", RFC 2049 (this document), Innosoft, First Virtual Holdings, November 1996. [US-ASCII] Coded Character Set -- 7-Bit American Standard Code for Information Interchange, ANSI X3.4-1986. [X400] Schicker, Pietro, "Message Handling Systems, X.400", Message Handling Systems and Distributed Applications, E. Stefferud, O-j. Jacobsen, and P. Schicker, eds., North- Holland, 1989, pp. 3-41. Freed & Borenstein Standards Track [Page 24] mail-2.5.4/reference/rfc2111 Content-ID and Message-ID URLs.txt000066400000000000000000000216311214434061600233030ustar00rootroot00000000000000 Network Working Group E. Levinson Request for Comments: 2111 XIson, Inc. Category: Standards Track March 1997 Content-ID and Message-ID Uniform Resource Locators 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. Abstract The Uniform Resource Locator (URL) schemes, "cid:" and "mid:" allow references to messages and the body parts of messages. For example, within a single multipart message, one HTML body part might include embedded references to other parts of the same message. 1. Introduction The use of [MIME] within email to convey Web pages and their associated images requires a URL scheme to permit the HTML to refer to the images or other data included in the message. The Content-ID Uniform Resource Locator, "cid:", serves that purpose. Similarly Net News readers use Message-IDs to link related messages together. The Message-ID URL provides a scheme, "mid:", to refer to such messages as a "resource". The "mid" (Message-ID) and "cid" (Content-ID) URL schemes provide identifiers for messages and their body parts. The "mid" scheme uses (a part of) the message-id of an email message to refer to a specific message. The "cid" scheme refers to a specific body part of a message; its use is generally limited to references to other body parts in the same message as the referring body part. The "mid" scheme may also refer to a specific body part within a designated message, by including the content-ID's address. A note on terminology. The terms "body part" and "MIME entity" are used interchangeably. They refer to the headers and body of a MIME message, either the message itself or one of the body parts contained in a Multipart message. Levinson Standards Track [Page 1] RFC 2111 CID and MID URLs March 1997 2. The MID and CID URL Schemes RFC1738 [URL] reserves the "mid" and "cid" schemes for Message-ID and Content-ID respectively. This memorandum defines the syntax for those URLs. Because they use the same syntactic elements they are presented together. The URLs take the form content-id = url-addr-spec message-id = url-addr-spec url-addr-spec = addr-spec ; URL encoding of RFC 822 addr-spec cid-url = "cid" ":" content-id mid-url = "mid" ":" message-id [ "/" content-id ] Note: in Internet mail messages, the addr-spec in a Content-ID [MIME] or Message-ID [822] header are enclosed in angle brackets (<>). Since addr-spec in a Message-ID or Content-ID might contain characters not allowed within a URL; any such character (including "/", which is reserved within the "mid" scheme) must be hex- encoded using the %hh escape mechanism in [URL]. A "mid" URL with only a "message-id" refers to an entire message. With the appended "content-id", it refers to a body part within a message, as does a "cid" URL. The Content-ID of a MIME body part is required to be globally unique. However, in many systems that store messages, body parts are not indexed independently their context (message). The "mid" URL long form was designed to supply the context needed to support interoperability with such systems. A implementation conforming to this specification is required to support the "mid" URL long form (message-id/content-id). Conforming implementations can choose to, but are not required to, take advantage of the content-id's uniqueness and interpret a "cid" URL to refer to any body part within the message store. In limited circumstances (e.g., within multipart/alternate), a single message may contain several body parts that have the same Content-ID. That occurs, for example, when identical data can be accessed through different methods [MIME, sect. 7.2.3]. In those cases, conforming implementations are required to use the rules of the containing MIME entity (e.g., multi-part/alternate) to select the body part to which the Content-ID refers. Levinson Standards Track [Page 2] RFC 2111 CID and MID URLs March 1997 A "cid" URL is converted to the corresponding Content-ID message header [MIME] by removing the "cid:" prefix, converting %hh hex- escaped characters to their ASCII equivalents and enclosing the remaining parts with an angle bracket pair, "<" and ">". For example, "mid:foo4%25foo1@bar.net" corresponds to Message-ID: A "mid" URL is converted to a Message-ID or Message-ID/Content-ID pair in a similar fashion. Both message-id and content-id are required to be globally unique. That is, no two different messages will ever have the same Message-ID addr-spec; no different body parts will ever have the same Content-ID addr-spec. A common technique used by many message systems is to use a time and date stamp along with the local host's domain name, e.g., 950124.162336@XIson.com. Some Examples The following message contains an HTML body part that refers to an image contained in another body part. Both body parts are contained in a Multipart/Related MIME entity. The HTML IMG tag contains a cidurl which points to the image. From: foo1@bar.net To: foo2@bar.net Subject: A simple example Mime-Version: 1.0 Content-Type: multipart/related; boundary="boundary-example-1"; type=Text/HTML --boundary-example 1 Content-Type: Text/HTML; charset=US-ASCII ... text of the HTML document, which might contain a hyperlink to the other body part, for example through a statement such as: IETF logo --boundary-example-1 Content-ID: foo4*foo1@bar.net Content-Type: IMAGE/GIF Content-Transfer-Encoding: BASE64 Levinson Standards Track [Page 3] RFC 2111 CID and MID URLs March 1997 R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5 NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A etc... --boundary-example-1-- The following message points to another message (hopefully still in the recipient's message store). From: bar@none.com To: phooey@all.com Subject: Here's how to do it Content-type: text/html; charset=usascii ... The items in my previous message, shows how the approach you propose can be used to accomplish ... 3. Security Considerations The URLs defined here provide an addressing or referencing mechanism. The values of these URLs disclose no more about the originators environment than the corresponding Message-ID and Content-ID values. Where concern exists about such disclosures the originator of a message using mid and cid URLs must take precautions to insure that confidential information is not disclosed. Those precautions should already be in place to handle existing mail use of the Message-ID and Content-ID. 4. References [822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages," August 1982, University of Delaware, STD 11, RFC 822. [MIME] N. Borenstein, N. Freed, "MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies," September 1993, RFC 1521. [URL] Berners-Lee, T., Masinter, L., and McCahill, M., "Uniform Resource Locators (URL)," December 1994. [MULREL] E. Levinson, "The MIME Multipart/Related Content-type," December 1995, RFC 1874. Levinson Standards Track [Page 4] RFC 2111 CID and MID URLs March 1997 5. Acknowledgments The original concept of "mid" and "cid" URLs were part of the Tim Berners-Lee's original vision of the World Wide Web. The ideas and design have benefited greatly by discussions with Harald Alvestrand, Dan Connolly, Roy Fielding, Larry Masinter, Jacob Palme, and others in the MHTML working group. 6. Author's Address Edward Levinson 47 Clive Street Metuchen, NJ 08840-1060 USA +1 908 549 3716 Levinson Standards Track [Page 5] mail-2.5.4/reference/rfc2183 Content-Disposition Header Field.txt000066400000000000000000000551661214434061600243230ustar00rootroot00000000000000 Network Working Group R. Troost Request for Comments: 2183 New Century Systems Updates: 1806 S. Dorner Category: Standards Track QUALCOMM Incorporated K. Moore, Editor University of Tennessee August 1997 Communicating Presentation Information in Internet Messages: The Content-Disposition Header Field 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. Abstract This memo provides a mechanism whereby messages conforming to the MIME specifications [RFC 2045, RFC 2046, RFC 2047, RFC 2048, RFC 2049] can convey presentational information. It specifies the "Content-Disposition" header field, which is optional and valid for any MIME entity ("message" or "body part"). Two values for this header field are described in this memo; one for the ordinary linear presentation of the body part, and another to facilitate the use of mail to transfer files. It is expected that more values will be defined in the future, and procedures are defined for extending this set of values. This document is intended as an extension to MIME. As such, the reader is assumed to be familiar with the MIME specifications, and [RFC 822]. The information presented herein supplements but does not replace that found in those documents. This document is a revision to the Experimental protocol defined in RFC 1806. As compared to RFC 1806, this document contains minor editorial updates, adds new parameters needed to support the File Transfer Body Part, and references a separate specification for the handling of non-ASCII and/or very long parameter values. Troost, et. al. Standards Track [Page 1] RFC 2183 Content-Disposition August 1997 1. Introduction MIME specifies a standard format for encapsulating multiple pieces of data into a single Internet message. That document does not address the issue of presentation styles; it provides a framework for the interchange of message content, but leaves presentation issues solely in the hands of mail user agent (MUA) implementors. Two common ways of presenting multipart electronic messages are as a main document with a list of separate attachments, and as a single document with the various parts expanded (displayed) inline. The display of an attachment is generally construed to require positive action on the part of the recipient, while inline message components are displayed automatically when the message is viewed. A mechanism is needed to allow the sender to transmit this sort of presentational information to the recipient; the Content-Disposition header provides this mechanism, allowing each component of a message to be tagged with an indication of its desired presentation semantics. Tagging messages in this manner will often be sufficient for basic message formatting. However, in many cases a more powerful and flexible approach will be necessary. The definition of such approaches is beyond the scope of this memo; however, such approaches can benefit from additional Content-Disposition values and parameters, to be defined at a later date. In addition to allowing the sender to specify the presentational disposition of a message component, it is desirable to allow her to indicate a default archival disposition; a filename. The optional "filename" parameter provides for this. Further, the creation-date, modification-date, and read-date parameters allow preservation of those file attributes when the file is transmitted over MIME email. NB: The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this document, are to be interpreted as described in [RFC 2119]. 2. The Content-Disposition Header Field Content-Disposition is an optional header field. In its absence, the MUA may use whatever presentation method it deems suitable. It is desirable to keep the set of possible disposition types small and well defined, to avoid needless complexity. Even so, evolving usage will likely require the definition of additional disposition types or parameters, so the set of disposition values is extensible; see below. Troost, et. al. Standards Track [Page 2] RFC 2183 Content-Disposition August 1997 In the extended BNF notation of [RFC 822], the Content-Disposition header field is defined as follows: disposition := "Content-Disposition" ":" disposition-type *(";" disposition-parm) disposition-type := "inline" / "attachment" / extension-token ; values are not case-sensitive disposition-parm := filename-parm / creation-date-parm / modification-date-parm / read-date-parm / size-parm / parameter filename-parm := "filename" "=" value creation-date-parm := "creation-date" "=" quoted-date-time modification-date-parm := "modification-date" "=" quoted-date-time read-date-parm := "read-date" "=" quoted-date-time size-parm := "size" "=" 1*DIGIT quoted-date-time := quoted-string ; contents MUST be an RFC 822 `date-time' ; numeric timezones (+HHMM or -HHMM) MUST be used NOTE ON PARAMETER VALUE LENGHTS: A short (length <= 78 characters) parameter value containing only non-`tspecials' characters SHOULD be represented as a single `token'. A short parameter value containing only ASCII characters, but including `tspecials' characters, SHOULD be represented as `quoted-string'. Parameter values longer than 78 characters, or which contain non-ASCII characters, MUST be encoded as specified in [RFC 2184]. `Extension-token', `parameter', `tspecials' and `value' are defined according to [RFC 2045] (which references [RFC 822] in the definition of some of these tokens). `quoted-string' and `DIGIT' are defined in [RFC 822]. Troost, et. al. Standards Track [Page 3] RFC 2183 Content-Disposition August 1997 2.1 The Inline Disposition Type A bodypart should be marked `inline' if it is intended to be displayed automatically upon display of the message. Inline bodyparts should be presented in the order in which they occur, subject to the normal semantics of multipart messages. 2.2 The Attachment Disposition Type Bodyparts can be designated `attachment' to indicate that they are separate from the main body of the mail message, and that their display should not be automatic, but contingent upon some further action of the user. The MUA might instead present the user of a bitmap terminal with an iconic representation of the attachments, or, on character terminals, with a list of attachments from which the user could select for viewing or storage. 2.3 The Filename Parameter The sender may want to suggest a filename to be used if the entity is detached and stored in a separate file. If the receiving MUA writes the entity to a file, the suggested filename should be used as a basis for the actual filename, where possible. It is important that the receiving MUA not blindly use the suggested filename. The suggested filename SHOULD be checked (and possibly changed) to see that it conforms to local filesystem conventions, does not overwrite an existing file, and does not present a security problem (see Security Considerations below). The receiving MUA SHOULD NOT respect any directory path information that may seem to be present in the filename parameter. The filename should be treated as a terminal component only. Portable specification of directory paths might possibly be done in the future via a separate Content-Disposition parameter, but no provision is made for it in this draft. Current [RFC 2045] grammar restricts parameter values (and hence Content-Disposition filenames) to US-ASCII. We recognize the great desirability of allowing arbitrary character sets in filenames, but it is beyond the scope of this document to define the necessary mechanisms. We expect that the basic [RFC 1521] `value' specification will someday be amended to allow use of non-US-ASCII characters, at which time the same mechanism should be used in the Content-Disposition filename parameter. Troost, et. al. Standards Track [Page 4] RFC 2183 Content-Disposition August 1997 Beyond the limitation to US-ASCII, the sending MUA may wish to bear in mind the limitations of common filesystems. Many have severe length and character set restrictions. Short alphanumeric filenames are least likely to require modification by the receiving system. The presence of the filename parameter does not force an implementation to write the entity to a separate file. It is perfectly acceptable for implementations to leave the entity as part of the normal mail stream unless the user requests otherwise. As a consequence, the parameter may be used on any MIME entity, even `inline' ones. These will not normally be written to files, but the parameter could be used to provide a filename if the receiving user should choose to write the part to a file. 2.4 The Creation-Date parameter The creation-date parameter MAY be used to indicate the date at which the file was created. If this parameter is included, the paramter value MUST be a quoted-string which contains a representation of the creation date of the file in [RFC 822] `date-time' format. UNIX and POSIX implementors are cautioned that the `st_ctime' file attribute of the `stat' structure is not the creation time of the file; it is thus not appropriate as a source for the creation-date parameter value. 2.5 The Modification-Date parameter The modification-date parameter MAY be used to indicate the date at which the file was last modified. If the modification-date parameter is included, the paramter value MUST be a quoted-string which contains a representation of the last modification date of the file in [RFC 822] `date-time' format. 2.6 The Read-Date parameter The read-date parameter MAY be used to indicate the date at which the file was last read. If the read-date parameter is included, the parameter value MUST be a quoted-string which contains a representation of the last-read date of the file in [RFC 822] `date- time' format. 2.7 The Size parameter The size parameter indicates an approximate size of the file in octets. It can be used, for example, to pre-allocate space before attempting to store the file, or to determine whether enough space exists. Troost, et. al. Standards Track [Page 5] RFC 2183 Content-Disposition August 1997 2.8 Future Extensions and Unrecognized Disposition Types In the likely event that new parameters or disposition types are needed, they should be registered with the Internet Assigned Numbers Authority (IANA), in the manner specified in Section 9 of this memo. Once new disposition types and parameters are defined, there is of course the likelihood that implementations will see disposition types and parameters they do not understand. Furthermore, since x-tokens are allowed, implementations may also see entirely unregistered disposition types and parameters. Unrecognized parameters should be ignored. Unrecognized disposition types should be treated as `attachment'. The choice of `attachment' for unrecognized types is made because a sender who goes to the trouble of producing a Content-Disposition header with a new disposition type is more likely aiming for something more elaborate than inline presentation. Unless noted otherwise in the definition of a parameter, Content- Disposition parameters are valid for all dispositions. (In contrast to MIME content-type parameters, which are defined on a per-content- type basis.) Thus, for example, the `filename' parameter still means the name of the file to which the part should be written, even if the disposition itself is unrecognized. 2.9 Content-Disposition and Multipart If a Content-Disposition header is used on a multipart body part, it applies to the multipart as a whole, not the individual subparts. The disposition types of the subparts do not need to be consulted until the multipart itself is presented. When the multipart is displayed, then the dispositions of the subparts should be respected. If the `inline' disposition is used, the multipart should be displayed as normal; however, an `attachment' subpart should require action from the user to display. If the `attachment' disposition is used, presentation of the multipart should not proceed without explicit user action. Once the user has chosen to display the multipart, the individual subpart dispositions should be consulted to determine how to present the subparts. Troost, et. al. Standards Track [Page 6] RFC 2183 Content-Disposition August 1997 2.10 Content-Disposition and the Main Message It is permissible to use Content-Disposition on the main body of an [RFC 822] message. 3. Examples Here is a an example of a body part containing a JPEG image that is intended to be viewed by the user immediately: Content-Type: image/jpeg Content-Disposition: inline Content-Description: just a small picture of me The following body part contains a JPEG image that should be displayed to the user only if the user requests it. If the JPEG is written to a file, the file should be named "genome.jpg". The recipient's user might also choose to set the last-modified date of the stored file to date in the modification-date parameter: Content-Type: image/jpeg Content-Disposition: attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"; Content-Description: a complete map of the human genome The following is an example of the use of the `attachment' disposition with a multipart body part. The user should see text- part-1 immediately, then take some action to view multipart-2. After taking action to view multipart-2, the user will see text-part-2 right away, and be required to take action to view jpeg-1. Subparts are indented for clarity; they would not be so indented in a real message. Troost, et. al. Standards Track [Page 7] RFC 2183 Content-Disposition August 1997 Content-Type: multipart/mixed; boundary=outer Content-Description: multipart-1 --outer Content-Type: text/plain Content-Disposition: inline Content-Description: text-part-1 Some text goes here --outer Content-Type: multipart/mixed; boundary=inner Content-Disposition: attachment Content-Description: multipart-2 --inner Content-Type: text/plain Content-Disposition: inline Content-Description: text-part-2 Some more text here. --inner Content-Type: image/jpeg Content-Disposition: attachment Content-Description: jpeg-1 --inner-- --outer-- 4. Summary Content-Disposition takes one of two values, `inline' and `attachment'. `Inline' indicates that the entity should be immediately displayed to the user, whereas `attachment' means that the user should take additional action to view the entity. The `filename' parameter can be used to suggest a filename for storing the bodypart, if the user wishes to store it in an external file. Troost, et. al. Standards Track [Page 8] RFC 2183 Content-Disposition August 1997 5. Security Considerations There are security issues involved any time users exchange data. While these are not to be minimized, neither does this memo change the status quo in that regard, except in one instance. Since this memo provides a way for the sender to suggest a filename, a receiving MUA must take care that the sender's suggested filename does not represent a hazard. Using UNIX as an example, some hazards would be: + Creating startup files (e.g., ".login"). + Creating or overwriting system files (e.g., "/etc/passwd"). + Overwriting any existing file. + Placing executable files into any command search path (e.g., "~/bin/more"). + Sending the file to a pipe (e.g., "| sh"). In general, the receiving MUA should not name or place the file such that it will get interpreted or executed without the user explicitly initiating the action. It is very important to note that this is not an exhaustive list; it is intended as a small set of examples only. Implementors must be alert to the potential hazards on their target systems. 6. References [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, March 1997. [RFC 2184] Freed, N. and K. Moore, "MIME Parameter value and Encoded Words: Character Sets, Lanaguage, and Continuations", RFC 2184, August 1997. [RFC 2045] Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies", RFC 2045, December 1996. Troost, et. al. Standards Track [Page 9] RFC 2183 Content-Disposition August 1997 [RFC 2046] Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail Extensions) Part Two: Media Types", RFC 2046, December 1996. [RFC 2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for non-ASCII Text", RFC 2047, December 1996. [RFC 2048] Freed, N., Klensin, J. and J. Postel, "MIME (Multipurpose Internet Mail Extensions) Part Four: Registration Procedures", RFC 2048, December 1996. [RFC 2049] Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail Extensions) Part Five: Conformance Criteria and Examples", RFC 2049, December 1996. [RFC 822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, UDEL, August 1982. 7. Acknowledgements We gratefully acknowledge the help these people provided during the preparation of this draft: Nathaniel Borenstein Ned Freed Keith Moore Dave Crocker Dan Pritchett Troost, et. al. Standards Track [Page 10] RFC 2183 Content-Disposition August 1997 8. Authors' Addresses You should blame the editor of this version of the document for any changes since RFC 1806: Keith Moore Department of Computer Science University of Tennessee, Knoxville 107 Ayres Hall Knoxville TN 37996-1301 USA Phone: +1 (423) 974-5067 Fax: +1 (423) 974-8296 Email: moore@cs.utk.edu The authors of RFC 1806 are: Rens Troost New Century Systems 324 East 41st Street #804 New York, NY, 10017 USA Phone: +1 (212) 557-2050 Fax: +1 (212) 557-2049 EMail: rens@century.com Steve Dorner QUALCOMM Incorporated 6455 Lusk Boulevard San Diego, CA 92121 USA EMail: sdorner@qualcomm.com 9. Registration of New Content-Disposition Values and Parameters New Content-Disposition values (besides "inline" and "attachment") may be defined only by Internet standards-track documents, or in Experimental documents approved by the Internet Engineering Steering Group. Troost, et. al. Standards Track [Page 11] RFC 2183 Content-Disposition August 1997 New content-disposition parameters may be registered by supplying the information in the following template and sending it via electronic mail to IANA@IANA.ORG: To: IANA@IANA.ORG Subject: Registration of new Content-Disposition parameter Content-Disposition parameter name: Allowable values for this parameter: (If the parameter can only assume a small number of values, list each of those values. Otherwise, describe the values that the parameter can assume.) Description: (What is the purpose of this parameter and how is it used?) 10. Changes since RFC 1806 The following changes have been made since the earlier version of this document, published in RFC 1806 as an Experimental protocol: + Updated references to MIME documents. In some cases this involved substituting a reference to one of the current MIME RFCs for a reference to RFC 1521; in other cases, a reference to RFC 1521 was simply replaced with the word "MIME". + Added a section on registration procedures, since none of the procedures in RFC 2048 seemed to be appropriate. + Added new parameter types: creation-date, modification-date, read-date, and size. + Incorporated a reference to draft-freed-pvcsc-* for encoding long or non-ASCII parameter values. + Added reference to RFC 2119 to define MUST, SHOULD, etc. keywords. Troost, et. al. Standards Track [Page 12] mail-2.5.4/reference/rfc2231 MIME Parameter Value and Encoded Word Extensions.txt000066400000000000000000000455201214434061600267630ustar00rootroot00000000000000 Network Working Group N. Freed Request for Comments: 2231 Innosoft Updates: 2045, 2047, 2183 K. Moore Obsoletes: 2184 University of Tennessee Category: Standards Track November 1997 MIME Parameter Value and Encoded Word Extensions: Character Sets, Languages, and Continuations 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 (1997). All Rights Reserved. 1. Abstract This memo defines extensions to the RFC 2045 media type and RFC 2183 disposition parameter value mechanisms to provide (1) a means to specify parameter values in character sets other than US-ASCII, (2) to specify the language to be used should the value be displayed, and (3) a continuation mechanism for long parameter values to avoid problems with header line wrapping. This memo also defines an extension to the encoded words defined in RFC 2047 to allow the specification of the language to be used for display as well as the character set. 2. Introduction The Multipurpose Internet Mail Extensions, or MIME [RFC-2045, RFC- 2046, RFC-2047, RFC-2048, RFC-2049], define a message format that allows for: Freed & Moore Standards Track [Page 1] RFC 2231 MIME Value and Encoded Word Extensions November 1997 (1) textual message bodies in character sets other than US-ASCII, (2) non-textual message bodies, (3) multi-part message bodies, and (4) textual header information in character sets other than US-ASCII. MIME is now widely deployed and is used by a variety of Internet protocols, including, of course, Internet email. However, MIME's success has resulted in the need for additional mechanisms that were not provided in the original protocol specification. In particular, existing MIME mechanisms provide for named media type (content-type field) parameters as well as named disposition (content-disposition field). A MIME media type may specify any number of parameters associated with all of its subtypes, and any specific subtype may specify additional parameters for its own use. A MIME disposition value may specify any number of associated parameters, the most important of which is probably the attachment disposition's filename parameter. These parameter names and values end up appearing in the content-type and content-disposition header fields in Internet email. This inherently imposes three crucial limitations: (1) Lines in Internet email header fields are folded according to RFC 822 folding rules. This makes long parameter values problematic. (2) MIME headers, like the RFC 822 headers they often appear in, are limited to 7bit US-ASCII, and the encoded-word mechanisms of RFC 2047 are not available to parameter values. This makes it impossible to have parameter values in character sets other than US-ASCII without specifying some sort of private per-parameter encoding. (3) It has recently become clear that character set information is not sufficient to properly display some sorts of information -- language information is also needed [RFC-2130]. For example, support for handicapped users may require reading text string Freed & Moore Standards Track [Page 2] RFC 2231 MIME Value and Encoded Word Extensions November 1997 aloud. The language the text is written in is needed for this to be done correctly. Some parameter values may need to be displayed, hence there is a need to allow for the inclusion of language information. The last problem on this list is also an issue for the encoded words defined by RFC 2047, as encoded words are intended primarily for display purposes. This document defines extensions that address all of these limitations. All of these extensions are implemented in a fashion that is completely compatible at a syntactic level with existing MIME implementations. In addition, the extensions are designed to have as little impact as possible on existing uses of MIME. IMPORTANT NOTE: These mechanisms end up being somewhat gibbous when they actually are used. As such, these mechanisms should not be used lightly; they should be reserved for situations where a real need for them exists. 2.1. Requirements notation This document occasionally uses terms that appear in capital letters. When the terms "MUST", "SHOULD", "MUST NOT", "SHOULD NOT", and "MAY" appear capitalized, they are being used to indicate particular requirements of this specification. A discussion of the meanings of these terms appears in [RFC- 2119]. 3. Parameter Value Continuations Long MIME media type or disposition parameter values do not interact well with header line wrapping conventions. In particular, proper header line wrapping depends on there being places where linear whitespace (LWSP) is allowed, which may or may not be present in a parameter value, and even if present may not be recognizable as such since specific knowledge of parameter value syntax may not be available to the agent doing the line wrapping. The result is that long parameter values may end up getting truncated or otherwise damaged by incorrect line wrapping implementations. A mechanism is therefore needed to break up parameter values into smaller units that are amenable to line wrapping. Any such mechanism MUST be compatible with existing MIME processors. This means that (1) the mechanism MUST NOT change the syntax of MIME media type and disposition lines, and Freed & Moore Standards Track [Page 3] RFC 2231 MIME Value and Encoded Word Extensions November 1997 (2) the mechanism MUST NOT depend on parameter ordering since MIME states that parameters are not order sensitive. Note that while MIME does prohibit modification of MIME headers during transport, it is still possible that parameters will be reordered when user agent level processing is done. The obvious solution, then, is to use multiple parameters to contain a single parameter value and to use some kind of distinguished name to indicate when this is being done. And this obvious solution is exactly what is specified here: The asterisk character ("*") followed by a decimal count is employed to indicate that multiple parameters are being used to encapsulate a single parameter value. The count starts at 0 and increments by 1 for each subsequent section of the parameter value. Decimal values are used and neither leading zeroes nor gaps in the sequence are allowed. The original parameter value is recovered by concatenating the various sections of the parameter, in order. For example, the content-type field Content-Type: message/external-body; access-type=URL; URL*0="ftp://"; URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" is semantically identical to Content-Type: message/external-body; access-type=URL; URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" Note that quotes around parameter values are part of the value syntax; they are NOT part of the value itself. Furthermore, it is explicitly permitted to have a mixture of quoted and unquoted continuation fields. 4. Parameter Value Character Set and Language Information Some parameter values may need to be qualified with character set or language information. It is clear that a distinguished parameter name is needed to identify when this information is present along with a specific syntax for the information in the value itself. In addition, a lightweight encoding mechanism is needed to accommodate 8 bit information in parameter values. Freed & Moore Standards Track [Page 4] RFC 2231 MIME Value and Encoded Word Extensions November 1997 Asterisks ("*") are reused to provide the indicator that language and character set information is present and encoding is being used. A single quote ("'") is used to delimit the character set and language information at the beginning of the parameter value. Percent signs ("%") are used as the encoding flag, which agrees with RFC 2047. Specifically, an asterisk at the end of a parameter name acts as an indicator that character set and language information may appear at the beginning of the parameter value. A single quote is used to separate the character set, language, and actual value information in the parameter value string, and an percent sign is used to flag octets encoded in hexadecimal. For example: Content-Type: application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A Note that it is perfectly permissible to leave either the character set or language field blank. Note also that the single quote delimiters MUST be present even when one of the field values is omitted. This is done when either character set, language, or both are not relevant to the parameter value at hand. This MUST NOT be done in order to indicate a default character set or language -- parameter field definitions MUST NOT assign a default character set or language. 4.1. Combining Character Set, Language, and Parameter Continuations Character set and language information may be combined with the parameter continuation mechanism. For example: Content-Type: application/x-stuff title*0*=us-ascii'en'This%20is%20even%20more%20 title*1*=%2A%2A%2Afun%2A%2A%2A%20 title*2="isn't it!" Note that: (1) Language and character set information only appear at the beginning of a given parameter value. (2) Continuations do not provide a facility for using more than one character set or language in the same parameter value. (3) A value presented using multiple continuations may contain a mixture of encoded and unencoded segments. Freed & Moore Standards Track [Page 5] RFC 2231 MIME Value and Encoded Word Extensions November 1997 (4) The first segment of a continuation MUST be encoded if language and character set information are given. (5) If the first segment of a continued parameter value is encoded the language and character set field delimiters MUST be present even when the fields are left blank. 5. Language specification in Encoded Words RFC 2047 provides support for non-US-ASCII character sets in RFC 822 message header comments, phrases, and any unstructured text field. This is done by defining an encoded word construct which can appear in any of these places. Given that these are fields intended for display, it is sometimes necessary to associate language information with encoded words as well as just the character set. This specification extends the definition of an encoded word to allow the inclusion of such information. This is simply done by suffixing the character set specification with an asterisk followed by the language tag. For example: From: =?US-ASCII*EN?Q?Keith_Moore?= 6. IMAP4 Handling of Parameter Values IMAP4 [RFC-2060] servers SHOULD decode parameter value continuations when generating the BODY and BODYSTRUCTURE fetch attributes. 7. Modifications to MIME ABNF The ABNF for MIME parameter values given in RFC 2045 is: parameter := attribute "=" value attribute := token ; Matching of attributes ; is ALWAYS case-insensitive. This specification changes this ABNF to: parameter := regular-parameter / extended-parameter regular-parameter := regular-parameter-name "=" value regular-parameter-name := attribute [section] attribute := 1*attribute-char Freed & Moore Standards Track [Page 6] RFC 2231 MIME Value and Encoded Word Extensions November 1997 attribute-char := section := initial-section / other-sections initial-section := "*0" other-sections := "*" ("1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9") *DIGIT) extended-parameter := (extended-initial-name "=" extended-value) / (extended-other-names "=" extended-other-values) extended-initial-name := attribute [initial-section] "*" extended-other-names := attribute other-sections "*" extended-initial-value := [charset] "'" [language] "'" extended-other-values extended-other-values := *(ext-octet / attribute-char) ext-octet := "%" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F") charset := language := The ABNF given in RFC 2047 for encoded-words is: encoded-word := "=?" charset "?" encoding "?" encoded-text "?=" This specification changes this ABNF to: encoded-word := "=?" charset ["*" language] "?" encoded-text "?=" 8. Character sets which allow specification of language In the future it is likely that some character sets will provide facilities for inline language labeling. Such facilities are inherently more flexible than those defined here as they allow for language switching in the middle of a string. Freed & Moore Standards Track [Page 7] RFC 2231 MIME Value and Encoded Word Extensions November 1997 If and when such facilities are developed they SHOULD be used in preference to the language labeling facilities specified here. Note that all the mechanisms defined here allow for the omission of language labels so as to be able to accommodate this possible future usage. 9. Security Considerations This RFC does not discuss security issues and is not believed to raise any security issues not already endemic in electronic mail and present in fully conforming implementations of MIME. 10. References [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822 August 1982. [RFC-1766] Alvestrand, H., "Tags for the Identification of Languages", RFC 1766, March 1995. [RFC-2045] Freed, N., and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, December 1996. [RFC-2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, December 1996. [RFC-2047] Moore, K., "Multipurpose Internet Mail Extensions (MIME) Part Three: Representation of Non-ASCII Text in Internet Message Headers", RFC 2047, December 1996. [RFC-2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose Internet Mail Extensions (MIME) Part Four: MIME Registration Procedures", RFC 2048, December 1996. [RFC-2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples", RFC 2049, December 1996. Freed & Moore Standards Track [Page 8] RFC 2231 MIME Value and Encoded Word Extensions November 1997 [RFC-2060] Crispin, M., "Internet Message Access Protocol - Version 4rev1", RFC 2060, December 1996. [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, March 1997. [RFC-2130] Weider, C., Preston, C., Simonsen, K., Alvestrand, H., Atkinson, R., Crispin, M., and P. Svanberg, "Report from the IAB Character Set Workshop", RFC 2130, April 1997. [RFC-2183] Troost, R., Dorner, S. and K. Moore, "Communicating Presentation Information in Internet Messages: The Content-Disposition Header", RFC 2183, August 1997. 11. Authors' Addresses Ned Freed Innosoft International, Inc. 1050 Lakes Drive West Covina, CA 91790 USA Phone: +1 626 919 3600 Fax: +1 626 919 3614 EMail: ned.freed@innosoft.com Keith Moore Computer Science Dept. University of Tennessee 107 Ayres Hall Knoxville, TN 37996-1301 USA EMail: moore@cs.utk.edu Freed & Moore Standards Track [Page 9] RFC 2231 MIME Value and Encoded Word Extensions November 1997 12. Full Copyright Statement Copyright (C) The Internet Society (1997). 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. Freed & Moore Standards Track [Page 10] mail-2.5.4/reference/rfc2387 MIME Multipart-Related Content-type.txt000066400000000000000000000457431214434061600246610ustar00rootroot00000000000000 Network Working Group E. Levinson Request for Comments: 2387 August 1998 Obsoletes: 2112 Category: Standards Track The MIME Multipart/Related Content-type 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 Multipart/Related content-type provides a common mechanism for representing objects that are aggregates of related MIME body parts. This document defines the Multipart/Related content-type and provides examples of its use. 1. Introduction Several applications of MIME, including MIME-PEM, and MIME-Macintosh and other proposals, require multiple body parts that make sense only in the aggregate. The present approach to these compound objects has been to define specific multipart subtypes for each new object. In keeping with the MIME philosophy of having one mechanism to achieve the same goal for different purposes, this document describes a single mechanism for such aggregate or compound objects. The Multipart/Related content-type addresses the MIME representation of compound objects. The object is categorized by a "type" parameter. Additional parameters are provided to indicate a specific starting body part or root and auxiliary information which may be required when unpacking or processing the object. Multipart/Related MIME entities may contain Content-Disposition headers that provide suggestions for the storage and display of a body part. Multipart/Related processing takes precedence over Content-Disposition; the interaction between them is discussed in section 4. Levinson Standards Track [Page 1] RFC 2387 Multipart/Related August 1998 Responsibility for the display or processing of a Multipart/Related's constituent entities rests with the application that handles the compound object. 2. Multipart/Related Registration Information The following form is copied from RFC 1590, Appendix A. To: IANA@isi.edu Subject: Registration of new Media Type content-type/subtype Media Type name: Multipart Media subtype name: Related Required parameters: Type, a media type/subtype. Optional parameters: Start Start-info Encoding considerations: Multipart content-types cannot have encodings. Security considerations: Depends solely on the referenced type. Published specification: RFC-REL (this document). Person & email address to contact for further information: Edward Levinson 47 Clive Street Metuchen, NJ 08840-1060 +1 908 494 1606 XIson@cnj.digex.net 3. Intended usage The Multipart/Related media type is intended for compound objects consisting of several inter-related body parts. For a Multipart/Related object, proper display cannot be achieved by individually displaying the constituent body parts. The content-type of the Multipart/Related object is specified by the type parameter. The "start" parameter, if given, points, via a content-ID, to the body part that contains the object root. The default root is the first body part within the Multipart/Related body. The relationships among the body parts of a compound object distinguishes it from other object types. These relationships are often represented by links internal to the object's components that Levinson Standards Track [Page 2] RFC 2387 Multipart/Related August 1998 reference the other components. Within a single operating environment the links are often file names, such links may be represented within a MIME message using content-IDs or the value of some other "Content-" headers. 3.1. The Type Parameter The type parameter must be specified and its value is the MIME media type of the "root" body part. It permits a MIME user agent to determine the content-type without reference to the enclosed body part. If the value of the type parameter and the root body part's content-type differ then the User Agent's behavior is undefined. 3.2. The Start Parameter The start parameter, if given, is the content-ID of the compound object's "root". If not present the "root" is the first body part in the Multipart/Related entity. The "root" is the element the applications processes first. 3.3. The Start-Info Parameter Additional information can be provided to an application by the start-info parameter. It contains either a string or points, via a content-ID, to another MIME entity in the message. A typical use might be to provide additional command line parameters or a MIME entity giving auxiliary information for processing the compound object. Applications that use Multipart/Related must specify the interpretation of start-info. User Agents shall provide the parameter's value to the processing application. Processes can distinguish a start-info reference from a token or quoted-string by examining the first non-white-space character, "<" indicates a reference. 3.4. Syntax related-param := [ ";" "start" "=" cid ] [ ";" "start-info" "=" ( cid-list / value ) ] [ ";" "type" "=" type "/" subtype ] ; order independent cid-list := cid cid-list cid := msg-id ; c.f. [822] Levinson Standards Track [Page 3] RFC 2387 Multipart/Related August 1998 value := token / quoted-string ; c.f. [MIME] ; value cannot begin with "<" Note that the parameter values will usually require quoting. Msg-id contains the special characters "<", ">", "@", and perhaps other special characters. If msg-id contains quoted-strings, those quote marks must be escaped. Similarly, the type parameter contains the special character "/". 4. Handling Content-Disposition Headers Content-Disposition Headers [DISP] suggest presentation styles for MIME body parts. [DISP] describes two presentation styles, called the disposition type, INLINE and ATTACHMENT. These, used within a multipart entity, allow the sender to suggest presentation information. [DISP] also provides for an optional storage (file) name. Content-Disposition headers could appear in one or more body parts contained within a Multipart/Related entity. Using Content-Disposition headers in addition to Multipart/Related provides presentation information to User Agents that do not recognize Multipart/Related. They will treat the multipart as Multipart/Mixed and they may find the Content-Disposition information useful. With Multipart/Related however, the application processing the compound object determines the presentation style for all the contained parts. In that context the Content-Disposition header information is redundant or even misleading. Hence, User Agents that understand Multipart/Related shall ignore the disposition type within a Multipart/Related body part. It may be possible for a User Agent capable of handling both Multipart/Related and Content-Disposition headers to provide the invoked application the Content-Disposition header's optional filename parameter to the Multipart/Related. The use of that information will depend on the specific application and should be specified when describing the handling of the corresponding compound object. Such descriptions would be appropriate in an RFC registering that object's media type. 5. Examples 5.1 Application/X-FixedRecord The X-FixedRecord content-type consists of one or more octet-streams and a list of the lengths of each record. The root, which lists the record lengths of each record within the streams. The record length Levinson Standards Track [Page 4] RFC 2387 Multipart/Related August 1998 list, type Application/X-FixedRecord, consists of a set of INTEGERs in ASCII format, one per line. Each INTEGER gives the number of octets from the octet-stream body part that constitute the next "record". The example below, uses a single data block. Content-Type: Multipart/Related; boundary=example-1 start="<950120.aaCC@XIson.com>"; type="Application/X-FixedRecord" start-info="-o ps" --example-1 Content-Type: Application/X-FixedRecord Content-ID: <950120.aaCC@XIson.com> 25 10 34 10 25 21 26 10 --example-1 Content-Type: Application/octet-stream Content-Description: The fixed length records Content-Transfer-Encoding: base64 Content-ID: <950120.aaCB@XIson.com> T2xkIE1hY0RvbmFsZCBoYWQgYSBmYXJtCkUgSS BFIEkgTwpBbmQgb24gaGlzIGZhcm0gaGUgaGFk IHNvbWUgZHVja3MKRSBJIEUgSSBPCldpdGggYS BxdWFjayBxdWFjayBoZXJlLAphIHF1YWNrIHF1 YWNrIHRoZXJlLApldmVyeSB3aGVyZSBhIHF1YW NrIHF1YWNrCkUgSSBFIEkgTwo= --example-1-- Levinson Standards Track [Page 5] RFC 2387 Multipart/Related August 1998 5.2 Text/X-Okie The Text/X-Okie is an invented markup language permitting the inclusion of images with text. A feature of this example is the inclusion of two additional body parts, both picture. They are referred to internally by the encapsulated document via each picture's body part content-ID. Usage of "cid:", as in this example, may be useful for a variety of compound objects. It is not, however, a part of the Multipart/Related specification. Content-Type: Multipart/Related; boundary=example-2; start="<950118.AEBH@XIson.com>" type="Text/x-Okie" --example-2 Content-Type: Text/x-Okie; charset=iso-8859-1; declaration="<950118.AEB0@XIson.com>" Content-ID: <950118.AEBH@XIson.com> Content-Description: Document {doc} This picture was taken by an automatic camera mounted ... {image file=cid:950118.AECB@XIson.com} {para} Now this is an enlargement of the area ... {image file=cid:950118:AFDH@XIson.com} {/doc} --example-2 Content-Type: image/jpeg Content-ID: <950118.AFDH@XIson.com> Content-Transfer-Encoding: BASE64 Content-Description: Picture A [encoded jpeg image] --example-2 Content-Type: image/jpeg Content-ID: <950118.AECB@XIson.com> Content-Transfer-Encoding: BASE64 Content-Description: Picture B [encoded jpeg image] --example-2-- 5.3 Content-Disposition In the above example each image body part could also have a Content- Disposition header. For example, Levinson Standards Track [Page 6] RFC 2387 Multipart/Related August 1998 --example-2 Content-Type: image/jpeg Content-ID: <950118.AECB@XIson.com> Content-Transfer-Encoding: BASE64 Content-Description: Picture B Content-Disposition: INLINE [encoded jpeg image] --example-2-- User Agents that recognize Multipart/Related will ignore the Content-Disposition header's disposition type. Other User Agents will process the Multipart/Related as Multipart/Mixed and may make use of that header's information. 6. User Agent Requirements User agents that do not recognize Multipart/Related shall, in accordance with [MIME], treat the entire entity as Multipart/Mixed. MIME User Agents that do recognize Multipart/Related entities but are unable to process the given type should give the user the option of suppressing the entire Multipart/Related body part shall be. Existing MIME-capable mail user agents (MUAs) handle the existing media types in a straightforward manner. For discrete media types (e.g. text, image, etc.) the body of the entity can be directly passed to a display process. Similarly the existing composite subtypes can be reduced to handing one or more discrete types. Handling Multipart/Related differs in that processing cannot be reduced to handling the individual entities. The following sections discuss what information the processing application requires. It is possible that an application specific "receiving agent" will manipulate the entities for display prior to invoking actual application process. Okie, above, is an example of this; it may need a receiving agent to parse the document and substitute local file names for the originator's file names. Other applications may just require a table showing the correspondence between the local file names and the originator's. The receiving agent takes responsibility for such processing. 6.1 Data Requirements MIME-capable mail user agents (MUAs) are required to provide the application: Levinson Standards Track [Page 7] RFC 2387 Multipart/Related August 1998 (a) the bodies of the MIME entities and the entity Content-* headers, (b) the parameters of the Multipart/Related Content-type header, and (c) the correspondence between each body's local file name, that body's header data, and, if present, the body part's content-ID. 6.2 Storing Multipart/Related Entities The Multipart/Related media type will be used for objects that have internal linkages between the body parts. When the objects are stored the linkages may require processing by the application or its receiving agent. 6.3 Recursion MIME is a recursive structure. Hence one must expect a Multipart/Related entity to contain other Multipart/Related entities. When a Multipart/Related entity is being processed for display or storage, any enclosed Multipart/Related entities shall be processed as though they were being stored. 6.4 Configuration Considerations It is suggested that MUAs that use configuration mechanisms, see [CFG] for an example, refer to Multipart/Related as Multi- part/Related/, were is the value of the "type" parameter. 7. Security Considerations Security considerations relevant to Multipart/Related are identical to those of the underlying content-type. 8. Acknowledgments This proposal is the result of conversations the author has had with many people. In particular, Harald A. Alvestrand, James Clark, Charles Goldfarb, Gary Houston, Ned Freed, Ray Moody, and Don Stinchfield, provided both encouragement and invaluable help. The author, however, take full responsibility for all errors contained in this document. Levinson Standards Track [Page 8] RFC 2387 Multipart/Related August 1998 9. References [822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", STD 11, RFC 822, August 1982. [CID] Levinson, E., and J. Clark, "Message/External-Body Content-ID Access Type", RFC 1873, December 1995, Levinson, E., "Message/External-Body Content-ID Access Type", Work in Progress. [CFG] Borenstein, N., "A User Agent Configuration Mechanism For Multimedia Mail Format Information", RFC 1524, September 1993. [DISP] Troost, R., and S. Dorner, "Communicating Presentation Information in Internet Messages: The Content- Disposition Header", RFC 1806, June 1995. [MIME] Borenstein, N., and Freed, N., "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996. 9. Author's Address Edward Levinson 47 Clive Street Metuchen, NJ 08840-1060 USA Phone: +1 908 494 1606 EMail: XIson@cnj.digex.com 10. Changes from previous draft (RFC 2112) Corrected cid urls to conform to RFC 2111; the angle brackets were removed. Levinson Standards Track [Page 9] RFC 2387 Multipart/Related August 1998 11. 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. Levinson Standards Track [Page 10] mail-2.5.4/reference/rfc2821 Simple Mail Transfer Protocol.txt000066400000000000000000005402641214434061600236520ustar00rootroot00000000000000Network Working Group J. Klensin, Editor Request for Comments: 2821 AT&T Laboratories Obsoletes: 821, 974, 1869 April 2001 Updates: 1123 Category: Standards Track Simple Mail Transfer Protocol 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 (2001). All Rights Reserved. Abstract This document is a self-contained specification of the basic protocol for the Internet electronic mail transport. It consolidates, updates and clarifies, but doesn't add new or change existing functionality of the following: - the original SMTP (Simple Mail Transfer Protocol) specification of RFC 821 [30], - domain name system requirements and implications for mail transport from RFC 1035 [22] and RFC 974 [27], - the clarifications and applicability statements in RFC 1123 [2], and - material drawn from the SMTP Extension mechanisms [19]. It obsoletes RFC 821, RFC 974, and updates RFC 1123 (replaces the mail transport materials of RFC 1123). However, RFC 821 specifies some features that were not in significant use in the Internet by the mid-1990s and (in appendices) some additional transport models. Those sections are omitted here in the interest of clarity and brevity; readers needing them should refer to RFC 821. It also includes some additional material from RFC 1123 that required amplification. This material has been identified in multiple ways, mostly by tracking flaming on various lists and newsgroups and problems of unusual readings or interpretations that have appeared as the SMTP extensions have been deployed. Where this specification moves beyond consolidation and actually differs from earlier documents, it supersedes them technically as well as textually. Although SMTP was designed as a mail transport and delivery protocol, this specification also contains information that is important to its use as a 'mail submission' protocol, as recommended for POP [3, 26] and IMAP [6]. Additional submission issues are discussed in RFC 2476 [15]. Section 2.3 provides definitions of terms specific to this document. Except when the historical terminology is necessary for clarity, this document uses the current 'client' and 'server' terminology to identify the sending and receiving SMTP processes, respectively. A companion document [32] discusses message headers, message bodies and formats and structures for them, and their relationship. Table of Contents 1. Introduction .................................................. 4 2. The SMTP Model ................................................ 5 2.1 Basic Structure .............................................. 5 2.2 The Extension Model .......................................... 7 2.2.1 Background ................................................. 7 2.2.2 Definition and Registration of Extensions .................. 8 2.3 Terminology .................................................. 9 2.3.1 Mail Objects ............................................... 10 2.3.2 Senders and Receivers ...................................... 10 2.3.3 Mail Agents and Message Stores ............................. 10 2.3.4 Host ....................................................... 11 2.3.5 Domain ..................................................... 11 2.3.6 Buffer and State Table ..................................... 11 2.3.7 Lines ...................................................... 12 2.3.8 Originator, Delivery, Relay, and Gateway Systems ........... 12 2.3.9 Message Content and Mail Data .............................. 13 2.3.10 Mailbox and Address ....................................... 13 2.3.11 Reply ..................................................... 13 2.4 General Syntax Principles and Transaction Model .............. 13 3. The SMTP Procedures: An Overview .............................. 15 3.1 Session Initiation ........................................... 15 3.2 Client Initiation ............................................ 16 3.3 Mail Transactions ............................................ 16 3.4 Forwarding for Address Correction or Updating ................ 19 3.5 Commands for Debugging Addresses ............................. 20 3.5.1 Overview ................................................... 20 3.5.2 VRFY Normal Response ....................................... 22 3.5.3 Meaning of VRFY or EXPN Success Response ................... 22 3.5.4 Semantics and Applications of EXPN ......................... 23 3.6 Domains ...................................................... 23 3.7 Relaying ..................................................... 24 3.8 Mail Gatewaying .............................................. 25 3.8.1 Header Fields in Gatewaying ................................ 26 3.8.2 Received Lines in Gatewaying ............................... 26 3.8.3 Addresses in Gatewaying .................................... 26 3.8.4 Other Header Fields in Gatewaying .......................... 27 3.8.5 Envelopes in Gatewaying .................................... 27 3.9 Terminating Sessions and Connections ......................... 27 3.10 Mailing Lists and Aliases ................................... 28 3.10.1 Alias ..................................................... 28 3.10.2 List ...................................................... 28 4. The SMTP Specifications ....................................... 29 4.1 SMTP Commands ................................................ 29 4.1.1 Command Semantics and Syntax ............................... 29 4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO) ................... 29 4.1.1.2 MAIL (MAIL) .............................................. 31 4.1.1.3 RECIPIENT (RCPT) ......................................... 31 4.1.1.4 DATA (DATA) .............................................. 33 4.1.1.5 RESET (RSET) ............................................. 34 4.1.1.6 VERIFY (VRFY) ............................................ 35 4.1.1.7 EXPAND (EXPN) ............................................ 35 4.1.1.8 HELP (HELP) .............................................. 35 4.1.1.9 NOOP (NOOP) .............................................. 35 4.1.1.10 QUIT (QUIT) ............................................. 36 4.1.2 Command Argument Syntax .................................... 36 4.1.3 Address Literals ........................................... 38 4.1.4 Order of Commands .......................................... 39 4.1.5 Private-use Commands ....................................... 40 4.2 SMTP Replies ................................................ 40 4.2.1 Reply Code Severities and Theory ........................... 42 4.2.2 Reply Codes by Function Groups ............................. 44 4.2.3 Reply Codes in Numeric Order .............................. 45 4.2.4 Reply Code 502 ............................................. 46 4.2.5 Reply Codes After DATA and the Subsequent . .... 46 4.3 Sequencing of Commands and Replies ........................... 47 4.3.1 Sequencing Overview ........................................ 47 4.3.2 Command-Reply Sequences .................................... 48 4.4 Trace Information ............................................ 49 4.5 Additional Implementation Issues ............................. 53 4.5.1 Minimum Implementation ..................................... 53 4.5.2 Transparency ............................................... 53 4.5.3 Sizes and Timeouts ......................................... 54 4.5.3.1 Size limits and minimums ................................. 54 4.5.3.2 Timeouts ................................................. 56 4.5.4 Retry Strategies ........................................... 57 4.5.4.1 Sending Strategy ......................................... 58 4.5.4.2 Receiving Strategy ....................................... 59 4.5.5 Messages with a null reverse-path .......................... 59 5. Address Resolution and Mail Handling .......................... 60 6. Problem Detection and Handling ................................ 62 6.1 Reliable Delivery and Replies by Email ....................... 62 6.2 Loop Detection ............................................... 63 6.3 Compensating for Irregularities .............................. 63 7. Security Considerations ....................................... 64 7.1 Mail Security and Spoofing ................................... 64 7.2 "Blind" Copies ............................................... 65 7.3 VRFY, EXPN, and Security ..................................... 65 7.4 Information Disclosure in Announcements ...................... 66 7.5 Information Disclosure in Trace Fields ....................... 66 7.6 Information Disclosure in Message Forwarding ................. 67 7.7 Scope of Operation of SMTP Servers ........................... 67 8. IANA Considerations ........................................... 67 9. References .................................................... 68 10. Editor's Address ............................................. 70 11. Acknowledgments .............................................. 70 Appendices ....................................................... 71 A. TCP Transport Service ......................................... 71 B. Generating SMTP Commands from RFC 822 Headers ................. 71 C. Source Routes ................................................. 72 D. Scenarios ..................................................... 73 E. Other Gateway Issues .......................................... 76 F. Deprecated Features of RFC 821 ................................ 76 Full Copyright Statement ......................................... 79 1. Introduction The objective of the Simple Mail Transfer Protocol (SMTP) is to transfer mail reliably and efficiently. SMTP is independent of the particular transmission subsystem and requires only a reliable ordered data stream channel. While this document specifically discusses transport over TCP, other transports are possible. Appendices to RFC 821 describe some of them. An important feature of SMTP is its capability to transport mail across networks, usually referred to as "SMTP mail relaying" (see section 3.8). A network consists of the mutually-TCP-accessible hosts on the public Internet, the mutually-TCP-accessible hosts on a firewall-isolated TCP/IP Intranet, or hosts in some other LAN or WAN environment utilizing a non-TCP transport-level protocol. Using SMTP, a process can transfer mail to another process on the same network or to some other network via a relay or gateway process accessible to both networks. In this way, a mail message may pass through a number of intermediate relay or gateway hosts on its path from sender to ultimate recipient. The Mail eXchanger mechanisms of the domain name system [22, 27] (and section 5 of this document) are used to identify the appropriate next-hop destination for a message being transported. 2. The SMTP Model 2.1 Basic Structure The SMTP design can be pictured as: +----------+ +----------+ +------+ | | | | | User |<-->| | SMTP | | +------+ | Client- |Commands/Replies| Server- | +------+ | SMTP |<-------------->| SMTP | +------+ | File |<-->| | and Mail | |<-->| File | |System| | | | | |System| +------+ +----------+ +----------+ +------+ SMTP client SMTP server When an SMTP client has a message to transmit, it establishes a two- way transmission channel to an SMTP server. The responsibility of an SMTP client is to transfer mail messages to one or more SMTP servers, or report its failure to do so. The means by which a mail message is presented to an SMTP client, and how that client determines the domain name(s) to which mail messages are to be transferred is a local matter, and is not addressed by this document. In some cases, the domain name(s) transferred to, or determined by, an SMTP client will identify the final destination(s) of the mail message. In other cases, common with SMTP clients associated with implementations of the POP [3, 26] or IMAP [6] protocols, or when the SMTP client is inside an isolated transport service environment, the domain name determined will identify an intermediate destination through which all mail messages are to be relayed. SMTP clients that transfer all traffic, regardless of the target domain names associated with the individual messages, or that do not maintain queues for retrying message transmissions that initially cannot be completed, may otherwise conform to this specification but are not considered fully-capable. Fully-capable SMTP implementations, including the relays used by these less capable ones, and their destinations, are expected to support all of the queuing, retrying, and alternate address functions discussed in this specification. The means by which an SMTP client, once it has determined a target domain name, determines the identity of an SMTP server to which a copy of a message is to be transferred, and then performs that transfer, is covered by this document. To effect a mail transfer to an SMTP server, an SMTP client establishes a two-way transmission channel to that SMTP server. An SMTP client determines the address of an appropriate host running an SMTP server by resolving a destination domain name to either an intermediate Mail eXchanger host or a final target host. An SMTP server may be either the ultimate destination or an intermediate "relay" (that is, it may assume the role of an SMTP client after receiving the message) or "gateway" (that is, it may transport the message further using some protocol other than SMTP). SMTP commands are generated by the SMTP client and sent to the SMTP server. SMTP replies are sent from the SMTP server to the SMTP client in response to the commands. In other words, message transfer can occur in a single connection between the original SMTP-sender and the final SMTP-recipient, or can occur in a series of hops through intermediary systems. In either case, a formal handoff of responsibility for the message occurs: the protocol requires that a server accept responsibility for either delivering a message or properly reporting the failure to do so. Once the transmission channel is established and initial handshaking completed, the SMTP client normally initiates a mail transaction. Such a transaction consists of a series of commands to specify the originator and destination of the mail and transmission of the message content (including any headers or other structure) itself. When the same message is sent to multiple recipients, this protocol encourages the transmission of only one copy of the data for all recipients at the same destination (or intermediate relay) host. The server responds to each command with a reply; replies may indicate that the command was accepted, that additional commands are expected, or that a temporary or permanent error condition exists. Commands specifying the sender or recipients may include server- permitted SMTP service extension requests as discussed in section 2.2. The dialog is purposely lock-step, one-at-a-time, although this can be modified by mutually-agreed extension requests such as command pipelining [13]. Once a given mail message has been transmitted, the client may either request that the connection be shut down or may initiate other mail transactions. In addition, an SMTP client may use a connection to an SMTP server for ancillary services such as verification of email addresses or retrieval of mailing list subscriber addresses. As suggested above, this protocol provides mechanisms for the transmission of mail. This transmission normally occurs directly from the sending user's host to the receiving user's host when the two hosts are connected to the same transport service. When they are not connected to the same transport service, transmission occurs via one or more relay SMTP servers. An intermediate host that acts as either an SMTP relay or as a gateway into some other transmission environment is usually selected through the use of the domain name service (DNS) Mail eXchanger mechanism. Usually, intermediate hosts are determined via the DNS MX record, not by explicit "source" routing (see section 5 and appendices C and F.2). 2.2 The Extension Model 2.2.1 Background In an effort that started in 1990, approximately a decade after RFC 821 was completed, the protocol was modified with a "service extensions" model that permits the client and server to agree to utilize shared functionality beyond the original SMTP requirements. The SMTP extension mechanism defines a means whereby an extended SMTP client and server may recognize each other, and the server can inform the client as to the service extensions that it supports. Contemporary SMTP implementations MUST support the basic extension mechanisms. For instance, servers MUST support the EHLO command even if they do not implement any specific extensions and clients SHOULD preferentially utilize EHLO rather than HELO. (However, for compatibility with older conforming implementations, SMTP clients and servers MUST support the original HELO mechanisms as a fallback.) Unless the different characteristics of HELO must be identified for interoperability purposes, this document discusses only EHLO. SMTP is widely deployed and high-quality implementations have proven to be very robust. However, the Internet community now considers some services to be important that were not anticipated when the protocol was first designed. If support for those services is to be added, it must be done in a way that permits older implementations to continue working acceptably. The extension framework consists of: - The SMTP command EHLO, superseding the earlier HELO, - a registry of SMTP service extensions, - additional parameters to the SMTP MAIL and RCPT commands, and - optional replacements for commands defined in this protocol, such as for DATA in non-ASCII transmissions [33]. SMTP's strength comes primarily from its simplicity. Experience with many protocols has shown that protocols with few options tend towards ubiquity, whereas protocols with many options tend towards obscurity. Each and every extension, regardless of its benefits, must be carefully scrutinized with respect to its implementation, deployment, and interoperability costs. In many cases, the cost of extending the SMTP service will likely outweigh the benefit. 2.2.2 Definition and Registration of Extensions The IANA maintains a registry of SMTP service extensions. A corresponding EHLO keyword value is associated with each extension. Each service extension registered with the IANA must be defined in a formal standards-track or IESG-approved experimental protocol document. The definition must include: - the textual name of the SMTP service extension; - the EHLO keyword value associated with the extension; - the syntax and possible values of parameters associated with the EHLO keyword value; - any additional SMTP verbs associated with the extension (additional verbs will usually be, but are not required to be, the same as the EHLO keyword value); - any new parameters the extension associates with the MAIL or RCPT verbs; - a description of how support for the extension affects the behavior of a server and client SMTP; and, - the increment by which the extension is increasing the maximum length of the commands MAIL and/or RCPT, over that specified in this standard. In addition, any EHLO keyword value starting with an upper or lower case "X" refers to a local SMTP service extension used exclusively through bilateral agreement. Keywords beginning with "X" MUST NOT be used in a registered service extension. Conversely, keyword values presented in the EHLO response that do not begin with "X" MUST correspond to a standard, standards-track, or IESG-approved experimental SMTP service extension registered with IANA. A conforming server MUST NOT offer non-"X"-prefixed keyword values that are not described in a registered extension. Additional verbs and parameter names are bound by the same rules as EHLO keywords; specifically, verbs beginning with "X" are local extensions that may not be registered or standardized. Conversely, verbs not beginning with "X" must always be registered. 2.3 Terminology 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 below. 1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the definition is an absolute requirement of the specification. 2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the definition is an absolute prohibition of the specification. 3. SHOULD This word, or the adjective "RECOMMENDED", mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course. 4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label. 5. MAY This word, or the adjective "OPTIONAL", mean that an item is truly optional. One vendor may choose to include the item because a particular marketplace requires it or because the vendor feels that it enhances the product while another vendor may omit the same item. An implementation which does not include a particular option MUST be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option MUST be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.) 2.3.1 Mail Objects SMTP transports a mail object. A mail object contains an envelope and content. The SMTP envelope is sent as a series of SMTP protocol units (described in section 3). It consists of an originator address (to which error reports should be directed); one or more recipient addresses; and optional protocol extension material. Historically, variations on the recipient address specification command (RCPT TO) could be used to specify alternate delivery modes, such as immediate display; those variations have now been deprecated (see appendix F, section F.6). The SMTP content is sent in the SMTP DATA protocol unit and has two parts: the headers and the body. If the content conforms to other contemporary standards, the headers form a collection of field/value pairs structured as in the message format specification [32]; the body, if structured, is defined according to MIME [12]. The content is textual in nature, expressed using the US-ASCII repertoire [1]. Although SMTP extensions (such as "8BITMIME" [20]) may relax this restriction for the content body, the content headers are always encoded using the US-ASCII repertoire. A MIME extension [23] defines an algorithm for representing header values outside the US-ASCII repertoire, while still encoding them using the US-ASCII repertoire. 2.3.2 Senders and Receivers In RFC 821, the two hosts participating in an SMTP transaction were described as the "SMTP-sender" and "SMTP-receiver". This document has been changed to reflect current industry terminology and hence refers to them as the "SMTP client" (or sometimes just "the client") and "SMTP server" (or just "the server"), respectively. Since a given host may act both as server and client in a relay situation, "receiver" and "sender" terminology is still used where needed for clarity. 2.3.3 Mail Agents and Message Stores Additional mail system terminology became common after RFC 821 was published and, where convenient, is used in this specification. In particular, SMTP servers and clients provide a mail transport service and therefore act as "Mail Transfer Agents" (MTAs). "Mail User Agents" (MUAs or UAs) are normally thought of as the sources and targets of mail. At the source, an MUA might collect mail to be transmitted from a user and hand it off to an MTA; the final ("delivery") MTA would be thought of as handing the mail off to an MUA (or at least transferring responsibility to it, e.g., by depositing the message in a "message store"). However, while these terms are used with at least the appearance of great precision in other environments, the implied boundaries between MUAs and MTAs often do not accurately match common, and conforming, practices with Internet mail. Hence, the reader should be cautious about inferring the strong relationships and responsibilities that might be implied if these terms were used elsewhere. 2.3.4 Host For the purposes of this specification, a host is a computer system attached to the Internet (or, in some cases, to a private TCP/IP network) and supporting the SMTP protocol. Hosts are known by names (see "domain"); identifying them by numerical address is discouraged. 2.3.5 Domain A domain (or domain name) consists of one or more dot-separated components. These components ("labels" in DNS terminology [22]) are restricted for SMTP purposes to consist of a sequence of letters, digits, and hyphens drawn from the ASCII character set [1]. Domain names are used as names of hosts and of other entities in the domain name hierarchy. For example, a domain may refer to an alias (label of a CNAME RR) or the label of Mail eXchanger records to be used to deliver mail instead of representing a host name. See [22] and section 5 of this specification. The domain name, as described in this document and in [22], is the entire, fully-qualified name (often referred to as an "FQDN"). A domain name that is not in FQDN form is no more than a local alias. Local aliases MUST NOT appear in any SMTP transaction. 2.3.6 Buffer and State Table SMTP sessions are stateful, with both parties carefully maintaining a common view of the current state. In this document we model this state by a virtual "buffer" and a "state table" on the server which may be used by the client to, for example, "clear the buffer" or "reset the state table," causing the information in the buffer to be discarded and the state to be returned to some previous state. 2.3.7 Lines SMTP commands and, unless altered by a service extension, message data, are transmitted in "lines". Lines consist of zero or more data characters terminated by the sequence ASCII character "CR" (hex value 0D) followed immediately by ASCII character "LF" (hex value 0A). This termination sequence is denoted as in this document. Conforming implementations MUST NOT recognize or generate any other character or character sequence as a line terminator. Limits MAY be imposed on line lengths by servers (see section 4.5.3). In addition, the appearance of "bare" "CR" or "LF" characters in text (i.e., either without the other) has a long history of causing problems in mail implementations and applications that use the mail system as a tool. SMTP client implementations MUST NOT transmit these characters except when they are intended as line terminators and then MUST, as indicated above, transmit them only as a sequence. 2.3.8 Originator, Delivery, Relay, and Gateway Systems This specification makes a distinction among four types of SMTP systems, based on the role those systems play in transmitting electronic mail. An "originating" system (sometimes called an SMTP originator) introduces mail into the Internet or, more generally, into a transport service environment. A "delivery" SMTP system is one that receives mail from a transport service environment and passes it to a mail user agent or deposits it in a message store which a mail user agent is expected to subsequently access. A "relay" SMTP system (usually referred to just as a "relay") receives mail from an SMTP client and transmits it, without modification to the message data other than adding trace information, to another SMTP server for further relaying or for delivery. A "gateway" SMTP system (usually referred to just as a "gateway") receives mail from a client system in one transport environment and transmits it to a server system in another transport environment. Differences in protocols or message semantics between the transport environments on either side of a gateway may require that the gateway system perform transformations to the message that are not permitted to SMTP relay systems. For the purposes of this specification, firewalls that rewrite addresses should be considered as gateways, even if SMTP is used on both sides of them (see [11]). 2.3.9 Message Content and Mail Data The terms "message content" and "mail data" are used interchangeably in this document to describe the material transmitted after the DATA command is accepted and before the end of data indication is transmitted. Message content includes message headers and the possibly-structured message body. The MIME specification [12] provides the standard mechanisms for structured message bodies. 2.3.10 Mailbox and Address As used in this specification, an "address" is a character string that identifies a user to whom mail will be sent or a location into which mail will be deposited. The term "mailbox" refers to that depository. The two terms are typically used interchangeably unless the distinction between the location in which mail is placed (the mailbox) and a reference to it (the address) is important. An address normally consists of user and domain specifications. The standard mailbox naming convention is defined to be "local- part@domain": contemporary usage permits a much broader set of applications than simple "user names". Consequently, and due to a long history of problems when intermediate hosts have attempted to optimize transport by modifying them, the local-part MUST be interpreted and assigned semantics only by the host specified in the domain part of the address. 2.3.11 Reply An SMTP reply is an acknowledgment (positive or negative) sent from receiver to sender via the transmission channel in response to a command. The general form of a reply is a numeric completion code (indicating failure or success) usually followed by a text string. The codes are for use by programs and the text is usually intended for human users. Recent work [34] has specified further structuring of the reply strings, including the use of supplemental and more specific completion codes. 2.4 General Syntax Principles and Transaction Model SMTP commands and replies have a rigid syntax. All commands begin with a command verb. All Replies begin with a three digit numeric code. In some commands and replies, arguments MUST follow the verb or reply code. Some commands do not accept arguments (after the verb), and some reply codes are followed, sometimes optionally, by free form text. In both cases, where text appears, it is separated from the verb or reply code by a space character. Complete definitions of commands and replies appear in section 4. Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command and extension name keywords) are not case sensitive, with the sole exception in this specification of a mailbox local-part (SMTP Extensions may explicitly specify case-sensitive elements). That is, a command verb, an argument value other than a mailbox local-part, and free form text MAY be encoded in upper case, lower case, or any mixture of upper and lower case with no impact on its meaning. This is NOT true of a mailbox local-part. The local-part of a mailbox MUST BE treated as case sensitive. Therefore, SMTP implementations MUST take care to preserve the case of mailbox local-parts. Mailbox domains are not case sensitive. In particular, for some hosts the user "smith" is different from the user "Smith". However, exploiting the case sensitivity of mailbox local-parts impedes interoperability and is discouraged. A few SMTP servers, in violation of this specification (and RFC 821) require that command verbs be encoded by clients in upper case. Implementations MAY wish to employ this encoding to accommodate those servers. The argument field consists of a variable length character string ending with the end of the line, i.e., with the character sequence . The receiver will take no action until this sequence is received. The syntax for each command is shown with the discussion of that command. Common elements and parameters are shown in section 4.1.2. Commands and replies are composed of characters from the ASCII character set [1]. When the transport service provides an 8-bit byte (octet) transmission channel, each 7-bit character is transmitted right justified in an octet with the high order bit cleared to zero. More specifically, the unextended SMTP service provides seven bit transport only. An originating SMTP client which has not successfully negotiated an appropriate extension with a particular server MUST NOT transmit messages with information in the high-order bit of octets. If such messages are transmitted in violation of this rule, receiving SMTP servers MAY clear the high-order bit or reject the message as invalid. In general, a relay SMTP SHOULD assume that the message content it has received is valid and, assuming that the envelope permits doing so, relay it without inspecting that content. Of course, if the content is mislabeled and the data path cannot accept the actual content, this may result in ultimate delivery of a severely garbled message to the recipient. Delivery SMTP systems MAY reject ("bounce") such messages rather than deliver them. No sending SMTP system is permitted to send envelope commands in any character set other than US-ASCII; receiving systems SHOULD reject such commands, normally using "500 syntax error - invalid character" replies. Eight-bit message content transmission MAY be requested of the server by a client using extended SMTP facilities, notably the "8BITMIME" extension [20]. 8BITMIME SHOULD be supported by SMTP servers. However, it MUST not be construed as authorization to transmit unrestricted eight bit material. 8BITMIME MUST NOT be requested by senders for material with the high bit on that is not in MIME format with an appropriate content-transfer encoding; servers MAY reject such messages. The metalinguistic notation used in this document corresponds to the "Augmented BNF" used in other Internet mail system documents. The reader who is not familiar with that syntax should consult the ABNF specification [8]. Metalanguage terms used in running text are surrounded by pointed brackets (e.g., ) for clarity. 3. The SMTP Procedures: An Overview This section contains descriptions of the procedures used in SMTP: session initiation, the mail transaction, forwarding mail, verifying mailbox names and expanding mailing lists, and the opening and closing exchanges. Comments on relaying, a note on mail domains, and a discussion of changing roles are included at the end of this section. Several complete scenarios are presented in appendix D. 3.1 Session Initiation An SMTP session is initiated when a client opens a connection to a server and the server responds with an opening message. SMTP server implementations MAY include identification of their software and version information in the connection greeting reply after the 220 code, a practice that permits more efficient isolation and repair of any problems. Implementations MAY make provision for SMTP servers to disable the software and version announcement where it causes security concerns. While some systems also identify their contact point for mail problems, this is not a substitute for maintaining the required "postmaster" address (see section 4.5.1). The SMTP protocol allows a server to formally reject a transaction while still allowing the initial connection as follows: a 554 response MAY be given in the initial connection opening message instead of the 220. A server taking this approach MUST still wait for the client to send a QUIT (see section 4.1.1.10) before closing the connection and SHOULD respond to any intervening commands with "503 bad sequence of commands". Since an attempt to make an SMTP connection to such a system is probably in error, a server returning a 554 response on connection opening SHOULD provide enough information in the reply text to facilitate debugging of the sending system. 3.2 Client Initiation Once the server has sent the welcoming message and the client has received it, the client normally sends the EHLO command to the server, indicating the client's identity. In addition to opening the session, use of EHLO indicates that the client is able to process service extensions and requests that the server provide a list of the extensions it supports. Older SMTP systems which are unable to support service extensions and contemporary clients which do not require service extensions in the mail session being initiated, MAY use HELO instead of EHLO. Servers MUST NOT return the extended EHLO-style response to a HELO command. For a particular connection attempt, if the server returns a "command not recognized" response to EHLO, the client SHOULD be able to fall back and send HELO. In the EHLO command the host sending the command identifies itself; the command may be interpreted as saying "Hello, I am " (and, in the case of EHLO, "and I support service extension requests"). 3.3 Mail Transactions There are three steps to SMTP mail transactions. The transaction starts with a MAIL command which gives the sender identification. (In general, the MAIL command may be sent only when no mail transaction is in progress; see section 4.1.4.) A series of one or more RCPT commands follows giving the receiver information. Then a DATA command initiates transfer of the mail data and is terminated by the "end of mail" data indicator, which also confirms the transaction. The first step in the procedure is the MAIL command. MAIL FROM: [SP ] This command tells the SMTP-receiver that a new mail transaction is starting and to reset all its state tables and buffers, including any recipients or mail data. The portion of the first or only argument contains the source mailbox (between "<" and ">" brackets), which can be used to report errors (see section 4.2 for a discussion of error reporting). If accepted, the SMTP server returns a 250 OK reply. If the mailbox specification is not acceptable for some reason, the server MUST return a reply indicating whether the failure is permanent (i.e., will occur again if the client tries to send the same address again) or temporary (i.e., the address might be accepted if the client tries again later). Despite the apparent scope of this requirement, there are circumstances in which the acceptability of the reverse-path may not be determined until one or more forward-paths (in RCPT commands) can be examined. In those cases, the server MAY reasonably accept the reverse-path (with a 250 reply) and then report problems after the forward-paths are received and examined. Normally, failures produce 550 or 553 replies. Historically, the can contain more than just a mailbox, however, contemporary systems SHOULD NOT use source routing (see appendix C). The optional are associated with negotiated SMTP service extensions (see section 2.2). The second step in the procedure is the RCPT command. RCPT TO: [ SP ] The first or only argument to this command includes a forward-path (normally a mailbox and domain, always surrounded by "<" and ">" brackets) identifying one recipient. If accepted, the SMTP server returns a 250 OK reply and stores the forward-path. If the recipient is known not to be a deliverable address, the SMTP server returns a 550 reply, typically with a string such as "no such user - " and the mailbox name (other circumstances and reply codes are possible). This step of the procedure can be repeated any number of times. The can contain more than just a mailbox. Historically, the can be a source routing list of hosts and the destination mailbox, however, contemporary SMTP clients SHOULD NOT utilize source routes (see appendix C). Servers MUST be prepared to encounter a list of source routes in the forward path, but SHOULD ignore the routes or MAY decline to support the relaying they imply. Similarly, servers MAY decline to accept mail that is destined for other hosts or systems. These restrictions make a server useless as a relay for clients that do not support full SMTP functionality. Consequently, restricted-capability clients MUST NOT assume that any SMTP server on the Internet can be used as their mail processing (relaying) site. If a RCPT command appears without a previous MAIL command, the server MUST return a 503 "Bad sequence of commands" response. The optional are associated with negotiated SMTP service extensions (see section 2.2). The third step in the procedure is the DATA command (or some alternative specified in a service extension). DATA If accepted, the SMTP server returns a 354 Intermediate reply and considers all succeeding lines up to but not including the end of mail data indicator to be the message text. When the end of text is successfully received and stored the SMTP-receiver sends a 250 OK reply. Since the mail data is sent on the transmission channel, the end of mail data must be indicated so that the command and reply dialog can be resumed. SMTP indicates the end of the mail data by sending a line containing only a "." (period or full stop). A transparency procedure is used to prevent this from interfering with the user's text (see section 4.5.2). The end of mail data indicator also confirms the mail transaction and tells the SMTP server to now process the stored recipients and mail data. If accepted, the SMTP server returns a 250 OK reply. The DATA command can fail at only two points in the protocol exchange: - If there was no MAIL, or no RCPT, command, or all such commands were rejected, the server MAY return a "command out of sequence" (503) or "no valid recipients" (554) reply in response to the DATA command. If one of those replies (or any other 5yz reply) is received, the client MUST NOT send the message data; more generally, message data MUST NOT be sent unless a 354 reply is received. - If the verb is initially accepted and the 354 reply issued, the DATA command should fail only if the mail transaction was incomplete (for example, no recipients), or if resources were unavailable (including, of course, the server unexpectedly becoming unavailable), or if the server determines that the message should be rejected for policy or other reasons. However, in practice, some servers do not perform recipient verification until after the message text is received. These servers SHOULD treat a failure for one or more recipients as a "subsequent failure" and return a mail message as discussed in section 6. Using a "550 mailbox not found" (or equivalent) reply code after the data are accepted makes it difficult or impossible for the client to determine which recipients failed. When RFC 822 format [7, 32] is being used, the mail data include the memo header items such as Date, Subject, To, Cc, From. Server SMTP systems SHOULD NOT reject messages based on perceived defects in the RFC 822 or MIME [12] message header or message body. In particular, they MUST NOT reject messages in which the numbers of Resent-fields do not match or Resent-to appears without Resent-from and/or Resent- date. Mail transaction commands MUST be used in the order discussed above. 3.4 Forwarding for Address Correction or Updating Forwarding support is most often required to consolidate and simplify addresses within, or relative to, some enterprise and less frequently to establish addresses to link a person's prior address with current one. Silent forwarding of messages (without server notification to the sender), for security or non-disclosure purposes, is common in the contemporary Internet. In both the enterprise and the "new address" cases, information hiding (and sometimes security) considerations argue against exposure of the "final" address through the SMTP protocol as a side-effect of the forwarding activity. This may be especially important when the final address may not even be reachable by the sender. Consequently, the "forwarding" mechanisms described in section 3.2 of RFC 821, and especially the 251 (corrected destination) and 551 reply codes from RCPT must be evaluated carefully by implementers and, when they are available, by those configuring systems. In particular: * Servers MAY forward messages when they are aware of an address change. When they do so, they MAY either provide address-updating information with a 251 code, or may forward "silently" and return a 250 code. But, if a 251 code is used, they MUST NOT assume that the client will actually update address information or even return that information to the user. Alternately, * Servers MAY reject or bounce messages when they are not deliverable when addressed. When they do so, they MAY either provide address-updating information with a 551 code, or may reject the message as undeliverable with a 550 code and no address-specific information. But, if a 551 code is used, they MUST NOT assume that the client will actually update address information or even return that information to the user. SMTP server implementations that support the 251 and/or 551 reply codes are strongly encouraged to provide configuration mechanisms so that sites which conclude that they would undesirably disclose information can disable or restrict their use. 3.5 Commands for Debugging Addresses 3.5.1 Overview SMTP provides commands to verify a user name or obtain the content of a mailing list. This is done with the VRFY and EXPN commands, which have character string arguments. Implementations SHOULD support VRFY and EXPN (however, see section 3.5.2 and 7.3). For the VRFY command, the string is a user name or a user name and domain (see below). If a normal (i.e., 250) response is returned, the response MAY include the full name of the user and MUST include the mailbox of the user. It MUST be in either of the following forms: User Name local-part@domain When a name that is the argument to VRFY could identify more than one mailbox, the server MAY either note the ambiguity or identify the alternatives. In other words, any of the following are legitimate response to VRFY: 553 User ambiguous or 553- Ambiguous; Possibilities are 553-Joe Smith 553-Harry Smith 553 Melvin Smith or 553-Ambiguous; Possibilities 553- 553- 553 Under normal circumstances, a client receiving a 553 reply would be expected to expose the result to the user. Use of exactly the forms given, and the "user ambiguous" or "ambiguous" keywords, possibly supplemented by extended reply codes such as those described in [34], will facilitate automated translation into other languages as needed. Of course, a client that was highly automated or that was operating in another language than English, might choose to try to translate the response, to return some other indication to the user than the literal text of the reply, or to take some automated action such as consulting a directory service for additional information before reporting to the user. For the EXPN command, the string identifies a mailing list, and the successful (i.e., 250) multiline response MAY include the full name of the users and MUST give the mailboxes on the mailing list. In some hosts the distinction between a mailing list and an alias for a single mailbox is a bit fuzzy, since a common data structure may hold both types of entries, and it is possible to have mailing lists containing only one mailbox. If a request is made to apply VRFY to a mailing list, a positive response MAY be given if a message so addressed would be delivered to everyone on the list, otherwise an error SHOULD be reported (e.g., "550 That is a mailing list, not a user" or "252 Unable to verify members of mailing list"). If a request is made to expand a user name, the server MAY return a positive response consisting of a list containing one name, or an error MAY be reported (e.g., "550 That is a user name, not a mailing list"). In the case of a successful multiline reply (normal for EXPN) exactly one mailbox is to be specified on each line of the reply. The case of an ambiguous request is discussed above. "User name" is a fuzzy term and has been used deliberately. An implementation of the VRFY or EXPN commands MUST include at least recognition of local mailboxes as "user names". However, since current Internet practice often results in a single host handling mail for multiple domains, hosts, especially hosts that provide this functionality, SHOULD accept the "local-part@domain" form as a "user name"; hosts MAY also choose to recognize other strings as "user names". The case of expanding a mailbox list requires a multiline reply, such as: C: EXPN Example-People S: 250-Jon Postel S: 250-Fred Fonebone S: 250 Sam Q. Smith or C: EXPN Executive-Washroom-List S: 550 Access Denied to You. The character string arguments of the VRFY and EXPN commands cannot be further restricted due to the variety of implementations of the user name and mailbox list concepts. On some systems it may be appropriate for the argument of the EXPN command to be a file name for a file containing a mailing list, but again there are a variety of file naming conventions in the Internet. Similarly, historical variations in what is returned by these commands are such that the response SHOULD be interpreted very carefully, if at all, and SHOULD generally only be used for diagnostic purposes. 3.5.2 VRFY Normal Response When normal (2yz or 551) responses are returned from a VRFY or EXPN request, the reply normally includes the mailbox name, i.e., "", where "domain" is a fully qualified domain name, MUST appear in the syntax. In circumstances exceptional enough to justify violating the intent of this specification, free-form text MAY be returned. In order to facilitate parsing by both computers and people, addresses SHOULD appear in pointed brackets. When addresses, rather than free-form debugging information, are returned, EXPN and VRFY MUST return only valid domain addresses that are usable in SMTP RCPT commands. Consequently, if an address implies delivery to a program or other system, the mailbox name used to reach that target MUST be given. Paths (explicit source routes) MUST NOT be returned by VRFY or EXPN. Server implementations SHOULD support both VRFY and EXPN. For security reasons, implementations MAY provide local installations a way to disable either or both of these commands through configuration options or the equivalent. When these commands are supported, they are not required to work across relays when relaying is supported. Since they were both optional in RFC 821, they MUST be listed as service extensions in an EHLO response, if they are supported. 3.5.3 Meaning of VRFY or EXPN Success Response A server MUST NOT return a 250 code in response to a VRFY or EXPN command unless it has actually verified the address. In particular, a server MUST NOT return 250 if all it has done is to verify that the syntax given is valid. In that case, 502 (Command not implemented) or 500 (Syntax error, command unrecognized) SHOULD be returned. As stated elsewhere, implementation (in the sense of actually validating addresses and returning information) of VRFY and EXPN are strongly recommended. Hence, implementations that return 500 or 502 for VRFY are not in full compliance with this specification. There may be circumstances where an address appears to be valid but cannot reasonably be verified in real time, particularly when a server is acting as a mail exchanger for another server or domain. "Apparent validity" in this case would normally involve at least syntax checking and might involve verification that any domains specified were ones to which the host expected to be able to relay mail. In these situations, reply code 252 SHOULD be returned. These cases parallel the discussion of RCPT verification discussed in section 2.1. Similarly, the discussion in section 3.4 applies to the use of reply codes 251 and 551 with VRFY (and EXPN) to indicate addresses that are recognized but that would be forwarded or bounced were mail received for them. Implementations generally SHOULD be more aggressive about address verification in the case of VRFY than in the case of RCPT, even if it takes a little longer to do so. 3.5.4 Semantics and Applications of EXPN EXPN is often very useful in debugging and understanding problems with mailing lists and multiple-target-address aliases. Some systems have attempted to use source expansion of mailing lists as a means of eliminating duplicates. The propagation of aliasing systems with mail on the Internet, for hosts (typically with MX and CNAME DNS records), for mailboxes (various types of local host aliases), and in various proxying arrangements, has made it nearly impossible for these strategies to work consistently, and mail systems SHOULD NOT attempt them. 3.6 Domains Only resolvable, fully-qualified, domain names (FQDNs) are permitted when domain names are used in SMTP. In other words, names that can be resolved to MX RRs or A RRs (as discussed in section 5) are permitted, as are CNAME RRs whose targets can be resolved, in turn, to MX or A RRs. Local nicknames or unqualified names MUST NOT be used. There are two exceptions to the rule requiring FQDNs: - The domain name given in the EHLO command MUST BE either a primary host name (a domain name that resolves to an A RR) or, if the host has no name, an address literal as described in section 4.1.1.1. - The reserved mailbox name "postmaster" may be used in a RCPT command without domain qualification (see section 4.1.1.3) and MUST be accepted if so used. 3.7 Relaying In general, the availability of Mail eXchanger records in the domain name system [22, 27] makes the use of explicit source routes in the Internet mail system unnecessary. Many historical problems with their interpretation have made their use undesirable. SMTP clients SHOULD NOT generate explicit source routes except under unusual circumstances. SMTP servers MAY decline to act as mail relays or to accept addresses that specify source routes. When route information is encountered, SMTP servers are also permitted to ignore the route information and simply send to the final destination specified as the last element in the route and SHOULD do so. There has been an invalid practice of using names that do not appear in the DNS as destination names, with the senders counting on the intermediate hosts specified in source routing to resolve any problems. If source routes are stripped, this practice will cause failures. This is one of several reasons why SMTP clients MUST NOT generate invalid source routes or depend on serial resolution of names. When source routes are not used, the process described in RFC 821 for constructing a reverse-path from the forward-path is not applicable and the reverse-path at the time of delivery will simply be the address that appeared in the MAIL command. A relay SMTP server is usually the target of a DNS MX record that designates it, rather than the final delivery system. The relay server may accept or reject the task of relaying the mail in the same way it accepts or rejects mail for a local user. If it accepts the task, it then becomes an SMTP client, establishes a transmission channel to the next SMTP server specified in the DNS (according to the rules in section 5), and sends it the mail. If it declines to relay mail to a particular address for policy reasons, a 550 response SHOULD be returned. Many mail-sending clients exist, especially in conjunction with facilities that receive mail via POP3 or IMAP, that have limited capability to support some of the requirements of this specification, such as the ability to queue messages for subsequent delivery attempts. For these clients, it is common practice to make private arrangements to send all messages to a single server for processing and subsequent distribution. SMTP, as specified here, is not ideally suited for this role, and work is underway on standardized mail submission protocols that might eventually supercede the current practices. In any event, because these arrangements are private and fall outside the scope of this specification, they are not described here. It is important to note that MX records can point to SMTP servers which act as gateways into other environments, not just SMTP relays and final delivery systems; see sections 3.8 and 5. If an SMTP server has accepted the task of relaying the mail and later finds that the destination is incorrect or that the mail cannot be delivered for some other reason, then it MUST construct an "undeliverable mail" notification message and send it to the originator of the undeliverable mail (as indicated by the reverse- path). Formats specified for non-delivery reports by other standards (see, for example, [24, 25]) SHOULD be used if possible. This notification message must be from the SMTP server at the relay host or the host that first determines that delivery cannot be accomplished. Of course, SMTP servers MUST NOT send notification messages about problems transporting notification messages. One way to prevent loops in error reporting is to specify a null reverse-path in the MAIL command of a notification message. When such a message is transmitted the reverse-path MUST be set to null (see section 4.5.5 for additional discussion). A MAIL command with a null reverse-path appears as follows: MAIL FROM:<> As discussed in section 2.4.1, a relay SMTP has no need to inspect or act upon the headers or body of the message data and MUST NOT do so except to add its own "Received:" header (section 4.4) and, optionally, to attempt to detect looping in the mail system (see section 6.2). 3.8 Mail Gatewaying While the relay function discussed above operates within the Internet SMTP transport service environment, MX records or various forms of explicit routing may require that an intermediate SMTP server perform a translation function between one transport service and another. As discussed in section 2.3.8, when such a system is at the boundary between two transport service environments, we refer to it as a "gateway" or "gateway SMTP". Gatewaying mail between different mail environments, such as different mail formats and protocols, is complex and does not easily yield to standardization. However, some general requirements may be given for a gateway between the Internet and another mail environment. 3.8.1 Header Fields in Gatewaying Header fields MAY be rewritten when necessary as messages are gatewayed across mail environment boundaries. This may involve inspecting the message body or interpreting the local-part of the destination address in spite of the prohibitions in section 2.4.1. Other mail systems gatewayed to the Internet often use a subset of RFC 822 headers or provide similar functionality with a different syntax, but some of these mail systems do not have an equivalent to the SMTP envelope. Therefore, when a message leaves the Internet environment, it may be necessary to fold the SMTP envelope information into the message header. A possible solution would be to create new header fields to carry the envelope information (e.g., "X-SMTP-MAIL:" and "X-SMTP-RCPT:"); however, this would require changes in mail programs in foreign environments and might risk disclosure of private information (see section 7.2). 3.8.2 Received Lines in Gatewaying When forwarding a message into or out of the Internet environment, a gateway MUST prepend a Received: line, but it MUST NOT alter in any way a Received: line that is already in the header. "Received:" fields of messages originating from other environments may not conform exactly to this specification. However, the most important use of Received: lines is for debugging mail faults, and this debugging can be severely hampered by well-meaning gateways that try to "fix" a Received: line. As another consequence of trace fields arising in non-SMTP environments, receiving systems MUST NOT reject mail based on the format of a trace field and SHOULD be extremely robust in the light of unexpected information or formats in those fields. The gateway SHOULD indicate the environment and protocol in the "via" clauses of Received field(s) that it supplies. 3.8.3 Addresses in Gatewaying From the Internet side, the gateway SHOULD accept all valid address formats in SMTP commands and in RFC 822 headers, and all valid RFC 822 messages. Addresses and headers generated by gateways MUST conform to applicable Internet standards (including this one and RFC 822). Gateways are, of course, subject to the same rules for handling source routes as those described for other SMTP systems in section 3.3. 3.8.4 Other Header Fields in Gatewaying The gateway MUST ensure that all header fields of a message that it forwards into the Internet mail environment meet the requirements for Internet mail. In particular, all addresses in "From:", "To:", "Cc:", etc., fields MUST be transformed (if necessary) to satisfy RFC 822 syntax, MUST reference only fully-qualified domain names, and MUST be effective and useful for sending replies. The translation algorithm used to convert mail from the Internet protocols to another environment's protocol SHOULD ensure that error messages from the foreign mail environment are delivered to the return path from the SMTP envelope, not to the sender listed in the "From:" field (or other fields) of the RFC 822 message. 3.8.5 Envelopes in Gatewaying Similarly, when forwarding a message from another environment into the Internet, the gateway SHOULD set the envelope return path in accordance with an error message return address, if supplied by the foreign environment. If the foreign environment has no equivalent concept, the gateway must select and use a best approximation, with the message originator's address as the default of last resort. 3.9 Terminating Sessions and Connections An SMTP connection is terminated when the client sends a QUIT command. The server responds with a positive reply code, after which it closes the connection. An SMTP server MUST NOT intentionally close the connection except: - After receiving a QUIT command and responding with a 221 reply. - After detecting the need to shut down the SMTP service and returning a 421 response code. This response code can be issued after the server receives any command or, if necessary, asynchronously from command receipt (on the assumption that the client will receive it after the next command is issued). In particular, a server that closes connections in response to commands that are not understood is in violation of this specification. Servers are expected to be tolerant of unknown commands, issuing a 500 reply and awaiting further instructions from the client. An SMTP server which is forcibly shut down via external means SHOULD attempt to send a line containing a 421 response code to the SMTP client before exiting. The SMTP client will normally read the 421 response code after sending its next command. SMTP clients that experience a connection close, reset, or other communications failure due to circumstances not under their control (in violation of the intent of this specification but sometimes unavoidable) SHOULD, to maintain the robustness of the mail system, treat the mail transaction as if a 451 response had been received and act accordingly. 3.10 Mailing Lists and Aliases An SMTP-capable host SHOULD support both the alias and the list models of address expansion for multiple delivery. When a message is delivered or forwarded to each address of an expanded list form, the return address in the envelope ("MAIL FROM:") MUST be changed to be the address of a person or other entity who administers the list. However, in this case, the message header [32] MUST be left unchanged; in particular, the "From" field of the message header is unaffected. An important mail facility is a mechanism for multi-destination delivery of a single message, by transforming (or "expanding" or "exploding") a pseudo-mailbox address into a list of destination mailbox addresses. When a message is sent to such a pseudo-mailbox (sometimes called an "exploder"), copies are forwarded or redistributed to each mailbox in the expanded list. Servers SHOULD simply utilize the addresses on the list; application of heuristics or other matching rules to eliminate some addresses, such as that of the originator, is strongly discouraged. We classify such a pseudo- mailbox as an "alias" or a "list", depending upon the expansion rules. 3.10.1 Alias To expand an alias, the recipient mailer simply replaces the pseudo- mailbox address in the envelope with each of the expanded addresses in turn; the rest of the envelope and the message body are left unchanged. The message is then delivered or forwarded to each expanded address. 3.10.2 List A mailing list may be said to operate by "redistribution" rather than by "forwarding". To expand a list, the recipient mailer replaces the pseudo-mailbox address in the envelope with all of the expanded addresses. The return address in the envelope is changed so that all error messages generated by the final deliveries will be returned to a list administrator, not to the message originator, who generally has no control over the contents of the list and will typically find error messages annoying. 4. The SMTP Specifications 4.1 SMTP Commands 4.1.1 Command Semantics and Syntax The SMTP commands define the mail transfer or the mail system function requested by the user. SMTP commands are character strings terminated by . The commands themselves are alphabetic characters terminated by if parameters follow and otherwise. (In the interest of improved interoperability, SMTP receivers are encouraged to tolerate trailing white space before the terminating .) The syntax of the local part of a mailbox must conform to receiver site conventions and the syntax specified in section 4.1.2. The SMTP commands are discussed below. The SMTP replies are discussed in section 4.2. A mail transaction involves several data objects which are communicated as arguments to different commands. The reverse-path is the argument of the MAIL command, the forward-path is the argument of the RCPT command, and the mail data is the argument of the DATA command. These arguments or data objects must be transmitted and held pending the confirmation communicated by the end of mail data indication which finalizes the transaction. The model for this is that distinct buffers are provided to hold the types of data objects, that is, there is a reverse-path buffer, a forward-path buffer, and a mail data buffer. Specific commands cause information to be appended to a specific buffer, or cause one or more buffers to be cleared. Several commands (RSET, DATA, QUIT) are specified as not permitting parameters. In the absence of specific extensions offered by the server and accepted by the client, clients MUST NOT send such parameters and servers SHOULD reject commands containing them as having invalid syntax. 4.1.1.1 Extended HELLO (EHLO) or HELLO (HELO) These commands are used to identify the SMTP client to the SMTP server. The argument field contains the fully-qualified domain name of the SMTP client if one is available. In situations in which the SMTP client system does not have a meaningful domain name (e.g., when its address is dynamically allocated and no reverse mapping record is available), the client SHOULD send an address literal (see section 4.1.3), optionally followed by information that will help to identify the client system. y The SMTP server identifies itself to the SMTP client in the connection greeting reply and in the response to this command. A client SMTP SHOULD start an SMTP session by issuing the EHLO command. If the SMTP server supports the SMTP service extensions it will give a successful response, a failure response, or an error response. If the SMTP server, in violation of this specification, does not support any SMTP service extensions it will generate an error response. Older client SMTP systems MAY, as discussed above, use HELO (as specified in RFC 821) instead of EHLO, and servers MUST support the HELO command and reply properly to it. In any event, a client MUST issue HELO or EHLO before starting a mail transaction. These commands, and a "250 OK" reply to one of them, confirm that both the SMTP client and the SMTP server are in the initial state, that is, there is no transaction in progress and all state tables and buffers are cleared. Syntax: ehlo = "EHLO" SP Domain CRLF helo = "HELO" SP Domain CRLF Normally, the response to EHLO will be a multiline reply. Each line of the response contains a keyword and, optionally, one or more parameters. Following the normal syntax for multiline replies, these keyworks follow the code (250) and a hyphen for all but the last line, and the code and a space for the last line. The syntax for a positive response, using the ABNF notation and terminal symbols of [8], is: ehlo-ok-rsp = ( "250" domain [ SP ehlo-greet ] CRLF ) / ( "250-" domain [ SP ehlo-greet ] CRLF *( "250-" ehlo-line CRLF ) "250" SP ehlo-line CRLF ) ehlo-greet = 1*(%d0-9 / %d11-12 / %d14-127) ; string of any characters other than CR or LF ehlo-line = ehlo-keyword *( SP ehlo-param ) ehlo-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-") ; additional syntax of ehlo-params depends on ; ehlo-keyword ehlo-param = 1*(%d33-127) ; any CHAR excluding and all ; control characters (US-ASCII 0-31 inclusive) Although EHLO keywords may be specified in upper, lower, or mixed case, they MUST always be recognized and processed in a case- insensitive manner. This is simply an extension of practices specified in RFC 821 and section 2.4.1. 4.1.1.2 MAIL (MAIL) This command is used to initiate a mail transaction in which the mail data is delivered to an SMTP server which may, in turn, deliver it to one or more mailboxes or pass it on to another system (possibly using SMTP). The argument field contains a reverse-path and may contain optional parameters. In general, the MAIL command may be sent only when no mail transaction is in progress, see section 4.1.4. The reverse-path consists of the sender mailbox. Historically, that mailbox might optionally have been preceded by a list of hosts, but that behavior is now deprecated (see appendix C). In some types of reporting messages for which a reply is likely to cause a mail loop (for example, mail delivery and nondelivery notifications), the reverse-path may be null (see section 3.7). This command clears the reverse-path buffer, the forward-path buffer, and the mail data buffer; and inserts the reverse-path information from this command into the reverse-path buffer. If service extensions were negotiated, the MAIL command may also carry parameters associated with a particular service extension. Syntax: "MAIL FROM:" ("<>" / Reverse-Path) [SP Mail-parameters] CRLF 4.1.1.3 RECIPIENT (RCPT) This command is used to identify an individual recipient of the mail data; multiple recipients are specified by multiple use of this command. The argument field contains a forward-path and may contain optional parameters. The forward-path normally consists of the required destination mailbox. Sending systems SHOULD not generate the optional list of hosts known as a source route. Receiving systems MUST recognize source route syntax but SHOULD strip off the source route specification and utilize the domain name associated with the mailbox as if the source route had not been provided. Similarly, relay hosts SHOULD strip or ignore source routes, and names MUST NOT be copied into the reverse-path. When mail reaches its ultimate destination (the forward-path contains only a destination mailbox), the SMTP server inserts it into the destination mailbox in accordance with its host mail conventions. For example, mail received at relay host xyz.com with envelope commands MAIL FROM: RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org> will normally be sent directly on to host d.bar.org with envelope commands MAIL FROM: RCPT TO: As provided in appendix C, xyz.com MAY also choose to relay the message to hosta.int, using the envelope commands MAIL FROM: RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org> or to jkl.org, using the envelope commands MAIL FROM: RCPT TO:<@jkl.org:userc@d.bar.org> Of course, since hosts are not required to relay mail at all, xyz.com may also reject the message entirely when the RCPT command is received, using a 550 code (since this is a "policy reason"). If service extensions were negotiated, the RCPT command may also carry parameters associated with a particular service extension offered by the server. The client MUST NOT transmit parameters other than those associated with a service extension offered by the server in its EHLO response. Syntax: "RCPT TO:" ("" / "" / Forward-Path) [SP Rcpt-parameters] CRLF 4.1.1.4 DATA (DATA) The receiver normally sends a 354 response to DATA, and then treats the lines (strings ending in sequences, as described in section 2.3.7) following the command as mail data from the sender. This command causes the mail data to be appended to the mail data buffer. The mail data may contain any of the 128 ASCII character codes, although experience has indicated that use of control characters other than SP, HT, CR, and LF may cause problems and SHOULD be avoided when possible. The mail data is terminated by a line containing only a period, that is, the character sequence "." (see section 4.5.2). This is the end of mail data indication. Note that the first of this terminating sequence is also the that ends the final line of the data (message text) or, if there was no data, ends the DATA command itself. An extra MUST NOT be added, as that would cause an empty line to be added to the message. The only exception to this rule would arise if the message body were passed to the originating SMTP-sender with a final "line" that did not end in ; in that case, the originating SMTP system MUST either reject the message as invalid or add in order to have the receiving SMTP server recognize the "end of data" condition. The custom of accepting lines ending only in , as a concession to non-conforming behavior on the part of some UNIX systems, has proven to cause more interoperability problems than it solves, and SMTP server systems MUST NOT do this, even in the name of improved robustness. In particular, the sequence "." (bare line feeds, without carriage returns) MUST NOT be treated as equivalent to . as the end of mail data indication. Receipt of the end of mail data indication requires the server to process the stored mail transaction information. This processing consumes the information in the reverse-path buffer, the forward-path buffer, and the mail data buffer, and on the completion of this command these buffers are cleared. If the processing is successful, the receiver MUST send an OK reply. If the processing fails the receiver MUST send a failure reply. The SMTP model does not allow for partial failures at this point: either the message is accepted by the server for delivery and a positive response is returned or it is not accepted and a failure reply is returned. In sending a positive completion reply to the end of data indication, the receiver takes full responsibility for the message (see section 6.1). Errors that are diagnosed subsequently MUST be reported in a mail message, as discussed in section 4.4. When the SMTP server accepts a message either for relaying or for final delivery, it inserts a trace record (also referred to interchangeably as a "time stamp line" or "Received" line) at the top of the mail data. This trace record indicates the identity of the host that sent the message, the identity of the host that received the message (and is inserting this time stamp), and the date and time the message was received. Relayed messages will have multiple time stamp lines. Details for formation of these lines, including their syntax, is specified in section 4.4. Additional discussion about the operation of the DATA command appears in section 3.3. Syntax: "DATA" CRLF 4.1.1.5 RESET (RSET) This command specifies that the current mail transaction will be aborted. Any stored sender, recipients, and mail data MUST be discarded, and all buffers and state tables cleared. The receiver MUST send a "250 OK" reply to a RSET command with no arguments. A reset command may be issued by the client at any time. It is effectively equivalent to a NOOP (i.e., if has no effect) if issued immediately after EHLO, before EHLO is issued in the session, after an end-of-data indicator has been sent and acknowledged, or immediately before a QUIT. An SMTP server MUST NOT close the connection as the result of receiving a RSET; that action is reserved for QUIT (see section 4.1.1.10). Since EHLO implies some additional processing and response by the server, RSET will normally be more efficient than reissuing that command, even though the formal semantics are the same. There are circumstances, contrary to the intent of this specification, in which an SMTP server may receive an indication that the underlying TCP connection has been closed or reset. To preserve the robustness of the mail system, SMTP servers SHOULD be prepared for this condition and SHOULD treat it as if a QUIT had been received before the connection disappeared. Syntax: "RSET" CRLF 4.1.1.6 VERIFY (VRFY) This command asks the receiver to confirm that the argument identifies a user or mailbox. If it is a user name, information is returned as specified in section 3.5. This command has no effect on the reverse-path buffer, the forward- path buffer, or the mail data buffer. Syntax: "VRFY" SP String CRLF 4.1.1.7 EXPAND (EXPN) This command asks the receiver to confirm that the argument identifies a mailing list, and if so, to return the membership of that list. If the command is successful, a reply is returned containing information as described in section 3.5. This reply will have multiple lines except in the trivial case of a one-member list. This command has no effect on the reverse-path buffer, the forward- path buffer, or the mail data buffer and may be issued at any time. Syntax: "EXPN" SP String CRLF 4.1.1.8 HELP (HELP) This command causes the server to send helpful information to the client. The command MAY take an argument (e.g., any command name) and return more specific information as a response. This command has no effect on the reverse-path buffer, the forward- path buffer, or the mail data buffer and may be issued at any time. SMTP servers SHOULD support HELP without arguments and MAY support it with arguments. Syntax: "HELP" [ SP String ] CRLF 4.1.1.9 NOOP (NOOP) This command does not affect any parameters or previously entered commands. It specifies no action other than that the receiver send an OK reply. This command has no effect on the reverse-path buffer, the forward- path buffer, or the mail data buffer and may be issued at any time. If a parameter string is specified, servers SHOULD ignore it. Syntax: "NOOP" [ SP String ] CRLF 4.1.1.10 QUIT (QUIT) This command specifies that the receiver MUST send an OK reply, and then close the transmission channel. The receiver MUST NOT intentionally close the transmission channel until it receives and replies to a QUIT command (even if there was an error). The sender MUST NOT intentionally close the transmission channel until it sends a QUIT command and SHOULD wait until it receives the reply (even if there was an error response to a previous command). If the connection is closed prematurely due to violations of the above or system or network failure, the server MUST cancel any pending transaction, but not undo any previously completed transaction, and generally MUST act as if the command or transaction in progress had received a temporary error (i.e., a 4yz response). The QUIT command may be issued at any time. Syntax: "QUIT" CRLF 4.1.2 Command Argument Syntax The syntax of the argument fields of the above commands (using the syntax specified in [8] where applicable) is given below. Some of the productions given below are used only in conjunction with source routes as described in appendix C. Terminals not defined in this document, such as ALPHA, DIGIT, SP, CR, LF, CRLF, are as defined in the "core" syntax [8 (section 6)] or in the message format syntax [32]. Reverse-path = Path Forward-path = Path Path = "<" [ A-d-l ":" ] Mailbox ">" A-d-l = At-domain *( "," A-d-l ) ; Note that this form, the so-called "source route", ; MUST BE accepted, SHOULD NOT be generated, and SHOULD be ; ignored. At-domain = "@" domain Mail-parameters = esmtp-param *(SP esmtp-param) Rcpt-parameters = esmtp-param *(SP esmtp-param) esmtp-param = esmtp-keyword ["=" esmtp-value] esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-") esmtp-value = 1*(%d33-60 / %d62-127) ; any CHAR excluding "=", SP, and control characters Keyword = Ldh-str Argument = Atom Domain = (sub-domain 1*("." sub-domain)) / address-literal sub-domain = Let-dig [Ldh-str] address-literal = "[" IPv4-address-literal / IPv6-address-literal / General-address-literal "]" ; See section 4.1.3 Mailbox = Local-part "@" Domain Local-part = Dot-string / Quoted-string ; MAY be case-sensitive Dot-string = Atom *("." Atom) Atom = 1*atext Quoted-string = DQUOTE *qcontent DQUOTE String = Atom / Quoted-string While the above definition for Local-part is relatively permissive, for maximum interoperability, a host that expects to receive mail SHOULD avoid defining mailboxes where the Local-part requires (or uses) the Quoted-string form or where the Local-part is case- sensitive. For any purposes that require generating or comparing Local-parts (e.g., to specific mailbox names), all quoted forms MUST be treated as equivalent and the sending system SHOULD transmit the form that uses the minimum quoting possible. Systems MUST NOT define mailboxes in such a way as to require the use in SMTP of non-ASCII characters (octets with the high order bit set to one) or ASCII "control characters" (decimal value 0-31 and 127). These characters MUST NOT be used in MAIL or RCPT commands or other commands that require mailbox names. Note that the backslash, "\", is a quote character, which is used to indicate that the next character is to be used literally (instead of its normal interpretation). For example, "Joe\,Smith" indicates a single nine character user field with the comma being the fourth character of the field. To promote interoperability and consistent with long-standing guidance about conservative use of the DNS in naming and applications (e.g., see section 2.3.1 of the base DNS document, RFC1035 [22]), characters outside the set of alphas, digits, and hyphen MUST NOT appear in domain name labels for SMTP clients or servers. In particular, the underscore character is not permitted. SMTP servers that receive a command in which invalid character codes have been employed, and for which there are no other reasons for rejection, MUST reject that command with a 501 response. 4.1.3 Address Literals Sometimes a host is not known to the domain name system and communication (and, in particular, communication to report and repair the error) is blocked. To bypass this barrier a special literal form of the address is allowed as an alternative to a domain name. For IPv4 addresses, this form uses four small decimal integers separated by dots and enclosed by brackets such as [123.255.37.2], which indicates an (IPv4) Internet Address in sequence-of-octets form. For IPv6 and other forms of addressing that might eventually be standardized, the form consists of a standardized "tag" that identifies the address syntax, a colon, and the address itself, in a format specified as part of the IPv6 standards [17]. Specifically: IPv4-address-literal = Snum 3("." Snum) IPv6-address-literal = "IPv6:" IPv6-addr General-address-literal = Standardized-tag ":" 1*dcontent Standardized-tag = Ldh-str ; MUST be specified in a standards-track RFC ; and registered with IANA Snum = 1*3DIGIT ; representing a decimal integer ; value in the range 0 through 255 Let-dig = ALPHA / DIGIT Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp IPv6-hex = 1*4HEXDIG IPv6-full = IPv6-hex 7(":" IPv6-hex) IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":" IPv6-hex)] ; The "::" represents at least 2 16-bit groups of zeros ; No more than 6 groups in addition to the "::" may be ; present IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::" [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal ; The "::" represents at least 2 16-bit groups of zeros ; No more than 4 groups in addition to the "::" and ; IPv4-address-literal may be present 4.1.4 Order of Commands There are restrictions on the order in which these commands may be used. A session that will contain mail transactions MUST first be initialized by the use of the EHLO command. An SMTP server SHOULD accept commands for non-mail transactions (e.g., VRFY or EXPN) without this initialization. An EHLO command MAY be issued by a client later in the session. If it is issued after the session begins, the SMTP server MUST clear all buffers and reset the state exactly as if a RSET command had been issued. In other words, the sequence of RSET followed immediately by EHLO is redundant, but not harmful other than in the performance cost of executing unnecessary commands. If the EHLO command is not acceptable to the SMTP server, 501, 500, or 502 failure replies MUST be returned as appropriate. The SMTP server MUST stay in the same state after transmitting these replies that it was in before the EHLO was received. The SMTP client MUST, if possible, ensure that the domain parameter to the EHLO command is a valid principal host name (not a CNAME or MX name) for its host. If this is not possible (e.g., when the client's address is dynamically assigned and the client does not have an obvious name), an address literal SHOULD be substituted for the domain name and supplemental information provided that will assist in identifying the client. An SMTP server MAY verify that the domain name parameter in the EHLO command actually corresponds to the IP address of the client. However, the server MUST NOT refuse to accept a message for this reason if the verification fails: the information about verification failure is for logging and tracing only. The NOOP, HELP, EXPN, VRFY, and RSET commands can be used at any time during a session, or without previously initializing a session. SMTP servers SHOULD process these normally (that is, not return a 503 code) even if no EHLO command has yet been received; clients SHOULD open a session with EHLO before sending these commands. If these rules are followed, the example in RFC 821 that shows "550 access denied to you" in response to an EXPN command is incorrect unless an EHLO command precedes the EXPN or the denial of access is based on the client's IP address or other authentication or authorization-determining mechanisms. The MAIL command (or the obsolete SEND, SOML, or SAML commands) begins a mail transaction. Once started, a mail transaction consists of a transaction beginning command, one or more RCPT commands, and a DATA command, in that order. A mail transaction may be aborted by the RSET (or a new EHLO) command. There may be zero or more transactions in a session. MAIL (or SEND, SOML, or SAML) MUST NOT be sent if a mail transaction is already open, i.e., it should be sent only if no mail transaction had been started in the session, or it the previous one successfully concluded with a successful DATA command, or if the previous one was aborted with a RSET. If the transaction beginning command argument is not acceptable, a 501 failure reply MUST be returned and the SMTP server MUST stay in the same state. If the commands in a transaction are out of order to the degree that they cannot be processed by the server, a 503 failure reply MUST be returned and the SMTP server MUST stay in the same state. The last command in a session MUST be the QUIT command. The QUIT command cannot be used at any other time in a session, but SHOULD be used by the client SMTP to request connection closure, even when no session opening command was sent and accepted. 4.1.5 Private-use Commands As specified in section 2.2.2, commands starting in "X" may be used by bilateral agreement between the client (sending) and server (receiving) SMTP agents. An SMTP server that does not recognize such a command is expected to reply with "500 Command not recognized". An extended SMTP server MAY list the feature names associated with these private commands in the response to the EHLO command. Commands sent or accepted by SMTP systems that do not start with "X" MUST conform to the requirements of section 2.2.2. 4.2 SMTP Replies Replies to SMTP commands serve to ensure the synchronization of requests and actions in the process of mail transfer and to guarantee that the SMTP client always knows the state of the SMTP server. Every command MUST generate exactly one reply. The details of the command-reply sequence are described in section 4.3. An SMTP reply consists of a three digit number (transmitted as three numeric characters) followed by some text unless specified otherwise in this document. The number is for use by automata to determine what state to enter next; the text is for the human user. The three digits contain enough encoded information that the SMTP client need not examine the text and may either discard it or pass it on to the user, as appropriate. Exceptions are as noted elsewhere in this document. In particular, the 220, 221, 251, 421, and 551 reply codes are associated with message text that must be parsed and interpreted by machines. In the general case, the text may be receiver dependent and context dependent, so there are likely to be varying texts for each reply code. A discussion of the theory of reply codes is given in section 4.2.1. Formally, a reply is defined to be the sequence: a three-digit code, , one line of text, and , or a multiline reply (as defined in section 4.2.1). Since, in violation of this specification, the text is sometimes not sent, clients which do not receive it SHOULD be prepared to process the code alone (with or without a trailing space character). Only the EHLO, EXPN, and HELP commands are expected to result in multiline replies in normal circumstances, however, multiline replies are allowed for any command. In ABNF, server responses are: Greeting = "220 " Domain [ SP text ] CRLF Reply-line = Reply-code [ SP text ] CRLF where "Greeting" appears only in the 220 response that announces that the server is opening its part of the connection. An SMTP server SHOULD send only the reply codes listed in this document. An SMTP server SHOULD use the text shown in the examples whenever appropriate. An SMTP client MUST determine its actions only by the reply code, not by the text (except for the "change of address" 251 and 551 and, if necessary, 220, 221, and 421 replies); in the general case, any text, including no text at all (although senders SHOULD NOT send bare codes), MUST be acceptable. The space (blank) following the reply code is considered part of the text. Whenever possible, a receiver- SMTP SHOULD test the first digit (severity indication) of the reply code. The list of codes that appears below MUST NOT be construed as permanent. While the addition of new codes should be a rare and significant activity, with supplemental information in the textual part of the response being preferred, new codes may be added as the result of new Standards or Standards-track specifications. Consequently, a sender-SMTP MUST be prepared to handle codes not specified in this document and MUST do so by interpreting the first digit only. 4.2.1 Reply Code Severities and Theory The three digits of the reply each have a special significance. The first digit denotes whether the response is good, bad or incomplete. An unsophisticated SMTP client, or one that receives an unexpected code, will be able to determine its next action (proceed as planned, redo, retrench, etc.) by examining this first digit. An SMTP client that wants to know approximately what kind of error occurred (e.g., mail system error, command syntax error) may examine the second digit. The third digit and any supplemental information that may be present is reserved for the finest gradation of information. There are five values for the first digit of the reply code: 1yz Positive Preliminary reply The command has been accepted, but the requested action is being held in abeyance, pending confirmation of the information in this reply. The SMTP client should send another command specifying whether to continue or abort the action. Note: unextended SMTP does not have any commands that allow this type of reply, and so does not have continue or abort commands. 2yz Positive Completion reply The requested action has been successfully completed. A new request may be initiated. 3yz Positive Intermediate reply The command has been accepted, but the requested action is being held in abeyance, pending receipt of further information. The SMTP client should send another command specifying this information. This reply is used in command sequence groups (i.e., in DATA). 4yz Transient Negative Completion reply The command was not accepted, and the requested action did not occur. However, the error condition is temporary and the action may be requested again. The sender should return to the beginning of the command sequence (if any). It is difficult to assign a meaning to "transient" when two different sites (receiver- and sender-SMTP agents) must agree on the interpretation. Each reply in this category might have a different time value, but the SMTP client is encouraged to try again. A rule of thumb to determine whether a reply fits into the 4yz or the 5yz category (see below) is that replies are 4yz if they can be successful if repeated without any change in command form or in properties of the sender or receiver (that is, the command is repeated identically and the receiver does not put up a new implementation.) 5yz Permanent Negative Completion reply The command was not accepted and the requested action did not occur. The SMTP client is discouraged from repeating the exact request (in the same sequence). Even some "permanent" error conditions can be corrected, so the human user may want to direct the SMTP client to reinitiate the command sequence by direct action at some point in the future (e.g., after the spelling has been changed, or the user has altered the account status). The second digit encodes responses in specific categories: x0z Syntax: These replies refer to syntax errors, syntactically correct commands that do not fit any functional category, and unimplemented or superfluous commands. x1z Information: These are replies to requests for information, such as status or help. x2z Connections: These are replies referring to the transmission channel. x3z Unspecified. x4z Unspecified. x5z Mail system: These replies indicate the status of the receiver mail system vis-a-vis the requested transfer or other mail system action. The third digit gives a finer gradation of meaning in each category specified by the second digit. The list of replies illustrates this. Each reply text is recommended rather than mandatory, and may even change according to the command with which it is associated. On the other hand, the reply codes must strictly follow the specifications in this section. Receiver implementations should not invent new codes for slightly different situations from the ones described here, but rather adapt codes already defined. For example, a command such as NOOP, whose successful execution does not offer the SMTP client any new information, will return a 250 reply. The reply is 502 when the command requests an unimplemented non-site-specific action. A refinement of that is the 504 reply for a command that is implemented, but that requests an unimplemented parameter. The reply text may be longer than a single line; in these cases the complete text must be marked so the SMTP client knows when it can stop reading the reply. This requires a special format to indicate a multiple line reply. The format for multiline replies requires that every line, except the last, begin with the reply code, followed immediately by a hyphen, "-" (also known as minus), followed by text. The last line will begin with the reply code, followed immediately by , optionally some text, and . As noted above, servers SHOULD send the if subsequent text is not sent, but clients MUST be prepared for it to be omitted. For example: 123-First line 123-Second line 123-234 text beginning with numbers 123 The last line In many cases the SMTP client then simply needs to search for a line beginning with the reply code followed by or and ignore all preceding lines. In a few cases, there is important data for the client in the reply "text". The client will be able to identify these cases from the current context. 4.2.2 Reply Codes by Function Groups 500 Syntax error, command unrecognized (This may include errors such as command line too long) 501 Syntax error in parameters or arguments 502 Command not implemented (see section 4.2.4) 503 Bad sequence of commands 504 Command parameter not implemented 211 System status, or system help reply 214 Help message (Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user) 220 Service ready 221 Service closing transmission channel 421 Service not available, closing transmission channel (This may be a reply to any command if the service knows it must shut down) 250 Requested mail action okay, completed 251 User not local; will forward to (See section 3.4) 252 Cannot VRFY user, but will accept message and attempt delivery (See section 3.5.3) 450 Requested mail action not taken: mailbox unavailable (e.g., mailbox busy) 550 Requested action not taken: mailbox unavailable (e.g., mailbox not found, no access, or command rejected for policy reasons) 451 Requested action aborted: error in processing 551 User not local; please try (See section 3.4) 452 Requested action not taken: insufficient system storage 552 Requested mail action aborted: exceeded storage allocation 553 Requested action not taken: mailbox name not allowed (e.g., mailbox syntax incorrect) 354 Start mail input; end with . 554 Transaction failed (Or, in the case of a connection-opening response, "No SMTP service here") 4.2.3 Reply Codes in Numeric Order 211 System status, or system help reply 214 Help message (Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user) 220 Service ready 221 Service closing transmission channel 250 Requested mail action okay, completed 251 User not local; will forward to (See section 3.4) 252 Cannot VRFY user, but will accept message and attempt delivery (See section 3.5.3) 354 Start mail input; end with . 421 Service not available, closing transmission channel (This may be a reply to any command if the service knows it must shut down) 450 Requested mail action not taken: mailbox unavailable (e.g., mailbox busy) 451 Requested action aborted: local error in processing 452 Requested action not taken: insufficient system storage 500 Syntax error, command unrecognized (This may include errors such as command line too long) 501 Syntax error in parameters or arguments 502 Command not implemented (see section 4.2.4) 503 Bad sequence of commands 504 Command parameter not implemented 550 Requested action not taken: mailbox unavailable (e.g., mailbox not found, no access, or command rejected for policy reasons) 551 User not local; please try (See section 3.4) 552 Requested mail action aborted: exceeded storage allocation 553 Requested action not taken: mailbox name not allowed (e.g., mailbox syntax incorrect) 554 Transaction failed (Or, in the case of a connection-opening response, "No SMTP service here") 4.2.4 Reply Code 502 Questions have been raised as to when reply code 502 (Command not implemented) SHOULD be returned in preference to other codes. 502 SHOULD be used when the command is actually recognized by the SMTP server, but not implemented. If the command is not recognized, code 500 SHOULD be returned. Extended SMTP systems MUST NOT list capabilities in response to EHLO for which they will return 502 (or 500) replies. 4.2.5 Reply Codes After DATA and the Subsequent . When an SMTP server returns a positive completion status (2yz code) after the DATA command is completed with ., it accepts responsibility for: - delivering the message (if the recipient mailbox exists), or - if attempts to deliver the message fail due to transient conditions, retrying delivery some reasonable number of times at intervals as specified in section 4.5.4. - if attempts to deliver the message fail due to permanent conditions, or if repeated attempts to deliver the message fail due to transient conditions, returning appropriate notification to the sender of the original message (using the address in the SMTP MAIL command). When an SMTP server returns a permanent error status (5yz) code after the DATA command is completed with ., it MUST NOT make any subsequent attempt to deliver that message. The SMTP client retains responsibility for delivery of that message and may either return it to the user or requeue it for a subsequent attempt (see section 4.5.4.1). The user who originated the message SHOULD be able to interpret the return of a transient failure status (by mail message or otherwise) as a non-delivery indication, just as a permanent failure would be interpreted. I.e., if the client SMTP successfully handles these conditions, the user will not receive such a reply. When an SMTP server returns a permanent error status (5yz) code after the DATA command is completely with ., it MUST NOT make any subsequent attempt to deliver the message. As with temporary error status codes, the SMTP client retains responsibility for the message, but SHOULD not again attempt delivery to the same server without user review and intervention of the message. 4.3 Sequencing of Commands and Replies 4.3.1 Sequencing Overview The communication between the sender and receiver is an alternating dialogue, controlled by the sender. As such, the sender issues a command and the receiver responds with a reply. Unless other arrangements are negotiated through service extensions, the sender MUST wait for this response before sending further commands. One important reply is the connection greeting. Normally, a receiver will send a 220 "Service ready" reply when the connection is completed. The sender SHOULD wait for this greeting message before sending any commands. Note: all the greeting-type replies have the official name (the fully-qualified primary domain name) of the server host as the first word following the reply code. Sometimes the host will have no meaningful name. See 4.1.3 for a discussion of alternatives in these situations. For example, 220 ISIF.USC.EDU Service ready or 220 mail.foo.com SuperSMTP v 6.1.2 Service ready or 220 [10.0.0.1] Clueless host service ready The table below lists alternative success and failure replies for each command. These SHOULD be strictly adhered to: a receiver may substitute text in the replies, but the meaning and action implied by the code numbers and by the specific command reply sequence cannot be altered. 4.3.2 Command-Reply Sequences Each command is listed with its usual possible replies. The prefixes used before the possible replies are "I" for intermediate, "S" for success, and "E" for error. Since some servers may generate other replies under special circumstances, and to allow for future extension, SMTP clients SHOULD, when possible, interpret only the first digit of the reply and MUST be prepared to deal with unrecognized reply codes by interpreting the first digit only. Unless extended using the mechanisms described in section 2.2, SMTP servers MUST NOT transmit reply codes to an SMTP client that are other than three digits or that do not start in a digit between 2 and 5 inclusive. These sequencing rules and, in principle, the codes themselves, can be extended or modified by SMTP extensions offered by the server and accepted (requested) by the client. In addition to the codes listed below, any SMTP command can return any of the following codes if the corresponding unusual circumstances are encountered: 500 For the "command line too long" case or if the command name was not recognized. Note that producing a "command not recognized" error in response to the required subset of these commands is a violation of this specification. 501 Syntax error in command or arguments. In order to provide for future extensions, commands that are specified in this document as not accepting arguments (DATA, RSET, QUIT) SHOULD return a 501 message if arguments are supplied in the absence of EHLO- advertised extensions. 421 Service shutting down and closing transmission channel Specific sequences are: CONNECTION ESTABLISHMENT S: 220 E: 554 EHLO or HELO S: 250 E: 504, 550 MAIL S: 250 E: 552, 451, 452, 550, 553, 503 RCPT S: 250, 251 (but see section 3.4 for discussion of 251 and 551) E: 550, 551, 552, 553, 450, 451, 452, 503, 550 DATA I: 354 -> data -> S: 250 E: 552, 554, 451, 452 E: 451, 554, 503 RSET S: 250 VRFY S: 250, 251, 252 E: 550, 551, 553, 502, 504 EXPN S: 250, 252 E: 550, 500, 502, 504 HELP S: 211, 214 E: 502, 504 NOOP S: 250 QUIT S: 221 4.4 Trace Information When an SMTP server receives a message for delivery or further processing, it MUST insert trace ("time stamp" or "Received") information at the beginning of the message content, as discussed in section 4.1.1.4. This line MUST be structured as follows: - The FROM field, which MUST be supplied in an SMTP environment, SHOULD contain both (1) the name of the source host as presented in the EHLO command and (2) an address literal containing the IP address of the source, determined from the TCP connection. - The ID field MAY contain an "@" as suggested in RFC 822, but this is not required. - The FOR field MAY contain a list of entries when multiple RCPT commands have been given. This may raise some security issues and is usually not desirable; see section 7.2. An Internet mail program MUST NOT change a Received: line that was previously added to the message header. SMTP servers MUST prepend Received lines to messages; they MUST NOT change the order of existing lines or insert Received lines in any other location. As the Internet grows, comparability of Received fields is important for detecting problems, especially slow relays. SMTP servers that create Received fields SHOULD use explicit offsets in the dates (e.g., -0800), rather than time zone names of any type. Local time (with an offset) is preferred to UT when feasible. This formulation allows slightly more information about local circumstances to be specified. If UT is needed, the receiver need merely do some simple arithmetic to convert the values. Use of UT loses information about the time zone-location of the server. If it is desired to supply a time zone name, it SHOULD be included in a comment. When the delivery SMTP server makes the "final delivery" of a message, it inserts a return-path line at the beginning of the mail data. This use of return-path is required; mail systems MUST support it. The return-path line preserves the information in the from the MAIL command. Here, final delivery means the message has left the SMTP environment. Normally, this would mean it had been delivered to the destination user or an associated mail drop, but in some cases it may be further processed and transmitted by another mail system. It is possible for the mailbox in the return path to be different from the actual sender's mailbox, for example, if error responses are to be delivered to a special error handling mailbox rather than to the message sender. When mailing lists are involved, this arrangement is common and useful as a means of directing errors to the list maintainer rather than the message originator. The text above implies that the final mail data will begin with a return path line, followed by one or more time stamp lines. These lines will be followed by the mail data headers and body [32]. It is sometimes difficult for an SMTP server to determine whether or not it is making final delivery since forwarding or other operations may occur after the message is accepted for delivery. Consequently, any further (forwarding, gateway, or relay) systems MAY remove the return path and rebuild the MAIL command as needed to ensure that exactly one such line appears in a delivered message. A message-originating SMTP system SHOULD NOT send a message that already contains a Return-path header. SMTP servers performing a relay function MUST NOT inspect the message data, and especially not to the extent needed to determine if Return-path headers are present. SMTP servers making final delivery MAY remove Return-path headers before adding their own. The primary purpose of the Return-path is to designate the address to which messages indicating non-delivery or other mail system failures are to be sent. For this to be unambiguous, exactly one return path SHOULD be present when the message is delivered. Systems using RFC 822 syntax with non-SMTP transports SHOULD designate an unambiguous address, associated with the transport envelope, to which error reports (e.g., non-delivery messages) should be sent. Historical note: Text in RFC 822 that appears to contradict the use of the Return-path header (or the envelope reverse path address from the MAIL command) as the destination for error messages is not applicable on the Internet. The reverse path address (as copied into the Return-path) MUST be used as the target of any mail containing delivery error messages. In particular: - a gateway from SMTP->elsewhere SHOULD insert a return-path header, unless it is known that the "elsewhere" transport also uses Internet domain addresses and maintains the envelope sender address separately. - a gateway from elsewhere->SMTP SHOULD delete any return-path header present in the message, and either copy that information to the SMTP envelope or combine it with information present in the envelope of the other transport system to construct the reverse path argument to the MAIL command in the SMTP envelope. The server must give special treatment to cases in which the processing following the end of mail data indication is only partially successful. This could happen if, after accepting several recipients and the mail data, the SMTP server finds that the mail data could be successfully delivered to some, but not all, of the recipients. In such cases, the response to the DATA command MUST be an OK reply. However, the SMTP server MUST compose and send an "undeliverable mail" notification message to the originator of the message. A single notification listing all of the failed recipients or separate notification messages MUST be sent for each failed recipient. For economy of processing by the sender, the former is preferred when possible. All undeliverable mail notification messages are sent using the MAIL command (even if they result from processing the obsolete SEND, SOML, or SAML commands) and use a null return path as discussed in section 3.7. The time stamp line and the return path line are formally defined as follows: Return-path-line = "Return-Path:" FWS Reverse-path Time-stamp-line = "Received:" FWS Stamp Stamp = From-domain By-domain Opt-info ";" FWS date-time ; where "date-time" is as defined in [32] ; but the "obs-" forms, especially two-digit ; years, are prohibited in SMTP and MUST NOT be used. From-domain = "FROM" FWS Extended-Domain CFWS By-domain = "BY" FWS Extended-Domain CFWS Extended-Domain = Domain / ( Domain FWS "(" TCP-info ")" ) / ( Address-literal FWS "(" TCP-info ")" ) TCP-info = Address-literal / ( Domain FWS Address-literal ) ; Information derived by server from TCP connection ; not client EHLO. Opt-info = [Via] [With] [ID] [For] Via = "VIA" FWS Link CFWS With = "WITH" FWS Protocol CFWS ID = "ID" FWS String / msg-id CFWS For = "FOR" FWS 1*( Path / Mailbox ) CFWS Link = "TCP" / Addtl-Link Addtl-Link = Atom ; Additional standard names for links are registered with the ; Internet Assigned Numbers Authority (IANA). "Via" is ; primarily of value with non-Internet transports. SMTP ; servers SHOULD NOT use unregistered names. Protocol = "ESMTP" / "SMTP" / Attdl-Protocol Attdl-Protocol = Atom ; Additional standard names for protocols are registered with the ; Internet Assigned Numbers Authority (IANA). SMTP servers ; SHOULD NOT use unregistered names. 4.5 Additional Implementation Issues 4.5.1 Minimum Implementation In order to make SMTP workable, the following minimum implementation is required for all receivers. The following commands MUST be supported to conform to this specification: EHLO HELO MAIL RCPT DATA RSET NOOP QUIT VRFY Any system that includes an SMTP server supporting mail relaying or delivery MUST support the reserved mailbox "postmaster" as a case- insensitive local name. This postmaster address is not strictly necessary if the server always returns 554 on connection opening (as described in section 3.1). The requirement to accept mail for postmaster implies that RCPT commands which specify a mailbox for postmaster at any of the domains for which the SMTP server provides mail service, as well as the special case of "RCPT TO:" (with no domain specification), MUST be supported. SMTP systems are expected to make every reasonable effort to accept mail directed to Postmaster from any other system on the Internet. In extreme cases --such as to contain a denial of service attack or other breach of security-- an SMTP server may block mail directed to Postmaster. However, such arrangements SHOULD be narrowly tailored so as to avoid blocking messages which are not part of such attacks. 4.5.2 Transparency Without some provision for data transparency, the character sequence "." ends the mail text and cannot be sent by the user. In general, users are not aware of such "forbidden" sequences. To allow all user composed text to be transmitted transparently, the following procedures are used: - Before sending a line of mail text, the SMTP client checks the first character of the line. If it is a period, one additional period is inserted at the beginning of the line. - When a line of mail text is received by the SMTP server, it checks the line. If the line is composed of a single period, it is treated as the end of mail indicator. If the first character is a period and there are other characters on the line, the first character is deleted. The mail data may contain any of the 128 ASCII characters. All characters are to be delivered to the recipient's mailbox, including spaces, vertical and horizontal tabs, and other control characters. If the transmission channel provides an 8-bit byte (octet) data stream, the 7-bit ASCII codes are transmitted right justified in the octets, with the high order bits cleared to zero. See 3.7 for special treatment of these conditions in SMTP systems serving a relay function. In some systems it may be necessary to transform the data as it is received and stored. This may be necessary for hosts that use a different character set than ASCII as their local character set, that store data in records rather than strings, or which use special character sequences as delimiters inside mailboxes. If such transformations are necessary, they MUST be reversible, especially if they are applied to mail being relayed. 4.5.3 Sizes and Timeouts 4.5.3.1 Size limits and minimums There are several objects that have required minimum/maximum sizes. Every implementation MUST be able to receive objects of at least these sizes. Objects larger than these sizes SHOULD be avoided when possible. However, some Internet mail constructs such as encoded X.400 addresses [16] will often require larger objects: clients MAY attempt to transmit these, but MUST be prepared for a server to reject them if they cannot be handled by it. To the maximum extent possible, implementation techniques which impose no limits on the length of these objects should be used. local-part The maximum total length of a user name or other local-part is 64 characters. domain The maximum total length of a domain name or number is 255 characters. path The maximum total length of a reverse-path or forward-path is 256 characters (including the punctuation and element separators). command line The maximum total length of a command line including the command word and the is 512 characters. SMTP extensions may be used to increase this limit. reply line The maximum total length of a reply line including the reply code and the is 512 characters. More information may be conveyed through multiple-line replies. text line The maximum total length of a text line including the is 1000 characters (not counting the leading dot duplicated for transparency). This number may be increased by the use of SMTP Service Extensions. message content The maximum total length of a message content (including any message headers as well as the message body) MUST BE at least 64K octets. Since the introduction of Internet standards for multimedia mail [12], message lengths on the Internet have grown dramatically, and message size restrictions should be avoided if at all possible. SMTP server systems that must impose restrictions SHOULD implement the "SIZE" service extension [18], and SMTP client systems that will send large messages SHOULD utilize it when possible. recipients buffer The minimum total number of recipients that must be buffered is 100 recipients. Rejection of messages (for excessive recipients) with fewer than 100 RCPT commands is a violation of this specification. The general principle that relaying SMTP servers MUST NOT, and delivery SMTP servers SHOULD NOT, perform validation tests on message headers suggests that rejecting a message based on the total number of recipients shown in header fields is to be discouraged. A server which imposes a limit on the number of recipients MUST behave in an orderly fashion, such as to reject additional addresses over its limit rather than silently discarding addresses previously accepted. A client that needs to deliver a message containing over 100 RCPT commands SHOULD be prepared to transmit in 100-recipient "chunks" if the server declines to accept more than 100 recipients in a single message. Errors due to exceeding these limits may be reported by using the reply codes. Some examples of reply codes are: 500 Line too long. or 501 Path too long or 452 Too many recipients (see below) or 552 Too much mail data. RFC 821 [30] incorrectly listed the error where an SMTP server exhausts its implementation limit on the number of RCPT commands ("too many recipients") as having reply code 552. The correct reply code for this condition is 452. Clients SHOULD treat a 552 code in this case as a temporary, rather than permanent, failure so the logic below works. When a conforming SMTP server encounters this condition, it has at least 100 successful RCPT commands in its recipients buffer. If the server is able to accept the message, then at least these 100 addresses will be removed from the SMTP client's queue. When the client attempts retransmission of those addresses which received 452 responses, at least 100 of these will be able to fit in the SMTP server's recipients buffer. Each retransmission attempt which is able to deliver anything will be able to dispose of at least 100 of these recipients. If an SMTP server has an implementation limit on the number of RCPT commands and this limit is exhausted, it MUST use a response code of 452 (but the client SHOULD also be prepared for a 552, as noted above). If the server has a configured site-policy limitation on the number of RCPT commands, it MAY instead use a 5XX response code. This would be most appropriate if the policy limitation was intended to apply if the total recipient count for a particular message body were enforced even if that message body was sent in multiple mail transactions. 4.5.3.2 Timeouts An SMTP client MUST provide a timeout mechanism. It MUST use per- command timeouts rather than somehow trying to time the entire mail transaction. Timeouts SHOULD be easily reconfigurable, preferably without recompiling the SMTP code. To implement this, a timer is set for each SMTP command and for each buffer of the data transfer. The latter means that the overall timeout is inherently proportional to the size of the message. Based on extensive experience with busy mail-relay hosts, the minimum per-command timeout values SHOULD be as follows: Initial 220 Message: 5 minutes An SMTP client process needs to distinguish between a failed TCP connection and a delay in receiving the initial 220 greeting message. Many SMTP servers accept a TCP connection but delay delivery of the 220 message until their system load permits more mail to be processed. MAIL Command: 5 minutes RCPT Command: 5 minutes A longer timeout is required if processing of mailing lists and aliases is not deferred until after the message was accepted. DATA Initiation: 2 minutes This is while awaiting the "354 Start Input" reply to a DATA command. Data Block: 3 minutes This is while awaiting the completion of each TCP SEND call transmitting a chunk of data. DATA Termination: 10 minutes. This is while awaiting the "250 OK" reply. When the receiver gets the final period terminating the message data, it typically performs processing to deliver the message to a user mailbox. A spurious timeout at this point would be very wasteful and would typically result in delivery of multiple copies of the message, since it has been successfully sent and the server has accepted responsibility for delivery. See section 6.1 for additional discussion. An SMTP server SHOULD have a timeout of at least 5 minutes while it is awaiting the next command from the sender. 4.5.4 Retry Strategies The common structure of a host SMTP implementation includes user mailboxes, one or more areas for queuing messages in transit, and one or more daemon processes for sending and receiving mail. The exact structure will vary depending on the needs of the users on the host and the number and size of mailing lists supported by the host. We describe several optimizations that have proved helpful, particularly for mailers supporting high traffic levels. Any queuing strategy MUST include timeouts on all activities on a per-command basis. A queuing strategy MUST NOT send error messages in response to error messages under any circumstances. 4.5.4.1 Sending Strategy The general model for an SMTP client is one or more processes that periodically attempt to transmit outgoing mail. In a typical system, the program that composes a message has some method for requesting immediate attention for a new piece of outgoing mail, while mail that cannot be transmitted immediately MUST be queued and periodically retried by the sender. A mail queue entry will include not only the message itself but also the envelope information. The sender MUST delay retrying a particular destination after one attempt has failed. In general, the retry interval SHOULD be at least 30 minutes; however, more sophisticated and variable strategies will be beneficial when the SMTP client can determine the reason for non-delivery. Retries continue until the message is transmitted or the sender gives up; the give-up time generally needs to be at least 4-5 days. The parameters to the retry algorithm MUST be configurable. A client SHOULD keep a list of hosts it cannot reach and corresponding connection timeouts, rather than just retrying queued mail items. Experience suggests that failures are typically transient (the target system or its connection has crashed), favoring a policy of two connection attempts in the first hour the message is in the queue, and then backing off to one every two or three hours. The SMTP client can shorten the queuing delay in cooperation with the SMTP server. For example, if mail is received from a particular address, it is likely that mail queued for that host can now be sent. Application of this principle may, in many cases, eliminate the requirement for an explicit "send queues now" function such as ETRN [9]. The strategy may be further modified as a result of multiple addresses per host (see below) to optimize delivery time vs. resource usage. An SMTP client may have a large queue of messages for each unavailable destination host. If all of these messages were retried in every retry cycle, there would be excessive Internet overhead and the sending system would be blocked for a long period. Note that an SMTP client can generally determine that a delivery attempt has failed only after a timeout of several minutes and even a one-minute timeout per connection will result in a very large delay if retries are repeated for dozens, or even hundreds, of queued messages to the same host. At the same time, SMTP clients SHOULD use great care in caching negative responses from servers. In an extreme case, if EHLO is issued multiple times during the same SMTP connection, different answers may be returned by the server. More significantly, 5yz responses to the MAIL command MUST NOT be cached. When a mail message is to be delivered to multiple recipients, and the SMTP server to which a copy of the message is to be sent is the same for multiple recipients, then only one copy of the message SHOULD be transmitted. That is, the SMTP client SHOULD use the command sequence: MAIL, RCPT, RCPT,... RCPT, DATA instead of the sequence: MAIL, RCPT, DATA, ..., MAIL, RCPT, DATA. However, if there are very many addresses, a limit on the number of RCPT commands per MAIL command MAY be imposed. Implementation of this efficiency feature is strongly encouraged. Similarly, to achieve timely delivery, the SMTP client MAY support multiple concurrent outgoing mail transactions. However, some limit may be appropriate to protect the host from devoting all its resources to mail. 4.5.4.2 Receiving Strategy The SMTP server SHOULD attempt to keep a pending listen on the SMTP port at all times. This requires the support of multiple incoming TCP connections for SMTP. Some limit MAY be imposed but servers that cannot handle more than one SMTP transaction at a time are not in conformance with the intent of this specification. As discussed above, when the SMTP server receives mail from a particular host address, it could activate its own SMTP queuing mechanisms to retry any mail pending for that host address. 4.5.5 Messages with a null reverse-path There are several types of notification messages which are required by existing and proposed standards to be sent with a null reverse path, namely non-delivery notifications as discussed in section 3.7, other kinds of Delivery Status Notifications (DSNs) [24], and also Message Disposition Notifications (MDNs) [10]. All of these kinds of messages are notifications about a previous message, and they are sent to the reverse-path of the previous mail message. (If the delivery of such a notification message fails, that usually indicates a problem with the mail system of the host to which the notification message is addressed. For this reason, at some hosts the MTA is set up to forward such failed notification messages to someone who is able to fix problems with the mail system, e.g., via the postmaster alias.) All other types of messages (i.e., any message which is not required by a standards-track RFC to have a null reverse-path) SHOULD be sent with with a valid, non-null reverse-path. Implementors of automated email processors should be careful to make sure that the various kinds of messages with null reverse-path are handled correctly, in particular such systems SHOULD NOT reply to messages with null reverse-path. 5. Address Resolution and Mail Handling Once an SMTP client lexically identifies a domain to which mail will be delivered for processing (as described in sections 3.6 and 3.7), a DNS lookup MUST be performed to resolve the domain name [22]. The names are expected to be fully-qualified domain names (FQDNs): mechanisms for inferring FQDNs from partial names or local aliases are outside of this specification and, due to a history of problems, are generally discouraged. The lookup first attempts to locate an MX record associated with the name. If a CNAME record is found instead, the resulting name is processed as if it were the initial name. If no MX records are found, but an A RR is found, the A RR is treated as if it was associated with an implicit MX RR, with a preference of 0, pointing to that host. If one or more MX RRs are found for a given name, SMTP systems MUST NOT utilize any A RRs associated with that name unless they are located using the MX RRs; the "implicit MX" rule above applies only if there are no MX records present. If MX records are present, but none of them are usable, this situation MUST be reported as an error. When the lookup succeeds, the mapping can result in a list of alternative delivery addresses rather than a single address, because of multiple MX records, multihoming, or both. To provide reliable mail transmission, the SMTP client MUST be able to try (and retry) each of the relevant addresses in this list in order, until a delivery attempt succeeds. However, there MAY also be a configurable limit on the number of alternate addresses that can be tried. In any case, the SMTP client SHOULD try at least two addresses. Two types of information is used to rank the host addresses: multiple MX records, and multihomed hosts. Multiple MX records contain a preference indication that MUST be used in sorting (see below). Lower numbers are more preferred than higher ones. If there are multiple destinations with the same preference and there is no clear reason to favor one (e.g., by recognition of an easily-reached address), then the sender-SMTP MUST randomize them to spread the load across multiple mail exchangers for a specific organization. The destination host (perhaps taken from the preferred MX record) may be multihomed, in which case the domain name resolver will return a list of alternative IP addresses. It is the responsibility of the domain name resolver interface to have ordered this list by decreasing preference if necessary, and SMTP MUST try them in the order presented. Although the capability to try multiple alternative addresses is required, specific installations may want to limit or disable the use of alternative addresses. The question of whether a sender should attempt retries using the different addresses of a multihomed host has been controversial. The main argument for using the multiple addresses is that it maximizes the probability of timely delivery, and indeed sometimes the probability of any delivery; the counter- argument is that it may result in unnecessary resource use. Note that resource use is also strongly determined by the sending strategy discussed in section 4.5.4.1. If an SMTP server receives a message with a destination for which it is a designated Mail eXchanger, it MAY relay the message (potentially after having rewritten the MAIL FROM and/or RCPT TO addresses), make final delivery of the message, or hand it off using some mechanism outside the SMTP-provided transport environment. Of course, neither of the latter require that the list of MX records be examined further. If it determines that it should relay the message without rewriting the address, it MUST sort the MX records to determine candidates for delivery. The records are first ordered by preference, with the lowest-numbered records being most preferred. The relay host MUST then inspect the list for any of the names or addresses by which it might be known in mail transactions. If a matching record is found, all records at that preference level and higher-numbered ones MUST be discarded from consideration. If there are no records left at that point, it is an error condition, and the message MUST be returned as undeliverable. If records do remain, they SHOULD be tried, best preference first, as described above. 6. Problem Detection and Handling 6.1 Reliable Delivery and Replies by Email When the receiver-SMTP accepts a piece of mail (by sending a "250 OK" message in response to DATA), it is accepting responsibility for delivering or relaying the message. It must take this responsibility seriously. It MUST NOT lose the message for frivolous reasons, such as because the host later crashes or because of a predictable resource shortage. If there is a delivery failure after acceptance of a message, the receiver-SMTP MUST formulate and mail a notification message. This notification MUST be sent using a null ("<>") reverse path in the envelope. The recipient of this notification MUST be the address from the envelope return path (or the Return-Path: line). However, if this address is null ("<>"), the receiver-SMTP MUST NOT send a notification. Obviously, nothing in this section can or should prohibit local decisions (i.e., as part of the same system environment as the receiver-SMTP) to log or otherwise transmit information about null address events locally if that is desired. If the address is an explicit source route, it MUST be stripped down to its final hop. For example, suppose that an error notification must be sent for a message that arrived with: MAIL FROM:<@a,@b:user@d> The notification message MUST be sent using: RCPT TO: Some delivery failures after the message is accepted by SMTP will be unavoidable. For example, it may be impossible for the receiving SMTP server to validate all the delivery addresses in RCPT command(s) due to a "soft" domain system error, because the target is a mailing list (see earlier discussion of RCPT), or because the server is acting as a relay and has no immediate access to the delivering system. To avoid receiving duplicate messages as the result of timeouts, a receiver-SMTP MUST seek to minimize the time required to respond to the final . end of data indicator. See RFC 1047 [28] for a discussion of this problem. 6.2 Loop Detection Simple counting of the number of "Received:" headers in a message has proven to be an effective, although rarely optimal, method of detecting loops in mail systems. SMTP servers using this technique SHOULD use a large rejection threshold, normally at least 100 Received entries. Whatever mechanisms are used, servers MUST contain provisions for detecting and stopping trivial loops. 6.3 Compensating for Irregularities Unfortunately, variations, creative interpretations, and outright violations of Internet mail protocols do occur; some would suggest that they occur quite frequently. The debate as to whether a well- behaved SMTP receiver or relay should reject a malformed message, attempt to pass it on unchanged, or attempt to repair it to increase the odds of successful delivery (or subsequent reply) began almost with the dawn of structured network mail and shows no signs of abating. Advocates of rejection claim that attempted repairs are rarely completely adequate and that rejection of bad messages is the only way to get the offending software repaired. Advocates of "repair" or "deliver no matter what" argue that users prefer that mail go through it if at all possible and that there are significant market pressures in that direction. In practice, these market pressures may be more important to particular vendors than strict conformance to the standards, regardless of the preference of the actual developers. The problems associated with ill-formed messages were exacerbated by the introduction of the split-UA mail reading protocols [3, 26, 5, 21]. These protocols have encouraged the use of SMTP as a posting protocol, and SMTP servers as relay systems for these client hosts (which are often only intermittently connected to the Internet). Historically, many of those client machines lacked some of the mechanisms and information assumed by SMTP (and indeed, by the mail format protocol [7]). Some could not keep adequate track of time; others had no concept of time zones; still others could not identify their own names or addresses; and, of course, none could satisfy the assumptions that underlay RFC 822's conception of authenticated addresses. In response to these weak SMTP clients, many SMTP systems now complete messages that are delivered to them in incomplete or incorrect form. This strategy is generally considered appropriate when the server can identify or authenticate the client, and there are prior agreements between them. By contrast, there is at best great concern about fixes applied by a relay or delivery SMTP server that has little or no knowledge of the user or client machine. The following changes to a message being processed MAY be applied when necessary by an originating SMTP server, or one used as the target of SMTP as an initial posting protocol: - Addition of a message-id field when none appears - Addition of a date, time or time zone when none appears - Correction of addresses to proper FQDN format The less information the server has about the client, the less likely these changes are to be correct and the more caution and conservatism should be applied when considering whether or not to perform fixes and how. These changes MUST NOT be applied by an SMTP server that provides an intermediate relay function. In all cases, properly-operating clients supplying correct information are preferred to corrections by the SMTP server. In all cases, documentation of actions performed by the servers (in trace fields and/or header comments) is strongly encouraged. 7. Security Considerations 7.1 Mail Security and Spoofing SMTP mail is inherently insecure in that it is feasible for even fairly casual users to negotiate directly with receiving and relaying SMTP servers and create messages that will trick a naive recipient into believing that they came from somewhere else. Constructing such a message so that the "spoofed" behavior cannot be detected by an expert is somewhat more difficult, but not sufficiently so as to be a deterrent to someone who is determined and knowledgeable. Consequently, as knowledge of Internet mail increases, so does the knowledge that SMTP mail inherently cannot be authenticated, or integrity checks provided, at the transport level. Real mail security lies only in end-to-end methods involving the message bodies, such as those which use digital signatures (see [14] and, e.g., PGP [4] or S/MIME [31]). Various protocol extensions and configuration options that provide authentication at the transport level (e.g., from an SMTP client to an SMTP server) improve somewhat on the traditional situation described above. However, unless they are accompanied by careful handoffs of responsibility in a carefully-designed trust environment, they remain inherently weaker than end-to-end mechanisms which use digitally signed messages rather than depending on the integrity of the transport system. Efforts to make it more difficult for users to set envelope return path and header "From" fields to point to valid addresses other than their own are largely misguided: they frustrate legitimate applications in which mail is sent by one user on behalf of another or in which error (or normal) replies should be directed to a special address. (Systems that provide convenient ways for users to alter these fields on a per-message basis should accept to establish a primary and permanent mailbox address for the user so that Sender fields within the message data can be generated sensibly.) This specification does not further address the authentication issues associated with SMTP other than to advocate that useful functionality not be disabled in the hope of providing some small margin of protection against an ignorant user who is trying to fake mail. 7.2 "Blind" Copies Addresses that do not appear in the message headers may appear in the RCPT commands to an SMTP server for a number of reasons. The two most common involve the use of a mailing address as a "list exploder" (a single address that resolves into multiple addresses) and the appearance of "blind copies". Especially when more than one RCPT command is present, and in order to avoid defeating some of the purpose of these mechanisms, SMTP clients and servers SHOULD NOT copy the full set of RCPT command arguments into the headers, either as part of trace headers or as informational or private-extension headers. Since this rule is often violated in practice, and cannot be enforced, sending SMTP systems that are aware of "bcc" use MAY find it helpful to send each blind copy as a separate message transaction containing only a single RCPT command. There is no inherent relationship between either "reverse" (from MAIL, SAML, etc., commands) or "forward" (RCPT) addresses in the SMTP transaction ("envelope") and the addresses in the headers. Receiving systems SHOULD NOT attempt to deduce such relationships and use them to alter the headers of the message for delivery. The popular "Apparently-to" header is a violation of this principle as well as a common source of unintended information disclosure and SHOULD NOT be used. 7.3 VRFY, EXPN, and Security As discussed in section 3.5, individual sites may want to disable either or both of VRFY or EXPN for security reasons. As a corollary to the above, implementations that permit this MUST NOT appear to have verified addresses that are not, in fact, verified. If a site disables these commands for security reasons, the SMTP server MUST return a 252 response, rather than a code that could be confused with successful or unsuccessful verification. Returning a 250 reply code with the address listed in the VRFY command after having checked it only for syntax violates this rule. Of course, an implementation that "supports" VRFY by always returning 550 whether or not the address is valid is equally not in conformance. Within the last few years, the contents of mailing lists have become popular as an address information source for so-called "spammers." The use of EXPN to "harvest" addresses has increased as list administrators have installed protections against inappropriate uses of the lists themselves. Implementations SHOULD still provide support for EXPN, but sites SHOULD carefully evaluate the tradeoffs. As authentication mechanisms are introduced into SMTP, some sites may choose to make EXPN available only to authenticated requestors. 7.4 Information Disclosure in Announcements There has been an ongoing debate about the tradeoffs between the debugging advantages of announcing server type and version (and, sometimes, even server domain name) in the greeting response or in response to the HELP command and the disadvantages of exposing information that might be useful in a potential hostile attack. The utility of the debugging information is beyond doubt. Those who argue for making it available point out that it is far better to actually secure an SMTP server rather than hope that trying to conceal known vulnerabilities by hiding the server's precise identity will provide more protection. Sites are encouraged to evaluate the tradeoff with that issue in mind; implementations are strongly encouraged to minimally provide for making type and version information available in some way to other network hosts. 7.5 Information Disclosure in Trace Fields In some circumstances, such as when mail originates from within a LAN whose hosts are not directly on the public Internet, trace ("Received") fields produced in conformance with this specification may disclose host names and similar information that would not normally be available. This ordinarily does not pose a problem, but sites with special concerns about name disclosure should be aware of it. Also, the optional FOR clause should be supplied with caution or not at all when multiple recipients are involved lest it inadvertently disclose the identities of "blind copy" recipients to others. 7.6 Information Disclosure in Message Forwarding As discussed in section 3.4, use of the 251 or 551 reply codes to identify the replacement address associated with a mailbox may inadvertently disclose sensitive information. Sites that are concerned about those issues should ensure that they select and configure servers appropriately. 7.7 Scope of Operation of SMTP Servers It is a well-established principle that an SMTP server may refuse to accept mail for any operational or technical reason that makes sense to the site providing the server. However, cooperation among sites and installations makes the Internet possible. If sites take excessive advantage of the right to reject traffic, the ubiquity of email availability (one of the strengths of the Internet) will be threatened; considerable care should be taken and balance maintained if a site decides to be selective about the traffic it will accept and process. In recent years, use of the relay function through arbitrary sites has been used as part of hostile efforts to hide the actual origins of mail. Some sites have decided to limit the use of the relay function to known or identifiable sources, and implementations SHOULD provide the capability to perform this type of filtering. When mail is rejected for these or other policy reasons, a 550 code SHOULD be used in response to EHLO, MAIL, or RCPT as appropriate. 8. IANA Considerations IANA will maintain three registries in support of this specification. The first consists of SMTP service extensions with the associated keywords, and, as needed, parameters and verbs. As specified in section 2.2.2, no entry may be made in this registry that starts in an "X". Entries may be made only for service extensions (and associated keywords, parameters, or verbs) that are defined in standards-track or experimental RFCs specifically approved by the IESG for this purpose. The second registry consists of "tags" that identify forms of domain literals other than those for IPv4 addresses (specified in RFC 821 and in this document) and IPv6 addresses (specified in this document). Additional literal types require standardization before being used; none are anticipated at this time. The third, established by RFC 821 and renewed by this specification, is a registry of link and protocol identifiers to be used with the "via" and "with" subclauses of the time stamp ("Received: header") described in section 4.4. Link and protocol identifiers in addition to those specified in this document may be registered only by standardization or by way of an RFC-documented, IESG-approved, Experimental protocol extension. 9. References [1] American National Standards Institute (formerly United States of America Standards Institute), X3.4, 1968, "USA Code for Information Interchange". ANSI X3.4-1968 has been replaced by newer versions with slight modifications, but the 1968 version remains definitive for the Internet. [2] Braden, R., "Requirements for Internet hosts - application and support", STD 3, RFC 1123, October 1989. [3] Butler, M., Chase, D., Goldberger, J., Postel, J. and J. Reynolds, "Post Office Protocol - version 2", RFC 937, February 1985. [4] Callas, J., Donnerhacke, L., Finney, H. and R. Thayer, "OpenPGP Message Format", RFC 2440, November 1998. [5] Crispin, M., "Interactive Mail Access Protocol - Version 2", RFC 1176, August 1990. [6] Crispin, M., "Internet Message Access Protocol - Version 4", RFC 2060, December 1996. [7] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", RFC 822, August 1982. [8] Crocker, D. and P. Overell, Eds., "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997. [9] De Winter, J., "SMTP Service Extension for Remote Message Queue Starting", RFC 1985, August 1996. [10] Fajman, R., "An Extensible Message Format for Message Disposition Notifications", RFC 2298, March 1998. [11] Freed, N, "Behavior of and Requirements for Internet Firewalls", RFC 2979, October 2000. [12] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, December 1996. [13] Freed, N., "SMTP Service Extension for Command Pipelining", RFC 2920, September 2000. [14] Galvin, J., Murphy, S., Crocker, S. and N. Freed, "Security Multiparts for MIME: Multipart/Signed and Multipart/Encrypted", RFC 1847, October 1995. [15] Gellens, R. and J. Klensin, "Message Submission", RFC 2476, December 1998. [16] Kille, S., "Mapping between X.400 and RFC822/MIME", RFC 2156, January 1998. [17] Hinden, R and S. Deering, Eds. "IP Version 6 Addressing Architecture", RFC 2373, July 1998. [18] Klensin, J., Freed, N. and K. Moore, "SMTP Service Extension for Message Size Declaration", STD 10, RFC 1870, November 1995. [19] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker, "SMTP Service Extensions", STD 10, RFC 1869, November 1995. [20] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. Crocker, "SMTP Service Extension for 8bit-MIMEtransport", RFC 1652, July 1994. [21] Lambert, M., "PCMAIL: A distributed mail system for personal computers", RFC 1056, July 1988. [22] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987. Mockapetris, P., "Domain names - concepts and facilities", STD 13, RFC 1034, November 1987. [23] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text", RFC 2047, December 1996. [24] Moore, K., "SMTP Service Extension for Delivery Status Notifications", RFC 1891, January 1996. [25] Moore, K., and G. Vaudreuil, "An Extensible Message Format for Delivery Status Notifications", RFC 1894, January 1996. [26] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996. [27] Partridge, C., "Mail routing and the domain system", RFC 974, January 1986. [28] Partridge, C., "Duplicate messages and SMTP", RFC 1047, February 1988. [29] Postel, J., ed., "Transmission Control Protocol - DARPA Internet Program Protocol Specification", STD 7, RFC 793, September 1981. [30] Postel, J., "Simple Mail Transfer Protocol", RFC 821, August 1982. [31] Ramsdell, B., Ed., "S/MIME Version 3 Message Specification", RFC 2633, June 1999. [32] Resnick, P., Ed., "Internet Message Format", RFC 2822, April 2001. [33] Vaudreuil, G., "SMTP Service Extensions for Transmission of Large and Binary MIME Messages", RFC 1830, August 1995. [34] Vaudreuil, G., "Enhanced Mail System Status Codes", RFC 1893, January 1996. 10. Editor's Address John C. Klensin AT&T Laboratories 99 Bedford St Boston, MA 02111 USA Phone: 617-574-3076 EMail: klensin@research.att.com 11. Acknowledgments Many people worked long and hard on the many iterations of this document. There was wide-ranging debate in the IETF DRUMS Working Group, both on its mailing list and in face to face discussions, about many technical issues and the role of a revised standard for Internet mail transport, and many contributors helped form the wording in this specification. The hundreds of participants in the many discussions since RFC 821 was produced are too numerous to mention, but they all helped this document become what it is. APPENDICES A. TCP Transport Service The TCP connection supports the transmission of 8-bit bytes. The SMTP data is 7-bit ASCII characters. Each character is transmitted as an 8-bit byte with the high-order bit cleared to zero. Service extensions may modify this rule to permit transmission of full 8-bit data bytes as part of the message body, but not in SMTP commands or responses. B. Generating SMTP Commands from RFC 822 Headers Some systems use RFC 822 headers (only) in a mail submission protocol, or otherwise generate SMTP commands from RFC 822 headers when such a message is handed to an MTA from a UA. While the MTA-UA protocol is a private matter, not covered by any Internet Standard, there are problems with this approach. For example, there have been repeated problems with proper handling of "bcc" copies and redistribution lists when information that conceptually belongs to a mail envelopes is not separated early in processing from header information (and kept separate). It is recommended that the UA provide its initial ("submission client") MTA with an envelope separate from the message itself. However, if the envelope is not supplied, SMTP commands SHOULD be generated as follows: 1. Each recipient address from a TO, CC, or BCC header field SHOULD be copied to a RCPT command (generating multiple message copies if that is required for queuing or delivery). This includes any addresses listed in a RFC 822 "group". Any BCC fields SHOULD then be removed from the headers. Once this process is completed, the remaining headers SHOULD be checked to verify that at least one To:, Cc:, or Bcc: header remains. If none do, then a bcc: header with no additional information SHOULD be inserted as specified in [32]. 2. The return address in the MAIL command SHOULD, if possible, be derived from the system's identity for the submitting (local) user, and the "From:" header field otherwise. If there is a system identity available, it SHOULD also be copied to the Sender header field if it is different from the address in the From header field. (Any Sender field that was already there SHOULD be removed.) Systems may provide a way for submitters to override the envelope return address, but may want to restrict its use to privileged users. This will not prevent mail forgery, but may lessen its incidence; see section 7.1. When an MTA is being used in this way, it bears responsibility for ensuring that the message being transmitted is valid. The mechanisms for checking that validity, and for handling (or returning) messages that are not valid at the time of arrival, are part of the MUA-MTA interface and not covered by this specification. A submission protocol based on Standard RFC 822 information alone MUST NOT be used to gateway a message from a foreign (non-SMTP) mail system into an SMTP environment. Additional information to construct an envelope must come from some source in the other environment, whether supplemental headers or the foreign system's envelope. Attempts to gateway messages using only their header "to" and "cc" fields have repeatedly caused mail loops and other behavior adverse to the proper functioning of the Internet mail environment. These problems have been especially common when the message originates from an Internet mailing list and is distributed into the foreign environment using envelope information. When these messages are then processed by a header-only remailer, loops back to the Internet environment (and the mailing list) are almost inevitable. C. Source Routes Historically, the was a reverse source routing list of hosts and a source mailbox. The first host in the SHOULD be the host sending the MAIL command. Similarly, the may be a source routing lists of hosts and a destination mailbox. However, in general, the SHOULD contain only a mailbox and domain name, relying on the domain name system to supply routing information if required. The use of source routes is deprecated; while servers MUST be prepared to receive and handle them as discussed in section 3.3 and F.2, clients SHOULD NOT transmit them and this section was included only to provide context. For relay purposes, the forward-path may be a source route of the form "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE MUST BE fully- qualified domain names. This form is used to emphasize the distinction between an address and a route. The mailbox is an absolute address, and the route is information about how to get there. The two concepts should not be confused. If source routes are used, RFC 821 and the text below should be consulted for the mechanisms for constructing and updating the forward- and reverse-paths. The SMTP server transforms the command arguments by moving its own identifier (its domain name or that of any domain for which it is acting as a mail exchanger), if it appears, from the forward-path to the beginning of the reverse-path. Notice that the forward-path and reverse-path appear in the SMTP commands and replies, but not necessarily in the message. That is, there is no need for these paths and especially this syntax to appear in the "To:" , "From:", "CC:", etc. fields of the message header. Conversely, SMTP servers MUST NOT derive final message delivery information from message header fields. When the list of hosts is present, it is a "reverse" source route and indicates that the mail was relayed through each host on the list (the first host in the list was the most recent relay). This list is used as a source route to return non-delivery notices to the sender. As each relay host adds itself to the beginning of the list, it MUST use its name as known in the transport environment to which it is relaying the mail rather than that of the transport environment from which the mail came (if they are different). D. Scenarios This section presents complete scenarios of several types of SMTP sessions. In the examples, "C:" indicates what is said by the SMTP client, and "S:" indicates what is said by the SMTP server. D.1 A Typical SMTP Transaction Scenario This SMTP example shows mail sent by Smith at host bar.com, to Jones, Green, and Brown at host foo.com. Here we assume that host bar.com contacts host foo.com directly. The mail is accepted for Jones and Brown. Green does not have a mailbox at host foo.com. S: 220 foo.com Simple Mail Transfer Service Ready C: EHLO bar.com S: 250-foo.com greets bar.com S: 250-8BITMIME S: 250-SIZE S: 250-DSN S: 250 HELP C: MAIL FROM: S: 250 OK C: RCPT TO: S: 250 OK C: RCPT TO: S: 550 No such user here C: RCPT TO: S: 250 OK C: DATA S: 354 Start mail input; end with . C: Blah blah blah... C: ...etc. etc. etc. C: . S: 250 OK C: QUIT S: 221 foo.com Service closing transmission channel D.2 Aborted SMTP Transaction Scenario S: 220 foo.com Simple Mail Transfer Service Ready C: EHLO bar.com S: 250-foo.com greets bar.com S: 250-8BITMIME S: 250-SIZE S: 250-DSN S: 250 HELP C: MAIL FROM: S: 250 OK C: RCPT TO: S: 250 OK C: RCPT TO: S: 550 No such user here C: RSET S: 250 OK C: QUIT S: 221 foo.com Service closing transmission channel D.3 Relayed Mail Scenario Step 1 -- Source Host to Relay Host S: 220 foo.com Simple Mail Transfer Service Ready C: EHLO bar.com S: 250-foo.com greets bar.com S: 250-8BITMIME S: 250-SIZE S: 250-DSN S: 250 HELP C: MAIL FROM: S: 250 OK C: RCPT TO:<@foo.com:Jones@XYZ.COM> S: 250 OK C: DATA S: 354 Start mail input; end with . C: Date: Thu, 21 May 1998 05:33:29 -0700 C: From: John Q. Public C: Subject: The Next Meeting of the Board C: To: Jones@xyz.com C: C: Bill: C: The next meeting of the board of directors will be C: on Tuesday. C: John. C: . S: 250 OK C: QUIT S: 221 foo.com Service closing transmission channel Step 2 -- Relay Host to Destination Host S: 220 xyz.com Simple Mail Transfer Service Ready C: EHLO foo.com S: 250 xyz.com is on the air C: MAIL FROM:<@foo.com:JQP@bar.com> S: 250 OK C: RCPT TO: S: 250 OK C: DATA S: 354 Start mail input; end with . C: Received: from bar.com by foo.com ; Thu, 21 May 1998 C: 05:33:29 -0700 C: Date: Thu, 21 May 1998 05:33:22 -0700 C: From: John Q. Public C: Subject: The Next Meeting of the Board C: To: Jones@xyz.com C: C: Bill: C: The next meeting of the board of directors will be C: on Tuesday. C: John. C: . S: 250 OK C: QUIT S: 221 foo.com Service closing transmission channel D.4 Verifying and Sending Scenario S: 220 foo.com Simple Mail Transfer Service Ready C: EHLO bar.com S: 250-foo.com greets bar.com S: 250-8BITMIME S: 250-SIZE S: 250-DSN S: 250-VRFY S: 250 HELP C: VRFY Crispin S: 250 Mark Crispin C: SEND FROM: S: 250 OK C: RCPT TO: S: 250 OK C: DATA S: 354 Start mail input; end with . C: Blah blah blah... C: ...etc. etc. etc. C: . S: 250 OK C: QUIT S: 221 foo.com Service closing transmission channel E. Other Gateway Issues In general, gateways between the Internet and other mail systems SHOULD attempt to preserve any layering semantics across the boundaries between the two mail systems involved. Gateway- translation approaches that attempt to take shortcuts by mapping, (such as envelope information from one system to the message headers or body of another) have generally proven to be inadequate in important ways. Systems translating between environments that do not support both envelopes and headers and Internet mail must be written with the understanding that some information loss is almost inevitable. F. Deprecated Features of RFC 821 A few features of RFC 821 have proven to be problematic and SHOULD NOT be used in Internet mail. F.1 TURN This command, described in RFC 821, raises important security issues since, in the absence of strong authentication of the host requesting that the client and server switch roles, it can easily be used to divert mail from its correct destination. Its use is deprecated; SMTP systems SHOULD NOT use it unless the server can authenticate the client. F.2 Source Routing RFC 821 utilized the concept of explicit source routing to get mail from one host to another via a series of relays. The requirement to utilize source routes in regular mail traffic was eliminated by the introduction of the domain name system "MX" record and the last significant justification for them was eliminated by the introduction, in RFC 1123, of a clear requirement that addresses following an "@" must all be fully-qualified domain names. Consequently, the only remaining justifications for the use of source routes are support for very old SMTP clients or MUAs and in mail system debugging. They can, however, still be useful in the latter circumstance and for routing mail around serious, but temporary, problems such as problems with the relevant DNS records. SMTP servers MUST continue to accept source route syntax as specified in the main body of this document and in RFC 1123. They MAY, if necessary, ignore the routes and utilize only the target domain in the address. If they do utilize the source route, the message MUST be sent to the first domain shown in the address. In particular, a server MUST NOT guess at shortcuts within the source route. Clients SHOULD NOT utilize explicit source routing except under unusual circumstances, such as debugging or potentially relaying around firewall or mail system configuration errors. F.3 HELO As discussed in sections 3.1 and 4.1.1, EHLO is strongly preferred to HELO when the server will accept the former. Servers must continue to accept and process HELO in order to support older clients. F.4 #-literals RFC 821 provided for specifying an Internet address as a decimal integer host number prefixed by a pound sign, "#". In practice, that form has been obsolete since the introduction of TCP/IP. It is deprecated and MUST NOT be used. F.5 Dates and Years When dates are inserted into messages by SMTP clients or servers (e.g., in trace fields), four-digit years MUST BE used. Two-digit years are deprecated; three-digit years were never permitted in the Internet mail system. F.6 Sending versus Mailing In addition to specifying a mechanism for delivering messages to user's mailboxes, RFC 821 provided additional, optional, commands to deliver messages directly to the user's terminal screen. These commands (SEND, SAML, SOML) were rarely implemented, and changes in workstation technology and the introduction of other protocols may have rendered them obsolete even where they are implemented. Clients SHOULD NOT provide SEND, SAML, or SOML as services. Servers MAY implement them. If they are implemented by servers, the implementation model specified in RFC 821 MUST be used and the command names MUST be published in the response to the EHLO command. Full Copyright Statement Copyright (C) The Internet Society (2001). 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. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. mail-2.5.4/reference/rfc2822 Internet Message Format.txt000066400000000000000000003301471214434061600225730ustar00rootroot00000000000000 Network Working Group P. Resnick, Editor Request for Comments: 2822 QUALCOMM Incorporated Obsoletes: 822 April 2001 Category: Standards Track Internet Message Format 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 (2001). All Rights Reserved. Abstract This standard specifies a syntax for text messages that are sent between computer users, within the framework of "electronic mail" messages. This standard supersedes the one specified in Request For Comments (RFC) 822, "Standard for the Format of ARPA Internet Text Messages", updating it to reflect current practice and incorporating incremental changes that were specified in other RFCs. Table of Contents 1. Introduction ............................................... 3 1.1. Scope .................................................... 3 1.2. Notational conventions ................................... 4 1.2.1. Requirements notation .................................. 4 1.2.2. Syntactic notation ..................................... 4 1.3. Structure of this document ............................... 4 2. Lexical Analysis of Messages ............................... 5 2.1. General Description ...................................... 5 2.1.1. Line Length Limits ..................................... 6 2.2. Header Fields ............................................ 7 2.2.1. Unstructured Header Field Bodies ....................... 7 2.2.2. Structured Header Field Bodies ......................... 7 2.2.3. Long Header Fields ..................................... 7 2.3. Body ..................................................... 8 3. Syntax ..................................................... 9 3.1. Introduction ............................................. 9 3.2. Lexical Tokens ........................................... 9 Resnick Standards Track [Page 1] RFC 2822 Internet Message Format April 2001 3.2.1. Primitive Tokens ....................................... 9 3.2.2. Quoted characters ......................................10 3.2.3. Folding white space and comments .......................11 3.2.4. Atom ...................................................12 3.2.5. Quoted strings .........................................13 3.2.6. Miscellaneous tokens ...................................13 3.3. Date and Time Specification ..............................14 3.4. Address Specification ....................................15 3.4.1. Addr-spec specification ................................16 3.5 Overall message syntax ....................................17 3.6. Field definitions ........................................18 3.6.1. The origination date field .............................20 3.6.2. Originator fields ......................................21 3.6.3. Destination address fields .............................22 3.6.4. Identification fields ..................................23 3.6.5. Informational fields ...................................26 3.6.6. Resent fields ..........................................26 3.6.7. Trace fields ...........................................28 3.6.8. Optional fields ........................................29 4. Obsolete Syntax ............................................29 4.1. Miscellaneous obsolete tokens ............................30 4.2. Obsolete folding white space .............................31 4.3. Obsolete Date and Time ...................................31 4.4. Obsolete Addressing ......................................33 4.5. Obsolete header fields ...................................33 4.5.1. Obsolete origination date field ........................34 4.5.2. Obsolete originator fields .............................34 4.5.3. Obsolete destination address fields ....................34 4.5.4. Obsolete identification fields .........................35 4.5.5. Obsolete informational fields ..........................35 4.5.6. Obsolete resent fields .................................35 4.5.7. Obsolete trace fields ..................................36 4.5.8. Obsolete optional fields ...............................36 5. Security Considerations ....................................36 6. Bibliography ...............................................37 7. Editor's Address ...........................................38 8. Acknowledgements ...........................................39 Appendix A. Example messages ..................................41 A.1. Addressing examples ......................................41 A.1.1. A message from one person to another with simple addressing .............................................41 A.1.2. Different types of mailboxes ...........................42 A.1.3. Group addresses ........................................43 A.2. Reply messages ...........................................43 A.3. Resent messages ..........................................44 A.4. Messages with trace fields ...............................46 A.5. White space, comments, and other oddities ................47 A.6. Obsoleted forms ..........................................47 Resnick Standards Track [Page 2] RFC 2822 Internet Message Format April 2001 A.6.1. Obsolete addressing ....................................48 A.6.2. Obsolete dates .........................................48 A.6.3. Obsolete white space and comments ......................48 Appendix B. Differences from earlier standards ................49 Appendix C. Notices ...........................................50 Full Copyright Statement ......................................51 1. Introduction 1.1. Scope This standard specifies a syntax for text messages that are sent between computer users, within the framework of "electronic mail" messages. This standard supersedes the one specified in Request For Comments (RFC) 822, "Standard for the Format of ARPA Internet Text Messages" [RFC822], updating it to reflect current practice and incorporating incremental changes that were specified in other RFCs [STD3]. This standard specifies a syntax only for text messages. In particular, it makes no provision for the transmission of images, audio, or other sorts of structured data in electronic mail messages. There are several extensions published, such as the MIME document series [RFC2045, RFC2046, RFC2049], which describe mechanisms for the transmission of such data through electronic mail, either by extending the syntax provided here or by structuring such messages to conform to this syntax. Those mechanisms are outside of the scope of this standard. In the context of electronic mail, messages are viewed as having an envelope and contents. The envelope contains whatever information is needed to accomplish transmission and delivery. (See [RFC2821] for a discussion of the envelope.) The contents comprise the object to be delivered to the recipient. This standard applies only to the format and some of the semantics of message contents. It contains no specification of the information in the envelope. However, some message systems may use information from the contents to create the envelope. It is intended that this standard facilitate the acquisition of such information by programs. This specification is intended as a definition of what message content format is to be passed between systems. Though some message systems locally store messages in this format (which eliminates the need for translation between formats) and others use formats that differ from the one specified in this standard, local storage is outside of the scope of this standard. Resnick Standards Track [Page 3] RFC 2822 Internet Message Format April 2001 Note: This standard is not intended to dictate the internal formats used by sites, the specific message system features that they are expected to support, or any of the characteristics of user interface programs that create or read messages. In addition, this standard does not specify an encoding of the characters for either transport or storage; that is, it does not specify the number of bits used or how those bits are specifically transferred over the wire or stored on disk. 1.2. Notational conventions 1.2.1. Requirements notation This document occasionally uses terms that appear in capital letters. When the terms "MUST", "SHOULD", "RECOMMENDED", "MUST NOT", "SHOULD NOT", and "MAY" appear capitalized, they are being used to indicate particular requirements of this specification. A discussion of the meanings of these terms appears in [RFC2119]. 1.2.2. Syntactic notation This standard uses the Augmented Backus-Naur Form (ABNF) notation specified in [RFC2234] for the formal definitions of the syntax of messages. Characters will be specified either by a decimal value (e.g., the value %d65 for uppercase A and %d97 for lowercase A) or by a case-insensitive literal value enclosed in quotation marks (e.g., "A" for either uppercase or lowercase A). See [RFC2234] for the full description of the notation. 1.3. Structure of this document This document is divided into several sections. This section, section 1, is a short introduction to the document. Section 2 lays out the general description of a message and its constituent parts. This is an overview to help the reader understand some of the general principles used in the later portions of this document. Any examples in this section MUST NOT be taken as specification of the formal syntax of any part of a message. Section 3 specifies formal ABNF rules for the structure of each part of a message (the syntax) and describes the relationship between those parts and their meaning in the context of a message (the semantics). That is, it describes the actual rules for the structure of each part of a message (the syntax) as well as a description of the parts and instructions on how they ought to be interpreted (the semantics). This includes analysis of the syntax and semantics of Resnick Standards Track [Page 4] RFC 2822 Internet Message Format April 2001 subparts of messages that have specific structure. The syntax included in section 3 represents messages as they MUST be created. There are also notes in section 3 to indicate if any of the options specified in the syntax SHOULD be used over any of the others. Both sections 2 and 3 describe messages that are legal to generate for purposes of this standard. Section 4 of this document specifies an "obsolete" syntax. There are references in section 3 to these obsolete syntactic elements. The rules of the obsolete syntax are elements that have appeared in earlier revisions of this standard or have previously been widely used in Internet messages. As such, these elements MUST be interpreted by parsers of messages in order to be conformant to this standard. However, since items in this syntax have been determined to be non-interoperable or to cause significant problems for recipients of messages, they MUST NOT be generated by creators of conformant messages. Section 5 details security considerations to take into account when implementing this standard. Section 6 is a bibliography of references in this document. Section 7 contains the editor's address. Section 8 contains acknowledgements. Appendix A lists examples of different sorts of messages. These examples are not exhaustive of the types of messages that appear on the Internet, but give a broad overview of certain syntactic forms. Appendix B lists the differences between this standard and earlier standards for Internet messages. Appendix C has copyright and intellectual property notices. 2. Lexical Analysis of Messages 2.1. General Description At the most basic level, a message is a series of characters. A message that is conformant with this standard is comprised of characters with values in the range 1 through 127 and interpreted as US-ASCII characters [ASCII]. For brevity, this document sometimes refers to this range of characters as simply "US-ASCII characters". Resnick Standards Track [Page 5] RFC 2822 Internet Message Format April 2001 Note: This standard specifies that messages are made up of characters in the US-ASCII range of 1 through 127. There are other documents, specifically the MIME document series [RFC2045, RFC2046, RFC2047, RFC2048, RFC2049], that extend this standard to allow for values outside of that range. Discussion of those mechanisms is not within the scope of this standard. Messages are divided into lines of characters. A line is a series of characters that is delimited with the two characters carriage-return and line-feed; that is, the carriage return (CR) character (ASCII value 13) followed immediately by the line feed (LF) character (ASCII value 10). (The carriage-return/line-feed pair is usually written in this document as "CRLF".) A message consists of header fields (collectively called "the header of the message") followed, optionally, by a body. The header is a sequence of lines of characters with special syntax as defined in this standard. The body is simply a sequence of characters that follows the header and is separated from the header by an empty line (i.e., a line with nothing preceding the CRLF). 2.1.1. Line Length Limits There are two limits that this standard places on the number of characters in a line. Each line of characters MUST be no more than 998 characters, and SHOULD be no more than 78 characters, excluding the CRLF. The 998 character limit is due to limitations in many implementations which send, receive, or store Internet Message Format messages that simply cannot handle more than 998 characters on a line. Receiving implementations would do well to handle an arbitrarily large number of characters in a line for robustness sake. However, there are so many implementations which (in compliance with the transport requirements of [RFC2821]) do not accept messages containing more than 1000 character including the CR and LF per line, it is important for implementations not to create such messages. The more conservative 78 character recommendation is to accommodate the many implementations of user interfaces that display these messages which may truncate, or disastrously wrap, the display of more than 78 characters per line, in spite of the fact that such implementations are non-conformant to the intent of this specification (and that of [RFC2821] if they actually cause information to be lost). Again, even though this limitation is put on messages, it is encumbant upon implementations which display messages Resnick Standards Track [Page 6] RFC 2822 Internet Message Format April 2001 to handle an arbitrarily large number of characters in a line (certainly at least up to the 998 character limit) for the sake of robustness. 2.2. Header Fields Header fields are lines composed of a field name, followed by a colon (":"), followed by a field body, and terminated by CRLF. A field name MUST be composed of printable US-ASCII characters (i.e., characters that have values between 33 and 126, inclusive), except colon. A field body may be composed of any US-ASCII characters, except for CR and LF. However, a field body may contain CRLF when used in header "folding" and "unfolding" as described in section 2.2.3. All field bodies MUST conform to the syntax described in sections 3 and 4 of this standard. 2.2.1. Unstructured Header Field Bodies Some field bodies in this standard are defined simply as "unstructured" (which is specified below as any US-ASCII characters, except for CR and LF) with no further restrictions. These are referred to as unstructured field bodies. Semantically, unstructured field bodies are simply to be treated as a single line of characters with no further processing (except for header "folding" and "unfolding" as described in section 2.2.3). 2.2.2. Structured Header Field Bodies Some field bodies in this standard have specific syntactical structure more restrictive than the unstructured field bodies described above. These are referred to as "structured" field bodies. Structured field bodies are sequences of specific lexical tokens as described in sections 3 and 4 of this standard. Many of these tokens are allowed (according to their syntax) to be introduced or end with comments (as described in section 3.2.3) as well as the space (SP, ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters (together known as the white space characters, WSP), and those WSP characters are subject to header "folding" and "unfolding" as described in section 2.2.3. Semantic analysis of structured field bodies is given along with their syntax. 2.2.3. Long Header Fields Each header field is logically a single line of characters comprising the field name, the colon, and the field body. For convenience however, and to deal with the 998/78 character limitations per line, the field body portion of a header field can be split into a multiple line representation; this is called "folding". The general rule is Resnick Standards Track [Page 7] RFC 2822 Internet Message Format April 2001 that wherever this standard allows for folding white space (not simply WSP characters), a CRLF may be inserted before any WSP. For example, the header field: Subject: This is a test can be represented as: Subject: This is a test Note: Though structured field bodies are defined in such a way that folding can take place between many of the lexical tokens (and even within some of the lexical tokens), folding SHOULD be limited to placing the CRLF at higher-level syntactic breaks. For instance, if a field body is defined as comma-separated values, it is recommended that folding occur after the comma separating the structured items in preference to other places where the field could be folded, even if it is allowed elsewhere. The process of moving from this folded multiple-line representation of a header field to its single line representation is called "unfolding". Unfolding is accomplished by simply removing any CRLF that is immediately followed by WSP. Each header field should be treated in its unfolded form for further syntactic and semantic evaluation. 2.3. Body The body of a message is simply lines of US-ASCII characters. The only two limitations on the body are as follows: - CR and LF MUST only occur together as CRLF; they MUST NOT appear independently in the body. - Lines of characters in the body MUST be limited to 998 characters, and SHOULD be limited to 78 characters, excluding the CRLF. Note: As was stated earlier, there are other standards documents, specifically the MIME documents [RFC2045, RFC2046, RFC2048, RFC2049] that extend this standard to allow for different sorts of message bodies. Again, these mechanisms are beyond the scope of this document. Resnick Standards Track [Page 8] RFC 2822 Internet Message Format April 2001 3. Syntax 3.1. Introduction The syntax as given in this section defines the legal syntax of Internet messages. Messages that are conformant to this standard MUST conform to the syntax in this section. If there are options in this section where one option SHOULD be generated, that is indicated either in the prose or in a comment next to the syntax. For the defined expressions, a short description of the syntax and use is given, followed by the syntax in ABNF, followed by a semantic analysis. Primitive tokens that are used but otherwise unspecified come from [RFC2234]. In some of the definitions, there will be nonterminals whose names start with "obs-". These "obs-" elements refer to tokens defined in the obsolete syntax in section 4. In all cases, these productions are to be ignored for the purposes of generating legal Internet messages and MUST NOT be used as part of such a message. However, when interpreting messages, these tokens MUST be honored as part of the legal syntax. In this sense, section 3 defines a grammar for generation of messages, with "obs-" elements that are to be ignored, while section 4 adds grammar for interpretation of messages. 3.2. Lexical Tokens The following rules are used to define an underlying lexical analyzer, which feeds tokens to the higher-level parsers. This section defines the tokens used in structured header field bodies. Note: Readers of this standard need to pay special attention to how these lexical tokens are used in both the lower-level and higher-level syntax later in the document. Particularly, the white space tokens and the comment tokens defined in section 3.2.3 get used in the lower-level tokens defined here, and those lower-level tokens are in turn used as parts of the higher-level tokens defined later. Therefore, the white space and comments may be allowed in the higher-level tokens even though they may not explicitly appear in a particular definition. 3.2.1. Primitive Tokens The following are primitive tokens referred to elsewhere in this standard, but not otherwise defined in [RFC2234]. Some of them will not appear anywhere else in the syntax, but they are convenient to refer to in other parts of this document. Resnick Standards Track [Page 9] RFC 2822 Internet Message Format April 2001 Note: The "specials" below are just such an example. Though the specials token does not appear anywhere else in this standard, it is useful for implementers who use tools that lexically analyze messages. Each of the characters in specials can be used to indicate a tokenization point in lexical analysis. NO-WS-CTL = %d1-8 / ; US-ASCII control characters %d11 / ; that do not include the %d12 / ; carriage return, line feed, %d14-31 / ; and white space characters %d127 text = %d1-9 / ; Characters excluding CR and LF %d11 / %d12 / %d14-127 / obs-text specials = "(" / ")" / ; Special characters used in "<" / ">" / ; other parts of the syntax "[" / "]" / ":" / ";" / "@" / "\" / "," / "." / DQUOTE No special semantics are attached to these tokens. They are simply single characters. 3.2.2. Quoted characters Some characters are reserved for special interpretation, such as delimiting lexical tokens. To permit use of these characters as uninterpreted data, a quoting mechanism is provided. quoted-pair = ("\" text) / obs-qp Where any quoted-pair appears, it is to be interpreted as the text character alone. That is to say, the "\" character that appears as part of a quoted-pair is semantically "invisible". Note: The "\" character may appear in a message where it is not part of a quoted-pair. A "\" character that does not appear in a quoted-pair is not semantically invisible. The only places in this standard where quoted-pair currently appears are ccontent, qcontent, dcontent, no-fold-quote, and no-fold-literal. Resnick Standards Track [Page 10] RFC 2822 Internet Message Format April 2001 3.2.3. Folding white space and comments White space characters, including white space used in folding (described in section 2.2.3), may appear between many elements in header field bodies. Also, strings of characters that are treated as comments may be included in structured field bodies as characters enclosed in parentheses. The following defines the folding white space (FWS) and comment constructs. Strings of characters enclosed in parentheses are considered comments so long as they do not appear within a "quoted-string", as defined in section 3.2.5. Comments may nest. There are several places in this standard where comments and FWS may be freely inserted. To accommodate that syntax, an additional token for "CFWS" is defined for places where comments and/or FWS can occur. However, where CFWS occurs in this standard, it MUST NOT be inserted in such a way that any line of a folded header field is made up entirely of WSP characters and nothing else. FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space obs-FWS ctext = NO-WS-CTL / ; Non white space controls %d33-39 / ; The rest of the US-ASCII %d42-91 / ; characters not including "(", %d93-126 ; ")", or "\" ccontent = ctext / quoted-pair / comment comment = "(" *([FWS] ccontent) [FWS] ")" CFWS = *([FWS] comment) (([FWS] comment) / FWS) Throughout this standard, where FWS (the folding white space token) appears, it indicates a place where header folding, as discussed in section 2.2.3, may take place. Wherever header folding appears in a message (that is, a header field body containing a CRLF followed by any WSP), header unfolding (removal of the CRLF) is performed before any further lexical analysis is performed on that header field according to this standard. That is to say, any CRLF that appears in FWS is semantically "invisible." A comment is normally used in a structured field body to provide some human readable informational text. Since a comment is allowed to contain FWS, folding is permitted within the comment. Also note that since quoted-pair is allowed in a comment, the parentheses and Resnick Standards Track [Page 11] RFC 2822 Internet Message Format April 2001 backslash characters may appear in a comment so long as they appear as a quoted-pair. Semantically, the enclosing parentheses are not part of the comment; the comment is what is contained between the two parentheses. As stated earlier, the "\" in any quoted-pair and the CRLF in any FWS that appears within the comment are semantically "invisible" and therefore not part of the comment either. Runs of FWS, comment or CFWS that occur between lexical tokens in a structured field header are semantically interpreted as a single space character. 3.2.4. Atom Several productions in structured header field bodies are simply strings of certain basic characters. Such productions are called atoms. Some of the structured header field bodies also allow the period character (".", ASCII value 46) within runs of atext. An additional "dot-atom" token is defined for those purposes. atext = ALPHA / DIGIT / ; Any character except controls, "!" / "#" / ; SP, and specials. "$" / "%" / ; Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" atom = [CFWS] 1*atext [CFWS] dot-atom = [CFWS] dot-atom-text [CFWS] dot-atom-text = 1*atext *("." 1*atext) Both atom and dot-atom are interpreted as a single unit, comprised of the string of characters that make it up. Semantically, the optional comments and FWS surrounding the rest of the characters are not part of the atom; the atom is only the run of atext characters in an atom, or the atext and "." characters in a dot-atom. Resnick Standards Track [Page 12] RFC 2822 Internet Message Format April 2001 3.2.5. Quoted strings Strings of characters that include characters other than those allowed in atoms may be represented in a quoted string format, where the characters are surrounded by quote (DQUOTE, ASCII value 34) characters. qtext = NO-WS-CTL / ; Non white space controls %d33 / ; The rest of the US-ASCII %d35-91 / ; characters not including "\" %d93-126 ; or the quote character qcontent = qtext / quoted-pair quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS] A quoted-string is treated as a unit. That is, quoted-string is identical to atom, semantically. Since a quoted-string is allowed to contain FWS, folding is permitted. Also note that since quoted-pair is allowed in a quoted-string, the quote and backslash characters may appear in a quoted-string so long as they appear as a quoted-pair. Semantically, neither the optional CFWS outside of the quote characters nor the quote characters themselves are part of the quoted-string; the quoted-string is what is contained between the two quote characters. As stated earlier, the "\" in any quoted-pair and the CRLF in any FWS/CFWS that appears within the quoted-string are semantically "invisible" and therefore not part of the quoted-string either. 3.2.6. Miscellaneous tokens Three additional tokens are defined, word and phrase for combinations of atoms and/or quoted-strings, and unstructured for use in unstructured header fields and in some places within structured header fields. word = atom / quoted-string phrase = 1*word / obs-phrase Resnick Standards Track [Page 13] RFC 2822 Internet Message Format April 2001 utext = NO-WS-CTL / ; Non white space controls %d33-126 / ; The rest of US-ASCII obs-utext unstructured = *([FWS] utext) [FWS] 3.3. Date and Time Specification Date and time occur in several header fields. This section specifies the syntax for a full date and time specification. Though folding white space is permitted throughout the date-time specification, it is RECOMMENDED that a single space be used in each place that FWS appears (whether it is required or optional); some older implementations may not interpret other occurrences of folding white space correctly. date-time = [ day-of-week "," ] date FWS time [CFWS] day-of-week = ([FWS] day-name) / obs-day-of-week day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" date = day month year year = 4*DIGIT / obs-year month = (FWS month-name FWS) / obs-month month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" day = ([FWS] 1*2DIGIT) / obs-day time = time-of-day FWS zone time-of-day = hour ":" minute [ ":" second ] hour = 2DIGIT / obs-hour minute = 2DIGIT / obs-minute second = 2DIGIT / obs-second zone = (( "+" / "-" ) 4DIGIT) / obs-zone Resnick Standards Track [Page 14] RFC 2822 Internet Message Format April 2001 The day is the numeric day of the month. The year is any numeric year 1900 or later. The time-of-day specifies the number of hours, minutes, and optionally seconds since midnight of the date indicated. The date and time-of-day SHOULD express local time. The zone specifies the offset from Coordinated Universal Time (UTC, formerly referred to as "Greenwich Mean Time") that the date and time-of-day represent. The "+" or "-" indicates whether the time-of-day is ahead of (i.e., east of) or behind (i.e., west of) Universal Time. The first two digits indicate the number of hours difference from Universal Time, and the last two digits indicate the number of minutes difference from Universal Time. (Hence, +hhmm means +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm) minutes). The form "+0000" SHOULD be used to indicate a time zone at Universal Time. Though "-0000" also indicates Universal Time, it is used to indicate that the time was generated on a system that may be in a local time zone other than Universal Time and therefore indicates that the date-time contains no information about the local time zone. A date-time specification MUST be semantically valid. That is, the day-of-the-week (if included) MUST be the day implied by the date, the numeric day-of-month MUST be between 1 and the number of days allowed for the specified month (in the specified year), the time-of-day MUST be in the range 00:00:00 through 23:59:60 (the number of seconds allowing for a leap second; see [STD12]), and the zone MUST be within the range -9959 through +9959. 3.4. Address Specification Addresses occur in several message header fields to indicate senders and recipients of messages. An address may either be an individual mailbox, or a group of mailboxes. address = mailbox / group mailbox = name-addr / addr-spec name-addr = [display-name] angle-addr angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr group = display-name ":" [mailbox-list / CFWS] ";" [CFWS] Resnick Standards Track [Page 15] RFC 2822 Internet Message Format April 2001 display-name = phrase mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list address-list = (address *("," address)) / obs-addr-list A mailbox receives mail. It is a conceptual entity which does not necessarily pertain to file storage. For example, some sites may choose to print mail on a printer and deliver the output to the addressee's desk. Normally, a mailbox is comprised of two parts: (1) an optional display name that indicates the name of the recipient (which could be a person or a system) that could be displayed to the user of a mail application, and (2) an addr-spec address enclosed in angle brackets ("<" and ">"). There is also an alternate simple form of a mailbox where the addr-spec address appears alone, without the recipient's name or the angle brackets. The Internet addr-spec address is described in section 3.4.1. Note: Some legacy implementations used the simple form where the addr-spec appears without the angle brackets, but included the name of the recipient in parentheses as a comment following the addr-spec. Since the meaning of the information in a comment is unspecified, implementations SHOULD use the full name-addr form of the mailbox, instead of the legacy form, to specify the display name associated with a mailbox. Also, because some legacy implementations interpret the comment, comments generally SHOULD NOT be used in address fields to avoid confusing such implementations. When it is desirable to treat several mailboxes as a single unit (i.e., in a distribution list), the group construct can be used. The group construct allows the sender to indicate a named group of recipients. This is done by giving a display name for the group, followed by a colon, followed by a comma separated list of any number of mailboxes (including zero and one), and ending with a semicolon. Because the list of mailboxes can be empty, using the group construct is also a simple way to communicate to recipients that the message was sent to one or more named sets of recipients, without actually providing the individual mailbox address for each of those recipients. 3.4.1. Addr-spec specification An addr-spec is a specific Internet identifier that contains a locally interpreted string followed by the at-sign character ("@", ASCII value 64) followed by an Internet domain. The locally interpreted string is either a quoted-string or a dot-atom. If the string can be represented as a dot-atom (that is, it contains no characters other than atext characters or "." surrounded by atext Resnick Standards Track [Page 16] RFC 2822 Internet Message Format April 2001 characters), then the dot-atom form SHOULD be used and the quoted-string form SHOULD NOT be used. Comments and folding white space SHOULD NOT be used around the "@" in the addr-spec. addr-spec = local-part "@" domain local-part = dot-atom / quoted-string / obs-local-part domain = dot-atom / domain-literal / obs-domain domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] dcontent = dtext / quoted-pair dtext = NO-WS-CTL / ; Non white space controls %d33-90 / ; The rest of the US-ASCII %d94-126 ; characters not including "[", ; "]", or "\" The domain portion identifies the point to which the mail is delivered. In the dot-atom form, this is interpreted as an Internet domain name (either a host name or a mail exchanger name) as described in [STD3, STD13, STD14]. In the domain-literal form, the domain is interpreted as the literal Internet address of the particular host. In both cases, how addressing is used and how messages are transported to a particular host is covered in the mail transport document [RFC2821]. These mechanisms are outside of the scope of this document. The local-part portion is a domain dependent string. In addresses, it is simply interpreted on the particular host as a name of a particular mailbox. 3.5 Overall message syntax A message consists of header fields, optionally followed by a message body. Lines in a message MUST be a maximum of 998 characters excluding the CRLF, but it is RECOMMENDED that lines be limited to 78 characters excluding the CRLF. (See section 2.1.1 for explanation.) In a message body, though all of the characters listed in the text rule MAY be used, the use of US-ASCII control characters (values 1 through 8, 11, 12, and 14 through 31) is discouraged since their interpretation by receivers for display is not guaranteed. Resnick Standards Track [Page 17] RFC 2822 Internet Message Format April 2001 message = (fields / obs-fields) [CRLF body] body = *(*998text CRLF) *998text The header fields carry most of the semantic information and are defined in section 3.6. The body is simply a series of lines of text which are uninterpreted for the purposes of this standard. 3.6. Field definitions The header fields of a message are defined here. All header fields have the same general syntactic structure: A field name, followed by a colon, followed by the field body. The specific syntax for each header field is defined in the subsequent sections. Note: In the ABNF syntax for each field in subsequent sections, each field name is followed by the required colon. However, for brevity sometimes the colon is not referred to in the textual description of the syntax. It is, nonetheless, required. It is important to note that the header fields are not guaranteed to be in a particular order. They may appear in any order, and they have been known to be reordered occasionally when transported over the Internet. However, for the purposes of this standard, header fields SHOULD NOT be reordered when a message is transported or transformed. More importantly, the trace header fields and resent header fields MUST NOT be reordered, and SHOULD be kept in blocks prepended to the message. See sections 3.6.6 and 3.6.7 for more information. The only required header fields are the origination date field and the originator address field(s). All other header fields are syntactically optional. More information is contained in the table following this definition. fields = *(trace *(resent-date / resent-from / resent-sender / resent-to / resent-cc / resent-bcc / resent-msg-id)) *(orig-date / from / sender / reply-to / Resnick Standards Track [Page 18] RFC 2822 Internet Message Format April 2001 to / cc / bcc / message-id / in-reply-to / references / subject / comments / keywords / optional-field) The following table indicates limits on the number of times each field may occur in a message header as well as any special limitations on the use of those fields. An asterisk next to a value in the minimum or maximum column indicates that a special restriction appears in the Notes column. Field Min number Max number Notes trace 0 unlimited Block prepended - see 3.6.7 resent-date 0* unlimited* One per block, required if other resent fields present - see 3.6.6 resent-from 0 unlimited* One per block - see 3.6.6 resent-sender 0* unlimited* One per block, MUST occur with multi-address resent-from - see 3.6.6 resent-to 0 unlimited* One per block - see 3.6.6 resent-cc 0 unlimited* One per block - see 3.6.6 resent-bcc 0 unlimited* One per block - see 3.6.6 resent-msg-id 0 unlimited* One per block - see 3.6.6 orig-date 1 1 from 1 1 See sender and 3.6.2 Resnick Standards Track [Page 19] RFC 2822 Internet Message Format April 2001 sender 0* 1 MUST occur with multi- address from - see 3.6.2 reply-to 0 1 to 0 1 cc 0 1 bcc 0 1 message-id 0* 1 SHOULD be present - see 3.6.4 in-reply-to 0* 1 SHOULD occur in some replies - see 3.6.4 references 0* 1 SHOULD occur in some replies - see 3.6.4 subject 0 1 comments 0 unlimited keywords 0 unlimited optional-field 0 unlimited The exact interpretation of each field is described in subsequent sections. 3.6.1. The origination date field The origination date field consists of the field name "Date" followed by a date-time specification. orig-date = "Date:" date-time CRLF The origination date specifies the date and time at which the creator of the message indicated that the message was complete and ready to enter the mail delivery system. For instance, this might be the time that a user pushes the "send" or "submit" button in an application program. In any case, it is specifically not intended to convey the time that the message is actually transported, but rather the time at which the human or other creator of the message has put the message into its final form, ready for transport. (For example, a portable computer user who is not connected to a network might queue a message Resnick Standards Track [Page 20] RFC 2822 Internet Message Format April 2001 for delivery. The origination date is intended to contain the date and time that the user queued the message, not the time when the user connected to the network to send the message.) 3.6.2. Originator fields The originator fields of a message consist of the from field, the sender field (when applicable), and optionally the reply-to field. The from field consists of the field name "From" and a comma-separated list of one or more mailbox specifications. If the from field contains more than one mailbox specification in the mailbox-list, then the sender field, containing the field name "Sender" and a single mailbox specification, MUST appear in the message. In either case, an optional reply-to field MAY also be included, which contains the field name "Reply-To" and a comma-separated list of one or more addresses. from = "From:" mailbox-list CRLF sender = "Sender:" mailbox CRLF reply-to = "Reply-To:" address-list CRLF The originator fields indicate the mailbox(es) of the source of the message. The "From:" field specifies the author(s) of the message, that is, the mailbox(es) of the person(s) or system(s) responsible for the writing of the message. The "Sender:" field specifies the mailbox of the agent responsible for the actual transmission of the message. For example, if a secretary were to send a message for another person, the mailbox of the secretary would appear in the "Sender:" field and the mailbox of the actual author would appear in the "From:" field. If the originator of the message can be indicated by a single mailbox and the author and transmitter are identical, the "Sender:" field SHOULD NOT be used. Otherwise, both fields SHOULD appear. The originator fields also provide the information required when replying to a message. When the "Reply-To:" field is present, it indicates the mailbox(es) to which the author of the message suggests that replies be sent. In the absence of the "Reply-To:" field, replies SHOULD by default be sent to the mailbox(es) specified in the "From:" field unless otherwise specified by the person composing the reply. In all cases, the "From:" field SHOULD NOT contain any mailbox that does not belong to the author(s) of the message. See also section 3.6.3 for more information on forming the destination addresses for a reply. Resnick Standards Track [Page 21] RFC 2822 Internet Message Format April 2001 3.6.3. Destination address fields The destination fields of a message consist of three possible fields, each of the same form: The field name, which is either "To", "Cc", or "Bcc", followed by a comma-separated list of one or more addresses (either mailbox or group syntax). to = "To:" address-list CRLF cc = "Cc:" address-list CRLF bcc = "Bcc:" (address-list / [CFWS]) CRLF The destination fields specify the recipients of the message. Each destination field may have one or more addresses, and each of the addresses indicate the intended recipients of the message. The only difference between the three fields is how each is used. The "To:" field contains the address(es) of the primary recipient(s) of the message. The "Cc:" field (where the "Cc" means "Carbon Copy" in the sense of making a copy on a typewriter using carbon paper) contains the addresses of others who are to receive the message, though the content of the message may not be directed at them. The "Bcc:" field (where the "Bcc" means "Blind Carbon Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message. There are three ways in which the "Bcc:" field is used. In the first case, when a message containing a "Bcc:" field is prepared to be sent, the "Bcc:" line is removed even though all of the recipients (including those specified in the "Bcc:" field) are sent a copy of the message. In the second case, recipients specified in the "To:" and "Cc:" lines each are sent a copy of the message with the "Bcc:" line removed as above, but the recipients on the "Bcc:" line get a separate copy of the message containing a "Bcc:" line. (When there are multiple recipient addresses in the "Bcc:" field, some implementations actually send a separate copy of the message to each recipient with a "Bcc:" containing only the address of that particular recipient.) Finally, since a "Bcc:" field may contain no addresses, a "Bcc:" field can be sent without any addresses indicating to the recipients that blind copies were sent to someone. Which method to use with "Bcc:" fields is implementation dependent, but refer to the "Security Considerations" section of this document for a discussion of each. Resnick Standards Track [Page 22] RFC 2822 Internet Message Format April 2001 When a message is a reply to another message, the mailboxes of the authors of the original message (the mailboxes in the "From:" field) or mailboxes specified in the "Reply-To:" field (if it exists) MAY appear in the "To:" field of the reply since these would normally be the primary recipients of the reply. If a reply is sent to a message that has destination fields, it is often desirable to send a copy of the reply to all of the recipients of the message, in addition to the author. When such a reply is formed, addresses in the "To:" and "Cc:" fields of the original message MAY appear in the "Cc:" field of the reply, since these are normally secondary recipients of the reply. If a "Bcc:" field is present in the original message, addresses in that field MAY appear in the "Bcc:" field of the reply, but SHOULD NOT appear in the "To:" or "Cc:" fields. Note: Some mail applications have automatic reply commands that include the destination addresses of the original message in the destination addresses of the reply. How those reply commands behave is implementation dependent and is beyond the scope of this document. In particular, whether or not to include the original destination addresses when the original message had a "Reply-To:" field is not addressed here. 3.6.4. Identification fields Though optional, every message SHOULD have a "Message-ID:" field. Furthermore, reply messages SHOULD have "In-Reply-To:" and "References:" fields as appropriate, as described below. The "Message-ID:" field contains a single unique message identifier. The "References:" and "In-Reply-To:" field each contain one or more unique message identifiers, optionally separated by CFWS. The message identifier (msg-id) is similar in syntax to an angle-addr construct without the internal CFWS. message-id = "Message-ID:" msg-id CRLF in-reply-to = "In-Reply-To:" 1*msg-id CRLF references = "References:" 1*msg-id CRLF msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] id-left = dot-atom-text / no-fold-quote / obs-id-left id-right = dot-atom-text / no-fold-literal / obs-id-right no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE Resnick Standards Track [Page 23] RFC 2822 Internet Message Format April 2001 no-fold-literal = "[" *(dtext / quoted-pair) "]" The "Message-ID:" field provides a unique message identifier that refers to a particular version of a particular message. The uniqueness of the message identifier is guaranteed by the host that generates it (see below). This message identifier is intended to be machine readable and not necessarily meaningful to humans. A message identifier pertains to exactly one instantiation of a particular message; subsequent revisions to the message each receive new message identifiers. Note: There are many instances when messages are "changed", but those changes do not constitute a new instantiation of that message, and therefore the message would not get a new message identifier. For example, when messages are introduced into the transport system, they are often prepended with additional header fields such as trace fields (described in section 3.6.7) and resent fields (described in section 3.6.6). The addition of such header fields does not change the identity of the message and therefore the original "Message-ID:" field is retained. In all cases, it is the meaning that the sender of the message wishes to convey (i.e., whether this is the same message or a different message) that determines whether or not the "Message-ID:" field changes, not any particular syntactic difference that appears (or does not appear) in the message. The "In-Reply-To:" and "References:" fields are used when creating a reply to a message. They hold the message identifier of the original message and the message identifiers of other messages (for example, in the case of a reply to a message which was itself a reply). The "In-Reply-To:" field may be used to identify the message (or messages) to which the new message is a reply, while the "References:" field may be used to identify a "thread" of conversation. When creating a reply to a message, the "In-Reply-To:" and "References:" fields of the resultant message are constructed as follows: The "In-Reply-To:" field will contain the contents of the "Message- ID:" field of the message to which this one is a reply (the "parent message"). If there is more than one parent message, then the "In- Reply-To:" field will contain the contents of all of the parents' "Message-ID:" fields. If there is no "Message-ID:" field in any of the parent messages, then the new message will have no "In-Reply-To:" field. Resnick Standards Track [Page 24] RFC 2822 Internet Message Format April 2001 The "References:" field will contain the contents of the parent's "References:" field (if any) followed by the contents of the parent's "Message-ID:" field (if any). If the parent message does not contain a "References:" field but does have an "In-Reply-To:" field containing a single message identifier, then the "References:" field will contain the contents of the parent's "In-Reply-To:" field followed by the contents of the parent's "Message-ID:" field (if any). If the parent has none of the "References:", "In-Reply-To:", or "Message-ID:" fields, then the new message will have no "References:" field. Note: Some implementations parse the "References:" field to display the "thread of the discussion". These implementations assume that each new message is a reply to a single parent and hence that they can walk backwards through the "References:" field to find the parent of each message listed there. Therefore, trying to form a "References:" field for a reply that has multiple parents is discouraged and how to do so is not defined in this document. The message identifier (msg-id) itself MUST be a globally unique identifier for a message. The generator of the message identifier MUST guarantee that the msg-id is unique. There are several algorithms that can be used to accomplish this. Since the msg-id has a similar syntax to angle-addr (identical except that comments and folding white space are not allowed), a good method is to put the domain name (or a domain literal IP address) of the host on which the message identifier was created on the right hand side of the "@", and put a combination of the current absolute date and time along with some other currently unique (perhaps sequential) identifier available on the system (for example, a process id number) on the left hand side. Using a date on the left hand side and a domain name or domain literal on the right hand side makes it possible to guarantee uniqueness since no two hosts use the same domain name or IP address at the same time. Though other algorithms will work, it is RECOMMENDED that the right hand side contain some domain identifier (either of the host itself or otherwise) such that the generator of the message identifier can guarantee the uniqueness of the left hand side within the scope of that domain. Semantically, the angle bracket characters are not part of the msg-id; the msg-id is what is contained between the two angle bracket characters. Resnick Standards Track [Page 25] RFC 2822 Internet Message Format April 2001 3.6.5. Informational fields The informational fields are all optional. The "Keywords:" field contains a comma-separated list of one or more words or quoted-strings. The "Subject:" and "Comments:" fields are unstructured fields as defined in section 2.2.1, and therefore may contain text or folding white space. subject = "Subject:" unstructured CRLF comments = "Comments:" unstructured CRLF keywords = "Keywords:" phrase *("," phrase) CRLF These three fields are intended to have only human-readable content with information about the message. The "Subject:" field is the most common and contains a short string identifying the topic of the message. When used in a reply, the field body MAY start with the string "Re: " (from the Latin "res", in the matter of) followed by the contents of the "Subject:" field body of the original message. If this is done, only one instance of the literal string "Re: " ought to be used since use of other strings or more than one instance can lead to undesirable consequences. The "Comments:" field contains any additional comments on the text of the body of the message. The "Keywords:" field contains a comma-separated list of important words and phrases that might be useful for the recipient. 3.6.6. Resent fields Resent fields SHOULD be added to any message that is reintroduced by a user into the transport system. A separate set of resent fields SHOULD be added each time this is done. All of the resent fields corresponding to a particular resending of the message SHOULD be together. Each new set of resent fields is prepended to the message; that is, the most recent set of resent fields appear earlier in the message. No other fields in the message are changed when resent fields are added. Each of the resent fields corresponds to a particular field elsewhere in the syntax. For instance, the "Resent-Date:" field corresponds to the "Date:" field and the "Resent-To:" field corresponds to the "To:" field. In each case, the syntax for the field body is identical to the syntax given previously for the corresponding field. When resent fields are used, the "Resent-From:" and "Resent-Date:" fields MUST be sent. The "Resent-Message-ID:" field SHOULD be sent. "Resent-Sender:" SHOULD NOT be used if "Resent-Sender:" would be identical to "Resent-From:". Resnick Standards Track [Page 26] RFC 2822 Internet Message Format April 2001 resent-date = "Resent-Date:" date-time CRLF resent-from = "Resent-From:" mailbox-list CRLF resent-sender = "Resent-Sender:" mailbox CRLF resent-to = "Resent-To:" address-list CRLF resent-cc = "Resent-Cc:" address-list CRLF resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF resent-msg-id = "Resent-Message-ID:" msg-id CRLF Resent fields are used to identify a message as having been reintroduced into the transport system by a user. The purpose of using resent fields is to have the message appear to the final recipient as if it were sent directly by the original sender, with all of the original fields remaining the same. Each set of resent fields correspond to a particular resending event. That is, if a message is resent multiple times, each set of resent fields gives identifying information for each individual time. Resent fields are strictly informational. They MUST NOT be used in the normal processing of replies or other such automatic actions on messages. Note: Reintroducing a message into the transport system and using resent fields is a different operation from "forwarding". "Forwarding" has two meanings: One sense of forwarding is that a mail reading program can be told by a user to forward a copy of a message to another person, making the forwarded message the body of the new message. A forwarded message in this sense does not appear to have come from the original sender, but is an entirely new message from the forwarder of the message. On the other hand, forwarding is also used to mean when a mail transport program gets a message and forwards it on to a different destination for final delivery. Resent header fields are not intended for use with either type of forwarding. The resent originator fields indicate the mailbox of the person(s) or system(s) that resent the message. As with the regular originator fields, there are two forms: a simple "Resent-From:" form which contains the mailbox of the individual doing the resending, and the more complex form, when one individual (identified in the "Resent-Sender:" field) resends a message on behalf of one or more others (identified in the "Resent-From:" field). Note: When replying to a resent message, replies behave just as they would with any other message, using the original "From:", Resnick Standards Track [Page 27] RFC 2822 Internet Message Format April 2001 "Reply-To:", "Message-ID:", and other fields. The resent fields are only informational and MUST NOT be used in the normal processing of replies. The "Resent-Date:" indicates the date and time at which the resent message is dispatched by the resender of the message. Like the "Date:" field, it is not the date and time that the message was actually transported. The "Resent-To:", "Resent-Cc:", and "Resent-Bcc:" fields function identically to the "To:", "Cc:", and "Bcc:" fields respectively, except that they indicate the recipients of the resent message, not the recipients of the original message. The "Resent-Message-ID:" field provides a unique identifier for the resent message. 3.6.7. Trace fields The trace fields are a group of header fields consisting of an optional "Return-Path:" field, and one or more "Received:" fields. The "Return-Path:" header field contains a pair of angle brackets that enclose an optional addr-spec. The "Received:" field contains a (possibly empty) list of name/value pairs followed by a semicolon and a date-time specification. The first item of the name/value pair is defined by item-name, and the second item is either an addr-spec, an atom, a domain, or a msg-id. Further restrictions may be applied to the syntax of the trace fields by standards that provide for their use, such as [RFC2821]. trace = [return] 1*received return = "Return-Path:" path CRLF path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / obs-path received = "Received:" name-val-list ";" date-time CRLF name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] name-val-pair = item-name CFWS item-value item-name = ALPHA *(["-"] (ALPHA / DIGIT)) item-value = 1*angle-addr / addr-spec / atom / domain / msg-id Resnick Standards Track [Page 28] RFC 2822 Internet Message Format April 2001 A full discussion of the Internet mail use of trace fields is contained in [RFC2821]. For the purposes of this standard, the trace fields are strictly informational, and any formal interpretation of them is outside of the scope of this document. 3.6.8. Optional fields Fields may appear in messages that are otherwise unspecified in this standard. They MUST conform to the syntax of an optional-field. This is a field name, made up of the printable US-ASCII characters except SP and colon, followed by a colon, followed by any text which conforms to unstructured. The field names of any optional-field MUST NOT be identical to any field name specified elsewhere in this standard. optional-field = field-name ":" unstructured CRLF field-name = 1*ftext ftext = %d33-57 / ; Any character except %d59-126 ; controls, SP, and ; ":". For the purposes of this standard, any optional field is uninterpreted. 4. Obsolete Syntax Earlier versions of this standard allowed for different (usually more liberal) syntax than is allowed in this version. Also, there have been syntactic elements used in messages on the Internet whose interpretation have never been documented. Though some of these syntactic forms MUST NOT be generated according to the grammar in section 3, they MUST be accepted and parsed by a conformant receiver. This section documents many of these syntactic elements. Taking the grammar in section 3 and adding the definitions presented in this section will result in the grammar to use for interpretation of messages. Note: This section identifies syntactic forms that any implementation MUST reasonably interpret. However, there are certainly Internet messages which do not conform to even the additional syntax given in this section. The fact that a particular form does not appear in any section of this document is not justification for computer programs to crash or for malformed data to be irretrievably lost by any implementation. To repeat an example, though this document requires lines in messages to be no longer than 998 characters, silently Resnick Standards Track [Page 29] RFC 2822 Internet Message Format April 2001 discarding the 999th and subsequent characters in a line without warning would still be bad behavior for an implementation. It is up to the implementation to deal with messages robustly. One important difference between the obsolete (interpreting) and the current (generating) syntax is that in structured header field bodies (i.e., between the colon and the CRLF of any structured header field), white space characters, including folding white space, and comments can be freely inserted between any syntactic tokens. This allows many complex forms that have proven difficult for some implementations to parse. Another key difference between the obsolete and the current syntax is that the rule in section 3.2.3 regarding lines composed entirely of white space in comments and folding white space does not apply. See the discussion of folding white space in section 4.2 below. Finally, certain characters that were formerly allowed in messages appear in this section. The NUL character (ASCII value 0) was once allowed, but is no longer for compatibility reasons. CR and LF were allowed to appear in messages other than as CRLF; this use is also shown here. Other differences in syntax and semantics are noted in the following sections. 4.1. Miscellaneous obsolete tokens These syntactic elements are used elsewhere in the obsolete syntax or in the main syntax. The obs-char and obs-qp elements each add ASCII value 0. Bare CR and bare LF are added to obs-text and obs-utext. The period character is added to obs-phrase. The obs-phrase-list provides for "empty" elements in a comma-separated list of phrases. Note: The "period" (or "full stop") character (".") in obs-phrase is not a form that was allowed in earlier versions of this or any other standard. Period (nor any other character from specials) was not allowed in phrase because it introduced a parsing difficulty distinguishing between phrases and portions of an addr-spec (see section 4.4). It appears here because the period character is currently used in many messages in the display-name portion of addresses, especially for initials in names, and therefore must be interpreted properly. In the future, period may appear in the regular syntax of phrase. obs-qp = "\" (%d0-127) obs-text = *LF *CR *(obs-char *LF *CR) Resnick Standards Track [Page 30] RFC 2822 Internet Message Format April 2001 obs-char = %d0-9 / %d11 / ; %d0-127 except CR and %d12 / %d14-127 ; LF obs-utext = obs-text obs-phrase = word *(word / "." / CFWS) obs-phrase-list = phrase / 1*([phrase] [CFWS] "," [CFWS]) [phrase] Bare CR and bare LF appear in messages with two different meanings. In many cases, bare CR or bare LF are used improperly instead of CRLF to indicate line separators. In other cases, bare CR and bare LF are used simply as ASCII control characters with their traditional ASCII meanings. 4.2. Obsolete folding white space In the obsolete syntax, any amount of folding white space MAY be inserted where the obs-FWS rule is allowed. This creates the possibility of having two consecutive "folds" in a line, and therefore the possibility that a line which makes up a folded header field could be composed entirely of white space. obs-FWS = 1*WSP *(CRLF 1*WSP) 4.3. Obsolete Date and Time The syntax for the obsolete date format allows a 2 digit year in the date field and allows for a list of alphabetic time zone specifications that were used in earlier versions of this standard. It also permits comments and folding white space between many of the tokens. obs-day-of-week = [CFWS] day-name [CFWS] obs-year = [CFWS] 2*DIGIT [CFWS] obs-month = CFWS month-name CFWS obs-day = [CFWS] 1*2DIGIT [CFWS] obs-hour = [CFWS] 2DIGIT [CFWS] obs-minute = [CFWS] 2DIGIT [CFWS] obs-second = [CFWS] 2DIGIT [CFWS] obs-zone = "UT" / "GMT" / ; Universal Time Resnick Standards Track [Page 31] RFC 2822 Internet Message Format April 2001 ; North American UT ; offsets "EST" / "EDT" / ; Eastern: - 5/ - 4 "CST" / "CDT" / ; Central: - 6/ - 5 "MST" / "MDT" / ; Mountain: - 7/ - 6 "PST" / "PDT" / ; Pacific: - 8/ - 7 %d65-73 / ; Military zones - "A" %d75-90 / ; through "I" and "K" %d97-105 / ; through "Z", both %d107-122 ; upper and lower case Where a two or three digit year occurs in a date, the year is to be interpreted as follows: If a two digit year is encountered whose value is between 00 and 49, the year is interpreted by adding 2000, ending up with a value between 2000 and 2049. If a two digit year is encountered with a value between 50 and 99, or any three digit year is encountered, the year is interpreted by adding 1900. In the obsolete time zone, "UT" and "GMT" are indications of "Universal Time" and "Greenwich Mean Time" respectively and are both semantically identical to "+0000". The remaining three character zones are the US time zones. The first letter, "E", "C", "M", or "P" stands for "Eastern", "Central", "Mountain" and "Pacific". The second letter is either "S" for "Standard" time, or "D" for "Daylight" (or summer) time. Their interpretations are as follows: EDT is semantically equivalent to -0400 EST is semantically equivalent to -0500 CDT is semantically equivalent to -0500 CST is semantically equivalent to -0600 MDT is semantically equivalent to -0600 MST is semantically equivalent to -0700 PDT is semantically equivalent to -0700 PST is semantically equivalent to -0800 The 1 character military time zones were defined in a non-standard way in [RFC822] and are therefore unpredictable in their meaning. The original definitions of the military zones "A" through "I" are equivalent to "+0100" through "+0900" respectively; "K", "L", and "M" are equivalent to "+1000", "+1100", and "+1200" respectively; "N" through "Y" are equivalent to "-0100" through "-1200" respectively; and "Z" is equivalent to "+0000". However, because of the error in [RFC822], they SHOULD all be considered equivalent to "-0000" unless there is out-of-band information confirming their meaning. Resnick Standards Track [Page 32] RFC 2822 Internet Message Format April 2001 Other multi-character (usually between 3 and 5) alphabetic time zones have been used in Internet messages. Any such time zone whose meaning is not known SHOULD be considered equivalent to "-0000" unless there is out-of-band information confirming their meaning. 4.4. Obsolete Addressing There are three primary differences in addressing. First, mailbox addresses were allowed to have a route portion before the addr-spec when enclosed in "<" and ">". The route is simply a comma-separated list of domain names, each preceded by "@", and the list terminated by a colon. Second, CFWS were allowed between the period-separated elements of local-part and domain (i.e., dot-atom was not used). In addition, local-part is allowed to contain quoted-string in addition to just atom. Finally, mailbox-list and address-list were allowed to have "null" members. That is, there could be two or more commas in such a list with nothing in between them. obs-angle-addr = [CFWS] "<" [obs-route] addr-spec ">" [CFWS] obs-route = [CFWS] obs-domain-list ":" [CFWS] obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain) obs-local-part = word *("." word) obs-domain = atom *("." atom) obs-mbox-list = 1*([mailbox] [CFWS] "," [CFWS]) [mailbox] obs-addr-list = 1*([address] [CFWS] "," [CFWS]) [address] When interpreting addresses, the route portion SHOULD be ignored. 4.5. Obsolete header fields Syntactically, the primary difference in the obsolete field syntax is that it allows multiple occurrences of any of the fields and they may occur in any order. Also, any amount of white space is allowed before the ":" at the end of the field name. obs-fields = *(obs-return / obs-received / obs-orig-date / obs-from / obs-sender / obs-reply-to / obs-to / Resnick Standards Track [Page 33] RFC 2822 Internet Message Format April 2001 obs-cc / obs-bcc / obs-message-id / obs-in-reply-to / obs-references / obs-subject / obs-comments / obs-keywords / obs-resent-date / obs-resent-from / obs-resent-send / obs-resent-rply / obs-resent-to / obs-resent-cc / obs-resent-bcc / obs-resent-mid / obs-optional) Except for destination address fields (described in section 4.5.3), the interpretation of multiple occurrences of fields is unspecified. Also, the interpretation of trace fields and resent fields which do not occur in blocks prepended to the message is unspecified as well. Unless otherwise noted in the following sections, interpretation of other fields is identical to the interpretation of their non-obsolete counterparts in section 3. 4.5.1. Obsolete origination date field obs-orig-date = "Date" *WSP ":" date-time CRLF 4.5.2. Obsolete originator fields obs-from = "From" *WSP ":" mailbox-list CRLF obs-sender = "Sender" *WSP ":" mailbox CRLF obs-reply-to = "Reply-To" *WSP ":" mailbox-list CRLF 4.5.3. Obsolete destination address fields obs-to = "To" *WSP ":" address-list CRLF obs-cc = "Cc" *WSP ":" address-list CRLF obs-bcc = "Bcc" *WSP ":" (address-list / [CFWS]) CRLF Resnick Standards Track [Page 34] RFC 2822 Internet Message Format April 2001 When multiple occurrences of destination address fields occur in a message, they SHOULD be treated as if the address-list in the first occurrence of the field is combined with the address lists of the subsequent occurrences by adding a comma and concatenating. 4.5.4. Obsolete identification fields The obsolete "In-Reply-To:" and "References:" fields differ from the current syntax in that they allow phrase (words or quoted strings) to appear. The obsolete forms of the left and right sides of msg-id allow interspersed CFWS, making them syntactically identical to local-part and domain respectively. obs-message-id = "Message-ID" *WSP ":" msg-id CRLF obs-in-reply-to = "In-Reply-To" *WSP ":" *(phrase / msg-id) CRLF obs-references = "References" *WSP ":" *(phrase / msg-id) CRLF obs-id-left = local-part obs-id-right = domain For purposes of interpretation, the phrases in the "In-Reply-To:" and "References:" fields are ignored. Semantically, none of the optional CFWS surrounding the local-part and the domain are part of the obs-id-left and obs-id-right respectively. 4.5.5. Obsolete informational fields obs-subject = "Subject" *WSP ":" unstructured CRLF obs-comments = "Comments" *WSP ":" unstructured CRLF obs-keywords = "Keywords" *WSP ":" obs-phrase-list CRLF 4.5.6. Obsolete resent fields The obsolete syntax adds a "Resent-Reply-To:" field, which consists of the field name, the optional comments and folding white space, the colon, and a comma separated list of addresses. obs-resent-from = "Resent-From" *WSP ":" mailbox-list CRLF obs-resent-send = "Resent-Sender" *WSP ":" mailbox CRLF Resnick Standards Track [Page 35] RFC 2822 Internet Message Format April 2001 obs-resent-date = "Resent-Date" *WSP ":" date-time CRLF obs-resent-to = "Resent-To" *WSP ":" address-list CRLF obs-resent-cc = "Resent-Cc" *WSP ":" address-list CRLF obs-resent-bcc = "Resent-Bcc" *WSP ":" (address-list / [CFWS]) CRLF obs-resent-mid = "Resent-Message-ID" *WSP ":" msg-id CRLF obs-resent-rply = "Resent-Reply-To" *WSP ":" address-list CRLF As with other resent fields, the "Resent-Reply-To:" field is to be treated as trace information only. 4.5.7. Obsolete trace fields The obs-return and obs-received are again given here as template definitions, just as return and received are in section 3. Their full syntax is given in [RFC2821]. obs-return = "Return-Path" *WSP ":" path CRLF obs-received = "Received" *WSP ":" name-val-list CRLF obs-path = obs-angle-addr 4.5.8. Obsolete optional fields obs-optional = field-name *WSP ":" unstructured CRLF 5. Security Considerations Care needs to be taken when displaying messages on a terminal or terminal emulator. Powerful terminals may act on escape sequences and other combinations of ASCII control characters with a variety of consequences. They can remap the keyboard or permit other modifications to the terminal which could lead to denial of service or even damaged data. They can trigger (sometimes programmable) answerback messages which can allow a message to cause commands to be issued on the recipient's behalf. They can also effect the operation of terminal attached devices such as printers. Message viewers may wish to strip potentially dangerous terminal escape sequences from the message prior to display. However, other escape sequences appear in messages for useful purposes (cf. [RFC2045, RFC2046, RFC2047, RFC2048, RFC2049, ISO2022]) and therefore should not be stripped indiscriminately. Resnick Standards Track [Page 36] RFC 2822 Internet Message Format April 2001 Transmission of non-text objects in messages raises additional security issues. These issues are discussed in [RFC2045, RFC2046, RFC2047, RFC2048, RFC2049]. Many implementations use the "Bcc:" (blind carbon copy) field described in section 3.6.3 to facilitate sending messages to recipients without revealing the addresses of one or more of the addressees to the other recipients. Mishandling this use of "Bcc:" has implications for confidential information that might be revealed, which could eventually lead to security problems through knowledge of even the existence of a particular mail address. For example, if using the first method described in section 3.6.3, where the "Bcc:" line is removed from the message, blind recipients have no explicit indication that they have been sent a blind copy, except insofar as their address does not appear in the message header. Because of this, one of the blind addressees could potentially send a reply to all of the shown recipients and accidentally reveal that the message went to the blind recipient. When the second method from section 3.6.3 is used, the blind recipient's address appears in the "Bcc:" field of a separate copy of the message. If the "Bcc:" field sent contains all of the blind addressees, all of the "Bcc:" recipients will be seen by each "Bcc:" recipient. Even if a separate message is sent to each "Bcc:" recipient with only the individual's address, implementations still need to be careful to process replies to the message as per section 3.6.3 so as not to accidentally reveal the blind recipient to other recipients. 6. Bibliography [ASCII] American National Standards Institute (ANSI), Coded Character Set - 7-Bit American National Standard Code for Information Interchange, ANSI X3.4, 1986. [ISO2022] International Organization for Standardization (ISO), Information processing - ISO 7-bit and 8-bit coded character sets - Code extension techniques, Third edition - 1986-05-01, ISO 2022, 1986. [RFC822] Crocker, D., "Standard for the Format of ARPA Internet Text Messages", RFC 822, August 1982. [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. Resnick Standards Track [Page 37] RFC 2822 Internet Message Format April 2001 [RFC2047] Moore, K., "Multipurpose Internet Mail Extensions (MIME) Part Three: Message Header Extensions for Non-ASCII Text", RFC 2047, November 1996. [RFC2048] Freed, N., Klensin, J. and J. Postel, "Multipurpose Internet Mail Extensions (MIME) Part Four: Format of Internet Message Bodies", RFC 2048, November 1996. [RFC2049] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples", RFC 2049, November 1996. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2234] Crocker, D., Editor, and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997. [RFC2821] Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC 2821, March 2001. [STD3] Braden, R., "Host Requirements", STD 3, RFC 1122 and RFC 1123, October 1989. [STD12] Mills, D., "Network Time Protocol", STD 12, RFC 1119, September 1989. [STD13] Mockapetris, P., "Domain Name System", STD 13, RFC 1034 and RFC 1035, November 1987. [STD14] Partridge, C., "Mail Routing and the Domain System", STD 14, RFC 974, January 1986. 7. Editor's Address Peter W. Resnick QUALCOMM Incorporated 5775 Morehouse Drive San Diego, CA 92121-1714 USA Phone: +1 858 651 4478 Fax: +1 858 651 1102 EMail: presnick@qualcomm.com Resnick Standards Track [Page 38] RFC 2822 Internet Message Format April 2001 8. Acknowledgements Many people contributed to this document. They included folks who participated in the Detailed Revision and Update of Messaging Standards (DRUMS) Working Group of the Internet Engineering Task Force (IETF), the chair of DRUMS, the Area Directors of the IETF, and people who simply sent their comments in via e-mail. The editor is deeply indebted to them all and thanks them sincerely. The below list includes everyone who sent e-mail concerning this document. Hopefully, everyone who contributed is named here: Matti Aarnio Barry Finkel Larry Masinter Tanaka Akira Erik Forsberg Denis McKeon Russ Allbery Chuck Foster William P McQuillan Eric Allman Paul Fox Alexey Melnikov Harald Tveit Alvestrand Klaus M. Frank Perry E. Metzger Ran Atkinson Ned Freed Steven Miller Jos Backus Jochen Friedrich Keith Moore Bruce Balden Randall C. Gellens John Gardiner Myers Dave Barr Sukvinder Singh Gill Chris Newman Alan Barrett Tim Goodwin John W. Noerenberg John Beck Philip Guenther Eric Norman J. Robert von Behren Tony Hansen Mike O'Dell Jos den Bekker John Hawkinson Larry Osterman D. J. Bernstein Philip Hazel Paul Overell James Berriman Kai Henningsen Jacob Palme Norbert Bollow Robert Herriot Michael A. Patton Raj Bose Paul Hethmon Uzi Paz Antony Bowesman Jim Hill Michael A. Quinlan Scott Bradner Paul E. Hoffman Eric S. Raymond Randy Bush Steve Hole Sam Roberts Tom Byrer Kari Hurtta Hugh Sasse Bruce Campbell Marco S. Hyman Bart Schaefer Larry Campbell Ofer Inbar Tom Scola W. J. Carpenter Olle Jarnefors Wolfgang Segmuller Michael Chapman Kevin Johnson Nick Shelness Richard Clayton Sudish Joseph John Stanley Maurizio Codogno Maynard Kang Einar Stefferud Jim Conklin Prabhat Keni Jeff Stephenson R. Kelley Cook John C. Klensin Bernard Stern Steve Coya Graham Klyne Peter Sylvester Mark Crispin Brad Knowles Mark Symons Dave Crocker Shuhei Kobayashi Eric Thomas Matt Curtin Peter Koch Lee Thompson Michael D'Errico Dan Kohn Karel De Vriendt Cyrus Daboo Christian Kuhtz Matthew Wall Jutta Degener Anand Kumria Rolf Weber Mark Delany Steen Larsen Brent B. Welch Resnick Standards Track [Page 39] RFC 2822 Internet Message Format April 2001 Steve Dorner Eliot Lear Dan Wing Harold A. Driscoll Barry Leiba Jack De Winter Michael Elkins Jay Levitt Gregory J. Woodhouse Robert Elz Lars-Johan Liman Greg A. Woods Johnny Eriksson Charles Lindsey Kazu Yamamoto Erik E. Fair Pete Loshin Alain Zahm Roger Fajman Simon Lyall Jamie Zawinski Patrik Faltstrom Bill Manning Timothy S. Zurcher Claus Andre Farber John Martin Resnick Standards Track [Page 40] RFC 2822 Internet Message Format April 2001 Appendix A. Example messages This section presents a selection of messages. These are intended to assist in the implementation of this standard, but should not be taken as normative; that is to say, although the examples in this section were carefully reviewed, if there happens to be a conflict between these examples and the syntax described in sections 3 and 4 of this document, the syntax in those sections is to be taken as correct. Messages are delimited in this section between lines of "----". The "----" lines are not part of the message itself. A.1. Addressing examples The following are examples of messages that might be sent between two individuals. A.1.1. A message from one person to another with simple addressing This could be called a canonical message. It has a single author, John Doe, a single recipient, Mary Smith, a subject, the date, a message identifier, and a textual message in the body. ---- From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- Resnick Standards Track [Page 41] RFC 2822 Internet Message Format April 2001 If John's secretary Michael actually sent the message, though John was the author and replies to this message should go back to him, the sender field would be used: ---- From: John Doe Sender: Michael Jones To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- A.1.2. Different types of mailboxes This message includes multiple addresses in the destination fields and also uses several different forms of addresses. ---- From: "Joe Q. Public" To: Mary Smith , jdoe@example.org, Who? Cc: , "Giant; \"Big\" Box" Date: Tue, 1 Jul 2003 10:52:37 +0200 Message-ID: <5678.21-Nov-1997@example.com> Hi everyone. ---- Note that the display names for Joe Q. Public and Giant; "Big" Box needed to be enclosed in double-quotes because the former contains the period and the latter contains both semicolon and double-quote characters (the double-quote characters appearing as quoted-pair construct). Conversely, the display name for Who? could appear without them because the question mark is legal in an atom. Notice also that jdoe@example.org and boss@nil.test have no display names associated with them at all, and jdoe@example.org uses the simpler address form without the angle brackets. Resnick Standards Track [Page 42] RFC 2822 Internet Message Format April 2001 A.1.3. Group addresses ---- From: Pete To: A Group:Chris Jones ,joe@where.test,John ; Cc: Undisclosed recipients:; Date: Thu, 13 Feb 1969 23:32:54 -0330 Message-ID: Testing. ---- In this message, the "To:" field has a single group recipient named A Group which contains 3 addresses, and a "Cc:" field with an empty group recipient named Undisclosed recipients. A.2. Reply messages The following is a series of three messages that make up a conversation thread between John and Mary. John firsts sends a message to Mary, Mary then replies to John's message, and then John replies to Mary's reply message. Note especially the "Message-ID:", "References:", and "In-Reply-To:" fields in each message. ---- From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- Resnick Standards Track [Page 43] RFC 2822 Internet Message Format April 2001 When sending replies, the Subject field is often retained, though prepended with "Re: " as described in section 3.6.5. ---- From: Mary Smith To: John Doe Reply-To: "Mary Smith: Personal Account" Subject: Re: Saying Hello Date: Fri, 21 Nov 1997 10:01:10 -0600 Message-ID: <3456@example.net> In-Reply-To: <1234@local.machine.example> References: <1234@local.machine.example> This is a reply to your hello. ---- Note the "Reply-To:" field in the above message. When John replies to Mary's message above, the reply should go to the address in the "Reply-To:" field instead of the address in the "From:" field. ---- To: "Mary Smith: Personal Account" From: John Doe Subject: Re: Saying Hello Date: Fri, 21 Nov 1997 11:00:00 -0600 Message-ID: In-Reply-To: <3456@example.net> References: <1234@local.machine.example> <3456@example.net> This is a reply to your reply. ---- A.3. Resent messages Start with the message that has been used as an example several times: ---- From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- Resnick Standards Track [Page 44] RFC 2822 Internet Message Format April 2001 Say that Mary, upon receiving this message, wishes to send a copy of the message to Jane such that (a) the message would appear to have come straight from John; (b) if Jane replies to the message, the reply should go back to John; and (c) all of the original information, like the date the message was originally sent to Mary, the message identifier, and the original addressee, is preserved. In this case, resent fields are prepended to the message: ---- Resent-From: Mary Smith Resent-To: Jane Brown Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800 Resent-Message-ID: <78910@example.net> From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- If Jane, in turn, wished to resend this message to another person, she would prepend her own set of resent header fields to the above and send that. Resnick Standards Track [Page 45] RFC 2822 Internet Message Format April 2001 A.4. Messages with trace fields As messages are sent through the transport system as described in [RFC2821], trace fields are prepended to the message. The following is an example of what those trace fields might look like. Note that there is some folding white space in the first one since these lines can be long. ---- Received: from x.y.test by example.net via TCP with ESMTP id ABC12345 for ; 21 Nov 1997 10:05:43 -0600 Received: from machine.example by x.y.test; 21 Nov 1997 10:01:22 -0600 From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- Resnick Standards Track [Page 46] RFC 2822 Internet Message Format April 2001 A.5. White space, comments, and other oddities White space, including folding white space, and comments can be inserted between many of the tokens of fields. Taking the example from A.1.3, white space and comments can be inserted into all of the fields. ---- From: Pete(A wonderful \) chap) To:A Group(Some people) :Chris Jones , joe@example.org, John (my dear friend); (the end of the group) Cc:(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ; Date: Thu, 13 Feb 1969 23:32 -0330 (Newfoundland Time) Message-ID: Testing. ---- The above example is aesthetically displeasing, but perfectly legal. Note particularly (1) the comments in the "From:" field (including one that has a ")" character appearing as part of a quoted-pair); (2) the white space absent after the ":" in the "To:" field as well as the comment and folding white space after the group name, the special character (".") in the comment in Chris Jones's address, and the folding white space before and after "joe@example.org,"; (3) the multiple and nested comments in the "Cc:" field as well as the comment immediately following the ":" after "Cc"; (4) the folding white space (but no comments except at the end) and the missing seconds in the time of the date field; and (5) the white space before (but not within) the identifier in the "Message-ID:" field. A.6. Obsoleted forms The following are examples of obsolete (that is, the "MUST NOT generate") syntactic elements described in section 4 of this document. Resnick Standards Track [Page 47] RFC 2822 Internet Message Format April 2001 A.6.1. Obsolete addressing Note in the below example the lack of quotes around Joe Q. Public, the route that appears in the address for Mary Smith, the two commas that appear in the "To:" field, and the spaces that appear around the "." in the jdoe address. ---- From: Joe Q. Public To: Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example Date: Tue, 1 Jul 2003 10:52:37 +0200 Message-ID: <5678.21-Nov-1997@example.com> Hi everyone. ---- A.6.2. Obsolete dates The following message uses an obsolete date format, including a non- numeric time zone and a two digit year. Note that although the day-of-week is missing, that is not specific to the obsolete syntax; it is optional in the current syntax as well. ---- From: John Doe To: Mary Smith Subject: Saying Hello Date: 21 Nov 97 09:55:06 GMT Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". ---- A.6.3. Obsolete white space and comments White space and comments can appear between many more elements than in the current syntax. Also, folding lines that are made up entirely of white space are legal. Resnick Standards Track [Page 48] RFC 2822 Internet Message Format April 2001 ---- From : John Doe To : Mary Smith __ Subject : Saying Hello Date : Fri, 21 Nov 1997 09(comment): 55 : 06 -0600 Message-ID : <1234 @ local(blah) .machine .example> This is a message just to say hello. So, "Hello". ---- Note especially the second line of the "To:" field. It starts with two space characters. (Note that "__" represent blank spaces.) Therefore, it is considered part of the folding as described in section 4.2. Also, the comments and white space throughout addresses, dates, and message identifiers are all part of the obsolete syntax. Appendix B. Differences from earlier standards This appendix contains a list of changes that have been made in the Internet Message Format from earlier standards, specifically [RFC822] and [STD3]. Items marked with an asterisk (*) below are items which appear in section 4 of this document and therefore can no longer be generated. 1. Period allowed in obsolete form of phrase. 2. ABNF moved out of document to [RFC2234]. 3. Four or more digits allowed for year. 4. Header field ordering (and lack thereof) made explicit. 5. Encrypted header field removed. 6. Received syntax loosened to allow any token/value pair. 7. Specifically allow and give meaning to "-0000" time zone. 8. Folding white space is not allowed between every token. 9. Requirement for destinations removed. 10. Forwarding and resending redefined. 11. Extension header fields no longer specifically called out. 12. ASCII 0 (null) removed.* 13. Folding continuation lines cannot contain only white space.* 14. Free insertion of comments not allowed in date.* 15. Non-numeric time zones not allowed.* 16. Two digit years not allowed.* 17. Three digit years interpreted, but not allowed for generation. 18. Routes in addresses not allowed.* 19. CFWS within local-parts and domains not allowed.* 20. Empty members of address lists not allowed.* Resnick Standards Track [Page 49] RFC 2822 Internet Message Format April 2001 21. Folding white space between field name and colon not allowed.* 22. Comments between field name and colon not allowed. 23. Tightened syntax of in-reply-to and references.* 24. CFWS within msg-id not allowed.* 25. Tightened semantics of resent fields as informational only. 26. Resent-Reply-To not allowed.* 27. No multiple occurrences of fields (except resent and received).* 28. Free CR and LF not allowed.* 29. Routes in return path not allowed.* 30. Line length limits specified. 31. Bcc more clearly specified. Appendix C. Notices Intellectual Property The IETF takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on the IETF's procedures with respect to rights in standards-track and standards-related documentation can be found in BCP-11. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification can be obtained from the IETF Secretariat. Resnick Standards Track [Page 50] RFC 2822 Internet Message Format April 2001 Full Copyright Statement Copyright (C) The Internet Society (2001). 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. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. Resnick Standards Track [Page 51] mail-2.5.4/reference/rfc3462 Reporting of Mail System Administrative Messages.txt000066400000000000000000000304471214434061600273700ustar00rootroot00000000000000 Network Working Group G. Vaudreuil Request for Comments: 3462 Lucent Technologies Obsoletes: 1892 January 2003 Category: Standards Track The Multipart/Report Content Type for the Reporting of Mail System Administrative Messages 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 (2003). All Rights Reserved. Abstract The Multipart/Report Multipurpose Internet Mail Extensions (MIME) content-type is a general "family" or "container" type for electronic mail reports of any kind. Although this memo defines only the use of the Multipart/Report content-type with respect to delivery status reports, mail processing programs will benefit if a single content- type is used to for all kinds of reports. This document is part of a four document set describing the delivery status report service. This collection includes the Simple Mail Transfer Protocol (SMTP) extensions to request delivery status reports, a MIME content for the reporting of delivery reports, an enumeration of extended status codes, and a multipart container for the delivery report, the original message, and a human-friendly summary of the failure. Vaudreuil Standards Track [Page 1] RFC 3462 Multipart/Report January 2003 Table of Contents Document Conventions................................................2 1. The Multipart/Report Content Type................................2 2. The Text/RFC822-Headers..........................................4 3. Security Considerations..........................................4 4. Normative References.............................................5 Appendix A - Changes from RFC 1893..................................6 Author's Address....................................................6 Full Copyright Statement............................................7 Document Conventions 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 BCP 14, RFC 2119 [RFC2119]. 1. The Multipart/Report Content Type The Multipart/Report MIME content-type is a general "family" or "container" type for electronic mail reports of any kind. Although this memo defines only the use of the Multipart/Report content-type with respect to delivery status reports, mail processing programs will benefit if a single content-type is used to for all kinds of reports. The Multipart/Report content-type is defined as follows: MIME type name: multipart MIME subtype name: report Required parameters: boundary, report-type Optional parameters: none Encoding considerations: 7bit should always be adequate Security considerations: see section 3 of this memo The syntax of Multipart/Report is identical to the Multipart/Mixed content type defined in [MIME]. When used to send a report, the Multipart/Report content-type must be the top-level MIME content type for any report message. The report-type parameter identifies the type of report. The parameter is the MIME content sub-type of the second body part of the Multipart/Report. User agents and gateways must be able to automatically determine that a message is a mail system report and should be processed as such. Placing the Multipart/Report as the outermost content provides a mechanism whereby an auto-processor may detect through parsing the RFC 822 headers that the message is a report. Vaudreuil Standards Track [Page 2] RFC 3462 Multipart/Report January 2003 The Multipart/Report content-type contains either two or three sub- parts, in the following order: 1) [Required] The first body part contains human readable message. The purpose of this message is to provide an easily understood description of the condition(s) that caused the report to be generated, for a human reader who may not have a user agent capable of interpreting the second section of the Multipart/Report. The text in the first section may be in any MIME standards-track content-type, charset, or language. Where a description of the error is desired in several languages or several media, a Multipart/Alternative construct may be used. This body part may also be used to send detailed information that cannot be easily formatted into a Message/Report body part. (2) [Required] A machine parsable body part containing an account of the reported message handling event. The purpose of this body part is to provide a machine-readable description of the condition(s) that caused the report to be generated, along with details not present in the first body part that may be useful to human experts. An initial body part, Message/delivery-status is defined in [DSN]. (3) [Optional] A body part containing the returned message or a portion thereof. This information may be useful to aid human experts in diagnosing problems. (Although it may also be useful to allow the sender to identify the message which the report was issued, it is hoped that the envelope-id and original-recipient-address returned in the Message/Report body part will replace the traditional use of the returned content for this purpose.) Return of content may be wasteful of network bandwidth and a variety of implementation strategies can be used. Generally the sender should choose the appropriate strategy and inform the recipient of the required level of returned content required. In the absence of an explicit request for level of return of content such as that provided in [DRPT], the agent that generated the delivery service report should return the full message content. When 8-bit or binary data not encoded in a 7 bit form is to be returned, and the return path is not guaranteed to be 8-bit or binary capable, two options are available. The original message MAY be re- encoded into a legal 7-bit MIME message or the Text/RFC822-Headers content-type MAY be used to return only the original message headers. Vaudreuil Standards Track [Page 3] RFC 3462 Multipart/Report January 2003 2. The Text/RFC822-Headers content-type The Text/RFC822-Headers MIME content-type provides a mechanism to label and return only the RFC 822 headers of a failed message. These headers are not the complete message and should not be returned as a Message/RFC822. The returned headers are useful for identifying the failed message and for diagnostics based on the received lines. The Text/RFC822-Headers content-type is defined as follows: MIME type name: Text MIME subtype name: RFC822-Headers Required parameters: None Optional parameters: None Encoding considerations: 7 bit is sufficient for normal RFC822 headers, however, if the headers are broken and require encoding to make them legal 7 bit content, they may be encoded in quoted-printable. Security considerations: See section 3 of this memo. The Text/RFC822-Headers body part should contain all the RFC822 header lines from the message which caused the report. The RFC822 headers include all lines prior to the blank line in the message. They include the MIME-Version and MIME Content-Headers. 3. 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. A signature covering the entire multipart/report structure could be used to prevent such forgeries; such a signature scheme is, however, beyond the scope of this document. Vaudreuil Standards Track [Page 4] RFC 3462 Multipart/Report January 2003 4. Normative References [SMTP] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821, August 1982. [DSN] Moore, K., and G. Vaudreuil, "An Extensible Message Format for Delivery Status Notifications", RFC 3464, January 2003. [RFC822] Crocker, D., "Standard for the format of ARPA Internet Text Messages", STD 11, RFC 822, August 1982. [MIME] Borenstein, N. and N. Freed, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, November 1996. [DRPT] Moore, K., "SMTP Service Extension for Delivery Status Notifications", RFC 3461, January 2003. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. Vaudreuil Standards Track [Page 5] RFC 3462 Multipart/Report January 2003 Appendix A - Changes from RFC 1892 Changed Authors contact information Updated required standards boilerplate Edited the text to make it spell-checker and grammar checker compliant Author's Address Gregory M. Vaudreuil Lucent Technologies 7291 Williamson Rd Dallas Tx, 75214 Phone: +1 214 823 9325 EMail: GregV@ieee.org Vaudreuil Standards Track [Page 6] RFC 3462 Multipart/Report January 2003 Full Copyright Statement Copyright (C) The Internet Society (2003). 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. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. Vaudreuil Standards Track [Page 7] mail-2.5.4/reference/rfc3696 Checking and Transformation of Names.txt000066400000000000000000001151701214434061600250720ustar00rootroot00000000000000 INFORMATIONAL Errata Network Working Group J. Klensin Request for Comments: 3696 February 2004 Category: Informational Application Techniques for Checking and Transformation of Names Status of this Memo This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. Copyright Notice Copyright (C) The Internet Society (2004). All Rights Reserved. Abstract Many Internet applications have been designed to deduce top-level domains (or other domain name labels) from partial information. The introduction of new top-level domains, especially non-country-code ones, has exposed flaws in some of the methods used by these applications. These flaws make it more difficult, or impossible, for users of the applications to access the full Internet. This memo discusses some of the techniques that have been used and gives some guidance for minimizing their negative impact as the domain name environment evolves. This document draws summaries of the applicable rules together in one place and supplies references to the actual standards. Klensin Informational [Page 1] RFC 3696 Checking and Transformation of Names February 2004 Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 2. Restrictions on domain (DNS) names . . . . . . . . . . . . . . 3 3. Restrictions on email addresses . . . . . . . . . . . . . . . 5 4. URLs and URIs . . . . . . . . . . . . . . . . . . . . . . . . 7 4.1. URI syntax definitions and issues . . . . . . . . . . . 7 4.2. The HTTP URL . . . . . . . . . . . . . . . . . . . . . . 8 4.3. The MAILTO URL . . . . . . . . . . . . . . . . . . . . . 9 4.4. Guessing domain names in web contexts . . . . . . . . . 11 5. Implications of internationalization . . . . . . . . . . . . . 11 6. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 7. Security Considerations . . . . . . . . . . . . . . . . . . . 13 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 13 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 14 9.1. Normative References . . . . . . . . . . . . . . . . . . 14 9.2. Informative References . . . . . . . . . . . . . . . . . 15 10. Author's Address . . . . . . . . . . . . . . . . . . . . . . . 15 11. Full Copyright Statement . . . . . . . . . . . . . . . . . . . 16 1. Introduction Designers of user interfaces to Internet applications have often found it useful to examine user-provided values for validity before passing them to the Internet tools themselves. This type of test, most commonly involving syntax checks or application of other rules to domain names, email addresses, or "web addresses" (URLs or, occasionally, extended URI forms (see Section 4)) may enable better- quality diagnostics for the user than might be available from the protocol itself. Local validity tests on values are also thought to improve the efficiency of back-office processing programs and to reduce the load on the protocols themselves. Certainly, they are consistent with the well-established principle that it is better to detect errors as early as possible. The tests must, however, be made correctly or at least safely. If criteria are applied that do not match the protocols, users will be inconvenienced, addresses and sites will effectively become inaccessible to some groups, and business and communications opportunities will be lost. Experience in recent years indicates that syntax tests are often performed incorrectly and that tests for top-level domain names are applied using obsolete lists and conventions. We assume that most of these incorrect tests are the result of the inability to conveniently locate exact definitions for the criteria to be applied. This document draws summaries of the applicable rules together in one place and supplies references to the Klensin Informational [Page 2] RFC 3696 Checking and Transformation of Names February 2004 actual standards. It does not add anything to those standards; it merely draws the information together into a form that may be more accessible. Many experts on Internet protocols believe that tests and rules of these sorts should be avoided in applications and that the tests in the protocols and back-office systems should be relied on instead. Certainly implementations of the protocols cannot assume that the data passed to them will be valid. Unless the standards specify particular behavior, this document takes no position on whether or not the testing is desirable. It only identifies the correct tests to be made if tests are to be applied. The sections that follow discuss domain names, email addresses, and URLs. 2. Restrictions on domain (DNS) names The authoritative definitions of the format and syntax of domain names appear in RFCs 1035 [RFC1035], 1123 [RFC1123], and 2181 [RFC2181]. Any characters, or combination of bits (as octets), are permitted in DNS names. However, there is a preferred form that is required by most applications. This preferred form has been the only one permitted in the names of top-level domains, or TLDs. In general, it is also the only form permitted in most second-level names registered in TLDs, although some names that are normally not seen by users obey other rules. It derives from the original ARPANET rules for the naming of hosts (i.e., the "hostname" rule) and is perhaps better described as the "LDH rule", after the characters that it permits. The LDH rule, as updated, provides that the labels (words or strings separated by periods) that make up a domain name must consist of only the ASCII [ASCII] alphabetic and numeric characters, plus the hyphen. No other symbols or punctuation characters are permitted, nor is blank space. If the hyphen is used, it is not permitted to appear at either the beginning or end of a label. There is an additional rule that essentially requires that top-level domain names not be all- numeric. When it is necessary to express labels with non-character octets, or to embed periods within labels, there is a mechanism for keying them in that utilizes an escape sequence. RFC 1035 [RFC1035] should be consulted if that mechanism is needed (most common applications, including email and the Web, will generally not permit those escaped strings). A special encoding is now available for non-ASCII characters, see the brief discussion in Section 5. Klensin Informational [Page 3] RFC 3696 Checking and Transformation of Names February 2004 Most internet applications that reference other hosts or systems assume they will be supplied with "fully-qualified" domain names, i.e., ones that include all of the labels leading to the root, including the TLD name. Those fully-qualified domain names are then passed to either the domain name resolution protocol itself or to the remote systems. Consequently, purported DNS names to be used in applications and to locate resources generally must contain at least one period (".") character. Those that do not are either invalid or require the application to supply additional information. Of course, this principle does not apply when the purpose of the application is to process or query TLD names themselves. The DNS specification also permits a trailing period to be used to denote the root, e.g., "a.b.c" and "a.b.c." are equivalent, but the latter is more explicit and is required to be accepted by applications. This convention is especially important when a TLD name is being referred to directly. For example, while ".COM" has become the popular terminology for referring to that top-level domain, "COM." would be strictly and technically correct in talking about the DNS, since it shows that "COM" is a top-level domain name. There is a long history of applications moving beyond the "one or more periods" test in an attempt to verify that a valid TLD name is actually present. They have done this either by applying some heuristics to the form of the name or by consulting a local list of valid names. The historical heuristics are no longer effective. If one is to keep a local list, much more effort must be devoted to keeping it up-to-date than was the case several years ago. The heuristics were based on the observation that, since the DNS was first deployed, all top-level domain names were two, three, or four characters in length. All two-character names were associated with "country code" domains, with the specific labels (with a few early exceptions) drawn from the ISO list of codes for countries and similar entities [IS3166]. The three-letter names were "generic" TLDs, whose function was not country-specific, and there was exactly one four-letter TLD, the infrastructure domain "ARPA." [RFC1591]. However, these length-dependent rules were conventions, rather than anything on which the protocols depended. Before the mid-1990s, lists of valid top-level domain names changed infrequently. New country codes were gradually, and then more rapidly, added as the Internet expanded, but the list of generic domains did not change at all between the establishment of the "INT." domain in 1988 and ICANN's allocation of new generic TLDs in 2000. Some application developers responded by assuming that any two-letter domain name could be valid as a TLD, but the list of generic TLDs was fixed and could be kept locally and tested. Several of these assumptions changed as ICANN started to allocate new top-level Klensin Informational [Page 4] RFC 3696 Checking and Transformation of Names February 2004 domains: one two-letter domain that does not appear in the ISO 3166-1 table [ISO.3166.1988] was tentatively approved, and new domains were created with three, four, and even six letter codes. As of the first quarter of 2003, the list of valid, non-country, top-level domains was .AERO, .BIZ, .COM, .COOP, .EDU, .GOV, .INFO, .INT, .MIL, .MUSEUM, .NAME, .NET, .ORG, .PRO, and .ARPA. ICANN is expected to expand that list at regular intervals, so the list that appears here should not be used in testing. Instead, systems that filter by testing top-level domain names should regularly update their local tables of TLDs (both "generic" and country-code-related) by polling the list published by IANA [DomainList]. It is likely that the better strategy has now become to make the "at least one period" test, to verify LDH conformance (including verification that the apparent TLD name is not all-numeric), and then to use the DNS to determine domain name validity, rather than trying to maintain a local list of valid TLD names. A DNS label may be no more than 63 octets long. This is in the form actually stored; if a non-ASCII label is converted to encoded "punycode" form (see Section 5), the length of that form may restrict the number of actual characters (in the original character set) that can be accommodated. A complete, fully-qualified, domain name must not exceed 255 octets. Some additional mechanisms for guessing correct domain names when incomplete information is provided have been developed for use with the web and are discussed in Section 4.4. 3. Restrictions on email addresses Reference documents: RFC 2821 [RFC2821] and RFC 2822 [RFC2822] Contemporary email addresses consist of a "local part" separated from a "domain part" (a fully-qualified domain name) by an at-sign ("@"). The syntax of the domain part corresponds to that in the previous section. The concerns identified in that section about filtering and lists of names apply to the domain names used in an email context as well. The domain name can also be replaced by an IP address in square brackets, but that form is strongly discouraged except for testing and troubleshooting purposes. The local part may appear using the quoting conventions described below. The quoted forms are rarely used in practice, but are required for some legitimate purposes. Hence, they should not be rejected in filtering routines but, should instead be passed to the email system for evaluation by the destination host. Klensin Informational [Page 5] RFC 3696 Checking and Transformation of Names February 2004 The exact rule is that any ASCII character, including control characters, may appear quoted, or in a quoted string. When quoting is needed, the backslash character is used to quote the following character. For example Abc\@def@example.com is a valid form of an email address. Blank spaces may also appear, as in Fred\ Bloggs@example.com The backslash character may also be used to quote itself, e.g., Joe.\\Blow@example.com In addition to quoting using the backslash character, conventional double-quote characters may be used to surround strings. For example "Abc@def"@example.com "Fred Bloggs"@example.com are alternate forms of the first two examples above. These quoted forms are rarely recommended, and are uncommon in practice, but, as discussed above, must be supported by applications that are processing email addresses. In particular, the quoted forms often appear in the context of addresses associated with transitions from other systems and contexts; those transitional requirements do still arise and, since a system that accepts a user-provided email address cannot "know" whether that address is associated with a legacy system, the address forms must be accepted and passed into the email environment. Without quotes, local-parts may consist of any combination of alphabetic characters, digits, or any of the special characters ! # $ % & ' * + - / = ? ^ _ ` . { | } ~ period (".") may also appear, but may not be used to start or end the local part, nor may two or more consecutive periods appear. Stated differently, any ASCII graphic (printing) character other than the at-sign ("@"), backslash, double quote, comma, or square brackets may appear without quoting. If any of that list of excluded characters are to appear, they must be quoted. Forms such as user+mailbox@example.com Klensin Informational [Page 6] RFC 3696 Checking and Transformation of Names February 2004 customer/department=shipping@example.com $A12345@example.com !def!xyz%abc@example.com _somename@example.com are valid and are seen fairly regularly, but any of the characters listed above are permitted. In the context of local parts, apostrophe ("'") and acute accent ("`") are ordinary characters, not quoting characters. Some of the characters listed above are used in conventions about routing or other types of special handling by some receiving hosts. But, since there is no way to know whether the remote host is using those conventions or just treating these characters as normal text, sending programs (and programs evaluating address validity) must simply accept the strings and pass them on. In addition to restrictions on syntax, there is a length limit on email addresses. That limit is a maximum of 64 characters (octets) in the "local part" (before the "@") and a maximum of 255 characters (octets) in the domain part (after the "@") for a total length of 320 characters. Systems that handle email should be prepared to process addresses which are that long, even though they are rarely encountered. 4. URLs and URIs 4.1. URI syntax definitions and issues The syntax for URLs (Uniform Resource Locators) is specified in [RFC1738]. The syntax for the more general "URI" (Uniform Resource Identifier) is specified in [RFC2396]. The URI syntax is extremely general, with considerable variations permitted according to the type of "scheme" (e.g., "http", "ftp", "mailto") that is being used. While it is possible to use the general syntax rules of RFC 2396 to perform syntax checks, they are general enough --essentially only specifying the separation of the scheme name and "scheme specific part" with a colon (":") and excluding some characters that must be escaped if used-- to provide little significant filtering or validation power. The following characters are reserved in many URIs -- they must be used for either their URI-intended purpose or must be encoded. Some particular schemes may either broaden or relax these restrictions (see the following sections for URLs applicable to "web pages" and electronic mail), or apply them only to particular URI component parts. Klensin Informational [Page 7] RFC 3696 Checking and Transformation of Names February 2004 ; / ? : @ & = + $ , ? In addition, control characters, the space character, the double- quote (") character, and the following special characters < > # % are generally forbidden and must either be avoided or escaped, as discussed below. The colon after the scheme name, and the percent sign used to escape characters, are specifically reserved for those purposes, although ":" may also be used elsewhere in some schemes. When it is necessary to encode these, or other, characters, the method used is to replace it with a percent-sign ("%") followed by two hexidecimal digits representing its octet value. See section 2.4.1 of [RFC2396] for an exact definition. Unless it is used as a delimiter of the URI scheme itself, any character may optionally be encoded this way; systems that are testing URI syntax should be prepared for these encodings to appear in any component of the URI except the scheme name itself. A "generic URI" syntax is specified and is more restrictive, but using it to test URI strings requires that one know whether or not the particular scheme in use obeys that syntax. Consequently, applications that intend to check or validate URIs should normally identify the scheme name and then apply scheme-specific tests. The rules for two of those -- HTTP [RFC1738] and MAILTO [RFC2368] URLs -- are discussed below, but the author of an application which intends to make very precise checks, or to reject particular syntax rather than just warning the user, should consult the relevant scheme- definition documents for precise syntax and relationships. 4.2. The HTTP URL Absolute HTTP URLs consist of the scheme name, a host name (expressed as a domain name or IP address), and optional port number, and then, optionally, a path, a search part, and a fragment identifier. These are separated, respectively, by a colon and the two slashes that precede the host name, a colon, a slash, a question mark, and a hash mark ("#"). So we have http://host:port/path?search#fragment http://host/path/ http://host/path#fragment Klensin Informational [Page 8] RFC 3696 Checking and Transformation of Names February 2004 http://host/path?search http://host and other variations on that form. There is also a "relative" form, but it almost never appears in text that a user might, e.g., enter into a form. See [RFC2616] for details. The characters / ; ? are reserved within the path and search parts and must be encoded; the first of these may be used unencoded, and is often used within the path, to designate hierarchy. 4.3. The MAILTO URL MAILTO is a URL type whose content is an email address. It can be used to encode any of the email address formats discussed in Section 3 above. It can also support multiple addresses and the inclusion of headers (e.g., Subject lines) within the body of the URL. MAILTO is authoritatively defined in RFC 2368 [RFC2368]; anyone expecting to accept and test multiple addresses or mail header or body formats should consult that document carefully. In accepting text for, or validating, a MAILTO URL, it is important to note that, while it can be used to encode any valid email address, it is not sufficient to copy an email address into a MAILTO URL since email addresses may include a number of characters that are invalid in, or have reserved uses for, URLs. Those characters must be encoded, as outlined in Section 4.1 above, when the addresses are mapped into the URL form. Conversely, addresses in MAILTO URLs cannot, in general, be copied directly into email contexts, since few email programs will reverse the decodings (and doing so might be interpreted as a protocol violation). The following characters may appear in MAILTO URLs only with the specific defined meanings given. If they appear in an email address (i.e., for some other purpose), they must be encoded: : The colon in "mailto:" < > # " % { } | \ ^ ~ ` These characters are "unsafe" in any URL, and must always be encoded. Klensin Informational [Page 9] RFC 3696 Checking and Transformation of Names February 2004 The following characters must also be encoded if they appear in a MAILTO URL ? & = Used to delimit headers and their values when these are encoded into URLs. Some examples may be helpful: +-------------------------+-----------------------------+-----------+ | Email address | MAILTO URL | Notes | +-------------------------+-----------------------------+-----------+ | Joe@example.com | mailto:joe@example.com | 1 | | | | | | user+mailbox@example | mailto: | 2 | | .com | user%2Bmailbox@example | | | | .com | | | | | | | customer/department= | mailto:customer%2F | 3 | | shipping@example.com | department=shipping@example | | | | .com | | | | | | | $A12345@example.com | mailto:$A12345@example | 4 | | | .com | | | | | | | !def!xyz%abc@example | mailto:!def!xyz%25abc | 5 | | .com | @example.com | | | | | | | _somename@example.com | mailto:_somename@example | 4 | | | .com | | +-------------------------+-----------------------------+-----------+ Table 1 Notes on Table 1. No characters appear in the email address that require escaping, so the body of the MAILTO URL is identical to the email address. 2. There is actually some uncertainty as to whether or not the "+" characters requires escaping in MAILTO URLs (the standards are not precisely clear). But, since any character in the address specification may optionally be encoded, it is probably safer to encode it. 3. The "/" character is generally reserved in URLs, and must be encoded as %2F. Klensin Informational [Page 10] RFC 3696 Checking and Transformation of Names February 2004 4. Neither the "$" nor the "_" character are given any special interpretation in MAILTO URLs, so need not be encoded. 5. While the "!" character has no special interpretation, the "%" character is used to introduce encoded sequences and hence it must always be encoded. 4.4. Guessing domain names in web contexts Several web browsers have adopted a practice that permits an incomplete domain name to be used as input instead of a complete URL. This has, for example, permitted users to type "microsoft" and have the browser interpret the input as "http://www.microsoft.com/". Other browser versions have gone even further, trying to build DNS names up through a series of heuristics, testing each variation in turn to see if it appears in the DNS, and accepting the first one found as the intended domain name. Still, others automatically invoke search engines if no period appears or if the reference fails. If any of these approaches are to be used, it is often critical that the browser recognize the complete list of TLDs. If an incomplete list is used, complete domain names may not be recognized as such and the system may try to turn them into completely different names. For example, "example.aero" is a fully-qualified name, since "AERO." is a TLD name. But, if the system doesn't recognize "AERO" as a TLD name, it is likely to try to look up "example.aero.com" and "www.example.aero.com" (and then fail or find the wrong host), rather than simply looking up the user-supplied name. As discussed in Section 2 above, there are dangers associated with software that attempts to "know" the list of top-level domain names locally and take advantage of that knowledge. These name-guessing heuristics are another example of that situation: if the lists are up-to-date and used carefully, the systems in which they are embedded may provide an easier, and more attractive, experience for at least some users. But finding the wrong host, or being unable to find a host even when its name is precisely known, constitute bad experiences by any measure. More generally, there have been bad experiences with attempts to "complete" domain names by adding additional information to them. These issues are described in some detail in RFC 1535 [RFC1535]. 5. Implications of internationalization The IETF has adopted a series of proposals ([RFC3490] - [RFC3492]) whose purpose is to permit encoding internationalized (i.e., non- ASCII) names in the DNS. The primary standard, and the group generically, are known as "IDNA". The actual strings stored in the Klensin Informational [Page 11] RFC 3696 Checking and Transformation of Names February 2004 DNS are in an encoded form: the labels begin with the characters "xn--" followed by the encoded string. Applications should be prepared to accept and process the encoded form (those strings are consistent with the "LDH rule" (see Section 2) so should not raise any separate issues) and the use of local, and potentially other, characters as appropriate to local systems and circumstances. The IDNA specification describes the exact process to be used to validate a name or encoded string. The process is sufficiently complex that shortcuts or heuristics, especially for versions of labels written directly in Unicode or other coded character sets, are likely to fail and cause problems. In particular, the strings cannot be validated with syntax or semantic rules of any of the usual sorts: syntax validity is defined only in terms of the result of executing a particular function. In addition to the restrictions imposed by the protocols themselves, many domains are implementing rules about just which non-ASCII names they will permit to be registered (see, e.g., [JET], [RegRestr]). This work is still relatively new, and the rules and conventions are likely to be different for each domain, or at least each language or script group. Attempting to test for those rules in a client program to see if a user-supplied name might possibly exist in the relevant domain would almost certainly be ill-advised. One quick local test however, may be reasonable: as of the time of this writing, there should be no instances of labels in the DNS that start with two characters, followed by two hyphens, where the two characters are not "xn" (in, of course, either upper or lower case). Such label strings, if they appear, are probably erroneous or obsolete, and it may be reasonable to at least warn the user about them. There is ongoing work in the IETF and elsewhere to define internationalized formats for use in other protocols, including email addresses. Those forms may or may not conform to existing rules for ASCII-only identifiers; anyone designing evaluators or filters should watch that work closely. 6. Summary When an application accepts a string from the user and ultimately passes it on to an API for a protocol, the desirability of testing or filtering the text in any way not required by the protocol itself is hotly debated. If it must divide the string into its components, or otherwise interpret it, it obviously must make at least enough tests to validate that process. With, e.g., domain names or email addresses that can be passed on untouched, the appropriateness of Klensin Informational [Page 12] RFC 3696 Checking and Transformation of Names February 2004 trying to figure out which ones are valid and which ones are not requires a more complex decision, one that should include considerations of how to make exactly the correct tests and to keep information that changes and evolves up-to-date. A test containing obsolete information, can be extremely frustrating for potential correspondents or customers and may harm desired relationships. 7. Security Considerations Since this document merely summarizes the requirements of existing standards, it does not introduce any new security issues. However, many of the techniques that motivate the document raise important security concerns of their own. Rejecting valid forms of domain names, email addresses, or URIs often denies service to the user of those entities. Worse, guessing at the user's intent when an incomplete address, or other string, is given can result in compromises to privacy or accuracy of reference if the wrong target is found and returned. From a security standpoint, the optimum behavior is probably to never guess, but instead, to force the user to specify exactly what is wanted. When that position involves a tradeoff with an acceptable user experience, good judgment should be used and the fact that it is a tradeoff recognized. Some characters have special or privileged meanings on some systems (i.e., ` on Unix). Applications should be careful to escape those locally if necessary. By the same token, they are valid, and should not be disallowed locally, or escaped when transmitted through Internet protocols, for such reasons if a remote site chooses to use them. The presence of local checking does not permit remote checking to be bypassed. Note that this can apply to a single machine; in particular, a local MTA should not assume that a local MUA has properly escaped locally-significant special characters. 8. Acknowledgements The author would like to express his appreciation for helpful comments from Harald Alvestrand, Eric A. Hall, and the RFC Editor, and for partial support of this work from SITA. Responsibility for any errors remains, of course, with the author. The first Internet-Draft on this subject was posted in February 2003. The document was submitted to the RFC Editor on 20 June 2003, returned for revisions on 19 August, and resubmitted on 5 September 2003. Klensin Informational [Page 13] RFC 3696 Checking and Transformation of Names February 2004 9. References 9.1. Normative References [RFC1035] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987. [RFC1123] Braden, R., Ed., "Requirements for Internet Hosts - Application and Support", STD 3, RFC 1123, October 1989. [RFC1535] Gavron, E., "A Security Problem and Proposed Correction With Widely Deployed DNS Software", RFC 1535, October 1993. [RFC1738] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform Resource Locators (URL)", RFC 1738, December 1994. [RFC2181] Elz, R. and R. Bush, "Clarifications to the DNS Specification", RFC 2181, July 1997. [RFC2368] Hoffman, P., Masinter, L. and J. Zawinski, "The mailto URL scheme", RFC 2368, July 1998. [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998. [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999. [RFC2821] Klensin, J., Ed., "Simple Mail Transfer Protocol", RFC 2821, April 2001. [RFC2822] Resnick, P., Ed., "Internet Message Format", RFC 2822, April 2001. [RFC3490] Faltstrom, P., Hoffman, P. and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003. [RFC3491] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003. Klensin Informational [Page 14] RFC 3696 Checking and Transformation of Names February 2004 [RFC3492] Costello, A., "Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)", RFC 3492, March 2003. [ASCII] American National Standards Institute (formerly United States of America Standards Institute), "USA Code for Information Interchange", ANSI X3.4-1968. ANSI X3.4-1968 has been replaced by newer versions with slight modifications, but the 1968 version remains definitive for the Internet. [DomainList] Internet Assigned Numbers Authority (IANA), Untitled alphabetical list of current top-level domains. http://data.iana.org/TLD/tlds-alpha-by-domain.txt ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt 9.2. Informative References [ISO.3166.1988] International Organization for Standardization, "Codes for the representation of names of countries, 3rd edition", ISO Standard 3166, August 1988. [JET] Konishi, K., et al., "Internationalized Domain Names Registration and Administration Guideline for Chinese, Japanese and Korean", Work in Progress. [RFC1591] Postel, J., "Domain Name System Structure and Delegation", RFC 1591, March 1994. [RegRestr] Klensin, J., "Registration of Internationalized Domain Names: Overview and Method", Work in Progress, February 2004. 10. Author's Address John C Klensin 1770 Massachusetts Ave, #322 Cambridge, MA 02140 USA Phone: +1 617 491 5735 EMail: john-ietf@jck.com Klensin Informational [Page 15] RFC 3696 Checking and Transformation of Names February 2004 11. Full Copyright Statement Copyright (C) The Internet Society (2004). This document is subject to the rights, licenses and restrictions contained in BCP 78 and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM 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. Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. Klensin Informational [Page 16] Html markup produced by rfcmarkup 1.77, available from http://tools.ietf.org/tools/rfcmarkup/mail-2.5.4/reference/rfc4155 The application-mbox Media Type.txt000066400000000000000000000465071214434061600241030ustar00rootroot00000000000000 INFORMATIONAL Network Working Group E. Hall Request for Comments: 4155 September 2005 Category: Informational The application/mbox Media Type Status of This Memo This memo provides information for the Internet community. It does not specify an Internet standard of any kind. Distribution of this memo is unlimited. Copyright Notice Copyright (C) The Internet Society (2005). Abstract This memo requests that the application/mbox media type be authorized for allocation by the IESG, according to the terms specified in RFC 2048. This memo also defines a default format for the mbox database, which must be supported by all conformant implementations. 1. Background and Overview UNIX-like operating systems have historically made widespread use of "mbox" database files for a variety of local email purposes. In the common case, mbox files store linear sequences of one or more electronic mail messages, with local email clients treating the database as a logical folder of email messages. mbox databases are also used by a variety of other messaging tools, such as mailing list management programs, archiving and filtering utilities, messaging servers, and other related applications. In recent years, mbox databases have also become common on a large number of non-UNIX computing platforms, for similar kinds of purposes. The increased pervasiveness of these files has led to an increased demand for a standardized, network-wide interchange of these files as discrete database objects. In turn, this dictates a need for a general media type definition for mbox files, which is the subject and purpose of this memo. Hall Informational [Page 1] RFC 4155 The application/mbox Media Type September 2005 2. About the mbox Database The mbox database format is not documented in an authoritative specification, but instead exists as a well-known output format that is anecdotally documented, or which is only authoritatively documented for a specific platform or tool. mbox databases typically contain a linear sequence of electronic mail messages. Each message begins with a separator line that identifies the message sender, and also identifies the date and time at which the message was received by the final recipient (either the last-hop system in the transfer path, or the system which serves as the recipient's mailstore). Each message is typically terminated by an empty line. The end of the database is usually recognized by either the absence of any additional data, or by the presence of an explicit end-of-file marker. The structure of the separator lines vary across implementations, but usually contain the exact character sequence of "From", followed by a single Space character (0x20), an email address of some kind, another Space character, a timestamp sequence of some kind, and an end-of- line marker. However, due to the lack of any authoritative specification, each of these attributes are known to vary widely across implementations. For example, the email address can reflect any addressing syntax that has ever been used on any messaging system in all of history (specifically including address forms that are not compatible with Internet messages, as defined by RFC 2822 [RFC2822]). Similarly, the timestamp sequences can also vary according to system output, while the end-of-line sequences will often reflect platform- specific requirements. Different data formats can even appear within a single database as a result of multiple mbox files being concatenated together, or because a single file was accessed by multiple messaging clients, each of which has used its own syntax for the separator line. Message data within mbox databases often reflects site-specific peculiarities. For example, it is entirely possible for the message body or headers in an mbox database to contain untagged eight-bit character data that implicitly reflects a site-specific default language or locale, or that reflects local defaults for timestamps and email addresses; none of this data is widely portable beyond the local scope. Similarly, message data can also contain unencoded eight-bit binary data, or can use encoding formats that represent a specific platform (e.g., BINHEX or UUENCODE sequences). Hall Informational [Page 2] RFC 4155 The application/mbox Media Type September 2005 Many implementations are also known to escape message body lines that begin with the character sequence of "From ", so as to prevent confusion with overly-liberal parsers that do not search for full separator lines. In the common case, a leading Greater-Than symbol (0x3E) is used for this purpose (with "From " becoming ">From "). However, other implementations are known not to escape such lines unless they are immediately preceded by a blank line or if they also appear to contain an email address and a timestamp. Other implementations are also known to perform secondary escapes against these lines if they are already escaped or quoted, while others ignore these mechanisms altogether. A comprehensive description of mbox database files on UNIX-like systems can be found at http://qmail.org./man/man5/mbox.html, which should be treated as mostly authoritative for those variations that are otherwise only documented in anecdotal form. However, readers are advised that many other platforms and tools make use of mbox databases, and that there are many more potential variations that can be encountered in the wild. In order to mitigate errors that may arise from such vagaries, this specification defines a "format" parameter to the application/mbox media type declaration, which can be used to identify the specific kind of mbox database that is being transferred. Furthermore, this specification defines a "default" database format which MUST be supported by implementations that claim to be compliant with this specification, and which is to be used as the implicit format for undeclared application/mbox data objects. Additional format types are to be defined in subsequent specifications. Messaging systems that receive an mbox database with an unknown format parameter value SHOULD treat the data as an opaque binary object, as if the data had been declared as application/octet-stream Refer to Appendix A for a description of the default mbox format. Note that RFC 2046 [RFC2046] defines the multipart/digest media type for transferring platform-independent message files. Because that specification defines a set of neutral and strict formatting rules, the multipart/digest media type already facilitates highly- predictable transfer and conversion operations; as such, implementers are strongly encouraged to support and use that media type where possible. Hall Informational [Page 3] RFC 4155 The application/mbox Media Type September 2005 3. Prerequisites and Terminology Readers of this document are expected to be familiar with the specification for MIME [RFC2045] and MIME-type registrations [RFC2048]. 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 [RFC2119]. 4. The application/mbox Media Type Registration This section provides the media type registration application (as per [RFC2048]). MIME media type name: application MIME subtype name: mbox Required parameters: none Optional parameters: The "format" parameter identifies the format of the mbox database and the messages contained therein. The default value for the "format" parameter is "default", and refers to the formatting rules defined in Appendix A of this memo. mbox databases that do not have a "format" parameter SHOULD be interpreted as having the implicit "format" value of "default". mbox databases that have an unknown value for the "format" parameter SHOULD be treated as opaque data objects, as if the media type had been specified as application/octet-stream. Additional values for the format parameter are to be defined in subsequent specifications, and registered with IANA. Encoding considerations: If an email client receives an mbox database as a message attachment, and then stores that attachment within a local mbox database, the contents of the two database files may become irreversibly intermingled, such that both databases are rendered unrecognizable. In order to avoid these collisions, messaging systems that support this specification MUST encode an mbox database (or at a minimum, the separator lines) with non-transparent transfer encoding (such as BASE64 or Quoted-Printable) whenever an application/mbox object is transferred via messaging protocols. Other transfer services are generally encouraged to adopt similar encoding strategies in order to allow for any subsequent retransmission that might occur, but this is not a requirement. Implementers should also be prepared to encode mbox data locally if non-compliant data is received. Hall Informational [Page 4] RFC 4155 The application/mbox Media Type September 2005 Security considerations: mbox data is passive, and does not generally represent a unique or new security threat. However, there is risk in sharing any kind of data, because unintentional information may be exposed, and this risk certainly applies to mbox data as well. Interoperability considerations: Due to the lack of a single authoritative specification for mbox databases, there are a large number of variations between database formats (refer to the introduction text for common examples), and it is expected that non- conformant data will be erroneously tagged or exchanged. Although the "default" format specified in this memo does not allow for these kinds of vagaries, prior negotiation or agreement between humans may sometimes be needed. Published specification: see Appendix A. Applications that use this media type: hundreds of messaging products make use of the mbox database format, in one form or another. Magic number(s): mbox database files can be recognized by having a leading character sequence of "From", followed by a single Space character (0x20), followed by additional printable character data (refer to the description in Appendix A for details). However, implementers are cautioned that all such files will not be compliant with all of the formatting rules, therefore implementers should treat these files with an appropriate amount of circumspection. File extension(s): mbox database files sometimes have an ".mbox" extension, but this is not required nor expected. As with magic numbers, implementers should avoid reflexive assumptions about the contents of such files. Macintosh File Type Code(s): None are known to be common. Person & email address to contact for further information: Eric A. Hall (ehall@ntrg.com) Intended usage: COMMON 5. Security Considerations See the discussion in section 4. Hall Informational [Page 5] RFC 4155 The application/mbox Media Type September 2005 6. IANA Considerations The IANA has registered the application/mbox media type in the MIME registry, using the application provided in section 4 above. Furthermore, IANA has established and will maintain a registry of values for the "format" parameter as described in this memo. The first registration is the "default" value, using the description provided in Appendix A. Subsequent values for the "format" parameter MUST be accompanied by some form of recognizable, complete, and legitimate specification, such as an IESG-approved specification, or some kind of authoritative vendor documentation. 7. Normative 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. [RFC2048] Freed, N., Klensin, J., and J. Postel, "Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures", BCP 13, RFC 2048, November 1996. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC2822] Resnick, P., "Internet Message Format", RFC 2822, April 2001. Hall Informational [Page 6] RFC 4155 The application/mbox Media Type September 2005 Appendix A. The "default" mbox Database Format In order to improve interoperability among messaging systems, this memo defines a "default" mbox database format, which MUST be supported by all implementations that claim to be compliant with this specification. The "default" mbox database format uses a linear sequence of Internet messages, with each message being immediately prefaced by a separator line, and being terminated by an empty line. More specifically: o Each message within the database MUST follow the syntax and formatting rules defined in RFC 2822 [RFC2822] and its related specifications, with the exception that the canonical mbox database MUST use a single Line-Feed character (0x0A) as the end-of-line sequence, and MUST NOT use a Carriage-Return/Line- Feed pair (NB: this requirement only applies to the canonical mbox database as transferred, and does not override any other specifications). This usage represents the most common historical representation of the mbox database format, and allows for the least amount of conversion. o Messages within the default mbox database MUST consist of seven-bit characters within an eight-bit stream. Eight-bit data within the stream MUST be converted to a seven-bit form (using appropriate, standardized encoding) and appropriately tagged (with the correct header fields) before the database is transferred. o Message headers and data in the default mbox database MUST be fully-qualified, as per the relevant specification(s). For example, email addresses in the various header fields MUST have legitimate domain names (as per RFC 2822), while extended characters and encodings MUST be specified in the appropriate location (as per the appropriate MIME specifications), and so forth. o Each message in the mbox database MUST be immediately preceded by a single separator line, which MUST conform to the following syntax: The exact character sequence of "From"; a single Space character (0x20); the email address of the message sender (as obtained from the message envelope or other authoritative source), conformant with the "addr-spec" syntax from RFC 2822; Hall Informational [Page 7] RFC 4155 The application/mbox Media Type September 2005 a single Space character; a timestamp indicating the UTC date and time when the message was originally received, conformant with the syntax of the traditional UNIX 'ctime' output sans timezone (note that the use of UTC precludes the need for a timezone indicator); an end-of-line marker. o Each message in the database MUST be terminated by an empty line, containing a single end-of-line marker. Note that the first message in an mbox database will only be prefaced by a separator line, while every other message will begin with two end-of-line sequences (one at the end of the message itself, and another to mark the end of the message within the mbox database file stream) and a separator line (marking the new message). The end of the database is implicitly reached when no more message data or separator lines are found. Also note that this specification does not prescribe any escape syntax for message body lines that begin with the character sequence of "From ". Recipient systems are expected to parse full separator lines as they are documented above. Author's Address Eric A. Hall EMail: ehall@ntrg.com Hall Informational [Page 8] RFC 4155 The application/mbox Media Type September 2005 Full Copyright Statement Copyright (C) The Internet Society (2005). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM 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. Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. Hall Informational [Page 9] mail-2.5.4/reference/rfc4234 Augmented BNF for Syntax Specifications - ABNF.txt000066400000000000000000000633561214434061600262760ustar00rootroot00000000000000 Network Working Group D. Crocker, Ed. Request for Comments: 4234 Brandenburg InternetWorking Obsoletes: 2234 P. Overell Category: Standards Track THUS plc. October 2005 Augmented BNF for Syntax Specifications: ABNF 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 (2005). Abstract Internet technical specifications often need to define a formal syntax. Over the years, a modified version of Backus-Naur Form (BNF), called Augmented BNF (ABNF), has been popular among many Internet specifications. The current specification documents ABNF. It balances compactness and simplicity, with reasonable representational power. The differences between standard BNF and ABNF involve naming rules, repetition, alternatives, order- independence, and value ranges. This specification also supplies additional rule definitions and encoding for a core lexical analyzer of the type common to several Internet specifications. Crocker & Overell Standards Track [Page 1] RFC 4234 ABNF October 2005 Table of Contents 1. INTRODUCTION ....................................................2 2. RULE DEFINITION .................................................3 2.1. Rule Naming ................................................3 2.2. Rule Form ..................................................3 2.3. Terminal Values ............................................4 2.4. External Encodings .........................................5 3. OPERATORS .......................................................6 3.1. Concatenation: Rule1 Rule2 ................................6 3.2. Alternatives: Rule1 / Rule2 ...............................6 3.3. Incremental Alternatives: Rule1 =/ Rule2 ...................7 3.4. Value Range Alternatives: %c##-## .........................7 3.5. Sequence Group: (Rule1 Rule2) .............................8 3.6. Variable Repetition: *Rule ................................8 3.7. Specific Repetition: nRule ................................9 3.8. Optional Sequence: [RULE] .................................9 3.9. Comment: ; Comment ........................................9 3.10. Operator Precedence .......................................9 4. ABNF DEFINITION OF ABNF ........................................10 5. SECURITY CONSIDERATIONS ........................................11 6. References .....................................................11 6.1. Normative References ......................................11 6.2. Informative References ....................................11 Appendix A. ACKNOWLEDGEMENTS .....................................13 Appendix B. APPENDIX - CORE ABNF OF ABNF .........................13 B.1. Core Rules ...............................................13 B.2. Common Encoding ..........................................14 1. INTRODUCTION Internet technical specifications often need to define a formal syntax and are free to employ whatever notation their authors deem useful. Over the years, a modified version of Backus-Naur Form (BNF), called Augmented BNF (ABNF), has been popular among many Internet specifications. It balances compactness and simplicity, with reasonable representational power. In the early days of the Arpanet, each specification contained its own definition of ABNF. This included the email specifications, [RFC733] and then [RFC822], which came to be the common citations for defining ABNF. The current document separates those definitions to permit selective reference. Predictably, it also provides some modifications and enhancements. The differences between standard BNF and ABNF involve naming rules, repetition, alternatives, order-independence, and value ranges. Appendix B supplies rule definitions and encoding for a core lexical analyzer of the type common to several Internet specifications. It is provided as a convenience and is otherwise separate from the meta Crocker & Overell Standards Track [Page 2] RFC 4234 ABNF October 2005 language defined in the body of this document, and separate from its formal status. Changes since [RFC2234]: In Section 3.7, the phrase: "That is, exactly occurrences of ." was corrected to: "That is, exactly occurrences of ." Some continuation comment lines needed to be corrected to begin with comment character (";"). 2. RULE DEFINITION 2.1. Rule Naming The name of a rule is simply the name itself; that is, a sequence of characters, beginning with an alphabetic character, and followed by a combination of alphabetics, digits, and hyphens (dashes). NOTE: Rule names are case-insensitive The names , , , and all refer to the same rule. Unlike original BNF, angle brackets ("<", ">") are not required. However, angle brackets may be used around a rule name whenever their presence facilitates in discerning the use of a rule name. This is typically restricted to rule name references in free-form prose, or to distinguish partial rules that combine into a string not separated by white space, such as shown in the discussion about repetition, below. 2.2. Rule Form A rule is defined by the following sequence: name = elements crlf where is the name of the rule, is one or more rule names or terminal specifications, and is the end-of-line indicator (carriage return followed by line feed). The equal sign separates the name from the definition of the rule. The elements form a sequence of one or more rule names and/or value definitions, combined according to the various operators defined in this document, such as alternative and repetition. Crocker & Overell Standards Track [Page 3] RFC 4234 ABNF October 2005 For visual ease, rule definitions are left aligned. When a rule requires multiple lines, the continuation lines are indented. The left alignment and indentation are relative to the first lines of the ABNF rules and need not match the left margin of the document. 2.3. Terminal Values Rules resolve into a string of terminal values, sometimes called characters. In ABNF, a character is merely a non-negative integer. In certain contexts, a specific mapping (encoding) of values into a character set (such as ASCII) will be specified. Terminals are specified by one or more numeric characters, with the base interpretation of those characters indicated explicitly. The following bases are currently defined: b = binary d = decimal x = hexadecimal Hence: CR = %d13 CR = %x0D respectively specify the decimal and hexadecimal representation of [US-ASCII] for carriage return. A concatenated string of such values is specified compactly, using a period (".") to indicate a separation of characters within that value. Hence: CRLF = %d13.10 ABNF permits the specification of literal text strings directly, enclosed in quotation-marks. Hence: command = "command string" Literal text strings are interpreted as a concatenated set of printable characters. Crocker & Overell Standards Track [Page 4] RFC 4234 ABNF October 2005 NOTE: ABNF strings are case-insensitive and the character set for these strings is us-ascii. Hence: rulename = "abc" and: rulename = "aBc" will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC", and "ABC". To specify a rule that IS case SENSITIVE, specify the characters individually. For example: rulename = %d97 %d98 %d99 or rulename = %d97.98.99 will match only the string that comprises only the lowercased characters, abc. 2.4. External Encodings External representations of terminal value characters will vary according to constraints in the storage or transmission environment. Hence, the same ABNF-based grammar may have multiple external encodings, such as one for a 7-bit US-ASCII environment, another for a binary octet environment, and still a different one when 16-bit Unicode is used. Encoding details are beyond the scope of ABNF, although Appendix A (Core) provides definitions for a 7-bit US-ASCII environment as has been common to much of the Internet. By separating external encoding from the syntax, it is intended that alternate encoding environments can be used for the same syntax. Crocker & Overell Standards Track [Page 5] RFC 4234 ABNF October 2005 3. OPERATORS 3.1. Concatenation: Rule1 Rule2 A rule can define a simple, ordered string of values (i.e., a concatenation of contiguous characters) by listing a sequence of rule names. For example: foo = %x61 ; a bar = %x62 ; b mumble = foo bar foo So that the rule matches the lowercase string "aba". LINEAR WHITE SPACE: Concatenation is at the core of the ABNF parsing model. A string of contiguous characters (values) is parsed according to the rules defined in ABNF. For Internet specifications, there is some history of permitting linear white space (space and horizontal tab) to be freely and implicitly interspersed around major constructs, such as delimiting special characters or atomic strings. NOTE: This specification for ABNF does not provide for implicit specification of linear white space. Any grammar that wishes to permit linear white space around delimiters or string segments must specify it explicitly. It is often useful to provide for such white space in "core" rules that are then used variously among higher-level rules. The "core" rules might be formed into a lexical analyzer or simply be part of the main ruleset. 3.2. Alternatives: Rule1 / Rule2 Elements separated by a forward slash ("/") are alternatives. Therefore, foo / bar will accept or . Crocker & Overell Standards Track [Page 6] RFC 4234 ABNF October 2005 NOTE: A quoted string containing alphabetic characters is a special form for specifying alternative characters and is interpreted as a non-terminal representing the set of combinatorial strings with the contained characters, in the specified order but with any mixture of upper and lower case. 3.3. Incremental Alternatives: Rule1 =/ Rule2 It is sometimes convenient to specify a list of alternatives in fragments. That is, an initial rule may match one or more alternatives, with later rule definitions adding to the set of alternatives. This is particularly useful for otherwise, independent specifications that derive from the same parent rule set, such as often occurs with parameter lists. ABNF permits this incremental definition through the construct: oldrule =/ additional-alternatives So that the rule set ruleset = alt1 / alt2 ruleset =/ alt3 ruleset =/ alt4 / alt5 is the same as specifying ruleset = alt1 / alt2 / alt3 / alt4 / alt5 3.4. Value Range Alternatives: %c##-## A range of alternative numeric values can be specified compactly, using dash ("-") to indicate the range of alternative values. Hence: DIGIT = %x30-39 is equivalent to: DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" Concatenated numeric values and numeric value ranges cannot be specified in the same string. A numeric value may use the dotted notation for concatenation or it may use the dash notation to specify Crocker & Overell Standards Track [Page 7] RFC 4234 ABNF October 2005 one value range. Hence, to specify one printable character between end of line sequences, the specification could be: char-line = %x0D.0A %x20-7E %x0D.0A 3.5. Sequence Group: (Rule1 Rule2) Elements enclosed in parentheses are treated as a single element, whose contents are STRICTLY ORDERED. Thus, elem (foo / bar) blat matches (elem foo blat) or (elem bar blat), and elem foo / bar blat matches (elem foo) or (bar blat). NOTE: It is strongly advised that grouping notation be used, rather than relying on the proper reading of "bare" alternations, when alternatives consist of multiple rule names or literals. Hence, it is recommended that the following form be used: (elem foo) / (bar blat) It will avoid misinterpretation by casual readers. The sequence group notation is also used within free text to set off an element sequence from the prose. 3.6. Variable Repetition: *Rule The operator "*" preceding an element indicates repetition. The full form is: *element where and are optional decimal values, indicating at least and at most occurrences of the element. Default values are 0 and infinity so that * allows any number, including zero; 1* requires at least one; 3*3 allows exactly 3 and 1*2 allows one or two. Crocker & Overell Standards Track [Page 8] RFC 4234 ABNF October 2005 3.7. Specific Repetition: nRule A rule of the form: element is equivalent to *element That is, exactly occurrences of . Thus, 2DIGIT is a 2- digit number, and 3ALPHA is a string of three alphabetic characters. 3.8. Optional Sequence: [RULE] Square brackets enclose an optional element sequence: [foo bar] is equivalent to *1(foo bar). 3.9. Comment: ; Comment A semi-colon starts a comment that continues to the end of line. This is a simple way of including useful notes in parallel with the specifications. 3.10. Operator Precedence The various mechanisms described above have the following precedence, from highest (binding tightest) at the top, to lowest (loosest) at the bottom: Strings, Names formation Comment Value range Repetition Grouping, Optional Concatenation Alternative Crocker & Overell Standards Track [Page 9] RFC 4234 ABNF October 2005 Use of the alternative operator, freely mixed with concatenations, can be confusing. Again, it is recommended that the grouping operator be used to make explicit concatenation groups. 4. ABNF DEFINITION OF ABNF NOTES: 1. This syntax requires a formatting of rules that is relatively strict. Hence, the version of a ruleset included in a specification might need preprocessing to ensure that it can be interpreted by an ABNF parser. 2. This syntax uses the rules provided in Appendix B (Core). rulelist = 1*( rule / (*c-wsp c-nl) ) rule = rulename defined-as elements c-nl ; continues if next line starts ; with white space rulename = ALPHA *(ALPHA / DIGIT / "-") defined-as = *c-wsp ("=" / "=/") *c-wsp ; basic rules definition and ; incremental alternatives elements = alternation *c-wsp c-wsp = WSP / (c-nl WSP) c-nl = comment / CRLF ; comment or newline comment = ";" *(WSP / VCHAR) CRLF alternation = concatenation *(*c-wsp "/" *c-wsp concatenation) concatenation = repetition *(1*c-wsp repetition) repetition = [repeat] element repeat = 1*DIGIT / (*DIGIT "*" *DIGIT) Crocker & Overell Standards Track [Page 10] RFC 4234 ABNF October 2005 element = rulename / group / option / char-val / num-val / prose-val group = "(" *c-wsp alternation *c-wsp ")" option = "[" *c-wsp alternation *c-wsp "]" char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE ; quoted string of SP and VCHAR ; without DQUOTE num-val = "%" (bin-val / dec-val / hex-val) bin-val = "b" 1*BIT [ 1*("." 1*BIT) / ("-" 1*BIT) ] ; series of concatenated bit values ; or single ONEOF range dec-val = "d" 1*DIGIT [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ] hex-val = "x" 1*HEXDIG [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ] prose-val = "<" *(%x20-3D / %x3F-7E) ">" ; bracketed string of SP and VCHAR ; without angles ; prose description, to be used as ; last resort 5. SECURITY CONSIDERATIONS Security is truly believed to be irrelevant to this document. 6. References 6.1. Normative References [US-ASCII] American National Standards Institute, "Coded Character Set -- 7-bit American Standard Code for Information Interchange", ANSI X3.4, 1986. 6.2. Informative References [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997. Crocker & Overell Standards Track [Page 11] RFC 4234 ABNF October 2005 [RFC733] Crocker, D., Vittal, J., Pogran, K., and D. Henderson, "Standard for the format of ARPA network text messages", RFC 733, November 1977. [RFC822] Crocker, D., "Standard for the format of ARPA Internet text messages", STD 11, RFC 822, August 1982. Crocker & Overell Standards Track [Page 12] RFC 4234 ABNF October 2005 Appendix A. ACKNOWLEDGEMENTS The syntax for ABNF was originally specified in RFC 733. Ken L. Harrenstien, of SRI International, was responsible for re-coding the BNF into an augmented BNF that makes the representation smaller and easier to understand. This recent project began as a simple effort to cull out the portion of RFC 822 that has been repeatedly cited by non-email specification writers, namely the description of augmented BNF. Rather than simply and blindly converting the existing text into a separate document, the working group chose to give careful consideration to the deficiencies, as well as benefits, of the existing specification and related specifications made available over the last 15 years, and therefore to pursue enhancement. This turned the project into something rather more ambitious than was first intended. Interestingly, the result is not massively different from that original, although decisions, such as removing the list notation, came as a surprise. This "separated" version of the specification was part of the DRUMS working group, with significant contributions from Jerome Abela, Harald Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom Harsch, Dan Kohn, Bill McQuillan, Keith Moore, Chris Newman, Pete Resnick, and Henning Schulzrinne. Julian Reschke warrants a special thanks for converting the Draft Standard version to XML source form. Appendix B. APPENDIX - CORE ABNF OF ABNF This Appendix is provided as a convenient core for specific grammars. The definitions may be used as a core set of rules. B.1. Core Rules Certain basic rules are in uppercase, such as SP, HTAB, CRLF, DIGIT, ALPHA, etc. ALPHA = %x41-5A / %x61-7A ; A-Z / a-z BIT = "0" / "1" CHAR = %x01-7F ; any 7-bit US-ASCII character, ; excluding NUL Crocker & Overell Standards Track [Page 13] RFC 4234 ABNF October 2005 CR = %x0D ; carriage return CRLF = CR LF ; Internet standard newline CTL = %x00-1F / %x7F ; controls DIGIT = %x30-39 ; 0-9 DQUOTE = %x22 ; " (Double Quote) HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" HTAB = %x09 ; horizontal tab LF = %x0A ; linefeed LWSP = *(WSP / CRLF WSP) ; linear white space (past newline) OCTET = %x00-FF ; 8 bits of data SP = %x20 VCHAR = %x21-7E ; visible (printing) characters WSP = SP / HTAB ; white space B.2. Common Encoding Externally, data are represented as "network virtual ASCII" (namely, 7-bit US-ASCII in an 8-bit field), with the high (8th) bit set to zero. A string of values is in "network byte order", in which the higher-valued bytes are represented on the left-hand side and are sent over the network first. Crocker & Overell Standards Track [Page 14] RFC 4234 ABNF October 2005 Authors' Addresses Dave Crocker (editor) Brandenburg InternetWorking 675 Spruce Dr. Sunnyvale, CA 94086 US Phone: +1.408.246.8253 EMail: dcrocker@bbiw.net Paul Overell THUS plc. 1/2 Berkeley Square 99 Berkeley Street Glasgow G3 7HR UK EMail: paul.overell@thus.net Crocker & Overell Standards Track [Page 15] RFC 4234 ABNF October 2005 Full Copyright Statement Copyright (C) The Internet Society (2005). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM 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. Intellectual Property The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org. Acknowledgement Funding for the RFC Editor function is currently provided by the Internet Society. Crocker & Overell Standards Track [Page 16] mail-2.5.4/reference/rfc822 Standard for the Format of ARPA Internet Text Messages.txt000066400000000000000000003174721214434061600277310ustar00rootroot00000000000000 RFC # 822 Obsoletes: RFC #733 (NIC #41952) STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES August 13, 1982 Revised by David H. Crocker Dept. of Electrical Engineering University of Delaware, Newark, DE 19711 Network: DCrocker @ UDel-Relay Standard for ARPA Internet Text Messages TABLE OF CONTENTS PREFACE .................................................... ii 1. INTRODUCTION ........................................... 1 1.1. Scope ............................................ 1 1.2. Communication Framework .......................... 2 2. NOTATIONAL CONVENTIONS ................................. 3 3. LEXICAL ANALYSIS OF MESSAGES ........................... 5 3.1. General Description .............................. 5 3.2. Header Field Definitions ......................... 9 3.3. Lexical Tokens ................................... 10 3.4. Clarifications ................................... 11 4. MESSAGE SPECIFICATION .................................. 17 4.1. Syntax ........................................... 17 4.2. Forwarding ....................................... 19 4.3. Trace Fields ..................................... 20 4.4. Originator Fields ................................ 21 4.5. Receiver Fields .................................. 23 4.6. Reference Fields ................................. 23 4.7. Other Fields ..................................... 24 5. DATE AND TIME SPECIFICATION ............................ 26 5.1. Syntax ........................................... 26 5.2. Semantics ........................................ 26 6. ADDRESS SPECIFICATION .................................. 27 6.1. Syntax ........................................... 27 6.2. Semantics ........................................ 27 6.3. Reserved Address ................................. 33 7. BIBLIOGRAPHY ........................................... 34 APPENDIX A. EXAMPLES ............................................... 36 B. SIMPLE FIELD PARSING ................................... 40 C. DIFFERENCES FROM RFC #733 .............................. 41 D. ALPHABETICAL LISTING OF SYNTAX RULES ................... 44 August 13, 1982 - i - RFC #822 Standard for ARPA Internet Text Messages PREFACE By 1977, the Arpanet employed several informal standards for the text messages (mail) sent among its host computers. It was felt necessary to codify these practices and provide for those features that seemed imminent. The result of that effort was Request for Comments (RFC) #733, "Standard for the Format of ARPA Network Text Message", by Crocker, Vittal, Pogran, and Henderson. The specification attempted to avoid major changes in existing software, while permitting several new features. This document revises the specifications in RFC #733, in order to serve the needs of the larger and more complex ARPA Internet. Some of RFC #733's features failed to gain adequate acceptance. In order to simplify the standard and the software that follows it, these features have been removed. A different addressing scheme is used, to handle the case of inter-network mail; and the concept of re-transmission has been introduced. This specification is intended for use in the ARPA Internet. However, an attempt has been made to free it of any dependence on that environment, so that it can be applied to other network text message systems. The specification of RFC #733 took place over the course of one year, using the ARPANET mail environment, itself, to provide an on-going forum for discussing the capabilities to be included. More than twenty individuals, from across the country, partici- pated in the original discussion. The development of this revised specification has, similarly, utilized network mail-based group discussion. Both specification efforts greatly benefited from the comments and ideas of the participants. The syntax of the standard, in RFC #733, was originally specified in the Backus-Naur Form (BNF) meta-language. Ken L. Harrenstien, of SRI International, was responsible for re-coding the BNF into an augmented BNF that makes the representation smaller and easier to understand. August 13, 1982 - ii - RFC #822 Standard for ARPA Internet Text Messages 1. INTRODUCTION 1.1. SCOPE This standard specifies a syntax for text messages that are sent among computer users, within the framework of "electronic mail". The standard supersedes the one specified in ARPANET Request for Comments #733, "Standard for the Format of ARPA Net- work Text Messages". In this context, messages are viewed as having an envelope and contents. The envelope contains whatever information is needed to accomplish transmission and delivery. The contents compose the object to be delivered to the recipient. This stan- dard applies only to the format and some of the semantics of mes- sage contents. It contains no specification of the information in the envelope. However, some message systems may use information from the contents to create the envelope. It is intended that this stan- dard facilitate the acquisition of such information by programs. Some message systems may store messages in formats that differ from the one specified in this standard. This specifica- tion is intended strictly as a definition of what message content format is to be passed BETWEEN hosts. Note: This standard is NOT intended to dictate the internal for- mats used by sites, the specific message system features that they are expected to support, or any of the charac- teristics of user interface programs that create or read messages. A distinction should be made between what the specification REQUIRES and what it ALLOWS. Messages can be made complex and rich with formally-structured components of information or can be kept small and simple, with a minimum of such information. Also, the standard simplifies the interpretation of differing visual formats in messages; only the visual aspect of a message is affected and not the interpretation of information within it. Implementors may choose to retain such visual distinctions. The formal definition is divided into four levels. The bot- tom level describes the meta-notation used in this document. The second level describes basic lexical analyzers that feed tokens to higher-level parsers. Next is an overall specification for messages; it permits distinguishing individual fields. Finally, there is definition of the contents of several structured fields. August 13, 1982 - 1 - RFC #822 Standard for ARPA Internet Text Messages 1.2. COMMUNICATION FRAMEWORK Messages consist of lines of text. No special provisions are made for encoding drawings, facsimile, speech, or structured text. No significant consideration has been given to questions of data compression or to transmission and storage efficiency, and the standard tends to be free with the number of bits con- sumed. For example, field names are specified as free text, rather than special terse codes. A general "memo" framework is used. That is, a message con- sists of some information in a rigid format, followed by the main part of the message, with a format that is not specified in this document. The syntax of several fields of the rigidly-formated ("headers") section is defined in this specification; some of these fields must be included in all messages. The syntax that distinguishes between header fields is specified separately from the internal syntax for particular fields. This separation is intended to allow simple parsers to operate on the general structure of messages, without concern for the detailed structure of individual header fields. Appendix B is provided to facilitate construction of these parsers. In addition to the fields specified in this document, it is expected that other fields will gain common use. As necessary, the specifications for these "extension-fields" will be published through the same mechanism used to publish this document. Users may also wish to extend the set of fields that they use privately. Such "user-defined fields" are permitted. The framework severely constrains document tone and appear- ance and is primarily useful for most intra-organization communi- cations and well-structured inter-organization communication. It also can be used for some types of inter-process communica- tion, such as simple file transfer and remote job entry. A more robust framework might allow for multi-font, multi-color, multi- dimension encoding of information. A less robust one, as is present in most single-machine message systems, would more severely constrain the ability to add fields and the decision to include specific fields. In contrast with paper-based communica- tion, it is interesting to note that the RECEIVER of a message can exercise an extraordinary amount of control over the message's appearance. The amount of actual control available to message receivers is contingent upon the capabilities of their individual message systems. August 13, 1982 - 2 - RFC #822 Standard for ARPA Internet Text Messages 2. NOTATIONAL CONVENTIONS This specification uses an augmented Backus-Naur Form (BNF) notation. The differences from standard BNF involve naming rules and indicating repetition and "local" alternatives. 2.1. RULE NAMING Angle brackets ("<", ">") are not used, in general. The name of a rule is simply the name itself, rather than "". Quotation-marks enclose literal text (which may be upper and/or lower case). Certain basic rules are in uppercase, such as SPACE, TAB, CRLF, DIGIT, ALPHA, etc. Angle brackets are used in rule definitions, and in the rest of this document, whenever their presence will facilitate discerning the use of rule names. 2.2. RULE1 / RULE2: ALTERNATIVES Elements separated by slash ("/") are alternatives. There- fore "foo / bar" will accept foo or bar. 2.3. (RULE1 RULE2): LOCAL ALTERNATIVES Elements enclosed in parentheses are treated as a single element. Thus, "(elem (foo / bar) elem)" allows the token sequences "elem foo elem" and "elem bar elem". 2.4. *RULE: REPETITION The character "*" preceding an element indicates repetition. The full form is: *element indicating at least and at most occurrences of element. Default values are 0 and infinity so that "*(element)" allows any number, including zero; "1*element" requires at least one; and "1*2element" allows one or two. 2.5. [RULE]: OPTIONAL Square brackets enclose optional elements; "[foo bar]" is equivalent to "*1(foo bar)". 2.6. NRULE: SPECIFIC REPETITION "(element)" is equivalent to "*(element)"; that is, exactly occurrences of (element). Thus 2DIGIT is a 2-digit number, and 3ALPHA is a string of three alphabetic characters. August 13, 1982 - 3 - RFC #822 Standard for ARPA Internet Text Messages 2.7. #RULE: LISTS A construct "#" is defined, similar to "*", as follows: #element indicating at least and at most elements, each separated by one or more commas (","). This makes the usual form of lists very easy; a rule such as '(element *("," element))' can be shown as "1#element". Wherever this construct is used, null elements are allowed, but do not contribute to the count of elements present. That is, "(element),,(element)" is permitted, but counts as only two elements. Therefore, where at least one ele- ment is required, at least one non-null element must be present. Default values are 0 and infinity so that "#(element)" allows any number, including zero; "1#element" requires at least one; and "1#2element" allows one or two. 2.8. ; COMMENTS A semi-colon, set off some distance to the right of rule text, starts a comment that continues to the end of line. This is a simple way of including useful notes in parallel with the specifications. August 13, 1982 - 4 - RFC #822 Standard for ARPA Internet Text Messages 3. LEXICAL ANALYSIS OF MESSAGES 3.1. GENERAL DESCRIPTION A message consists of header fields and, optionally, a body. The body is simply a sequence of lines containing ASCII charac- ters. It is separated from the headers by a null line (i.e., a line with nothing preceding the CRLF). 3.1.1. LONG HEADER FIELDS Each header field can be viewed as a single, logical line of ASCII characters, comprising a field-name and a field-body. For convenience, the field-body portion of this conceptual entity can be split into a multiple-line representation; this is called "folding". The general rule is that wherever there may be linear-white-space (NOT simply LWSP-chars), a CRLF immediately followed by AT LEAST one LWSP-char may instead be inserted. Thus, the single line To: "Joe & J. Harvey" , JJV @ BBN can be represented as: To: "Joe & J. Harvey" , JJV@BBN and To: "Joe & J. Harvey" , JJV @BBN and To: "Joe & J. Harvey" , JJV @ BBN The process of moving from this folded multiple-line representation of a header field to its single line represen- tation is called "unfolding". Unfolding is accomplished by regarding CRLF immediately followed by a LWSP-char as equivalent to the LWSP-char. Note: While the standard permits folding wherever linear- white-space is permitted, it is recommended that struc- tured fields, such as those containing addresses, limit folding to higher-level syntactic breaks. For address fields, it is recommended that such folding occur August 13, 1982 - 5 - RFC #822 Standard for ARPA Internet Text Messages between addresses, after the separating comma. 3.1.2. STRUCTURE OF HEADER FIELDS Once a field has been unfolded, it may be viewed as being com- posed of a field-name followed by a colon (":"), followed by a field-body, and terminated by a carriage-return/line-feed. The field-name must be composed of printable ASCII characters (i.e., characters that have values between 33. and 126., decimal, except colon). The field-body may be composed of any ASCII characters, except CR or LF. (While CR and/or LF may be present in the actual text, they are removed by the action of unfolding the field.) Certain field-bodies of headers may be interpreted according to an internal syntax that some systems may wish to parse. These fields are called "structured fields". Examples include fields containing dates and addresses. Other fields, such as "Subject" and "Comments", are regarded simply as strings of text. Note: Any field which has a field-body that is defined as other than simply is to be treated as a struc- tured field. Field-names, unstructured field bodies and structured field bodies each are scanned by their own, independent "lexical" analyzers. 3.1.3. UNSTRUCTURED FIELD BODIES For some fields, such as "Subject" and "Comments", no struc- turing is assumed, and they are treated simply as s, as in the message body. Rules of folding apply to these fields, so that such field bodies which occupy several lines must therefore have the second and successive lines indented by at least one LWSP-char. 3.1.4. STRUCTURED FIELD BODIES To aid in the creation and reading of structured fields, the free insertion of linear-white-space (which permits folding by inclusion of CRLFs) is allowed between lexical tokens. Rather than obscuring the syntax specifications for these structured fields with explicit syntax for this linear-white- space, the existence of another "lexical" analyzer is assumed. This analyzer does not apply for unstructured field bodies that are simply strings of text, as described above. The analyzer provides an interpretation of the unfolded text August 13, 1982 - 6 - RFC #822 Standard for ARPA Internet Text Messages composing the body of the field as a sequence of lexical sym- bols. These symbols are: - individual special characters - quoted-strings - domain-literals - comments - atoms The first four of these symbols are self-delimiting. Atoms are not; they are delimited by the self-delimiting symbols and by linear-white-space. For the purposes of regenerating sequences of atoms and quoted-strings, exactly one SPACE is assumed to exist, and should be used, between them. (Also, in the "Clarifications" section on "White Space", below, note the rules about treatment of multiple contiguous LWSP-chars.) So, for example, the folded body of an address field ":sysmail"@ Some-Group. Some-Org, Muhammed.(I am the greatest) Ali @(the)Vegas.WBA August 13, 1982 - 7 - RFC #822 Standard for ARPA Internet Text Messages is analyzed into the following lexical symbols and types: :sysmail quoted string @ special Some-Group atom . special Some-Org atom , special Muhammed atom . special (I am the greatest) comment Ali atom @ atom (the) comment Vegas atom . special WBA atom The canonical representations for the data in these addresses are the following strings: ":sysmail"@Some-Group.Some-Org and Muhammed.Ali@Vegas.WBA Note: For purposes of display, and when passing such struc- tured information to other systems, such as mail proto- col services, there must be NO linear-white-space between s that are separated by period (".") or at-sign ("@") and exactly one SPACE between all other s. Also, headers should be in a folded form. August 13, 1982 - 8 - RFC #822 Standard for ARPA Internet Text Messages 3.2. HEADER FIELD DEFINITIONS These rules show a field meta-syntax, without regard for the particular type or internal syntax. Their purpose is to permit detection of fields; also, they present to higher-level parsers an image of each field as fitting on one line. field = field-name ":" [ field-body ] CRLF field-name = 1* field-body = field-body-contents [CRLF LWSP-char field-body] field-body-contents = August 13, 1982 - 9 - RFC #822 Standard for ARPA Internet Text Messages 3.3. LEXICAL TOKENS The following rules are used to define an underlying lexical analyzer, which feeds tokens to higher level parsers. See the ANSI references, in the Bibliography. ; ( Octal, Decimal.) CHAR = ; ( 0-177, 0.-127.) ALPHA = ; (101-132, 65.- 90.) ; (141-172, 97.-122.) DIGIT = ; ( 60- 71, 48.- 57.) CTL = ; ( 177, 127.) CR = ; ( 15, 13.) LF = ; ( 12, 10.) SPACE = ; ( 40, 32.) HTAB = ; ( 11, 9.) <"> = ; ( 42, 34.) CRLF = CR LF LWSP-char = SPACE / HTAB ; semantics = SPACE linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE ; CRLF => folding specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted- / "," / ";" / ":" / "\" / <"> ; string, to use / "." / "[" / "]" ; within a word. delimiters = specials / linear-white-space / comment text = atoms, specials, CR & bare LF, but NOT ; comments and including CRLF> ; quoted-strings are ; NOT recognized. atom = 1* quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or ; quoted chars. qtext = , ; => may be folded "\" & CR, and including linear-white-space> domain-literal = "[" *(dtext / quoted-pair) "]" August 13, 1982 - 10 - RFC #822 Standard for ARPA Internet Text Messages dtext = may be folded "]", "\" & CR, & including linear-white-space> comment = "(" *(ctext / quoted-pair / comment) ")" ctext = may be folded ")", "\" & CR, & including linear-white-space> quoted-pair = "\" CHAR ; may quote any char phrase = 1*word ; Sequence of words word = atom / quoted-string 3.4. CLARIFICATIONS 3.4.1. QUOTING Some characters are reserved for special interpretation, such as delimiting lexical tokens. To permit use of these charac- ters as uninterpreted data, a quoting mechanism is provided. To quote a character, precede it with a backslash ("\"). This mechanism is not fully general. Characters may be quoted only within a subset of the lexical constructs. In particu- lar, quoting is limited to use within: - quoted-string - domain-literal - comment Within these constructs, quoting is REQUIRED for CR and "\" and for the character(s) that delimit the token (e.g., "(" and ")" for a comment). However, quoting is PERMITTED for any character. Note: In particular, quoting is NOT permitted within atoms. For example when the local-part of an addr-spec must contain a special character, a quoted string must be used. Therefore, a specification such as: Full\ Name@Domain is not legal and must be specified as: "Full Name"@Domain August 13, 1982 - 11 - RFC #822 Standard for ARPA Internet Text Messages 3.4.2. WHITE SPACE Note: In structured field bodies, multiple linear space ASCII characters (namely HTABs and SPACEs) are treated as single spaces and may freely surround any symbol. In all header fields, the only place in which at least one LWSP-char is REQUIRED is at the beginning of continua- tion lines in a folded field. When passing text to processes that do not interpret text according to this standard (e.g., mail protocol servers), then NO linear-white-space characters should occur between a period (".") or at-sign ("@") and a . Exactly ONE SPACE should be used in place of arbitrary linear-white-space and comment sequences. Note: Within systems conforming to this standard, wherever a member of the list of delimiters is allowed, LWSP-chars may also occur before and/or after it. Writers of mail-sending (i.e., header-generating) programs should realize that there is no network-wide definition of the effect of ASCII HT (horizontal-tab) characters on the appear- ance of text at another network host; therefore, the use of tabs in message headers, though permitted, is discouraged. 3.4.3. COMMENTS A comment is a set of ASCII characters, which is enclosed in matching parentheses and which is not within a quoted-string The comment construct permits message originators to add text which will be useful for human readers, but which will be ignored by the formal semantics. Comments should be retained while the message is subject to interpretation according to this standard. However, comments must NOT be included in other cases, such as during protocol exchanges with mail servers. Comments nest, so that if an unquoted left parenthesis occurs in a comment string, there must also be a matching right parenthesis. When a comment acts as the delimiter between a sequence of two lexical symbols, such as two atoms, it is lex- ically equivalent with a single SPACE, for the purposes of regenerating the sequence, such as when passing the sequence onto a mail protocol server. Comments are detected as such only within field-bodies of structured fields. If a comment is to be "folded" onto multiple lines, then the syntax for folding must be adhered to. (See the "Lexical August 13, 1982 - 12 - RFC #822 Standard for ARPA Internet Text Messages Analysis of Messages" section on "Folding Long Header Fields" above, and the section on "Case Independence" below.) Note that the official semantics therefore do not "see" any unquoted CRLFs that are in comments, although particular pars- ing programs may wish to note their presence. For these pro- grams, it would be reasonable to interpret a "CRLF LWSP-char" as being a CRLF that is part of the comment; i.e., the CRLF is kept and the LWSP-char is discarded. Quoted CRLFs (i.e., a backslash followed by a CR followed by a LF) still must be followed by at least one LWSP-char. 3.4.4. DELIMITING AND QUOTING CHARACTERS The quote character (backslash) and characters that delimit syntactic units are not, generally, to be taken as data that are part of the delimited or quoted unit(s). In particular, the quotation-marks that define a quoted-string, the parentheses that define a comment and the backslash that quotes a following character are NOT part of the quoted- string, comment or quoted character. A quotation-mark that is to be part of a quoted-string, a parenthesis that is to be part of a comment and a backslash that is to be part of either must each be preceded by the quote-character backslash ("\"). Note that the syntax allows any character to be quoted within a quoted-string or comment; however only certain characters MUST be quoted to be included as data. These characters are the ones that are not part of the alternate text group (i.e., ctext or qtext). The one exception to this rule is that a single SPACE is assumed to exist between contiguous words in a phrase, and this interpretation is independent of the actual number of LWSP-chars that the creator places between the words. To include more than one SPACE, the creator must make the LWSP- chars be part of a quoted-string. Quotation marks that delimit a quoted string and backslashes that quote the following character should NOT accompany the quoted-string when the string is passed to processes that do not interpret data according to this specification (e.g., mail protocol servers). 3.4.5. QUOTED-STRINGS Where permitted (i.e., in words in structured fields) quoted- strings are treated as a single symbol. That is, a quoted- string is equivalent to an atom, syntactically. If a quoted- string is to be "folded" onto multiple lines, then the syntax for folding must be adhered to. (See the "Lexical Analysis of August 13, 1982 - 13 - RFC #822 Standard for ARPA Internet Text Messages Messages" section on "Folding Long Header Fields" above, and the section on "Case Independence" below.) Therefore, the official semantics do not "see" any bare CRLFs that are in quoted-strings; however particular parsing programs may wish to note their presence. For such programs, it would be rea- sonable to interpret a "CRLF LWSP-char" as being a CRLF which is part of the quoted-string; i.e., the CRLF is kept and the LWSP-char is discarded. Quoted CRLFs (i.e., a backslash fol- lowed by a CR followed by a LF) are also subject to rules of folding, but the presence of the quoting character (backslash) explicitly indicates that the CRLF is data to the quoted string. Stripping off the first following LWSP-char is also appropriate when parsing quoted CRLFs. 3.4.6. BRACKETING CHARACTERS There is one type of bracket which must occur in matched pairs and may have pairs nested within each other: o Parentheses ("(" and ")") are used to indicate com- ments. There are three types of brackets which must occur in matched pairs, and which may NOT be nested: o Colon/semi-colon (":" and ";") are used in address specifications to indicate that the included list of addresses are to be treated as a group. o Angle brackets ("<" and ">") are generally used to indicate the presence of a one machine-usable refer- ence (e.g., delimiting mailboxes), possibly including source-routing to the machine. o Square brackets ("[" and "]") are used to indicate the presence of a domain-literal, which the appropriate name-domain is to use directly, bypassing normal name-resolution mechanisms. 3.4.7. CASE INDEPENDENCE Except as noted, alphabetic strings may be represented in any combination of upper and lower case. The only syntactic units August 13, 1982 - 14 - RFC #822 Standard for ARPA Internet Text Messages which requires preservation of case information are: - text - qtext - dtext - ctext - quoted-pair - local-part, except "Postmaster" When matching any other syntactic unit, case is to be ignored. For example, the field-names "From", "FROM", "from", and even "FroM" are semantically equal and should all be treated ident- ically. When generating these units, any mix of upper and lower case alphabetic characters may be used. The case shown in this specification is suggested for message-creating processes. Note: The reserved local-part address unit, "Postmaster", is an exception. When the value "Postmaster" is being interpreted, it must be accepted in any mixture of case, including "POSTMASTER", and "postmaster". 3.4.8. FOLDING LONG HEADER FIELDS Each header field may be represented on exactly one line con- sisting of the name of the field and its body, and terminated by a CRLF; this is what the parser sees. For readability, the field-body portion of long header fields may be "folded" onto multiple lines of the actual field. "Long" is commonly inter- preted to mean greater than 65 or 72 characters. The former length serves as a limit, when the message is to be viewed on most simple terminals which use simple display software; how- ever, the limit is not imposed by this standard. Note: Some display software often can selectively fold lines, to suit the display terminal. In such cases, sender- provided folding can interfere with the display software. 3.4.9. BACKSPACE CHARACTERS ASCII BS characters (Backspace, decimal 8) may be included in texts and quoted-strings to effect overstriking. However, any use of backspaces which effects an overstrike to the left of the beginning of the text or quoted-string is prohibited. August 13, 1982 - 15 - RFC #822 Standard for ARPA Internet Text Messages 3.4.10. NETWORK-SPECIFIC TRANSFORMATIONS During transmission through heterogeneous networks, it may be necessary to force data to conform to a network's local con- ventions. For example, it may be required that a CR be fol- lowed either by LF, making a CRLF, or by , if the CR is to stand alone). Such transformations are reversed, when the message exits that network. When crossing network boundaries, the message should be treated as passing through two modules. It will enter the first module containing whatever network-specific transforma- tions that were necessary to permit migration through the "current" network. It then passes through the modules: o Transformation Reversal The "current" network's idiosyncracies are removed and the message is returned to the canonical form speci- fied in this standard. o Transformation The "next" network's local idiosyncracies are imposed on the message. ------------------ From ==> | Remove Net-A | Net-A | idiosyncracies | ------------------ || \/ Conformance with standard || \/ ------------------ | Impose Net-B | ==> To | idiosyncracies | Net-B ------------------ August 13, 1982 - 16 - RFC #822 Standard for ARPA Internet Text Messages 4. MESSAGE SPECIFICATION 4.1. SYNTAX Note: Due to an artifact of the notational conventions, the syn- tax indicates that, when present, some fields, must be in a particular order. Header fields are NOT required to occur in any particular order, except that the message body must occur AFTER the headers. It is recommended that, if present, headers be sent in the order "Return- Path", "Received", "Date", "From", "Subject", "Sender", "To", "cc", etc. This specification permits multiple occurrences of most fields. Except as noted, their interpretation is not specified here, and their use is discouraged. The following syntax for the bodies of various fields should be thought of as describing each field body as a single long string (or line). The "Lexical Analysis of Message" section on "Long Header Fields", above, indicates how such long strings can be represented on more than one line in the actual transmitted message. message = fields *( CRLF *text ) ; Everything after ; first null line ; is message body fields = dates ; Creation time, source ; author id & one 1*destination ; address required *optional-field ; others optional source = [ trace ] ; net traversals originator ; original mail [ resent ] ; forwarded trace = return ; path to sender 1*received ; receipt tags return = "Return-path" ":" route-addr ; return address received = "Received" ":" ; one per relay ["from" domain] ; sending host ["by" domain] ; receiving host ["via" atom] ; physical path *("with" atom) ; link/mail protocol ["id" msg-id] ; receiver msg id ["for" addr-spec] ; initial form August 13, 1982 - 17 - RFC #822 Standard for ARPA Internet Text Messages ";" date-time ; time received originator = authentic ; authenticated addr [ "Reply-To" ":" 1#address] ) authentic = "From" ":" mailbox ; Single author / ( "Sender" ":" mailbox ; Actual submittor "From" ":" 1#mailbox) ; Multiple authors ; or not sender resent = resent-authentic [ "Resent-Reply-To" ":" 1#address] ) resent-authentic = = "Resent-From" ":" mailbox / ( "Resent-Sender" ":" mailbox "Resent-From" ":" 1#mailbox ) dates = orig-date ; Original [ resent-date ] ; Forwarded orig-date = "Date" ":" date-time resent-date = "Resent-Date" ":" date-time destination = "To" ":" 1#address ; Primary / "Resent-To" ":" 1#address / "cc" ":" 1#address ; Secondary / "Resent-cc" ":" 1#address / "bcc" ":" #address ; Blind carbon / "Resent-bcc" ":" #address optional-field = / "Message-ID" ":" msg-id / "Resent-Message-ID" ":" msg-id / "In-Reply-To" ":" *(phrase / msg-id) / "References" ":" *(phrase / msg-id) / "Keywords" ":" #phrase / "Subject" ":" *text / "Comments" ":" *text / "Encrypted" ":" 1#2word / extension-field ; To be defined / user-defined-field ; May be pre-empted msg-id = "<" addr-spec ">" ; Unique message id August 13, 1982 - 18 - RFC #822 Standard for ARPA Internet Text Messages extension-field = user-defined-field = 4.2. FORWARDING Some systems permit mail recipients to forward a message, retaining the original headers, by adding some new fields. This standard supports such a service, through the "Resent-" prefix to field names. Whenever the string "Resent-" begins a field name, the field has the same semantics as a field whose name does not have the prefix. However, the message is assumed to have been forwarded by an original recipient who attached the "Resent-" field. This new field is treated as being more recent than the equivalent, original field. For example, the "Resent-From", indicates the person that forwarded the message, whereas the "From" field indi- cates the original author. Use of such precedence information depends upon partici- pants' communication needs. For example, this standard does not dictate when a "Resent-From:" address should receive replies, in lieu of sending them to the "From:" address. Note: In general, the "Resent-" fields should be treated as con- taining a set of information that is independent of the set of original fields. Information for one set should not automatically be taken from the other. The interpre- tation of multiple "Resent-" fields, of the same type, is undefined. In the remainder of this specification, occurrence of legal "Resent-" fields are treated identically with the occurrence of August 13, 1982 - 19 - RFC #822 Standard for ARPA Internet Text Messages fields whose names do not contain this prefix. 4.3. TRACE FIELDS Trace information is used to provide an audit trail of mes- sage handling. In addition, it indicates a route back to the sender of the message. The list of known "via" and "with" values are registered with the Network Information Center, SRI International, Menlo Park, California. 4.3.1. RETURN-PATH This field is added by the final transport system that delivers the message to its recipient. The field is intended to contain definitive information about the address and route back to the message's originator. Note: The "Reply-To" field is added by the originator and serves to direct replies, whereas the "Return-Path" field is used to identify a path back to the origina- tor. While the syntax indicates that a route specification is optional, every attempt should be made to provide that infor- mation in this field. 4.3.2. RECEIVED A copy of this field is added by each transport service that relays the message. The information in the field can be quite useful for tracing transport problems. The names of the sending and receiving hosts and time-of- receipt may be specified. The "via" parameter may be used, to indicate what physical mechanism the message was sent over, such as Arpanet or Phonenet, and the "with" parameter may be used to indicate the mail-, or connection-, level protocol that was used, such as the SMTP mail protocol, or X.25 tran- sport protocol. Note: Several "with" parameters may be included, to fully specify the set of protocols that were used. Some transport services queue mail; the internal message iden- tifier that is assigned to the message may be noted, using the "id" parameter. When the sending host uses a destination address specification that the receiving host reinterprets, by August 13, 1982 - 20 - RFC #822 Standard for ARPA Internet Text Messages expansion or transformation, the receiving host may wish to record the original specification, using the "for" parameter. For example, when a copy of mail is sent to the member of a distribution list, this parameter may be used to record the original address that was used to specify the list. 4.4. ORIGINATOR FIELDS The standard allows only a subset of the combinations possi- ble with the From, Sender, Reply-To, Resent-From, Resent-Sender, and Resent-Reply-To fields. The limitation is intentional. 4.4.1. FROM / RESENT-FROM This field contains the identity of the person(s) who wished this message to be sent. The message-creation process should default this field to be a single, authenticated machine address, indicating the AGENT (person, system or process) entering the message. If this is not done, the "Sender" field MUST be present. If the "From" field IS defaulted this way, the "Sender" field is optional and is redundant with the "From" field. In all cases, addresses in the "From" field must be machine-usable (addr-specs) and may not contain named lists (groups). 4.4.2. SENDER / RESENT-SENDER This field contains the authenticated identity of the AGENT (person, system or process) that sends the message. It is intended for use when the sender is not the author of the mes- sage, or to indicate who among a group of authors actually sent the message. If the contents of the "Sender" field would be completely redundant with the "From" field, then the "Sender" field need not be present and its use is discouraged (though still legal). In particular, the "Sender" field MUST be present if it is NOT the same as the "From" Field. The Sender mailbox specification includes a word sequence which must correspond to a specific agent (i.e., a human user or a computer program) rather than a standard address. This indicates the expectation that the field will identify the single AGENT (person, system, or process) responsible for sending the mail and not simply include the name of a mailbox from which the mail was sent. For example in the case of a shared login name, the name, by itself, would not be adequate. The local-part address unit, which refers to this agent, is expected to be a computer system term, and not (for example) a generalized person reference which can be used outside the network text message context. August 13, 1982 - 21 - RFC #822 Standard for ARPA Internet Text Messages Since the critical function served by the "Sender" field is identification of the agent responsible for sending mail and since computer programs cannot be held accountable for their behavior, it is strongly recommended that when a computer pro- gram generates a message, the HUMAN who is responsible for that program be referenced as part of the "Sender" field mail- box specification. 4.4.3. REPLY-TO / RESENT-REPLY-TO This field provides a general mechanism for indicating any mailbox(es) to which responses are to be sent. Three typical uses for this feature can be distinguished. In the first case, the author(s) may not have regular machine-based mail- boxes and therefore wish(es) to indicate an alternate machine address. In the second case, an author may wish additional persons to be made aware of, or responsible for, replies. A somewhat different use may be of some help to "text message teleconferencing" groups equipped with automatic distribution services: include the address of that service in the "Reply- To" field of all messages submitted to the teleconference; then participants can "reply" to conference submissions to guarantee the correct distribution of any submission of their own. Note: The "Return-Path" field is added by the mail transport service, at the time of final deliver. It is intended to identify a path back to the orginator of the mes- sage. The "Reply-To" field is added by the message originator and is intended to direct replies. 4.4.4. AUTOMATIC USE OF FROM / SENDER / REPLY-TO For systems which automatically generate address lists for replies to messages, the following recommendations are made: o The "Sender" field mailbox should be sent notices of any problems in transport or delivery of the original messages. If there is no "Sender" field, then the "From" field mailbox should be used. o The "Sender" field mailbox should NEVER be used automatically, in a recipient's reply message. o If the "Reply-To" field exists, then the reply should go to the addresses indicated in that field and not to the address(es) indicated in the "From" field. August 13, 1982 - 22 - RFC #822 Standard for ARPA Internet Text Messages o If there is a "From" field, but no "Reply-To" field, the reply should be sent to the address(es) indicated in the "From" field. Sometimes, a recipient may actually wish to communicate with the person that initiated the message transfer. In such cases, it is reasonable to use the "Sender" address. This recommendation is intended only for automated use of originator-fields and is not intended to suggest that replies may not also be sent to other recipients of messages. It is up to the respective mail-handling programs to decide what additional facilities will be provided. Examples are provided in Appendix A. 4.5. RECEIVER FIELDS 4.5.1. TO / RESENT-TO This field contains the identity of the primary recipients of the message. 4.5.2. CC / RESENT-CC This field contains the identity of the secondary (informa- tional) recipients of the message. 4.5.3. BCC / RESENT-BCC This field contains the identity of additional recipients of the message. The contents of this field are not included in copies of the message sent to the primary and secondary reci- pients. Some systems may choose to include the text of the "Bcc" field only in the author(s)'s copy, while others may also include it in the text sent to all those indicated in the "Bcc" list. 4.6. REFERENCE FIELDS 4.6.1. MESSAGE-ID / RESENT-MESSAGE-ID This field contains a unique identifier (the local-part address unit) which refers to THIS version of THIS message. The uniqueness of the message identifier is guaranteed by the host which generates it. This identifier is intended to be machine readable and not necessarily meaningful to humans. A message identifier pertains to exactly one instantiation of a particular message; subsequent revisions to the message should August 13, 1982 - 23 - RFC #822 Standard for ARPA Internet Text Messages each receive new message identifiers. 4.6.2. IN-REPLY-TO The contents of this field identify previous correspon- dence which this message answers. Note that if message iden- tifiers are used in this field, they must use the msg-id specification format. 4.6.3. REFERENCES The contents of this field identify other correspondence which this message references. Note that if message identif- iers are used, they must use the msg-id specification format. 4.6.4. KEYWORDS This field contains keywords or phrases, separated by commas. 4.7. OTHER FIELDS 4.7.1. SUBJECT This is intended to provide a summary, or indicate the nature, of the message. 4.7.2. COMMENTS Permits adding text comments onto the message without disturbing the contents of the message's body. 4.7.3. ENCRYPTED Sometimes, data encryption is used to increase the privacy of message contents. If the body of a message has been encrypted, to keep its contents private, the "Encrypted" field can be used to note the fact and to indicate the nature of the encryption. The first parameter indicates the software used to encrypt the body, and the second, optional is intended to aid the recipient in selecting the proper decryption key. This code word may be viewed as an index to a table of keys held by the recipient. Note: Unfortunately, headers must contain envelope, as well as contents, information. Consequently, it is neces- sary that they remain unencrypted, so that mail tran- sport services may access them. Since names, addresses, and "Subject" field contents may contain August 13, 1982 - 24 - RFC #822 Standard for ARPA Internet Text Messages sensitive information, this requirement limits total message privacy. Names of encryption software are registered with the Net- work Information Center, SRI International, Menlo Park, Cali- fornia. 4.7.4. EXTENSION-FIELD A limited number of common fields have been defined in this document. As network mail requirements dictate, addi- tional fields may be standardized. To provide user-defined fields with a measure of safety, in name selection, such extension-fields will never have names that begin with the string "X-". Names of Extension-fields are registered with the Network Information Center, SRI International, Menlo Park, California. 4.7.5. USER-DEFINED-FIELD Individual users of network mail are free to define and use additional header fields. Such fields must have names which are not already used in the current specification or in any definitions of extension-fields, and the overall syntax of these user-defined-fields must conform to this specification's rules for delimiting and folding fields. Due to the extension-field publishing process, the name of a user- defined-field may be pre-empted Note: The prefatory string "X-" will never be used in the names of Extension-fields. This provides user-defined fields with a protected set of names. August 13, 1982 - 25 - RFC #822 Standard for ARPA Internet Text Messages 5. DATE AND TIME SPECIFICATION 5.1. SYNTAX date-time = [ day "," ] date time ; dd mm yy ; hh:mm:ss zzz day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" date = 1*2DIGIT month 2DIGIT ; day month year ; e.g. 20 Jun 82 month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" time = hour zone ; ANSI and Military hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59 zone = "UT" / "GMT" ; Universal Time ; North American : UT / "EST" / "EDT" ; Eastern: - 5/ - 4 / "CST" / "CDT" ; Central: - 6/ - 5 / "MST" / "MDT" ; Mountain: - 7/ - 6 / "PST" / "PDT" ; Pacific: - 8/ - 7 / 1ALPHA ; Military: Z = UT; ; A:-1; (J not used) ; M:-12; N:+1; Y:+12 / ( ("+" / "-") 4DIGIT ) ; Local differential ; hours+min. (HHMM) 5.2. SEMANTICS If included, day-of-week must be the day implied by the date specification. Time zone may be indicated in several ways. "UT" is Univer- sal Time (formerly called "Greenwich Mean Time"); "GMT" is per- mitted as a reference to Universal Time. The military standard uses a single character for each zone. "Z" is Universal Time. "A" indicates one hour earlier, and "M" indicates 12 hours ear- lier; "N" is one hour later, and "Y" is 12 hours later. The letter "J" is not used. The other remaining two forms are taken from ANSI standard X3.51-1975. One allows explicit indication of the amount of offset from UT; the other uses common 3-character strings for indicating time zones in North America. August 13, 1982 - 26 - RFC #822 Standard for ARPA Internet Text Messages 6. ADDRESS SPECIFICATION 6.1. SYNTAX address = mailbox ; one addressee / group ; named list group = phrase ":" [#mailbox] ";" mailbox = addr-spec ; simple address / phrase route-addr ; name & addr-spec route-addr = "<" [route] addr-spec ">" route = 1#("@" domain) ":" ; path-relative addr-spec = local-part "@" domain ; global address local-part = word *("." word) ; uninterpreted ; case-preserved domain = sub-domain *("." sub-domain) sub-domain = domain-ref / domain-literal domain-ref = atom ; symbolic reference 6.2. SEMANTICS A mailbox receives mail. It is a conceptual entity which does not necessarily pertain to file storage. For example, some sites may choose to print mail on their line printer and deliver the output to the addressee's desk. A mailbox specification comprises a person, system or pro- cess name reference, a domain-dependent string, and a name-domain reference. The name reference is optional and is usually used to indicate the human name of a recipient. The name-domain refer- ence specifies a sequence of sub-domains. The domain-dependent string is uninterpreted, except by the final sub-domain; the rest of the mail service merely transmits it as a literal string. 6.2.1. DOMAINS A name-domain is a set of registered (mail) names. A name- domain specification resolves to a subordinate name-domain specification or to a terminal domain-dependent string. Hence, domain specification is extensible, permitting any number of registration levels. August 13, 1982 - 27 - RFC #822 Standard for ARPA Internet Text Messages Name-domains model a global, logical, hierarchical addressing scheme. The model is logical, in that an address specifica- tion is related to name registration and is not necessarily tied to transmission path. The model's hierarchy is a directed graph, called an in-tree, such that there is a single path from the root of the tree to any node in the hierarchy. If more than one path actually exists, they are considered to be different addresses. The root node is common to all addresses; consequently, it is not referenced. Its children constitute "top-level" name- domains. Usually, a service has access to its own full domain specification and to the names of all top-level name-domains. The "top" of the domain addressing hierarchy -- a child of the root -- is indicated by the right-most field, in a domain specification. Its child is specified to the left, its child to the left, and so on. Some groups provide formal registration services; these con- stitute name-domains that are independent logically of specific machines. In addition, networks and machines impli- citly compose name-domains, since their membership usually is registered in name tables. In the case of formal registration, an organization implements a (distributed) data base which provides an address-to-route mapping service for addresses of the form: person@registry.organization Note that "organization" is a logical entity, separate from any particular communication network. A mechanism for accessing "organization" is universally avail- able. That mechanism, in turn, seeks an instantiation of the registry; its location is not indicated in the address specif- ication. It is assumed that the system which operates under the name "organization" knows how to find a subordinate regis- try. The registry will then use the "person" string to deter- mine where to send the mail specification. The latter, network-oriented case permits simple, direct, attachment-related address specification, such as: user@host.network Once the network is accessed, it is expected that a message will go directly to the host and that the host will resolve August 13, 1982 - 28 - RFC #822 Standard for ARPA Internet Text Messages the user name, placing the message in the user's mailbox. 6.2.2. ABBREVIATED DOMAIN SPECIFICATION Since any number of levels is possible within the domain hierarchy, specification of a fully qualified address can become inconvenient. This standard permits abbreviated domain specification, in a special case: For the address of the sender, call the left-most sub-domain Level N. In a header address, if all of the sub-domains above (i.e., to the right of) Level N are the same as those of the sender, then they do not have to appear in the specification. Otherwise, the address must be fully qualified. This feature is subject to approval by local sub- domains. Individual sub-domains may require their member systems, which originate mail, to provide full domain specification only. When permitted, abbrevia- tions may be present only while the message stays within the sub-domain of the sender. Use of this mechanism requires the sender's sub-domain to reserve the names of all top-level domains, so that full specifications can be distinguished from abbrevi- ated specifications. For example, if a sender's address is: sender@registry-A.registry-1.organization-X and one recipient's address is: recipient@registry-B.registry-1.organization-X and another's is: recipient@registry-C.registry-2.organization-X then ".registry-1.organization-X" need not be specified in the the message, but "registry-C.registry-2" DOES have to be specified. That is, the first two addresses may be abbrevi- ated, but the third address must be fully specified. When a message crosses a domain boundary, all addresses must be specified in the full format, ending with the top-level name-domain in the right-most field. It is the responsibility of mail forwarding services to ensure that addresses conform August 13, 1982 - 29 - RFC #822 Standard for ARPA Internet Text Messages with this requirement. In the case of abbreviated addresses, the relaying service must make the necessary expansions. It should be noted that it often is difficult for such a service to locate all occurrences of address abbreviations. For exam- ple, it will not be possible to find such abbreviations within the body of the message. The "Return-Path" field can aid recipients in recovering from these errors. Note: When passing any portion of an addr-spec onto a process which does not interpret data according to this stan- dard (e.g., mail protocol servers). There must be NO LWSP-chars preceding or following the at-sign or any delimiting period ("."), such as shown in the above examples, and only ONE SPACE between contiguous s. 6.2.3. DOMAIN TERMS A domain-ref must be THE official name of a registry, network, or host. It is a symbolic reference, within a name sub- domain. At times, it is necessary to bypass standard mechan- isms for resolving such references, using more primitive information, such as a network host address rather than its associated host name. To permit such references, this standard provides the domain- literal construct. Its contents must conform with the needs of the sub-domain in which it is interpreted. Domain-literals which refer to domains within the ARPA Inter- net specify 32-bit Internet addresses, in four 8-bit fields noted in decimal, as described in Request for Comments #820, "Assigned Numbers." For example: [10.0.3.19] Note: THE USE OF DOMAIN-LITERALS IS STRONGLY DISCOURAGED. It is permitted only as a means of bypassing temporary system limitations, such as name tables which are not complete. The names of "top-level" domains, and the names of domains under in the ARPA Internet, are registered with the Network Information Center, SRI International, Menlo Park, California. 6.2.4. DOMAIN-DEPENDENT LOCAL STRING The local-part of an addr-spec in a mailbox specification (i.e., the host's name for the mailbox) is understood to be August 13, 1982 - 30 - RFC #822 Standard for ARPA Internet Text Messages whatever the receiving mail protocol server allows. For exam- ple, some systems do not understand mailbox references of the form "P. D. Q. Bach", but others do. This specification treats periods (".") as lexical separators. Hence, their presence in local-parts which are not quoted- strings, is detected. However, such occurrences carry NO semantics. That is, if a local-part has periods within it, an address parser will divide the local-part into several tokens, but the sequence of tokens will be treated as one uninter- preted unit. The sequence will be re-assembled, when the address is passed outside of the system such as to a mail pro- tocol service. For example, the address: First.Last@Registry.Org is legal and does not require the local-part to be surrounded with quotation-marks. (However, "First Last" DOES require quoting.) The local-part of the address, when passed outside of the mail system, within the Registry.Org domain, is "First.Last", again without quotation marks. 6.2.5. BALANCING LOCAL-PART AND DOMAIN In some cases, the boundary between local-part and domain can be flexible. The local-part may be a simple string, which is used for the final determination of the recipient's mailbox. All other levels of reference are, therefore, part of the domain. For some systems, in the case of abbreviated reference to the local and subordinate sub-domains, it may be possible to specify only one reference within the domain part and place the other, subordinate name-domain references within the local-part. This would appear as: mailbox.sub1.sub2@this-domain Such a specification would be acceptable to address parsers which conform to RFC #733, but do not support this newer Internet standard. While contrary to the intent of this stan- dard, the form is legal. Also, some sub-domains have a specification syntax which does not conform to this standard. For example: sub-net.mailbox@sub-domain.domain August 13, 1982 - 31 - RFC #822 Standard for ARPA Internet Text Messages uses a different parsing sequence for local-part than for domain. Note: As a rule, the domain specification should contain fields which are encoded according to the syntax of this standard and which contain generally-standardized information. The local-part specification should con- tain only that portion of the address which deviates from the form or intention of the domain field. 6.2.6. MULTIPLE MAILBOXES An individual may have several mailboxes and wish to receive mail at whatever mailbox is convenient for the sender to access. This standard does not provide a means of specifying "any member of" a list of mailboxes. A set of individuals may wish to receive mail as a single unit (i.e., a distribution list). The construct permits specification of such a list. Recipient mailboxes are speci- fied within the bracketed part (":" - ";"). A copy of the transmitted message is to be sent to each mailbox listed. This standard does not permit recursive specification of groups within groups. While a list must be named, it is not required that the con- tents of the list be included. In this case, the
serves only as an indication of group distribution and would appear in the form: name:; Some mail services may provide a group-list distribution facility, accepting a single mailbox reference, expanding it to the full distribution list, and relaying the mail to the list's members. This standard provides no additional syntax for indicating such a service. Using the address alternative, while listing one mailbox in it, can mean either that the mailbox reference will be expanded to a list or that there is a group with one member. 6.2.7. EXPLICIT PATH SPECIFICATION At times, a message originator may wish to indicate the transmission path that a message should follow. This is called source routing. The normal addressing scheme, used in an addr-spec, is carefully separated from such information; the portion of a route-addr is provided for such occa- sions. It specifies the sequence of hosts and/or transmission August 13, 1982 - 32 - RFC #822 Standard for ARPA Internet Text Messages services that are to be traversed. Both domain-refs and domain-literals may be used. Note: The use of source routing is discouraged. Unless the sender has special need of path restriction, the choice of transmission route should be left to the mail tran- sport service. 6.3. RESERVED ADDRESS It often is necessary to send mail to a site, without know- ing any of its valid addresses. For example, there may be mail system dysfunctions, or a user may wish to find out a person's correct address, at that site. This standard specifies a single, reserved mailbox address (local-part) which is to be valid at each site. Mail sent to that address is to be routed to a person responsible for the site's mail system or to a person with responsibility for general site operation. The name of the reserved local-part address is: Postmaster so that "Postmaster@domain" is required to be valid. Note: This reserved local-part must be matched without sensi- tivity to alphabetic case, so that "POSTMASTER", "postmas- ter", and even "poStmASteR" is to be accepted. August 13, 1982 - 33 - RFC #822 Standard for ARPA Internet Text Messages 7. BIBLIOGRAPHY ANSI. "USA Standard Code for Information Interchange," X3.4. American National Standards Institute: New York (1968). Also in: Feinler, E. and J. Postel, eds., "ARPANET Protocol Hand- book", NIC 7104. ANSI. "Representations of Universal Time, Local Time Differen- tials, and United States Time Zone References for Information Interchange," X3.51-1975. American National Standards Insti- tute: New York (1975). Bemer, R.W., "Time and the Computer." In: Interface Age (Feb. 1979). Bennett, C.J. "JNT Mail Protocol". Joint Network Team, Ruther- ford and Appleton Laboratory: Didcot, England. Bhushan, A.K., Pogran, K.T., Tomlinson, R.S., and White, J.E. "Standardizing Network Mail Headers," ARPANET Request for Comments No. 561, Network Information Center No. 18516; SRI International: Menlo Park (September 1973). Birrell, A.D., Levin, R., Needham, R.M., and Schroeder, M.D. "Grapevine: An Exercise in Distributed Computing," Communica- tions of the ACM 25, 4 (April 1982), 260-274. Crocker, D.H., Vittal, J.J., Pogran, K.T., Henderson, D.A. "Standard for the Format of ARPA Network Text Message," ARPANET Request for Comments No. 733, Network Information Center No. 41952. SRI International: Menlo Park (November 1977). Feinler, E.J. and Postel, J.B. ARPANET Protocol Handbook, Net- work Information Center No. 7104 (NTIS AD A003890). SRI International: Menlo Park (April 1976). Harary, F. "Graph Theory". Addison-Wesley: Reading, Mass. (1969). Levin, R. and Schroeder, M. "Transport of Electronic Messages through a Network," TeleInformatics 79, pp. 29-33. North Holland (1979). Also as Xerox Palo Alto Research Center Technical Report CSL-79-4. Myer, T.H. and Henderson, D.A. "Message Transmission Protocol," ARPANET Request for Comments, No. 680, Network Information Center No. 32116. SRI International: Menlo Park (1975). August 13, 1982 - 34 - RFC #822 Standard for ARPA Internet Text Messages NBS. "Specification of Message Format for Computer Based Message Systems, Recommended Federal Information Processing Standard." National Bureau of Standards: Gaithersburg, Maryland (October 1981). NIC. Internet Protocol Transition Workbook. Network Information Center, SRI-International, Menlo Park, California (March 1982). Oppen, D.C. and Dalal, Y.K. "The Clearinghouse: A Decentralized Agent for Locating Named Objects in a Distributed Environ- ment," OPD-T8103. Xerox Office Products Division: Palo Alto, CA. (October 1981). Postel, J.B. "Assigned Numbers," ARPANET Request for Comments, No. 820. SRI International: Menlo Park (August 1982). Postel, J.B. "Simple Mail Transfer Protocol," ARPANET Request for Comments, No. 821. SRI International: Menlo Park (August 1982). Shoch, J.F. "Internetwork naming, addressing and routing," in Proc. 17th IEEE Computer Society International Conference, pp. 72-79, Sept. 1978, IEEE Cat. No. 78 CH 1388-8C. Su, Z. and Postel, J. "The Domain Naming Convention for Internet User Applications," ARPANET Request for Comments, No. 819. SRI International: Menlo Park (August 1982). August 13, 1982 - 35 - RFC #822 Standard for ARPA Internet Text Messages APPENDIX A. EXAMPLES A.1. ADDRESSES A.1.1. Alfred Neuman A.1.2. Neuman@BBN-TENEXA These two "Alfred Neuman" examples have identical seman- tics, as far as the operation of the local host's mail sending (distribution) program (also sometimes called its "mailer") and the remote host's mail protocol server are concerned. In the first example, the "Alfred Neuman" is ignored by the mailer, as "Neuman@BBN-TENEXA" completely specifies the reci- pient. The second example contains no superfluous informa- tion, and, again, "Neuman@BBN-TENEXA" is the intended reci- pient. Note: When the message crosses name-domain boundaries, then these specifications must be changed, so as to indicate the remainder of the hierarchy, starting with the top level. A.1.3. "George, Ted" This form might be used to indicate that a single mailbox is shared by several users. The quoted string is ignored by the originating host's mailer, because "Shared@Group.Arpanet" completely specifies the destination mailbox. A.1.4. Wilt . (the Stilt) Chamberlain@NBA.US The "(the Stilt)" is a comment, which is NOT included in the destination mailbox address handed to the originating system's mailer. The local-part of the address is the string "Wilt.Chamberlain", with NO space between the first and second words. A.1.5. Address Lists Gourmets: Pompous Person , Childs@WGBH.Boston, Galloping Gourmet@ ANT.Down-Under (Australian National Television), Cheapie@Discount-Liquors;, Cruisers: Port@Portugal, Jones@SEA;, Another@Somewhere.SomeOrg August 13, 1982 - 36 - RFC #822 Standard for ARPA Internet Text Messages This group list example points out the use of comments and the mixing of addresses and groups. A.2. ORIGINATOR ITEMS A.2.1. Author-sent George Jones logs into his host as "Jones". He sends mail himself. From: Jones@Group.Org or From: George Jones A.2.2. Secretary-sent George Jones logs in as Jones on his host. His secre- tary, who logs in as Secy sends mail for him. Replies to the mail should go to George. From: George Jones Sender: Secy@Other-Group A.2.3. Secretary-sent, for user of shared directory George Jones' secretary sends mail for George. Replies should go to George. From: George Jones Sender: Secy@Other-Group Note that there need not be a space between "Jones" and the "<", but adding a space enhances readability (as is the case in other examples. A.2.4. Committee activity, with one author George is a member of a committee. He wishes to have any replies to his message go to all committee members. From: George Jones Sender: Jones@Host Reply-To: The Committee: Jones@Host.Net, Smith@Other.Org, Doe@Somewhere-Else; Note that if George had not included himself in the August 13, 1982 - 37 - RFC #822 Standard for ARPA Internet Text Messages enumeration of The Committee, he would not have gotten an implicit reply; the presence of the "Reply-to" field SUPER- SEDES the sending of a reply to the person named in the "From" field. A.2.5. Secretary acting as full agent of author George Jones asks his secretary (Secy@Host) to send a message for him in his capacity as Group. He wants his secre- tary to handle all replies. From: George Jones Sender: Secy@Host Reply-To: Secy@Host A.2.6. Agent for user without online mailbox A friend of George's, Sarah, is visiting. George's secretary sends some mail to a friend of Sarah in computer- land. Replies should go to George, whose mailbox is Jones at Registry. From: Sarah Friendly Sender: Secy-Name Reply-To: Jones@Registry. A.2.7. Agent for member of a committee George's secretary sends out a message which was authored jointly by all the members of a committee. Note that the name of the committee cannot be specified, since names are not permitted in the From field. From: Jones@Host, Smith@Other-Host, Doe@Somewhere-Else Sender: Secy@SHost August 13, 1982 - 38 - RFC #822 Standard for ARPA Internet Text Messages A.3. COMPLETE HEADERS A.3.1. Minimum required Date: 26 Aug 76 1429 EDT Date: 26 Aug 76 1429 EDT From: Jones@Registry.Org or From: Jones@Registry.Org Bcc: To: Smith@Registry.Org Note that the "Bcc" field may be empty, while the "To" field is required to have at least one address. A.3.2. Using some of the additional fields Date: 26 Aug 76 1430 EDT From: George Jones Sender: Secy@SHOST To: "Al Neuman"@Mad-Host, Sam.Irving@Other-Host Message-ID: A.3.3. About as complex as you're going to get Date : 27 Aug 76 0932 PDT From : Ken Davis Subject : Re: The Syntax in the RFC Sender : KSecy@Other-Host Reply-To : Sam.Irving@Reg.Organization To : George Jones , Al.Neuman@MAD.Publisher cc : Important folk: Tom Softwood , "Sam Irving"@Other-Host;, Standard Distribution: /main/davis/people/standard@Other-Host, "standard.dist.3"@Tops-20-Host>; Comment : Sam is away on business. He asked me to handle his mail for him. He'll be able to provide a more accurate explanation when he returns next week. In-Reply-To: , George's message X-Special-action: This is a sample of user-defined field- names. There could also be a field-name "Special-action", but its name might later be preempted Message-ID: <4231.629.XYzi-What@Other-Host> August 13, 1982 - 39 - RFC #822 Standard for ARPA Internet Text Messages B. SIMPLE FIELD PARSING Some mail-reading software systems may wish to perform only minimal processing, ignoring the internal syntax of structured field-bodies and treating them the same as unstructured-field- bodies. Such software will need only to distinguish: o Header fields from the message body, o Beginnings of fields from lines which continue fields, o Field-names from field-contents. The abbreviated set of syntactic rules which follows will suffice for this purpose. It describes a limited view of mes- sages and is a subset of the syntactic rules provided in the main part of this specification. One small exception is that the con- tents of field-bodies consist only of text: B.1. SYNTAX message = *field *(CRLF *text) field = field-name ":" [field-body] CRLF field-name = 1* field-body = *text [CRLF LWSP-char field-body] B.2. SEMANTICS Headers occur before the message body and are terminated by a null line (i.e., two contiguous CRLFs). A line which continues a header field begins with a SPACE or HTAB character, while a line beginning a field starts with a printable character which is not a colon. A field-name consists of one or more printable characters (excluding colon, space, and control-characters). A field-name MUST be contained on one line. Upper and lower case are not dis- tinguished when comparing field-names. August 13, 1982 - 40 - RFC #822 Standard for ARPA Internet Text Messages C. DIFFERENCES FROM RFC #733 The following summarizes the differences between this stan- dard and the one specified in Arpanet Request for Comments #733, "Standard for the Format of ARPA Network Text Messages". The differences are listed in the order of their occurrence in the current specification. C.1. FIELD DEFINITIONS C.1.1. FIELD NAMES These now must be a sequence of printable characters. They may not contain any LWSP-chars. C.2. LEXICAL TOKENS C.2.1. SPECIALS The characters period ("."), left-square bracket ("["), and right-square bracket ("]") have been added. For presentation purposes, and when passing a specification to a system that does not conform to this standard, periods are to be contigu- ous with their surrounding lexical tokens. No linear-white- space is permitted between them. The presence of one LWSP- char between other tokens is still directed. C.2.2. ATOM Atoms may not contain SPACE. C.2.3. SPECIAL TEXT ctext and qtext have had backslash ("\") added to the list of prohibited characters. C.2.4. DOMAINS The lexical tokens and have been added. C.3. MESSAGE SPECIFICATION C.3.1. TRACE The "Return-path:" and "Received:" fields have been specified. August 13, 1982 - 41 - RFC #822 Standard for ARPA Internet Text Messages C.3.2. FROM The "From" field must contain machine-usable addresses (addr- spec). Multiple addresses may be specified, but named-lists (groups) may not. C.3.3. RESENT The meta-construct of prefacing field names with the string "Resent-" has been added, to indicate that a message has been forwarded by an intermediate recipient. C.3.4. DESTINATION A message must contain at least one destination address field. "To" and "CC" are required to contain at least one address. C.3.5. IN-REPLY-TO The field-body is no longer a comma-separated list, although a sequence is still permitted. C.3.6. REFERENCE The field-body is no longer a comma-separated list, although a sequence is still permitted. C.3.7. ENCRYPTED A field has been specified that permits senders to indicate that the body of a message has been encrypted. C.3.8. EXTENSION-FIELD Extension fields are prohibited from beginning with the char- acters "X-". C.4. DATE AND TIME SPECIFICATION C.4.1. SIMPLIFICATION Fewer optional forms are permitted and the list of three- letter time zones has been shortened. C.5. ADDRESS SPECIFICATION August 13, 1982 - 42 - RFC #822 Standard for ARPA Internet Text Messages C.5.1. ADDRESS The use of quoted-string, and the ":"-atom-":" construct, have been removed. An address now is either a single mailbox reference or is a named list of addresses. The latter indi- cates a group distribution. C.5.2. GROUPS Group lists are now required to to have a name. Group lists may not be nested. C.5.3. MAILBOX A mailbox specification may indicate a person's name, as before. Such a named list no longer may specify multiple mailboxes and may not be nested. C.5.4. ROUTE ADDRESSING Addresses now are taken to be absolute, global specifications, independent of transmission paths. The construct has been provided, to permit explicit specification of transmis- sion path. RFC #733's use of multiple at-signs ("@") was intended as a general syntax for indicating routing and/or hierarchical addressing. The current standard separates these specifications and only one at-sign is permitted. C.5.5. AT-SIGN The string " at " no longer is used as an address delimiter. Only at-sign ("@") serves the function. C.5.6. DOMAINS Hierarchical, logical name-domains have been added. C.6. RESERVED ADDRESS The local-part "Postmaster" has been reserved, so that users can be guaranteed at least one valid address at a site. August 13, 1982 - 43 - RFC #822 Standard for ARPA Internet Text Messages D. ALPHABETICAL LISTING OF SYNTAX RULES address = mailbox ; one addressee / group ; named list addr-spec = local-part "@" domain ; global address ALPHA = ; (101-132, 65.- 90.) ; (141-172, 97.-122.) atom = 1* authentic = "From" ":" mailbox ; Single author / ( "Sender" ":" mailbox ; Actual submittor "From" ":" 1#mailbox) ; Multiple authors ; or not sender CHAR = ; ( 0-177, 0.-127.) comment = "(" *(ctext / quoted-pair / comment) ")" CR = ; ( 15, 13.) CRLF = CR LF ctext = may be folded ")", "\" & CR, & including linear-white-space> CTL = ; ( 177, 127.) date = 1*2DIGIT month 2DIGIT ; day month year ; e.g. 20 Jun 82 dates = orig-date ; Original [ resent-date ] ; Forwarded date-time = [ day "," ] date time ; dd mm yy ; hh:mm:ss zzz day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" delimiters = specials / linear-white-space / comment destination = "To" ":" 1#address ; Primary / "Resent-To" ":" 1#address / "cc" ":" 1#address ; Secondary / "Resent-cc" ":" 1#address / "bcc" ":" #address ; Blind carbon / "Resent-bcc" ":" #address DIGIT = ; ( 60- 71, 48.- 57.) domain = sub-domain *("." sub-domain) domain-literal = "[" *(dtext / quoted-pair) "]" domain-ref = atom ; symbolic reference dtext = may be folded "]", "\" & CR, & including linear-white-space> extension-field = August 13, 1982 - 44 - RFC #822 Standard for ARPA Internet Text Messages field = field-name ":" [ field-body ] CRLF fields = dates ; Creation time, source ; author id & one 1*destination ; address required *optional-field ; others optional field-body = field-body-contents [CRLF LWSP-char field-body] field-body-contents = field-name = 1* group = phrase ":" [#mailbox] ";" hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59 HTAB = ; ( 11, 9.) LF = ; ( 12, 10.) linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE ; CRLF => folding local-part = word *("." word) ; uninterpreted ; case-preserved LWSP-char = SPACE / HTAB ; semantics = SPACE mailbox = addr-spec ; simple address / phrase route-addr ; name & addr-spec message = fields *( CRLF *text ) ; Everything after ; first null line ; is message body month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" msg-id = "<" addr-spec ">" ; Unique message id optional-field = / "Message-ID" ":" msg-id / "Resent-Message-ID" ":" msg-id / "In-Reply-To" ":" *(phrase / msg-id) / "References" ":" *(phrase / msg-id) / "Keywords" ":" #phrase / "Subject" ":" *text / "Comments" ":" *text / "Encrypted" ":" 1#2word / extension-field ; To be defined / user-defined-field ; May be pre-empted orig-date = "Date" ":" date-time originator = authentic ; authenticated addr [ "Reply-To" ":" 1#address] ) phrase = 1*word ; Sequence of words August 13, 1982 - 45 - RFC #822 Standard for ARPA Internet Text Messages qtext = , ; => may be folded "\" & CR, and including linear-white-space> quoted-pair = "\" CHAR ; may quote any char quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or ; quoted chars. received = "Received" ":" ; one per relay ["from" domain] ; sending host ["by" domain] ; receiving host ["via" atom] ; physical path *("with" atom) ; link/mail protocol ["id" msg-id] ; receiver msg id ["for" addr-spec] ; initial form ";" date-time ; time received resent = resent-authentic [ "Resent-Reply-To" ":" 1#address] ) resent-authentic = = "Resent-From" ":" mailbox / ( "Resent-Sender" ":" mailbox "Resent-From" ":" 1#mailbox ) resent-date = "Resent-Date" ":" date-time return = "Return-path" ":" route-addr ; return address route = 1#("@" domain) ":" ; path-relative route-addr = "<" [route] addr-spec ">" source = [ trace ] ; net traversals originator ; original mail [ resent ] ; forwarded SPACE = ; ( 40, 32.) specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted- / "," / ";" / ":" / "\" / <"> ; string, to use / "." / "[" / "]" ; within a word. sub-domain = domain-ref / domain-literal text = atoms, specials, CR & bare LF, but NOT ; comments and including CRLF> ; quoted-strings are ; NOT recognized. time = hour zone ; ANSI and Military trace = return ; path to sender 1*received ; receipt tags user-defined-field = word = atom / quoted-string August 13, 1982 - 46 - RFC #822 Standard for ARPA Internet Text Messages zone = "UT" / "GMT" ; Universal Time ; North American : UT / "EST" / "EDT" ; Eastern: - 5/ - 4 / "CST" / "CDT" ; Central: - 6/ - 5 / "MST" / "MDT" ; Mountain: - 7/ - 6 / "PST" / "PDT" ; Pacific: - 8/ - 7 / 1ALPHA ; Military: Z = UT; <"> = ; ( 42, 34.) August 13, 1982 - 47 - RFC #822 mail-2.5.4/spec/000077500000000000000000000000001214434061600133775ustar00rootroot00000000000000mail-2.5.4/spec/environment.rb000066400000000000000000000000731214434061600162700ustar00rootroot00000000000000$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) mail-2.5.4/spec/fixtures/000077500000000000000000000000001214434061600152505ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/attachments/000077500000000000000000000000001214434061600175635ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/attachments/basic_email.eml000066400000000000000000000027571214434061600225250ustar00rootroot00000000000000Delivered-To: raasdnil@gmail.com Received: by 10.140.178.13 with SMTP id a13cs354079rvf; Fri, 21 Nov 2008 20:05:05 -0800 (PST) Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Return-Path: Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net X-TPG-Junk-Status: Message not scanned X-TPG-Antivirus: Passed Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 for ; Sat, 22 Nov 2008 15:05:01 +1100 Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> From: Mikel Lindsaar To: Mikel Lindsaar Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v929.2) Subject: Testing 123 Date: Sat, 22 Nov 2008 15:04:59 +1100 X-Mailer: Apple Mail (2.929.2) Plain email. Hope it works well! Mikel mail-2.5.4/spec/fixtures/attachments/test.gif000066400000000000000000000072231214434061600212350ustar00rootroot00000000000000GIF89ad2•|ÄbīydŦ[2n1ݩmĵɍlɺl.Ȝҽ}G1ugřU,ѿ©yˠͺ|gq5qLubŤkDnXȶ|XʫҨŭz=&ɱyUYDذ͙cM̵μpv9!sTGVAأ>50ʸҵ֭sIJⱕΣஒv{͒r|A)崙GљzT'ۦ_Hr  L!ܵmZñP:θC94vQ©`8Εuչ⼩H1p\Q;r]|D.נỨ_ԝ~L5vaЦ麠꽤p2 E.侬jG8N8eQU>e>fP`JкbMjT黢xeXBv<&涛|i޶\H߸뾥nz@(nHؽðŇeڲ֞ƴjV蹟uоެhRӾ๦˴L7R;P&NJigAx?(U7+ZDԫc:)ѻJ4r7縝t^\Es8!׮aK~I3ǵ۴I2zB,s6ϖvD+ joZͿĬˏn|N8M7-䳘ЗxF/m/вhS]GҚ{~pخp33(#^A4 S<˹ȧT>㽪~C+\>1ʲʳǯq4u:#ͯM6_K.!Ӝ}p[d<]x;$̑pwcOtOaR[lVјxϽW@u7 x}¯ëī㲗Ӫs_b;!,d2ldY|pN9AG>LdBʒB%JIرBOV(  Ui$hJuC9nl5ssXhV+5BǼ4RpKт!$ 0Qy0H$PJ|qBT6gU y,MI9aNmTڠXSd'LB.Z3nGHxA; < Y;Ĺ4+Qj #F.i;S"fmۨuOСP1Pn#<-gP\ krzX\HёI0HK\\wtSNy@SI yrhB"'Ȁ~57D!ux!@BeFq_4XJ"P-tvThL9SՒ 5!Lf?P[pE*זF a̲c9 elY{M}ZٶD ~"ƭuH|8 "`D5ܡފhzXch IEUU 7B:C -DIxe*&`ÑG\"hb#3N.PJ؈Ru>UՑI "Ļ"Zu#VڅFaʱ faqpѩIenjƙgiwRZ1|gAA!.E\ i>˥QTv]xGj.G ­F'X r3Kě :x8Qihlt-AwJ=PwiՐE~AF99Ð\Er@cLfO?-LQ=f@ާW` *4ZQquݕs[[2؉ jdUz:٪}Zjz֌զ xhZWHA~ G97d:N58ՈO`:س-tU sӀljE2r:T$ SKu;X9a@R4*3$ j8=.HF+Ld$ % oc8AͤaDB>MPh4Ѥ\OQK;Zhl 0c#Ɉliuz5Ump g,0=$ e!fxa0jV3@6de+ԑ` [a ;{]_3P%,+LR`ь:*\!~ůԡsA7ѱQۛKN6)S)01hd86A:+ UC{jŁ@zM  8 0J:v(86JZ܌<+?tk aoTĐuЕ:,(+DRA;⍔ȉa&$? dߠEyv2W ;HC/I9 tB6᧯rzPdDeO^RfA|IRQ1a|5 L>9Po mыr+Ŝb$q "GjЍn0@HGDMEsh*4^?P(J*[!"9zoE D2Z"uP>iH YZ9>s_ GE:?'5XNH<GEsimKEhLưNT[\Weڵ H x;[rI&$/~E NrϧZ R 8bVj{"]Kف JziteH\xp>yh?YjG΂2A'7\*D4n0" b 8PArBs ȉf,>"aw\_4}-0ў ,kB\mhxm 5w۵Cg" MH&Kd4gǤ}eQ35aTbf| /}5a W6Rs&qm6g`E7g"J2hi%r8Ju8ry"QWjC20Di-F p-= |PNeN4j:;Kw|/-;0.a"fF&Zu"4[]a[^p 0w2=xm+s,e~\7n3(ezҁ`oqety^yiR)"WAǃ_vxsB `, B?N*@8C2'l9i }H#u#VBbCWE$`},c]ԄQq~|G?Q]qR]?l'HqwH?Pdw8) opvy>xwSxDJiuh혈y¢rEpaW]{i,bF't6jW/V;/ueOW=|Bdu߂!AA_ֿcڐk^ۘmv&vLG!AvcmeV=>"6 3P=IIvŔB<HHHH8Nm?!Q0p냹u}w\+J)\^4QT(Pӂ& ^?7?7?)kGx=y'S x^SFduqǏ*8RV|xh4D諴iq5A"6h+[%f궭 3Yle9\Q& n^CZ>)9P@ IOB£57NҞl >_=PjӴ!:MSքӿ?!VR.oMC+.$$Ai:;Y WUHF'BL!C++XZd2.Ȇ zR<¥"GU6bkM2c|gaTUB&}OS|y˄MwwT z'nb)wcH}‘wq$nL*A5rJ+ťY?!!"gWÐHR!Fkn>E 2Opm"JeLBb>|?,50~nR_e{H0uАu3S//7{ g;9fY 1?B/CQ:Q.˃#X Chcr1)t O^B`*- Q:q4P'M`'Yc?>HBaīcDnE؄5LK'c"Y(R]F> stream x+TT(TH-JN-()MQ( ()JU5Tp*O endstream endobj 5 0 obj 51 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 100 50] >> endobj 6 0 obj << /ProcSet [ /PDF /ImageB /ImageC /ImageI ] /XObject << /Im1 7 0 R >> >> endobj 7 0 obj << /Length 8 0 R /Type /XObject /Subtype /Image /Width 100 /Height 50 /ColorSpace 9 0 R /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x{gTVsnd}nLn `G^Eb{{jA%j4Ğs9ߵև}7 sYO{7kI[&hONe _Uej[~.#CN]Jpq3Nq3R7g>,_jJ;FxzϯW^em? 4o|~Io;Jm)!ڬiK .F] ?ԓl_oUeVv8Pt;n;shSuW]u&ustYi&.hhՂ-5ټ1fs?Ƙk Sf{nY2iViP&lub w߿Ҳ64;jB`p yAwK"Tߐ5EWO_Wp˻_Y`VYuJ/Cm.tE_ó{*VnCJ DgKivo wj 2-u=Qp$@aǷ{pc޵V-Yuy渮Ys)K'j|ap傱aVjchJҬ>X+t]7[[#`uԡ- weJ<>yۤ2v1T?Zl8:p/lݕdבL B)&gm/~:_b˘UkbV4GĠxVW;1+WZ~Ĭ.?;WQgٷm4߭ϹU1R|8r^@vD_ZD3QnaA5K:εޟi'~1[blܣS3hDzm - 6zi˦-hf5g6g /yZ.gt㪯7. ٳ6Na1 'n"Y{rڎr -.=Z-zm]>쏴g5fߝk7e>o Խ܌YayV7zލ^~{ YPl Q;^cޝ[Ui˒_ʋv>5'3 X`]m^~8P Szg6G[{MʠK{n5 DlϳϕjVfsǘ.f;V[؎Ty.'iVaStX_$t}&ǝm N_X]OxWU}ʓ,ՏgK_Ulu P J,׺4`uj2oT]*?#*ާ#C+?*/2y-fJXю=`u%[zo~뚯 /XM^4`J+P}j1 8n4s. ܹ*և =MU`;MG\Sm`弫B@pH7ꛒo ҞXռW`ZCe:˿k+\p`y< 8\;ٗ`M`dWkYiRP,B%ƒonV_/#p9`~>57S:kZ@UtSb G-Xala+,ՙ-𡒟VVܼ @oeqR乞sI4.yTݩz-,+2Pg䴓؂m{"2Q=BϕWVnH >-`V?V BK!- VC*H`feYeZzh U]w$قߖ^-`5tXlj%+b ̬VVL[ڦkU$©FE^ўH61MwZΙ9{XXmmq1<(؂dmҨ~ X:WA`%h@kW+-5<%PHV9`V# VC1C&1[[``RrʌB.* G+ق?Y.`Vj98%5gmP]G+v,{2x? tl!k׬ܽV` kk-v1:t?ҜBBI2wdw@qhC' -` l`UX_X_H Mdtmu[±|{VIVtV` ^` 4X@f @׭ ¡˴ t``5¦~;]kb/Dec[r *CoF}BhV-XmmrWHx-T@$?i͛C*҆O-t҆ͳuO!m[h)d69RIxFb'F;IXG҆$!m[ P!m4&دfQfāMq'xFuXQ˃9Ě* $m =3! Gl!ZPОwݐ6^%iClJ6OzJ-JVH&[f $mV$mj-(t<;J$B8 <2Ҝ[ 0acL[`i8`MքvK|b{sc mҶ3X-(>BH;!m <nNF|Hb ?4f[X-4vE6 ` ׺ryu!m-ܭ([HaXh[-K{-O<l!"_Z@I8I`0+h@dict2Ky~ mjqܼ} -`츳OHDi-Ҧ5W fzE{usXv'0oΞٶ3l!pdۿԿ)*jc`@\ڪStBO(K V` seZb ` 6Ɛ6W m2oS J`[Z٤8Dcg$8?!͊<ނ|thE1Ȳ?Zgt\ޙ\6;[x_hq is{Ս,;!ߔX5?k+tM O O ?KC6E+.5&9&)JxCqwag^[Nsc]uEM$m#]l6̶\={AMu!mL.8fމsu2BiBZmmtoss\0Kx-XڒS+f ̬.](~H#JltҬ!pG6BFE":I`z 2p;Px N+2X]%m>ň y eiBFaBڤYw?]ڙ6Pvl!k7|`%CM mr"Hڴ-lk!m[~X{:&|eV0+670[XW6Sl:=eaf;a֩Px )r\Fx l eaگ ic:քS2l{[G{dG_ʺQi#6Z5,m҆P_=Ht6[|w#kI mf%lϕd6ܩ˹]E|6`V6]qlOd4ޓJF,m i0_> ð}O̰ YڬKfm4P=X2xsqWtbs+[0@ҦMHod}6+!m~HFZt!-# %-7fQ0$mőɌ`@3>WyN'-1) ~6BwbmlA5+%`i`&K'6` C-lO$iSi_| Y--EjiSKF(K.3[eiCM㖬dLJaY]&72Z̊RU$"#TH2B};cAs=aڤ@Ȏ&P6~>#w$="a |^@6$m=oeic5_, 6CPx RjFhnHb 0B%i;Ts`;PNmWXmf#t7B/Ka-pjB3}/aoaF/Y Hm$#ԭ)̩tޔ/uW1Jef RH, %jZFJNmD5J` Ej3E6d9lfidߚipnoC]0B -)9ɩ ؂^aRĦ iSv_2B3M%Ou(PĦ+!m4s|r>%X2B#]Yڀ-ܶjU?jVlRl}ޛ)6=+%Vdgw]*#TKHa6rjs PHכK_h||VdZk#i'P6 lRjނ0B1-SRNm[uDl::ix~VbS\/ai> 1rjs/>U&fdR0Uð`f椿IPS|If ^(<% C0BWPM#4**}(bPK2B)!inxhJ%i/4vGjQ"`5Q6B9ai[+v",m|IXu ؂`EǃLceVon} `^լ1]2B4:Rjl_o*s;U$PĦD(f5}8l|._fd#ZCĦdSjqxH&Mk O= KĦaDxTCb d֧>HM?HmxV2e" l~ʹSt<--[ ŦxPl6?"y 41oYZ@t<&~,ig+Jð`5{Pt<`RǣǢ!Mu6wOǬڀ-TCu[8x6F!:60BEC%m(6}9P+R;}"6Z@«uJjs9_x@(@j_crq:>6a1?Y!b&fHf%` l iC6i?_is7^޾(bSx8 @ u2+q0/' {XVu3'lKV+'*f%ͽPb ڬ룳 P6hDj;\5g#ĬXڸR! ~t<86%i#T6-tAxH-GZ@{ʹRu|Q?j$X$߿Fc΄6bJ soY $mBu bS6ԆN96$m/m(wbV&(`Bک~6e#MYڠo1(%+U!#faZ8!@P&7BύPE4-P! lAxXQ!Mx[XGR#Cn::*6nN'FgҦ#-t,uĬ=AF(6#4B[rwx:I\((J|1<+ĦĬP35B!mBJڐ ix4PlB:' QHS(66FhMV,mܤFTĦh"b la֘bt<"R#2BYTejb` bVK*!NFmĦ,moLPt<@׹AlAŹJ٫r{}-pǣ>bzH̑ a[`oR60)u9Nl u<)&B8iN,0hUH2P@lJlGg) iRR8߳quy0B]l/䎇(-Pǃ؂l iCP&u<:>dCF1S!Mxؔ:hJ҆Ҹ1ĦQ4Bc`D# i &ۢ=y} -sǃvtMzYJmT҆|6xh0MV\HSX'5Bs:V6^!Q_'iiAeCwOvPu*H- iCl:d"PxPlF(U_Y:- { +^@-BZ+HmHP{ w<҂)QI`2uxBZ讕 Ә=Ҩ!׹#Pu0+x'm6W~i#1+6T_7:t"biS' ŦD*Uނ( JVMeG#,mrp#4@}ǜ VHA}`%[߶H->T{VCP2BI@CoE 0BeiIb2B{^ޒP] `%u ^k5Bl4>஍ VDlJ`%W؂bRj$XH0B!m-ܡԦ,mY*` _p#T`‡kC4JHh]6R!X6BE}]6BVdR#̊ wb *Ŧh2[u6Hwm-H`%Ԇ]JmPAx(҆Л* 4_Y$8e\;WrlJYڌAы#f" ݵͬDl #btSǃum z H(k$F+\v6n6ie| T_w;]ҙG*P6WE w< iBڷRj:eb H' _vnrA`Y$de7)6ein6\_T]FFFwmlj )fCة&.C[╎GgnmQ&։:XnJjHwm-T;\FV2]2Y :5B[nG^h@+׹A:FV+ĦۗS%30F(1+Uǃ+0 +l GP_7r@};yx݁ isF{__ endstream endobj 8 0 obj 9261 endobj 10 0 obj << /Length 11 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xMHaї$T& R+SeL b}wg-E"u.VDNC:DuE^";cT03y|URcE4`λޘvztLUF\)s:k-iYj6|vP4*wd>,y vڴ=S԰79 ڸ@`ӋmvUl5`P=Gj)kP*}6~^/~.~a2 nײ0%f|U 9l7?j`l7"tiNf]?uhgM Zʲ4i[&LY_x {xO$̥߬S]%֧&7g̞>r=g8`候 8rʶ<dWT'<eL~.u"A=9뗚]>313X3-$e}u,gmg664$ыEzL*LZ_j_]Xy[?Xs N/ ]|msϚƫk_WfȸA2)oz-di2|m٣j|5ԥej8ɮeE7[Q|IM%ײxf)|6\ k`Ҳ䍐.> endobj 12 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 1 0 obj << /Producer (Mac OS X 10.5.8 Quartz PDFContext) /CreationDate (D:20090827222429Z00'00') /ModDate (D:20090827222429Z00'00') >> endobj xref 0 13 0000000000 65535 f 0000010904 00000 n 0000000165 00000 n 0000010772 00000 n 0000000022 00000 n 0000000147 00000 n 0000000268 00000 n 0000000357 00000 n 0000009801 00000 n 0000010736 00000 n 0000009821 00000 n 0000010716 00000 n 0000010854 00000 n trailer << /Size 13 /Root 12 0 R /Info 1 0 R /ID [ <7af05eb605c91127cf4f015fea4d9646> <7af05eb605c91127cf4f015fea4d9646> ] >> startxref 11046 %%EOF mail-2.5.4/spec/fixtures/attachments/test.png000066400000000000000000000154561214434061600212630ustar00rootroot00000000000000PNG  IHDRd2RPtEXtSoftwareAdobe ImageReadyqe<IDATx N0&q8IiIBQH# O/BFΈJK۱?n:A܌[tϢ!d9|4^]Ƅ2&uT( 2p8e;,p̍fppsw~)x~1|e&I[%,@=w]Hsm~zahx)8[b:cS}v*dhUH΁Bm'eUQͶ0<#4UY2TRZΧK0/*i*XK0r}|œǏ g9yY94r 0N>7 >$Okb=0'N^` |9ϟ@߿ONׯf 3v.,ԅM@v-.r/ KET_?# ( R.F`P@0ZAA**&.'dri0N\Ғ" H OЉaCbcbE 4RN=Xb|? γY2/&29[XR Bmݖ%m6bWDV(2LqˆE1 TrOL0\}Tx JȺ5'B&i:e}I!QQ߿]t0pFPafmBpAC5De d`9nNky},L0$LŽCWjZیRJV w۬oBOOu( :&s e&}˶!rm0(8XQpZ!\1Ŏ_rJ UBdl" y #2j) X'[86}/xWGMnTU9Z@X@#R@Vܦzu׃G>|u&%L(L^`v\|2"߾INƔ  ȴM;f+Eʼnw]Y ԉ7N]YH\B )]D2( p:L e:||7^G.CWO?ʛe4{E5:,~b]QJ1P[‹4u{$MO*qIVY>(ֵD@2cĬUI>E' Y.iYhk̲)$F&A׃h;ɊጝbH^NcJ^A 5&˘ccYM#*ߐe3(pV=>*X`Y($FD!v +S QP6"~ /`e)($̛sdCv6ys߹ p`.alz3!J -9ꁔZsUֵ\WWE.T|qPIW7V=mA? # pLTd"%yU9d%(fa,9\]*KV͖Hǂq7P 뇸!褬bX=jNA&_E#c]T>Z{C8{VBT!—b 8eXtQF$!ly8CR(gp|Xo%NUoybd:~ՓV8*ΜE0i^h Tac(̊Ra>z\j+`أn?|H.}Ċ2k86``NHbq/Q3K)4QL*؀I #c_Hlk1:Wq 6W,',)#H}4)|` koe:5{7߿{__wNrXj!s((em bKt!֤6)YyT*q|>F<5R؜aIk¤~tpXh\[6Ke)#AAqqC6ٛw/o7w@)"<Rb鎤vɡ9k4 tM Q:"*oL4<1 r#6#WǥrHj'~1!pgzj:;wrwxYYwG($_L3Y}DQv~LPe9,pA(RK#.}}Ov2]4nuuǪOUMdft'zas!-+8Ҕdز9(ݳ;7Y! IʹӃ`XOm" l<筭[˪AeE *Lt}‚BS]6g*c0TIN3}!8IzdH)RD e\SK~)<̜@kV#iJ\"QbOIRnDܚGVUé&HX8npʼb*@yM{4mzW,J4#V#`Ε`C""H oBEg\Z/g]`{0w7Pz ػRV@Pmw0;jpQ|cc<g0_x`iMg! +)w35صJ8ԋhAH9=i+U/@ ৿.: Z% -nSr(2N87#itVY  &>x+ 0'Vs=<,=d3̈X oɞzPK~3+w޼wB&5#^,'r4ypfY vv L;첀:vG+bXbKWi>[\.M/s~ n㺛uy}Ab.e3KVC1_ɴn5%%:^&Za3HbUymV^A rhU\JT7J *ŻFkw[Q\ٙI+W՘<51,lAqߵcZj2eDu㡴$0C+􅬚I%a>EJp, G(SvRr|܇U(P%"V{.]ˉtT7f0s# \(ؾ*RWW]S;|v>y,w{;R<-ZҠ_7PK*?ϳsޚQǙN6K&M#S43eDT`YQ_"(EQbea@A$nNeh Xu={Zgx_>wֺd_ಶXi 0VH'cV;Mi{",k-%>ExL &fxϼz`{p6Qe&t7ǕDzÕJ< 5LQ7saa2]dyWAUQY}i8Y]6BpéhXl,$f !Jc8*23BR)#~_Rܮ঳k"]Ao J9j)*9rj=lC}abF/P!!iF{`l"hqLg;|*m7cӦRa1U#Ps -/j/~s$ک~z^x$ {V6m۸K-OtR7?[}b/oa Z7r(qS2 {kA 2Q:tNC&_Jd{T:n??udfa;'}]zd=kN~ǎCnMOulM__>:*l d;HEK/O?'V|h=Kc0Ú,Rue]!c&{zE)'(ϟ,9A+NTU>.2ϧLLИ%;}# ϞS_c`qJm {8a-c-Ӏiw0z6-MZDdmi67ZB,uJ=g|AdH7 f;Sxˋņ@4+X#e oSz dڪd>2&HFoWQ"A ]Fφd$Sh.*K/h{G9A~z [{>t/ش1AS~qط'9/gʫW{/KWhL@XLpu-l[xf #U+jcAN6pLu-ageFtYSG%(*c6M [7^~텡mҹ\N=rPE]o֧layVP=_R!o%ZQg b>Z /Yҍi \uKˋKKK 4[Z7Nڮ ¤C9vhVQ swL3u1ŴRj, X{iRaX/J&x;#v9!t6r4p3o1n0n/l.m.l.m/o3r7 w='|D.M6V@_JjUtaFFIL!P%T+Y/^5cQ:M6J3F/~C+|@(z=%w:#u8 s6q4p2o1n/m/l.l.l.m0p4t9!x?)~G1O9XCbNmYwdFFJM"Q&V+Y1_7e=jDpJvR|YƒaNJhːoЖvԝ~٣ݪᯔ嵛麡ĬɱͶлӾнλ˹ɷƴð濭㼪߹ݵڲ֮өϦ̡ȝĘ{xrn~izdu_p[lVgRdM`I[EWAS=P9K5I2F.}B+{?'y=%w:"u7 s6q4p2o1n0m/l.l.m.n1p5u:$zA*I2Q<[EeQp\{hFGK N#R(V-\2`8f?lErLxT~[Äbȋj̒rјx֟ڥޫⱕ淜꼢ƭʳθѼԿѿϽͻ˹ȶƳ°忭⻪߸ܴذխҩϥˠȜė{vqm}hxct^oZkUgQbM^HZCV@S;N8K4H0E-|A)z?'x<$v9"t7r5q3p2o1m0m.l.l.m/o2r7u<%{C-K5T?^IhSr_lFHK O%S)W.\4b;hAnGsNzU]Ňeɍl͓sҚ{סۦଐ㲗縞뾤êǯ˴ιҼѿν̺ʸǵŲ侫Ứ޷۳دԫҨͤʟǛÖ~yupk|fwbr]nXiTePaK]GYCU>Q:N7J3G/C,|A)z=&w;#u8!s6r4p2o1n0m/m.l.l.m0o3r8!w>'}E/M7WB`LkWubrFIM"P&U+Y0^6cP9M5I2F.~C+{?(y=%w:#u8 s6q3p2n1n0m/l/l.l.n1p4t:"y@)H1P:ZDcOmZyevGJM#R'U,Z2_8e=jDpKwR~YƒaNJȋpјx՞٤ݪⰕ嵛黢ŭʲͷѻӾнμ̹ɶƳñ⼪๦ݵٱ֮ҩХ̡ȝŘ{wrm~iydu_p[lVgQcM_H[EW@S'w<#v9!t7r5p3p2n0m0m.l.l.m/o2r7 w<&|D.L6U?_JiTt`nIL O%T*X/]4b;hAnHtO{V^ňeʎmΕtӛ{סۨ୑䳘踞뾥êǰ˴ϹҼоϼ̺ʸǵIJ侫Ứ޷۳ׯԫѧͣʟƚÕ}yuok{fvbr]mXiSdOaK\FXBT>Q:N7J2F/C+{@)z=&w;#u8!s6q5p3o1n/m/l.l.l/m0o3s8!x>(}F/O8XBaMlXvdsIM"Q&U+Z1^6d=jCoJvQ|Xƒ`ƉgːnЖvԜ}٣ݩᯓ嵚麠ĬɱͶкӾоμ̺ɷǴñ㼪๦ݶڲ֮ӪЦ̢ɝř•|wrn~izev`q\mWhSdN`I[EXBS=O9M6I2F.}C+{@(x<%w:"u7s5r4p2n1m0m/l.l.m/n1p5t:#zA*H2Q;ZEdOo[zgxJM#R(V,[2`8f>lEqKxS~[Äbȋj̑pїx֟ڥޫⰕ涛껢ƭʳηѻԾҿϽͻ˹ȶų°忭⼩߸ܴٱ֭ҩΤˠȝĘ{vqm}hyct_pZkVgQcM_HZDW@R]HgSr^l}ŸK O$S)W/\3b:gAmFsNzV\ņdȍkΓsљzנڦ߬㲖縞뽣ªǯ˴ϸѽѿϽͺʸȵij¯侬Ứ޸۳ذիҨΣʟǛ×yupk{gxbs]nYjTfPbK]GYCU>R;N7J3F0C-|A)z>&w<#u9!s6r4p3o1n0m/l.l.l.m0o3r8 w>'|D.M7VA`KjVuaqťL!P%T*Y0]6c;hBnIuPzW^ƈfʎnΕuӜ}עܧஒ䴙蹠쾥ëȰ˵Ϲӽоϼ͹ʷƴı㽪ຨ޶ڲخԫѦ͢ɟƙ•}xtojzfvaq\mWiSeO`J\FXBT>Q:M5I2F/~C+|@(y=&w;#u8 s5r4p2o1n/m/m.l.l.m0p4s9"x?)~G0O:XCcMmYxeuɩM"Q'U,Z1_7e=kDpKwR}YÃaNJhːoЖwԝ٣ݩⰔ嶛黡ŭɲͶѺӾҿнͻ˹ɷƴñ⽪๦ܶٱ֮Ҫϥ̢ɝř|wsm~iydu`p[lWhRcM_I[EW@S^IhTs`máϱO$S*X.]4b;h@nHtOzV]ŇdɍlΔtӚ{נۧ୐㲘縞뽤μ@62oYOͣʟƚÖue*fOaKQ$n0n/m.l.l.m0p4s8 w>'|E0N8VBaLkVvcrǦҵP&T+Y1^6c1dN`JlC3jA0g=-d;*b8(`6% Y-W+V)T(S%R%h.n0m/l.l.l/n0p5t:"y@)G1P:YEcOn[yfwʪչQ'U,[1`8e>jDqKwS}ZƒbNJȋpїx՞٤ݪⰕ涜鼢ŭɲͷѻӾC94ѿоͻ@61°⼩߸ݵٱ֭өХˡȜĘM;3l[m~hydt_pZkVhRcM^IZDW@S=P8K4H1" y<$w9"u7r5q3p1n0m/l/m.m.l/n2q6u;${B,J3S=]HfRq]~j|ͮؼS)W-\4a9g@mFrMyU\ĆcȌk͒rҙzןڥ߬㲖淝꼤©ƯʴϸҼԿC94ҾϽͻ@61¯俬ứ߸۴ٰխҨΣˠǛė%pl|gxbs^oYjUfPaL^HZDU?R;N7J3H0" x;$v9!s6r4q3o1o0m/m.l.l.m0o3r7 v=&|D-L6V@_KiUtaoģвT*Y/^5c;hBoHtOzW^ňeʎlΔtӛ|סۧ߮䳘蹟뾥ëȰ̵ϹҼC:4оϼ̺?61㾫໨ݶ۲׮ԫѧͣʟƚ–1%ojzfwar]nXiSeOaK\FYBU>Q:M6J2F/" w;#u8 s6r4p2o1n0m/m.l.l/m0p4s8!x?(}F0O8XCbNlXwctǧӶõU,Z0_7d]HgSs_l}ΰپ˻X/]4b:gAmGtNyV\ĆdɍlΓsҚ{נۦ߬䲗縞꽤©ǯ˴θѼԿC:5Ѿϼͺʸ?50俬⻨߷۴ذիѨͣʠǛ×~r% Z?4kXnYjTfOaL^GZBU>R;M7J3F/~D,! u8!t6r4q2o1n0n/l/l.l.m0o3r7 w='|E/M7WA`LkVubqťѴ³οY0^5c;iBoIuP{W_ňfʎnϕuӜ}آܨஒ崙躠쿥ëȱ̵йҽC:5оμ̹ʷ?50ɞƚ•}yl0# K3)aMdN`J\FXAT>Q:L6I2F/~B+! u8 s6q4p3o1n/m/m.l.m.n1p4t9#x?)~G1P:YDcNmYxevɩոŶ¥Z2_8e>jDpKwR}Y„`NJh̑pЗw՝٣ݪᰕ嵛黡ŭɲͷлӾC:5ҿнλ˹ɶ>50ȜŘ{wsmhL? \50⻩߸۴ذ֬ѨΤˠțėzvql}hxczTE+Y8+ZCV?R4/Ứ޷۳ׯԬѨΣʟƚ–~yupk|fwar]nY_@2}M:U>Q:N7J3G0~C,|@)! t6r4q2o1m0m/l/l.l.m0p3s8!w>'}E0N8WBbMlXvcrǦҶóʩ_6d4/๧ݶڲ׮ӪЦ̢ɝř}xsn~izev`q\lWiSR5*M/#S=P:M5I1F/~B+{@(  r6q4p2o1n/m/l.l.l.n1p5t:#yA*~H1Q;ZEdOo[yfwʫչƷ̩`8e>kEqKxR~Z„bNji̒qЗx՞٤ު᱕涜鼢ŭɲͷѻӿC:5ҿϾλ˸ȶŴ>4/߹ܴٱ֭ҩϥ̠ȝĘ{vqm}iyct_oZlVgQ\G&S'  r5q3p1o0m/l/l.l.m/n2r6u<%{C,J5R=\HfSq^~j|ͮؽɻͪa9g@mGsMxU\ĆdɌlΓrҚz֠ۦ߬㲖緝뽤ªƯ˴θѼԿC95ѿϼ̻ʸȵij>4/޷۴ذլѨΣʠǜ×zupk|gwcs^oYjUfPbK&Q;N8J4G0D,|@)z>&  r4p3o1n0m/m.l.l.m/o3r8 v=&|D.L7V@_KjUtaoģгͿͫb;iBoHuP{W^ƇfʎmΕuӛ|ءܨ୒䳙蹟쾥ëȰ̵ϹҽC:5Ѿϼ̺ʷǴIJ=3/޶۳ׯԫЧͣʞƚ•}xspj{evaq\mXiTeOxM;A(P:M6J2G/~C,{@(z=%  r4p2o1m/m/m/l.l.n1p4s9"x?(}F0O9XCbNmYwdtȨӶĵ̭e=jDpJwQ}Yƒ`ƉhːoϖwԜ~أݪᯔ嵚黡ŭɲͶкӽC95оμ̺ɷƴñ=3.ݶڲ׭ӪЦ̢ɝŘ|wrwWI~izdu`p[mVhR]IpB1P8L5H1E.}B+{?(y<% r4p2o0n0m.l.l.l/n1p5u:#yA*I2R<[FeQp\{hyˬֺȹͭf>kFrLwS[Åbȋj͒qљy՞ڥޫⱖ涜꼣ŮɳηѻӾC94ѿнͻ˸ȶų°=3.wtp{nxkugrdo`vf{v|i O8/dE9xQBuN>S7+ B(S'x;$ q3o1n0n/l/l.l.m/n2q7v<&{C-K6S?]HhSr^l~áϰٿ˼ͮhAmGtOzU]ĆdɍlΓsӚzנۦ߭㲗縞뽤©ǯ˴ϸҼԿB94ѿϼ̻ʸȵIJ¯=3.3'"yuaRD*U>Q:N6J3G/C,|@)y>&x;$ p2o1n0m/m.l.l.m0p3s8 w>'|E.N7WAaLjVvbrŤҴóοͰiBoIuP|W_ƈgˏnϖvԜ}آܩஒ䴙躠쿦ìȱ̵ϹҽC94оμ˺ʷƴñ=3.3&!xton\\A6- F-#vJ8XAT>P:L6I2F.~C+|@(y=%w;# p2n1m0m/l.l.l/m1p5t9"x@)~G1O:YDdNnYxevɪոƶͱkDpKwS}YƒaNJiˑpЗxԝ٤ުⰕ嵛껢ŭʲͷѻӾҿнͼ˹ɶŴð忭㼪߹ܵٱ֭ҩϥˡȜŘ{vrn}iydu_q[lVgQcM_IZEV@S=O8K5H1E.}A*{?'y=$v:!t7s5q3o2o1n0m/m.l.m/n2q5u;$zB+J4S=\GfQq]|i{ͮ׼ɺͲlFsMyT\ącȌk͒rљy֟ڦ߬㲖渝꼤¨ǮʴθѻԿѾнͺ˸ȵų°忬⻩߸ܴذլѨΤˠǛėzuql|hxcs^oYjUgQbK]GYCU?R;N7K4G0D-}@)z>&x;$u9!t6s5p3o2n0m/l/m.l.m/n2r6 v<&|D.L7U?^JiTt`oâϲڿ̽ͳnHtOzV]ŇeɍlΔtҚ|סۧ୑䳘繞쾥êǰ̵ϹҽѾϽͺʷǴIJ侬Ẩ޷۳װԫѧͣɞƚÖ~xtok{fvar]nYiSeOaK\FXBU>Q:N6J2F/~C,|@)y>%x;#v8!t6q4q2o1n0m/l/l.l/m0o3s8"x?(}F0N9WBaMlXwdrƧҶõʹoJvQ|Xƒ_ƈgʏoϖvԜ}أݩᯓ嵚軠쿧Ĭȱ̵кӾоμ̹ɶƴð㽪๦ݵڲ֮ӪЦ̢ȝř|xsn~jzeu`q\mWhScN`I\EXAS=P9M5I1E.~B+{?(y=%w:"t8 s5r3o2o1m/m.m/l.l.n1p5u:#yA*~H2Q;ZEdPo[zgxʫֺǸ͵qLxS~[ÅbNjȋpїx՞ڥޫⰕ巜꼢ŮʲͷлӾҿϽλ˸ɶƳð忭⼩߹ݴٱ֭ҩΥˠȜĘ{wrm}hyct_pZkUgQcL^HZDV@R'y<$v:!t7s5q4p1o1m/m/l.l.m/n2q6u<%zC,J4S>\HgSr^~k}ŸͯؾʻͶsNyU\Ćdȍk͓sљ{֠ۦ߬㲖縞뽤ªǯ˴θѼԿѿϽ̺ʸȵŲ¯侬Ứ߷۴ذլѨΣ˟ƛėzuql{gwcs]nYjTePbK]GYCV>R;N7J4G/D,|A)z=&x<#v9 s6r4q3o2n0m/m.l.l/m0o3s8 w=&|E.M7V@`JjVuapģѳͿ͸tP{W_ƈfʎnϕuӛ|עܨஒ䴙蹟쿦ëȱ̵ϹҽѾμ̹ʷƴIJ佫ຨݶ۳دԪѧ͢ɞƚ•}xtoj{fvar]mWiSeO`J\FXBU=Q:M6I3F.~B+{@)y=&w:#u8 s6r4p3o1n0l/m.l.l/m1p3s9"x?(}F0O9XCbNmXxeuȨԷŵ͹wQ|Yƒ`ljh̐oЗwԝ٣ݩᯔ嶚黡ŭɲͶлӾҿоμ̹ɶƳð㽪๦ݵڱ֭ӪХ̡ȝř|wrn~iyeu`p[lWgRcN_I[EW@S&x<$v9!t7r5q3p1n0m/m.l.l.l0n2q7 u=&{C-L5T?]IhTs_m~¡αڿ˼ͼzU]ĆdɎm͔tӚ{נۧ߭䲘縞뾤ªǰ˵ιҽտѿμͺʸǵŲ侬Ứ޷ڳׯիѨͣʟƛÖ~ytok{gvbs]nYiTeOaK]GYBU>Q;M7J3F0D,|A)z=&x;#v8!s6r4q3o1n0m/m/l.l.m0p3s8!w>'|E/M8WAaLkWvcrƦҵ³ͽ|X_ƈgʏnϕuԜ}أܨᯓ崙麟뾦īȱ͵йӽоμ̺ɷƴı㽫๧ݶڲ׮ӪЦ̢ɞƙ|xsn~jzeu`q\lWhRdO`I\EXBT>P:L5I2F/~C+|@(y=%w;#u8 s6q4p2o1n0m.m.l.m/n1p4t:#x?)~G1P:YEcOnZyfwɪոƷ;}YÄaNJiˑpИw՞٥ݪⱔ涛鼡ŭɳͷѺӾѿоλ̹ɶƴð忭⼩߹ܵٱ֭ҩХˡȝŘ|wrm}hydu_p[kVgQcM_H[EWAR=O8L5H1E.}B*{?'y<%v:"u7 s5q3o2n0n/m/l.l.l/n2q6u;$zB,I4S=\GgRq]}j{ͮؽɺͿ[ĆdȌk͒rљz֟ڦެ㱖緝꽣©Ʈ˴θѻԿҾϽͻʸǵų侬⻩߷۴ذլҨΤʠǛė~zvpl|gwcs^oYkUfPbK]GZCU?R;N8J4G0D,}A*z>&x<$v8!t6r5q2o2n0m/m/l.l.l/o2r7 w=&|D-L7V@_JiUtaoãв;^ŇeɎmΔtӛ|סܧ୑䳘蹞뾤ëȰ˵ϹҼѾϽ̺ɸǴIJ侫ຨ޶ڳدԫЦͣɟƚ•}xtok{fvar]mXiTdN`K]GYBT>P;M6J3G/~C,|@)y=&w;#u9 s6r4p2o1m0m/m.l.l.m0o4s9"x?(}F0N9XBbMlYwdtǦӶĵd2;Z:;`;h(S;pHHmail-2.5.4/spec/fixtures/attachments/test.zip000066400000000000000000000260141214434061600212710ustar00rootroot00000000000000PKC;test.pdfUX JJz <7#c CƖu%K2YƖe0 F!٢,CXD`LBB)ޞ=Μ\:\iLUI]oq{qޗ~v 4ӟ]O|Kj$[GOc @ C !<{=89LVz 3ll\ް}?乙m8[1>n暪PC+2Ͽ!@T/l1Aa!^P(/qP >o"(TUT*nom!A^vhbU;"~Al<1^* *T [ֿͩJva?)*;bCM1X_?pA!v^St(!$ XB |pPࡑgGڣ){ޟffp61dձzGW~bݟumXpֵF%crA Jfnwo_Ĺ9`PԞER y|Y~v_=rLYgo 9v2ll'0yr!;t&1 ͻ{3>C& Z>-ڕD: vƿEEBO6y>r7w~ܜh䯩OG_ Qp+ 1g1$eSǗ6˃{okCjD?wA>o;u?YP6+"4?mr#| ]ھhKr,&ޱq9h?fvS cؒQA}@ 82؋:e MuR[ݯAЎm]+(ŋ ջ%/?ˉZi\ 7iWW0jp rVkuAU!ö>oL.!V_uZYfƛ|gփ]rNKoW~t}Ck",8{0^Ai]:tqZ(չKK'W'x.\ vz(XBm2S تq"Ƶ db]jZ?7~泫XC_V µ*MIm\ Upi?c,:PXsIS5.*q5fe?tpEI x0Hk#ϙK Kv('J?:֞sϠ:uC"cs c'oZ9t ᾅhHMKŷl~&.nteG]zz%jA$CɌ{L 5MjL5W(4v} ?Y:oKRm3Hwt{Z⣵Ute'kE .eK&duH7ƭNlKrWRЕ֬5I*`E/v<De WisCYasNs6^gŐ01 u(t_n=οRҾ?sk-lXx;.8`mWYrcN4o b[>*`*x<}F&h>&&ZCB3^@ Xчj?}RAiY}@ C1NC?4-k?{Z%EgiٗVf5kbD wXDjE;\ZTfCKJ9P 5ﲦjN3,34ZT S~9˶bPUࠜiztbu++^,SB^?BMS=1ȪXJiePI-CG'y[YlxqժK:(^?KM|kǽuX\ +p%|ϲ8=?/'^:CCL, i0so!A$M=D?''M<M4Zpҏb@;B~¿(@36USO1gAB$|WOTuMeuAPжC:{f J=򬠶3 3qwbjШA"#SqD\M6}q֗dz\)ʔfFO5~-)/Cr e_@gpY4a0[KL.I&}Qk e-Sa͌MQ']}@RxV,KѵKܤ!MI_Ԛ&ȍu^oevEc^N%b-bU+82 ;De ::]q<NMej]>_Mo9>e2B;H,ҭ+bczd5S"Nb~0+"SdxF 2M/ߕpw1k[Yת(~z5ԬWu A7s/NsxT.F<#zam /w*:;m'[*!JC,5erw|&Nnexxv -gk:ЦoVh3a1F$l)lckkR fvr6R4 =)}؅v}n i_dlg4~S[D9N6S!*͵?K}ZnmZGhLvsfe|^%hx;3$n8%udMr/УFt Smv#H¦Cs"]o4tY}C_0W~!5қW+PmLy$'JÀ1/566GkV[p+r%:O}zay'#)ܣbЂ^7 k$ZR|ۏk߻$C\JE6z0~ik N+i?K͸5|_o8Yΰz1vZfBLQJτ~x+ZvϚ}UsʉM24bEЩ.x7tߠ# .WTVTaR#oGZRllZ0 Ň%zma\}'^{DzT$=t-Wgd  {* 9p^ۧ*|N,.Q ~!.iDhcPs\S.1N y.HOl.ZzuǧḏGRDxq<_Ĉ*ˆh&{3d QonY,7ID|\b]Xw"lPS`ʆ3]{oC,,cN|1kiv_ђ} {s }ȀCSrsK^`09Lo.Zkd _;}Wyg´'cJ2D9-/l9"qvsODW\n~OeI6qJ~}z3y~7CE 4vn6@SW %_9'SIQ-WNړkpD'}+iM44B,} "G`8) 6oֽ8q7Ng֦4 L .UPw}W[o/N,88;lQȪZ$}t[buN I{skM"ZK/ /n⣧UMy%6pv/9sv.hDjJ^ޭ;B4Z o',!ŭ_x/:$kM[+ .&y W9K 񷓅U]?peKj5^^u wȦ=)BϳV+'$⵩WbsH"O>՗h@/t)|j]=Q%h [ 6xa VA\> #IТ! `l_}-Z#k`,Sy59/ s$p5)a.O9{adKḞbQJo4XÛ<Ѵ9G&MMIpD| `oasm3vSA`r^Ts/=nBn-쮆P[C~Ga : UʟbQ!NjI7agz,x?<0ρ_(\-#:7%i(Wx-= f@y'6UK[=~CC;2D wʔΤKd v&xQ@?\ W.Bf9*VgiF\B xXD=TVHYj* 3VO7ؖ)7v D>ʂN][au {1cz9 ҏcyڵBf8D kD-O‡g 'kyo=J-Ho=ak`95 |?kmi*u͕yi3; Fw"yҞ $%:f~Y,͉zKF~POZ  -[|GB_LG3$ c9-6kE@s 5D5sr Y>TA*bɧyYy8"|r旮=`񖤺Uy'7 _Z8\I+ ݮN}<&O#=AމS D!ֆqQL; Qn;AO-,Fq|V1Kޜf(qDETrN^S%1(T/H a2 Zs:$m*hɕapHu@^)g0Oj9Q WAKeтҐ% D[d.FOjXr߈0ˊ0"ewWRo:b7R԰Xs l8oL ['}̯H.EpXcQVl36mНzoŹ.YOOPѡvސwo )Z8_=^C@Xd96Zs) KtjEqCc HRxas" E[vB^g W*kHzG⠳ޫLjNWR*+NiLzt!H#kk+}69M=)Ivx 2;ƥтAOEWXe$GЖ✢TQEDѬΙBθJψ.[,vp:<~en'n˶^zqD%vl.^MA$'Tw125Fu7H9Gv]o*njo`W^WҬ |8,y'Q9W!4T*Rz,=oN3PSB 6ߨa2qqV}yR48{^&TLVTH<]ꖟ./ IDorAO.="iOJNOVg~0q19n3%F]M:Tn3Ćl%*Z3_{ 3._ +9?*gc$2p8=Hdj2)\{I /^@B &_YcyoLTIaʯ}m eNV©[lV$5!w~Fe߶_ȕ}e%P &g)U"x5x%=ʎ`BX 輹I`B 'Z32}U~$NHN߃q>k'e; yD[ LAWtP-~WSk Y+r'tm칊]*~Y;jȗ[F8K\_9vB[|KOî pq&>dȒ`ȁZ<.88 1x쾈u^m˭]UBx$/F:dd3_=,yE|N$7"Jy'Mąld"T [ 'ϩkyT/VcBc|Ԝ1ZzlTgdas\yw7VEhݵt%V׶ɞX;PMOeIG9Tk 9̳w">&=XRw 8QbHjvtakusb.XVe ;f_Ɍjd3F!,FAߺ8UlBěKjȋs9Havtr֙ٞm7H]$|:dNOs)s|MR̜gzrp?n{77̛aD0[y'DV;c7=BKl!YIa 6р7p\" [%YnE7ZCAW$ Q$6 d/wt̳D]pO胕gdBŧoiʹXBx@y{Ygzӷ,a6tДfG[Ɂ,ҎLx[&)'sH[ϸf˨U <^wh`I{ktⓔގ$|˖yfpm:npHim% pO1b9D5W0؄9y8--NO& ,Sȁ#;; ?FN$g)Ђ$ wg8o!8[ok83>%~y]'^ǛZJy"9au [5|gG+Z)13& + 3>LH XDQr $ޚ&S^['6AoͷRsț[) 4oz/u Y ;tc"笮y'nc@f/ON`{d6a,@ d\Ifa(-돦$cYg2|[g⛛ϟ8 Z22stO\x<3JϺsǧd*+(u_' kP3WTn&a)yѯeƌT׷!2J3YUU\su ]k8(DĕcC>F.>[ͺ-gNknKU߃O,CO$N-)`.c0gRR1M /o=? ez`GL=Y^"{ T"caX$%ܻ2{:&Eai<,%(usyww_G 7lL5Ѓ^^J8}c䞆1ޭ ؁:5LG\.Ajȇ{1Pv!GCZcF\Źm.u|Ѿ.W]% 0SI/ezϕBvTsS zWGN<Eo!ꯌ}*R0`)]>prYks\S[T5Ӎ*Ͱпh _BSk7ڿTMSM /Ni{_u/|OUE[?F0!{lĀ?>Aп =-M'\E딪C\n?R:DUUE.-mjcPKMNG.*,PK C; __MACOSX/UX JJPKC;__MACOSX/._test.pdfUX JJc`cg`b`MLVVP'A @+PK%!(RPKC;MNG.*, @test.pdfUXJJPK C; @At*__MACOSX/UXJJPKC;%!(R @*__MACOSX/._test.pdfUXJJPK$+mail-2.5.4/spec/fixtures/attachments/てすと.txt000066400000000000000000000000411214434061600234210ustar00rootroot00000000000000this is a test これわてすとmail-2.5.4/spec/fixtures/emails/000077500000000000000000000000001214434061600165225ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/attachment_emails/000077500000000000000000000000001214434061600222045ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_content_disposition.eml000066400000000000000000000012261214434061600312120ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-13-196941151 Content-Type: text/x-ruby-script; name="hello.rb" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="api.rb" puts "Hello, world!" gets --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_content_location.eml000066400000000000000000000016701214434061600304610ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-13-196941151 Content-Type: image/jpeg Content-Transfer-Encoding: base64 Content-Location: Photo25.jpg Content-ID: Content-Disposition: inline jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_message_rfc822.eml000066400000000000000000000102221214434061600276220ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-13-196941151 Content-Type: message/rfc822 From xxxx@xxxx.com Tue May 10 11:28:07 2005 Return-Path: X-Original-To: xxxx@xxxx.com Delivered-To: xxxx@xxxx.com Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT) Received: from xxx.xxxxx.com ([127.0.0.1]) by localhost (xxx.xxxxx.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 70060-03 for ; Tue, 10 May 2005 17:26:49 +0000 (GMT) Received: from xxx.xxxxx.com (xxx.xxxxx.com [69.36.39.150]) by xxx.xxxxx.com (Postfix) with ESMTP id 8B957A94B for ; Tue, 10 May 2005 17:26:48 +0000 (GMT) Received: from xxx.xxxxx.com (xxx.xxxxx.com [64.233.184.203]) by xxx.xxxxx.com (Postfix) with ESMTP id 9972514824C for ; Tue, 10 May 2005 12:26:40 -0500 (CDT) Received: by xxx.xxxxx.com with SMTP id 68so1694448wri for ; Tue, 10 May 2005 10:26:40 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=xxxxx.com; h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type; b=g8ZO5ttS6GPEMAz9WxrRk9+9IXBUfQIYsZLL6T88+ECbsXqGIgfGtzJJFn6o9CE3/HMrrIGkN5AisxVFTGXWxWci5YA/7PTVWwPOhJff5BRYQDVNgRKqMl/SMttNrrRElsGJjnD1UyQ/5kQmcBxq2PuZI5Zc47u6CILcuoBcM+A= Received: by 10.54.96.19 with SMTP id t19mr621017wrb; Tue, 10 May 2005 10:26:39 -0700 (PDT) Received: by 10.54.110.5 with HTTP; Tue, 10 May 2005 10:26:39 -0700 (PDT) Message-ID: Date: Tue, 10 May 2005 11:26:39 -0600 From: Test Tester Reply-To: Test Tester To: xxxx@xxxx.com, xxxx@xxxx.com Subject: Another PDF Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_2192_32400445.1115745999735" X-Virus-Scanned: amavisd-new at textdrive.com ------=_Part_2192_32400445.1115745999735 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Just attaching another PDF, here, to see what the message looks like, and to see if I can figure out what is going wrong here. ------=_Part_2192_32400445.1115745999735 Content-Type: application/pdf; name="broken.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="broken.pdf" JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg 1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI 8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw ------=_Part_2192_32400445.1115745999735-- --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_only_email.eml000066400000000000000000000014371214434061600272500ustar00rootroot00000000000000Subject: this message JUST contains an attachment From: Ryan Finnie To: bob@domain.dom Content-Disposition: attachment; filename=blah.gz Content-Transfer-Encoding: base64 Content-Description: Attachment has identical content to above foo.gz Message-Id: <1066974048.4264.62.camel@localhost> Mime-Version: 1.0 Date: 23 Oct 2003 22:40:49 -0700 Content-Type: application/x-gzip; NAME=blah.gz SubjectthismessageJUSTcontainsanattachmentFromRyanFinnierfinniedomaindomTobo bdomaindomContentDispositionattachmentfilenameAblahgzContentTypeapplication/ xgzipnameAblahgzContentTransferEncodingbase64ContentDescriptionAttachmenthas identicalcontenttoabovefoogzMessageId1066974048426462camellocalhostMimeVersi on10Date23Oct20032240490700H4sIAOHBmD8AA4vML1XPyVHISy1LLVJIy8xLUchNVeQCAHbe7 64WAmail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_pdf.eml000066400000000000000000000072021214434061600256650ustar00rootroot00000000000000From xxxx@xxxx.com Tue May 10 11:28:07 2005 Return-Path: X-Original-To: xxxx@xxxx.com Delivered-To: xxxx@xxxx.com Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT) Received: from xxx.xxxxx.com ([127.0.0.1]) by localhost (xxx.xxxxx.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 70060-03 for ; Tue, 10 May 2005 17:26:49 +0000 (GMT) Received: from xxx.xxxxx.com (xxx.xxxxx.com [69.36.39.150]) by xxx.xxxxx.com (Postfix) with ESMTP id 8B957A94B for ; Tue, 10 May 2005 17:26:48 +0000 (GMT) Received: from xxx.xxxxx.com (xxx.xxxxx.com [64.233.184.203]) by xxx.xxxxx.com (Postfix) with ESMTP id 9972514824C for ; Tue, 10 May 2005 12:26:40 -0500 (CDT) Received: by xxx.xxxxx.com with SMTP id 68so1694448wri for ; Tue, 10 May 2005 10:26:40 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=xxxxx.com; h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type; b=g8ZO5ttS6GPEMAz9WxrRk9+9IXBUfQIYsZLL6T88+ECbsXqGIgfGtzJJFn6o9CE3/HMrrIGkN5AisxVFTGXWxWci5YA/7PTVWwPOhJff5BRYQDVNgRKqMl/SMttNrrRElsGJjnD1UyQ/5kQmcBxq2PuZI5Zc47u6CILcuoBcM+A= Received: by 10.54.96.19 with SMTP id t19mr621017wrb; Tue, 10 May 2005 10:26:39 -0700 (PDT) Received: by 10.54.110.5 with HTTP; Tue, 10 May 2005 10:26:39 -0700 (PDT) Message-ID: Date: Tue, 10 May 2005 11:26:39 -0600 From: Test Tester Reply-To: Test Tester To: xxxx@xxxx.com, xxxx@xxxx.com Subject: Another PDF Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_2192_32400445.1115745999735" X-Virus-Scanned: amavisd-new at textdrive.com ------=_Part_2192_32400445.1115745999735 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Just attaching another PDF, here, to see what the message looks like, and to see if I can figure out what is going wrong here. ------=_Part_2192_32400445.1115745999735 Content-Type: application/pdf; name="broken.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="broken.pdf" JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg 1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI 8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw ------=_Part_2192_32400445.1115745999735-- mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_with_encoded_name.eml000066400000000000000000000035101214434061600305460ustar00rootroot00000000000000From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 Return-Path: Message-ID: Date: Sun, 8 May 2005 14:09:11 -0500 From: xxxxxxxxx xxxxxxx Reply-To: xxxxxxxxx xxxxxxx To: xxxxx xxxx Subject: Fwd: Signed email causes file attachments In-Reply-To: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_5028_7368284.1115579351471" References: ------=_Part_5028_7368284.1115579351471 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline We should not include these files or vcards as attachments. ---------- Forwarded message ---------- From: xxxxx xxxxxx Date: May 8, 2005 1:17 PM Subject: Signed email causes file attachments To: xxxxxxx@xxxxxxxxxx.com Hi, Test attachments oddly encoded with japanese charset. ------=_Part_5028_7368284.1115579351471 Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3 Content-Transfer-Encoding: base64 Content-Disposition: attachment MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw ------=_Part_5028_7368284.1115579351471-- mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_with_quoted_filename.eml000066400000000000000000000067611214434061600313210ustar00rootroot00000000000000Return-Path: Received: from ?10.0.1.6? (d36-211-30.home1.cgocable.net [24.36.211.30]) by mx.google.com with ESMTPS id g14sm267889rvb.22.2009.05.13.08.42.03 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 13 May 2009 08:42:04 -0700 (PDT) Message-Id: From: Jeffrey Hardy To: Jeffrey Hardy Content-Type: multipart/mixed; boundary=Apple-Mail-6--218366681 Mime-Version: 1.0 (Apple Message framework v935.3) Subject: =?ISO-8859-1?Q?Eelanal=FC=FCsi_p=E4ring?= Date: Wed, 13 May 2009 11:42:01 -0400 X-Mailer: Apple Mail (2.935.3) --Apple-Mail-6--218366681 Content-Disposition: inline; filename*=ISO-8859-1''Eelanal%FC%FCsi%20p%E4ring.jpg Content-Type: image/jpeg; x-unix-mode=0700; name="=?ISO-8859-1?Q?Eelanal=FC=FCsi_p=E4ring.jpg?=" Content-Transfer-Encoding: base64 /9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAUAAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAAgICAgICAgICAgMCAgIDBAMCAgMEBQQEBAQEBQYFBQUFBQUGBgcHCAcHBgkJCgoJCQwMDAwM DAwMDAwMDAwMDAEDAwMFBAUJBgYJDQsJCw0PDg4ODg8PDAwMDAwPDwwMDAwMDA8MDAwMDAwMDAwM DAwMDAwMDAwMDAwMDAwMDAwM/8AAEQgAMgAyAwERAAIRAQMRAf/EAHsAAAIDAQEAAAAAAAAAAAAA AAgJBgcKBQQBAQAAAAAAAAAAAAAAAAAAAAAQAAEDAwEEBgYIAwkAAAAAAAIBAwQRBQYSADETByEi MjMUCFFhUmM0NUFxYlMVFjYJoUNz8EKSw1SEVRc3EQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIR AxEAPwB9e9aJ0+r17AuTzM/uI4TyUvFzwnCcf/P2a29pwJs2Q8Ua0QpAlw0BSESdlEBouoQ4Yf3U d1V0gsud+5p5lJDs2427Oo0R1uQzwrA3ZreUdGiLrNDxIZuJvoiq4q+hV2C17J+4/wAz7zItFoyh m031ua45IYakW9toyVpdTjJSIjzFDFoTFCFrrKqdRdygY/LXzV8r88uVttplKxpzIHGIlknSyGTb 5ciSStCwMloQNouLRurzQDrXTVF2Bi9hkLJs8Bw6o4jeh1F3oQdUkX11TYOvsArecDn4XIPlU5dL YBHl2YSTsWIkiUCPIdYMilG4qog8FKKO9VLSlKVVAyh5JkF3vkiYXipMlySRuFGZbNwiJXNRF1VJ V+lfpVd9KbgjEt97XJiOG84E6S0kNGV4jchTTiM6g1Ei6x3KNVqlE9GwGd5eeU6czckxgn7zNZnt tlCh2u2SI0QpL0cUZ1q8+yTKqjbqK4yogZaS0qtVoBjT/IP5hsStF+sdgt0O8Qbt4h8bjb58dXzN 4xdIDBxGCbIjTrKiLQk1V6KqDm+RsrL3+WmLs8woTluzyJAZZzCI4bbq/iDdW33EcaqBo6o8TUPQ ur012C3dgU/+7DAu44DygyWI6X4TYchuLMyGSKrT0yVEA42tK0qLTD9K+n69gzzzxt0lGGWXH7U/ NuTXiUQnAKC4BusvtgKUEkIlbLUq1SnoXYJfG/LRsDEkutK6Nkdgybi2BK3IBJBSHHozKFp4zNOJ 7aqpLqQ2y1AyX9v3mfBtPOeFIOYTQZDab45eYchR0NOaWTbfhm32RM20URJVVEMxqqqmwPS/FRlA Jx3ENpymlU3eqmwdfH5Oi6eGqpeKZMiVNycNUXp+utNgnewDJz8xblt5ieVmV8qb3fSsq3ptHbBk bsUlG33OOuqJKoVEIELquAqgptEYagUtSBlP5u4Dk/KjPcrwnOI7MXI8YmAzdoqGbkbiIyhDNhvK gk5GmR+E80ZCimKiqohj1QjN95a8xsZs8TLskwrLcHxDIJCSrFkF9s8+Ha5quNq42sWXIabbeVxs i0aSqooqotOjYCn8neA5ZzB5h24sNnRcZg2/hyFyGY04Qm1GopqDAoiuF0oNEVEXcS/SoaDLDOXE bUxARy4ZBKZBBF15tEekGiL1yRtNI1ovQKL6ERV6NgsHCxu9uUr9fmmhyGc8L94RCTw0FhQVItvF 1VoKABKRovSTpEXsigWp+boH+kkd1xe03v8AZ3/x2AFcozqz4ZFWZklwGC8SCsOztqhTXVcWgEba KvBbVV6TNN1VQV3bACXPnFHPMdZbZnVou9ut+e8vrqdmxmxXditsessCQkngTFADkKb0kifAiVRF lzhIA1I1AyCi2XIrLKzFrMhW1Pw5X/avKq5XF0mpwuI9J4gNynXWzkMPEHhyWPw3QbFsSaIyDYFX 8osrDlbz7Vuyk/dLW7cX4bUZvUjMNE4jjjLaLQT6+pB6dgcVhHMhmcATRVBBAXizVcRGxEOk1Mqo iCCLVVXoTYPTiFwczzmBLz6Qy3Bs9ktXgrHirg1kXBLmqiF5ubSkSMq4xH0w2yEXdFXDoiihBdf4 l70t3C7P8n2vr9e/YFMcxMNy/GbxJZyyM65cJSk+U8H+MkgXSIVdF6q8USVVQtVFqlFRKU2Cvoty uVlkm7BkAZnRp9t8TFt0W+yjoVQxIEKiGNVpVKKnV2CRLcLfn1vlYzPSVZryLSu+ERUF4mFXQT0O QIqD4aqIWmhjVNYgqpsA+XPlZEtV1NuxZLPyJ+xOpGkxZAaWGHWq1jFMaFENxtKK6giSglUMhLo2 A4PLVyizvJguuQlf7HYo0KR+HMyJdtnXQJD7raOSiYjjKhsF4dV0Khkqa1Wu5UUD3x3BYOLtybHa nJMl3IXPGzb1I0JLuF3RSQzkm2AACuNqgtg2Ig2IiAJQUXYKw/Osv/lE+F4vfJ2vvd/e/wAfs7BX vml+a2T5P8Ez2PnneO9r3Hs+vVsAhPfpbJfl/wAVbfivm3874D3f33r4ewRIfhh7zvQ7z+mvw3vP R6tg7y9/D7Hdsd38F3i919j777WwNy5e/o7B/lPy9P058p7R/D/5nvNWwS0OxH3/ABcTd/VXs/b9 GwB9/g/9S/t/s9g//9k= --Apple-Mail-6--218366681--mail-2.5.4/spec/fixtures/emails/attachment_emails/attachment_with_unquoted_name.eml000066400000000000000000000012201214434061600310050ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-13-196941151 Content-Type: text/plain; name=This is a test.txt Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=This is a test.txt Hi there. --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/error_emails/000077500000000000000000000000001214434061600212055ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/error_emails/bad_date_header.eml000066400000000000000000000046041214434061600247430ustar00rootroot00000000000000X-YMAIL-UMID: 1_28022_AGnHtEQAAW9xTQLt8wZPlyfni5U X-Apparently-To: someone@yahoo.com via 68.180.199.105; Fri, 10 Dec 2010 19:20:19 -0800 Received-SPF: pass (mta1007.mail.sp2.yahoo.com: domain of return@reactive-outpost.com designates 74.206.28.55 as permitted sender) X-YMailISG: EfAmUiocZAp0Gt06jFhMyq.RIPUVX9lzgOtsRqYzqYiHPTr1 0fU8Vw4OuGrVz8pSoGW6xDId01O9G9v_HqarLXv8V_3Z9ut5fddpRwyrVOpc 1NYVLhP.FzTcsd9snLKon1z0xEKDX0aWVgu6rOeJ3niXPtE3ubgKne3SWhrc 9Jh34ln.bbeJ52jQ7ToV0m5oC1_T47MCsj._NgxOknVeA1lAJbbtNAEclmXl SQvHnQENVjs9FKYmFsB8d1dSX61CsJq0OMSpC5aqnGFAV2DBPOggUD217rpT n.5Pe5NXv16E0mXO2gNKgtho5W72qSE.1nWBGc5Vl0h8XrXUj._O9Nkajzg2 .klfTThF3zT2ThdTWgFl4lwkNjPKrc1EvlDcd1IPDQYwvMc1SEUpP_lddKwd aQiDt9G9Bu_Nf9vS5T97ZrS6pJJde4U0vrV872UEF.Mj2kpocFr_ba3fC6wP kUO.gj3xw2YQmo3I56NV66VndTOrSya2qAGpkCjkWtT6irAxwXakWlts.EFC iCRmdqsx7CN4UdCJw3vtDc7ASdV5Ty.kKy2GvIrHOFW.gFYGCXM7V0YnXBD1 ho5ePgvP6hGNkrHA9MQzUKq7s6uikRvVPBR7ojjcxqpKOgilKuobsYeuEKZ. kOvWe6P3uZJxV4KVnGfBxCe9SU27RdVpdlWmI3cJc7ut2OfMUoTnI_dVBbK8 1O0tXTco9FYvL8IJfS4RzSnQOw7HDcqF4oNAeghagmlKAuvSCYk19XkqIdDd tzQO1K3DxMIdvS5ut39WQ.LoDu0b6BmFB.YDgUMF6zM3PtgzoJuVumOg1fvh jGf.3v5mgno63PiAoKoBSQkdCdf0GD_jPX1RX_Us405EVLsTjzyjiEno99Vq pxps1ab0rNal.g4Nep2ik_W7TgX6GCxUtZVFoHRbl4rA7gMPIPuF0MF5SkTN jd6vOu6eYRCyCBo_afBI_FkaG6J4gxis8FtAOpUFmXLW7Iwh2uVr4aoiv7ag Ee2U3XYQovYoYtzCsg.iAe97SjJcqINnps0DoC5ky9ijX9WSz4tJj_HgXWAo 2e8gh.25kkMg70QTFOdPONgQe3dF2g9wI7ELcIcMYSyMbvqqAY3OMTigxh9O _7PpaK_qHQ270JbYhnK53ZrNrIIwM1lhBjdjLfNjSaotnLT5.t1BobGskqhz 90CGlOIrzeI2xo_3c8Q.K8hceK_9oxsMP7TyML6J9KaEbV3lW0vHFUxXb21u 4bdKY3KBsxOPCA-- X-Originating-IP: [74.206.28.55] Authentication-Results: mta1007.mail.sp2.yahoo.com from=reactive-outpost.com; domainkeys=neutral (no sig); from=reactive-outpost.com; dkim=neutral (no sig) Received: from 127.0.0.1 (EHLO reactive-outpost.com) (74.206.28.55) by mta1007.mail.sp2.yahoo.com with SMTP; Fri, 10 Dec 2010 19:20:19 -0800 Received: from localhost (127.0.0.1) by reactive-outpost.com id h0calo0n7lgf for ; Fri, 10 Dec 2010 22:08:27 -0800 (envelope-from ) From: "Grants-Notification" Subject: You may_be Eligible for Legitimate_Cash from_GovAgencies! To: someone@yahoo.com Precedence: junk In-Reply-To: someone@yahoo.com Content-Type: text/html ; charest="us-ascii" Content-Transfer-Encoding: 7bit Date:
mail-2.5.4/spec/fixtures/emails/error_emails/bad_date_header2.eml000066400000000000000000000021521214434061600250210ustar00rootroot00000000000000X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0xO0Q9MTtTQ0w9MA== X-Message-Status: n X-SID-PRA: enews@Free-Quilting.com X-AUTH-Result: NONE X-Message-Info: JGTYoYF78jHCcITVD+zs6u3ahcolNfp0m61kNO2SBMwKZtwdSoGZLR+eV3xtqv3QU2mvP3b1AtESP6eCYbaI4dABkTSkMMCjZGPGH3Q01dsRSddQ0kCWDw== Received: from drg.drgnetwork.com ([63.76.155.39]) by col0-mc2-f14.Col0.hotmail.com with Microsoft SMTPSVC(6.0.3790.4675); Tue, 14 Dec 2010 22:59:10 -0800 Received: from SFGAS1.DRGNETWORK.COM (sfgas1.drgnetwork.com [63.76.155.11]) by drg.drgnetwork.com (8.13.8/8.13.8) with ESMTP id oBF6xAuc018214 for ; Wed, 15 Dec 2010 00:59:10 -0600 Message-Id: <201012150659.oBF6xAuc018214@drg.drgnetwork.com> Sender: enews@Free-Quilting.com Date: Wed, 15 Dec 2010 59:10 -0500 From: "Free-Quilting.com" MIME-Version: 1.0 To: cc: Subject: 40% OFF holiday patterns and fabric! Content-Type: multipart/alternative; boundary="--PART.BOUNDARY.0001" Return-Path: bounces@strategicfulfillment.com X-OriginalArrivalTime: 15 Dec 2010 06:59:10.0647 (UTC) FILETIME=[93232C70:01CB9C25] mail-2.5.4/spec/fixtures/emails/error_emails/bad_subject.eml000066400000000000000000000052531214434061600241560ustar00rootroot00000000000000Received: from survey1usmta.mysurvey.com (survey1usmta.mysurvey.com [198.178.238.149]) by mtain-dh02.r1000.mx.aol.com (Internet Inbound) with ESMTP id 35AF9380001BD for ; Wed, 15 Dec 2010 12:22:13 -0500 (EST) Received: from 172.30.44.41 (172.30.44.57) by survey1usmta.mysurvey.com (PowerMTA(TM) v3.5r15) id h13ska0ko6cn for ; Wed, 15 Dec 2010 12:21:20 -0500 (envelope-from ) From: =?UTF-8?B?TXlTdXJ2ZXk=?= =?UTF-8?B?LmNvbSAmIEM=?= =?UTF-8?B?YXJvbCBBZGE=?= =?UTF-8?B?bXM=?= REPLY-TO: carol@reply.mysurvey.com To: someone@aol.com Date: Wed, 15 Dec 2010 12:21:20 -0500 Subject: =?UTF-8?B?TXlTdXJ2ZXk=?= =?UTF-8?B?LmNvbTogIFk=?= =?UTF-8?B?b3UgaGF2ZSA=?= =?UTF-8?B?YSBzdXJ2ZXk=?= =?UTF-8?B?IHdhaXRpbmc=?= =?UTF-8?B?ISAg?= =?UTF-8?Q?91123105?= =?UTF-8?B??= MIME-Version: 1.0 Content-Type: multipart/alternative;boundary="----=_Layout_Part_DC7E1BB5_1105_4DB3_BAE3_2A6208EB099A" x-aol-global-disposition: G X-AOL-SCOLL-SCORE: 1:2:376293952:93952408 X-AOL-SCOLL-URL_COUNT: 5 x-aol-sid: 3039ac1d41164d08f9453480 X-AOL-IP: 198.178.238.149 X-AOL-SPF: domain : mysurvey.com SPF : pass ------=_Layout_Part_DC7E1BB5_1105_4DB3_BAE3_2A6208EB099A Content-type: text/plain;charset="UTF-8" CONTENT-TRANSFER-ENCODING: 8bit You have a survey waiting! To take the survey: ================================================================== Please do not reply to this email, as we do not process emails sent to this address. To view FAQ's or to contact us, please go to our http://www.mysurvey.com/index.cfm?action=Main.lobbyGeneral&MyContent=contact page. ================================================================== You received this email because you (or someone in your household) registered to be a MySurvey.com member. Being a MySurvey.com member means receiving periodic email invitations to give your opinions via e-surveys as well as being eligible for special projects and product tests. If you wish to be removed from the MySurvey.com panel, please click here to http://www.mysurvey.com/index.cfm?action=Main.lobbyGeneral&myContent=unsubscribes. ================================================================== ------=_Layout_Part_DC7E1BB5_1105_4DB3_BAE3_2A6208EB099A Content-type: text/html;charset="UTF-8" CONTENT-TRANSFER-ENCODING: 8bit
hello world
------=_Layout_Part_DC7E1BB5_1105_4DB3_BAE3_2A6208EB099A-- mail-2.5.4/spec/fixtures/emails/error_emails/cant_parse_from.eml000066400000000000000000000020641214434061600250500ustar00rootroot00000000000000Date: Thu, 11 Jun 2009 23:25:02 -0700 From: Apple To: karl.baum@gmail.com Message-Id: <7oh6b1$1clhrjk@badger-vip.apple.com> Subject: Meet the new MacBook Pro family. Now includes 13-inch. Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=mimepart_4b0c353551675_3d1c15b79ea5e70c1783 --mimepart_4b0c353551675_3d1c15b79ea5e70c1783 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: Quoted-printable Content-Disposition: inline From one solid piece of aluminum comes a MacBook Pro that's thin and light,= beautifully streamlined, and durable. --mimepart_4b0c353551675_3d1c15b79ea5e70c1783 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: Quoted-printable Content-Disposition: inline From one solid piece of aluminum comes a MacBook Pro that's thin and light,= beautifully streamlined, and durable.
--mimepart_4b0c353551675_3d1c15b79ea5e70c1783-- mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_7-bit.eml000066400000000000000000000434731214434061600301450ustar00rootroot00000000000000Received: from nahou-mscnx06p.corp.enron.com ([192.168.110.237]) by NAHOU-MSMBX03V.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Thu, 10 Jan 2002 16:10:15 -0600 Received: from NAHOU-MSMSW06P.corp.enron.com ([192.168.110.228]) by nahou-mscnx06p.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Thu, 10 Jan 2002 16:10:14 -0600 Received: from mailman.enron.com (unverified) by NAHOU-MSMSW06P.corp.enron.com (Content Technologies SMTPRS 4.2.5) with ESMTP id for ; Thu, 10 Jan 2002 16:10:13 -0600 Received: from email11.quris.net (email11.quris.net [208.169.17.235]) by mailman.enron.com (8.11.4/8.11.4/corp-1.06) with ESMTP id g0AMAB920109 for ; Thu, 10 Jan 2002 16:10:11 -0600 (CST) Received: from localhost.quris.net (localhost [127.0.0.1]) by email11.quris.net (8.12.1/8.12.1) with SMTP id g0AM9nNk021044 for emclaug@enron.com; Thu, 10 Jan 2002 15:10:08 -0700 (MST) Message-Id: <101BN3c3ce68600277550d@bounce.quris.net> Errors-To: 101BN3c3ce68600277550d@bounce.quris.net From: Discover Card Reply-To: discovercard_newsflash@discover.qrs1.net To: emclaug@enron.com Subject: Discover(R) Card News Online - January 2002 Date: Wed, 9 Jan 2002 19:47:50 MST X-Quris: 8:EC:1440:0:101BN3c3ce68600277550d MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="-----=aaaaaaaaaa0" Return-Path: 101BN3c3ce68600277550d@bounce.quris.net -------=aaaaaaaaaa0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7-bit DISCOVERÆ CARD News Online January 2002 DISCOVER log in to the Account Center Internet ShopCenter(SM) In This Edition: Be Charitable Get Organized Manage Your Finances Better Protect Yourself Save More Money DISCOVERÆ It's a new year and time for new beginnings. Let us help you out with some possible resolutions. Be sure to read on! Be Charitable $1 Million Donated to the Families of Freedom Scholarship Fundô We're happy to announce that the second $1 million for the Discover Card Relief Efforts program, has been donated to the Families of Freedom Scholarship Fund*. Families of Freedom Scholarship Fund(TM) The Fund will benefit children and spouses of airplane crew and passengers, World Trade Center and Pentagon employees and visitors, as well as firefighters, emergency medical and law enforcement personnel affected by the attacks of September 11th. Thanks to you, we're making quick progress toward our goal of $5 million to help America's relief efforts by doing what you do everyday -- using your Discover Card. Learn more about the Discover Card Donation Program. To make a personal donation to the Families of Freedom Scholarship Fund, visit www.familiesoffreedom.org . Return to TOP Get Organized Four More Ways to Manage your Account... Discover Interactive With the Discover Inter@ctive e-mail reminders, it's easier than ever to manage your DiscoverÆ Card Account. In addition to the Discover Inter@ctive e-mail reminders already offered -- there are now four new convenient options that will notify you when: A Balance Transfer has Posted A Merchant Refund or Credit has Posted A Purchase Exceeds a Specified Amount (set by you) The Account Balance Exceeds a Specified Amount (set by you) To view a sample e-mail or to sign up for these new Discover Inter@ctive e-mails, click here today, and start enjoying the benefits right away. Return to TOP Manage Your Finances Better TRANSFER A BALANCE ONLINE Consolidate Your Holiday Balances and Save! Are all those holiday credit balances too much to keep up with? We can make it easier and help you save money! Just transfer those high-rate holiday balances to your Discover Card and get a special balance transfer rate! We can even send you an e-mail when your Balance Transfer has posted to your Discover Card account. Transfer a Balance or Learn more . Return to TOP Protect Yourself KNOW FRAUD(TM) Know Fraud and Keep Your Identity Safe Discover Card is a proud participant in the Know Fraudô campaign, a national initiative led by the Federal Government to prevent identity theft. Learn easy ways to protect your identity, how identity thieves work and more. Get informed! Return to TOP Save More Money Strunk and White Get a special Cashback Bonus award Barnes & Noble.com Get a 7% Cashback BonusÆ award** when you use your Discover Card to buy anything from Barnes & Noble.com. Plus, get FREE SHIPPING when you purchase two or more items in a single order. Hurry and stock up on all books, textbooks, movies, posters, music and more, only at Barnes & Noble.com . Return to TOP IMPORTANT INFORMATION PLEASE DO NOT REPLY TO THIS E-MAIL This e-mail was sent to: emclaug@enron.com You are receiving this e-mail because you are a registered Discover Card Account Center user and have subscribed to receive e-mail newsletters from Discover Card. To unsubscribe click here , log in to the Account Center, and change your settings. To update your e-mail address, or change your Account Center preferences, click here and log in. If you have questions about your Account, please e-mail us through Secure Messages and we will be happy to assist you. Discover Card takes your online security seriously. Enjoy 100% Fraud Protection against unauthorized transactions whenever you use your Discover Card, online or off. So, you can rest easy when you use your Discover Card. We respect your privacy. To view our privacy policy online, visit Discovercard.com * Discover Financial Services is not associated with CSFA. Citizens' Scholarship Foundation of America, Families of Freedom Scholarship Fund and all associated logos are trademarks of Citizens' Scholarship Foundation of America. ** Special Cashback Bonus award Terms and Conditions: For Cardmembers who participate in the Cashback Bonus program. This special Cashback Bonus award is separate from your annual Cashback Bonus award you may receive from Discover Card, and is not part of the Discover Card Cashback Bonus award calculation method. If, as of the date we determine whether you meet the terms of this offer, your Account is closed or delinquent, you will not receive this special Cashback Bonus award. Please allow 6 to 8 weeks for your special Cashback Bonus award to be credited to your Discover Card Account. Offer not transferable. ©2002 Discover Bank. Member FDIC. -------=aaaaaaaaaa0 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: 7-bit DISCOVERÆ CARD News Online January 2002 DISCOVER log in to the Account Center Internet ShopCenter(SM) In This Edition: Be Charitable Get Organized Manage Your Finances Better Protect Yourself Save More Money DISCOVERÆ It's a new year and time for new beginnings. Let us help you out with some possible resolutions. Be sure to read on! Be Charitable $1 Million Donated to the Families of Freedom Scholarship Fundô We're happy to announce that the second $1 million for the Discover Card Relief Efforts program, has been donated to the Families of Freedom Scholarship Fund*. Families of Freedom Scholarship Fund(TM) The Fund will benefit children and spouses of airplane crew and passengers, World Trade Center and Pentagon employees and visitors, as well as firefighters, emergency medical and law enforcement personnel affected by the attacks of September 11th. Thanks to you, we're making quick progress toward our goal of $5 million to help America's relief efforts by doing what you do everyday -- using your Discover Card. Learn more about the Discover Card Donation Program. To make a personal donation to the Families of Freedom Scholarship Fund, visit www.familiesoffreedom.org . Return to TOP Get Organized Four More Ways to Manage your Account... Discover Interactive With the Discover Inter@ctive e-mail reminders, it's easier than ever to manage your DiscoverÆ Card Account. In addition to the Discover Inter@ctive e-mail reminders already offered -- there are now four new convenient options that will notify you when: A Balance Transfer has Posted A Merchant Refund or Credit has Posted A Purchase Exceeds a Specified Amount (set by you) The Account Balance Exceeds a Specified Amount (set by you) To view a sample e-mail or to sign up for these new Discover Inter@ctive e-mails, click here today, and start enjoying the benefits right away. Return to TOP Manage Your Finances Better TRANSFER A BALANCE ONLINE Consolidate Your Holiday Balances and Save! Are all those holiday credit balances too much to keep up with? We can make it easier and help you save money! Just transfer those high-rate holiday balances to your Discover Card and get a special balance transfer rate! We can even send you an e-mail when your Balance Transfer has posted to your Discover Card account. Transfer a Balance or Learn more . Return to TOP Protect Yourself KNOW FRAUD(TM) Know Fraud and Keep Your Identity Safe Discover Card is a proud participant in the Know Fraudô campaign, a national initiative led by the Federal Government to prevent identity theft. Learn easy ways to protect your identity, how identity thieves work and more. Get informed! Return to TOP Save More Money Strunk and White Get a special Cashback Bonus award Barnes & Noble.com Get a 7% Cashback BonusÆ award** when you use your Discover Card to buy anything from Barnes & Noble.com. Plus, get FREE SHIPPING when you purchase two or more items in a single order. Hurry and stock up on all books, textbooks, movies, posters, music and more, only at Barnes & Noble.com . Return to TOP IMPORTANT INFORMATION PLEASE DO NOT REPLY TO THIS E-MAIL This e-mail was sent to: emclaug@enron.com You are receiving this e-mail because you are a registered Discover Card Account Center user and have subscribed to receive e-mail newsletters from Discover Card. To unsubscribe click here , log in to the Account Center, and change your settings. To update your e-mail address, or change your Account Center preferences, click here and log in. If you have questions about your Account, please e-mail us through Secure Messages and we will be happy to assist you. Discover Card takes your online security seriously. Enjoy 100% Fraud Protection against unauthorized transactions whenever you use your Discover Card, online or off. So, you can rest easy when you use your Discover Card. We respect your privacy. To view our privacy policy online, visit Discovercard.com * Discover Financial Services is not associated with CSFA. Citizens' Scholarship Foundation of America, Families of Freedom Scholarship Fund and all associated logos are trademarks of Citizens' Scholarship Foundation of America. ** Special Cashback Bonus award Terms and Conditions: For Cardmembers who participate in the Cashback Bonus program. This special Cashback Bonus award is separate from your annual Cashback Bonus award you may receive from Discover Card, and is not part of the Discover Card Cashback Bonus award calculation method. If, as of the date we determine whether you meet the terms of this offer, your Account is closed or delinquent, you will not receive this special Cashback Bonus award. Please allow 6 to 8 weeks for your special Cashback Bonus award to be credited to your Discover Card Account. Offer not transferable. ©2002 Discover Bank. Member FDIC. -------=aaaaaaaaaa0-- mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_empty.eml000066400000000000000000000043321214434061600303500ustar00rootroot00000000000000Recieved: from nahou-mscnx06p.corp.enron.com ([192.168.110.237]) by NAHOU-MSMBX03V.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Tue, 13 Nov 2001 19:08:16 -0800 Received: from corp.enron.com ([192.168.110.228]) by nahou-mscnx06p.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Tue, 13 Nov 2001 21:07:21 -0600 Received: from mailman.enron.com (unverified) by corp.enron.com (Content Technologies SMTPRS 4.2.1) with ESMTP id for ; Tue, 13 Nov 2001 21:07:19 -0600 Received: from smtp011.mail.yahoo.com (smtp011.mail.yahoo.com [216.136.173.31]) by mailman.enron.com (8.11.4/8.11.4/corp-1.06) with ESMTP id g343Bbl58584 for ; Tue, 13 Nov 2001 21:07:07 -0600 (CST) Received: from unknown (HELO localhost) (youdd5o2o449465@219.133.84.88 with login) by smtp011.mail.yahoo.com with SMTP; Wed, 14 Nov 2001 03:13:54 -0000 MIME-Version: 1.0 From: 3712f2@msa.hinet.net To: brucegemini@yahoo.com.tw Subject: 4d8119¡@(¤j¸ÉªwÄѱM½æ) ¤j®a»¡­^»y ¨C¤éÅ¥MP3 (2004¦~6¤ë¥÷) ÁcÅ餤¤å¥úºÐª© (­^»y±Ð¾Ç)¡@8afb90 BCc: Array Content-Type: text/html; charset="big5" Content-Transfer-Encoding: Message-ID: <11107978796724623> 9bbf38a544f990e73cd12f3c56c60e6180edebd31d752d3997fa4c0650d6aaa338f73f155d5d382832b195b33cbbaa243830c981e12db0c9aac12db9a39836caab5058c0f5efbf326331103f9e1008c106f630fe4d33575efa5d362a28ece62c3fd2a034df2dab92e1f0f664b6179889f4f98a962e2287e336ec652475ccdf7fcdd85f8e025161d8f10c3bd9cc5701c0c7ed1ed84b5b2c01a05eee9e641da8b0

³nÅé«Ò°ê§ó·s¨³³t 06f630fe4d33575efa5d362a28ece62c3fd2a034df2dab92e1f0f664b6179889f4f98a962e2287e336ec652475ccdf7fcdd85f8e025161d8f10c3bd9cc5701c0c7ed1ed84b5b2c01a05eee9e641da8b09bbf38a544f990e73cd12f3c56c60e6180edebd31d752d3997fa4c0650d6aaa338f73f155d5d382832b195b33cbbaa243830c981e12db0c9aac12db9a39836caab5058c0f5efbf326331103f9e1008c1 _______________________________________________________________________ Yahoo! ¤u¨ã¦C - ¤º¸m¨¾¤î¼u¥Xµøµ¡¤u¯à¡I http://toolbar.yahoo.com.hk mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_plain.eml000066400000000000000000000141021214434061600303110ustar00rootroot00000000000000Return-Path: Delivered-To: em-ca-bruceg-spam@em.ca Received: (qmail 32184 invoked by uid 700); 28 Mar 2005 01:14:54 -0000 Delivered-To: em-ca-em-ca-bruceg@em.ca Received: (qmail 32179 invoked by uid 115); 28 Mar 2005 01:14:54 -0000 Received: from baocqccyw@hq.lindsayelec.com by churchill by uid 64011 with qmail-scanner-1.22 (clamdscan: 0.75-1. spamassassin: 2.63. Clear:RC:0(200.141.184.56):. Processed in 10.454045 secs); 28 Mar 2005 01:14:54 -0000 Received: from dial.suednet.com.br (HELO hq.lindsayelec.com) (200.141.184.56) by churchill.factcomp.com with SMTP; 28 Mar 2005 01:14:42 -0000 Return-path: From: shavonda Cabral To: Subject: bookkeeping Get in on IGTS asap. Date: Sun, 27 Mar 2005 19:11:59 -0600 Reply-To: MIME-Version: 1.0 X-Virus-Status: Scanned by norton Message-ID: <41314357824.13240873.93296@oxygen-k19.hq.lindsayelec.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: plain Content-Length: 5102 Lines: 125 acidness Exciting Easter Investor Alert Ticker:IGTS Current:0.01 Rating:Big Mover Next Week This st0ck receives our top rating - 10 out of 10 Breaking NEWS (released last night): Intelligent Sports, Inc. Offers Affordable Alternative This is the first news release the company put out since November - this is going to be exciting stock play Jump on board while you can - Don't regret It later About the Company: Youth And Amateur Sports Company Poised For Growth Intelligent Sports, Inc. is a publicly held company trading on the OTC markets under the ticker symbol ìIGTSî. Intelligent Sports will be the holding company for several sports related businesses. Intelligent Sports provides business units with strategic guidance and support in the areas of marketing, sales, sponsorships, partnerships, policy & procedures, finance and expansion. Their initial business launch is to develop youth and amateur sports centers throughout the country that offers a year-round sports calendar with emphasis on youth and amateur sports programs and skill development. Their plan is to expand this concept into membership-based, multi-purpose sports facilities that will promote a diverse range of sports programs, leagues, tournaments, clinics, individual sports skill development and nutritional training. Fresh News: UPLAND, Calif., Mar 22, 2005 (PRIMEZONE via COMTEX) Participation fees for school sports programs continues to escalate, at the same time record obesity levels in children are being reported by the Center for Disease Control. Intelligent Sports, Inc. (Pink Sheets:IGTS) is working to do their part to curb this alarming trend of by offering affordable fitness centers to kids. "The time when school sports programs had enrollment fees of $10 is fading," said former NBA star and Intelligent Sports, Inc. board member, Reggie Theus. "Not every parent is willing to pay $300 enrollment fees for a sport their child is only casually interested in; some parents can't afford to pay that much for a sport their child excels at." According to the President's Council on Physical Fitness and Sports, only 17 percent of middle and junior high schools and 2 percent of senior high schools require daily physical activity for all students. Hoping to fill the gap, The Sports Zone by Intelligent Sports will support a wide range of membership-based after-school sports programs, weekend leagues and tournaments promoting individual athletic skill development, the concepts of teamwork and discipline, and a love of the game. The Sports Zone opened in early October in Upland, California. It encompasses a 10,000 square foot facility featuring two basketball courts and caters to court sports including basketball, volleyball, cheerleading, and wrestling, and also has the ability to host soccer, football and other field-related athletic activity within the complex arena. +++++++++++++++++++++++++++ IGTS is expected to Explode All Next Week Be Sure To Get It Immediately, and profit big! ++++++++++++++++++++++++++++ Disclaimer This publication is not registered investment advisor, The information presented above is not an offer to buy or sell securities it contains "forward looking statements" within the meaning of Section 27A of the Securities Act of 1933 and Section 21B of the Securities Exchange Act of 1934. Any statements that express or involve discussions with respect to predictions, goals, expectations, beliefs, plans, projections, objectives, assumptions or future events or performance are not statements of historical fact and may be "forward looking statements." In compliance with Section 17(b), the publishers of this report disclose the holding of IGTS shares prior to the publication of this report. Be aware of an inherent conflict of interest resulting from such holdings due to our intent to profit from the liquidation of these shares. Shares may be sold at any time, even after positive statements have been made regarding the above company. Since we own shares, there is an inherent conflict of interest in our statements and opinions. Readers of this publication are cautioned not to place undue reliance on forward looking statements, which are based on certain assumptions and expectations involving various risks and uncertainties, that could cause results to differ materially from those set forth in the forward- looking statements. Please be advised that nothing within this email shall constitute a solicitation or an offer to buy or sell any security mentioned herein. This newsletter is neither a registered investment advisor nor affiliated with any broker or dealer. All statements made are our express opinion only and should be treated as such. We may own, buy and sell any securities mentioned at any time. This report includes forward-looking statements within the meaning of The Private Securities Litigation Reform Act of 1995. This newsletter was paid 41 500, from third party to send this report. Please do your own diligence before investing in any profiled company. You may lose money from investing. caddis worktable mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_qp_with_space.eml000066400000000000000000000035101214434061600320350ustar00rootroot00000000000000Return-Path: Delivered-To: em-ca-bait-precedes@em.ca Received: (qmail 7622 invoked by uid 115); 7 Nov 2004 21:30:59 -0000 Received: from fyouizjnp@swissonline.ch by churchill by uid 64011 with qmail-scanner-1.22 (clamdscan: 0.75-1. spamassassin: 2.63. Clear:RC:0(222.47.112.31):. Processed in 1.163709 secs); 07 Nov 2004 21:30:59 -0000 Received: from unknown (HELO 209.5.178.248) (222.47.112.31) by churchill.factcomp.com with SMTP; 7 Nov 2004 21:30:57 -0000 Message-ID: From: "Wilmer Capps" To: bait-passover@em.ca Subject: Low or High Blood Pressure? We can help. Date: Sun, 07 Nov 2004 18:23:56 -0300 X-Mailer: gene annulus pneumococcus-polyhedral: belgrade hanoverian lima MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_NextPart_000_003A_5008K66J.3Z4LC80J" This is a multi-part message in MIME format. ------=_NextPart_000_003A_5008K66J.3Z4LC80J Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted printable If you're in need of a good RX site for online purchases, we are your answer. With Tens of Thousands of happy customers who saved huge, you can't go wrong. http://magyar8stator.com/26 Lots More Info Here Above URL is for more info & if you are interested. ------=_NextPart_000_003A_5008K66J.3Z4LC80J Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable If you're in need of a good RX site for online purchases, we are your answ= er.

With Tens of Thousands of happy customers who saved huge, you can't go wro= ng.

Lots More Info Here


Above URL is for more info & if you are interested.
------=_NextPart_000_003A_5008K66J.3Z4LC80J-- mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_spam.eml000066400000000000000000000036761214434061600301640ustar00rootroot00000000000000Received: from nahou-mscnx06p.corp.enron.com ([192.168.110.237]) by napdx-msmbx01v.corp.enron.com with Microsoft SMTPSVC(5.0.2195.1600); Sun, 19 Aug 2001 04:06:57 -0800 Received: from corp.enron.com ([192.168.110.226]) by nahou-mscnx06p.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Sun, 19 Aug 2001 06:06:02 -0600 Received: from mailman.enron.com (unverified) by corp.enron.com (Content Technologies SMTPRS 4.2.1) with ESMTP id for ; Sun, 19 Aug 2001 06:04:08 -0600 Received: from poetrix.com ([61.146.170.133]) by mailman.enron.com (8.11.4/8.11.4/corp-1.06) with ESMTP id g343Bbl38716 for ; Sun, 19 Aug 2001 07:03:27 -0500 (CDT) Message-ID: <35FDF82F.D000339@poetrix.com> Date: Sun, 19 Aug 2001 06:31:03 -0700 From: "neal ragland" User-Agent: AspMail 3.06 X-Accept-Language: en-us MIME-Version: 1.0 To: "palmer vladi.Pimenovraud" Suvladi.Pimenovject: For a vladi.Pimenovetter and more promising future just check eke Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7vladi.Pimenovit middagh oldusercompare othermachine one-twist natascha mz05 ntsoft netvladi.Pimenovr We supply high quality medications vladi.Pimenovy mail order at very competitive prices and provide a professional, convenient and affordavladi.Pimenovle means of purchasing your presc_ription medicines online Depresion-an"xiety, Antivladi.Pimenoviotic, Wt Loss, Women's Health, Mus-cle Relaxants, Sleeping Aids, Allergies and Paain Relief. Your tastes will vladi.Pimenove met here with 600 medications Hscearpomh http://fi.com.adherentgood.com/?2NX1q/vladi.Pimenoviayimh more people are using it for quicker rx refill When you're not with me?Well darling Im telling you now Im no good without you anyhowAnd have I told you lately that I love you Or you and I, If I only had wings of a little angel mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_text-html.eml000066400000000000000000000035141214434061600311410ustar00rootroot00000000000000Return-Path: Delivered-To: rait@bruce-guenter.dyndns.org Received: (qmail 12977 invoked from network); 6 May 2005 10:58:40 -0000 Received: from localhost (localhost [127.0.0.1]) by bruce-guenter.dyndns.org ([192.168.1.3]); 06 May 2005 10:58:40 -0000 Received: from zak.futurequest.net ([127.0.0.1]) by localhost ([127.0.0.1]) with SMTP via TCP; 06 May 2005 10:58:40 -0000 Received: (qmail 2252 invoked from network); 6 May 2005 10:58:39 -0000 Received: from lsne-catv-dhcp-29-115.urbanet.ch (unknown [80.238.29.115]) by zak.futurequest.net ([69.5.6.152]) with SMTP via TCP; 06 May 2005 10:58:29 -0000 Received: from mail.datavalet.com (80.238.29.115) by 80.238.29.115 (fairwayv.4) with SMTP id <09166i58p> (Authid: 3811297); Fri, 06 May 2005 10:52:01 -0100 Reply-To: "chianfong cuthbert" From: "chianfong cuthbert" To: cvs@bruce-guenter.dyndns.org Cc: rait@bruce-guenter.dyndns.org Subject: RE: We will help you refinance your home. Date: Fri, 06 May 2005 15:55:01 +0400 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="--651790_269334.01570" Content-Length: 636 Lines: 22 ----651790_269334.01570 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: text/html Hello,

You have qualified for the lowest rate in years.
You could get over $400,000 for as little as $500 a month.
Low rates are fixed no matter what.

Please visit the link below to verify your information:
Approval Form

Best Regards,
chianfong cuthbert, Account Manager
Reynolds Associates, LLC

--------------------
if you received this in error: re-m0-ve ----651790_269334.01570-- mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_with_8bits.eml000066400000000000000000001054251214434061600313030ustar00rootroot00000000000000Recieved: from nahou-mscnx06p.corp.enron.com ([192.168.110.237]) by NAHOU-MSMBX07V.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Wed, 5 Dec 2001 02:00:07 -0600 Received: from corp.enron.com ([192.168.110.226]) by nahou-mscnx06p.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Wed, 5 Dec 2001 02:00:19 -0600 Received: from mailman.enron.com (unverified) by corp.enron.com (Content Technologies SMTPRS 4.2.1) with ESMTP id for ; Wed, 5 Dec 2001 02:00:03 -0600 Received: from mail2.provantage.com (adsl-64-108-84-28.dsl.akrnoh.ameritech.net [64.108.84.28]) by mailman.enron.com (8.11.4/8.11.4/corp-1.06) with ESMTP id fB57xSl15666 for ; Wed, 5 Dec 2001 01:59:29 -0600 (CST) Message-Id: <200112050759.fB57xSl15666@mailman.enron.com> Received: from aaa (W3NEW [65.192.161.22]) by mail2.provantage.com with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2653.13) id XBHNSC17; Tue, 4 Dec 2001 19:27:33 -0500 Date: Tue, 04 Dec 2001 17:11:25 -0459 MIME-Version: 1.0 X-Mailer: J4L-GFIMailer X-Expid: jajenardmeremesyi To: jeff_dasovich@enron.com Subject: The Original Advantage #e13011 Reply-To: announcements@provantage.com X-Priority: 3 X-JMSavedFile: D:\HTML Mailer\Outbound 29457673512957792\mail43379.eml Sender: "announcements@provantage.com" From: "announcements@provantage.com" Content-Transfer-Encoding: 8bits Content-Type: text/html; charset="ISO-8859-1" Return-Path: announcements@provantage.com PROVANTAGE.COM : The Original Advantage


December 04, 2001

Can't read this email? Click here

Issue#: e13011

To unsubscribe from the 
Original Advantage Click here
(Do Not Reply to this email)

PROVANTAGE Customer: jeff_dasovich@enron.com

Holiday Gift Ideas for the Computer Professional!
11Mbps Wireless Cable/DSL Router
By Belkin
The Belkin Wireless Cable/DSL Gateway Router lets you share files and a broadband Internet connection among all your computers-without using cables. It's ...More
  $201.42

Nostromo n45 Dual Analog USB Gamepad
By Belkin
The Nostromo n45 USB game pad's advanced ergonomic design, dual analog and USB-compatibility make the n45 innovative PC game pad to hit the market in years. ...More
  $12.31

New!

Plus! for Windows XP
By Microsoft
Personalize your computer experience like never before.
Built exclusively to take advantage of the power of Windows XP, MS Plus! delivers exciting ...More
  $33.47

iPAQ H3670 Color Pocket PC
By Compaq
You want to do more with life? The iPAQ Pocket PC H3670 is designed to ride along on the voyage of life-in your pocket or mounted to your mountain bike. ...More
  $465.50

FireWire Hub 6-Port
By IOGEAR
IOGEAR's FireWire hubs provide 1394a compliant ports that support data transfer rates of 100, 200 and 400 Mbps (megabits per second), and automatically ...More
  $60.09

HomeConnect 10/100 Mbps Dual Speed Ethernet 5-Port
By 3Com
Share an Internet connection among several computers (Your Internet service provider may charge additional fees.). Surf Web sites, send e-mail, download ...More
  $41.76

New!

Links 2001 Expansion Pack Volume 1
By Microsoft
Join PGA Tour pros Mike Weir & Keith Clearwater on 4 new courses designed for Links 2001:
  • The Canyons Course at Bighorn, Thanksgiving Point ...More
  •   $20.93

    Mavica CD1000 Digital Cam 12Bit 2.1 Pixel 3" CD-R
    By Sony
    Start with a high capacity, 156 MB 3" CD-R plus a high resolution, 2.1 megapixel image sensor. Attach it to a high-powered 52mm 10x optical zoom lens and ...More
      $908.56

    Wireless Bluetooth PC Card
    By 3Com
    Personal Connections - Instantly
    For spontaneous connections between your notebook PC and other Bluetooth devices, as well as "light" network ...More
      $109.31

    MultiSync LCD1830 18in LCD Flat Panel Display
    By NEC/Mitsubishi
    For users who need superior image quality in a small space, the MultiSync LCD Series monitors deliver bright, sharp screen performance in a slim, lightweight ...More
      $833.05

    New!

    MechCommander 2
    By Microsoft
    Take control of an entire company of the most fearsome military machines in history - BattleMechs!
    As a MechCommander, you command a unit of ...More
      $24.02

    DSP-500 Digitally-Enhanced USB Gaming/Multimedia
    By Plantronics
    Plantronics' DSP-500 digitally-enhanced gaming/multimedia headset with full-range stereo sound. Perfect for multimedia applications such as games, CDs ...More
      $78.99

    RipGo! Handheld 4X6 Mini USB CD Burner/MP3 Player
    By Imation
    Whether you're a music enthusiast or a mobile business professional, the Imation RipGO! device will satisfy the creative urges of your imagination. Designed ...More
      $369.96

    CD-RW Drive 16X/10X/40X USB 2.0 Drive w/USB 2.0
    By IOGEAR
    Drive. Unlock the power of the new Hi-Speed USB 2.0. IOGEAR's IMPULSE Drive. Burns at a blazing 16x speed, allowing you to create CDs faster than ever ...More
      $188.54

    Spressa CRX175A-A1 Drive 24x/10x/40x Int EIDE
    By Sony
    Receive a $30 rebate direct from Sony on SNYC97M purchases between 10/01/01 and 12/31/01. ... More
      $145.46

    Digital Voice Recorder w/No Software
    By Sony
    Features Include
  • World's first memory stick Digital voice recorder
  • Uses removable MS (memory stick)
  • Recording time: 63 min (SP)/131 min ...More
  •   $195.68

     
     

    Web Address: www.PROVANTAGE.com 
     Toll Free: 800-336-1166     Fax: 330-494-5260     email: sales@provantage.com


    Privacy Policy
    | Terms & Conditions | FREE Catalog

    ©2001 PROVANTAGE Corporation, 7249 Whipple Ave. NW, North Canton, OH 44720

    Products, prices, terms, conditions, or offers may change at any time. Company and/or product names are generally trademarks, or registered trademarks of their respective companies. Some promotional text may be copyrighted by the product's manufacturer. 
    The Original Advantage promotional email is delivered only to customers of PROVANTAGE Corporation. PROVANTAGE customers have purchased products in the past and submitted their email address as part of the checkout process. Or, customers have entered their name in the "Add to Email List" box on the PROVANTAGE.com home page. Any customer may unsubscribe from the list at any time by going to http://www.provantage.com/unsubscribe.htm. The email address is permanently removed from additional promotional electronic mailings, and will not be reactivated unless requested by the customer.  

    BizRate Customer Certified (GOLD) Site

    mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_with_semi_colon.eml000066400000000000000000000176201214434061600324000ustar00rootroot00000000000000Return-Path: Delivered-To: cvs@bruce-guenter.dyndns.org Received: (qmail 25055 invoked from network); 30 Jun 2005 03:57:11 -0000 Received: from localhost (localhost [127.0.0.1]) by bruce-guenter.dyndns.org ([192.168.1.3]); 30 Jun 2005 03:57:11 -0000 Received: from zak.futurequest.net ([127.0.0.1]) by localhost ([127.0.0.1]) with SMTP via TCP; 30 Jun 2005 03:57:11 -0000 Received: (qmail 20286 invoked from network); 30 Jun 2005 03:57:10 -0000 Received: from mx-host.dot.tk (unknown [220.173.239.48]) by zak.futurequest.net ([69.5.6.152]) with ESMTP via TCP; 30 Jun 2005 03:57:08 -0000 from: "Shelby" To: Subject: Attention Date: Wed, 29 Jun 2005 22:57:10 -0600 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----26473166335893217" X-Mailer: Microsoft Office Outlook, Build 11.0.5510 Thread-Index: AcT9+CUlRgRKMiKZSj+BjT+PHEf8rQ== X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 Content-Length: 7044 Lines: 244 This is a multi-part message in MIME format. ------26473166335893217 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Dear Homeowner, You have been pre-approved for a $402,000 Home Loan at a 3.45% Fixed Rate. This offer is being extended to you unconditionally and your credit is in no way a factor. To take Advantage of this Limited Time opportunity all we ask is that you visit our Website and complete the 1 minute post Approval Form. Enter Here Sincerely, Esteban Tanner Regional CEO Tuuuuurn oooooff notiiificatiiiiions heeeeeeere. ------26473166335893217 Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable;

    Dear Homeowner,

     

    You have been pre-approved for a $402,000 Home Loan at a 3.45% Fixed Rate.

    This offer is being extended to you unconditionally and your credit is in no way a factor.

     

    To take Advantage of this Limited Time opportunity all

    we ask is that you visit our Website and complete

    the 1 minute post Approval Form.

     

    Enter Here

     

    Sincerely,

     

    Esteban Tanner

    Regional CEO

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Tuuuuurn oooooff notiiificatiiiiions heeeeeeere.

    ------26473166335893217-- mail-2.5.4/spec/fixtures/emails/error_emails/content_transfer_encoding_x_uuencode.eml000066400000000000000000000077141214434061600313570ustar00rootroot00000000000000Received: from nahou-mscnx06p.corp.enron.com ([192.168.110.237]) by napdx-msmbx01v.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Thu, 10 Jan 2002 14:12:53 -0800 Received: from NAHOU-MSMSW06P.corp.enron.com ([192.168.110.228]) by nahou-mscnx06p.corp.enron.com with Microsoft SMTPSVC(5.0.2195.2966); Thu, 10 Jan 2002 16:12:52 -0600 Received: from mailman.enron.com (unverified) by NAHOU-MSMSW06P.corp.enron.com (Content Technologies SMTPRS 4.2.5) with ESMTP id ; Thu, 10 Jan 2002 16:12:47 -0600 Received: from tblexch01.transmission.bpa.gov (int.transmission.bpa.gov [206.137.58.133] (may be forged)) by mailman.enron.com (8.11.4/8.11.4/corp-1.06) with ESMTP id g0AMCB920856; Thu, 10 Jan 2002 16:12:11 -0600 (CST) Received: from TBLLIST1 ([206.137.58.134]) by tblexch01.transmission.bpa.gov with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2650.21) id CRWWC3K1; Thu, 10 Jan 2002 14:11:55 -0800 Received: from LIST.TRANSMISSION.BPA.GOV by LIST.TRANSMISSION.BPA.GOV (LISTSERV-TCP/IP release 1.8c) with spool id 2458 for RRGA-L@LIST.TRANSMISSION.BPA.GOV; Thu, 10 Jan 2002 14:13:50 -0800 Received: from [207.202.136.216] (ip136.r2.d.pdx.nwlink.com [207.202.136.136]) by comet.pacifier.com (8.11.2/8.11.1) with ESMTP id g0ALxLX06696; Thu, 10 Jan 2002 13:59:21 -0800 (PST) Mime-Version: 1.0 X-Sender: lpeters@mail.pacifier.com References: <1168BAF252B7D41194810001028D743108913C@SERVER> Content-Type: multipart/mixed; boundary="============_-1201422494==_============" Message-ID: Date: Thu, 10 Jan 2002 13:59:53 -0800 Sender: RTO West Regional Representatives Group From: "Lon L. Peters" Subject: PGP Comments on RTO West Release of Dec. 14 Comments: cc: ltopaz@gcpud.org, gary.zarker@ci.seattle.wa.us, dgodard@gcpud.org, wdobbins@dcpud.org, drobinson@cowlitzpud.org, bgeddes@popud.com, "Culbertson, Tim" , kknitte@gcpud.org, paula.green@ci.seattle.wa.us, jim.harding@ci.seattle.wa.us, ghuhta@cowlitzpud.org, dosborn@gcpud.org, jscheel@popud.com, jim.todd@ci.seattle.wa.us, CWAGERS@dcpud.org, ali.rodol@ci.seattle.wa.us, kevin.clark@ci.seattle.wa.us, bessex@cowlitzpud.org, Cindy.Wright@ci.seattle.wa.us, "Juj, Hardev" , "Conger, Kurt" , "Kindley, Ray" To: RRGA-L@LIST.RTOWEST.ORG In-Reply-To: <1168BAF252B7D41194810001028D743108913C@SERVER> Return-Path: owner-rrga-l@list.rtowest.org --============_-1201422494==_============ Content-Type: text/plain; charset="us-ascii" ; format="flowed" Attached are the comments of the Public Generating Pool. -- _________________________________ Lon L. Peters Northwest Economic Research, Inc. 6765 S.W. Preslynn Drive Portland, Oregon 97225-2668 503-203-1539 (voice) 503-203-1569 (fax) 503-709-5942 (mobile) lpeters@pacifier.com NOTICE: This communication and its attachments, if any, may contain sensitive, privileged, or other confidential information. If you are not the intended recipient or believe that you have received this communication in error, please notify the sender of this communication and delete the copy you received from all storage devices. In addition, please do not print, copy, retransmit, forward, disseminate, or otherwise use this communication or its attachments, if any. Thank you. --============_-1201422494==_============ Content-Id: Content-Type: application/msword; name="PGP_Cmts_on_12-14-01_Pkg.doc" ; x-mac-type="5738424E" ; x-mac-creator="4D535744" Content-Disposition: attachment; filename="PGP_Cmts_on_12-14-01_Pkg.doc" ; modification-date="Thu, 10 Jan 2002 13:58:10 -0800" Content-Transfer-Encoding: x-uuencode --============_-1201422494==_============-- mail-2.5.4/spec/fixtures/emails/error_emails/empty_group_lists.eml000066400000000000000000000254661214434061600255110ustar00rootroot00000000000000Return-Path: Received: from murder ([unix socket]) by i.aaa.net (Cyrus v2.2.12-Invoca-RPM-2.2.12-6.fc4) with LMTPA; Thu, 03 Dec 2009 10:50:45 -0800 X-Sieve: CMU Sieve 2.2 Received: from smtp.aaa.org (unknown [10.1.1.254]) by i.aaa.net (Postfix) with ESMTP id B789577FFC for ; Thu, 3 Dec 2009 10:50:44 -0800 (PST) Received: from imr-f9b5566049f9cb01.prolexic.com (unknown [10.2.2.254]) by smtp.aaa.org (Postfix) with ESMTP id 6B026D64546 for ; Thu, 3 Dec 2009 12:08:32 -0800 (PST) Received: from web82107.mail.mud.yahoo.com (web82107.mail.mud.yahoo.com [209.191.84.220]) by imr-f9b5566049f9cb01.prolexic.com (Postfix) with SMTP id 6B5392BA0459 for ; Thu, 3 Dec 2009 10:50:23 -0800 (PST) Received: (qmail 85490 invoked by uid 60001); 3 Dec 2009 18:50:22 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sbcglobal.net; s=s1024; t=1259866222; bh=aBaCpZTcwSmyoRxhnNZNc5KV/Eb3zHvR3BG0svTu0C0=; h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type; b=cREZCCsrtGfOYR9ckj97DV792GZUX/4Hktzlm5+WBuxdD8Q4XpjRz7dZ1Rei9JOKH8gseoE6KqujBA7EulWGx/XPX5TlDxgO8c2Vk3ae/Qeh38bDJ8MZXRc3dU1w+IMykQyU+qfFKHjkS1sTE7qcmheL1JsTs+BAXtyyqJL+J+4= DomainKey-Signature:a=rsa-sha1; q=dns; c=nofws; s=s1024; d=sbcglobal.net; h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type; b=nvmIZcXhl5ZMIwmDabz/TSUlgtHH5VdCGrTn1U6/zkGM1pZvwJgq/BMbY+5o+mwlMz78DrUT9TJwfx48JDz8j4swqWh1dlEfztr4S18hgoVt7RqeuIxGOfOEpa6jlzbgE04EQcKy9ePZsSgOv97IH1Oh8HU7MxPUj1KO9NaKsTA=; Message-ID: <203751.85280.qm@web82107.mail.mud.yahoo.com> X-YMail-OSG: M3VWGGoVM1mRrN0VVqOo_OuQD_g7jcvHWnqhUlpmVpXhEVZvd0t2zfR8Zvl5BY34dERYPAO_SdtSjPrdGHXgu8LQ7s1z74yCasGWj5jLvgVb.l8helkzU2RuUVfjxzO5AxztzNz1gt0nMG0iY4LrYoHWj1fvC6iduhm_H7LRUzBa5MezeY8soTyY1i0ugmXCgsAYu3etOBvYfwqnNmJmRBBgrgu7LB5aXqiQFTWhxKirD7cQrygLK3QPv7r4utOXt2viJDLFBgITADv.ZMOV5HL7VexNpvTIgDDxfYhDLy8F.h8nTquqIYSUUv5eMZUSbEml.QvSrtj5tjuryeWcIFTL6bHTwDBKNq_0gcEZWWbF_g6XiTjcGPVNDlVXVzni3DMOlt8_cscWGy95q_y2ArbGRrJLO5.0OQPdi6uxNIN.qXGwlijACJTlnpd1_k._CkT5_ivRiof0WAcmszBifAA8PLImnre40_vLQfGQN3cN0QfyYgv_dgVaXBhwkeuBfnthQugsAUbBcifuS7ymi37vSSTYpJ.nuHinkBsm8fVBr3FXNGZXB.YtpcxSSbvhimTtoZviodhD7zG2a1oE.X0GUT6FmsnUwVZPZkw0n_17m9.SSe8Qok8YXc9xfTKJyQAtn2yoMrS5.zMMhoQ8h26dmiXyv2N7V5SjOBYCc7ynqi7H6yPWe7FHQls_arY8vzF8xiC1THpiXJkiN4JHScNPk8aVxwY8L278d3RwSdTKa6CjDw1eIxu9XanW.eB0x3t6_VmuNcDRjhTG022kURXkA6x.UuCrKdP0eiVnSXFI0KiI9Xzhg1AMoiMPZRYDQneEPkgtMw.PJePhfVrOo.svKrGzuk5dG6PDHIqTSmd8MwlhZ56eTsDrakeo3ooVoRW_4oi9vyc7LVaJ32shn5mD5RwNyKhPHvzCAVCc3tc_AwkNqoEehTKOaxWuZc_jVuVB4bjJZsXPGeDqh FuKqBNQHUzr8v6AeX3grpz3M_0jE2qPES2GbJEItyat4WrVzA4SerkByWZHS9xNj.j_xbqdnVznbAdftUA4GFjQMZZql1KgFqrOHnhNkp6Z1QO7IQjCDaVwTATJ5h5uEFbKdmr1QPmmFNbFQub.HwmfikVgWNBn90wUKS2CsJf2IEOHSOicDzIMoC6PWzjCXGGZHZMRcSmtaIXkZ4UYELtiQQCBRgZWh7mhV6wjjbxLE0xv5.lKPSsLzql8COylkhrnoVF2jckLWroGXHsFtEQ5qD2nhDmN.ZlJJ01c1BdE2rGCKbKNfh9qvqXYA0kt9TsfO.H_sp7NWKZmFVnVrGbszkg6xXs4Bo1ITBjxzITVenK_WwO_YPXUV2cHNAXFP88bhiRvKSS31GxaT12QR4RHrWqe0ZjkgfoO.jK9ysUx3NnVSmiDzmnENJAoYbO1Sf8JDVj5yDSCyMxvL4iI7xUBHIzq.lpr6yk1IRkE5074pxlITkHejyzljPbzIUF6OWg95Edlro_QjIQHGeEE1EzNE_JrscrjDYX6mW40CCLFu7ImZVuFmwxC11sC5MIj4KUp8TYSNj2n0WVcTt4jXzSOB4eOlRxtE9dDo3wACeEXc_dzD2BjIOpfUYnIUw2xgRN7wFpd4z6EQ2g3eEv6ny7x9sd0SEh36xG0ZC0juI7Qp0Rj6_1A_YBiIY0AODUdtV1vVuWLTq82Fj0xOhH7I5c03ZYRcJoQBpuc4GDnU.wCi3n.eb1_oHaocDz0E6b6UkpGBB.2d1SXx6BOVu1DEdm6KSg3BUeDld.GzUOUKtWbzyOYdPdedcTa4gljnujUb5tCkjpgEmz_iP0GCs7SYbTcj6AIQxAliexrcdQeNxqxS7hlNOwQmsSGyjufJ7Xrq_NnTp8cWCNUhgmtb4r_gcUjOnPJoz.YpZ8asjZ.uZOgHXpmPIsZL1gozfp_rqYzkx3NYJ8S47IMD84Fa3iVco5SWXVlUx pF_rRHgvkNQtdMaVU5YZdEGr6OlG.CTrAlZa0IoZ0HgFtB_Lg_ Received: from [41.222.192.69] by web82107.mail.mud.yahoo.com via HTTP; Thu, 03 Dec 2009 10:50:22 PST X-Mailer: YahooMailClassic/8.1.6 YahooMailWebService/0.8.100.260964 Date: Thu, 3 Dec 2009 10:50:22 -0800 (PST) From: Cecil Edwards Reply-To: western.uniontransfer1@hotmail.fr Subject: Western Union Swift Money Transfer To: undisclosed recipients: ; MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="0-2052022825-1259866222=:85280" X-CSI-MailScanner-Information: Please contact the ISP for more information X-CSI-MailScanner: Found to be clean X-CSI-MailScanner-SpamCheck: spam, ORDB-RBL X-CSI-MailScanner-From: ceciledwards@sbcglobal.net X-Spam-Status: Yes --0-2052022825-1259866222=:85280 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable Attention Beneficiary: =A0 This is to officially informed you that we have concluded arrangements to e= ffect your payment of $1,500,000.00 United States Dollars through WESTERN U= NION Swift Money transfer services today, but the maximum amount you will b= e receiving every day starting from tomorrow is $5,000.00 as reflected in o= ur transfer system daily until the funds is completely transferred. =A0 This special arrangement is being used to avoid all scrupulous demands by b= oth the states and federal authorities that have previously delayed your pa= yment till date; we shall need your maximum co-operation to ensure that str= ictness and confidence is maintained to avoid any further delays.You are to= discard any request asking you to send money to any agency such as courier= company,Bank and Security Agency as there are no such and any money commit= ted their will be regret, so be wise.=20 =A0 Please contact the Accredited WESTERN UNION Agent for the details of your f= irst payment of $5,000 United States Dollars and reconfirm your correct det= ails that you will like the first transfer to be program with such as Recei= vers Name, destination where you will like the transfer to be send to and y= our cell phone number for urgent communication if the need arise. Fill your details below for reference purposes: *NAME OF CUSTOMER: ......... *ADDRESS: .......... *COUNTRY: ................. *TEL: ..................... *OCCUPATION: .............. =A0 Remember your obligation to secure an International Remittance Form as stat= ed in United Nation act of (FRT209) that will help build and renew your tra= nsfer file for record keeping as a way of checkmating the present Economics= crisis situations. Contact the below Electronic Transfer unit of WESTERN UNION for immediate p= rograming of your first transfer: =A0 Name: Rev.John Ntepe Mobile:+229 97292685 Email: (western.union1891@live.fr) or (westerrnunion_2@sify.com) =A0 Regards. Thanks and God Bless. Mrs.Cecil Edward --=20 Filter4: This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. --0-2052022825-1259866222=:85280 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: quoted-printable
    Attention = Beneficiary:
     
    This is to officially informed you that we have concluded= arrangements to effect your payment of $1,500,000.00 United States Dollars= through WESTERN UNION Swift Money transfer services today, but the maximum= amount you will be receiving every day starting from tomorrow is $5,000.00= as reflected in our transfer system daily until the funds is completely tr= ansferred.
     
    This special arrangement is being used to avoid all scrupul= ous demands by both the states and federal authorities that have previously= delayed your payment till date; we shall need your maximum co-operation to ensure that strictne= ss and confidence is maintained to avoid any further delays.You are to disc= ard any request asking you to send money to any agency such as courier comp= any,Bank and Security Agency as there are no such and any money committed t= heir will be regret, so be wise.
     
    Please contact the Accredited WESTER= N UNION Agent for the details of your first payment of $5,000 United States= Dollars and reconfirm your correct details that you will like the first tr= ansfer to be program with such as Receivers Name, destination where you wil= l like the transfer to be send to and your cell phone number for urgent com= munication if the need arise.
    Fill your details below for reference purposes:
    *NAME OF CUSTOMER: .........
    *ADDRESS: ..........
    *COUNTRY: ......= ............
    *TEL: .....................
    *OCCUPATION: .............. 
    Reme= mber your obligation to secure an International Remittance Form as stated i= n United Nation act of (FRT209) that will help build and renew your transfe= r file for record keeping as a way of checkmating the present Economics cri= sis situations.
    Contact the below Electronic Transfer unit of WESTERN UNION for immediate programing o= f your first transfer:
     
    Name: Rev.John Ntepe

    Mobile:+229 97292685
    Email= : (western.union1891@live.fr) or (westerrnunion_2@sify.com)

     
    Regards.
    Thanks and God Bless.

    Mrs.Cecil Edward


    --=20
    This message has been scanned for viruses and
    dangerous content by MailScanner, and is
    believed to be clean. --0-2052022825-1259866222=:85280-- mail-2.5.4/spec/fixtures/emails/error_emails/empty_in_reply_to.eml000066400000000000000000000044361214434061600254540ustar00rootroot00000000000000Return-path: Envelope-to: abuser@r.ru Delivery-date: Sat, 19 Sep 2009 21:41:40 +0400 Received: from mail-fx0-f215.google.com ([209.85.220.215]:39047) by mail.rg.com with esmtp id 1Mp3wA-0007kA-Ic for ; Sat, 19 Sep 2009 21:41:30 +0400 Received: by fxm11 with SMTP id 11so1412272fxm.15 for ; Sat, 19 Sep 2009 10:40:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:subject:date :message-id:mime-version:content-type:x-priority:x-msmail-priority :x-mailer:importance:x-mimeole:in-reply-to; bh=U4LmZ2XrYxpE2gzziKYLSJXvmTsl0JSdrp4OYcIw2xw=; b=N4ZFNsnhqgG0qILwgjv0Sh0qKgSR+A5hMn60yxtSlACUDq/xQ/52pJkCuMChX0Pzxo HaRYdiAsxyzlzmSStwtM/fAHZSNrXD0pLpeQOCi1r8ZSyQ6mKb4WgO56FFNOjCA0rLl8 NOelymNmCIYTwuYz5Dd0PthnWL0YZPU+YUEHU= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:subject:date:message-id:mime-version:content-type :x-priority:x-msmail-priority:x-mailer:importance:x-mimeole :in-reply-to; b=ZTs05s6OpCmZp0GWYqGIv8xGM+AmM7+QL6SdaR45KgwCcN8sJH0SB4PI4QMFSW3+ZX IdYVUGjqer/bEz7POPS8FOTCZW1QTkRcTHqVEFezAmotlc0VfLVSnnW9oRpzJ/UFQUWM +Wn0vcObiGmrUPUJWWiNgBvuRnrJHk+nICCQI= Received: by 10.86.240.9 with SMTP id n9mr2799028fgh.70.1253375382709; Sat, 19 Sep 2009 08:49:42 -0700 (PDT) Return-Path: Received: from articondell (ppp85-140-104-88.pppoe.mtu-net.ru [85.140.104.88]) by mx.google.com with ESMTPS id e11sm2485072fga.21.2009.09.19.08.49.39 (version=SSLv3 cipher=RC4-MD5); Sat, 19 Sep 2009 08:49:40 -0700 (PDT) From: "Andrey Kuznetsov" To: Subject: illegal copy of our patient education software Date: Sat, 19 Sep 2009 19:49:36 +0400 Message-ID: MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_NextPart_000_000A_01CA3962.51E52370" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook, Build 10.0.4024 Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.5579 In-Reply-To: Recivied-SPF: (invalid) RSpam-Score: 40 List-Id: abuser@rg.com Mailing List Reply-To: ak@g.com mail-2.5.4/spec/fixtures/emails/error_emails/encoding_madness.eml000066400000000000000000000033511214434061600252060ustar00rootroot00000000000000Delivered-To: e-f5f4@app.ar-example.com Received: by 10.2.1.1 with SMTP id p21cs62610wem; Wed, 22 Sep 2010 00:30:55 -0700 (PDT) Received: by 10.15.2.1 with SMTP id p24mr499372ybh.380.1285140655013; Wed, 22 Sep 2010 00:30:55 -0700 (PDT) Return-Path: Received: from aquila.el-example.org ([174.1.8.2]) by mx.google.com with ESMTP id a6si11272839ybo.18.2010.09.22.00.30.54; Wed, 22 Sep 2010 00:30:54 -0700 (PDT) Received-SPF: neutral (google.com: 174.1.8.2 is neither permitted nor denied by best guess record for domain of production@aquila.el-example.org) client-ip=174.1.8.2; Authentication-Results: mx.google.com; spf=neutral (google.com: 174.1.8.2 is neither permitted nor denied by best guess record for domain of production@aquila.el-example.org) smtp.mail=production@aquila.el-example.org Received: from aquila.el-example.org (localhost [127.0.0.1]) by aquila.el-example.org (8.14.2/8.14.2) with ESMTP id o8M7UrfD018673 for ; Wed, 22 Sep 2010 02:30:54 -0500 (CDT) (envelope-from production@aquila.el-example.org) Received: (from production@localhost) by aquila.el-example.org (8.14.2/8.14.2/Submit) id o8M7Urh3018672; Wed, 22 Sep 2010 02:30:53 -0500 (CDT) (envelope-from production) Message-Id: <201009220730.o8M7Urh3018672@aquila.el-example.org> MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-Mailer: MIME::Lite 3.027 (F2.74; T1.28; A2.04; B3.07; Q3.07) Date: Wed, 22 Sep 2010 02:30:53 -0500 From: no-reply@crm.el-example.org To: e-f5f4@app.ar-example.com Reply-To: "KLAUS- HÄNSCHEL" <> Subject: eBay Bid - 2008 Ford Super Duty F-350 DRW King Ranch Crew Cab 4x4 (156) - Stock# XXXX Body Textmail-2.5.4/spec/fixtures/emails/error_emails/header_fields_with_empty_values.eml000066400000000000000000000025301214434061600303120ustar00rootroot00000000000000Received: from mx01.medieveven.no (192.168.42.42) by epost.vartland.no (192.168.73.7) with Microsoft SMTP Server id 8.1.393.1; Fri, 30 Oct 2009 20:08:07 +0100 Received: from woodward.joyent.us ([8.12.42.230]) by mx01.medieveven.no with ESMTP; 30 Oct 2009 20:11:23 +0100 Received: from [10.0.0.5] (ti0083a340-0282.bb.online.no [88.89.59.28]) by woodward.joyent.us (Postfix) with ESMTPSA id EC35240C85 for ; Fri, 30 Oct 2009 19:07:44 +0000 (GMT) From: =?iso-8859-1?Q?J=F8rn_St=F8ylen?= To: AF Test Date: Fri, 30 Oct 2009 20:07:42 +0100 Subject: Testmail Thread-Topic: Testmail Thread-Index: AcpZlFLF/Y9EfcC0QZKKEuUFm2Snqw== Message-ID: <4FDC124A-1FC4-4B29-8502-E459BD9AB397@prikkprikkprikk.no> Accept-Language: nb-NO X-MS-Exchange-Organization-AuthAs: Anonymous X-MS-Exchange-Organization-AuthSource: epost.vartland.no X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ironport-anti-spam-filtered: true x-ironport-av: E=Sophos;i="4.44,655,1249250400"; d="scan'208";a="2439461" x-ironport-anti-spam-result: AvMBAPfV6koIDCrmhWdsb2JhbACbVgEBAQoLChoDxH2EPQQ Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 -- J=F8rn St=F8ylen -- http://www.prikkprikkprikk.no 924 38 051 -- jorn@prikkprikkprikk.no mail-2.5.4/spec/fixtures/emails/error_emails/missing_body.eml000066400000000000000000000007431214434061600243760ustar00rootroot00000000000000Message-ID: <001301c17797$9cd0ef30$a3ab620c@vaio> From: "SCS_2" To: Subject: REDACTED Date: Tue, 27 Nov 2001 15:02:35 -0800 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_000F_01C17754.8C3CAF30" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.2919.6700 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700 Return-Path: redacted@attglobal.net mail-2.5.4/spec/fixtures/emails/error_emails/missing_content_disposition.eml000066400000000000000000000043671214434061600275450ustar00rootroot00000000000000Message-Id: <200201221435.g0MEZP927213@mailman.enron.com> Content-Type: multipart/related; boundary="_----------=_10117101281980" MIME-Version: 1.0 Date: Tue, 22 Jan 2002 14:35:28 UT Subject: Redacted To: redacted@example.com From: redacted@example.com Return-Path: redacted@example.com --_----------=_10117101281980 Content-Location: somefile.jpg Content-Transfer-Encoding: base64 Content-Type: image/jpg Content-Disposition: Date: Tue, 22 Jan 2002 14:35:28 UT X-Mailer: MIME-Version: ICAKIApUaGFuayB5b3UgZm9yIHVzaW5nIG91ciBhdXRvbWF0ZWQgc2VsZiBzZXJ2aWNlIHBhc3N3 b3JkIHJlc2V0IG9wdGlvbi4gICAgCiAKVGhlIHVzZXIgaWQgYW5kIHBhc3N3b3JkIGluIFNBUCAo QXBvbGxvIFByb2R1Y3Rpb24gYW5kIEhSIFByb2R1Y3Rpb24pLCBlSFJvbmxpbmUsIGlCdXlpdCBh bmQgaVBheWl0IGFyZSBhbGwgc3luY2hyb25pemVkLiAgV2hlbiB5b3UgcmVzZXQgeW91ciBwYXNz d29yZCBpbiBlSFJvbmxpbmUsIGl0IGF1dG9tYXRpY2FsbHkgc3luY2hyb25pemVzIHRoZSBwYXNz d29yZCBpbiB0aGUgb3RoZXIgc3lzdGVtcy4gIAogClBsZWFzZSBmb2xsb3cgdGhlIHN0ZXBzIHRv IHJlc2V0IGFuZCBzeW5jaHJvbml6ZSB5b3VyIHBhc3N3b3Jkcy4KIAoxLiAgICAgICAgR28gdG8g ZWhyb25saW5lLmVucm9uLmNvbQoyLiAgICAgICBDbGljayBvbiB0aGUgICBidXR0b24KMy4gICAg ICAgRW50ZXIgeW91ciBVc2VyIElkIChTQVAgUGVyc29ubmVsIE51bWJlcikgYW5kIHRlbXBvcmFy eSBwYXNzd29yZCAobG9jYXRlZCBhdCB0aGUgYm90dG9tIG9mIHRoaXMgZW1haWwpCjQuICAgICAg IFlvdSB3aWxsIHRoZW4gYmUgYXNrZWQgdG8gY2hhbmdlIHlvdXIgcGFzc3dvcmQKNS4gICAgICAg RW50ZXIgeW91ciBuZXcgcGFzc3dvcmQgdHdpY2UKNi4gICAgICAgT25jZSB5b3UgaGF2ZSBzdWNj ZXNzZnVsbHkgY2hhbmdlZCB5b3VyIHBhc3N3b3JkIGluIGVIUm9ubGluZSwgeW91IGhhdmUgc3lu Y2hyb25pemVkIHlvdXIgcGFzc3dvcmQgZm9yIFNBUCAoQXBvbGxvIFByb2R1Y3Rpb24gYW5kIEhS IFByb2R1Y3Rpb24pLCBlSFJvbmxpbmUsIGlCdXlpdCBhbmQgaVBheWl0CjcuICAgICAgIElmIHlv dSB3ZXJlIHRyeWluZyB0byBhY2Nlc3MgYW4gYXBwbGljYXRpb24gb3RoZXIgdGhhbiBlSFJvbmxp bmUsIGNsb3NlIGVIUm9ubGluZSBhbmQgcHJvY2VlZCB0byB0aGUgZGVzaXJlZCBhcHBsaWNhdGlv bi4gIFlvdSB3aWxsIG5vdyBiZSBhYmxlIHRvIGxvZyBpbiB3aXRoIHlvdXIgTkVXIHBhc3N3b3Jk LgogCiBUSElTIElTIEEgR0VORVJBVEVEIEVNQUlMIC0gRE8gTk9UIFJFUExZIQogCklGIFlPVSBO RUVEIEZVUlRIRVIgQVNTSVNUQU5DRSwgQ09OVEFDVCBUSEUgSVNDIEhFTFAgREVTSyBBVDogIDcx My0zNDUtNDcyNwogClRoZSBwYXNzd29yZCBmb3IgeW91ciBhY2NvdW50OiBQMDA1MDA1NTMgICBo YXMgYmVlbiByZXNldCB0bzogMTIyODIyNjYgIAogCkdvIHRvIGVIUm9ubGluZSBub3c6IGh0dHA6 Ly9laHJvbmxpbmUuZW5yb24uY29tIDxodHRwczovL2Vocm9ubGluZS5lbnJvbi5jb20vPiAgIAoK --_----------=_10117101281980-- mail-2.5.4/spec/fixtures/emails/error_emails/multiple_content_types.eml000066400000000000000000000010611214434061600265130ustar00rootroot00000000000000From: Subject: Redacted To: Message-ID: <105647271315.NCV17523@x263.net> MIME-version: 1.0 Content-Type: multipart/alternative; boundary="----_001_5973_47T00ZN9.15SY2428" Content-type: text/plain This is a multi-part message in MIME format. ------_001_5973_47T00ZN9.15SY2428 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7Bit foo ------_001_5973_47T00ZN9.15SY2428 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 7Bit

    foo

    ------_001_5973_47T00ZN9.15SY2428-- mail-2.5.4/spec/fixtures/emails/error_emails/must_supply_encoding.eml000066400000000000000000000013631214434061600261610ustar00rootroot00000000000000X-YMAIL-UMID: 1_132725_AEe3iGIAAGS4TOAfWQ3foSiBC54 X-Apparently-To: anyone@yahoo.com via 98.136.183.71; Sun, 14 Nov 2010 09:41:45 -0800 Message-Id: <201011141741.oAEHfiKs020181@app9.msg2u.net> MIME-Version: 1.0 Content-Transfer-Encoding: binary Content-Type: multipart/alternative; boundary="_----------=_128975650412616235" X-Mailer: MIME::Lite 3.020 (F2.73; T1.21; A1.77; B3.01; Q3.01) Date: Sun, 14 Nov 2010 17:41:44 +0000 From: Biz Phone Systems from EclipseMediaOnline�� To: anyone@YAHOO.COM Subject: Impress your clients with a business phone��� Reply-To: Biz Phone Systems from EclipseMediaOnline�� <44.41.17.14.11.2010.1139.1.328.1477949.614@reply.here2there-travelers-msgs.net> mail-2.5.4/spec/fixtures/emails/error_emails/new_line_in_to_header.eml000066400000000000000000000027101214434061600262040ustar00rootroot00000000000000Delivered-To: e-s-a-g-8718@app.ar.com Received: by 10.2.1.1 with SMTP id c60cs12954wel; Wed, 13 Oct 2010 07:44:39 -0700 (PDT) Received: by 10.15.1.1 with SMTP id f12mr1139775ybe.360.1286981078364; Wed, 13 Oct 2010 07:44:38 -0700 (PDT) Return-Path: Received: from services.travidiabamboo.com (services.travidiabamboo.com [72.21.1.1]) by mx.google.com with ESMTP id v33si16714378yba.88.2010.10.13.07.44.37; Wed, 13 Oct 2010 07:44:38 -0700 (PDT) Received-SPF: pass (google.com: domain of l@gcn-example.com designates 72.21.1.1 as permitted sender) client-ip=72.21.1.1; Authentication-Results: mx.google.com; spf=pass (google.com: domain of l@gcn-example.com designates 72.21.1.1 as permitted sender) smtp.mail=l@gcn-example.com Received: from travidiabamboo.com (services [10.0.0.2]) by services.travidiabamboo.com (Postfix) with ESMTP id A532170702; Wed, 13 Oct 2010 07:53:04 -0700 (PDT) Date: Wed, 13 Oct 2010 07:53:04 -0700 From: l@gcn-example.com To: leads@sg.dc.com, sag@leads.gs.ry.com, sn@example-hotmail.com, e-s-a-g-8718@app.ar.com, jp@t-exmaple.com, cc@c-l-example.com Message-Id: <4cb5c7d0a3cce_120e..fdbed2b861958562@s.t-example.com.tmail> Subject: [Online Lead] Online Lead #1111111 Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 2010-10-13T07:53:04-09:00 ... (not important) ...mail-2.5.4/spec/fixtures/emails/error_emails/trademark_character_in_subject.eml000066400000000000000000000035351214434061600301050ustar00rootroot00000000000000Delivered-To: e-r-w-a-4462@app.ar.com Received: by 10.1.1.1 with SMTP id w10cs10896muo; Tue, 12 Oct 2010 13:20:24 -0700 (PDT) Received: by 10.2.1.5 with SMTP id bk15mr6105827qab.89.1286914824124; Tue, 12 Oct 2010 13:20:24 -0700 (PDT) Return-Path: Received: from mail.ga-example.com (mail.ga-example.com [64.1.2.3]) by mx.google.com with ESMTP id 13si112341247qcd.23.2010.10.12.13.20.23; Tue, 12 Oct 2010 13:20:24 -0700 (PDT) Received-SPF: neutral (google.com: 64.1.2.3 is neither permitted nor denied by best guess record for domain of j@yahoo-example.com) client-ip=64.1.2.3; Authentication-Results: mx.google.com; spf=neutral (google.com: 64.1.2.3 is neither permitted nor denied by best guess record for domain of j@yahoo-example.com) smtp.mail=j@yahoo-example.com X-MDAV-Processed: mail.ga-example.com, Tue, 12 Oct 2010 16:21:07 -0400 X-Spam-Processed: mail.ga-example.com, Tue, 12 Oct 2010 16:21:06 -0400 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on MAIL02.VD-example.com X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,DATE_IN_PAST_03_06, FORGED_YAHOO_RCVD,INVALID_DATE,NO_RELAYS,SUBJECT_NEEDS_ENCODING shortcircuit=no autolearn=no version=3.2.5 Received: from GAWWW03 by ga-example.com (MDaemon PRO v11.0.3) with ESMTP id md50004804310.msg for ; Tue, 12 Oct 2010 16:21:05 -0400 X-MDRemoteIP: 192.168.254.73 X-Return-Path: j@yahoo-example.com X-Envelope-From: j@yahoo-example.com X-MDaemon-Deliver-To: e-r-w-a-4462@app.ar.com Date: Tue, 12 Oct 2010 16:21:05 H0500 Subject: GA.comô has a lead for you To: c@ra-example.com,e-r-w-a-4462@app.ar.com,leads@ga-example.com MIME-Version: 1.0 Content-type: text/plain; charset=iso-8859-1 From: j@yahoo-example.com Message-ID: Body Text - not importantmail-2.5.4/spec/fixtures/emails/error_emails/weird_to_header.eml000066400000000000000000000020731214434061600250320ustar00rootroot00000000000000Delivered-To: e-s-a-s-2200@app.ar.com Received: by 10.103.1.1 with SMTP id w10cs50835muo; Thu, 14 Oct 2010 20:25:16 -0700 (PDT) Received: by 10.150.205.4 with SMTP id c4mr736200ybg.26.1287113115711; Thu, 14 Oct 2010 20:25:15 -0700 (PDT) Return-Path: Received: from i.tp.host ([172.1.1.1]) by mx.google.com with ESMTP id s21si2123456.90.2010.10.14.20.25.15; Thu, 14 Oct 2010 20:25:15 -0700 (PDT) Received-SPF: neutral (google.com: 172.1.1.1 is neither permitted nor denied by best guess record for domain of anonymous@i.tp.host) client-ip=172.1.1.1; Authentication-Results: mx.google.com; spf=neutral (google.com: 172.1.1.1 is neither permitted nor denied by best guess record for domain of anonymous@i.tp.host) smtp.mail=anonymous@i.tp.host Received: (qmail 28454 invoked by uid 48); 14 Oct 2010 23:25:06 -0400 Date: 14 Oct 2010 23:25:06 -0400 Message-ID: <20101015032506.28448.qmail@i.tp.host> From: anonymous@i.tp.host To: , user-example@aol.com, e-s-a-s-2200@app.ar.com Subject: CONTACT: COMMENT: PAGE THEY WERE ON: mail-2.5.4/spec/fixtures/emails/mime_emails/000077500000000000000000000000001214434061600210035ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/mime_emails/email_with_similar_boundaries.eml000066400000000000000000000026101214434061600275560ustar00rootroot00000000000000Received: from xxxx.xxxxxxx.xxx (127.0.0.1) by xxxx.xxxxxxxx.xxx (127.0.01) with Microsoft SMTP Server id 11.1.111.1; Thu, 5 Apr 2012 01:01:01 -0700 Message-ID: To: Subject: Xxxxxx Date: Fri, 6 Apr 2012 01:01:01 +0000 From: Xxxxx X-Mailer: PHP/5.2.6 Content-Type: multipart/mixed; boundary="----=_NextPart_476c4fde88e507bb8028170e8cf47c73" MIME-Version: 1.0 ------=_NextPart_476c4fde88e507bb8028170e8cf47c73 Content-Type: multipart/alternative; boundary="----=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt" ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Test ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 8bit Test

    Test

    ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt-- ------=_NextPart_476c4fde88e507bb8028170e8cf47c73 Content-Type: application/octetstream Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="LOGO.png" Content-ID: SNIP ------=_NextPart_476c4fde88e507bb8028170e8cf47c73-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email11.eml000066400000000000000000000012511214434061600236030ustar00rootroot00000000000000From xxx@xxxx.com Wed Apr 27 14:15:31 2005 Mime-Version: 1.0 (Apple Message framework v619.2) To: "xxxxx@xxxxx" Message-Id: <416eaebec6d333ec6939eaf8a7d80724@xxxxx> Content-Type: multipart/alternative; boundary=Apple-Mail-5-1037861608 From: "xxxxx@xxxxx" Subject: worse when you use them. Date: Wed, 27 Apr 2005 14:15:31 -0700 --Apple-Mail-5-1037861608 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed XXXXX Xxxxx --Apple-Mail-5-1037861608 Content-Transfer-Encoding: 7bit Content-Type: text/enriched; charset=US-ASCII XXXXX Xxxxx --Apple-Mail-5-1037861608-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email12.eml000066400000000000000000000016701214434061600236110ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-13-196941151 Content-Type: image/jpeg Content-Transfer-Encoding: base64 Content-Location: Photo25.jpg Content-ID: Content-Disposition: inline jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email2.eml000066400000000000000000000144041214434061600235270ustar00rootroot00000000000000From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 Return-Path: X-Original-To: xxxxx@xxxxx.xxxxxxxxx.com Delivered-To: xxxxx@xxxxx.xxxxxxxxx.com Received: from localhost (localhost [127.0.0.1]) by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 06C9DA98D for ; Sun, 8 May 2005 19:09:13 +0000 (GMT) Received: from xxxxx.xxxxxxxxx.com ([127.0.0.1]) by localhost (xxxxx.xxxxxxxxx.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 88783-08 for ; Sun, 8 May 2005 19:09:12 +0000 (GMT) Received: from xxxxxxx.xxxxxxxxx.com (xxxxxxx.xxxxxxxxx.com [69.36.39.150]) by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 10D8BA960 for ; Sun, 8 May 2005 19:09:12 +0000 (GMT) Received: from zproxy.gmail.com (zproxy.gmail.com [64.233.162.199]) by xxxxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 9EBC4148EAB for ; Sun, 8 May 2005 14:09:11 -0500 (CDT) Received: by zproxy.gmail.com with SMTP id 13so1233405nzp for ; Sun, 08 May 2005 12:09:11 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:references; b=cid1mzGEFa3gtRa06oSrrEYfKca2CTKu9sLMkWxjbvCsWMtp9RGEILjUz0L5RySdH5iO661LyNUoHRFQIa57bylAbXM3g2DTEIIKmuASDG3x3rIQ4sHAKpNxP7Pul+mgTaOKBv+spcH7af++QEJ36gHFXD2O/kx9RePs3JNf/K8= Received: by 10.36.10.16 with SMTP id 16mr1012493nzj; Sun, 08 May 2005 12:09:11 -0700 (PDT) Received: by 10.36.5.10 with HTTP; Sun, 8 May 2005 12:09:11 -0700 (PDT) Message-ID: Date: Sun, 8 May 2005 14:09:11 -0500 From: xxxxxxxxx xxxxxxx Reply-To: xxxxxxxxx xxxxxxx To: xxxxx xxxx Subject: Fwd: Signed email causes file attachments In-Reply-To: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_5028_7368284.1115579351471" References: ------=_Part_5028_7368284.1115579351471 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline We should not include these files or vcards as attachments. ---------- Forwarded message ---------- From: xxxxx xxxxxx Date: May 8, 2005 1:17 PM Subject: Signed email causes file attachments To: xxxxxxx@xxxxxxxxxx.com Hi, Just started to use my xxxxxxxx account (to set-up a GTD system, natch) and noticed that when I send content via email the signature/ certificate from my email account gets added as a file (e.g. "smime.p7s"). Obviously I can uncheck the signature option in the Mail compose window but how often will I remember to do that? Is there any way these kind of files could be ignored, e.g. via some sort of exclusions list? ------=_Part_5028_7368284.1115579351471 Content-Type: application/pkcs7-signature; name=smime.p7s Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw o8xS3A0a1LXealcmlEbJibmKkEaoXci3MhryLgpaa+Kk/sH02SNatDO1vS28bPsibZpcc6deFrla hSYnL+PW54mDTGHIcCN2fbx/Y6qspzqmtKaXrv75NBtuy9cB6KzU4j2xXbTkAwz3pRSghJJaAwdp +yIivAD3vr0kJE3p+Ez34HMh33EXEpFoWcN+MCEQZD9WnmFViMrvfvMXLGVFQfAAcC060eGFSRJ1 ZQ9UVQIDAQABoy0wKzAbBgNVHREEFDASgRBzbWhhdW5jaEBtYWMuY29tMAwGA1UdEwEB/wQCMAAw DQYJKoZIhvcNAQEEBQADgYEAQMrg1n2pXVWteP7BBj+Pk3UfYtbuHb42uHcLJjfjnRlH7AxnSwrd L3HED205w3Cq8T7tzVxIjRRLO/ljq0GedSCFBky7eYo1PrXhztGHCTSBhsiWdiyLWxKlOxGAwJc/ lMMnwqLOdrQcoF/YgbjeaUFOQbUh94w9VDNpWZYCZwcwggM/MIICqKADAgECAgENMA0GCSqGSIb3 DQEBBQUAMIHRMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlD YXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0 aW9uIFNlcnZpY2VzIERpdmlzaW9uMSQwIgYDVQQDExtUaGF3dGUgUGVyc29uYWwgRnJlZW1haWwg Q0ExKzApBgkqhkiG9w0BCQEWHHBlcnNvbmFsLWZyZWVtYWlsQHRoYXd0ZS5jb20wHhcNMDMwNzE3 MDAwMDAwWhcNMTMwNzE2MjM1OTU5WjBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENv bnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWlsIElz c3VpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMSmPFVzVftOucqZWh5owHUEcJ3f 6f+jHuy9zfVb8hp2vX8MOmHyv1HOAdTlUAow1wJjWiyJFXCO3cnwK4Vaqj9xVsuvPAsH5/EfkTYk KhPPK9Xzgnc9A74r/rsYPge/QIACZNenprufZdHFKlSFD0gEf6e20TxhBEAeZBlyYLf7AgMBAAGj gZQwgZEwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLnRo YXd0ZS5jb20vVGhhd3RlUGVyc29uYWxGcmVlbWFpbENBLmNybDALBgNVHQ8EBAMCAQYwKQYDVR0R BCIwIKQeMBwxGjAYBgNVBAMTEVByaXZhdGVMYWJlbDItMTM4MA0GCSqGSIb3DQEBBQUAA4GBAEiM 0VCD6gsuzA2jZqxnD3+vrL7CF6FDlpSdf0whuPg2H6otnzYvwPQcUCCTcDz9reFhYsPZOhl+hLGZ GwDFGguCdJ4lUJRix9sncVcljd2pnDmOjCBPZV+V2vf3h9bGCE6u9uo05RAaWzVNd+NWIXiC3CEZ Nd4ksdMdRv9dX2VPMYIC5zCCAuMCAQEwaTBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3Rl IENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWls IElzc3VpbmcgQ0ECAw5c+TAJBgUrDgMCGgUAoIIBUzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB MBwGCSqGSIb3DQEJBTEPFw0wNTA1MDgxODE3NDZaMCMGCSqGSIb3DQEJBDEWBBQSkG9j6+hB0pKp fV9tCi/iP59sNTB4BgkrBgEEAYI3EAQxazBpMGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3 dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h aWwgSXNzdWluZyBDQQIDDlz5MHoGCyqGSIb3DQEJEAILMWugaTBiMQswCQYDVQQGEwJaQTElMCMG A1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNv bmFsIEZyZWVtYWlsIElzc3VpbmcgQ0ECAw5c+TANBgkqhkiG9w0BAQEFAASCAQAm1GeF7dWfMvrW 8yMPjkhE+R8D1DsiCoWSCp+5gAQm7lcK7V3KrZh5howfpI3TmCZUbbaMxOH+7aKRKpFemxoBY5Q8 rnCkbpg/++/+MI01T69hF/rgMmrGcrv2fIYy8EaARLG0xUVFSZHSP+NQSYz0TTmh4cAESHMzY3JA nHOoUkuPyl8RXrimY1zn0lceMXlweZRouiPGuPNl1hQKw8P+GhOC5oLlM71UtStnrlk3P9gqX5v7 Tj7Hx057oVfY8FMevjxGwU3EK5TczHezHbWWgTyum9l2ZQbUQsDJxSniD3BM46C1VcbDLPaotAZ0 fTYLZizQfm5hcWEbfYVzkSzLAAAAAAAA ------=_Part_5028_7368284.1115579351471-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email4.eml000066400000000000000000000036511214434061600235330ustar00rootroot00000000000000Return-Path: Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500 Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id j48HUC213279 for ; Sun, 8 May 2005 12:30:13 -0500 Received: from conversion-xxx.xxxx.xxx.net by xxx.xxxx.xxx id <0IG600901LQ64I@xxx.xxxx.xxx> for ; Sun, 8 May 2005 12:30:12 -0500 Received: from agw1 by xxx.xxxx.xxx with ESMTP id <0IG600JFYLYCAxxx@xxxx.xxx> for ; Sun, 8 May 2005 12:30:12 -0500 Date: Sun, 8 May 2005 12:30:08 -0500 From: xxx@xxxx.xxx To: xxx@xxxx.xxx Message-Id: <7864245.1115573412626.JavaMxxx@xxxx.xxx> Subject: Filth Mime-Version: 1.0 Content-Type: multipart/mixed; boundary=mimepart_427e4cb4ca329_133ae40413c81ef X-Mms-Priority: 1 X-Mms-Transaction-Id: 3198421808-0 X-Mms-Message-Type: 0 X-Mms-Sender-Visibility: 1 X-Mms-Read-Reply: 1 X-Original-To: xxx@xxxx.xxx X-Mms-Message-Class: 0 X-Mms-Delivery-Report: 0 X-Mms-Mms-Version: 16 Delivered-To: xxx@xxxx.xxx X-Nokia-Ag-Version: 2.0 This is a multi-part message in MIME format. --mimepart_427e4cb4ca329_133ae40413c81ef Content-Type: multipart/mixed; boundary=mimepart_427e4cb4cbd97_133ae40413c8217 --mimepart_427e4cb4cbd97_133ae40413c8217 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline Content-Location: text.txt Some text --mimepart_427e4cb4cbd97_133ae40413c8217-- --mimepart_427e4cb4ca329_133ae40413c81ef Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit -- This Orange Multi Media Message was sent wirefree from an Orange MMS phone. If you would like to reply, please text or phone the sender directly by using the phone number listed in the sender's address. To learn more about Orange's Multi Media Messaging Service, find us on the Web at xxx.xxxx.xxx.uk/mms --mimepart_427e4cb4ca329_133ae40413c81ef --mimepart_427e4cb4ca329_133ae40413c81ef- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email7.eml000066400000000000000000000031001214434061600235230ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com --Apple-Mail-13-196941151 Content-Type: multipart/mixed; boundary=Apple-Mail-12-196940926 --Apple-Mail-12-196940926 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=ISO-8859-1; delsp=yes; format=flowed This is the first part. --Apple-Mail-12-196940926 Content-Transfer-Encoding: 7bit Content-Type: text/x-ruby-script; x-unix-mode=0666; name="test.rb" Content-Disposition: attachment; filename=test.rb puts "testing, testing" --Apple-Mail-12-196940926 Content-Transfer-Encoding: base64 Content-Type: application/pdf; x-unix-mode=0666; name="test.pdf" Content-Disposition: inline; filename=test.pdf YmxhaCBibGFoIGJsYWg= --Apple-Mail-12-196940926 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed --Apple-Mail-12-196940926-- --Apple-Mail-13-196941151 Content-Transfer-Encoding: base64 Content-Type: application/pkcs7-signature; name=smime.p7s Content-Disposition: attachment; filename=smime.p7s jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= --Apple-Mail-13-196941151-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_encoded_stack_level_too_deep.eml000066400000000000000000000032631214434061600313610ustar00rootroot00000000000000X-Gmail-Received: 220984aec4c4885e060987be043c9363cbef8551 Received: by 10.36.47.16; Tue, 28 Jun 2005 01:02:11 -0700 (PDT) Message-ID: <89d7557c0506280102495d555f@mail.gmail.com> Date: Tue, 28 Jun 2005 01:02:11 -0700 From: Gmail Team Reply-To: x.y@gmail.com To: =?ISO-8859-1?Q?Nicolas_Fouch=E9?= Subject: =?ISO-8859-1?Q?Nicolas_Fouch=E9_has_accepted_your_invitation_to_Gmail?= Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_976_15222032.1119945731186" ------=_Part_976_15222032.1119945731186 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Nicolas Fouch=E9 has accepted your invitation to Gmail and has chosen the= =20 brand new address x.y@gmail.com. Be one of the first to email Nicolas= =20 at this new Gmail address--just hit reply and send Nicolas a message.=20 x.y@gmail.com has also been automatically added to your contact list= =20 so you can stay in touch with Gmail.=20 Thanks,=20 The Gmail Team ------=_Part_976_15222032.1119945731186 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline

    Nicolas Fouch=E9 has accepted your invitation to Gmail and has chosen the brand new address x.y@gmail.com. Be one of the first to = email=20 Nicolas at this new Gmail address--just hit reply and send=20 Nicolas a message. x.y@gmail.com has also been automatically added = to your contact list so you can stay in touch with Gmail.


    Thanks,

    The Gmail Team

    ------=_Part_976_15222032.1119945731186--mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_with_illegal_boundary.eml000066400000000000000000000043561214434061600301010ustar00rootroot00000000000000From email_test@me.nowhere Return-Path: Received: from omta05sl.mx.bigpond.com by me.nowhere.else with ESMTP id 632BD5758 for ; Sun, 21 Oct 2007 19:38:21 +1000 Received: from oaamta05sl.mx.bigpond.com by omta05sl.mx.bigpond.com with ESMTP id <20071021093820.HSPC16667.omta05sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com> for ; Sun, 21 Oct 2007 19:38:20 +1000 Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 Date: Sun, 21 Oct 2007 19:38:13 +1000 From: Mikel Lindsaar Reply-To: Mikel Lindsaar To: mikel@me.nowhere Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> Subject: Testing outlook Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850 X-Get_mail_default: mikel@me.nowhere.else X-Priority: 3 X-Original-To: mikel@me.nowhere X-Mailer: Microsoft Outlook Express 6.00.2900.3138 Delivered-To: mikel@me.nowhere X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138 X-Msmail-Priority: Normal This is a multi-part message in MIME format. ------=_NextPart_000_0093_01C81419.EB75E850 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: Quoted-printable Hello This is an outlook test So there. Me. ------=_NextPart_000_0093_01C81419.EB75E850 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: Quoted-printable
    Hello
    This is an outlook=20 test
     
    So there.
     
    Me.
    ------=_NextPart_000_0093_01C81419.EB75E850-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_with_mimepart_without_content_type.eml000066400000000000000000000101751214434061600327550ustar00rootroot00000000000000X-Gmail-Received: b2c98353cc39d93e4204831226f778c200d28109 Delivered-To: roor32@gmail.com Received: by 10.64.10.4 with SMTP id 4cs594808qbj; Fri, 20 Oct 2006 01:53:34 -0700 (PDT) Received: by 10.65.224.11 with SMTP id b11mr149813qbr; Fri, 20 Oct 2006 01:53:34 -0700 (PDT) Return-Path: <> Received: from anis.telecom.uqam.ca (anis.telecom.uqam.ca [132.208.250.6]) by mx.google.com with ESMTP id e13si1575402qbe.2006.10.20.01.53.34; Fri, 20 Oct 2006 01:53:34 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of anis.telecom.uqam.ca designates 132.208.250.6 as permitted sender) Received: from anis4.telecom.uqam.ca (anis4.telecom.uqam.ca [132.208.250.236]) by sortant.uqam.ca (8.13.6/8.12.1) with SMTP id k9K8SIwA023763 for ; Fri, 20 Oct 2006 04:28:33 -0400 (EDT) Received: from antivirus.uqam.ca ([127.0.0.1]) by anis4.telecom.uqam.ca (SAVSMTP 3.1.1.32) with SMTP id M2006102004283404041 for ; Fri, 20 Oct 2006 04:28:34 -0400 Received: from localhost (localhost) by antivirus.uqam.ca (8.13.6/8.12.1) id k9JMDbg4005560; Fri, 20 Oct 2006 04:28:33 -0400 (EDT) Date: Fri, 20 Oct 2006 04:28:33 -0400 (EDT) From: Mail Delivery Subsystem Message-Id: <200610200828.k9JMDbg4005560@antivirus.uqam.ca> To: MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="k9JMDbg4005560.1161332913/antivirus.uqam.ca" Subject: Warning: could not send message for past 1 day Auto-Submitted: auto-generated (warning-timeout) This is a MIME-encapsulated message --k9JMDbg4005560.1161332913/antivirus.uqam.ca ********************************************** ** THIS IS A WARNING MESSAGE ONLY ** ** YOU DO NOT NEED TO RESEND YOUR MESSAGE ** ********************************************** The original message was received at Thu, 19 Oct 2006 01:23:47 -0400 (EDT) from py-out-1112.google.com [64.233.166.178] ----- Transcript of session follows ----- ... Deferred Warning: message still undelivered after 1 day Will keep trying until message is 5 days old --k9JMDbg4005560.1161332913/antivirus.uqam.ca Content-Type: message/delivery-status Reporting-MTA: dns; antivirus.uqam.ca Arrival-Date: Thu, 19 Oct 2006 01:23:47 -0400 (EDT) Final-Recipient: RFC822; larose.julie@courrier.uqam.ca Action: delayed Status: 4.5.0 Diagnostic-Code: SMTP; Last-Attempt-Date: Fri, 20 Oct 2006 04:28:33 -0400 (EDT) Will-Retry-Until: Tue, 24 Oct 2006 01:23:47 -0400 (EDT) --k9JMDbg4005560.1161332913/antivirus.uqam.ca Content-Type: message/rfc822 Return-Path: Received: from py-out-1112.google.com (py-out-1112.google.com [64.233.166.178]) by intrant.uqam.ca (8.13.6/8.12.2/uqam-filtres) with SMTP id k9J5Ni8o007263 for ; Thu, 19 Oct 2006 01:23:47 -0400 (EDT) X-UQAM-Spam-Filter: Filtre-Uqam re: abuse@uqam.ca Received: by py-out-1112.google.com with SMTP id t32so610221pyc for ; Wed, 18 Oct 2006 22:23:33 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:to:subject:mime-version:content-type:content-transfer-encoding:content-disposition; b=Fwt0k1kaMU+1kM1iTG0q4Xf94p9alSohgM7QQN0CSjfBYUUhT+J4Y6+ZWotaaSffV3gX86RE/n97n0yQ/33EgYKIifuEpa0hi2mg3KTmcDqlCjiDfih58Z998GEFfbhu0he2jsoB+k6AgVRFPwP6LMRi6T66vr2f7IOAmX2IHiU= Received: by 10.65.241.20 with SMTP id t20mr15391984qbr; Wed, 18 Oct 2006 15:10:03 -0700 (PDT) Received: by 10.64.10.4 with HTTP; Wed, 18 Oct 2006 15:10:03 -0700 (PDT) Message-ID: <89d7557c0610181510r6fa5ebd8n66a7deec71ade118@mail.gmail.com> Date: Wed, 18 Oct 2006 18:10:03 -0400 From: "=?ISO-8859-1?Q?RogE9?=" To: larose.julie@courrier.uqam.ca Subject: Est-ce toi ? MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline Salut, je ne suis pas sur de m'adresser a la bonne personne. Mais si jamais tu me reconnais :p, peux-tu repondre a ce mail ? Merci. Roger --k9JMDbg4005560.1161332913/antivirus.uqam.ca-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_with_multipart_mixed_quoted_boundary.eml000066400000000000000000000055451214434061600332610ustar00rootroot00000000000000From email_test@me.nowhere Return-Path: Received: from omta05sl.mx.bigpond.com by me.nowhere.else with ESMTP id 632BD5758 for ; Sun, 21 Oct 2007 19:38:21 +1000 Received: from oaamta05sl.mx.bigpond.com by omta05sl.mx.bigpond.com with ESMTP id <20071021093820.HSPC16667.omta05sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com> for ; Sun, 21 Oct 2007 19:38:20 +1000 Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 Date: Sun, 21 Oct 2007 19:38:13 +1000 From: Mikel Lindsaar Reply-To: Mikel Lindsaar To: mikel@me.nowhere Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> Subject: Testing outlook Subject: Another PDF Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_2192_32400445.1115745999735" X-Virus-Scanned: amavisd-new at textdrive.com ------=_Part_2192_32400445.1115745999735 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Just attaching another PDF, here, to see what the message looks like, and to see if I can figure out what is going wrong here. ------=_Part_2192_32400445.1115745999735 Content-Type: application/pdf; name="broken.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="broken.pdf" JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg 1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI 8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw ------=_Part_2192_32400445.1115745999735-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_with_nested_attachment.eml000066400000000000000000000115271214434061600302550ustar00rootroot00000000000000From jamis@37signals.com Thu Feb 22 11:20:31 2007 Mime-Version: 1.0 (Apple Message framework v752.3) Message-Id: <2CCE0408-10C7-4045-9B16-A1C11C31469B@37signals.com> Content-Type: multipart/signed; micalg=sha1; boundary=Apple-Mail-42-587703407; protocol="application/pkcs7-signature" To: Jamis Buck Subject: Testing attachments From: Jamis Buck Date: Thu, 22 Feb 2007 11:20:31 -0700 --Apple-Mail-42-587703407 Content-Type: multipart/mixed; boundary=Apple-Mail-41-587703287 --Apple-Mail-41-587703287 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed Here is a test of an attachment via email. - Jamis --Apple-Mail-41-587703287 Content-Transfer-Encoding: base64 Content-Type: image/png; x-unix-mode=0644; name=byo-ror-cover.png Content-Disposition: inline; filename=truncated.png iVBORw0KGgoAAAANSUhEUgAAAKUAAADXCAYAAAB7wZEQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz AAALEgAACxIB0t1+/AAAABd0RVh0Q3JlYXRpb24gVGltZQAxLzI1LzIwMDeD9CJVAAAAGHRFWHRT b2Z0d2FyZQBBZG9iZSBGaXJld29ya3NPsx9OAAAyBWlUWHRYTUw6Y29tLmFkb2JlLnhtcDw/eHBh Y2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1l dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMS1j MDIwIDEuMjU1NzE2LCBUdWUgT2N0IDEwIDIwMDYgMjM6MTY6MzQiPgogICA8cmRmOlJERiB4bWxu czpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAg ICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4YXA9Imh0 dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eGFwOkNyZWF0b3JUb29sPkFk b2JlIEZpcmV3b3JrcyBDUzM8L3hhcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhhcDpDcmVhdGVE YXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhhcDpN b2RpZnlEYXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9y ZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAg ICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAg ICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0 hhojpmnJMfaYFmSkXWg5PGCmHXVj/c9At0hSK2xGdd8F3muk0VFjb4f5Ue0ksQ8qAcq0delaXhdb DjKNnF+3B3t9kObZYmk7AZgWYqO9anpR3wpM9sQ5XslB9a+kWyTtNb0fOmudzGHfPFBQDKesyycm DBL7Cw5bXjIEuci+SSOm/LYnXDZu6iuPEj8lYBb+OU8xx1f9m+e5rhJiYKqjo5vHfiZp+VUkW9xc Ufd6JHNWc47PkQqb9ie3SLEZB/ZqyAssiqURY+G35iOMZUrHbasHnb80QAPv9FHtAbJIyro7bi5b ai2TEAKen5+LJNWrglZjm3UbZvt7KryA2J5b5J1jZF8kL6GzvG1Zqx54Y1y7J7n20wMOt9frG2sW uwGP07kNz3732vf6bfvAvLldfS+9fts2euXY37D+R29FGZdlnhzV4TTFmPJduBP2RbNNua4rTqcT Qt7Xy1KUB0AHSdP5AZQYvHZg7WD1XvYeMO1A9HhZPqMX5KXbMBrn2efxns/ee21674efxz4Tp/fq 2HZ648dgYaC1i3Vq1IbNPq3PvDTPezY9FaRISjvnzWqdgcWN8EJgjnNq+Z7ktOm9l2Nfth28EZi4 bG/we5JwxM+Tql47/D/X6b38I8/RyxvxPJrX6zvQbo3h9jyJx+C0ALX327QETHl5eYlaYCT5rPTb +5/rAq26t3lKIxV/p88hq6ptngdgCzoPjJqndiLfc/6y5A14WeDFGNPct4iUsJBV2bYzLEV7m83s 6Rp63VPhHKC/g/LzaU9qexJRr56043JWinqAtfZqsSm1sjoznthl54dtCqv+uL4nIY+oYWuc3+nH kGfn8b0HQpvOYLQAZUDanbJs3jQhITZEgdarZK+cO6ySlL13rut5nFaN23s7u3Snz6eRPTkCoc2/ Vp1zHfZVFpZ87FiMVLV1iqyK5rlzfji2GzjfDsodlD+Weo5UD4h6PwKqzQMqID0tq2VjjFVSMpis ZLRAs7sePZBZAHI+gIanB8I7MD+femAceeUe2Kxa5jS950kZ1p5eNEdeX1+jFmSpZ+1EdWCsDcne NPNgUHNw3aYpnzv9PGTX0uo94EtN9qq1rOdxe3kc79T8ukeHJJ8Fnxej6qlylbLLsjQLOy6Xy2a1 kefs/N+nM7+S7IG5/E5Yc7F003pWErLjbH0O5cGadiMptSB/DZ5U5DI9yeg5MFYyMj8lC/Y7/Xjq OZlWcnpg9aQfXz2HRq+Wn5xOp6gN8tWq8R44e2pfyzLYemEgprst+XXk2Zj2nXlbsG05BprndTMv C3QRaXczshhVsHnMgfYn80Y2g5JureA6wBasPeP7LkE/jvZMJAaf/g/U2RelHsisvan5FqweIAHg Pwc7L68GxvVDAAAAAElFTkSuQmCC --Apple-Mail-41-587703287-- --Apple-Mail-42-587703407 Content-Transfer-Encoding: base64 Content-Type: application/pkcs7-signature; name=smime.p7s Content-Disposition: attachment; filename=smime.p7s MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGJzCCAuAw ggJJoAMCAQICEFjnFNYXwDEZRWY5EkfzopUwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCWkEx JTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xLDAqBgNVBAMTI1RoYXd0ZSBQ ZXJzb25hbCBGcmVlbWFpbCBJc3N1aW5nIENBMB4XDTA2MDkxMjE3MDExMloXDTA3MDkxMjE3MDEx MlowRTEfMB0GA1UEAxMWVGhhd3RlIEZyZWVtYWlsIE1lbWJlcjEiMCAGCSqGSIb3DQEJARYTamFt aXNAMzdzaWduYWxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO2A9JeOFIFJ G6z8pTcAldrZ2nMe+Xb1tNrbHgoVzN/QhHXM4qst2Ml93cmFLjMmwG7P9RJeU4oNx+jTqVoBB7NV Ne1/o56Do0KhfMZ9iUDQdPLbkZMq4EEpFMdm6PyM3muRKwPhj66iAWe/osCb8DowUK2f66vaRx0Z Y0MQHIIrXE02Ta4IfAhIfPqBLkZ4WgTYBHN9vMdYea1jF0GO4gqGk1wqwb3yxv2QMYMbwJ6SI+k/ ZjkSR/OilTCBhwYLKoZIhvcNAQkQAgsxeKB2MGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3 dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h aWwgSXNzdWluZyBDQQIQWOcU1hfAMRlFZjkSR/OilTANBgkqhkiG9w0BAQEFAASCAQCfwQiC3v6/ yleRDGv3bJ4nQYQ+c3mz3+mn3Xi6uU35n3piwxZZaWRdmLyiXPvU+QReHpSf3l2qsEZM3sdE0XF9 eRul/+QTFJcDNXOEAxG1zC2Gpz+6c6RrX4Ou12Pwkp+pNrZWTSY/mZgdqcArupOBcZi7qBjoWcy5 wb54dfvSSjrjmqLbkH/E8ww/6gGQuU/xXpAUZgUrTmQHrNKeIdSh5oDkOxFaFWvnmb8Z/2ixKqW/ Ux6WqamyvBtTs/5YBEtnpZOk+uVoscYEUBhU+DVJ2OSvTdXSivMtBdXmGTsG22k+P1NGUHi/A7ev xPaO0uk4V8xyjNlN4HPuGpkrlXwPAAAAAAAA --Apple-Mail-42-587703407-- mail-2.5.4/spec/fixtures/emails/mime_emails/raw_email_with_quoted_illegal_boundary.eml000066400000000000000000000043601214434061600314550ustar00rootroot00000000000000From email_test@me.nowhere Return-Path: Received: from omta05sl.mx.bigpond.com by me.nowhere.else with ESMTP id 632BD5758 for ; Sun, 21 Oct 2007 19:38:21 +1000 Received: from oaamta05sl.mx.bigpond.com by omta05sl.mx.bigpond.com with ESMTP id <20071021093820.HSPC16667.omta05sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com> for ; Sun, 21 Oct 2007 19:38:20 +1000 Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 Date: Sun, 21 Oct 2007 19:38:13 +1000 From: Mikel Lindsaar Reply-To: Mikel Lindsaar To: mikel@me.nowhere Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> Subject: Testing outlook Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_NextPart_000_0093_01C81419.EB75E850" X-Get_mail_default: mikel@me.nowhere.else X-Priority: 3 X-Original-To: mikel@me.nowhere X-Mailer: Microsoft Outlook Express 6.00.2900.3138 Delivered-To: mikel@me.nowhere X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138 X-Msmail-Priority: Normal This is a multi-part message in MIME format. ------=_NextPart_000_0093_01C81419.EB75E850 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: Quoted-printable Hello This is an outlook test So there. Me. ------=_NextPart_000_0093_01C81419.EB75E850 Content-Type: text/html; charset=iso-8859-1 Content-Transfer-Encoding: Quoted-printable
    Hello
    This is an outlook=20 test
     
    So there.
     
    Me.
    ------=_NextPart_000_0093_01C81419.EB75E850-- mail-2.5.4/spec/fixtures/emails/mime_emails/sig_only_email.eml000066400000000000000000000016421214434061600244770ustar00rootroot00000000000000Date: Mon, 4 Jun 2007 15:01:31 -0700 From: Test To: Mikel Subject: Re: Testing multipart/signed Message-ID: <20070604150131.40d4fa1e@reforged> Mime-Version: 1.0 Content-Type: multipart/signed; boundary=Sig_2GIY2xfzqSADMmu9sKGJqWm; protocol="application/pgp-signature"; micalg=PGP-SHA1 --Sig_2GIY2xfzqSADMmu9sKGJqWm Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable This is random text, not what has been signed below, ie, this sig email is not signed correctly. --Sig_2GIY2xfzqSADMmu9sKGJqWm Content-Type: application/pgp-signature; name=signature.asc Content-Disposition: attachment; filename=signature.asc -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DB1111Iu7dfRchrkBInkRArniAKCue17JOxXBiAZHwLy3uFacU+pmhwCgwzhf V5YSPv2xmYOA6mJ6oVaasseQ= =T7p9 -----END PGP SIGNATURE----- --Sig_2GIY2xfzqSADMmu9sKGJqWm-- mail-2.5.4/spec/fixtures/emails/mime_emails/two_from_in_message.eml000066400000000000000000000033071214434061600255330ustar00rootroot00000000000000Return-Path: Received: from mail-xxx.google.com (mail-xxx.google.com [0.0.0.0]) by smtp.test.com (Postfix) with ESMTP id xxxx for ; Wed, 2 Dec 2009 09:39:57 +0000 (UTC) Received: by qyk6 with SMTP id 6so3112qyk.3 for ; Wed, 02 Dec 2009 01:39:53 -0800 (PST) MIME-Version: 1.0 Received: by 0.0.0.0 with SMTP id xxx.000.0000000000000; Wed, 02 Dec 2009 01:39:53 -0800 (PST) In-Reply-To: <8fc5086d0912020131y377ba0ccpf8f14783cfc3014a@test.com> References: <8fc5086d0912020131y377ba0ccpf8f14783cfc3014a@test.com> From: Tester 1 Date: Wed, 2 Dec 2009 22:39:33 +1300 Message-ID: <8fc5086d0912020139y1564ad32jb4f4209fa464f4a6@test.com> Subject: Sending messages include last little bit To: tester2@test.com Content-Type: multipart/alternative; boundary=00c09fa216eb1bfc0a0479bba823 --00c09fa216eb1bfc0a0479bba823 Content-Type: text/plain; charset=ISO-8859-1 When sending email: * From Hotmail you get the ads as well. * From GMail you also get the person's signature. I'm curious, and I might do some digging tomorrow as well, to see if its possible to strip the last little bit (signature/ads) from email messages. --00c09fa216eb1bfc0a0479bba823 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
    When sending ema= il:
    * From Hotmail you get the ads as well.
    * Fr= om GMail you also get the person's signature.

    = I'm curious, and I might do some digging tomorrow as well, to see if it= s possible to strip the last little bit (signature/ads) from email messages= .
    --00c09fa216eb1bfc0a0479bba823--mail-2.5.4/spec/fixtures/emails/multi_charset/000077500000000000000000000000001214434061600213655ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/multi_charset/japanese.eml000066400000000000000000000005101214434061600236460ustar00rootroot00000000000000MIME-Version: 1.0 Subject: =?UTF-8?B?44G+44G/44KA44KB44KC?= From: Mikel Lindsaar To: =?UTF-8?B?44G/44GR44KL?= Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: base64 44GL44GN44GP44GI44GTCgotLSAKaHR0cDovL2xpbmRzYWFyLm5ldC8KUmFpbHMsIFJTcGVjIGFu ZCBMaWZlIGJsb2cuLi4uCg==mail-2.5.4/spec/fixtures/emails/multi_charset/japanese_attachment.eml000066400000000000000000000015531214434061600260660ustar00rootroot00000000000000MIME-Version: 1.0 Received: by 10.231.35.72 with HTTP; Fri, 16 Oct 2009 05:39:34 -0700 (PDT) Date: Fri, 16 Oct 2009 23:39:34 +1100 Delivered-To: raasdnil@gmail.com Message-ID: <57a815bf0910160539m64240421gb35ea52e101aedbc@mail.gmail.com> Subject: testing From: Mikel Lindsaar To: Mikel Lindsaar Content-Type: multipart/mixed; boundary=00032557395e3572cf04760cb060 --00032557395e3572cf04760cb060 Content-Type: text/plain; charset=UTF-8 testing -- http://lindsaar.net/ Rails, RSpec and Life blog.... --00032557395e3572cf04760cb060 Content-Type: text/plain; charset=UTF-8; name="=?UTF-8?B?44Gm44GZ44GoLnR4dA==?=" Content-Disposition: attachment; filename="=?UTF-8?B?44Gm44GZ44GoLnR4dA==?=" Content-Transfer-Encoding: base64 X-Attachment-Id: f_g0uxfl510 dGhpcyBpcyBhIHRlc3QK44GT44KM44KP44Gm44GZ44Go --00032557395e3572cf04760cb060--mail-2.5.4/spec/fixtures/emails/multi_charset/japanese_attachment_long_name.eml000066400000000000000000000045011214434061600301010ustar00rootroot00000000000000Delivered-To: raasdnil@gmail.com Received: by 10.231.12.67 with SMTP id w3cs164325ibw; Fri, 30 Oct 2009 01:11:12 -0700 (PDT) Received: by 10.150.44.2 with SMTP id r2mr2367210ybr.77.1256890271939; Fri, 30 Oct 2009 01:11:11 -0700 (PDT) Return-Path: Received: from mx1.test.lindsaar.net.au (mx1.test.lindsaar.net.au [210.14.110.240]) by mx.google.com with ESMTP id 25si7923673gxk.34.2009.10.30.01.11.11; Fri, 30 Oct 2009 01:11:11 -0700 (PDT) Received-SPF: neutral (google.com: 210.14.110.240 is neither permitted nor denied by domain of mikel@test.lindsaar.net) client-ip=210.14.110.240; Authentication-Results: mx.google.com; spf=neutral (google.com: 210.14.110.240 is neither permitted nor denied by domain of mikel@test.lindsaar.net) smtp.mail=mikel@test.lindsaar.net Received: from [192.168.4.253] (60-241-138-146.static.tpgi.com.au [60.241.138.146]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: mikel) by mx1.test.lindsaar.net.au (Postfix) with ESMTPSA id 5C0186DD4CD for ; Fri, 30 Oct 2009 19:11:08 +1100 (EST) Subject: =?utf-8?B?44G+44G/44KA44KB44KC44G+44G/44KA44KB44KC44G+44G/44KA?= =?utf-8?B?44KB44KC44G+44G/44KA44KB44KC44G+44G/44KA44KB44KC44G+?= =?utf-8?B?44G/44KA44KB44KC44G+44G/44KA44KB44KC44G+44G/44KA44KB?= =?utf-8?B?44KC44G+44G/44KA44KB44KC44G+44G/44KA44KB44KC?= From: Mikel Lindsaar Content-Type: multipart/mixed; boundary=Apple-Mail-6--589811753 Message-Id: <60A112A8-F26C-4E23-95B8-4EB9F139D6A0@test.lindsaar.net> Date: Fri, 30 Oct 2009 19:11:02 +1100 To: Mikel Lindsaar Mime-Version: 1.0 (Apple Message framework v1076) X-Mailer: Apple Mail (2.1076) --Apple-Mail-6--589811753 Content-Disposition: attachment; filename*0*=utf-8''%E3%81%8B%E3%81%8D%E3%81%8F%E3%81%91%E3%81%93%E3%81%8B%E3%81%8D%E3%81%8F%E3%81%91%E3%81%93%E3%81%8B%E3%81%8D%E3%81%8F%E3%81%91%E3%81%93%E3%81%8B%E3%81%8D%E3%81%8F%E3%81%91%E3%81%93%E3%81%8B; filename*1*=%E3%81%8D%E3%81%8F%E3%81%91%E3%81%93.txt Content-Type: text/plain; x-unix-mode=0644; name="=?utf-8?B?44GL44GN44GP44GR44GT44GL44GN44GP44GR44GT44GL44GN44GP?= =?utf-8?B?44GR44GT44GL44GN44GP44GR44GT44GL44GN44GP44GR44GTLnR4?= =?utf-8?B?dA==?=" Content-Transfer-Encoding: 7bit this is the data --Apple-Mail-6--589811753--mail-2.5.4/spec/fixtures/emails/multi_charset/japanese_shiftjis.eml000066400000000000000000000003741214434061600255610ustar00rootroot00000000000000MIME-Version: 1.0 Subject: =?UTF-8?B?44G+44G/44KA44KB44KC?= From: Mikel Lindsaar To: =?UTF-8?B?44G/44GR44KL?= Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit $B$9$_$^$;$s!#(B mail-2.5.4/spec/fixtures/emails/multipart_report_emails/000077500000000000000000000000001214434061600234705ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/multipart_report_emails/multi_address_bounce1.eml000066400000000000000000000171121214434061600304440ustar00rootroot00000000000000Received: from lvmail01.LL.com (LHLO lvmail01.LL.com) (10.60.6.3) by lvmail01.LL.com with LMTP; Tue, 23 Feb 2010 22:16:41 -0800 (PST) Received: by lvmail01.LL.com (Postfix) id 3E47A1BC025; Tue, 23 Feb 2010 22:16:41 -0800 (PST) Date: Tue, 23 Feb 2010 22:16:41 -0800 (PST) From: MAILER-DAEMON@lvmail01.LL.com (Mail Delivery System) Subject: Undelivered Mail Returned to Sender To: rahul.chaudhari@LL.com Auto-Submitted: auto-replied MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="9B7841BC027.1266992201/lvmail01.LL.com" Content-Transfer-Encoding: 7bit Message-Id: <20100224061641.3E47A1BC025@lvmail01.LL.com> This is a MIME-encapsulated message. --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Notification Content-Type: text/plain; charset=us-ascii This is the mail system at host lvmail01.LL.com. I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. The mail system : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Delivery report Content-Type: message/delivery-status Reporting-MTA: dns; lvmail01.LL.com X-Postfix-Queue-ID: 9B7841BC027 X-Postfix-Sender: rfc822; rahul.chaudhari@LL.com Arrival-Date: Tue, 23 Feb 2010 22:16:15 -0800 (PST) Final-Recipient: rfc822; bbbbvhvbbvkjbhfbvbvjhb@gmail.com Original-Recipient: rfc822;bbbbvhvbbvkjbhfbvbvjhb@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Original-Recipient: rfc822;bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; egyfefsdvsfvvhjsd@gmail.com Original-Recipient: rfc822;egyfefsdvsfvvhjsd@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; kfhejkfbsjkjsbhds@gmail.com Original-Recipient: rfc822;kfhejkfbsjkjsbhds@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com Original-Recipient: rfc822;qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Undelivered Message Content-Type: message/rfc822 Content-Transfer-Encoding: 7bit Return-Path: Received: from localhost (localhost [127.0.0.1]) by lvmail01.LL.com (Postfix) with ESMTP id 9B7841BC027; Tue, 23 Feb 2010 22:16:15 -0800 (PST) X-Virus-Scanned: amavisd-new at LL.com Received: from lvmail01.LL.com ([127.0.0.1]) by localhost (lvmail01.LL.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HXMOLJWXGcFK; Tue, 23 Feb 2010 22:16:15 -0800 (PST) Received: from lvmail01.LL.com (lvmail01.LL.com [10.60.6.3]) by lvmail01.LL.com (Postfix) with ESMTP id 12D311BC025; Tue, 23 Feb 2010 22:16:15 -0800 (PST) Date: Tue, 23 Feb 2010 22:16:14 -0800 (PST) From: Rahul Chaudhari To: egyfefsdvsfvvhjsd@gmail.com, kfhejkfbsjkjsbhds@gmail.com, bbbbvhvbbvkjbhfbvbvjhb@gmail.com, qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com, bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Message-ID: <118707422.15521266992174819.JavaMail.root@lvmail01> Subject: Test of bounce email MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Originating-IP: [10.50.4.44] X-Mailer: Zimbra 6.0.1_GA_1816.UBUNTU8_64 (ZimbraWebClient - FF3.0 (Linux)/6.0.1_GA_1816.UBUNTU8_64) This is just testing. Thanks & Regards, Rahul P. Chaudhari Software Developer LIVIA India Private Limited Board Line - +91.22.6725 5100 Hand Phone - +91.809 783 3437 Web URL: www.LL.com --9B7841BC027.1266992201/lvmail01.LL.com-- mail-2.5.4/spec/fixtures/emails/multipart_report_emails/multi_address_bounce2.eml000066400000000000000000000171121214434061600304450ustar00rootroot00000000000000Received: from lvmail01.LL.com (LHLO lvmail01.LL.com) (10.60.6.3) by lvmail01.LL.com with LMTP; Tue, 23 Feb 2010 22:16:41 -0800 (PST) Received: by lvmail01.LL.com (Postfix) id 3E47A1BC025; Tue, 23 Feb 2010 22:16:41 -0800 (PST) Date: Tue, 23 Feb 2010 22:16:41 -0800 (PST) From: MAILER-DAEMON@lvmail01.LL.com (Mail Delivery System) Subject: Undelivered Mail Returned to Sender To: rahul.chaudhari@LL.com Auto-Submitted: auto-replied MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="9B7841BC027.1266992201/lvmail01.LL.com" Content-Transfer-Encoding: 7bit Message-Id: <20100224061641.3E47A1BC025@lvmail01.LL.com> This is a MIME-encapsulated message. --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Notification Content-Type: text/plain; charset=us-ascii This is the mail system at host lvmail01.LL.com. I'm sorry to have to inform you that your message could not be delivered to one or more recipients. It's attached below. For further assistance, please send mail to postmaster. If you do so, please include this problem report. You can delete your own text from the attached returned message. The mail system : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) : host gmail-smtp-in.l.google.com[209.85.223.33] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 (in reply to RCPT TO command) --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Delivery report Content-Type: message/delivery-status Reporting-MTA: dns; lvmail01.LL.com X-Postfix-Queue-ID: 9B7841BC027 X-Postfix-Sender: rfc822; rahul.chaudhari@LL.com Arrival-Date: Tue, 23 Feb 2010 22:16:15 -0800 (PST) Final-Recipient: rfc822; bbbbvhvbbvkjbhfbvbvjhb@gmail.com Original-Recipient: rfc822;bbbbvhvbbvkjbhfbvbvjhb@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Original-Recipient: rfc822;bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; egyfefsdvsfvvhjsd@gmail.com Original-Recipient: rfc822;egyfefsdvsfvvhjsd@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; kfhejkfbsjkjsbhds@gmail.com Original-Recipient: rfc822;kfhejkfbsjkjsbhds@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 Final-Recipient: rfc822; qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com Original-Recipient: rfc822;qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com Action: failed Status: 5.1.1 Remote-MTA: dns; gmail-smtp-in.l.google.com Diagnostic-Code: smtp; 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 41si5422799iwn.27 --9B7841BC027.1266992201/lvmail01.LL.com Content-Description: Undelivered Message Content-Type: message/rfc822 Content-Transfer-Encoding: 7bit Return-Path: Received: from localhost (localhost [127.0.0.1]) by lvmail01.LL.com (Postfix) with ESMTP id 9B7841BC027; Tue, 23 Feb 2010 22:16:15 -0800 (PST) X-Virus-Scanned: amavisd-new at LL.com Received: from lvmail01.LL.com ([127.0.0.1]) by localhost (lvmail01.LL.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HXMOLJWXGcFK; Tue, 23 Feb 2010 22:16:15 -0800 (PST) Received: from lvmail01.LL.com (lvmail01.LL.com [10.60.6.3]) by lvmail01.LL.com (Postfix) with ESMTP id 12D311BC025; Tue, 23 Feb 2010 22:16:15 -0800 (PST) Date: Tue, 23 Feb 2010 22:16:14 -0800 (PST) From: Rahul Chaudhari To: egyfefsdvsfvvhjsd@gmail.com, kfhejkfbsjkjsbhds@gmail.com, bbbbvhvbbvkjbhfbvbvjhb@gmail.com, qfvhgsvhgsduiohncdhcvhsdfvsfygusd@gmail.com, bscdbcjhasbcjhbdscbhbsdhcbj@gmail.com Message-ID: <118707422.15521266992174819.JavaMail.root@lvmail01> Subject: Test of bounce email MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Originating-IP: [10.50.4.44] X-Mailer: Zimbra 6.0.1_GA_1816.UBUNTU8_64 (ZimbraWebClient - FF3.0 (Linux)/6.0.1_GA_1816.UBUNTU8_64) This is just testing. Thanks & Regards, Rahul P. Chaudhari Software Developer LIVIA India Private Limited Board Line - +91.22.6725 5100 Hand Phone - +91.809 783 3437 Web URL: www.LL.com --9B7841BC027.1266992201/lvmail01.LL.com-- mail-2.5.4/spec/fixtures/emails/multipart_report_emails/multipart_report_multiple_status.eml000066400000000000000000000106731214434061600331300ustar00rootroot00000000000000Return-Path: <> X-Original-To: notification+promo@blah.com Delivered-To: notification+promo@blah.com Received: from schemailmta04.ci.com (schemailmta04.ci.com [209.183.37.58]) by blah.com (Postfix) with ESMTP id 24EF419F546 for ; Tue, 29 Jun 2010 15:42:46 +0000 (UTC) To: notification+promo@blah.com From: Mail Administrator Reply-To: Subject: Mail System Error - Returned Mail Date: Tue, 29 Jun 2010 10:42:44 -0500 Message-ID: <20100629154244.OZPA15102.schemailmta04.ci.com@schemailmta04> MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; Boundary="===========================_ _= 6078796(15102)1277826164" X-Cloudmark-Analysis: v=1.0 c=1 a=q8OS1GolVHwA:10 a=ev1gGZlfZ-EA:10 a=HQ-Cukr2AAAA:8 a=qihIh-XuXL65y3o_mUgA:9 a=mUL5bUDOV_-gjcCZylcY5Lz4jjsA:4 a=iQvSWfByulMA:10 a=ni8l3qMSI1sA:10 a=WHDNLAQ519cA:10 a=Fry9e7MVxuJdODrS104A:9 a=JYo4OF_E9TqbHrUN2TvLdggtx2cA:4 a=S0jCPnXDAAAA:8 a=pXkHMj1YAAAA:8 a=5ErcFzC0N3E7OloTRA8A:9 a=cC0RL7HlXt3RrKfnpEbxHCeM-zQA:4 a=cHEBK1Z0Lu8A:10 a=p9ZeupWRHUwA:10 a=7sPVfr_AX1EA:10 --===========================_ _= 6078796(15102)1277826164 Content-Type: message/delivery-status; This Message was undeliverable due to the following reason: has restricted SMS e-mail Please reply to if you feel this message to be in error. --===========================_ _= 6078796(15102)1277826164 Content-Type: message/delivery-status Reporting-MTA: dns; schemailmta04.ci.com Arrival-Date: Tue, 29 Jun 2010 10:42:37 -0500 Received-From-MTA: dns; schemailedgegx04.ci.com (172.16.130.170) Original-Recipient: rfc822;u@ci.com Final-Recipient: RFC822; Action: failed Status: 5.3.0 --===========================_ _= 6078796(15102)1277826164 Content-Type: message/rfc822 Received: from schemailedgegx04.ci.com ([172.16.130.170]) by schemailmta04.ci.com (InterMail vM.6.01.04.00 201-2131-118-20041027) with ESMTP id <20100629154237.OZBY15102.schemailmta04.ci.com@schemailedgegx04.ci.com> for ; Tue, 29 Jun 2010 10:42:37 -0500 Received: from blah.com ([1.1.1.1]) by schemailedgegx04.ci.com (InterMail vG.1.02.00.04 201-2136-104-104-20050323) with ESMTP id <20100629154225.WEFB17009.schemailedgegx04.ci.com@blah.com> for ; Tue, 29 Jun 2010 10:42:25 -0500 Received: from blah.com (snooki [10.12.126.68]) by blah.com (Postfix) with ESMTP id 4BDAE19F546 for ; Tue, 29 Jun 2010 15:42:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=blah.com; s=2010; t=1277826145; bh=wC3hHAhQgApcTmwQsi2F4OJf40rbyIek/WwIuzSc3V M=; h=Date:From:Reply-To:To:Message-ID:Subject:Mime-Version: Content-Type:Content-Transfer-Encoding:List-Unsubscribe; b=aw+Bhd8 t1goZUXWBAHSrHaM1IdqhkXqF5WVMwGRYcnya4FHNw05XfpB3TTpTFda13DfhtziFRk zHSfiNbMapv7Vz+D3A/9NHg5nKahSMosZVTa0BfajYWNd1aY8JUWUlxdQHxQQ4ygCBj /MndJohtSm6K3gsqdIv88DNXdBGBEw= Date: Tue, 29 Jun 2010 15:42:25 +0000 From: HomeRun Reply-To: HomeRun To: u@ci.com Message-ID: <4c2a146147ac8_61ff157c4ec1652df@s.h.c.mail> Subject: Your Friend F M wants you to join HomeRun Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="--==_mimepart_4c2a146141756_61ff157c4ec1649a8"; charset=UTF-8 Content-Transfer-Encoding: 7bit List-Unsubscribe: ----==_mimepart_4c2a146141756_61ff157c4ec1649a8 Date: Tue, 29 Jun 2010 15:42:25 +0000 Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: base64 Content-ID: <4c2a146145451_61ff157c4ec165040@s.h.c.mail> SGV5IGNpbmd1bGFybWVmYXJpZGEsCgpGYXJpZGEgTWFsaWsgdGhpbmtzIHlv dSBzaG91bGQgYXBwbHkgdG8gam9pbiBIb21lUnVuLCB5b3VyIHBsYWNlIGZv dC4sIFNhbiBGcmFuY2lzY28sIENBLCA5NDEyMywgVVNB ----==_mimepart_4c2a146141756_61ff157c4ec1649a8 Date: Tue, 29 Jun 2010 15:42:25 +0000 Mime-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: base64 Content-ID: <4c2a1461468ae_61ff157c4ec165194@s.h.c.mail> PCFET0NUWVBFIGh0bWw+CjxodG1sPgo8aGVhZD4KPHRpdGxlPkhvbWVSdW4g LSBZb3VyIEZyaWVuZCBGYXJpZGEgTWFsaWsgd2FudHMgeW91IHRvIGpvaW4g cnVuLmNvbS9vLjQ1YjBkMzgwLmdpZicgd2lkdGg9JzEnIC8+CjwvdGQ+Cjwv dHI+CjwvdGFibGU+CjwvdGQ+CjwvdHI+CjwvdGFibGU+CjwvZGl2Pgo8L2Jv ZHk+CjwvaHRtbD4K ----==_mimepart_4c2a146141756_61ff157c4ec1649a8-- --===========================_ _= 6078796(15102)1277826164-- Comments mail-2.5.4/spec/fixtures/emails/multipart_report_emails/report_422.eml000066400000000000000000000100101214434061600260610ustar00rootroot00000000000000Return-Path: Received: from acomputer ([unix socket]) by imap01.sssssss.net (Cyrus) with LMTPA; Wed, 16 Jan 2008 13:51:42 -0800 X-Sieve: CMU Sieve 2.2 Received: from smtp.sssssss.org (unknown [198.0.0.92]) by imap01.sssssss.net (Postfix) with ESMTP id BFE6477FAE for ; Wed, 16 Jan 2008 13:51:40 -0800 (PST) Received: from ns1.sssssss.net.au (ns1.sssssss.net.au [202.0.0.246]) by smtp.sssssss.org (Postfix) with ESMTP id 96E5C6C6830 for ; Wed, 16 Jan 2008 11:08:14 -0800 (PST) Received: from ns1.sssssss.net.au (unknown [127.0.0.1]) by ns1.sssssss.net.au (Postfix) with ESMTP id E1BCEF227 for ; Thu, 17 Jan 2008 03:40:53 +1100 (EST) Received: from ns1.sssssss.net.au (ns1.sssssss.net.au [202.0.0.246]) by localhost (FormatMessage) with SMTP id ceaa681bbcb6c7f6 for ; Thu, 17 Jan 2008 03:40:53 +1100 (EST) Received: from mail11.tppppp.com.au (unknown [203.0.0.161]) by ns1.sssssss.net.au (Postfix) with ESMTP id 7F2D2F225 for ; Thu, 17 Jan 2008 03:40:52 +1100 (EST) Received: from localhost (localhost) by mail11.tppppp.com.au (envelope-from MAILER-DAEMON) (8.14.2/8.14.2) id m0GFZ1c3009410; Thu, 17 Jan 2008 03:40:52 +1100 Date: Thu, 17 Jan 2008 03:40:52 +1100 From: Mail Delivery Subsystem Message-Id: <200801161640.m0GFZ1c3009410@mail11.ttttt.com.au> To: MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="m0GFZ1c3009410.1200501652/mail11.ttttt.com.au" Subject: Warning: could not send message for past 8 hours Auto-Submitted: auto-generated (warning-timeout) Resent-Date: Thu, 17 Jan 2008 03:40:53 +1100 (EST) Resent-From: Resent-To: Resent-Message-ID: X-Spam-Status: No --m0GFZ1c3009410.1200501652/mail11.ttttt.com.au Content-Type: text/plain ********************************************** ** THIS IS A WARNING MESSAGE ONLY ** ** YOU DO NOT NEED TO RESEND YOUR MESSAGE ** ********************************************** The original message was received at Wed, 16 Jan 2008 19:38:07 +1100 from 60-0-0-61.static.tppppp.com.au [60.0.0.61] This message was generated by mail11.tppppp.com.au ----- Transcript of session follows ----- .... while talking to mail.oooooooo.com.au.: >>> DATA <<< 452 4.2.2 ... Mailbox full ... Deferred: 452 4.2.2 ... Mailbox full <<< 503 5.0.0 Need RCPT (recipient) Warning: message still undelivered after 8 hours Will keep trying until message is 5 days old -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. --m0GFZ1c3009410.1200501652/mail11.ttttt.com.au Content-Type: message/delivery-status Reporting-MTA: dns; mail11.ttttt.com.au Arrival-Date: Wed, 16 Jan 2008 19:38:07 +1100 Final-Recipient: RFC822; fraser@oooooooo.com.au Action: delayed Status: 4.2.2 Remote-MTA: DNS; mail.oooooooo.com.au Diagnostic-Code: SMTP; 452 4.2.2 ... Mailbox full Last-Attempt-Date: Thu, 17 Jan 2008 03:40:52 +1100 --m0GFZ1c3009410.1200501652/mail11.ttttt.com.au Content-Type: text/rfc822-headers Return-Path: Received: from k1s2yo86 (60-0-0-61.static.tppppp.com.au [60.0.0.61]) by mail11.tppppp.com.au (envelope-from jennifer@sss.sssssss.net.au) (8.14.2/8.14.2) with ESMTP id m0G8c0fR020461 for ; Wed, 16 Jan 2008 19:38:07 +1100 Date: Wed, 16 Jan 2008 19:38:07 +1100 From: Sydney Message-ID: <15655788.13.1200472642578.JavaMail.Administrator@mail.ttttt.com.au> Subject: Wanted MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_12_28168925.1200472642578" X-Virus-Scanned: ClamAV 0.91.2/5484/Wed Jan 16 06:31:27 2008 on mail11.tppppp.com.au X-Virus-Status: Clean --m0GFZ1c3009410.1200501652/mail11.ttttt.com.au-- mail-2.5.4/spec/fixtures/emails/multipart_report_emails/report_530.eml000066400000000000000000000100471214434061600260730ustar00rootroot00000000000000Return-Path: Received: from acomputer ([unix socket]) by imap01.sssss.net (Cyrus) with LMTPA; Sun, 23 Dec 2007 15:04:04 -0800 X-Sieve: CMU Sieve 2.2 Received: from smtp.sssss.org (unknown [198.0.0.92]) by imap01.sssss.net (Postfix) with ESMTP id E434877FB0 for ; Sun, 23 Dec 2007 15:04:03 -0800 (PST) Received: from mail12.tttttt.com.au (mail12.tttttt.com.au [203.0.0.162]) by smtp.sssss.org (Postfix) with ESMTP id 53313B42B7 for ; Sun, 23 Dec 2007 15:03:54 -0800 (PST) Received: from localhost (localhost) by mail12.tttttt.com.au (envelope-from MAILER-DAEMON) (8.14.2/8.14.2) id lBNN3rDp003436; Mon, 24 Dec 2007 10:03:53 +1100 Date: Mon, 24 Dec 2007 10:03:53 +1100 From: Mail Delivery Subsystem Message-Id: <200712232303.lBNN3rDp003436@mail12.rrrr.com.au> To: MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="lBNN3rDp003436.1198451033/mail12.rrrr.com.au" Subject: Returned mail: see transcript for details Auto-Submitted: auto-generated (failure) X-Spam-Status: No This is a MIME-encapsulated message --lBNN3rDp003436.1198451033/mail12.rrrr.com.au The original message was received at Mon, 24 Dec 2007 10:03:47 +1100 from 60-0-0-146.static.tttttt.com.au [60.0.0.146] This message was generated by mail12.tttttt.com.au ----- The following addresses had permanent fatal errors ----- (reason: 553 5.3.0 ... Unknown E-Mail Address) ----- Transcript of session follows ----- ... while talking to mail.zzzzzz.com.: >>> DATA <<< 553 5.3.0 ... Unknown E-Mail Address 550 5.1.1 ... User unknown <<< 503 5.0.0 Need RCPT (recipient) -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. --lBNN3rDp003436.1198451033/mail12.rrrr.com.au Content-Type: message/delivery-status Reporting-MTA: dns; mail12.rrrr.com.au Received-From-MTA: DNS; 60-0-0-146.static.tttttt.com.au Arrival-Date: Mon, 24 Dec 2007 10:03:47 +1100 Final-Recipient: RFC822; edwin@zzzzzzz.com Action: failed Status: 5.3.0 Remote-MTA: DNS; mail.zzzzzz.com Diagnostic-Code: SMTP; 553 5.3.0 ... Unknown E-Mail Address Last-Attempt-Date: Mon, 24 Dec 2007 10:03:53 +1100 --lBNN3rDp003436.1198451033/mail12.rrrr.com.au Content-Type: text/rfc822-headers Return-Path: Received: from [192.168.0.3] (60-0-0-146.static.tttttt.com.au [60.0.0.146]) by mail12.tttttt.com.au (envelope-from mikel@sssss.net) (8.14.2/8.14.2) with ESMTP id lBNN3jDq002941 for ; Mon, 24 Dec 2007 10:03:47 +1100 Resent-Date: Mon, 24 Dec 2007 10:03:47 +1100 Date: Mon, 24 Dec 2007 10:03:47 +1100 Resent-Message-Id: <200712232303.lBNN3jDq002941@mail12.rrrr.com.au> Message-Id: <200712232303.lBNN3jDq002941@mail12.rrrr.com.au> Mime-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary=80874BE0-2DFF-4BCB-8AA1-A00E17ACA2EA Received: from murder ([unix socket]) by imap01.sssss.net (Cyrus v2.2.12-Invoca-RPM-2.2.12-6.fc4) with LMTPA; Sun, 23 Dec 2007 12:59:14 -0800 Received: from smtp.sssss.org (unknown [198.0.0.92]) by imap01.sssss.net (Postfix) with ESMTP id 0AC9F77EDD for ; Sun, 23 Dec 2007 12:59:14 -0800 (PST) Received: from ns1.sssss.net.au (ns1.sssss.net.au [202.0.0.246]) by smtp.sssss.org (Postfix) with ESMTP id 6FC83B42B4 for ; Sun, 23 Dec 2007 12:59:09 -0800 (PST) Received: from unicom (unknown [85.0.0.121]) by ns1.sssss.net.au (Postfix) with ESMTP id 85ED5F1F7 for ; Mon, 24 Dec 2007 07:59:02 +1100 (EST) Received: from [85.0.0.121] by mail.zzzzzz.com; , 23 Dec 2007 12:57:34 -0800 X-Mailer: Apple Mail (2.753) From: postoffice Subject: Returned mail: User unknown Resent-From: mikel@sssss.net Auto-Submitted: auto-generated (failure) To: "Merrill" X-Virus-Scanned: ClamAV 0.91.2/5229/Mon Dec 24 07:36:55 2007 on mail12.tttttt.com.au X-Virus-Status: Clean --lBNN3rDp003436.1198451033/mail12.rrrr.com.au-- mail-2.5.4/spec/fixtures/emails/plain_emails/000077500000000000000000000000001214434061600211575ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/plain_emails/basic_email.eml000066400000000000000000000027571214434061600241210ustar00rootroot00000000000000Delivered-To: raasdnil@gmail.com Received: by 10.140.178.13 with SMTP id a13cs354079rvf; Fri, 21 Nov 2008 20:05:05 -0800 (PST) Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Return-Path: Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net X-TPG-Junk-Status: Message not scanned X-TPG-Antivirus: Passed Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 for ; Sat, 22 Nov 2008 15:05:01 +1100 Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> From: Mikel Lindsaar To: Mikel Lindsaar Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v929.2) Subject: Testing 123 Date: Sat, 22 Nov 2008 15:04:59 +1100 X-Mailer: Apple Mail (2.929.2) Plain email. Hope it works well! Mikel mail-2.5.4/spec/fixtures/emails/plain_emails/mix_caps_content_type.eml000066400000000000000000000005251214434061600262560ustar00rootroot00000000000000From joe@company.com Fri Feb 19 08:41:30 2010 From: Big Bug bb@bug.com To: rubymail@ruby-lang.org Subject: undef method parameter bug Date: Fri, 19 Feb 2010 10:08:29 +0300 MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Message-Id: 201002191008.30117.foo.bar@company.com foo bar mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email.eml000066400000000000000000000010401214434061600236110ustar00rootroot00000000000000From jamis_buck@byu.edu Mon May 2 16:07:05 2005 Mime-Version: 1.0 (Apple Message framework v622) Content-Transfer-Encoding: base64 Message-Id: Content-Type: text/plain; charset=EUC-KR; format=flowed To: willard15georgina@jamis.backpackit.com From: Jamis Buck Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= Date: Mon, 2 May 2005 16:07:05 -0600 tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin wLogSmFtaXPA1LTPtNku mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email10.eml000066400000000000000000000016741214434061600237670ustar00rootroot00000000000000Return-Path: Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 Date: Tue, 10 May 2005 15:27:03 -0500 From: xxx@xxxx.xxx Sender: xxx@xxxx.xxx To: xxxxxxxxxxx@xxxx.xxxx.xxx Message-Id: X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx Delivered-To: xxx@xxxx.xxx Importance: normal Content-Type: text/plain; charset=X-UNKNOWN Test test. Hi. Waving. m ---------------------------------------------------------------- Sent via Bell Mobility's Text Messaging service. Envoyé par le service de messagerie texte de Bell Mobilité. ---------------------------------------------------------------- mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email5.eml000066400000000000000000000016201214434061600237020ustar00rootroot00000000000000Return-Path: Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 Date: Tue, 10 May 2005 15:27:03 -0500 From: xxx@xxxx.xxx Sender: xxx@xxxx.xxx To: xxxxxxxxxxx@xxxx.xxxx.xxx Message-Id: X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx Delivered-To: xxx@xxxx.xxx Importance: normal Test test. Hi. Waving. m ---------------------------------------------------------------- Sent via Bell Mobility's Text Messaging service. Envoyé par le service de messagerie texte de Bell Mobilité. ---------------------------------------------------------------- mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email6.eml000066400000000000000000000016731214434061600237130ustar00rootroot00000000000000Return-Path: Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 Date: Tue, 10 May 2005 15:27:03 -0500 From: xxx@xxxx.xxx Sender: xxx@xxxx.xxx To: xxxxxxxxxxx@xxxx.xxxx.xxx Message-Id: X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx Delivered-To: xxx@xxxx.xxx Importance: normal Content-Type: text/plain; charset=us-ascii Test test. Hi. Waving. m ---------------------------------------------------------------- Sent via Bell Mobility's Text Messaging service. Envoyé par le service de messagerie texte de Bell Mobilité. ---------------------------------------------------------------- mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email8.eml000066400000000000000000000035101214434061600237050ustar00rootroot00000000000000From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 Return-Path: Message-ID: Date: Sun, 8 May 2005 14:09:11 -0500 From: xxxxxxxxx xxxxxxx Reply-To: xxxxxxxxx xxxxxxx To: xxxxx xxxx Subject: Fwd: Signed email causes file attachments In-Reply-To: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_5028_7368284.1115579351471" References: ------=_Part_5028_7368284.1115579351471 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline We should not include these files or vcards as attachments. ---------- Forwarded message ---------- From: xxxxx xxxxxx Date: May 8, 2005 1:17 PM Subject: Signed email causes file attachments To: xxxxxxx@xxxxxxxxxx.com Hi, Test attachments oddly encoded with japanese charset. ------=_Part_5028_7368284.1115579351471 Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3 Content-Transfer-Encoding: base64 Content-Disposition: attachment MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw ------=_Part_5028_7368284.1115579351471-- mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_bad_time.eml000066400000000000000000000044211214434061600254430ustar00rootroot00000000000000Return-Path: Received: from murder ([unix socket]) by imap1.AAAAAAAAA.net (Cyrus v2.2.12-Invoca-RPM-2.2.12-6.fc4) with LMTPA; Mon, 30 Jun 2008 02:34:00 -0700 X-Sieve: CMU Sieve 2.2 Received: from smtp2.BBBBBBBBBBB.org (unknown [10.254.15.30]) by imap1.AAAAAAAAA.net (Postfix) with ESMTP id 9444077D75 for ; Mon, 30 Jun 2008 02:34:00 -0700 (PDT) Received: from localhost (unknown [92.47.238.91]) by smtp2.BBBBBBBBBBB.org (Postfix) with ESMTP id 44D0110011 for ; Mon, 9 Jun 2008 12:24:02 -0700 (PDT) Message-ID: <86a2019dbec6$caa86cc0$390b0485@auracom.net> From: "=?windows-1251?B?wPLo6u7iYQ==?=" To: Subject: [0]: XXXXXXX XXXXX XXXXX ! Date: Mon, 30 Jun 3609 15:33:50 +0600 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=----=_NextPart_000_0023_08_E8CD50F3.4EF2F754 X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 6.00.2900.2180 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180 X-CSI-MailScanner-Information: Please contact the ISP for more information X-CSI-MailScanner: Found to be clean X-CSI-MailScanner-SpamCheck: spam, ORDB-RBL X-CSI-MailScanner-From: yusuf75thu@auracom.net X-Spam-Status: Yes This is a multi-part message in MIME format. ------=_NextPart_000_0023_08_E8CD50F3.4EF2F754 Content-Type: text/plain; charset="windows-1251" Content-Transfer-Encoding: quoted-printable Filter2: This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. ------=_NextPart_000_0023_08_E8CD50F3.4EF2F754 Content-Type: text/html; charset="windows-1251" Content-Transfer-Encoding: quoted-printable
    This message has been scanned for viruses and
    dangerous content by MailScanner, and is
    believed to be clean. ------=_NextPart_000_0023_08_E8CD50F3.4EF2F754-- mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_double_at_in_header.eml000066400000000000000000000010421214434061600276270ustar00rootroot00000000000000From jamis_buck@byu.edu Mon May 2 16:07:05 2005 Mime-Version: 1.0 (Apple Message framework v622) Content-Transfer-Encoding: base64 Message-Id: Content-Type: text/plain; charset=EUC-KR; format=flowed To: willard15georgina@jamis.backpackit.com From: Jamis Buck Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= Date: Mon, 2 May 2005 16:07:05 -0600 tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin wLogSmFtaXPA1LTPtNku mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_incorrect_header.eml000066400000000000000000000016021214434061600271750ustar00rootroot00000000000000Received: from xxx.xxx.xxx ([xxx.xxx.xxx.xxx] verified) by xxx.com (CommuniGate Pro SMTP 4.2.8) with SMTP id 2532598 for xxx@xxx.com; Wed, 23 Feb 2005 17:51:49 -0500 Received-SPF: softfail receiver=xxx.com; client-ip=xxx.xxx.xxx.xxx; envelope-from=xxx@xxx.xxx quite Delivered-To: xxx@xxx.xxx Received: by xxx.xxx.xxx (Wostfix, from userid xxx) id 0F87F333; Wed, 23 Feb 2005 16:16:17 -0600 Date: Wed, 23 Feb 2005 18:20:17 -0400 From: "xxx xxx" Message-ID: <4D6AA7EB.6490534@xxx.xxx> To: xxx@xxx.com Subject: Stop adware/spyware once and for all. X-Scanned-By: MIMEDefang 2.11 (www dot roaringpenguin dot com slash mimedefang) You are infected with: Ad Ware and Spy Ware Get your free scan and removal download now, before it gets any worse. http://xxx.xxx.info?aid=3D13&?stat=3D4327kdzt no more? (you will still be infected) http://xxx.xxx.info/discon/?xxx@xxx.com mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_multiple_from.eml000066400000000000000000000017361214434061600265630ustar00rootroot00000000000000Delivered-To: tim@powerupdev.com Return-Path: To: tim@powerupdev.com concierge@powerupdev.com From: tim@powerupdev.com concierge@powerupdev.com Subject: /home/svn/public/minebox revision 214 Reply-to: tim@powerupdev.com concierge@powerupdev.com Message-Id: <20071022234523.5BD8E86D2@mangaverde.net> Date: Mon, 22 Oct 2007 23:45:23 +0000 (UTC)

    recordkick 2007-10-22 23:45:23 +0000 (Mon, 22 Oct 2007)

    test subversion


    Modified:
    trunk/README
    ===================================================================
    --- trunk/README\t2007-10-22
    23:41:34 UTC (rev 213)
    +++ trunk/README\t2007-10-22 23:45:23 UTC (rev 214)
    @@ -1,5 +1,5 @@
     == Welcome
    to Rails
    -Test
    +Tedst
     Rails is a web-application and persistence framework that includes everything
     needed
    to create database-backed web-applications according to the
     Model-View-Control pattern of separation. This pattern
    splits the view (also
    
    
    
    mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_quoted_with_0d0a.eml000066400000000000000000000011701214434061600270350ustar00rootroot00000000000000Mime-Version: 1.0 (Apple Message framework v730) Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> From: foo@example.com Subject: testing Date: Mon, 6 Jun 2005 22:21:22 +0200 To: blah@example.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain A fax has arrived from remote ID ''.=0D=0A-----------------------= -------------------------------------=0D=0ATime: 3/9/2006 3:50:52= PM=0D=0AReceived from remote ID: =0D=0AInbound user ID XXXXXXXXXX, r= outing code XXXXXXXXX=0D=0AResult: (0/352;0/0) Successful Send=0D=0AP= age record: 1 - 1=0D=0AElapsed time: 00:58 on channel 11=0D=0A mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_reply.eml000066400000000000000000000026501214434061600250340ustar00rootroot00000000000000Return-Path: Received: from me ([unix socket]) by xxxxx1.xxxx.net (Cyrus v2.2.12) with LMTPA; Sun, 18 Nov 2007 00:56:33 -0800 Received: from smtp.xxxx.org (unknown [127.0.0.1]) by xxxxx1.xxxx.net (Postfix) with ESMTP id F128477EB5; Sun, 18 Nov 2007 00:56:32 -0800 (PST) Received: from omta02sl.mx.bigpond.com (omta02sl.mx.bigpond.com [144.140.93.154]) by smtp.xxxx.org (Postfix) with ESMTP id 2D567ACC08; Sun, 18 Nov 2007 00:56:28 -0800 (PST) Received: from oaamta05sl.mx.bigpond.com ([124.183.219.10]) by omta02sl.mx.bigpond.com with ESMTP id <20071118085627.YVPI22254.omta02sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com>; Sun, 18 Nov 2007 08:56:27 +0000 Received: from [10.0.0.1] (really [124.183.219.10]) by oaamta05sl.mx.bigpond.com with ESMTP id <20071118085627.TQWF6995.oaamta05sl.mx.bigpond.com@[10.0.0.1]>; Sun, 18 Nov 2007 08:56:27 +0000 Message-ID: <473FFE27.20003@xxx.org> Date: Sun, 18 Nov 2007 19:56:07 +1100 From: Testing User-Agent: Mozilla Thunderbird 1.0.6 (Windows/20050716) X-Accept-Language: en-us, en MIME-Version: 1.0 To: Mikel Lindsaar Subject: Re: Test reply email References: <473FF3B8.9020707@xxx.org> <348F04F142D69C21-291E56D292BC@xxxx.net> In-Reply-To: <348F04F142D69C21-291E56D292BC@xxxx.net> Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Message body mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_simple.eml000066400000000000000000000007041214434061600251700ustar00rootroot00000000000000From mike@nowhere.com Return-Path: Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 Date: Sun, 21 Oct 2007 19:38:13 +1000 From: Mikel Lindsaar To: Mikel Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> Subject: Testing outlook Hello Mikel mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_string_in_date_field.eml000066400000000000000000000012661214434061600300370ustar00rootroot00000000000000From mikel@me.com Mon May 2 16:07:05 2005 Mime-Version: 1.0 (Apple Message framework v622) Received: from jsj1wlrmd001.webex.com (by jsj1wlrmd001.webex.com (8.12.10/8.12.11) with ESMTP id m8MKKPTs022429 for ; Mon, 22 Sep 2008 20:20:25 GMT Content-Transfer-Encoding: base64 Message-Id: Content-Type: text/plain; charset=EUC-KR; format=flowed To: bob@bob.com From: mikel@me.com Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= Date: Sat, 20 Sep 2008 20:04:30 +0300 (ùòåï ÷éõ éøåùìéí) tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin wLogSmFtaXPA1LTPtNku mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_trailing_dot.eml000066400000000000000000000023171214434061600263600ustar00rootroot00000000000000Delivered-To: xxx@xxx.com Received: by 10.67.31.8 with SMTP id i8cs1195ugj; Mon, 22 Sep 2008 13:45:18 -0700 (PDT) Received: by 10.100.207.5 with SMTP id e5mr3483815ang.104.1222110393505; Mon, 22 Sep 2008 12:06:33 -0700 (PDT) Return-Path: Received: from rubyforge.org (rubyforge.org [205.234.109.19]) by mx.google.com with ESMTP id c2si899474ana.10.2008.09.22.12.06.28; Mon, 22 Sep 2008 12:06:33 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of noreply@rubyforge.org designates 205.234.109.19 as permitted sender) client-ip=205.234.109.19; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of noreply@rubyforge.org designates 205.234.109.19 as permitted sender) smtp.mail=noreply@rubyforge.org Received: by rubyforge.org (Postfix, from userid 502) id 8FB1518581AC; Mon, 22 Sep 2008 15:06:28 -0400 (EDT) To: noreply@rubyforge.org From: Sandy M. Subject: [skynet-help][60666] How are intermediate files handled in SkyNet? Content-type: text/plain; charset=UTF-8 Message-Id: <20080922190628.8FB1518581AC@rubyforge.org> Date: Mon, 22 Sep 2008 15:06:28 -0400 (EDT) Testing, testing, 123.mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_with_at_display_name.eml000066400000000000000000000030411214434061600300600ustar00rootroot00000000000000Delivered-To: raasdnil@gmail.com Received: by 10.140.178.13 with SMTP id a13cs354079rvf; Fri, 21 Nov 2008 20:05:05 -0800 (PST) Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Return-Path: Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; Fri, 21 Nov 2008 20:05:04 -0800 (PST) Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net X-TPG-Junk-Status: Message not scanned X-TPG-Antivirus: Passed Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 for ; Sat, 22 Nov 2008 15:05:01 +1100 Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> From: Mikel Lindsaar , jack@lindsar.com To: smith@gmail.com, Mikel@Lindsaar , tom@gmail.com Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v929.2) Subject: Testing 123 Date: Sat, 22 Nov 2008 15:04:59 +1100 X-Mailer: Apple Mail (2.929.2) Plain email. Hope it works well! Mikel mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_with_bad_date.eml000066400000000000000000000041541214434061600264600ustar00rootroot00000000000000Return-Path: X-Original-To: external@xxx.xxxxxxxx.xxx.xx Delivered-To: external@xxx.xxxxxxxx.xxx.xx Received: from server.xxx.xxxxxxxx.xxx.xx (localhost.xxxxxxxx.xxx.xx [127.0.0.1]) by server.xxx.xxxxxxxx.xxx.xx (Postfix) with ESMTP id 0173828456 for ; Mon, 5 Nov 2007 20:17:37 +1100 (EST) Received: from server.xxx.xxxxxxxx.xxx.xx (server.xxx.xxxxxxxx.xxx.xx [10.130.1.250]) by localhost (FormatMessage) with SMTP id d7be4d19ed6d330c for ; Mon, 05 Nov 2007 20:17:37 +1100 (EST) Received: from server.sydney.xxxxxxxx.xxx.xx (unknown [10.130.2.6]) by server.xxx.xxxxxxxx.xxx.xx (Postfix) with ESMTP id BB00328442 for ; Mon, 5 Nov 2007 20:17:37 +1100 (EST) Received: from dircomm (unknown [10.130.2.8]) by server.sydney.xxxxxxxx.xxx.xx (Postfix) with ESMTP id 20A692841F for ; Mon, 5 Nov 2007 20:18:24 +1100 (EST) X-Mailbox-Line: From subventive@vodtravel.com Message-ID: <000001c81a67$a4450700$0100007f@localhost> From: "Darrell Shaw" To: Subject: Microsoft Vlsta & Office2007, Just released for 79$ Save 1599.95$ 0ff Retai| Date: Pn, 29 paX 2007 21:13:00 +0100 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook, Build 10.0.3416 Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.150 X-CSI-TMailScanner-Information: Please contact the ISP for more information X-CSI-TMailScanner: Found to be clean X-CSI-TMailScanner-SpamCheck: not spam, SpamAssassin (score=1.87, required 4, autolearn=disabled, INVALID_DATE 0.23, RAZOR2_CF_RANGE_51_100 1.49, RAZOR2_CHECK 0.15) X-CSI-TMailScanner-SpamScore: s X-TMailScanner-From: subventive@vodtravel.com Resent-Date: Mon, 05 Nov 2007 20:17:37 +1100 (EST) Resent-From: Resent-To: Resent-Message-ID: X-UID: 4702 Status: RO hotnewsoft . com mail-2.5.4/spec/fixtures/emails/plain_emails/raw_email_with_partially_quoted_subject.eml000066400000000000000000000010231214434061600320260ustar00rootroot00000000000000From jamis@37signals.com Mon May 2 16:07:05 2005 Mime-Version: 1.0 (Apple Message framework v622) Content-Transfer-Encoding: base64 Message-Id: Content-Type: text/plain; charset=EUC-KR; format=flowed To: jamis@37signals.com From: Jamis Buck Subject: Re: Test: =?UTF-8?B?Iua8ouWtlyI=?= mid =?UTF-8?B?Iua8ouWtlyI=?= tail Date: Mon, 2 May 2005 16:07:05 -0600 tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin wLogSmFtaXPA1LTPtNku mail-2.5.4/spec/fixtures/emails/rfc2822/000077500000000000000000000000001214434061600176125ustar00rootroot00000000000000mail-2.5.4/spec/fixtures/emails/rfc2822/example01.eml000066400000000000000000000003501214434061600221030ustar00rootroot00000000000000From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example02.eml000066400000000000000000000004301214434061600221030ustar00rootroot00000000000000From: John Doe Sender: Michael Jones To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example03.eml000066400000000000000000000004351214434061600221110ustar00rootroot00000000000000From: "Joe Q. Public" To: Mary Smith , jdoe@example.org, Who? Cc: , "Giant; \"Big\" Box" Date: Tue, 1 Jul 2003 10:52:37 +0200 Message-ID: <5678.21-Nov-1997@example.com> Hi everyone. mail-2.5.4/spec/fixtures/emails/rfc2822/example04.eml000066400000000000000000000003461214434061600221130ustar00rootroot00000000000000From: Pete To: A Group:Chris Jones ,joe@where.test,John ; Cc: Undisclosed recipients:; Date: Thu, 13 Feb 1969 23:32:54 -0330 Message-ID: Testing. mail-2.5.4/spec/fixtures/emails/rfc2822/example05.eml000066400000000000000000000003501214434061600221070ustar00rootroot00000000000000From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example06.eml000066400000000000000000000005421214434061600221130ustar00rootroot00000000000000From: Mary Smith To: John Doe Reply-To: "Mary Smith: Personal Account" Subject: Re: Saying Hello Date: Fri, 21 Nov 1997 10:01:10 -0600 Message-ID: <3456@example.net> In-Reply-To: <1234@local.machine.example> References: <1234@local.machine.example> This is a reply to your hello. mail-2.5.4/spec/fixtures/emails/rfc2822/example07.eml000066400000000000000000000005151214434061600221140ustar00rootroot00000000000000To: "Mary Smith: Personal Account" From: John Doe Subject: Re: Saying Hello Date: Fri, 21 Nov 1997 11:00:00 -0600 Message-ID: In-Reply-To: <3456@example.net> References: <1234@local.machine.example> <3456@example.net> This is a reply to your reply. mail-2.5.4/spec/fixtures/emails/rfc2822/example08.eml000066400000000000000000000006311214434061600221140ustar00rootroot00000000000000Resent-From: Mary Smith Resent-To: Jane Brown Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800 Resent-Message-ID: <78910@example.net> From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example09.eml000066400000000000000000000006771214434061600221270ustar00rootroot00000000000000Received: from x.y.test by example.net via TCP with ESMTP id ABC12345 for ; 21 Nov 1997 10:05:43 -0600 Received: from machine.example by x.y.test; 21 Nov 1997 10:01:22 -0600 From: John Doe To: Mary Smith Subject: Saying Hello Date: Fri, 21 Nov 1997 09:55:06 -0600 Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example10.eml000066400000000000000000000007321214434061600221070ustar00rootroot00000000000000From: Pete(A wonderful \) chap) To:A Group(Some people) :Chris Jones , joe@example.org, John (my dear friend); (the end of the group) Cc:(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ; Date: Thu, 13 Feb 1969 23:32 -0330 (Newfoundland Time) Message-ID: Testing. mail-2.5.4/spec/fixtures/emails/rfc2822/example11.eml000066400000000000000000000003341214434061600221060ustar00rootroot00000000000000From: Joe Q. Public To: Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example Date: Tue, 1 Jul 2003 10:52:37 +0200 Message-ID: <5678.21-Nov-1997@example.com> Hi everyone. mail-2.5.4/spec/fixtures/emails/rfc2822/example12.eml000066400000000000000000000003371214434061600221120ustar00rootroot00000000000000From: John Doe To: Mary Smith Subject: Saying Hello Date: 21 Nov 97 09:55:06 GMT Message-ID: <1234@local.machine.example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example13.eml000066400000000000000000000004461214434061600221140ustar00rootroot00000000000000From : John Doe To : Mary Smith __ Subject : Saying Hello Date : Fri, 21 Nov 1997 09(comment): 55 : 06 -0600 Message-ID : <1234 @ local(blah) .machine .example> This is a message just to say hello. So, "Hello". mail-2.5.4/spec/fixtures/emails/rfc2822/example14.eml000066400000000000000000000007261214434061600221160ustar00rootroot00000000000000From test@example.com Mon Aug 22 09:45:15 2011 Date: Fri, 19 Aug 2011 10:47:17 +0900 From: Atsushi Yoshida Reply-To: rudeboyjet@gmail.com Subject: Re: TEST =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?= =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?= To: rudeboyjet@gmail.com Message-Id: <0CC5E11ED2C1D@example.com> In-Reply-To: Mime-Version: 1.0 Content-Type: text/plain; charset=iso-2022-jp Content-Transfer-Encoding: 7bit Hello mail-2.5.4/spec/fixtures/emails/sample_output_multipart000066400000000000000000000000001214434061600234350ustar00rootroot00000000000000mail-2.5.4/spec/mail/000077500000000000000000000000001214434061600143215ustar00rootroot00000000000000mail-2.5.4/spec/mail/attachments_list_spec.rb000066400000000000000000000311351214434061600212310ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' def encode_base64(str) Mail::Encodings::Base64.encode(str) end def check_decoded(actual, expected) if RUBY_VERSION >= '1.9' actual.encoding.should eq Encoding::BINARY actual.should eq expected.force_encoding(Encoding::BINARY) else actual.should eq expected end end describe "Attachments" do before(:each) do @mail = Mail.new @test_png = File.open(fixture('attachments', 'test.png'), 'rb', &:read) end describe "from direct content" do it "should work" do @mail.attachments['test.png'] = @test_png @mail.attachments['test.png'].filename.should eq 'test.png' check_decoded(@mail.attachments[0].decoded, @test_png) end it "should work out magically the mime_type" do @mail.attachments['test.png'] = @test_png @mail.attachments[0].mime_type.should eq 'image/png' end it "should assign the filename" do @mail.attachments['test.png'] = @test_png @mail.attachments[0].filename.should eq 'test.png' end it "should assign mime-encoded multibyte filename" do @mail.attachments['てすと.txt'] = File.open(fixture('attachments', 'てすと.txt'), 'rb', &:read) @mail.attachments.should_not be_blank Mail::Encodings.decode_encode(@mail.attachments[0].filename, :decode).should eq 'てすと.txt' end end describe "from a supplied Hash" do it "should work" do @mail.attachments['test.png'] = { :content => @test_png } @mail.attachments[0].filename.should eq 'test.png' check_decoded(@mail.attachments[0].decoded, @test_png) end it "should allow you to override the content_type" do @mail.attachments['test.png'] = { :content => @test_png, :content_type => "application/x-gzip" } @mail.attachments[0].content_type.should eq 'application/x-gzip' end it "should allow you to override the mime_type" do @mail.attachments['test.png'] = { :content => @test_png, :mime_type => "application/x-gzip" } @mail.attachments[0].mime_type.should eq 'application/x-gzip' end it "should allow you to override the mime_type" do @mail.attachments['invoice.jpg'] = { :data => "you smiling", :mime_type => "image/x-jpg", :transfer_encoding => "base64" } @mail.attachments[0].mime_type.should eq 'image/x-jpg' end end describe "decoding and encoding" do it "should set its content_transfer_encoding" do @mail.attachments['test.png'] = { :content => @test_png } @mail.ready_to_send! @mail.attachments[0].content_transfer_encoding.should eq 'base64' end it "should encode its body to base64" do @mail.attachments['test.png'] = { :content => @test_png } @mail.ready_to_send! @mail.attachments[0].encoded.should include(encode_base64(@test_png)) end it "should allow you to pass in an encoded attachment with an encoding" do encoded_data = encode_base64(@test_png) @mail.attachments['test.png'] = { :content => encoded_data, :encoding => 'base64' } check_decoded(@mail.attachments[0].decoded, @test_png) end it "should allow you set a mime type and encoding without overriding the encoding" do encoded = encode_base64('') @mail.attachments['test.png'] = { :mime_type => 'text/xml', :content => encoded, :encoding => 'base64' } @mail.attachments[0].content_transfer_encoding.should eq 'base64' check_decoded(@mail.attachments[0].decoded, '') end it "should not allow you to pass in an encoded attachment with an unknown encoding" do base64_encoded_data = encode_base64(@test_png) doing {@mail.attachments['test.png'] = { :content => base64_encoded_data, :encoding => 'weird_encoding' }}.should raise_error end it "should be able to call read on the attachment to return the decoded data" do @mail.attachments['test.png'] = { :content => @test_png } if RUBY_VERSION >= '1.9' expected = @mail.attachments[0].read.force_encoding(@test_png.encoding) else expected = @mail.attachments[0].read end expected.should eq @test_png end it "should only add one newline between attachment body and boundary" do contents = "I have\ntwo lines with trailing newlines\n\n" @mail.attachments['text.txt'] = { :content => contents} encoded = @mail.encoded regex = /\r\n#{Regexp.escape(contents.gsub(/\n/, "\r\n"))}\r\n--#{@mail.boundary}--\r\n\Z/ encoded.should match regex end end describe "multiple attachments" do it "should allow you to pass in more than one attachment" do mail = Mail.new mail.attachments['test.pdf'] = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) mail.attachments['test.gif'] = File.open(fixture('attachments', 'test.gif'), 'rb', &:read) mail.attachments['test.jpg'] = File.open(fixture('attachments', 'test.jpg'), 'rb', &:read) mail.attachments['test.zip'] = File.open(fixture('attachments', 'test.zip'), 'rb', &:read) mail.attachments[0].filename.should eq 'test.pdf' mail.attachments[1].filename.should eq 'test.gif' mail.attachments[2].filename.should eq 'test.jpg' mail.attachments[3].filename.should eq 'test.zip' end end describe "inline attachments" do it "should set the content_disposition to inline or attachment as appropriate" do mail = Mail.new mail.attachments['test.pdf'] = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) mail.attachments['test.pdf'].content_disposition.should eq 'attachment; filename=test.pdf' mail.attachments.inline['test.png'] = File.open(fixture('attachments', 'test.png'), 'rb', &:read) mail.attachments.inline['test.png'].content_disposition.should eq 'inline; filename=test.png' end it "should return a cid" do mail = Mail.new mail.attachments.inline['test.png'] = @test_png mail.attachments['test.png'].url.should eq "cid:#{mail.attachments['test.png'].cid}" end it "should respond true to inline?" do mail = Mail.new mail.attachments.inline['test.png'] = @test_png mail.attachments['test.png'].should be_inline end end describe "getting the content ID from an attachment" do before(:each) do @mail = Mail.new @mail.attachments['test.gif'] = File.open(fixture('attachments', 'test.gif'), 'rb', &:read) @cid = @mail.attachments['test.gif'].content_id end it "should return a content-id for the attachment on creation if passed inline => true" do @cid.should_not be_nil end it "should return a valid content-id on inline attachments" do Mail::ContentIdField.new(@cid).errors.should be_empty end it "should provide a URL escaped content_id (without brackets) for use inside an email" do @inline = @mail.attachments['test.gif'].cid uri_parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI @inline.should eq uri_parser.escape(@cid.gsub(/^$/, '')) end end describe "setting the content type correctly" do it "should set the content type to multipart/mixed if none given and you add an attachment" do mail = Mail.new mail.attachments['test.pdf'] = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) mail.encoded mail.mime_type.should eq 'multipart/mixed' end it "allows you to set the attachment before the content type" do mail = Mail.new mail.attachments["test.png"] = File.open(fixture('attachments', 'test.png'), 'rb', &:read) mail.body = "Lots of HTML" mail.mime_version = '1.0' mail.content_type = 'text/html; charset=UTF-8' end end describe "should handle filenames with non-7bit characters correctly" do it "should not raise an exception with a filename that contains a non-7bit-character" do filename = "f\u00f6\u00f6.b\u00e4r" if RUBY_VERSION >= '1.9' filename.encoding.should eq Encoding::UTF_8 end mail = Mail.new doing { mail.attachments[filename] = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) }.should_not raise_error end end end describe "reading emails with attachments" do describe "test emails" do it "should find the attachment using content location" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_content_location.eml'))) mail.attachments.length.should eq 1 end it "should find an attachment defined with 'name' and Content-Disposition: attachment" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_content_disposition.eml'))) mail.attachments.length.should eq 1 end it "should use the content-type filename or name over the content-disposition filename" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_content_disposition.eml'))) mail.attachments[0].filename.should eq 'hello.rb' end it "should decode an attachment" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_pdf.eml'))) mail.attachments[0].decoded.length.should eq 1026 end it "should find an attachment that has an encoded name value" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_with_encoded_name.eml'))) mail.attachments.length.should eq 1 result = mail.attachments[0].filename if RUBY_VERSION >= '1.9' expected = "01 Quien Te Dij\212at. Pitbull.mp3".force_encoding(result.encoding) else expected = "01 Quien Te Dij\212at. Pitbull.mp3" end result.should eq expected end it "should find an attachment that has a name not surrounded by quotes" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', "attachment_with_unquoted_name.eml"))) mail.attachments.length.should eq 1 mail.attachments.first.filename.should eq "This is a test.txt" end it "should find attachments inside parts with content-type message/rfc822" do mail = Mail.read(fixture(File.join("emails", "attachment_emails", "attachment_message_rfc822.eml"))) mail.attachments.length.should eq 1 mail.attachments[0].decoded.length.should eq 1026 end it "attach filename decoding (issue 83)" do data = <<-limitMAIL Subject: aaa From: aaa@aaa.com To: bbb@aaa.com Content-Type: multipart/mixed; boundary=0016e64c0af257c3a7048b69e1ac --0016e64c0af257c3a7048b69e1ac Content-Type: multipart/alternative; boundary=0016e64c0af257c3a1048b69e1aa --0016e64c0af257c3a1048b69e1aa Content-Type: text/plain; charset=ISO-8859-1 aaa --0016e64c0af257c3a1048b69e1aa Content-Type: text/html; charset=ISO-8859-1 aaa
    --0016e64c0af257c3a1048b69e1aa-- --0016e64c0af257c3a7048b69e1ac Content-Type: text/plain; charset=US-ASCII; name="=?utf-8?b?Rm90bzAwMDkuanBn?=" Content-Disposition: attachment; filename="=?utf-8?b?Rm90bzAwMDkuanBn?=" Content-Transfer-Encoding: base64 X-Attachment-Id: f_gbneqxxy0 YWFhCg== --0016e64c0af257c3a7048b69e1ac-- limitMAIL mail = Mail.new(data) #~ puts Mail::Encodings.decode_encode(mail.attachments[0].filename, :decode) mail.attachments[0].filename.should eq "Foto0009.jpg" end end end describe "attachment order" do it "should be preserved instead when content type exists" do mail = Mail.new do to "aaaa@aaaa.aaa" from "aaaa2@aaaa.aaa" subject "a subject" date Time.now text_part do content_type 'text/plain; charset=UTF-8' body "a \nsimplebody\n" end end mail.attachments['test.zip'] = File.open(fixture('attachments', 'test.zip'), 'rb', &:read) mail.attachments['test.pdf'] = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) mail.attachments['test.gif'] = File.open(fixture('attachments', 'test.gif'), 'rb', &:read) mail.attachments['test.jpg'] = File.open(fixture('attachments', 'test.jpg'), 'rb', &:read) mail.attachments[0].filename.should eq 'test.zip' mail.attachments[1].filename.should eq 'test.pdf' mail.attachments[2].filename.should eq 'test.gif' mail.attachments[3].filename.should eq 'test.jpg' mail2 = Mail.new(mail.encoded) mail2.attachments[0].filename.should eq 'test.zip' mail2.attachments[1].filename.should eq 'test.pdf' mail2.attachments[2].filename.should eq 'test.gif' mail2.attachments[3].filename.should eq 'test.jpg' end end mail-2.5.4/spec/mail/body_spec.rb000066400000000000000000000410241214434061600166160ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Body do # 3.5 Overall message syntax # # A message consists of header fields, optionally followed by a message # body. Lines in a message MUST be a maximum of 998 characters # excluding the CRLF, but it is RECOMMENDED that lines be limited to 78 # characters excluding the CRLF. (See section 2.1.1 for explanation.) # In a message body, though all of the characters listed in the text # rule MAY be used, the use of US-ASCII control characters (values 1 # through 8, 11, 12, and 14 through 31) is discouraged since their # interpretation by receivers for display is not guaranteed. # # message = (fields / obs-fields) # [CRLF body] # # body = *(*998text CRLF) *998text # # The header fields carry most of the semantic information and are # defined in section 3.6. The body is simply a series of lines of text # which are uninterpreted for the purposes of this standard. # describe "initialization" do it "should be instantiated" do doing { Mail::Body.new }.should_not raise_error end it "should initialize on a nil value" do doing { Mail::Body.new(nil) }.should_not raise_error end it "should accept text as raw source data" do body = Mail::Body.new('this is some text') body.to_s.should eq 'this is some text' end it "should accept nil as a value and return an empty body" do body = Mail::Body.new body.to_s.should eq '' end it "should accept an array as the body and join it" do doing { Mail::Body.new(["line one\n", "line two\n"]) }.should_not raise_error end it "should accept an array as the body and join it" do body = Mail::Body.new(["line one\n", "line two\n"]) body.encoded.should eq "line one\r\nline two\r\n" end end describe "encoding" do it "should accept text as raw source data" do body = Mail::Body.new('this is some text') body.encoded.should eq 'this is some text' end it "should set its own encoding to us_ascii if it is ascii only body" do body = Mail::Body.new('This is some text') body.charset.should eq 'US-ASCII' end it "should allow you to set its encoding" do body = Mail::Body.new('') body.charset = 'UTF-8' body.charset.should eq 'UTF-8' end it "should allow you to specify an encoding" do body = Mail::Body.new('') body.encoding = 'base64' body.encoding.should eq 'base64' end it "should convert all new lines to crlf" do body = Mail::Body.new("This has \n various \r new \r\n lines") body.encoded.should eq "This has \r\n various \r\n new \r\n lines" end end describe "decoding" do it "should convert all new lines to crlf" do body = Mail::Body.new("This has \n various \r new \r\n lines") body.decoded.should eq "This has \n various \n new \n lines" end it "should not change a body on decode if not given an encoding type to decode" do body = Mail::Body.new("The=3Dbody") body.decoded.should eq "The=3Dbody" end it "should change return the raw text if it does not recognise the encoding" do body = Mail::Body.new("The=3Dbody") body.encoding = '7bit' body.decoded.should eq "The=3Dbody" end it "should change a body on decode if given an encoding type to decode" do body = Mail::Body.new("The=3Dbody") body.encoding = 'quoted-printable' body.decoded.should eq "The=body" end it "should change a body on decode if given an encoding type to decode" do body = Mail::Body.new("VGhlIGJvZHk=\n") body.encoding = 'base64' body.decoded.should eq "The body" end end describe "splitting up a multipart document" do it "should store the boundary passed in" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.boundary.should eq '----=_Part_2192_32400445' end it "should split at the boundry string given returning two message bodies" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445').parts.length.should eq 2 end it "should keep the preamble text as its own preamble" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.preamble.should eq "this is some text" end it "should return the parts as their own messages" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.parts[0].class.should eq Mail::Part body.parts[1].class.should eq Mail::Part end it "should return the first part as its own message" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.parts[0].content_type.should eq "text/plain; charset=ISO-8859-1" end it "should return the first part as its own message" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.parts[1].content_type.should eq "text/html" end it "should separate out its parts" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.should be_multipart end it "should keep track of its parts" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.parts.length.should eq 2 end it "should round trip its parts" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.preamble = "Really! this is some text" body.epilogue = "And this is the end" new_body = Mail::Body.new(body.encoded) new_body.split!('----=_Part_2192_32400445') new_body.parts.length.should eq 2 new_body.parts[0].decoded.should eq "This is a plain text\n" new_body.parts[1].decoded.should eq "

    This is HTML

    " new_body.preamble.should eq "Really! this is some text" new_body.epilogue.should eq "And this is the end" end it "should allow you to change the boundary" do multipart_body = "this is some text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nThis is a plain text\r\n\r\n------=_Part_2192_32400445\r\nContent-Type: text/html\r\n\r\n

    This is HTML

    \r\n------=_Part_2192_32400445--\r\n" body = Mail::Body.new(multipart_body) body.split!('----=_Part_2192_32400445') body.boundary = '------=_MIMEPART' new_body = Mail::Body.new(body.encoded) new_body.split!('------=_MIMEPART') new_body.parts.length.should eq 2 new_body.preamble.should eq "this is some text" end end describe "detecting non ascii" do it "should say an empty string is all ascii" do body = Mail::Body.new body.should be_only_us_ascii end it "should say if a body is ascii" do body = Mail::Body.new('This is ASCII') body.should be_only_us_ascii end it "should say if a body is not ascii" do body = Mail::Body.new("This is NOT plain text ASCII − かきくけこ") body.should_not be_only_us_ascii end end describe "adding parts" do it "should allow you to add a part" do body = Mail::Body.new('') body << Mail::Part.new('') body.parts.length.should eq 1 body.should be_multipart end it "should allow you to sort the parts" do body = Mail::Body.new('') body << Mail::Part.new("content-type: text/html\r\nsubject: HTML") body << Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text") body << Mail::Part.new("content-type: text/enriched\r\nsubject: Enriched") body.parts.length.should eq 3 body.should be_multipart body.sort_parts! body.parts[0].content_type.should eq "text/plain" body.parts[1].content_type.should eq "text/enriched" body.parts[2].content_type.should eq "text/html" end it "should allow you to sort the parts with an arbitrary sort order" do body = Mail::Body.new('') body.set_sort_order([ "text/plain", "text/html", "text/enriched" ]) body << Mail::Part.new("content-type: text/html\r\nsubject: HTML") body << Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text") body << Mail::Part.new("content-type: text/enriched\r\nsubject: Enriched") body.parts.length.should eq 3 body.should be_multipart body.sort_parts! body.parts[0].content_type.should eq "text/plain" body.parts[1].content_type.should eq "text/html" body.parts[2].content_type.should eq "text/enriched" end it "should allow you to sort the parts with an arbitrary sort order" do body = Mail::Body.new('') body.set_sort_order(["application/x-yaml", "text/plain"]) body << Mail::Part.new("content-type: text/plain\r\nsubject: HTML") body << Mail::Part.new("content-type: text/html\r\nsubject: Plain Text") body << Mail::Part.new("content-type: application/x-yaml\r\nsubject: Enriched") body.parts.length.should eq 3 body.should be_multipart body.sort_parts! body.parts[0].content_type.should eq "application/x-yaml" body.parts[1].content_type.should eq "text/plain" body.parts[2].content_type.should eq "text/html" end it "should sort the parts on encode" do body = Mail::Body.new('') body << Mail::Part.new("content-type: text/html\r\nsubject: HTML") body << Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text") body << Mail::Part.new("content-type: text/enriched\r\nsubject: Enriched") body.parts.length.should eq 3 body.should be_multipart body.encoded body.parts[0].content_type.should eq "text/plain" body.parts[1].content_type.should eq "text/enriched" body.parts[2].content_type.should eq "text/html" end it "should put the part types it doesn't know about at the end" do body = Mail::Body.new('') body << Mail::Part.new("content-type: text/html\r\nsubject: HTML") body << Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text") body << Mail::Part.new("content-type: image/jpeg\r\n") body.parts.length.should eq 3 body.should be_multipart body.encoded body.parts[0].content_type.should eq "text/plain" body.parts[1].content_type.should eq "text/html" body.parts[2].content_type.should eq "image/jpeg" end it "should allow you to sort the parts recursively" do part = Mail::Part.new('Content-Type: multipart/alternate') part.add_part(Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text")) part.add_part(Mail::Part.new("content-type: text/html\r\nsubject: HTML")) part.add_part(Mail::Part.new("content-type: text/enriched\r\nsubject: Enriched")) body = Mail::Body.new('') body << part body << Mail::Part.new("content-type: image/jpeg\r\nsubject: JPGEG\r\n\r\nsdkjskjdksjdkjsd") body.parts.length.should eq 2 body.should be_multipart body.sort_parts! body.parts[0].content_type.should match %r{\Amultipart/alternate(;|\Z)} body.parts[1].content_type.should eq "image/jpeg" body.parts[0].parts[0].content_type.should eq "text/plain" body.parts[0].parts[1].content_type.should eq "text/enriched" body.parts[0].parts[2].content_type.should eq "text/html" end it "should allow you to sort the parts recursively" do part = Mail::Part.new('Content-Type: multipart/alternate') part.add_part(Mail::Part.new("content-type: text/enriched\r\nsubject: Enriched")) part.add_part(Mail::Part.new("content-type: text/plain\r\nsubject: Plain Text")) part.add_part(Mail::Part.new("content-type: text/html\r\nsubject: HTML")) body = Mail::Body.new('') body << part body << Mail::Part.new("content-type: image/jpeg\r\nsubject: JPGEG\r\n\r\nsdkjskjdksjdkjsd") body.parts.length.should eq 2 body.should be_multipart body.sort_parts! body.parts[0].content_type.should match %r{\Amultipart/alternate(;|\Z)} body.parts[1].content_type.should eq "image/jpeg" body.parts[0].parts[0].content_type.should eq "text/plain" body.parts[0].parts[1].content_type.should eq "text/enriched" body.parts[0].parts[2].content_type.should eq "text/html" end end describe "matching" do it "should still equal itself" do body = Mail::Body.new('The body') body.should eq body end it "should match on the body part decoded if given a string to ==" do body = Mail::Body.new('The body') (body == 'The body').should be_true end it "should match on the body part decoded if given a string to ==" do body = Mail::Body.new("VGhlIGJvZHk=\n") body.encoding = 'base64' (body == "The body").should be_true end it "should match on the body part decoded if given a string to =~" do body = Mail::Body.new('The body') (body =~ /The/).should eq 0 end it "should match on the body part decoded if given a string to ==" do body = Mail::Body.new("VGhlIGJvZHk=\n") body.encoding = 'base64' (body =~ /The/).should eq 0 end it "should match on the body part decoded if given a string to match" do body = Mail::Body.new('The body') (body.match(/The/))[0].should eq 'The' end it "should match on the body part decoded if given a string to match" do body = Mail::Body.new("VGhlIGJvZHk=\n") body.encoding = 'base64' (body.match(/The/))[0].should eq 'The' end it "should match on the body part decoded if given a string to include?" do body = Mail::Body.new('The Body') body.should include('The') end it "should match on the body part decoded if given a string to include?" do body = Mail::Body.new("VGhlIGJvZHk=\n") body.encoding = 'base64' body.should include('The') end end describe "non US-ASCII charset" do it "should encoded" do body = Mail::Body.new("あいうえお\n") body.charset = 'iso-2022-jp' expect = (RUBY_VERSION < '1.9') ? "あいうえお\r\n" : "\e$B$\"$$$&$($*\e(B\r\n" body.encoded.should eq expect end end end mail-2.5.4/spec/mail/configuration_spec.rb000066400000000000000000000043071214434061600205330ustar00rootroot00000000000000require 'spec_helper' class MyTestDeliveryMethod attr_accessor :settings def initialize(values) self.settings = {}.merge!(values) end end describe Mail::Configuration do describe "network configurations" do it "defaults delivery_method to smtp" do # Need to clear out any prior configuration, as setting nil on the config # will not clear it. Mail::Configuration.instance.send(:initialize) Mail.defaults { delivery_method nil, { :address => 'some.host' } } Mail.delivery_method.settings[:address].should eq 'some.host' end it "should be available from the Mail.defaults method" do Mail.defaults { delivery_method :smtp, { :address => 'some.host' } } Mail.delivery_method.settings[:address].should eq 'some.host' end it "should configure sendmail" do Mail.defaults { delivery_method :sendmail, :location => "/usr/bin/sendmail" } Mail.delivery_method.class.should eq Mail::Sendmail Mail.delivery_method.settings[:location].should eq "/usr/bin/sendmail" end it "should configure sendmail using a string" do Mail.defaults { delivery_method 'sendmail', :location => "/usr/bin/sendmail" } Mail.delivery_method.class.should eq Mail::Sendmail Mail.delivery_method.settings[:location].should eq "/usr/bin/sendmail" end it "should configure exim" do Mail.defaults { delivery_method :exim, :location => "/usr/bin/exim" } Mail.delivery_method.class.should eq Mail::Exim Mail.delivery_method.settings[:location].should eq "/usr/bin/exim" end it "should configure an open SMTP connection" do smtp = Net::SMTP.start('127.0.0.1', 25) Mail.defaults { delivery_method :smtp_connection, {:connection => smtp} } Mail.delivery_method.class.should eq Mail::SMTPConnection Mail.delivery_method.smtp.should eq smtp end it "should accept a plug-in delivery method" do Mail.defaults { delivery_method MyTestDeliveryMethod, { :option1 => "one", :option2 => "two" }} Mail.delivery_method.class.should eq MyTestDeliveryMethod Mail.delivery_method.settings[:option1].should eq "one" Mail.delivery_method.settings[:option2].should eq "two" end end end mail-2.5.4/spec/mail/core_extensions/000077500000000000000000000000001214434061600175305ustar00rootroot00000000000000mail-2.5.4/spec/mail/core_extensions/string_spec.rb000066400000000000000000000026121214434061600223760ustar00rootroot00000000000000 require 'spec_helper' describe 'core_extensions/string' do describe "to_crlf" do it "should change a single LF to CRLF" do "\n".to_crlf.should eq "\r\n" end it "should change multiple LF to CRLF" do "\n\n".to_crlf.should eq "\r\n\r\n" end it "should change a single CR to CRLF" do "\r".to_crlf.should eq "\r\n" end it "should not change CRLF" do "\r\n".to_crlf.should eq "\r\n" end it "should not change multiple CRLF" do "\r\n\r\n".to_crlf.should eq "\r\n\r\n" end it "should handle a mix" do "\r \n\r\n".to_crlf.should eq "\r\n \r\n\r\n" end end describe "to_lf" do it "should change a single CR to LF" do "\r".to_lf.should eq "\n" end it "should change multiple LF to CRLF" do "\r\r".to_lf.should eq "\n\n" end it "should change a single CRLF to LF" do "\r\n".to_lf.should eq "\n" end it "should change multiple CR to LF" do "\r\n\r\n".to_lf.should eq "\n\n" end it "should not change LF" do "\n".to_lf.should eq "\n" end it "should not change multiple CRLF" do "\n\n".to_lf.should eq "\n\n" end it "should handle a mix" do "\r \n\r\n".to_lf.should eq "\n \n\n" end end describe 'constantize' do it 'should converts string to constant' do "Kernel".constantize.should eq Kernel end end end mail-2.5.4/spec/mail/core_extensions_spec.rb000066400000000000000000000054741214434061600211010ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Object do describe "blank method" do it "should say nil is blank" do nil.should be_blank end it "should say false is blank" do false.should be_blank end it "should say true is not blank" do true.should_not be_blank end it "should say an empty array is blank" do [].should be_blank end it "should say an empty hash is blank" do {}.should be_blank end it "should say an empty string is blank" do ''.should be_blank " ".should be_blank a = ''; 1000.times { a << ' ' } a.should be_blank "\t \n\n".should be_blank end end describe "not blank method" do it "should say a number is not blank" do 1.should_not be_blank end it "should say a valueless hash is not blank" do {:one => nil, :two => nil}.should_not be_blank end it "should say a hash containing an empty hash is not blank" do {:key => {}}.should_not be_blank end end describe "to_lf method on String" do it "should leave lf as lf" do "\n".to_lf.should eq "\n" end it "should clean just cr to lf" do "\r".to_lf.should eq "\n" end it "should leave crlf as lf" do "\r\n".to_lf.should eq "\n" end it "should handle japanese characters" do string = "\343\201\202\343\201\210\343\201\206\343\201\210\343\201\212\r\n\r\n\343\201\213\343\201\215\343\201\217\343\201\221\343\201\223\r\n\r\n\343\201\225\343\201\227\343\201\244\343\201\233\343\201\235\r\n\r\n" string.to_lf.should eq "\343\201\202\343\201\210\343\201\206\343\201\210\343\201\212\n\n\343\201\213\343\201\215\343\201\217\343\201\221\343\201\223\n\n\343\201\225\343\201\227\343\201\244\343\201\233\343\201\235\n\n" end end describe "to_crlf method on String" do it "should clean just lf to crlf" do "\n".to_crlf.should eq "\r\n" end it "should clean just cr to crlf" do "\r".to_crlf.should eq "\r\n" end it "should leave crlf as crlf" do "\r\n".to_crlf.should eq "\r\n" end it "should handle japanese characters" do string = "\343\201\202\343\201\210\343\201\206\343\201\210\343\201\212\r\n\r\n\343\201\213\343\201\215\343\201\217\343\201\221\343\201\223\r\n\r\n\343\201\225\343\201\227\343\201\244\343\201\233\343\201\235\r\n\r\n" string.to_crlf.should eq "\343\201\202\343\201\210\343\201\206\343\201\210\343\201\212\r\n\r\n\343\201\213\343\201\215\343\201\217\343\201\221\343\201\223\r\n\r\n\343\201\225\343\201\227\343\201\244\343\201\233\343\201\235\r\n\r\n" end end describe "methods on NilClass" do it "should return empty string on to_crlf" do nil.to_crlf.should eq '' end it "should return empty string on to_lf" do nil.to_lf.should eq '' end end end mail-2.5.4/spec/mail/elements/000077500000000000000000000000001214434061600161355ustar00rootroot00000000000000mail-2.5.4/spec/mail/elements/address_list_spec.rb000066400000000000000000000125431214434061600221610ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::AddressList do describe "parsing" do it "should parse an address list" do parse_text = 'test@lindsaar.net' doing { Mail::AddressList.new(parse_text) }.should_not raise_error end it "should raise an error if the input is useless" do parse_text = '@@@@@@' doing { Mail::AddressList.new(parse_text) }.should raise_error end it "should not raise an error if the input is just blank" do parse_text = nil doing { Mail::AddressList.new(parse_text) }.should_not raise_error end it "should raise an error if the input is useless" do parse_text = "This ( is an invalid address!" doing { Mail::AddressList.new(parse_text) }.should raise_error end it "should give the address passed in" do parse_text = 'test@lindsaar.net' result = 'test@lindsaar.net' a = Mail::AddressList.new(parse_text) a.addresses.first.to_s.should eq result end it "should give the addresses passed in" do parse_text = 'test@lindsaar.net, test2@lindsaar.net' result = ['test@lindsaar.net', 'test2@lindsaar.net'] a = Mail::AddressList.new(parse_text) a.addresses.map {|addr| addr.to_s }.should eq result end it "should preserve the display name" do parse_text = '"Mikel Lindsaar" ' result = 'Mikel Lindsaar ' a = Mail::AddressList.new(parse_text) a.addresses.first.format.should eq result a.addresses.first.display_name.should eq 'Mikel Lindsaar' end it "should handle and ignore nil addresses" do parse_text = ' , user-example@aol.com, e-s-a-s-2200@app.ar.com' result = ['user-example@aol.com', 'e-s-a-s-2200@app.ar.com'] a = Mail::AddressList.new(parse_text) a.addresses.map {|addr| addr.to_s }.should eq result end it "should handle truly horrific combinations of commas, spaces, and addresses" do parse_text = ' ,, foo@example.com, , ,,, bar@example.com ,,' result = ['foo@example.com', 'bar@example.com'] a = Mail::AddressList.new(parse_text) a.addresses.map {|addr| addr.to_s }.should eq result end it "should handle folding whitespace" do parse_text = "foo@example.com,\r\n\tbar@example.com" result = ['foo@example.com', 'bar@example.com'] a = Mail::AddressList.new(parse_text) a.addresses.map {|addr| addr.to_s }.should eq result end it "should handle malformed folding whitespace" do pending parse_text = "leads@sg.dc.com,\n\t sag@leads.gs.ry.com,\n\t sn@example-hotmail.com,\n\t e-s-a-g-8718@app.ar.com,\n\t jp@t-exmaple.com,\n\t\n\t cc@c-l-example.com" result = %w(leads@sg.dc.com sag@leads.gs.ry.com sn@example-hotmail.com e-s-a-g-8718@app.ar.com jp@t-exmaple.com cc@c-l-example.com) a = Mail::AddressList.new(parse_text) a.addresses.map {|addr| addr.to_s }.should eq result end it "should extract comments in addreses which are part of a group" do parse_text = "group: jimmy ;"; result = ["comment"] a = Mail::AddressList.new(parse_text) a.addresses.first.comments.should eq result end end describe "functionality" do it "should give back a list of address nodes" do list = Mail::AddressList.new('mikel@me.com, bob@you.com') list.address_nodes.length.should eq 2 end it "should make each node a class of SyntaxNode" do list = Mail::AddressList.new('mikel@me.com, bob@you.com') list.address_nodes.each { |n| n.class.should eq Treetop::Runtime::SyntaxNode } end it "should give a block of address nodes with groups" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.address_nodes.length.should eq 2 end it "should give all the recipients when asked" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.individual_recipients.length.should eq 1 end it "should give all the groups when asked" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.group_recipients.length.should eq 1 end it "should ask the group for all its addresses" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.group_recipients.first.group_list.addresses.length.should eq 2 end it "should give all the addresses when asked" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.addresses.length.should eq 3 end it "should handle a really nasty obsolete address list" do pending psycho_obsolete = "Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example" list = Mail::AddressList.new(psycho_obsolete) list.addresses.length.should eq 2 end it "should create an address instance for each address returned" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.addresses.each do |address| address.class.should eq Mail::Address end end it "should provide a list of group names" do list = Mail::AddressList.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') list.group_names.should eq ["my_group"] end end end mail-2.5.4/spec/mail/elements/address_spec.rb000066400000000000000000001040141214434061600211210ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Address do describe "functionality" do it "should allow us to instantiate an empty address object and call inspect" do doing { Mail::Address.new.inspect }.should_not raise_error end it "should allow us to instantiate an empty address object and call to_s" do Mail::Address.new.to_s.should eq '' end it "should allow us to instantiate an empty address object and call format" do Mail::Address.new.format.should eq '' end it "should allow us to instantiate an empty address object and call address" do [nil, '', ' '].each do |input| Mail::Address.new(input).address.should eq nil end end it "should allow us to instantiate an empty address object and call local" do [nil, '', ' '].each do |input| Mail::Address.new(input).local.should eq nil end end it "should allow us to instantiate an empty address object and call domain" do [nil, '', ' '].each do |input| Mail::Address.new(input).domain.should eq nil end end ['"-Earnings...Notification-" ', '<56253817>'].each do |spammy_address| it "should ignore funky local-only spammy addresses in angle brackets #{spammy_address}" do Mail::Address.new(spammy_address).address.should eq nil end end it "should give its address back on :to_s if there is no display name" do parse_text = 'test@lindsaar.net' result = 'test@lindsaar.net' Mail::Address.new(parse_text).to_s.should eq result end it "should give its format back on :to_s if there is a display name" do parse_text = 'Mikel Lindsaar ' result = 'Mikel Lindsaar ' Mail::Address.new(parse_text).to_s.should eq result end it "should give back the display name" do parse_text = 'Mikel Lindsaar ' result = 'Mikel Lindsaar' a = Mail::Address.new(parse_text) a.display_name.should eq result end it "should preserve the display name passed in" do parse_text = '"Mikel Lindsaar" ' result = 'Mikel Lindsaar' a = Mail::Address.new(parse_text) a.display_name.should eq result end it "should preserve the display name passed in with token unsafe chars" do parse_text = '"Mikel@@@Lindsaar" ' result = 'Mikel@@@Lindsaar' a = Mail::Address.new(parse_text) a.display_name.should eq result end it "should decode the display name without calling #decoded first" do encoded = '=?ISO-8859-1?Q?Jan_Kr=FCtisch?= ' Mail::Address.new(encoded).display_name.should eq 'Jan Krütisch' end it "should give back the local part" do parse_text = 'Mikel Lindsaar ' result = 'test' a = Mail::Address.new(parse_text) a.local.should eq result end it "should give back the domain" do parse_text = 'Mikel Lindsaar ' result = 'lindsaar.net' a = Mail::Address.new(parse_text) a.domain.should eq result end it "should give back the formated address" do parse_text = 'Mikel Lindsaar ' result = 'Mikel Lindsaar ' a = Mail::Address.new(parse_text) a.format.should eq result end it "should handle an address without a domain" do parse_text = 'test' result = 'test' a = Mail::Address.new(parse_text) a.address.should eq result end it "should handle comments" do parse_text = "Mikel Lindsaar (author) " result = ['author'] a = Mail::Address.new(parse_text) a.comments.should eq result end it "should handle multiple comments" do parse_text = "Mikel (first name) Lindsaar (author) " result = ['first name', 'author'] a = Mail::Address.new(parse_text) a.comments.should eq result end it "should give back the raw value" do parse_text = "Mikel (first name) Lindsaar (author) " result = "Mikel (first name) Lindsaar (author) " a = Mail::Address.new(parse_text) a.raw.should eq result end it "should format junk addresses as raw text" do junk = '<"somename@gmail.com">' Mail::Address.new(junk).format.should eq junk end end describe "assigning values directly" do it "should allow you to assign an address" do a = Mail::Address.new a.address = 'mikel@test.lindsaar.net' a.address.should eq 'mikel@test.lindsaar.net' a.format.should eq 'mikel@test.lindsaar.net' end it "should allow you to assign a display name" do a = Mail::Address.new a.display_name = 'Mikel Lindsaar' a.display_name.should eq 'Mikel Lindsaar' end it "should return an empty format a display name and no address defined" do a = Mail::Address.new a.display_name = 'Mikel Lindsaar' a.format.should eq '' end it "should allow you to assign an address and a display name" do a = Mail::Address.new a.address = 'mikel@test.lindsaar.net' a.display_name = 'Mikel Lindsaar' a.format.should eq 'Mikel Lindsaar ' end end describe "parsing" do describe "basic email addresses" do it "should handle all OK local parts" do [['aamine', 'aamine'], ['"Minero Aoki"', '"Minero Aoki"'], ['"!@#$%^&*()"', '"!@#$%^&*()"'], ['a.b.c', 'a.b.c'] ].each do |(words, ok)| a = Mail::Address.new(words) a.local.should eq ok end end it "should handle all OK domains" do [['loveruby.net', 'loveruby.net'], ['"love ruby".net', '"love ruby".net'], ['a."love ruby".net', 'a."love ruby".net'], ['"!@#$%^&*()"', '"!@#$%^&*()"'], ['[192.168.1.1]', '[192.168.1.1]'] ].each do |(words, ok)| a = Mail::Address.new(%Q|me@#{words}|) a.domain.should eq ok end end end describe "email addresses from the wild" do it "should handle |aamine@loveruby.net|" do address = Mail::Address.new('aamine@loveruby.net') address.should break_down_to({ :display_name => nil, :address => 'aamine@loveruby.net', :local => 'aamine', :domain => 'loveruby.net', :format => 'aamine@loveruby.net', :comments => nil, :raw => 'aamine@loveruby.net'}) end it "should handle |Minero Aoki |" do address = Mail::Address.new('Minero Aoki ') address.should break_down_to({ :display_name => 'Minero Aoki', :address => 'aamine@loveruby.net', :local => 'aamine', :domain => 'loveruby.net', :format => 'Minero Aoki ', :comments => nil, :raw => 'Minero Aoki '}) end it "should handle |Minero Aoki|" do address = Mail::Address.new('Minero Aoki') address.should break_down_to({ :display_name => 'Minero Aoki', :address => 'aamine@loveruby.net', :local => 'aamine', :domain => 'loveruby.net', :format => 'Minero Aoki ', :comments => nil, :raw => 'Minero Aoki'}) end it 'should handle |"Minero Aoki" |' do address = Mail::Address.new('"Minero Aoki" ') address.should break_down_to({ :display_name => 'Minero Aoki', :address => 'aamine@loveruby.net', :local => 'aamine', :domain => 'loveruby.net', :format => 'Minero Aoki ', :comments => nil, :raw => '"Minero Aoki" '}) end it "should handle |Minero Aoki|" do address = Mail::Address.new('Minero Aoki') address.should break_down_to({ :display_name => 'Minero Aoki', :address => 'aamine@0246.loveruby.net', :local => 'aamine', :domain => '0246.loveruby.net', :format => 'Minero Aoki ', :comments => nil, :raw => 'Minero Aoki'}) end it "should handle lots of dots" do 1.upto(10) do |times| dots = "." * times address = Mail::Address.new("hoge#{dots}test@docomo.ne.jp") address.should break_down_to({ :display_name => nil, :address => "hoge#{dots}test@docomo.ne.jp", :local => "hoge#{dots}test", :domain => 'docomo.ne.jp', :format => "hoge#{dots}test@docomo.ne.jp", :comments => nil, :raw => "hoge#{dots}test@docomo.ne.jp"}) end end it "should handle trailing dots" do 1.upto(10) do |times| dots = "." * times address = Mail::Address.new("hogetest#{dots}@docomo.ne.jp") address.should break_down_to({ :display_name => nil, :address => "hogetest#{dots}@docomo.ne.jp", :local => "hogetest#{dots}", :domain => 'docomo.ne.jp', :format => "hogetest#{dots}@docomo.ne.jp", :comments => nil, :raw => "hogetest#{dots}@docomo.ne.jp"}) end end it 'should handle |"Joe & J. Harvey" |' do address = Mail::Address.new('"Joe & J. Harvey" ') address.should break_down_to({ :name => 'Joe & J. Harvey', :display_name => 'Joe & J. Harvey', :address => 'ddd@Org', :domain => 'Org', :local => 'ddd', :format => '"Joe & J. Harvey" ', :comments => nil, :raw => '"Joe & J. Harvey" '}) end it 'should handle |"spickett@tiac.net" |' do address = Mail::Address.new('"spickett@tiac.net" ') address.should break_down_to({ :name => 'spickett@tiac.net', :display_name => 'spickett@tiac.net', :address => 'Sean.Pickett@zork.tiac.net', :domain => 'zork.tiac.net', :local => 'Sean.Pickett', :format => '"spickett@tiac.net" ', :comments => nil, :raw => '"spickett@tiac.net" '}) end it "should handle |rls@intgp8.ih.att.com (-Schieve,R.L.)|" do address = Mail::Address.new('rls@intgp8.ih.att.com (-Schieve,R.L.)') address.should break_down_to({ :name => '-Schieve,R.L.', :display_name => nil, :address => 'rls@intgp8.ih.att.com', :comments => ['-Schieve,R.L.'], :domain => 'intgp8.ih.att.com', :local => 'rls', :format => 'rls@intgp8.ih.att.com (-Schieve,R.L.)', :raw => 'rls@intgp8.ih.att.com (-Schieve,R.L.)'}) end it "should handle |jrh%cup.portal.com@portal.unix.portal.com|" do address = Mail::Address.new('jrh%cup.portal.com@portal.unix.portal.com') address.should break_down_to({ :name => nil, :display_name => nil, :address => 'jrh%cup.portal.com@portal.unix.portal.com', :comments => nil, :domain => 'portal.unix.portal.com', :local => 'jrh%cup.portal.com', :format => 'jrh%cup.portal.com@portal.unix.portal.com', :raw => 'jrh%cup.portal.com@portal.unix.portal.com'}) end it "should handle |astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')|" do address = Mail::Address.new("astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')") address.should break_down_to({ :name => "'paul astrachan/xvt3'", :display_name => nil, :address => 'astrachan@austlcm.sps.mot.com', :comments => ["'paul astrachan/xvt3'"], :domain => 'austlcm.sps.mot.com', :local => 'astrachan', :format => "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')", :raw => "astrachan@austlcm.sps.mot.com ('paul astrachan/xvt3')"}) end it "should handle 'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)'" do address = Mail::Address.new('TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)') address.should break_down_to({ :name => 'JAMES R. TWINE - THE NERD', :display_name => nil, :address => 'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU', :comments => ['JAMES R. TWINE - THE NERD'], :domain => 'SNYBUF.CS.SNYBUF.EDU', :local => 'TWINE57%SDELVB.decnet', :format => 'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)', :raw => 'TWINE57%SDELVB.decnet@SNYBUF.CS.SNYBUF.EDU (JAMES R. TWINE - THE NERD)'}) end it "should be able to handle 'David Apfelbaum '" do address = Mail::Address.new('David Apfelbaum ') address.should break_down_to({ :name => 'David Apfelbaum', :display_name => 'David Apfelbaum', :address => 'da0g+@andrew.cmu.edu', :comments => nil, :domain => 'andrew.cmu.edu', :local => 'da0g+', :format => 'David Apfelbaum ', :raw => 'David Apfelbaum '}) end it 'should handle |"JAMES R. TWINE - THE NERD" |' do address = Mail::Address.new('"JAMES R. TWINE - THE NERD" ') address.should break_down_to({ :name => 'JAMES R. TWINE - THE NERD', :display_name => 'JAMES R. TWINE - THE NERD', :address => 'TWINE57%SDELVB%SNYDELVA.bitnet@CUNYVM.CUNY.EDU', :comments => nil, :domain => 'CUNYVM.CUNY.EDU', :local => 'TWINE57%SDELVB%SNYDELVA.bitnet', :format => '"JAMES R. TWINE - THE NERD" ', :raw => '"JAMES R. TWINE - THE NERD" '}) end it "should handle '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk'" do address = Mail::Address.new('/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk') address.should break_down_to({ :name => nil, :display_name => nil, :address => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk', :comments => nil, :domain => 'mhs-relay.ac.uk', :local => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/', :format => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk', :raw => '/G=Owen/S=Smith/O=SJ-Research/ADMD=INTERSPAN/C=GB/@mhs-relay.ac.uk'}) end it 'should handle |"Stephen Burke, Liverpool" |' do address = Mail::Address.new('"Stephen Burke, Liverpool" ') address.should break_down_to({ :name => 'Stephen Burke, Liverpool', :display_name => 'Stephen Burke, Liverpool', :address => 'BURKE@vxdsya.desy.de', :comments => nil, :domain => 'vxdsya.desy.de', :local => 'BURKE', :format => '"Stephen Burke, Liverpool" ', :raw => '"Stephen Burke, Liverpool" '}) end it "should handle 'The Newcastle Info-Server '" do address = Mail::Address.new('The Newcastle Info-Server ') address.should break_down_to({ :name => 'The Newcastle Info-Server', :display_name => 'The Newcastle Info-Server', :address => 'info-admin@newcastle.ac.uk', :comments => nil, :domain => 'newcastle.ac.uk', :local => 'info-admin', :format => 'The Newcastle Info-Server ', :raw => 'The Newcastle Info-Server '}) end it "should handle 'Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])'" do address = Mail::Address.new('Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])') address.should break_down_to({ :name => 'Suba Peddada [CONTRACTOR]', :display_name => nil, :address => 'Suba.Peddada@eng.sun.com', :comments => ['Suba Peddada [CONTRACTOR]'], :domain => 'eng.sun.com', :local => 'Suba.Peddada', :format => 'Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])', :raw => 'Suba.Peddada@eng.sun.com (Suba Peddada [CONTRACTOR])'}) end it "should handle 'Paul Manser (0032 memo) '" do address = Mail::Address.new('Paul Manser (0032 memo) ') address.should break_down_to({ :name => 'Paul Manser', :display_name => 'Paul Manser', :address => 'a906187@tiuk.ti.com', :comments => ['0032 memo'], :domain => 'tiuk.ti.com', :local => 'a906187', :format => 'Paul Manser (0032 memo)', :raw => 'Paul Manser (0032 memo) '}) end it 'should handle |"gregg (g.) woodcock" |' do address = Mail::Address.new('"gregg (g.) woodcock" ') address.should break_down_to({ :name => 'gregg (g.) woodcock', :display_name => 'gregg (g.) woodcock', :address => 'woodcock@bnr.ca', :comments => nil, :domain => 'bnr.ca', :local => 'woodcock', :format => '"gregg (g.) woodcock" ', :raw => '"gregg (g.) woodcock" '}) end it 'should handle |Graham.Barr@tiuk.ti.com|' do address = Mail::Address.new('Graham.Barr@tiuk.ti.com') address.should break_down_to({ :name => nil, :display_name => nil, :address => 'Graham.Barr@tiuk.ti.com', :comments => nil, :domain => 'tiuk.ti.com', :local => 'Graham.Barr', :format => 'Graham.Barr@tiuk.ti.com', :raw => 'Graham.Barr@tiuk.ti.com'}) end it "should handle |a909937 (Graham Barr (0004 bodg))|" do address = Mail::Address.new('a909937 (Graham Barr (0004 bodg))') address.should break_down_to({ :name => 'Graham Barr (0004 bodg)', :display_name => nil, :address => 'a909937', :comments => ['Graham Barr (0004 bodg)'], :domain => nil, :local => 'a909937', :format => 'a909937 (Graham Barr \(0004 bodg\))', :raw => 'a909937 (Graham Barr (0004 bodg))'}) end it "should handle |david d `zoo' zuhn |" do address = Mail::Address.new("david d `zoo' zuhn ") address.should break_down_to({ :name => "david d `zoo' zuhn", :display_name => "david d `zoo' zuhn", :address => 'zoo@aggregate.com', :comments => nil, :domain => 'aggregate.com', :local => 'zoo', :format => "david d `zoo' zuhn ", :raw => "david d `zoo' zuhn "}) end it "should handle |(foo@bar.com (foobar), ned@foo.com (nedfoo) ) |" do address = Mail::Address.new('(foo@bar.com (foobar), ned@foo.com (nedfoo) ) ') address.should break_down_to({ :name => 'foo@bar.com \(foobar\), ned@foo.com \(nedfoo\) ', :display_name => '(foo@bar.com \(foobar\), ned@foo.com \(nedfoo\) )', :address => 'kevin@goess.org', :comments => ['foo@bar.com (foobar), ned@foo.com (nedfoo) '], :domain => 'goess.org', :local => 'kevin', :format => '"(foo@bar.com \\\\(foobar\\\\), ned@foo.com \\\\(nedfoo\\\\) )" (foo@bar.com \(foobar\), ned@foo.com \(nedfoo\) )', :raw => '(foo@bar.com (foobar), ned@foo.com (nedfoo) ) '}) end it "should handle |Pete(A wonderful ) chap) |" do address = Mail::Address.new('Pete(A wonderful \) chap) ') address.should break_down_to({ :name => 'Pete', :display_name => 'Pete', :address => 'pete(his account)@silly.test', :comments => ['A wonderful \\) chap', 'his account', 'his host'], :domain => 'silly.test', :local => 'pete(his account)', :format => 'Pete (A wonderful \\) chap his account his host)', :raw => 'Pete(A wonderful \\) chap) '}) end it "should handle |Joe Q. Public |" do address = Mail::Address.new('Joe Q. Public ') address.should break_down_to({ :name => 'Joe Q. Public', :display_name => 'Joe Q. Public', :address => 'john.q.public@example.com', :comments => nil, :domain => 'example.com', :local => 'john.q.public', :format => '"Joe Q. Public" ', :raw => 'Joe Q. Public '}) end it "should handle |Mary Smith <@machine.tld:mary@example.net>|" do address = Mail::Address.new('Mary Smith <@machine.tld:mary@example.net>') address.should break_down_to({ :name => 'Mary Smith', :display_name => 'Mary Smith', :address => '@machine.tld:mary@example.net', :comments => nil, :domain => 'example.net', :local => '@machine.tld:mary', :format => 'Mary Smith <@machine.tld:mary@example.net>', :raw => 'Mary Smith <@machine.tld:mary@example.net>'}) end it "should handle |jdoe@test . example|" do pending address = Mail::Address.new('jdoe@test . example') address.should break_down_to({ :name => 'jdoe@test.example', :display_name => 'jdoe@test.example', :address => 'jdoe@test.example', :comments => nil, :domain => 'test.example', :local => 'jdoe', :format => 'jdoe@test.example', :raw => 'jdoe@test.example'}) end it "should handle |groupname+domain.com@example.com|" do address = Mail::Address.new('groupname+domain.com@example.com') address.should break_down_to({ :name => nil, :display_name => nil, :address => 'groupname+domain.com@example.com', :comments => nil, :domain => 'example.com', :local => 'groupname+domain.com', :format => 'groupname+domain.com@example.com', :raw => 'groupname+domain.com@example.com'}) end end end describe "creating" do describe "parts of an address" do it "should add an address" do address = Mail::Address.new address.address = "mikel@test.lindsaar.net" address.should break_down_to({:address => 'mikel@test.lindsaar.net'}) end it "should add a display name" do address = Mail::Address.new address.display_name = "Mikel Lindsaar" address.display_name.should eq 'Mikel Lindsaar' end end end describe "modifying an address" do it "should add an address" do address = Mail::Address.new address.address = "mikel@test.lindsaar.net" address.should break_down_to({:address => 'mikel@test.lindsaar.net'}) end it "should add a display name" do address = Mail::Address.new address.display_name = "Mikel Lindsaar" address.display_name.should eq 'Mikel Lindsaar' end it "should take an address and a display name and join them" do address = Mail::Address.new address.address = "mikel@test.lindsaar.net" address.display_name = "Mikel Lindsaar" address.format.should eq 'Mikel Lindsaar ' end it "should take a display name and an address and join them" do address = Mail::Address.new address.display_name = "Mikel Lindsaar" address.address = "mikel@test.lindsaar.net" address.format.should eq 'Mikel Lindsaar ' end end describe "providing encoded and decoded outputs" do it "should provide an encoded output" do address = Mail::Address.new address.display_name = "Mikel Lindsaar" address.address = "mikel@test.lindsaar.net" address.encoded.should eq 'Mikel Lindsaar ' end it "should provide an encoded output for non us-ascii" do address = Mail::Address.new address.display_name = "まける" address.address = "mikel@test.lindsaar.net" address.encoded.should eq '=?UTF-8?B?44G+44GR44KL?= ' end it "should provide an encoded output for non us-ascii" do address = Mail::Address.new address.display_name = "まける" address.address = "mikel@test.lindsaar.net" address.decoded.should eq '"まける" ' end end end mail-2.5.4/spec/mail/elements/date_time_element_spec.rb000066400000000000000000000010441214434061600231370ustar00rootroot00000000000000require 'spec_helper' describe Mail::DateTimeElement do it "should parse a date" do date_text = 'Wed, 27 Apr 2005 14:15:31 -0700' doing { Mail::DateTimeElement.new(date_text) }.should_not raise_error end it "should raise an error if the input is useless" do date_text = nil doing { Mail::DateTimeElement.new(date_text) }.should raise_error end it "should raise an error if the input is useless" do date_text = '""""""""""""""""' doing { Mail::DateTimeElement.new(date_text) }.should raise_error end end mail-2.5.4/spec/mail/elements/envelope_from_element_spec.rb000066400000000000000000000026301214434061600240460ustar00rootroot00000000000000require 'spec_helper' describe Mail::EnvelopeFromElement do describe "parsing a from envelope string" do it "should parse a full field" do doing { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 7 00:39:21 2009") }.should_not raise_error end it "should parse a full field with a double digit day" do doing { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") }.should_not raise_error end it "should parse a full field with a single space day" do doing { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") }.should_not raise_error end end describe "accessor methods" do it "should return the address" do envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") envelope.address.should eq "mikel@test.lindsaar.net" end it "should return the date_time" do envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") envelope.date_time.should eq ::DateTime.parse("Mon Aug 17 00:39:21 2009") end end describe 'formatting' do it 'should format delivery date using UNIX ctime style' do time = Time.now envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net #{time.ctime}") envelope.to_s.should eq "mikel@test.lindsaar.net #{time.ctime}" end end end mail-2.5.4/spec/mail/elements/message_ids_element_spec.rb000066400000000000000000000027231214434061600234740ustar00rootroot00000000000000require 'spec_helper' describe Mail::MessageIdsElement do it "should parse a message_id" do msg_id_text = '<1234@test.lindsaar.net>' doing { Mail::MessageIdsElement.new(msg_id_text) }.should_not raise_error end it "should parse multiple message_ids" do msg_id_text = '<1234@test.lindsaar.net> <1234@test.lindsaar.net>' doing { Mail::MessageIdsElement.new(msg_id_text) }.should_not raise_error end it "should raise an error if the input is useless" do msg_id_text = nil doing { Mail::MessageIdsElement.new(msg_id_text) }.should raise_error end it "should raise an error if the input is useless" do msg_id_text = '""""""""""""""""' doing { Mail::MessageIdsElement.new(msg_id_text) }.should raise_error end it "should respond to message_ids" do msg_id_text = '<1234@test.lindsaar.net> <1234@test.lindsaar.net>' msg_ids = Mail::MessageIdsElement.new(msg_id_text) msg_ids.message_ids.should eq ['1234@test.lindsaar.net', '1234@test.lindsaar.net'] end it "should respond to message_id" do msg_id_text = '<1234@test.lindsaar.net>' msg_ids = Mail::MessageIdsElement.new(msg_id_text) msg_ids.message_id.should eq '1234@test.lindsaar.net' end it "should not fail to parse a message id with dots in it" do text = "<4afb664ca3078_48dc..fdbe32b865532b@ax-desktop.mail>" m = Mail::MessageIdsElement.new(text) m.message_id.should eq "4afb664ca3078_48dc..fdbe32b865532b@ax-desktop.mail" end end mail-2.5.4/spec/mail/elements/phrase_list_spec.rb000066400000000000000000000011701214434061600220100ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::PhraseList do describe "parsing" do it "should parse a phrase list" do parse_text = '"Mikel Lindsaar", "Mikel", you, somewhere' doing { Mail::PhraseList.new(parse_text) }.should_not raise_error end it "should raise an error if the input is useless" do parse_text = nil doing { Mail::PhraseList.new(parse_text) }.should raise_error end it "should not raise an error if the input is empty" do parse_text = '""""""""""""""""' Mail::PhraseList.new(parse_text).phrases.should eq [parse_text[1...-1]] end end end mail-2.5.4/spec/mail/elements/received_element_spec.rb000066400000000000000000000027321214434061600227770ustar00rootroot00000000000000require 'spec_helper' describe Mail::ReceivedElement do it "should parse a date" do received_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' doing { Mail::ReceivedElement.new(received_text) }.should_not raise_error end it "should raise an error if the input is useless" do received_text = nil doing { Mail::ReceivedElement.new(received_text) }.should raise_error end it "should raise an error if the input is useless" do received_text = '""""""""""""""""' doing { Mail::ReceivedElement.new(received_text) }.should raise_error end it "should give back the date time" do received_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' date_text = '10 May 2005 17:26:50 +0000 (GMT)' rec = Mail::ReceivedElement.new(received_text) rec.date_time.should eq ::DateTime.parse(date_text) end it "should give back the info" do received_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' info_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ' rec = Mail::ReceivedElement.new(received_text) rec.info.should eq info_text end end mail-2.5.4/spec/mail/encoding_spec.rb000066400000000000000000000173101214434061600174500ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "mail encoding" do it "should allow you to assign a mail wide charset" do mail = Mail.new mail.charset = 'utf-8' mail.charset.should eq 'utf-8' end describe "using default encoding" do it "should allow you to send in unencoded strings to fields and encode them" do mail = Mail.new mail.charset = 'utf-8' mail.subject = "This is あ string" result = "Subject: =?UTF-8?Q?This_is_=E3=81=82_string?=\r\n" mail[:subject].encoded.should eq result end it "should allow you to send in unencoded strings to address fields and encode them" do mail = Mail.new mail.charset = 'utf-8' mail.to = "Mikel Lindsああr " result = "To: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= \r\n" mail[:to].encoded.should eq result end it "should allow you to send in unencoded strings to address fields and encode them" do mail = Mail.new mail.charset = 'utf-8' mail.to = "あdあ " result = "To: =?UTF-8?B?44GCZOOBgg==?= \r\n" mail[:to].encoded.should eq result end it "should allow you to send in multiple unencoded strings to address fields and encode them" do mail = Mail.new mail.charset = 'utf-8' mail.to = ["Mikel Lindsああr ", "あdあ "] result = "To: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" mail[:to].encoded.should eq result end it "should allow you to send unquoted non us-ascii strings, with spaces in them" do mail = Mail.new mail.charset = 'utf-8' mail.to = ["Foo áëô îü "] result = "To: Foo =?UTF-8?B?w6HDq8O0?= =?UTF-8?B?IMOuw7w=?= \r\n" mail[:to].encoded.should eq result end it "should allow you to send in multiple unencoded strings to any address field" do mail = Mail.new mail.charset = 'utf-8' ['To', 'From', 'Cc', 'Reply-To'].each do |field| mail.send("#{field.downcase.gsub("-", '_')}=", ["Mikel Lindsああr ", "あdあ "]) result = "#{field}: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" mail[field].encoded.should eq result end end it "should handle groups" do mail = Mail.new mail.charset = 'utf-8' mail.to = "test1@lindsaar.net, group: test2@lindsaar.net, me@lindsaar.net;" result = "To: test1@lindsaar.net, \r\n\sgroup: test2@lindsaar.net, \r\n\sme@lindsaar.net;\r\n" mail[:to].encoded.should eq result end it "should handle groups with funky characters" do mail = Mail.new mail.charset = 'utf-8' mail.to = '"Mikel Lindsああr" , group: "あdあ" , me@lindsaar.net;' result = "To: =?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= , \r\n\sgroup: =?UTF-8?B?44GCZOOBgg==?= , \r\n\sme@lindsaar.net;\r\n" mail[:to].encoded.should eq result end describe "quoting token safe chars" do it "should not quote the display name if unquoted" do mail = Mail.new mail.charset = 'utf-8' mail.to = 'Mikel Lindsaar ' mail[:to].encoded.should eq %{To: Mikel Lindsaar \r\n} end it "should not quote the display name if already quoted" do mail = Mail.new mail.charset = 'utf-8' mail.to = '"Mikel Lindsaar" ' mail[:to].encoded.should eq %{To: Mikel Lindsaar \r\n} end end describe "quoting token unsafe chars" do it "should quote the display name" do pending mail = Mail.new mail.charset = 'utf-8' mail.to = "Mikel @ me Lindsaar " mail[:to].encoded.should eq %{To: "Mikel @ me Lindsaar" \r\n} end it "should preserve quotes needed from the user and not double quote" do mail = Mail.new mail.charset = 'utf-8' mail.to = %{"Mikel @ me Lindsaar" } mail[:to].encoded.should eq %{To: "Mikel @ me Lindsaar" \r\n} end end end describe "specifying an email wide encoding" do it "should allow you to send in unencoded strings to fields and encode them" do mail = Mail.new mail.charset = 'ISO-8859-1' subject = "This is あ string" subject.force_encoding('ISO8859-1') if RUBY_VERSION > '1.9' mail.subject = subject result = mail[:subject].encoded string = "Subject: =?ISO-8859-1?Q?This_is_=E3=81=82_string?=\r\n" if RUBY_VERSION > '1.9' string.force_encoding('ISO8859-1') result.force_encoding('ISO8859-1') end result.should eq string end it "should allow you to send in unencoded strings to address fields and encode them" do mail = Mail.new mail.charset = 'ISO-8859-1' string = "Mikel Lindsああr " string.force_encoding('ISO8859-1') if RUBY_VERSION > '1.9' mail.to = string result = mail[:to].encoded string = "To: Mikel =?ISO-8859-1?B?TGluZHPjgYLjgYJy?= \r\n" if RUBY_VERSION > '1.9' string.force_encoding('ISO8859-1') result.force_encoding('ISO8859-1') end result.should eq string end it "should allow you to send in multiple unencoded strings to address fields and encode them" do mail = Mail.new mail.charset = 'ISO-8859-1' array = ["Mikel Lindsああr ", "あdあ "] array.map! { |a| a.force_encoding('ISO8859-1') } if RUBY_VERSION > '1.9' mail.to = array result = mail[:to].encoded string = "To: Mikel =?ISO-8859-1?B?TGluZHPjgYLjgYJy?= , \r\n\s=?ISO-8859-1?B?44GCZOOBgg==?= \r\n" if RUBY_VERSION > '1.9' string.force_encoding('ISO8859-1') result.force_encoding('ISO8859-1') end result.should eq string end it "should allow you to send in multiple unencoded strings to any address field" do mail = Mail.new array = ["Mikel Lindsああr ", "あdあ "] array.map! { |a| a.force_encoding('ISO8859-1') } if RUBY_VERSION > '1.9' mail.charset = 'ISO-8859-1' ['To', 'From', 'Cc', 'Reply-To'].each do |field| mail.send("#{field.downcase.gsub("-", '_')}=", array) string = "#{field}: Mikel =?ISO-8859-1?B?TGluZHPjgYLjgYJy?= , \r\n\s=?ISO-8859-1?B?44GCZOOBgg==?= \r\n" result = mail[field].encoded if RUBY_VERSION > '1.9' string.force_encoding('ISO8859-1') result.force_encoding('ISO8859-1') end result.should eq string end end end it "should let you define a charset per part" do mail = Mail.new part = Mail::Part.new part.content_type = "text/html" part.charset = "ISO-8859-1" part.body = "blah" mail.add_part(part) mail.parts[0].content_type.should eq "text/html; charset=ISO-8859-1" end it "should skip invalid characters" do m = Mail.new m['Subject'] = Mail::SubjectField.new("=?utf-8?Q?Hello_=96_World?=") if RUBY_VERSION > '1.9' lambda { m.subject.should be_valid_encoding }.should_not raise_error else m.subject.should eq "Hello World" end end end mail-2.5.4/spec/mail/encodings/000077500000000000000000000000001214434061600162725ustar00rootroot00000000000000mail-2.5.4/spec/mail/encodings/base64_spec.rb000066400000000000000000000012461214434061600207200ustar00rootroot00000000000000require 'spec_helper' describe Mail::Encodings::Base64 do it "should encode base 64 from text" do result = "VGhpcyBpcyBhIHRlc3Q=\r\n" Mail::Encodings::Base64.encode('This is a test').should eq result end it "should decode base 64 text" do result = 'This is a test' Mail::Encodings::Base64.decode("VGhpcyBpcyBhIHRlc3Q=\n").should eq result end it "should encode base 64 from binary" do result = "AAAAAA==\r\n" Mail::Encodings::Base64.encode("\000\000\000\000").should eq result end it "should decode base 64 text" do result = "\000\000\000\000" Mail::Encodings::Base64.decode("AAAAAA==\n").should eq result end end mail-2.5.4/spec/mail/encodings/quoted_printable_spec.rb000066400000000000000000000034771214434061600232050ustar00rootroot00000000000000require 'spec_helper' describe Mail::Encodings::QuotedPrintable do it "should encode quoted printable from text" do result = "This is\r\na test=\r\n" Mail::Encodings::QuotedPrintable.encode("This is\na test").should eq result end it "should encode quoted printable from crlf text" do result = "This is\r\na test=\r\n" Mail::Encodings::QuotedPrintable.encode("This is\r\na test").should eq result end it "should encode quoted printable from cr text" do result = "This is\r\na test=\r\n" Mail::Encodings::QuotedPrintable.encode("This is\ra test").should eq result end it "should decode quoted printable" do result = "This is\na test" Mail::Encodings::QuotedPrintable.decode("This is\r\na test").should eq result end it "should encode quoted printable from binary" do result = "=00=00=00=00=\r\n" Mail::Encodings::QuotedPrintable.encode("\000\000\000\000").should eq result end it "should decode quoted printable text" do result = "\000\000\000\000" Mail::Encodings::QuotedPrintable.decode("=00=00=00=00").should eq result end %w(=0D =0A =0D=0A).each do |linebreak| expected = "first line wraps\n\nsecond paragraph" it "should cope with inappropriate #{linebreak} line break encoding" do body = "first line=\r\n wraps#{linebreak}\r\n#{linebreak}\r\nsecond paragraph=\r\n" Mail::Encodings::QuotedPrintable.decode(body).should eq expected end end [["\r", "=0D"], ["\n", "=0A"], ["\r\n", "=0D=0A"]].each do |crlf, linebreak| expected = "first line wraps\n\nsecond paragraph" it "should allow encoded #{linebreak} line breaks with soft line feeds" do body = "first line=\r\n wraps#{linebreak}=\r\n#{linebreak}=\r\nsecond paragraph=\r\n" Mail::Encodings::QuotedPrintable.decode(body).should eq expected end end end mail-2.5.4/spec/mail/encodings_spec.rb000066400000000000000000001033111214434061600176300ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Encodings do describe "base64 Encoding" do it "should return true for base64" do Mail::Encodings.defined?('base64').should be_true end it "should return true for Base64" do Mail::Encodings.defined?('Base64').should be_true end it "should return true for :base64" do Mail::Encodings.defined?(:base64).should be_true end it "should return the Base64 Encoding class" do Mail::Encodings.get_encoding('Base64').should eq Mail::Encodings::Base64 end it "should return the base64 Encoding class" do Mail::Encodings.get_encoding('base64').should eq Mail::Encodings::Base64 end it "should return the base64 Encoding class" do Mail::Encodings.get_encoding(:base64).should eq Mail::Encodings::Base64 end end describe "quoted-printable Encoding" do it "should return true for quoted-printable" do Mail::Encodings.defined?('quoted-printable').should be_true end it "should return true for Quoted-Printable" do Mail::Encodings.defined?('Quoted-Printable').should be_true end it "should return true for :quoted_printable" do Mail::Encodings.defined?(:quoted_printable).should be_true end it "should return the QuotedPrintable Encoding class" do Mail::Encodings.get_encoding('quoted-printable').should eq Mail::Encodings::QuotedPrintable end it "should return the QuotedPrintable Encoding class" do Mail::Encodings.get_encoding('Quoted-Printable').should eq Mail::Encodings::QuotedPrintable end it "should return the QuotedPrintable Encoding class" do Mail::Encodings.get_encoding(:quoted_printable).should eq Mail::Encodings::QuotedPrintable end end describe "B encodings" do # From rfc2047: # From: =?US-ASCII?Q?Keith_Moore?= # To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= # CC: =?ISO-8859-1?Q?Andr=E9?= Pirard # Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= # =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?= # # Note: In the first 'encoded-word' of the Subject field above, the # last "=" at the end of the 'encoded-text' is necessary because each # 'encoded-word' must be self-contained (the "=" character completes a # group of 4 base64 characters representing 2 octets). An additional # octet could have been encoded in the first 'encoded-word' (so that # the encoded-word would contain an exact multiple of 3 encoded # octets), except that the second 'encoded-word' uses a different # 'charset' than the first one. # it "should just return the string if us-ascii and asked to B encoded string" do string = "This is a string" result = "This is a string" if RUBY_VERSION >= "1.9.1" string = string.force_encoding('US-ASCII') Mail::Encodings.b_value_encode(string).should eq(result) else encoding = 'US-ASCII' Mail::Encodings.b_value_encode(string, encoding).should eq(result) end end it "should accept other encodings" do string = "This is あ string" result = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' if RUBY_VERSION >= "1.9.1" string = string.force_encoding('UTF-8') Mail::Encodings.b_value_encode(string).should eq(result) else string = "This is あ string" encoding = 'UTF-8' Mail::Encodings.b_value_encode(string, encoding).should eq(result) end end it "should complain if there is no encoding passed for Ruby < 1.9" do string = "This is あ string" if RUBY_VERSION >= "1.9.1" string = string.force_encoding('UTF-8') doing {Mail::Encodings.b_value_encode(string)}.should_not raise_error else doing {Mail::Encodings.b_value_encode(string, nil)}.should raise_error("Must supply an encoding") end end it "should split the string up into bite sized chunks that can be wrapped easily" do string = "This is あ really long string This is あ really long string This is あ really long string This is あ really long string This is あ really long string" result = '=?UTF-8?B?VGhpcyBpcyDjgYIgcmVhbGx5IGxvbmcgc3RyaW5nIFRoaXMgaXMg44GCIHJl?= =?UTF-8?B?YWxseSBsb25nIHN0cmluZyBUaGlzIGlzIOOBgiByZWFsbHkgbG9uZyBzdHJp?= =?UTF-8?B?bmcgVGhpcyBpcyDjgYIgcmVhbGx5IGxvbmcgc3RyaW5nIFRoaXMgaXMg44GC?= =?UTF-8?B?IHJlYWxseSBsb25nIHN0cmluZw==?=' if RUBY_VERSION >= "1.9.1" string = string.force_encoding('UTF-8') Mail::Encodings.b_value_encode(string).should eq(result) else encoding = 'UTF-8' Mail::Encodings.b_value_encode(string, encoding).should eq(result) end end it "should decode an encoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should decode a long encoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgcmVhbGx5IGxvbmcgc3RyaW5nIFRoaXMgaXMg44GCIHJl?= =?UTF-8?B?YWxseSBsb25nIHN0cmluZyBUaGlzIGlzIOOBgiByZWFsbHkgbG9uZyBzdHJp?= =?UTF-8?B?bmcgVGhpcyBpcyDjgYIgcmVhbGx5IGxvbmcgc3RyaW5nIFRoaXMgaXMg44GC?= =?UTF-8?B?IHJlYWxseSBsb25nIHN0cmluZw==?=' result = "This is あ really long string This is あ really long string This is あ really long string This is あ really long string This is あ really long string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should decode UTF-16 encoded string" do string = "=?UTF-16?B?MEIwRDBGMEgwSg==?=" result = "あいうえお" Mail::Encodings.value_decode(string).should == result end it "should decode UTF-32 encoded string" do string = "=?UTF-32?B?AAAwQgAAMEQAADBGAAAwSAAAMEo=?=" result = "あいうえお" Mail::Encodings.value_decode(string).should == result end it "should decode a string that looks similar to an encoded string (contains '=?')" do string = "1+1=?" Mail::Encodings.value_decode(string).should == string end if '1.9'.respond_to?(:force_encoding) it "should decode 8bit encoded string" do string = "=?8bit?Q?ALPH=C3=89E?=" result = "ALPH\xC3\x89E" Mail::Encodings.value_decode(string).should == result end it "should decode ks_c_5601-1987 encoded string" do string = '=?ks_c_5601-1987?B?seggx/bB+A==?= '.force_encoding('us-ascii') Mail::Encodings.value_decode(string).should == "김 현진 " end it "should decode shift-jis encoded string" do string = '=?shift-jis?Q?=93=FA=96{=8C=EA=?='.force_encoding('us-ascii') Mail::Encodings.value_decode(string).should == "日本語" end it "should decode GB18030 encoded string misidentified as GB2312" do string = '=?GB2312?B?6V8=?='.force_encoding('us-ascii') Mail::Encodings.value_decode(string).should == "開" end end end describe "Q encodings" do # From rfc2047: # From: =?US-ASCII?Q?Keith_Moore?= # To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= # CC: =?ISO-8859-1?Q?Andr=E9?= Pirard # Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?= # =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?= # # Note: In the first 'encoded-word' of the Subject field above, the # last "=" at the end of the 'encoded-text' is necessary because each # 'encoded-word' must be self-contained (the "=" character completes a # group of 4 base64 characters representing 2 octets). An additional # octet could have been encoded in the first 'encoded-word' (so that # the encoded-word would contain an exact multiple of 3 encoded # octets), except that the second 'encoded-word' uses a different # 'charset' than the first one. # it "should just return the string if us-ascii and asked to Q encoded string" do if RUBY_VERSION >= "1.9.1" string = "This is a string" string = string.force_encoding('US-ASCII') Mail::Encodings.q_value_encode(string).should eq "This is a string" else string = "This is a string" encoding = 'US-ASCII' Mail::Encodings.q_value_encode(string, encoding).should eq "This is a string" end end it "should complain if there is no encoding passed for Ruby < 1.9" do if RUBY_VERSION >= "1.9.1" string = "This is あ string" string = string.force_encoding('UTF-8') doing {Mail::Encodings.q_value_encode(string)}.should_not raise_error else string = "This is あ string" doing {Mail::Encodings.q_value_encode(string)}.should raise_error("Must supply an encoding") end end it "should accept other character sets" do if RUBY_VERSION >= "1.9.1" string = "This is あ string" string = string.force_encoding('UTF-8') Mail::Encodings.q_value_encode(string).should eq '=?UTF-8?Q?This_is_=E3=81=82_string?=' else string = "This is あ string" encoding = 'UTF-8' Mail::Encodings.q_value_encode(string, encoding).should eq '=?UTF-8?Q?This_is_=E3=81=82_string?=' end end it "should decode an encoded string" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a q encoded string and decode it" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should decode q encoded =5F as underscore" do string = "=?UTF-8?Q?This_=C2=AD_and=5Fthat?=" result = "This ­ and_that" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should not fold a long string that has no spaces" do original = "ВосстановлениеВосстановлениеВашегопароля" if RUBY_VERSION >= '1.9' original.force_encoding('UTF-8') result = "Subject: =?UTF-8?Q?=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=B0=D1=88=D0=B5=D0=B3=D0=BE=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D1=8F?=\r\n" else result = "Subject: =?UTF-8?Q?=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=B0=D1=88=D0=B5=D0=B3=D0=BE=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D1=8F?=\r\n" end mail = Mail.new mail.subject = original mail[:subject].decoded.should eq original mail[:subject].encoded.should eq result end it "should round trip a complex string properly" do original = "ВосстановлениеВосстановлениеВашегопароля This is a NUT?????Z__string that== could (break) anything" if RUBY_VERSION >= '1.9' original.force_encoding('UTF-8') end result = "Subject: =?UTF-8?Q?=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=BE=D1=81=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=92=D0=B0=D1=88=D0=B5=D0=B3=D0=BE=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D1=8F?=\r\n =?UTF-8?Q?_This_is_a_NUT=3F=3F=3F=3F=3FZ=5F=5Fstring_that=3D=3D_could?=\r\n =?UTF-8?Q?_=28break=29_anything?=\r\n" mail = Mail.new mail.subject = original mail[:subject].decoded.should eq original mail[:subject].encoded.should eq result mail = Mail.new(mail.encoded) mail[:subject].decoded.should eq original mail[:subject].encoded.should eq result mail = Mail.new(mail.encoded) mail[:subject].decoded.should eq original mail[:subject].encoded.should eq result end it "should round trip another complex string (koi-8)" do original = "Слово 9999 и число" mail = Mail.new mail.subject = (RUBY_VERSION >= "1.9" ? original.encode('koi8-r') : Iconv.conv('koi8-r', 'UTF-8', original)) mail[:subject].charset = 'koi8-r' wrapped = mail[:subject].wrapped_value unwrapped = Mail::Encodings.value_decode(wrapped) unwrapped.gsub("Subject: ", "").should eq original end end describe "mixed Q and B encodings" do it "should decode an encoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?= =?UTF-8?Q?_This_was_=E3=81=82_string?=' result = "This is あ string This was あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end end describe "parameter MIME encodings" do # Character set and language information may be combined with the # parameter continuation mechanism. For example: # # Content-Type: application/x-stuff # title*0*=us-ascii'en'This%20is%20even%20more%20 # title*1*=%2A%2A%2Afun%2A%2A%2A%20 # title*2="isn't it!" # # Note that: # # (1) Language and character set information only appear at # the beginning of a given parameter value. # # (2) Continuations do not provide a facility for using more # than one character set or language in the same # parameter value. # # (3) A value presented using multiple continuations may # contain a mixture of encoded and unencoded segments. # # (4) The first segment of a continuation MUST be encoded if # language and character set information are given. # # (5) If the first segment of a continued parameter value is # encoded the language and character set field delimiters # MUST be present even when the fields are left blank. # before(:each) do Mail.defaults do param_encode_language('en') end end it "should leave an unencoded string alone" do string = "this isn't encoded" result = "this isn't encoded" Mail::Encodings.param_decode(string, 'us-ascii').should eq result end it "should unencode an encoded string" do string = "This%20is%20even%20more%20" result = "This is even more " result.force_encoding('us-ascii') if RUBY_VERSION >= '1.9' Mail::Encodings.param_decode(string, 'us-ascii').should eq result end it "should unencoded an encoded string and return the right charset on 1.9" do string = "This%20is%20even%20more%20" result = "This is even more " result.force_encoding('us-ascii') if RUBY_VERSION >= '1.9' Mail::Encodings.param_decode(string, 'us-ascii').should eq result end it "should unencode a complete string that included unencoded parts" do string = "This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn't it" result = "This is even more ***fun*** isn't it" result.force_encoding('iso-8859-1') if RUBY_VERSION >= '1.9' Mail::Encodings.param_decode(string, 'iso-8859-1').should eq result end it "should encode a string" do string = "This is あ string" if RUBY_VERSION >= '1.9' Mail::Encodings.param_encode(string).should eq "utf-8'en'This%20is%20%20%E3%81%82%20string" else Mail::Encodings.param_encode(string).should eq "utf8'en'This%20is%20%20%E3%81%82%20string" end end it "should just quote US-ASCII with spaces" do string = "This is even more" if RUBY_VERSION >= '1.9' Mail::Encodings.param_encode(string).should eq '"This is even more"' else Mail::Encodings.param_encode(string).should eq '"This is even more"' end end it "should leave US-ASCII without spaces alone" do string = "fun" if RUBY_VERSION >= '1.9' Mail::Encodings.param_encode(string).should eq 'fun' else Mail::Encodings.param_encode(string).should eq 'fun' end end end describe "decoding a string and detecting the encoding type" do it "should detect an encoded Base64 string to the decoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a multiple encoded Base64 string to the decoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?==?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a multiple encoded Base64 string with a space to the decoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?= =?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a multiple encoded Base64 string with a whitespace to the decoded string" do string = "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?= \r\n\s=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should decode B and Q encodings together if needed" do string = "=?UTF-8?Q?This_is_=E3=81=82_string?==?UTF-8?Q?This_is_=E3=81=82_string?= Some non encoded stuff =?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?= \r\n\sMore non encoded stuff" result = "This is あ stringThis is あ string Some non encoded stuff This is あ string \r\n\sMore non encoded stuff" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a encoded and unencoded Base64 string to the decoded string" do string = "Some non encoded stuff =?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?= \r\n\sMore non encoded stuff" result = "Some non encoded stuff This is あ string \r\n\sMore non encoded stuff" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect an encoded QP string to the decoded string" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should decode UTF-16 encoded string" do string = "=?UTF-16?Q?0B0D0F0H0J=?=" result = "あいうえお" Mail::Encodings.value_decode(string).should == result end it "should decode UTF-32 encoded string" do string = "=?UTF-32?Q?=00=000B=00=000D=00=000F=00=000H=00=000J=?=" result = "あいうえお" Mail::Encodings.value_decode(string).should == result end it "should detect multiple encoded QP string to the decoded string" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?==?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect multiple encoded QP string with a space to the decoded string" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?= =?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect multiple encoded QP string with a space to the decoded string" do string = "=?UTF-8?Q?This_is_=E3=81=82_string?= \r\n\s=?UTF-8?Q?This_is_=E3=81=82_string?=" result = "This is あ stringThis is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a encoded and unencoded QP string to the decoded string" do string = "Some non encoded stuff =?UTF-8?Q?This_is_=E3=81=82_string?= \r\n\sMore non encoded stuff" result = "Some non encoded stuff This is あ string \r\n\sMore non encoded stuff" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should detect a plain string and return it" do string = 'This is あ string' result = "This is あ string" result.force_encoding('UTF-8') if RUBY_VERSION >= '1.9' Mail::Encodings.value_decode(string).should eq result end it "should handle a very long string efficiently" do string = "This is a string " * 10000 Mail::Encodings.value_decode(string).should eq string end it "should handle Base64 encoded ISO-2022-JP string" do pending string = "ISO-2022-JP =?iso-2022-jp?B?GyRCJCQkPSRLITwkXiRrJEskSyE8JDgkJyQkJFQhPBsoQg==?=" result = "ISO-2022-JP いそにーまるににーじぇいぴー" Mail::Encodings.value_decode(string).should eq result end end describe "altering an encoded text to decoded and visa versa" do describe "decoding" do before(:each) do @original = $KCODE if RUBY_VERSION < '1.9' end after(:each) do $KCODE = @original if RUBY_VERSION < '1.9' end it "should detect an encoded Base64 string and return the decoded string" do string = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result = "This is あ string" if RUBY_VERSION >= '1.9' result.force_encoding('UTF-8') else $KCODE = 'UTF-8' end Mail::Encodings.decode_encode(string, :decode).should eq result end it "should detect an encoded QP string and return the decoded string" do string = '=?UTF-8?Q?This_is_=E3=81=82_string?=' result = "This is あ string" if RUBY_VERSION >= '1.9' result.force_encoding('UTF-8') else $KCODE = 'UTF-8' end Mail::Encodings.decode_encode(string, :decode).should eq result end it "should detect an a string is already decoded and leave it alone" do string = 'This is あ string' result = "This is あ string" if RUBY_VERSION >= '1.9' result.force_encoding('UTF-8') else $KCODE = 'UTF-8' end Mail::Encodings.decode_encode(string, :decode).should eq result end end describe "encoding" do it "should encode a string into Base64" do string = "This is あ string" if RUBY_VERSION >= '1.9' result = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' result.force_encoding('UTF-8') else result = '=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=' $KCODE = 'UTF-8' end Mail::Encodings.decode_encode(string, :encode).should eq result end it "should leave a string that doesn't need encoding alone" do string = 'This is a string' result = "This is a string" if RUBY_VERSION >= '1.9' result.force_encoding('UTF-8') else $KCODE = 'UTF-8' end Mail::Encodings.decode_encode(string, :encode).should eq result end end describe "unquote and convert to" do it "should unquote quoted printable and convert to utf-8" do a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "[166417] Bekr\303\246ftelse fra Rejsefeber" end it "should unquote base64 and convert to utf-8" do a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "[166417] Bekr\303\246ftelse fra Rejsefeber" end it "should handle no charset" do a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "[166417]_Bekr=E6ftelse_fra_Rejsefeber" end it "should unquote multiple lines" do a ="=?utf-8?q?Re=3A_=5B12=5D_=23137=3A_Inkonsistente_verwendung_von_=22Hin?==?utf-8?b?enVmw7xnZW4i?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "Re: [12] #137: Inkonsistente verwendung von \"Hinzuf\303\274gen\"" end it "should unquote a string in the middle of the text" do a ="Re: Photos =?ISO-8859-1?Q?Brosch=FCre_Rand?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "Re: Photos Brosch\303\274re Rand" end it "should unquote and change to an ISO encoding if we really want" do a = "=?ISO-8859-1?Q?Brosch=FCre_Rand?=" b = Mail::Encodings.unquote_and_convert_to(a, 'iso-8859-1') expected = "Brosch\374re Rand" expected.force_encoding('iso-8859-1') if expected.respond_to?(:force_encoding) b.should eq expected end it "should unquote Shift_JIS QP with trailing =" do a = "=?Shift_JIS?Q?=93=FA=96{=8C=EA=?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "日本語" end it "handles Windows 1252 QP encoding" do # TODO: JRuby 1.7.0 has an encoding issue https://jira.codehaus.org/browse/JRUBY-6999 pending if defined?(JRUBY_VERSION) && JRUBY_VERSION >= '1.7.0' a = "=?WINDOWS-1252?Q?simple_=96_dash_=96_?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "simple – dash – " end it "should unquote multiple strings in the middle of the text" do a = "=?Shift_JIS?Q?=93=FA=96{=8C=EA=?= , =?Shift_JIS?Q?=93=FA=96{=8C=EA=?= " b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "日本語 , 日本語 " end it "should handle multiline quoted headers with mixed content" do a = "=?iso-2022-jp?B?GyRCP3AwQxsoQg==?=2=?iso-2022-jp?B?GyRCIiobKEI=?= =?iso-2022-jp?B?GyRCOkc2YUxnPj4kcj5+JGsySCQsJFskSCRzJEk4K0V2GyhC?= =?iso-2022-jp?B?GyRCJD8kaSRKJCQhKjxkJDckJCQzJEgkRyQ5JE0hI0Z8GyhC?= =?iso-2022-jp?B?GyRCS1wkTiQkJCQkSCQzJG0hIiRvJFMkNSRTJE5AJDMmGyhC?= =?iso-2022-jp?B?GyRCJCw8OiRvJGwkRCREJCIkazg9Ol8hIiRKJHMkSCQrGyhC?= =?iso-2022-jp?B?GyRCOGVAJCRLO0QkNSRNJFAhIkxeQk4kSiQkISokSCReGyhC?= =?iso-2022-jp?B?GyRCJF4kTztXJCYkTiRAISMbKEI=?=" b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "瑞庵2→最近門松を飾る家がほとんど見当たらない!寂しいことですね。日本のいいところ、わびさびの世界が失われつつある現在、なんとか後世に残さねば、勿体ない!とままは思うのだ。" end it "should handle quoted string with mixed content that have a plain string at the end" do a = 'Der Kunde ist K=?utf-8?B?w7Y=?=nig' b = Mail::Encodings.unquote_and_convert_to(a, 'utf-8') b.should eq "Der Kunde ist König" end end end describe "quoted printable encoding and decoding" do it "should handle underscores in the text" do expected = 'something_with_underscores' Mail::Encodings.get_encoding(:quoted_printable).encode(expected).unpack("M").first.should eq expected end it "should handle underscores in the text" do expected = 'something with_underscores' Mail::Encodings.get_encoding(:quoted_printable).encode(expected).unpack("M").first.should eq expected end it "should keep the underscores in the text" do expected = 'something_with_underscores' encoded = Mail::Encodings.get_encoding(:quoted_printable).encode(expected) Mail::Encodings.get_encoding(:quoted_printable).decode(encoded).should eq expected end it "should handle a new line in the text" do if RUBY_VERSION >= '1.9' expected = "\nRe: ol\341".force_encoding('ISO-8859-1').encode('utf-8') else expected = Iconv.conv("UTF-8", "ISO-8859-1", "\nRe: ol\341") end encoded = "=?ISO-8859-1?Q?\nRe=3A_ol=E1?=" Mail::Encodings.value_decode(encoded).should eq expected end end describe "pre encoding non usascii text" do it "should not change an ascii string" do raw = 'mikel@test.lindsaar.net' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq raw end it "should encode a display that contains non usascii" do raw = 'Lindsああr ' encoded = '=?UTF-8?B?TGluZHPjgYLjgYJy?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode a single token that contains non usascii" do raw = '' encoded = Mail::Encodings.encode_non_usascii(raw, 'utf-8') Mail::Encodings.value_decode(encoded).should eq raw end it "should encode a display that contains non usascii with quotes as no quotes" do raw = '"Lindsああr" ' encoded = '=?UTF-8?B?TGluZHPjgYLjgYJy?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode a display name with us-ascii and non-usascii parts" do raw = 'Mikel Lindsああr ' encoded = 'Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode a display name with us-ascii and non-usascii parts ignoring quotes" do raw = '"Mikel Lindsああr" ' encoded = '=?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode a quoted display name with us-ascii and non-usascii that ends with a non-usascii part" do raw = '"Marc André" ' encoded = '=?UTF-8?B?TWFyYyBBbmRyw6k=?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode multiple addresses correctly" do raw = '"Mikel Lindsああr" , "あdあ" ' encoded = '=?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= , =?UTF-8?B?44GCZOOBgg==?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode multiple unquoted addresses correctly" do raw = 'Mikel Lindsああr , あdあ ' encoded = 'Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , =?UTF-8?B?44GCZOOBgg==?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should encode multiple un bracketed addresses and groups correctly" do raw = '"Mikel Lindsああr" test1@lindsaar.net, group: "あdあ" test2@lindsaar.net, me@lindsaar.net;' encoded = '=?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= test1@lindsaar.net, group: =?UTF-8?B?44GCZOOBgg==?= test2@lindsaar.net, me@lindsaar.net;' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end it "should correctly match and encode non-usascii letters at the end of a quoted string" do raw = '"Felix Baarß" ' encoded = '=?UTF-8?B?RmVsaXggQmFhcsOf?= ' Mail::Encodings.encode_non_usascii(raw, 'utf-8').should eq encoded end end describe "address encoding" do it "should not do anything to a plain address" do raw = 'mikel@test.lindsaar.net' encoded = 'mikel@test.lindsaar.net' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should encode an address correctly" do raw = '"Mikel Lindsああr" ' encoded = '=?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= ' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should encode multiple addresses correctly" do raw = ['"Mikel Lindsああr" ', '"あdあ" '] encoded = '=?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= , =?UTF-8?B?44GCZOOBgg==?= ' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should handle a single ascii address correctly from a string" do raw = ['"Mikel Lindsaar" '] encoded = '"Mikel Lindsaar" ' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should handle multiple ascii addresses correctly from a string" do raw = 'Mikel Lindsaar , Ada ' encoded = 'Mikel Lindsaar , Ada ' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should handle ascii addresses correctly as an array" do raw = ['Mikel Lindsaar ', 'Ada '] encoded = 'Mikel Lindsaar , Ada ' Mail::Encodings.address_encode(raw, 'utf-8').should eq encoded end it "should ignore single nil" do Mail::Encodings.address_encode(nil, 'utf-8').should eq nil end it "should ignore nil in arrays" do Mail::Encodings.address_encode(["aa@bb.com", nil], 'utf-8').should eq "aa@bb.com" end end end mail-2.5.4/spec/mail/example_emails_spec.rb000066400000000000000000000350321214434061600206500ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "Test emails" do describe "from RFC2822" do # From RFC 2822: # This could be called a canonical message. It has a single author, # John Doe, a single recipient, Mary Smith, a subject, the date, a # message identifier, and a textual message in the body. it "should handle the basic test email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example01.eml')) mail.from.should eq ["jdoe@machine.example"] mail.to.should eq ['mary@example.net'] mail.message_id.should eq '1234@local.machine.example' mail.date.should eq ::DateTime.parse('21 Nov 1997 09:55:06 -0600') mail.subject.should eq 'Saying Hello' end # From RFC 2822: # If John's secretary Michael actually sent the message, though John # was the author and replies to this message should go back to him, the # sender field would be used: it "should handle the sender test email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example02.eml')) mail.from.should eq ['jdoe@machine.example'] mail.sender.should eq 'mjones@machine.example' mail.to.should eq ['mary@example.net'] mail.message_id.should eq '1234@local.machine.example' mail.date.should eq ::DateTime.parse('21 Nov 1997 09:55:06 -0600') mail.subject.should eq 'Saying Hello' end # From RFC 2822: # This message includes multiple addresses in the destination fields # and also uses several different forms of addresses. # # Note that the display names for Joe Q. Public and Giant; "Big" Box # needed to be enclosed in double-quotes because the former contains # the period and the latter contains both semicolon and double-quote # characters (the double-quote characters appearing as quoted-pair # construct). Conversely, the display name for Who? could appear # without them because the question mark is legal in an atom. Notice # also that jdoe@example.org and boss@nil.test have no display names # associated with them at all, and jdoe@example.org uses the simpler # address form without the angle brackets. # # "Giant; \"Big\" Box" it "should handle multiple recipients test email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example03.eml')) mail.from.should eq ['john.q.public@example.com'] mail.to.should eq ['mary@x.test', 'jdoe@example.org', 'one@y.test'] mail.cc.should eq ['boss@nil.test', "sysservices@example.net"] mail.message_id.should eq '5678.21-Nov-1997@example.com' mail.date.should eq ::DateTime.parse('1 Jul 2003 10:52:37 +0200') end # From RFC 2822: # A.1.3. Group addresses # In this message, the "To:" field has a single group recipient named A # Group which contains 3 addresses, and a "Cc:" field with an empty # group recipient named Undisclosed recipients. it "should handle group address email test" do mail = Mail.read(fixture('emails', 'rfc2822', 'example04.eml')) mail.from.should eq ['pete@silly.example'] mail.to.should eq ['c@a.test', 'joe@where.test', 'jdoe@one.test'] mail[:cc].group_names.should eq ['Undisclosed recipients'] mail.message_id.should eq 'testabcd.1234@silly.example' mail.date.should eq ::DateTime.parse('Thu, 13 Feb 1969 23:32:54 -0330') end # From RFC 2822: # A.2. Reply messages # The following is a series of three messages that make up a # conversation thread between John and Mary. John firsts sends a # message to Mary, Mary then replies to John's message, and then John # replies to Mary's reply message. # # Note especially the "Message-ID:", "References:", and "In-Reply-To:" # fields in each message. it "should handle reply messages" do mail = Mail.read(fixture('emails', 'rfc2822', 'example05.eml')) mail.from.should eq ["jdoe@machine.example"] mail.to.should eq ['mary@example.net'] mail.subject.should eq 'Saying Hello' mail.message_id.should eq '1234@local.machine.example' mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 09:55:06 -0600') end # From RFC 2822: # When sending replies, the Subject field is often retained, though # prepended with "Re: " as described in section 3.6.5. # Note the "Reply-To:" field in the below message. When John replies # to Mary's message above, the reply should go to the address in the # "Reply-To:" field instead of the address in the "From:" field. it "should handle reply message 2" do mail = Mail.read(fixture('emails', 'rfc2822', 'example06.eml')) mail.from.should eq ['mary@example.net'] mail.to.should eq ['jdoe@machine.example'] mail.reply_to.should eq ['smith@home.example'] mail.subject.should eq 'Re: Saying Hello' mail.message_id.should eq '3456@example.net' mail[:in_reply_to].message_ids.should eq ['1234@local.machine.example'] mail[:references].message_ids.should eq ['1234@local.machine.example'] mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 10:01:10 -0600') end # From RFC 2822: # Final reply message it "should handle the final reply message" do mail = Mail.read(fixture('emails', 'rfc2822', 'example07.eml')) mail.to.should eq ['smith@home.example'] mail.from.should eq ['jdoe@machine.example'] mail.subject.should eq 'Re: Saying Hello' mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 11:00:00 -0600') mail.message_id.should eq 'abcd.1234@local.machine.tld' mail.in_reply_to.should eq '3456@example.net' mail[:references].message_ids.should eq ['1234@local.machine.example', '3456@example.net'] end # From RFC2822 # A.3. Resent messages # Say that Mary, upon receiving this message, wishes to send a copy of # the message to Jane such that (a) the message would appear to have # come straight from John; (b) if Jane replies to the message, the # reply should go back to John; and (c) all of the original # information, like the date the message was originally sent to Mary, # the message identifier, and the original addressee, is preserved. In # this case, resent fields are prepended to the message: # # If Jane, in turn, wished to resend this message to another person, # she would prepend her own set of resent header fields to the above # and send that. it "should handle the rfc resent example email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example08.eml')) mail.resent_from.should eq ['mary@example.net'] mail.resent_to.should eq ['j-brown@other.example'] mail.resent_date.should eq ::DateTime.parse('Mon, 24 Nov 1997 14:22:01 -0800') mail.resent_message_id.should eq '78910@example.net' mail.from.should eq ['jdoe@machine.example'] mail.to.should eq ['mary@example.net'] mail.subject.should eq 'Saying Hello' mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 09:55:06 -0600') mail.message_id.should eq '1234@local.machine.example' end # A.4. Messages with trace fields # As messages are sent through the transport system as described in # [RFC2821], trace fields are prepended to the message. The following # is an example of what those trace fields might look like. Note that # there is some folding white space in the first one since these lines # can be long. it "should handle the RFC trace example email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example09.eml')) mail.received[0].info.should eq 'from x.y.test by example.net via TCP with ESMTP id ABC12345 for ' mail.received[0].date_time.should eq ::DateTime.parse('21 Nov 1997 10:05:43 -0600') mail.received[1].info.should eq 'from machine.example by x.y.test' mail.received[1].date_time.should eq ::DateTime.parse('21 Nov 1997 10:01:22 -0600') mail.from.should eq ['jdoe@machine.example'] mail.to.should eq ['mary@example.net'] mail.subject.should eq 'Saying Hello' mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 09:55:06 -0600') mail.message_id.should eq '1234@local.machine.example' end # A.5. White space, comments, and other oddities # White space, including folding white space, and comments can be # inserted between many of the tokens of fields. Taking the example # from A.1.3, white space and comments can be inserted into all of the # fields. # # The below example is aesthetically displeasing, but perfectly legal. # Note particularly (1) the comments in the "From:" field (including # one that has a ")" character appearing as part of a quoted-pair); (2) # the white space absent after the ":" in the "To:" field as well as # the comment and folding white space after the group name, the special # character (".") in the comment in Chris Jones's address, and the # folding white space before and after "joe@example.org,"; (3) the # multiple and nested comments in the "Cc:" field as well as the # comment immediately following the ":" after "Cc"; (4) the folding # white space (but no comments except at the end) and the missing # seconds in the time of the date field; and (5) the white space before # (but not within) the identifier in the "Message-ID:" field. it "should handle the rfc whitespace test email" do mail = Mail.read(fixture('emails', 'rfc2822', 'example10.eml')) mail.from.should eq ["pete(his account)@silly.test"] mail.to.should eq ["c@public.example", "joe@example.org", "jdoe@one.test"] mail[:cc].group_names.should eq ['(Empty list)(start)Undisclosed recipients '] mail.date.should eq ::DateTime.parse('Thu, 13 Feb 1969 23:32 -0330') mail.message_id.should eq 'testabcd.1234@silly.test' end # A.6. Obsoleted forms # The following are examples of obsolete (that is, the "MUST NOT # generate") syntactic elements described in section 4 of this # document. # A.6.1. Obsolete addressing # Note in the below example the lack of quotes around Joe Q. Public, # the route that appears in the address for Mary Smith, the two commas # that appear in the "To:" field, and the spaces that appear around the # "." in the jdoe address. it "should handle the rfc obsolete addressing" do pending mail = Mail.read(fixture('emails', 'rfc2822', 'example11.eml')) mail[:from].addresses.should eq ['john.q.public@example.com'] mail.from.should eq '"Joe Q. Public" ' mail.to.should eq ["@machine.tld:mary@example.net", 'jdoe@test.example'] mail.date.should eq ::DateTime.parse('Tue, 1 Jul 2003 10:52:37 +0200') mail.message_id.should eq '5678.21-Nov-1997@example.com' end # A.6.2. Obsolete dates # # The following message uses an obsolete date format, including a non- # numeric time zone and a two digit year. Note that although the # day-of-week is missing, that is not specific to the obsolete syntax; # it is optional in the current syntax as well. it "should handle the rfc obsolete dates" do pending mail = Mail.read(fixture('emails', 'rfc2822', 'example12.eml')) mail.from.should eq 'jdoe@machine.example' mail.to.should eq 'mary@example.net' mail.date.should eq ::DateTime.parse('21 Nov 97 09:55:06 GMT') mail.message_id.should eq '1234@local.machine.example' end # A.6.3. Obsolete white space and comments # # White space and comments can appear between many more elements than # in the current syntax. Also, folding lines that are made up entirely # of white space are legal. # # Note especially the second line of the "To:" field. It starts with # two space characters. (Note that "__" represent blank spaces.) # Therefore, it is considered part of the folding as described in # section 4.2. Also, the comments and white space throughout # addresses, dates, and message identifiers are all part of the # obsolete syntax. it "should handle the rfc obsolete whitespace email" do pending mail = Mail.read(fixture('emails', 'rfc2822', 'example13.eml')) mail.from.should eq 'John Doe ' mail.to.should eq 'Mary Smith ' mail.date.should eq ::DateTime.parse('Fri, 21 Nov 1997 09:55:06 -0600') mail.message_id.should eq '1234@local(blah).machine.example' doing { Mail::Message.new(email) }.should_not raise_error end it "should handle folding subject" do mail = Mail.read(fixture('emails', 'rfc2822', 'example14.eml')) mail.from.should eq ["atsushi@example.com"] mail.subject.should eq "Re: TEST テストテスト" mail.message_id.should eq '0CC5E11ED2C1D@example.com' mail.body.decoded.should eq "Hello\n" end end describe "from the wild" do describe "raw_email_encoded_stack_level_too_deep.eml" do before(:each) do @message = Mail.read(fixture('emails', 'mime_emails', 'raw_email_encoded_stack_level_too_deep.eml')) end it "should return an 'encoded' version without raising a SystemStackError" do doing { @message.encoded }.should_not raise_error end it "should have two parts" do @message.parts.length.should eq 2 end end describe "sig_only_email.eml" do before(:each) do @message = Mail.read(fixture('emails', 'mime_emails', 'sig_only_email.eml')) end it "should not error on multiart/signed emails" do doing { @message.encoded }.should_not raise_error end it "should have one attachment called signature.asc" do @message.attachments.length.should eq 1 @message.attachments.first.filename.should eq 'signature.asc' end end describe "handling invalid group lists" do before(:each) do @message = Mail.read(fixture('emails', 'error_emails', 'empty_group_lists.eml')) end it "should parse the email and encode without crashing" do doing { @message.encoded }.should_not raise_error end it "should return an empty groups list" do @message[:to].group_addresses.should eq [] end end end describe "empty address lists" do before(:each) do @message = Mail.read(fixture('emails', 'error_emails', 'weird_to_header.eml')) end it "should parse the email and encode without crashing" do doing { @message.encoded }.should_not raise_error end it "should return an empty groups list" do @message.to.should eq ['user-example@aol.com', 'e-s-a-s-2200@app.ar.com'] end end end mail-2.5.4/spec/mail/field_list_spec.rb000066400000000000000000000030171214434061600177770ustar00rootroot00000000000000require 'spec_helper' describe Mail::FieldList do it "should be able to add new fields" do fl = Mail::FieldList.new fl << Mail::Field.new("To: mikel@me.com") fl << Mail::Field.new("From: mikel@me.com") fl.length.should eq 2 end it "should be able to add new fields in the right order" do fl = Mail::FieldList.new fl << Mail::Field.new("To: mikel@me.com") fl << Mail::Field.new("From: mikel@me.com") fl << Mail::Field.new("Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500") fl << Mail::Field.new("Return-Path: mikel@me.com") fl[0].field.class.should eq Mail::ReturnPathField fl[1].field.class.should eq Mail::ReceivedField fl[2].field.class.should eq Mail::FromField fl[3].field.class.should eq Mail::ToField end it "should add new Received items after the existing ones" do fl = Mail::FieldList.new fl << Mail::Field.new("To: mikel@me.com") fl << Mail::Field.new("From: mikel@me.com") fl << Mail::Field.new("Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500") fl << Mail::Field.new("Return-Path: mikel@me.com") fl << Mail::Field.new("Received: from 123.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500") fl[2].field.value.should eq 'from 123.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500' end end mail-2.5.4/spec/mail/field_spec.rb000066400000000000000000000314001214434061600167410ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Field do describe "initialization" do it "should be instantiated" do doing {Mail::Field.new('To: Mikel')}.should_not raise_error Mail::Field.new('To: Mikel').field.class.should eq Mail::ToField end it "should allow you to init on an array" do field = Mail::Field.new("To", ['test1@lindsaar.net', 'Mikel ']) field.addresses.should eq ["test1@lindsaar.net", "test2@lindsaar.net"] end it "should allow us to pass an empty value" do doing {Mail::Field.new('To')}.should_not raise_error Mail::Field.new('To').field.class.should eq Mail::ToField end it "should allow us to pass a value" do doing {Mail::Field.new('To', 'Mikel')}.should_not raise_error Mail::Field.new('To', 'Mikel').field.class.should eq Mail::ToField end it "should match up fields to class names" do structured_fields = %w[ Date From Sender Reply-To To Cc Bcc Message-ID In-Reply-To References Keywords Resent-Date Resent-From Resent-Sender Resent-To Resent-Cc Resent-Bcc Resent-Message-ID Return-Path Received Subject Comments Mime-Version Content-Transfer-Encoding Content-Description Content-Disposition Content-Type ] structured_fields.each do |sf| words = sf.split("-").map { |a| a.capitalize } klass = "#{words.join}Field" Mail::Field.new("#{sf}: ").field.class.should eq Mail.const_get(klass) end end it "should match up fields to class names regardless of case" do structured_fields = %w[ dATE fROM sENDER REPLY-TO TO CC BCC MESSAGE-ID IN-REPLY-TO REFERENCES KEYWORDS resent-date resent-from rESENT-sENDER rESENT-tO rESent-cc resent-bcc reSent-MESSAGE-iD rEtURN-pAtH rEcEiVeD Subject Comments Mime-VeRSIOn cOntenT-transfer-EnCoDiNg Content-Description Content-Disposition cOnTENt-TyPe ] structured_fields.each do |sf| words = sf.split("-").map { |a| a.capitalize } klass = "#{words.join}Field" Mail::Field.new("#{sf}: ").field.class.should eq Mail.const_get(klass) end end it "should say anything that is not a known field is an optional field" do unstructured_fields = %w[ Too Becc bccc Random X-Mail MySpecialField ] unstructured_fields.each do |sf| Mail::Field.new("#{sf}: Value").field.class.should eq Mail::OptionalField end end it "should split the name and values out of the raw field passed in" do field = Mail::Field.new('To: Bob') field.name.should eq 'To' field.value.should eq 'Bob' end it "should split the name and values out of the raw field passed in if missing whitespace" do field = Mail::Field.new('To:Bob') field.name.should eq 'To' field.value.should eq 'Bob' end it "should split the name and values out of the raw field passed in if having added inapplicable whitespace" do field = Mail::Field.new('To : Bob ') field.name.should eq 'To' field.value.should eq 'Bob' end it "should return an unstuctured field if the structured field parsing raises an error" do Mail::ToField.should_receive(:new).and_raise(Mail::Field::ParseError.new(Mail::ToField, 'To: Bob, ,,, Frank, Smith', "Some reason")) field = Mail::Field.new('To: Bob, ,,, Frank, Smith') field.field.class.should eq Mail::UnstructuredField field.name.should eq 'To' field.value.should eq 'Bob, ,,, Frank, Smith' end it "should call to_s on its field when sent to_s" do @field = Mail::SubjectField.new('Subject: Hello bob') Mail::SubjectField.should_receive(:new).and_return(@field) @field.should_receive(:to_s).once Mail::Field.new('Subject: Hello bob').to_s end it "should pass missing methods to its instantiated field class" do field = Mail::Field.new('To: Bob') field.field.should_receive(:addresses).once field.addresses end it "should change its type if you change the name" do field = Mail::Field.new("To: mikel@me.com") field.field.class.should eq Mail::ToField field.value = "bob@me.com" field.field.class.should eq Mail::ToField end it "should create a field without trying to parse if given a symbol" do field = Mail::Field.new('Message-ID') field.field.class.should eq Mail::MessageIdField end it "should inherit charset" do charset = 'iso-2022-jp' field = Mail::Field.new('Subject: こんにちは', charset) field.charset.should eq charset end end describe "error handling" do it "should populate the errors array if it finds a field it can't deal with" do field = Mail::Field.new('Content-Transfer-Encoding: 8@bit') field.field.errors.size.should eq 1 field.field.errors[0][0].should eq 'Content-Transfer-Encoding' field.field.errors[0][1].should eq '8@bit' field.field.errors[0][2].to_s.should =~ /ContentTransferEncodingElement can not parse |17-bit|/ end end describe "helper methods" do it "should reply if it is responsible for a field name as a capitalized string - structured field" do field = Mail::Field.new("To: mikel@test.lindsaar.net") field.responsible_for?("To").should be_true end it "should reply if it is responsible for a field as a lower case string - structured field" do field = Mail::Field.new("To: mikel@test.lindsaar.net") field.responsible_for?("to").should be_true end it "should reply if it is responsible for a field as a symbol - structured field" do field = Mail::Field.new("To: mikel@test.lindsaar.net") field.responsible_for?(:to).should be_true end it "should say it is == to another if their field names match" do Mail::Field.new("To: mikel").same(Mail::Field.new("To: bob")).should be_true end it "should say it is not == to another if their field names do not match" do Mail::Field.new("From: mikel").should_not == Mail::Field.new("To: bob") end it "should sort according to the field order" do list = [Mail::Field.new("To: mikel"), Mail::Field.new("Return-Path: bob")] list.sort[0].name.should eq "Return-Path" end end describe 'user defined fields' do it "should say it is == to another if their field names match" do Mail::Field.new("X-Foo: mikel").same(Mail::Field.new("X-Foo: bob")).should be_true end it "should say it is not == to another if their field names do not match" do Mail::Field.new("X-Foo: mikel").should_not == Mail::Field.new("X-Bar: bob") end end describe "passing an encoding" do it "should allow you to send in unencoded strings to fields and encode them" do subject = Mail::SubjectField.new("This is あ string", 'utf-8') subject.encoded.should eq "Subject: =?UTF-8?Q?This_is_=E3=81=82_string?=\r\n" subject.decoded.should eq "This is あ string" end it "should allow you to send in unencoded strings to address fields and encode them" do to = Mail::ToField.new('"Mikel Lindsああr" ', 'utf-8') to.encoded.should eq "To: =?UTF-8?B?TWlrZWwgTGluZHPjgYLjgYJy?= \r\n" end it "should allow you to send in unencoded strings without quotes to address fields and encode them" do to = Mail::ToField.new('Mikel Lindsああr ', 'utf-8') to.encoded.should eq "To: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= \r\n" end it "should allow you to send in unencoded strings to address fields and encode them" do to = Mail::ToField.new("あdあ ", 'utf-8') to.encoded.should eq "To: =?UTF-8?B?44GCZOOBgg==?= \r\n" end it "should allow you to send in multiple unencoded strings to address fields and encode them" do to = Mail::ToField.new(["Mikel Lindsああr ", "あdあ "], 'utf-8') to.encoded.should eq "To: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" end it "should allow you to send in multiple unencoded strings to any address field" do mail = Mail.new mail.charset = 'utf-8' array = ["Mikel Lindsああr ", "あdあ "] field = Mail::ToField.new(array, 'utf-8') field.encoded.should eq "#{Mail::ToField::CAPITALIZED_FIELD}: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" field = Mail::FromField.new(array, 'utf-8') field.encoded.should eq "#{Mail::FromField::CAPITALIZED_FIELD}: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" field = Mail::CcField.new(array, 'utf-8') field.encoded.should eq "#{Mail::CcField::CAPITALIZED_FIELD}: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" field = Mail::ReplyToField.new(array, 'utf-8') field.encoded.should eq "#{Mail::ReplyToField::CAPITALIZED_FIELD}: Mikel =?UTF-8?B?TGluZHPjgYLjgYJy?= , \r\n\s=?UTF-8?B?44GCZOOBgg==?= \r\n" end it "should allow an encoded value in the Subject field and decode it automatically (issue 44)" do pending if RUBY_VERSION < '1.9' subject = Mail::SubjectField.new("=?ISO-8859-1?Q?2_=FAlt?=", 'utf-8') subject.decoded.should eq "2 últ" end it "should allow you to encoded text in the middle (issue 44)" do pending if RUBY_VERSION < '1.9' subject = Mail::SubjectField.new("ma=?ISO-8859-1?Q?=F1ana?=", 'utf-8') subject.decoded.should eq "mañana" end it "more tolerable to encoding definitions, ISO (issue 120)" do pending if RUBY_VERSION < '1.9' subject = Mail::SubjectField.new("ma=?ISO88591?Q?=F1ana?=", 'utf-8') subject.decoded.should eq "mañana" end it "more tolerable to encoding definitions, ISO-long (issue 120)" do # Rubies under 1.9 don't handle encoding conversions pending if RUBY_VERSION < '1.9' # TODO: JRuby 1.7.0 has an encoding issue https://jira.codehaus.org/browse/JRUBY-6999 pending if defined?(JRUBY_VERSION) && JRUBY_VERSION >= '1.7.0' subject = Mail::SubjectField.new("=?iso2022jp?B?SEVBUlQbJEIkSiQ0TyJNbRsoQg?=", 'utf-8') subject.decoded.should eq "HEARTなご連絡" end it "more tolerable to encoding definitions, UTF (issue 120)" do to = Mail::ToField.new("=?utf-8?B?44GCZOOBgg==?= ", 'utf-8') to.encoded.should eq "To: =?utf-8?B?44GCZOOBgg==?= \r\n" to.decoded.should eq "\"あdあ\" " end it "more tolerable to encoding definitions, ISO (issue 120)" do subject = Mail::SubjectField.new("=?UTF-8?B?UmU6IHRlc3QgZW52w61vIG1lbnNhamUgY29u?=", 'utf-8') subject.decoded.should eq "Re: test envío mensaje con" end it "more tolerable to encoding definitions, Windows (issue 120)" do pending if RUBY_VERSION < '1.9' # TODO: JRuby 1.7.0 has an encoding issue https://jira.codehaus.org/browse/JRUBY-6999 pending if defined?(JRUBY_VERSION) && JRUBY_VERSION >= '1.7.0' subject = Mail::SubjectField.new("=?Windows1252?Q?It=92s_a_test=3F?=", 'utf-8') subject.decoded.should eq "It’s a test?" end it "should support ascii encoded utf-8 subjects" do s = "=?utf-8?Q?simp?= =?utf-8?Q?le_=E2=80=93_dash_=E2=80=93_?=" subject = Mail::SubjectField.new(s, 'utf-8') subject.decoded.should == "simple – dash – " end it "should support ascii encoded windows subjects" do pending if RUBY_VERSION < '1.9' # TODO: JRuby 1.7.0 has an encoding issue https://jira.codehaus.org/browse/JRUBY-6999 pending if defined?(JRUBY_VERSION) && JRUBY_VERSION >= '1.7.0' s = "=?WINDOWS-1252?Q?simp?= =?WINDOWS-1252?Q?le_=96_dash_=96_?=" subject = Mail::SubjectField.new(s, "UTF-8") subject.decoded.should == "simple – dash – " end end describe Mail::Field::ParseError do it "should be structured" do error = nil begin Mail::DateTimeElement.new("invalid") rescue Mail::Field::ParseError => e error = e end error.should_not be_nil error.element.should eq Mail::DateTimeElement error.value.should eq "invalid" error.reason.should_not be_nil end end end mail-2.5.4/spec/mail/fields/000077500000000000000000000000001214434061600155675ustar00rootroot00000000000000mail-2.5.4/spec/mail/fields/bcc_field_spec.rb000066400000000000000000000074471214434061600210340ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::BccField do # The "Bcc:" field (where the "Bcc" means "Blind Carbon Copy") contains # addresses of recipients of the message whose addresses are not to be # revealed to other recipients of the message. There are three ways in # which the "Bcc:" field is used. In the first case, when a message # containing a "Bcc:" field is prepared to be sent, the "Bcc:" line is # removed even though all of the recipients (including those specified # in the "Bcc:" field) are sent a copy of the message. In the second # case, recipients specified in the "To:" and "Cc:" lines each are sent # a copy of the message with the "Bcc:" line removed as above, but the # recipients on the "Bcc:" line get a separate copy of the message # containing a "Bcc:" line. (When there are multiple recipient # addresses in the "Bcc:" field, some implementations actually send a # separate copy of the message to each recipient with a "Bcc:" # containing only the address of that particular recipient.) Finally, # since a "Bcc:" field may contain no addresses, a "Bcc:" field can be # sent without any addresses indicating to the recipients that blind # copies were sent to someone. Which method to use with "Bcc:" fields # is implementation dependent, but refer to the "Security # Considerations" section of this document for a discussion of each. describe "initialization" do it "should initialize" do doing { Mail::BccField.new("Bcc: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::BccField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::BccField.new('Bcc: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Bcc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::BccField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Bcc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods occurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::BccField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::BccField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::BccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::BccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return nothing on encoded as Bcc should not be in the mail" do t = Mail::BccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "" end it "should return the decoded line" do t = Mail::BccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.decoded.should eq "sam@me.com, my_group: mikel@me.com, bob@you.com;" end end end mail-2.5.4/spec/mail/fields/cc_field_spec.rb000066400000000000000000000055441214434061600206660ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # The "Cc:" field (where the "Cc" means "Carbon Copy" in the sense of # making a copy on a typewriter using carbon paper) contains the # addresses of others who are to receive the message, though the # content of the message may not be directed at them. describe Mail::CcField do describe "initialization" do it "should initialize" do doing { Mail::CcField.new("Cc: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::CcField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::CcField.new('Cc: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Cc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::CcField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Cc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods occurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::CcField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::CcField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::CcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::CcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line for one address" do t = Mail::CcField.new('sam@me.com') t.encoded.should eq "Cc: sam@me.com\r\n" end it "should return the encoded line" do t = Mail::CcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Cc: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end it "should return the decoded line" do t = Mail::CcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.decoded.should eq "sam@me.com, my_group: mikel@me.com, bob@you.com;" end end end mail-2.5.4/spec/mail/fields/comments_field_spec.rb000066400000000000000000000012111214434061600221110ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::CommentsField do # # comments = "Comments:" unstructured CRLF it "should initialize" do doing { Mail::CommentsField.new("this is a comment") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::CommentsField.new('Comments: this is a comment') t.name.should eq 'Comments' t.value.should eq 'this is a comment' end it "should accept a string with the field name" do t = Mail::CommentsField.new('this is a comment') t.name.should eq 'Comments' t.value.should eq 'this is a comment' end end mail-2.5.4/spec/mail/fields/common/000077500000000000000000000000001214434061600170575ustar00rootroot00000000000000mail-2.5.4/spec/mail/fields/common/address_container_spec.rb000066400000000000000000000012711214434061600241060ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe 'AddressContainer' do it "should allow you to append an address to an address field result" do m = Mail.new("To: mikel@test.lindsaar.net") m.to.should eq ['mikel@test.lindsaar.net'] m.to << 'bob@test.lindsaar.net' m.to.should eq ['mikel@test.lindsaar.net', 'bob@test.lindsaar.net'] end it "should handle complex addresses correctly" do m = Mail.new("From: mikel@test.lindsaar.net") m.from.should eq ['mikel@test.lindsaar.net'] m.from << '"Ada Lindsaar" , bob@test.lindsaar.net' m.from.should eq ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net', 'bob@test.lindsaar.net'] end end mail-2.5.4/spec/mail/fields/common/common_address_spec.rb000066400000000000000000000251731214434061600234230ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "Mail::CommonAddress" do describe "address handling" do it "should give the addresses it is going to" do field = Mail::ToField.new("To: test1@lindsaar.net") field.addresses.first.should eq "test1@lindsaar.net" end it "should split up the address list into individual addresses" do field = Mail::ToField.new("To: test1@lindsaar.net, test2@lindsaar.net") field.addresses.should eq ["test1@lindsaar.net", "test2@lindsaar.net"] end it "should give the formatted addresses" do field = Mail::ToField.new("To: Mikel , Bob ") field.formatted.should eq ["Mikel ", "Bob "] end it "should give the display names" do field = Mail::ToField.new("To: Mikel , Bob ") field.display_names.should eq ["Mikel", "Bob"] end it "should give the actual address objects" do field = Mail::ToField.new("To: Mikel , Bob ") field.addrs.each do |addr| addr.class.should eq Mail::Address end end it "should handle groups as well" do field = Mail::ToField.new("To: test1@lindsaar.net, group: test2@lindsaar.net, me@lindsaar.net;") field.addresses.should eq ["test1@lindsaar.net", "test2@lindsaar.net", "me@lindsaar.net"] end it "should provide a list of groups" do field = Mail::ToField.new("To: test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.group_names.should eq ["My Group"] end it "should provide a list of addresses per group" do field = Mail::ToField.new("To: test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.groups["My Group"].length.should eq 2 field.groups["My Group"].first.to_s.should eq 'test2@lindsaar.net' field.groups["My Group"].last.to_s.should eq 'me@lindsaar.net' end it "should provide a list of addresses that are just in the groups" do field = Mail::ToField.new("To: test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.group_addresses.should eq ['test2@lindsaar.net', 'me@lindsaar.net'] end describe ".value=" do it "should handle initializing as an empty string" do field = Mail::ToField.new("") field.addresses.should eq [] field.value = 'mikel@test.lindsaar.net' field.addresses.should eq ['mikel@test.lindsaar.net'] end it "should encode to an empty string if it has no addresses or groups" do field = Mail::ToField.new("") field.encoded.should eq '' field.value = 'mikel@test.lindsaar.net' field.encoded.should eq "To: mikel@test.lindsaar.net\r\n" end context "a unquoted multi-byte address is given" do let(:given_value) { 'みける ' } it "should allow you to set an unquoted, multi-byte address value after initialization" do expected_result = "To: =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("") field.value = given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("") field.value = given_value field.value.should eq given_value end end context "a quoted multi-byte address is given" do let(:given_value) { '"みける" ' } it "should allow you to set an quoted, multi-byte address value after initialization" do expected_result = "To: =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("") field.value = given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("") field.value = given_value field.value.should eq given_value end end end describe ".<<" do it "should allow you to append an address" do field = Mail::ToField.new("") field << 'mikel@test.lindsaar.net' field.addresses.should eq ["mikel@test.lindsaar.net"] end context "a unquoted multi-byte address is given" do let(:given_value) { 'みける ' } context "initialized with an empty string" do it "should allow you to append an unquoted, multi-byte address value" do expected_result = "To: =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("") field << given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("") field << given_value field.value.should eq given_value end end context "initialized with an us-ascii address" do it "should allow you to append a quoted, multi-byte address value" do expected_result = "To: Mikel , \r\n =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("Mikel ") field << given_value field.encoded.should eq expected_result end end context "initialized with an multi-byte address" do it "should allow you to append a quoted, multi-byte address value" do expected_result = "To: =?UTF-8?B?44Of44Kx44Or?= , \r\n =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("ミケル ") field << given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("ミケル ") field << given_value field.value.should eq ["ミケル ", given_value].join(', ') end end end context "a quoted multi-byte address is given" do let(:given_value) { '"みける" ' } context "initialized with an empty string" do it "should allow you to append a quoted, multi-byte address value" do expected_result = "To: =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("") field << given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("") field << given_value field.value.should eq given_value end end context "initialized with an us-ascii address" do it "should allow you to append a quoted, multi-byte address value" do expected_result = "To: Mikel , \r\n =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("Mikel ") field << given_value field.encoded.should eq expected_result end end context "initialized with an multi-byte address" do it "should allow you to append a quoted, multi-byte address value" do expected_result = "To: =?UTF-8?B?44Of44Kx44Or?= , \r\n =?UTF-8?B?44G/44GR44KL?= \r\n" field = Mail::ToField.new("ミケル ") field << given_value field.encoded.should eq expected_result end it "should keep the given value" do field = Mail::ToField.new("ミケル ") field << given_value field.value.should eq ["ミケル ", given_value].join(', ') end end end end it "should preserve the display name" do field = Mail::ToField.new('"Mikel Lindsaar" ') field.display_names.should eq ["Mikel Lindsaar"] end it "should handle multiple addresses" do field = Mail::ToField.new(['test1@lindsaar.net', 'Mikel ']) field.addresses.should eq ['test1@lindsaar.net', 'test2@lindsaar.net'] end it "should handle missing display names with an angle address" do field = Mail::ToField.new('') field.encoded.should eq "To: mikel@test.lindsaar.net\r\n" end it "should handle empty display names with an angle address" do field = Mail::ToField.new('"" ') field.encoded.should eq "To: mikel@test.lindsaar.net\r\n" end end describe "encoding and decoding fields" do it "should allow us to encode an address field" do field = Mail::ToField.new("test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.encoded.should eq "To: test1@lindsaar.net, \r\n\sMy Group: test2@lindsaar.net, \r\n\sme@lindsaar.net;\r\n" end it "should allow us to encode a simple address field" do field = Mail::ToField.new("test1@lindsaar.net") field.encoded.should eq "To: test1@lindsaar.net\r\n" end it "should allow us to encode an address field" do field = Mail::CcField.new("test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.encoded.should eq "Cc: test1@lindsaar.net, \r\n\sMy Group: test2@lindsaar.net, \r\n\sme@lindsaar.net;\r\n" end it "should allow us to decode an address field" do field = Mail::ToField.new("test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;") field.decoded.should eq "test1@lindsaar.net, My Group: test2@lindsaar.net, me@lindsaar.net;" end it "should allow us to decode a non ascii address field" do field = Mail::ToField.new("=?UTF-8?B?44G/44GR44KL?= ") field.decoded.should eq '"みける" ' end it "should allow us to decode a non ascii address field" do field = Mail::ToField.new("=?UTF-8?B?44G/44GR44KL?= , =?UTF-8?B?44G/44GR44KL?= ") field.decoded.should eq '"みける" , "みける" ' end end it "should yield each address object in turn" do field = Mail::ToField.new("test1@lindsaar.net, test2@lindsaar.net, me@lindsaar.net") addresses = [] field.each do |address| addresses << address.address end addresses.should eq ["test1@lindsaar.net", "test2@lindsaar.net", "me@lindsaar.net"] end end mail-2.5.4/spec/mail/fields/common/common_date_spec.rb000066400000000000000000000013401214434061600227010ustar00rootroot00000000000000require 'spec_helper' describe Mail::CommonAddress do describe "encoding and decoding fields" do it "should allow us to encode an date field" do field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') field.encoded.should eq "Date: Wed, 12 Aug 2009 00:00:02 +0000\r\n" end it "should allow us to encode an resent date field" do field = Mail::ResentDateField.new('12 Aug 2009 00:00:02 GMT') field.encoded.should eq "Resent-Date: Wed, 12 Aug 2009 00:00:02 +0000\r\n" end it "should allow us to decode an address field" do field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') field.decoded.should eq "Wed, 12 Aug 2009 00:00:02 +0000" end end end mail-2.5.4/spec/mail/fields/common/common_field_spec.rb000066400000000000000000000064711214434061600230610ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::CommonField do describe "multi-charset support" do before(:each) do @original = $KCODE if RUBY_VERSION < '1.9' end after(:each) do $KCODE = @original if RUBY_VERSION < '1.9' end it "should return '' on to_s if there is no value" do Mail::SubjectField.new(nil).to_s.should eq '' end it "should leave ascii alone" do field = Mail::SubjectField.new("This is a test") field.encoded.should eq "Subject: This is a test\r\n" field.decoded.should eq "This is a test" end it "should encode a utf-8 string as utf-8 quoted printable" do value = "かきくけこ" if RUBY_VERSION < '1.9' $KCODE = 'u' result = "Subject: =?UTF-8?Q?=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n" else value.force_encoding('UTF-8') result = "Subject: =?UTF-8?Q?=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n" end field = Mail::SubjectField.new(value) field.encoded.should eq result field.decoded.should eq value field.value.should eq value end it "should wrap an encoded at 60 characters" do value = "かきくけこ かきくけこ かきくけこ かきくけこ かきくけこ かきくけこ かきくけこ かきくけこ かきくけこ" if RUBY_VERSION < '1.9' $KCODE = 'u' result = "Subject: =?UTF-8?Q?=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n" else value.force_encoding('UTF-8') result = "Subject: =?UTF-8?Q?=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n\s=?UTF-8?Q?_=E3=81=8B=E3=81=8D=E3=81=8F=E3=81=91=E3=81=93?=\r\n" end field = Mail::SubjectField.new(value) field.encoded.should eq result field.decoded.should eq value field.value.should eq value end it "should handle charsets in assigned addresses" do value = '"かきくけこ" ' if RUBY_VERSION < '1.9' $KCODE = 'u' result = "From: =?UTF-8?B?44GL44GN44GP44GR44GT?= \r\n" else value.force_encoding('UTF-8') result = "From: =?UTF-8?B?44GL44GN44GP44GR44GT?= \r\n" end field = Mail::FromField.new(value) field.encoded.should eq result field.decoded.should eq value end end end mail-2.5.4/spec/mail/fields/common/common_message_id_spec.rb000066400000000000000000000017651214434061600240770ustar00rootroot00000000000000require 'spec_helper' require 'mail/fields/common/common_message_id' describe Mail::CommonMessageId do describe "encoding and decoding fields" do it "should allow us to encode a message id field" do field = Mail::MessageIdField.new('') field.encoded.should eq "Message-ID: \r\n" end it "should allow us to encode a message id field" do field = Mail::MessageIdField.new('<1234@test.lindsaar.net>') field.encoded.should eq "Message-ID: <1234@test.lindsaar.net>\r\n" end it "should allow us to encode an in reply to field" do field = Mail::InReplyToField.new('<1234@test.lindsaar.net>') field.encoded.should eq "In-Reply-To: <1234@test.lindsaar.net>\r\n" end it "should allow us to decode a message id field" do field = Mail::MessageIdField.new('<1234@test.lindsaar.net>') field.decoded.should eq "<1234@test.lindsaar.net>" end end end mail-2.5.4/spec/mail/fields/common/parameter_hash_spec.rb000066400000000000000000000044551214434061600234110ustar00rootroot00000000000000require 'spec_helper' require 'mail/fields/common/parameter_hash' describe Mail::ParameterHash do it "should return the values in the hash" do hash = Mail::ParameterHash.new hash.merge!({'value1' => 'one', 'value2' => 'two'}) hash.keys.should include("value1") hash.keys.should include("value2") hash.values.should include('one') hash.values.should include('two') end it "should return the values in the hash regardless of symbol or string" do hash = Mail::ParameterHash.new hash.merge!({'value1' => 'one', 'value2' => 'two'}) hash['value1'].should eq 'one' hash['value2'].should eq 'two' hash[:value1].should eq 'one' hash[:value2].should eq 'two' end it "should return the values in the hash using case-insensitive key matching" do hash = Mail::ParameterHash.new hash.merge!({'value1' => 'one', 'VALUE2' => 'two'}) hash['VALUE1'].should eq 'one' hash['vAlUe2'].should eq 'two' hash[:VaLuE1].should eq 'one' hash[:value2].should eq 'two' end it "should return the correct value if they are not encoded" do hash = Mail::ParameterHash.new hash.merge!({'value1' => 'one', 'value2' => 'two'}) hash['value1'].should eq 'one' hash['value2'].should eq 'two' end it "should return a name list concatenated" do hash = Mail::ParameterHash.new hash.merge!({'value*1' => 'one', 'value*2' => 'two'}) hash['value'].should eq 'onetwo' end it "should return a name list concatenated and unencoded" do hash = Mail::ParameterHash.new hash.merge!({'value*0*' => "us-ascii'en'This%20is%20even%20more%20", 'value*1*' => "%2A%2A%2Afun%2A%2A%2A%20", 'value*2' => "isn't it"}) hash['value'].should eq "This is even more ***fun*** isn't it" end it "should allow us to add a value" do hash = Mail::ParameterHash.new hash['value'] = 'bob' hash['value'].should eq 'bob' end it "should return an encoded value" do hash = Mail::ParameterHash.new hash.merge!({'value*0*' => "us-ascii'en'This%20is%20even%20more%20", 'value*1*' => "%2A%2A%2Afun%2A%2A%2A%20", 'value*2' => "isn't it"}) hash.encoded.should eq %Q{value*0*=us-ascii'en'This%20is%20even%20more%20;\r\n\svalue*1*=%2A%2A%2Afun%2A%2A%2A%20;\r\n\svalue*2="isn't it"} end end mail-2.5.4/spec/mail/fields/content_description_field_spec.rb000066400000000000000000000025121214434061600243460ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentDescriptionField do # Content-Description Header Field # # The ability to associate some descriptive information with a given # body is often desirable. For example, it may be useful to mark an # "image" body as "a picture of the Space Shuttle Endeavor." Such text # may be placed in the Content-Description header field. This header # field is always optional. # # description := "Content-Description" ":" *text # # The description is presumed to be given in the US-ASCII character # set, although the mechanism specified in RFC 2047 may be used for # non-US-ASCII Content-Description values. # describe "initialization" do it "should initialize" do doing { Mail::ContentDescriptionField.new("Content-Description: This is a description") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::ContentDescriptionField.new('Content-Description: This is a description') t.name.should eq 'Content-Description' t.value.should eq 'This is a description' end it "should accept a string without the field name" do t = Mail::ContentDescriptionField.new('This is a description') t.name.should eq 'Content-Description' t.value.should eq 'This is a description' end end end mail-2.5.4/spec/mail/fields/content_disposition_field_spec.rb000066400000000000000000000063431214434061600243750ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentDispositionField do describe "initialization" do it "should initialize" do doing { Mail::ContentDispositionField.new("attachment; filename=File") }.should_not raise_error end it "should accept a string with the field name" do c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=File') c.name.should eq 'Content-Disposition' c.value.should eq 'attachment; filename=File' end it "should accept a string without the field name" do c = Mail::ContentDispositionField.new('attachment; filename=File') c.name.should eq 'Content-Disposition' c.value.should eq 'attachment; filename=File' end it "should accept a nil value and generate a disposition type" do c = Mail::ContentDispositionField.new(nil) c.name.should eq 'Content-Disposition' c.value.should_not be_nil end it "should render encoded" do c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=File') c.encoded.should eq "Content-Disposition: attachment;\r\n\sfilename=File\r\n" end it "should render encoded for inline" do c = Mail::ContentDispositionField.new('Content-Disposition: inline') c.encoded.should eq "Content-Disposition: inline\r\n" end it "should wrap a filename in double quotation marks only if the filename contains spaces and does not already have double quotation marks" do c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=This is a bad filename.txt') c.value.should eq 'attachment; filename="This is a bad filename.txt"' c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=some.jpg') c.value.should eq 'attachment; filename=some.jpg' c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename="Bad filename but at least it is wrapped in quotes.txt"') c.value.should eq 'attachment; filename="Bad filename but at least it is wrapped in quotes.txt"' end it "should render decoded" do c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=File') c.decoded.should eq 'attachment; filename=File' end it "should render decoded inline" do c = Mail::ContentDispositionField.new('Content-Disposition: inline') c.decoded.should eq 'inline' end it "should handle upper and mixed case INLINE and AttachMent" do c = Mail::ContentDispositionField.new('Content-Disposition: INLINE') c.decoded.should eq 'inline' c = Mail::ContentDispositionField.new('Content-Disposition: AttachMent') c.decoded.should eq 'attachment' end end describe "instance methods" do it "should give its disposition type" do c = Mail::ContentDispositionField.new('Content-Disposition: attachment; filename=File') c.disposition_type.should eq 'attachment' c.parameters.should eql({"filename" => 'File'}) end # see spec/fixtures/trec_2005_corpus/missing_content_disposition.eml it "should accept a blank disposition type" do c = Mail::ContentDispositionField.new('Content-Disposition: ') c.disposition_type.should_not be_nil end end end mail-2.5.4/spec/mail/fields/content_id_field_spec.rb000066400000000000000000000100121214434061600224110ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentIdField do # Content-ID Header Field # # In constructing a high-level user agent, it may be desirable to allow # one body to make reference to another. Accordingly, bodies may be # labelled using the "Content-ID" header field, which is syntactically # identical to the "Content-ID" header field: # # id := "Content-ID" ":" msg-id # # Like the Content-ID values, Content-ID values must be generated to be # world-unique. # # The Content-ID value may be used for uniquely identifying MIME # entities in several contexts, particularly for caching data # referenced by the message/external-body mechanism. Although the # Content-ID header is generally optional, its use is MANDATORY in # implementations which generate data of the optional MIME media type # "message/external-body". That is, each message/external-body entity # must have a Content-ID field to permit caching of such data. # # It is also worth noting that the Content-ID value has special # semantics in the case of the multipart/alternative media type. This # is explained in the section of RFC 2046 dealing with # multipart/alternative. describe "initialization" do it "should initialize" do doing { Mail::ContentIdField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do c = Mail::ContentIdField.new('Content-ID: <1234@test.lindsaar.net>') c.name.should eq 'Content-ID' c.value.should eq '<1234@test.lindsaar.net>' c.content_id.should eq '1234@test.lindsaar.net' end it "should accept a string without the field name" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.name.should eq 'Content-ID' m.value.should eq '<1234@test.lindsaar.net>' m.content_id.should eq '1234@test.lindsaar.net' end it "should accept a nil value and generate a content_id" do m = Mail::ContentIdField.new(nil) m.name.should eq 'Content-ID' m.value.should_not be_nil end it "should allow it to be encoded" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.encoded.should eq "Content-ID: <1234@test.lindsaar.net>\r\n" end it "should allow it to be decoded" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.decoded.should eq "<1234@test.lindsaar.net>" end end describe "ensuring only one message ID" do it "should not accept a string with multiple message IDs but only return the first" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net> <4567@test.lindsaar.net>') m.name.should eq 'Content-ID' m.to_s.should eq '<1234@test.lindsaar.net>' m.content_id.should eq '1234@test.lindsaar.net' end it "should change the message id if given a new message id" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.to_s.should eq '<1234@test.lindsaar.net>' m.value = '<4567@test.lindsaar.net>' m.to_s.should eq '<4567@test.lindsaar.net>' end end describe "instance methods" do it "should provide to_s" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.to_s.should eq '<1234@test.lindsaar.net>' m.content_id.to_s.should eq '1234@test.lindsaar.net' end it "should provide encoded" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.encoded.should eq "Content-ID: <1234@test.lindsaar.net>\r\n" end it "should respond to :responsible_for?" do m = Mail::ContentIdField.new('<1234@test.lindsaar.net>') m.should respond_to(:responsible_for?) end end describe "generating a message id" do it "should generate a message ID if it has no value" do m = Mail::ContentIdField.new m.content_id.should_not be_blank end it "should generate a random message ID" do m = Mail::ContentIdField.new 1.upto(100) do m.content_id.should_not == Mail::ContentIdField.new.content_id end end end end mail-2.5.4/spec/mail/fields/content_location_field_spec.rb000066400000000000000000000023241214434061600236340ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentLocationField do # Content-Location Header Field # describe "initialization" do it "should initialize" do doing { Mail::ContentLocationField.new("Content-Location", "7bit") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::ContentLocationField.new('Content-Location: photo.jpg') t.name.should eq 'Content-Location' t.value.should eq 'photo.jpg' end it "should accept a string without the field name" do t = Mail::ContentLocationField.new('photo.jpg') t.name.should eq 'Content-Location' t.value.should eq 'photo.jpg' end it "should render an encoded field" do t = Mail::ContentLocationField.new('photo.jpg') t.encoded.should eq "Content-Location: photo.jpg\r\n" end it "should render a decoded field" do t = Mail::ContentLocationField.new('photo.jpg') t.decoded.should eq 'photo.jpg' end end describe "parsing the value" do it "should return an encoding string unquoted" do t = Mail::ContentLocationField.new('"A quoted filename.jpg"') t.location.should eq 'A quoted filename.jpg' end end end mail-2.5.4/spec/mail/fields/content_transfer_encoding_field_spec.rb000066400000000000000000000107231214434061600255200ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentTransferEncodingField do # Content-Transfer-Encoding Header Field # # Many media types which could be usefully transported via email are # represented, in their "natural" format, as 8bit character or binary # data. Such data cannot be transmitted over some transfer protocols. # For example, RFC 821 (SMTP) restricts mail messages to 7bit US-ASCII # data with lines no longer than 1000 characters including any trailing # CRLF line separator. # # It is necessary, therefore, to define a standard mechanism for # encoding such data into a 7bit short line format. Proper labelling # of unencoded material in less restrictive formats for direct use over # less restrictive transports is also desireable. This document # specifies that such encodings will be indicated by a new "Content- # Transfer-Encoding" header field. This field has not been defined by # any previous standard. # # 6.1. Content-Transfer-Encoding Syntax # # The Content-Transfer-Encoding field's value is a single token # specifying the type of encoding, as enumerated below. Formally: # # encoding := "Content-Transfer-Encoding" ":" mechanism # # mechanism := "7bit" / "8bit" / "binary" / # "quoted-printable" / "base64" / # ietf-token / x-token # # These values are not case sensitive -- Base64 and BASE64 and bAsE64 # are all equivalent. An encoding type of 7BIT requires that the body # # is already in a 7bit mail-ready representation. This is the default # value -- that is, "Content-Transfer-Encoding: 7BIT" is assumed if the # Content-Transfer-Encoding header field is not present. # describe "initialization" do it "should initialize" do doing { Mail::ContentTransferEncodingField.new("Content-Transfer-Encoding: 7bit") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::ContentTransferEncodingField.new('Content-Transfer-Encoding: 7bit') t.name.should eq 'Content-Transfer-Encoding' t.value.should eq '7bit' end it "should accept a string without the field name" do t = Mail::ContentTransferEncodingField.new('7bit') t.name.should eq 'Content-Transfer-Encoding' t.value.should eq '7bit' end it "should render an encoded field" do t = Mail::ContentTransferEncodingField.new('7bit') t.encoded.should eq "Content-Transfer-Encoding: 7bit\r\n" end it "should render a decoded field" do t = Mail::ContentTransferEncodingField.new('7bit') t.decoded.should eq '7bit' end end describe "parsing the value" do it "should return an encoding string" do ["7bit", "8bit", "binary", 'quoted-printable', "base64"].each do |encoding| t = Mail::ContentTransferEncodingField.new(encoding) t.encoding.should eq encoding end end it "should treat 7bits/7-bit and 8bits/8-bit as 7bit and 8bit" do %w(7bits 7-bit).each do |mechanism| Mail::ContentTransferEncodingField.new(mechanism).encoding.should eq '7bit' end %w(8bits 8-bit).each do |mechanism| Mail::ContentTransferEncodingField.new(mechanism).encoding.should eq '8bit' end end it "should handle any valid 'x-token' value" do t = Mail::ContentTransferEncodingField.new('X-This-is_MY-encoding') t.encoding.should eq 'x-this-is_my-encoding' end it "should handle an x-encoding" do t = Mail::ContentTransferEncodingField.new("x-uuencode") t.encoding.should eq "x-uuencode" end it "should handle an ietf encoding (practically, any token)" do t = Mail::ContentTransferEncodingField.new("ietf-token") t.encoding.should eq "ietf-token" end it "should replace the existing value" do t = Mail::ContentTransferEncodingField.new("7bit") t.parse("quoted-printable") t.encoding.should eq 'quoted-printable' end it "should raise an error on bogus values" do doing { Mail::ContentTransferEncodingField.new("broken@foo") }.should raise_error end it "should handle an empty content transfer encoding" do t = Mail::ContentTransferEncodingField.new("") t.encoding.should eq "" end it "should handle a hyphen" do t = Mail::ContentTransferEncodingField.new('7-bit') t.decoded.should eq '7bit' t = Mail::ContentTransferEncodingField.new('8-bit') t.decoded.should eq '8bit' end end end mail-2.5.4/spec/mail/fields/content_type_field_spec.rb000066400000000000000000000745121214434061600230150ustar00rootroot00000000000000require 'spec_helper' describe Mail::ContentTypeField do # Content-Type Header Field # # The purpose of the Content-Type field is to describe the data # contained in the body fully enough that the receiving user agent can # pick an appropriate agent or mechanism to present the data to the # user, or otherwise deal with the data in an appropriate manner. The # value in this field is called a media type. # # HISTORICAL NOTE: The Content-Type header field was first defined in # RFC 1049. RFC 1049 used a simpler and less powerful syntax, but one # that is largely compatible with the mechanism given here. # # The Content-Type header field specifies the nature of the data in the # body of an entity by giving media type and subtype identifiers, and # by providing auxiliary information that may be required for certain # media types. After the media type and subtype names, the remainder # of the header field is simply a set of parameters, specified in an # attribute=value notation. The ordering of parameters is not # significant. # # In general, the top-level media type is used to declare the general # type of data, while the subtype specifies a specific format for that # type of data. Thus, a media type of "image/xyz" is enough to tell a # user agent that the data is an image, even if the user agent has no # knowledge of the specific image format "xyz". Such information can # be used, for example, to decide whether or not to show a user the raw # data from an unrecognized subtype -- such an action might be # reasonable for unrecognized subtypes of text, but not for # unrecognized subtypes of image or audio. For this reason, registered # subtypes of text, image, audio, and video should not contain embedded # information that is really of a different type. Such compound # formats should be represented using the "multipart" or "application" # types. # # Parameters are modifiers of the media subtype, and as such do not # fundamentally affect the nature of the content. The set of # meaningful parameters depends on the media type and subtype. Most # parameters are associated with a single specific subtype. However, a # given top-level media type may define parameters which are applicable # to any subtype of that type. Parameters may be required by their # defining content type or subtype or they may be optional. MIME # implementations must ignore any parameters whose names they do not # recognize. # # For example, the "charset" parameter is applicable to any subtype of # "text", while the "boundary" parameter is required for any subtype of # the "multipart" media type. # # There are NO globally-meaningful parameters that apply to all media # types. Truly global mechanisms are best addressed, in the MIME # model, by the definition of additional Content-* header fields. # # An initial set of seven top-level media types is defined in RFC 2046. # Five of these are discrete types whose content is essentially opaque # as far as MIME processing is concerned. The remaining two are # composite types whose contents require additional handling by MIME # processors. # # This set of top-level media types is intended to be substantially # complete. It is expected that additions to the larger set of # supported types can generally be accomplished by the creation of new # subtypes of these initial types. In the future, more top-level types # may be defined only by a standards-track extension to this standard. # If another top-level type is to be used for any reason, it must be # given a name starting with "X-" to indicate its non-standard status # and to avoid a potential conflict with a future official name. # describe "initialization" do it "should initialize" do doing { Mail::ContentTypeField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do c = Mail::ContentTypeField.new('Content-Type: text/plain') c.name.should eq 'Content-Type' c.value.should eq 'text/plain' end it "should accept a string without the field name" do c = Mail::ContentTypeField.new('text/plain') c.name.should eq 'Content-Type' c.value.should eq 'text/plain' end it "should accept a nil value and generate a content_type" do c = Mail::ContentTypeField.new('Content-Type', nil) c.name.should eq 'Content-Type' c.value.should_not be_nil end it "should render encoded" do c = Mail::ContentTypeField.new('Content-Type: text/plain') c.encoded.should eq "Content-Type: text/plain\r\n" end it "should render encoded with parameters" do c = Mail::ContentTypeField.new('text/plain; charset=US-ASCII; format=flowed') c.encoded.should eq %Q{Content-Type: text/plain;\r\n\scharset=US-ASCII;\r\n\sformat=flowed\r\n} end it "should render quoted values encoded" do c = Mail::ContentTypeField.new('text/plain; example="foo bar"') c.encoded.should eq %Q{Content-Type: text/plain;\r\n\sexample="foo bar"\r\n} end it "should render decoded" do c = Mail::ContentTypeField.new('text/plain; charset=US-ASCII; format=flowed') c.decoded.should eq 'text/plain; charset=US-ASCII; format=flowed' end it "should render quoted values decoded" do c = Mail::ContentTypeField.new('text/plain; example="foo bar"') c.decoded.should eq 'text/plain; example="foo bar"' end it "should render " do c = Mail::ContentTypeField.new('message/delivery-status') c.main_type.should eq 'message' c.sub_type.should eq 'delivery-status' end it "should wrap a filename in double quotation marks only if the filename contains spaces and does not already have double quotation marks" do c = Mail::ContentTypeField.new('text/plain; name=This is a bad filename.txt') c.value.should eq 'text/plain; name="This is a bad filename.txt"' c = Mail::ContentTypeField.new('image/jpg; name=some.jpg; size=100') c.value.should eq 'image/jpg; name=some.jpg; size=100' c = Mail::ContentTypeField.new('text/plain; name="Bad filename but at least it is wrapped in quotes.txt"') c.value.should eq 'text/plain; name="Bad filename but at least it is wrapped in quotes.txt"' end it "should only wrap filenames in double quotation marks" do c = Mail::ContentTypeField.new("image/jpg;\r\n\sname=some .jpg\r\n\ssize=100") c.value.should eq %Q{image/jpg;\r\n\sname="some .jpg"\r\n\ssize=100} end end describe "instance methods" do it "should return a content_type" do c = Mail::ContentTypeField.new('text/plain') c.content_type.should eq 'text/plain' end it "should return a content_type for the :string method" do c = Mail::ContentTypeField.new('text/plain') c.string.should eq 'text/plain' end it "should return a main_type" do c = Mail::ContentTypeField.new('text/plain') c.main_type.should eq 'text' end it "should return a sub_type" do c = Mail::ContentTypeField.new('text/plain') c.main_type.should eq 'text' end it "should return a parameter as a hash" do c = Mail::ContentTypeField.new('text/plain; charset=US-ASCII') c.parameters.should eql({"charset" => 'US-ASCII'}) end it "should return multiple parameters as a hash" do c = Mail::ContentTypeField.new('text/plain; charset=US-ASCII; format=flowed') c.parameters.should eql({"charset" => 'US-ASCII', "format" => 'flowed'}) end it "should return boundry parameters" do c = Mail::ContentTypeField.new('multipart/mixed; boundary=Apple-Mail-13-196941151') c.parameters.should eql({"boundary" => 'Apple-Mail-13-196941151'}) end it "should be indifferent with the access" do c = Mail::ContentTypeField.new('multipart/mixed; boundary=Apple') c.parameters[:boundary].should eq "Apple" c.parameters['boundary'].should eq "Apple" end end describe "class methods" do it "should give back an initialized instance with a unique boundary" do boundary = Mail::ContentTypeField.with_boundary('multipart/mixed') boundary.encoded.should =~ %r{Content-Type: multipart/mixed;\r\n\sboundary="--==_mimepart_[\w]+_[\w]+"\r\n} end it "should give back an initialized instance with different type with a unique boundary" do boundary = Mail::ContentTypeField.with_boundary('multipart/alternative') boundary.encoded.should =~ %r{Content-Type: multipart/alternative;\r\n\sboundary="--==_mimepart_[\w]+_[\w]+"\r\n} end it "should give unique boundaries" do boundary1 = Mail::ContentTypeField.with_boundary('multipart/alternative').parameters['boundary'] 0.upto(250) do boundary2 = Mail::ContentTypeField.with_boundary('multipart/alternative').parameters['boundary'] boundary1.should_not == boundary2 end end end describe "Testing a bunch of email Content-Type fields" do it "should handle 'application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3'" do string = %q{application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/octet-stream' c.main_type.should eq 'application' c.sub_type.should eq 'octet-stream' c.parameters.should eql({'name*' => "iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3"}) end it "should handle 'application/pdf;'" do string = %q{application/pdf;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/pdf' c.main_type.should eq 'application' c.sub_type.should eq 'pdf' c.parameters.should eql({}) end it "should handle 'application/pdf; name=\"broken.pdf\"'" do string = %q{application/pdf; name="broken.pdf"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/pdf' c.main_type.should eq 'application' c.sub_type.should eq 'pdf' c.parameters.should eql({"name" => "broken.pdf"}) end it "should handle 'application/pkcs7-signature;'" do string = %q{application/pkcs7-signature;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/pkcs7-signature' c.main_type.should eq 'application' c.sub_type.should eq 'pkcs7-signature' c.parameters.should eql({}) end it "should handle 'application/pkcs7-signature; name=smime.p7s'" do string = %q{application/pkcs7-signature; name=smime.p7s} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/pkcs7-signature' c.main_type.should eq 'application' c.sub_type.should eq 'pkcs7-signature' c.parameters.should eql({"name" => "smime.p7s"}) end it "should handle 'application/x-gzip; NAME=blah.gz'" do string = %q{application/x-gzip; NAME=blah.gz} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'application/x-gzip' c.main_type.should eq 'application' c.sub_type.should eq 'x-gzip' c.parameters.should eql({"NAME" => "blah.gz"}) end it "should handle 'image/jpeg'" do string = %q{image/jpeg} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'image/jpeg' c.main_type.should eq 'image' c.sub_type.should eq 'jpeg' c.parameters.should eql({}) end it "should handle 'image/jpeg'" do string = %q{image/jpeg} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'image/jpeg' c.main_type.should eq 'image' c.sub_type.should eq 'jpeg' c.parameters.should eql({}) end it "should handle 'image/jpeg;'" do string = %q{image/jpeg} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'image/jpeg' c.main_type.should eq 'image' c.sub_type.should eq 'jpeg' c.parameters.should eql({}) end it "should handle 'image/png;'" do string = %q{image/png} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'image/png' c.main_type.should eq 'image' c.sub_type.should eq 'png' c.parameters.should eql({}) end it "should handle 'message/delivery-status'" do string = %q{message/delivery-status} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'message/delivery-status' c.main_type.should eq 'message' c.sub_type.should eq 'delivery-status' c.parameters.should eql({}) end it "should handle 'message/rfc822'" do string = %q{message/rfc822} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'message/rfc822' c.main_type.should eq 'message' c.sub_type.should eq 'rfc822' c.parameters.should eql({}) end it "should handle 'multipart/alternative;'" do string = %q{multipart/alternative;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({}) end it "should handle 'multipart/alternative; boundary=\"----=_NextPart_000_0093_01C81419.EB75E850\"'" do string = %q{multipart/alternative; boundary="----=_NextPart_000_0093_01C81419.EB75E850"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" =>"----=_NextPart_000_0093_01C81419.EB75E850"}) end it "should handle 'multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850'" do string = %q{multipart/alternative; boundary="----=_NextPart_000_0093_01C81419.EB75E850"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" =>"----=_NextPart_000_0093_01C81419.EB75E850"}) end it "should handle 'Multipart/Alternative;boundary=MuLtIpArT_BoUnDaRy'" do string = %q{Multipart/Alternative; boundary=MuLtIpArT_BoUnDaRy} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" =>"MuLtIpArT_BoUnDaRy"}) end it "should handle 'Multipart/Alternative;boundary=MuLtIpArT_BoUnDaRy'" do string = %q{Multipart/Alternative;boundary=MuLtIpArT_BoUnDaRy} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" =>"MuLtIpArT_BoUnDaRy"}) end it %(should handle 'multipart/alternative; boundary="----jkhkjgyurlkmn789809";; charset="us-ascii"') do string = %(multipart/alternative; boundary="----jkhkjgyurlkmn789809";; charset="us-ascii") c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.parameters['boundary'].should == '----jkhkjgyurlkmn789809' end it "should handle 'multipart/mixed'" do string = %q{multipart/mixed} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/mixed' c.main_type.should eq 'multipart' c.sub_type.should eq 'mixed' c.parameters.should eql({}) end it "should handle 'multipart/mixed;'" do string = %q{multipart/mixed;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/mixed' c.main_type.should eq 'multipart' c.sub_type.should eq 'mixed' c.parameters.should eql({}) end it "should handle 'multipart/mixed; boundary=Apple-Mail-13-196941151'" do string = %q{multipart/mixed; boundary=Apple-Mail-13-196941151} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/mixed' c.main_type.should eq 'multipart' c.sub_type.should eq 'mixed' c.parameters.should eql({"boundary" => "Apple-Mail-13-196941151"}) end it "should handle 'multipart/mixed; boundary=mimepart_427e4cb4ca329_133ae40413c81ef'" do string = %q{multipart/mixed; boundary=mimepart_427e4cb4ca329_133ae40413c81ef} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/mixed' c.main_type.should eq 'multipart' c.sub_type.should eq 'mixed' c.parameters.should eql({"boundary" => "mimepart_427e4cb4ca329_133ae40413c81ef"}) end it "should handle 'multipart/report; report-type=delivery-status;'" do string = %q{multipart/report; report-type=delivery-status;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/report' c.main_type.should eq 'multipart' c.sub_type.should eq 'report' c.parameters.should eql({"report-type" => "delivery-status"}) end it "should handle 'multipart/signed;'" do string = %q{multipart/signed;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/signed' c.main_type.should eq 'multipart' c.sub_type.should eq 'signed' c.parameters.should eql({}) end it "should handle 'text/enriched;'" do string = %q{text/enriched;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/enriched' c.main_type.should eq 'text' c.sub_type.should eq 'enriched' c.parameters.should eql({}) end it "should handle 'text/html;'" do string = %q{text/html;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/html' c.main_type.should eq 'text' c.sub_type.should eq 'html' c.parameters.should eql({}) end it "should handle 'text/html; charset=iso-8859-1;'" do string = %q{text/html; charset=iso-8859-1;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/html' c.main_type.should eq 'text' c.sub_type.should eq 'html' c.parameters.should eql({"charset" => 'iso-8859-1'}) end it "should handle 'TEXT/PLAIN; charset=ISO-8859-1;'" do string = %q{TEXT/PLAIN; charset=ISO-8859-1;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'ISO-8859-1'}) end it "should handle 'text/plain'" do string = %q{text/plain} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({}) end it "should handle 'text/plain;'" do string = %q{text/plain;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({}) end it "should handle 'text/plain; charset=ISO-8859-1'" do string = %q{text/plain; charset=ISO-8859-1} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'ISO-8859-1'}) end it "should handle 'text/plain; charset=ISO-8859-1;'" do string = %q{text/plain; charset=ISO-8859-1; format=flowed} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'ISO-8859-1', "format" => 'flowed'}) end it "should handle 'text/plain; charset=us-ascii;'" do string = %q{text/plain; charset=us-ascii} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'us-ascii'}) end it "should handle 'text/plain; charset=US-ASCII; format=flowed'" do string = %q{text/plain; charset=US-ASCII; format=flowed} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'US-ASCII', "format" => 'flowed'}) end it "should handle 'text/plain; charset=US-ASCII; format=flowed'" do string = %q{text/plain; charset=US-ASCII; format=flowed} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'US-ASCII', "format" => 'flowed'}) end it "should handle 'text/plain; charset=utf-8'" do string = %q{text/plain; charset=utf-8} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'utf-8'}) end it "should handle 'text/plain; charset=utf-8'" do string = %q{text/plain; charset=X-UNKNOWN} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/plain' c.main_type.should eq 'text' c.sub_type.should eq 'plain' c.parameters.should eql({"charset" => 'X-UNKNOWN'}) end it "should handle 'text/x-ruby-script;'" do string = %q{text/x-ruby-script;} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/x-ruby-script' c.main_type.should eq 'text' c.sub_type.should eq 'x-ruby-script' c.parameters.should eql({}) end it "should handle 'text/x-ruby-script; name=\"hello.rb\"'" do string = %q{text/x-ruby-script; name="hello.rb"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'text/x-ruby-script' c.main_type.should eq 'text' c.sub_type.should eq 'x-ruby-script' c.parameters.should eql({"name" => 'hello.rb'}) end it "should handle 'multipart/mixed; boundary=\"=_NextPart_Lycos_15031600484464_ID\"" do string = %q{multipart/mixed; boundary="=_NextPart_Lycos_15031600484464_ID"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/mixed' c.main_type.should eq 'multipart' c.sub_type.should eq 'mixed' c.parameters.should eql({"boundary" => '=_NextPart_Lycos_15031600484464_ID'}) end it "should handle 'multipart/alternative; boundary=----=_=NextPart_000_0093_01C81419.EB75E850" do string = %q{multipart/alternative; boundary=----=_=NextPart_000_0093_01C81419.EB75E850} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" => '----=_=NextPart_000_0093_01C81419.EB75E850'}) end it "should handle 'multipart/alternative; boundary=\"----=_=NextPart_000_0093_01C81419.EB75E850\"" do string = %q{multipart/alternative; boundary="----=_=NextPart_000_0093_01C81419.EB75E850"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/alternative' c.main_type.should eq 'multipart' c.sub_type.should eq 'alternative' c.parameters.should eql({"boundary" => '----=_=NextPart_000_0093_01C81419.EB75E850'}) end it "should handle 'multipart/related;boundary=1_4626B816_9F1690;Type=\"application/smil\";Start=\"\"'" do string = %q{multipart/related;boundary=1_4626B816_9F1690;Type="application/smil";Start=""} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'multipart/related' c.main_type.should eq 'multipart' c.sub_type.should eq 'related' c.parameters.should eql({"boundary" => '1_4626B816_9F1690', "Type" => 'application/smil', "Start" => ''}) end it "should handle 'IMAGE/JPEG; name=\"IM 006.jpg\"'" do string = %q{IMAGE/JPEG; name="IM 006.jpg"} c = Mail::ContentTypeField.new(string) c.content_type.should eq 'image/jpeg' c.main_type.should eq 'image' c.sub_type.should eq 'jpeg' c.parameters.should eql({"name" => "IM 006.jpg"}) end it "should handle 'unknown/unknown'" do string = %(unknown/unknown; charset=iso-8859-1; name=IMSTP19.gif) c = Mail::ContentTypeField.new(string) c.content_type.should eq 'unknown/unknown' c.main_type.should eq 'unknown' c.sub_type.should eq 'unknown' c.parameters.should eql('charset' => 'iso-8859-1', 'name' => 'IMSTP19.gif') end end describe "finding a filename" do it "should locate a filename if there is a filename" do string = %q{application/octet-stream; filename=mikel.jpg} c = Mail::ContentTypeField.new(string) c.filename.should eq 'mikel.jpg' end it "should locate a name if there is no filename" do string = %q{application/octet-stream; name=mikel.jpg} c = Mail::ContentTypeField.new(string) c.filename.should eq 'mikel.jpg' end it "should locate an encoded name as a filename" do string = %q{application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%91at.%20Pitbull.mp3} c = Mail::ContentTypeField.new(string) if RUBY_VERSION >= '1.9' expected = "01 Quien Te Dij\221at. Pitbull.mp3".force_encoding(Encoding::BINARY) result = c.filename.force_encoding(Encoding::BINARY) else expected = "01 Quien Te Dij\221at. Pitbull.mp3" result = c.filename end expected.should eq result end it "should encode a non us-ascii filename" do @original = $KCODE if RUBY_VERSION < '1.9' Mail.defaults do param_encode_language('jp') end c = Mail::ContentTypeField.new('application/octet-stream') string = "01 Quien Te Dij\221at. Pitbull.mp3" case when RUBY_VERSION >= '1.9.3' string.force_encoding('SJIS') result = %Q{Content-Type: application/octet-stream;\r\n\sfilename*=windows-31j'jp'01%20Quien%20Te%20Dij%91%61t.%20Pitbull.mp3\r\n} when RUBY_VERSION >= '1.9' string.force_encoding('SJIS') result = %Q{Content-Type: application/octet-stream;\r\n\sfilename*=shift_jis'jp'01%20Quien%20Te%20Dij%91%61t.%20Pitbull.mp3\r\n} else $KCODE = 'SJIS' result = %Q{Content-Type: application/octet-stream;\r\n\sfilename*=sjis'jp'01%20Quien%20Te%20Dij%91at.%20Pitbull.mp3\r\n} end c.filename = string c.parameters.should eql({"filename" => string}) c.encoded.should eq result $KCODE = @original if RUBY_VERSION < '1.9' end end describe "handling badly formated content-type fields" do it "should handle missing sub-type on a text content type" do c = Mail::ContentTypeField.new('Content-Type: text') c.content_type.should eq 'text/plain' end it "should handle missing ; after content-type" do c = Mail::ContentTypeField.new('Content-Type: multipart/mixed boundary="----=_NextPart_000_000F_01C17754.8C3CAF30"') c.content_type.should eq 'multipart/mixed' c.parameters['boundary'].should eq '----=_NextPart_000_000F_01C17754.8C3CAF30' end end describe "initializing with an array" do it "should initialize with an array" do c = Mail::ContentTypeField.new(['text', 'html', {'charset' => 'UTF-8'}]) c.content_type.should eq 'text/html' c.parameters['charset'].should eq 'UTF-8' end it "should allow many parameters to be passed in" do c = Mail::ContentTypeField.new(['text', 'html', {"format"=>"flowed", "charset"=>"utf-8"}]) c.content_type.should eq 'text/html' c.parameters['charset'].should eq 'utf-8' c.parameters['format'].should eq 'flowed' end end describe "special case values needing sanity" do it "should handle 'text/plain;ISO-8559-1'" do c = Mail::ContentTypeField.new('text/plain;ISO-8559-1') c.string.should eq 'text/plain' c.parameters['charset'].should eq 'iso-8559-1' end it "should handle 'text/plain; charset = \"iso-8859-1\"'" do c = Mail::ContentTypeField.new('text/plain; charset = "iso-8859-1"') c.string.should eq 'text/plain' c.parameters['charset'].should eq 'iso-8859-1' end it "should handle text; params" do c = Mail::ContentTypeField.new('text; charset=utf-8') c.string.should eq 'text/plain' c.parameters['charset'].should eq 'utf-8' end it 'should handle text/html; charset="charset="GB2312""' do c = Mail::ContentTypeField.new('text/html; charset="charset="GB2312""') c.string.should eq 'text/html' c.parameters['charset'].should eq 'gb2312' end it "should handle application/octet-stream; name=archiveshelp1[1].htm" do c = Mail::ContentTypeField.new('application/octet-stream; name=archiveshelp1[1].htm') c.string.should eq 'application/octet-stream' c.parameters['name'].should eq 'archiveshelp1[1].htm' end it 'should handle text/plain;; format="flowed"' do c = Mail::ContentTypeField.new('text/plain;; format="flowed"') c.string.should eq 'text/plain' c.parameters['format'].should eq 'flowed' end it 'set an empty content type to text/plain' do c = Mail::ContentTypeField.new('') c.string.should eq 'text/plain' end it "should just ignore illegal params like audio/x-midi;\r\n\sname=Part .exe" do c = Mail::ContentTypeField.new("audio/x-midi;\r\n\sname=Part .exe") c.string.should eq 'audio/x-midi' c.parameters['name'].should eq nil end it "should handle: rfc822; format=flowed; charset=iso-8859-15" do c = Mail::ContentTypeField.new("rfc822; format=flowed; charset=iso-8859-15") c.string.should eq 'text/plain' c.parameters['format'].should eq 'flowed' c.parameters['charset'].should eq 'iso-8859-15' end it "should just get the mime type if all else fails with some real garbage" do c = Mail::ContentTypeField.new("text/html; format=flowed; charset=iso-8859-15 Mime-Version: 1.0") c.string.should eq 'text/html' end it "shouldn't include separating semicolon in parameter value when sanitizing" do c = Mail::ContentTypeField.new(%Q{Multipart/Related;boundary=boundary123?WUT; type="application/xml";}) c.parameters['boundary'].should eq 'boundary123?WUT' end end end mail-2.5.4/spec/mail/fields/date_field_spec.rb000066400000000000000000000060371214434061600212140ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::DateField do # The origination date field consists of the field name "Date" followed # by a date-time specification. # # orig-date = "Date:" date-time CRLF # # The origination date specifies the date and time at which the creator # of the message indicated that the message was complete and ready to # enter the mail delivery system. For instance, this might be the time # that a user pushes the "send" or "submit" button in an application # program. In any case, it is specifically not intended to convey the # time that the message is actually transported, but rather the time at # which the human or other creator of the message has put the message # into its final form, ready for transport. (For example, a portable # computer user who is not connected to a network might queue a message # for delivery. The origination date is intended to contain the date # and time that the user queued the message, not the time when the user # connected to the network to send the message.) describe "initialization" do it "should initialize" do doing { Mail::DateField.new("12 Aug 2009 00:00:02 GMT") }.should_not raise_error end it "should be able to tell the time" do Mail::DateField.new("12 Aug 2009 00:00:02 GMT").date_time.class.should eq DateTime end it "should mix in the CommonAddress module" do Mail::DateField.included_modules.should include(Mail::CommonDate) end it "should accept a string with the field name" do t = Mail::DateField.new('Date: 12 Aug 2009 00:00:02 GMT') t.name.should eq 'Date' t.value.should eq 'Wed, 12 Aug 2009 00:00:02 +0000' t.date_time.should eq ::DateTime.parse('12 Aug 2009 00:00:02 GMT') end it "should accept a string without the field name" do t = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') t.name.should eq 'Date' t.value.should eq 'Wed, 12 Aug 2009 00:00:02 +0000' t.date_time.should eq ::DateTime.parse('12 Aug 2009 00:00:02 GMT') end it "should accept nil as a value" do t = Mail::DateField.new(nil) t.date_time.should_not be_nil end it "should allow us to encode an date field" do field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') field.encoded.should eq "Date: Wed, 12 Aug 2009 00:00:02 +0000\r\n" end it "should allow us to decode an address field" do field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') field.decoded.should eq "Wed, 12 Aug 2009 00:00:02 +0000" end it "should be able to parse a really bad spacing example" do field = Mail::DateField.new("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") field.decoded.should eq "Fri, 21 Nov 1997 09:55:06 -0600" end it "should give today's date if no date is specified" do now = Time.now Time.stub!(:now).and_return(now) Mail::DateField.new.date_time.should eq ::DateTime.parse(now.to_s) end end end mail-2.5.4/spec/mail/fields/envelope_spec.rb000066400000000000000000000027631214434061600207530ustar00rootroot00000000000000require 'spec_helper' describe Mail::Envelope do # From RFC4155 The application/mbox Media Type # # o Each message in the mbox database MUST be immediately preceded # by a single separator line, which MUST conform to the following # syntax: # # The exact character sequence of "From"; # # a single Space character (0x20); # # the email address of the message sender (as obtained from the # message envelope or other authoritative source), conformant # with the "addr-spec" syntax from RFC 2822; # # a single Space character; # # a timestamp indicating the UTC date and time when the message # was originally received, conformant with the syntax of the # traditional UNIX 'ctime' output sans timezone (note that the # use of UTC precludes the need for a timezone indicator); # # an end-of-line marker. it "should initialize" do doing { Mail::Envelope.new('mikel@test.lindsaar.net Mon May 2 16:07:05 2005') }.should_not raise_error end describe "accessor methods" do it "should return the address" do envelope = Mail::Envelope.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") envelope.from.should eq "mikel@test.lindsaar.net" end it "should return the date_time" do envelope = Mail::Envelope.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") envelope.date.should eq ::DateTime.parse("Mon Aug 17 00:39:21 2009") end end end mail-2.5.4/spec/mail/fields/from_field_spec.rb000066400000000000000000000063271214434061600212440ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # from = "From:" mailbox-list CRLF describe Mail::FromField do describe "initialization" do it "should initialize" do doing { Mail::FromField.new("From: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::FromField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::FromField.new('From: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'From' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::FromField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'From' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oFromurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::FromField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::FromField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::FromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::FromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::FromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "From: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end it "should return the encoded line" do t = Mail::FromField.new("bob@me.com") t.encoded.should eq "From: bob@me.com\r\n" end it "should return the decoded line" do t = Mail::FromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.decoded.should eq "sam@me.com, my_group: mikel@me.com, bob@you.com;" end end it "should handle non ascii" do t = Mail::FromField.new('"Foo áëô îü" ') t.decoded.should eq '"Foo áëô îü" ' t.encoded.should eq "From: =?UTF-8?B?Rm9vIMOhw6vDtCDDrsO8?= \r\n" end it "should work without quotes" do t = Mail::FromField.new('Foo áëô îü ') t.encoded.should eq "From: Foo =?UTF-8?B?w6HDq8O0?= =?UTF-8?B?IMOuw7w=?= \r\n" t.decoded.should eq '"Foo áëô îü" ' end end mail-2.5.4/spec/mail/fields/in_reply_to_field_spec.rb000066400000000000000000000076351214434061600226270ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # The "In-Reply-To:" field will contain the contents of the "Message- # ID:" field of the message to which this one is a reply (the "parent # message"). If there is more than one parent message, then the "In- # Reply-To:" field will contain the contents of all of the parents' # "Message-ID:" fields. If there is no "Message-ID:" field in any of # the parent messages, then the new message will have no "In-Reply-To:" # field. describe Mail::InReplyToField do describe "initialization" do it "should initialize" do doing { Mail::InReplyToField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::InReplyToField.new('In-Reply-To: <1234@test.lindsaar.net>') t.name.should eq 'In-Reply-To' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should accept a string without the field name" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net>') t.name.should eq 'In-Reply-To' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should provide encoded" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net>') t.encoded.should eq "In-Reply-To: <1234@test.lindsaar.net>\r\n" end it "should handle many encoded message IDs" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net> <4567@test.lindsaar.net>') t.encoded.should eq "In-Reply-To: <1234@test.lindsaar.net>\r\n <4567@test.lindsaar.net>\r\n" end it "should handle an array of message IDs" do t = Mail::InReplyToField.new(['<1234@test.lindsaar.net>', '<4567@test.lindsaar.net>']) t.encoded.should eq "In-Reply-To: <1234@test.lindsaar.net>\r\n <4567@test.lindsaar.net>\r\n" end it "should provide decoded" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net>') t.decoded.should eq "<1234@test.lindsaar.net>" end it "should handle many decoded message IDs" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net> <4567@test.lindsaar.net>') t.decoded.should eq '<1234@test.lindsaar.net> <4567@test.lindsaar.net>' end it "should handle an empty value" do t = Mail::InReplyToField.new('') t.name.should eq 'In-Reply-To' t.decoded.should eq nil end end describe "handlign multiple message ids" do it "should handle many message IDs" do t = Mail::InReplyToField.new('<1234@test.lindsaar.net> <4567@test.lindsaar.net>') t.name.should eq 'In-Reply-To' t.message_ids.should eq ['1234@test.lindsaar.net', '4567@test.lindsaar.net'] end end it "should output lines shorter than 998 chars" do k = Mail::InReplyToField.new(' ') lines = k.encoded.split("\r\n\s") lines.each { |line| line.length.should < 998 } end end mail-2.5.4/spec/mail/fields/keywords_field_spec.rb000066400000000000000000000066361214434061600221530ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::KeywordsField do describe "initializing" do it "should initialize" do doing { Mail::KeywordsField.new("this, is, email") }.should_not raise_error end it "should accept a string with the field name" do k = Mail::KeywordsField.new('Keywords: these are keywords, so there') k.name.should eq 'Keywords' k.value.should eq 'these are keywords, so there' end it "should accept a string with the field name" do k = Mail::KeywordsField.new('these are keywords, so there') k.name.should eq 'Keywords' k.value.should eq 'these are keywords, so there' end end describe "giving a list of keywords" do it "should return a list of keywords" do k = Mail::KeywordsField.new('these are keywords, so there') k.keywords.should eq ['these are keywords', 'so there'] end it "should handle phrases" do k = Mail::KeywordsField.new('"these, are keywords", so there') k.keywords.should eq ['these, are keywords', 'so there'] end it "should handle comments" do k = Mail::KeywordsField.new('"these, are keywords", so there (This is an irrelevant comment)') k.keywords.should eq ['these, are keywords', 'so there (This is an irrelevant comment)'] end it "should handle comments" do k = Mail::KeywordsField.new('"these, are keywords", so there (This is an irrelevant comment)') k.keywords.should eq ['these, are keywords', 'so there (This is an irrelevant comment)'] end it "should handle comments in quotes" do k = Mail::KeywordsField.new('"these, are keywords (another comment to be ignored)", so there (This is an irrelevant comment)') k.keywords.should eq ['these, are keywords (another comment to be ignored)', 'so there (This is an irrelevant comment)'] end end describe "encoding and decoding" do it "should encode" do k = Mail::KeywordsField.new('these are keywords, so there') k.encoded.should eq "Keywords: these are keywords,\r\n so there\r\n" end it "should decode" do k = Mail::KeywordsField.new('these are keywords, so there') k.decoded.should eq "these are keywords, so there" end end it "should output lines shorter than 998 chars" do k = Mail::KeywordsField.new('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed placerat euismod velit nec convallis. Cras bibendum mattis arcu a tincidunt. Nullam ac orci vitae massa elementum ultricies ultricies nec quam. Praesent eleifend viverra semper. Sed id ultricies ipsum. Pellentesque sed nunc mauris, at varius sem. Curabitur pretium pellentesque velit, eget pellentesque dolor interdum eget. Duis ac lectus nec arcu pharetra lobortis. Integer risus felis, convallis ut feugiat quis, imperdiet ut sapien. Nullam imperdiet leo nec lectus imperdiet mollis. Proin nec lectus id erat pellentesque pretium vitae sit amet massa. Proin interdum pellentesque mi, at tristique sem facilisis ut. Donec enim mauris, viverra ut lacinia pharetra, elementum nec mi. Ut at interdum massa. Integer placerat tortor at tellus lobortis a mattis massa ultricies. Vivamus nec dolor at justo fringilla laoreet rhoncus fermentum lectus. Praesent tincidunt congue mauris vitae aliquam. Mauris arcu mauris, faucibus sed turpis duis.') lines = k.encoded.split("\r\n\s") lines.each { |line| line.length.should < 998 } end end mail-2.5.4/spec/mail/fields/message_id_field_spec.rb000066400000000000000000000131151214434061600223720ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # 3.6.4. Identification fields # # Though optional, every message SHOULD have a "Message-ID:" field. # Furthermore, reply messages SHOULD have "In-Reply-To:" and # "References:" fields as appropriate, as described below. # # The "Message-ID:" field contains a single unique message identifier. # The "References:" and "In-Reply-To:" field each contain one or more # unique message identifiers, optionally separated by CFWS. # # The message identifier (msg-id) is similar in syntax to an angle-addr # construct without the internal CFWS. # # message-id = "Message-ID:" msg-id CRLF # # in-reply-to = "In-Reply-To:" 1*msg-id CRLF # # references = "References:" 1*msg-id CRLF # # msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] # # id-left = dot-atom-text / no-fold-quote / obs-id-left # # id-right = dot-atom-text / no-fold-literal / obs-id-right # # no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE # # no-fold-literal = "[" *(dtext / quoted-pair) "]" # # The "Message-ID:" field provides a unique message identifier that # refers to a particular version of a particular message. The # uniqueness of the message identifier is guaranteed by the host that # generates it (see below). This message identifier is intended to be # machine readable and not necessarily meaningful to humans. A message # identifier pertains to exactly one instantiation of a particular # message; subsequent revisions to the message each receive new message # identifiers. # # Note: There are many instances when messages are "changed", but those # changes do not constitute a new instantiation of that message, and # therefore the message would not get a new message identifier. For # example, when messages are introduced into the transport system, they # are often prepended with additional header fields such as trace # fields (described in section 3.6.7) and resent fields (described in # section 3.6.6). The addition of such header fields does not change # the identity of the message and therefore the original "Message-ID:" # field is retained. In all cases, it is the meaning that the sender # of the message wishes to convey (i.e., whether this is the same # message or a different message) that determines whether or not the # "Message-ID:" field changes, not any particular syntactic difference # that appears (or does not appear) in the message. describe Mail::MessageIdField do describe "initialization" do it "should initialize" do doing { Mail::MessageIdField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do m = Mail::MessageIdField.new('Message-ID: <1234@test.lindsaar.net>') m.name.should eq 'Message-ID' m.value.should eq '<1234@test.lindsaar.net>' m.message_id.should eq '1234@test.lindsaar.net' end it "should accept a string without the field name" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.name.should eq 'Message-ID' m.value.should eq '<1234@test.lindsaar.net>' m.message_id.should eq '1234@test.lindsaar.net' end it "should accept a nil value and generate a message_id" do m = Mail::MessageIdField.new(nil) m.name.should eq 'Message-ID' m.value.should_not be_nil end end describe "ensuring only one message ID" do it "should not accept a string with multiple message IDs but only return the first" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net> <4567@test.lindsaar.net>') m.name.should eq 'Message-ID' m.to_s.should eq '<1234@test.lindsaar.net>' m.message_id.should eq '1234@test.lindsaar.net' m.message_ids.should eq ['1234@test.lindsaar.net'] end it "should change the message id if given a new message id" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.to_s.should eq '<1234@test.lindsaar.net>' m.value = '<4567@test.lindsaar.net>' m.to_s.should eq '<4567@test.lindsaar.net>' end end describe "instance methods" do it "should provide to_s" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.to_s.should eq '<1234@test.lindsaar.net>' m.message_id.to_s.should eq '1234@test.lindsaar.net' end it "should provide encoded" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.encoded.should eq "Message-ID: <1234@test.lindsaar.net>\r\n" end it "should provide decoded" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.decoded.should eq "<1234@test.lindsaar.net>" end it "should respond to :responsible_for?" do m = Mail::MessageIdField.new('<1234@test.lindsaar.net>') m.should respond_to(:responsible_for?) end end describe "generating a message id" do it "should generate a message ID if it has no value" do m = Mail::MessageIdField.new m.message_id.should_not be_blank end it "should generate a random message ID" do m = Mail::MessageIdField.new 1.upto(100) do m.message_id.should_not == Mail::MessageIdField.new.message_id end end end describe "weird message IDs" do it "should be able to parse <000701c874a6$3df7eaf0$b9e7c0d0$@geille@fiscon.com>" do m = Mail::MessageIdField.new('<000701c874a6$3df7eaf0$b9e7c0d0$@geille@fiscon.com>') m.message_id.should eq '000701c874a6$3df7eaf0$b9e7c0d0$@geille@fiscon.com' end end end mail-2.5.4/spec/mail/fields/mime_version_field_spec.rb000066400000000000000000000143101214434061600227640ustar00rootroot00000000000000require 'spec_helper' describe Mail::MimeVersionField do # MIME-Version Header Field # # Since RFC 822 was published in 1982, there has really been only one # format standard for Internet messages, and there has been little # perceived need to declare the format standard in use. This document # is an independent specification that complements RFC 822. Although # the extensions in this document have been defined in such a way as to # be compatible with RFC 822, there are still circumstances in which it # might be desirable for a mail-processing agent to know whether a # message was composed with the new standard in mind. # # Therefore, this document defines a new header field, "MIME-Version", # which is to be used to declare the version of the Internet message # body format standard in use. # # Messages composed in aMimeVersionordance with this document MUST include such # a header field, with the following verbatim text: # # MIME-Version: 1.0 # # The presence of this header field is an assertion that the message # has been composed in compliance with this document. # # Since it is possible that a future document might extend the message # format standard again, a formal BNF is given for the content of the # MIME-Version field: # # version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT # # Thus, future format specifiers, which might replace or extend "1.0", # are constrained to be two integer fields, separated by a period. If # a message is received with a MIME-version value other than "1.0", it # cannot be assumed to conform with this document. # # Note that the MIME-Version header field is required at the top level # of a message. It is not required for each body part of a multipart # entity. It is required for the embedded headers of a body of type # "message/rfc822" or "message/partial" if and only if the embedded # message is itself claimed to be MIME-conformant. # # It is not possible to fully specify how a mail reader that conforms # with MIME as defined in this document should treat a message that # might arrive in the future with some value of MIME-Version other than # "1.0". # # It is also worth noting that version control for specific media types # is not aMimeVersionomplished using the MIME-Version mechanism. In particular, # some formats (such as application/postscript) have version numbering # conventions that are internal to the media format. Where such # conventions exist, MIME does nothing to supersede them. Where no # such conventions exist, a MIME media type might use a "version" # parameter in the content-type field if necessary. # # NOTE TO IMPLEMENTORS: When checking MIME-Version values any RFC 822 # comment strings that are present must be ignored. In particular, the # following four MIME-Version fields are equivalent: # # MIME-Version: 1.0 # # MIME-Version: 1.0 (produced by MetaSend Vx.x) # # MIME-Version: (produced by MetaSend Vx.x) 1.0 # # MIME-Version: 1.(produced by MetaSend Vx.x)0 # # In the absence of a MIME-Version field, a receiving mail user agent # (whether conforming to MIME requirements or not) may optionally # choose to interpret the body of the message aMimeVersionording to local # conventions. Many such conventions are currently in use and it # should be noted that in practice non-MIME messages can contain just # about anything. # # It is impossible to be certain that a non-MIME mail message is # actually plain text in the US-ASCII character set since it might well # be a message that, using some set of nonstandard local conventions # that predate MIME, includes text in another character set or non- # textual data presented in a manner that cannot be automatically # recognized (e.g., a uuencoded compressed UNIX tar file). describe "initialization" do it "should initialize" do doing { Mail::MimeVersionField.new("1.0") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::MimeVersionField.new('Mime-Version: 1.0') t.name.should eq 'Mime-Version' t.value.should eq '1.0' end it "should accept a string without the field name" do t = Mail::MimeVersionField.new('1.0') t.name.should eq 'Mime-Version' t.value.should eq '1.0' end end describe "parsing a version string" do it "should get a major value" do t = Mail::MimeVersionField.new('1.0') t.major.should eq 1 end it "should get a minor value" do t = Mail::MimeVersionField.new('1.0') t.minor.should eq 0 end it "should get a version string" do t = Mail::MimeVersionField.new('1.0') t.version.should eq '1.0' end it "should handle comments before the major version" do t = Mail::MimeVersionField.new('(This is a comment) 1.0') t.version.should eq '1.0' end it "should handle comments before the major version without space" do t = Mail::MimeVersionField.new('(This is a comment)1.0') t.version.should eq '1.0' end it "should handle comments after the major version without space" do t = Mail::MimeVersionField.new('1(This is a comment).0') t.version.should eq '1.0' end it "should handle comments before the minor version without space" do t = Mail::MimeVersionField.new('1.(This is a comment)0') t.version.should eq '1.0' end it "should handle comments after the minor version without space" do t = Mail::MimeVersionField.new('1.0(This is a comment)') t.version.should eq '1.0' end it "should handle comments after the minor version" do t = Mail::MimeVersionField.new('1.0 (This is a comment)') t.version.should eq '1.0' end it "should accept nil as a value" do t = Mail::MimeVersionField.new(nil) t.version.should_not be_nil end it "should provide an encoded value" do t = Mail::MimeVersionField.new('1.0 (This is a comment)') t.encoded.should eq "Mime-Version: 1.0\r\n" end it "should provide an decoded value" do t = Mail::MimeVersionField.new('1.0 (This is a comment)') t.decoded.should eq '1.0' end end end mail-2.5.4/spec/mail/fields/received_field_spec.rb000066400000000000000000000070101214434061600220550ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::ReceivedField do it "should initialize" do doing { Mail::ReceivedField.new("Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)") }.should_not raise_error end it "should be able to tell the time" do Mail::ReceivedField.new("Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)").date_time.class.should eq DateTime end it "should accept a string with the field name" do t = Mail::ReceivedField.new('Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)') t.name.should eq 'Received' t.value.should eq 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' t.info.should eq 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ' t.date_time.should eq ::DateTime.parse('10 May 2005 17:26:50 +0000 (GMT)') end it "should accept a string without the field name" do t = Mail::ReceivedField.new('from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)') t.name.should eq 'Received' t.value.should eq 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' t.info.should eq 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ' t.date_time.should eq ::DateTime.parse('10 May 2005 17:26:50 +0000 (GMT)') end it "should provide an encoded value" do t = Mail::ReceivedField.new('from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)') t.encoded.should eq "Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000\r\n" end it "should provide an encoded value with correct timezone" do t = Mail::ReceivedField.new('from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 -0500 (EST)') t.encoded.should eq "Received: from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 -0500\r\n" end it "should provide an decoded value" do t = Mail::ReceivedField.new('from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)') t.decoded.should eq 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000' end it "should handle empty name-value lists with a comment only (qmail style)" do t = Mail::ReceivedField.new('(qmail 24365 invoked by uid 99); 25 Jan 2011 12:31:11 -0000') t.info.should eq '(qmail 24365 invoked by uid 99)' end it "should handle a blank value" do t = Mail::ReceivedField.new('') t.decoded.should eq '' t.encoded.should eq "Received: \r\n" end end mail-2.5.4/spec/mail/fields/references_field_spec.rb000066400000000000000000000065551214434061600224250ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # The "References:" field will contain the contents of the parent's # "References:" field (if any) followed by the contents of the parent's # "Message-ID:" field (if any). If the parent message does not contain # a "References:" field but does have an "In-Reply-To:" field # containing a single message identifier, then the "References:" field # will contain the contents of the parent's "In-Reply-To:" field # followed by the contents of the parent's "Message-ID:" field (if # any). If the parent has none of the "References:", "In-Reply-To:", # or "Message-ID:" fields, then the new message will have no # "References:" field. describe Mail::ReferencesField do it "should initialize" do doing { Mail::ReferencesField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::ReferencesField.new('References: <1234@test.lindsaar.net>') t.name.should eq 'References' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should accept a string without the field name" do t = Mail::ReferencesField.new('<1234@test.lindsaar.net>') t.name.should eq 'References' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should accept multiple message ids" do t = Mail::ReferencesField.new('<1234@test.lindsaar.net> <5678@test.lindsaar.net>') t.name.should eq 'References' t.value.should eq '<1234@test.lindsaar.net> <5678@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' t.message_ids.should eq ['1234@test.lindsaar.net', '5678@test.lindsaar.net'] t.to_s.should eq '<1234@test.lindsaar.net> <5678@test.lindsaar.net>' end it "should accept an array of message ids" do t = Mail::ReferencesField.new(['<1234@test.lindsaar.net>', '<5678@test.lindsaar.net>']) t.encoded.should eq "References: <1234@test.lindsaar.net>\r\n <5678@test.lindsaar.net>\r\n" end it "should accept no message ids" do t = Mail::ReferencesField.new('') t.name.should eq 'References' t.decoded.should eq nil end it "should output lines shorter than 998 chars" do k = Mail::ReferencesField.new(' ') lines = k.encoded.split("\r\n\s") lines.each { |line| line.length.should < 998 } end end mail-2.5.4/spec/mail/fields/reply_to_field_spec.rb000066400000000000000000000045661214434061600221410ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # reply-to = "Reply-To:" address-list CRLF # describe Mail::ReplyToField do describe "initialization" do it "should initialize" do doing { Mail::ReplyToField.new("Reply-To: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ReplyToField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ReplyToField.new('Reply-To: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Reply-To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ReplyToField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Reply-To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oReplyTours in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ReplyToField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ReplyToField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Reply-To: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end end end mail-2.5.4/spec/mail/fields/resent_bcc_field_spec.rb000066400000000000000000000046401214434061600224040ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF describe Mail::ResentBccField do describe "initialization" do it "should initialize" do doing { Mail::ResentBccField.new("Resent-Bcc: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ResentBccField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ResentBccField.new('Resent-Bcc: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Bcc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ResentBccField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Bcc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oResentBccurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ResentBccField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ResentBccField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ResentBccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ResentBccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ResentBccField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Resent-Bcc: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end end end mail-2.5.4/spec/mail/fields/resent_cc_field_spec.rb000066400000000000000000000046041214434061600222420ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # resent-cc = "Resent-Cc:" address-list CRLF describe Mail::ResentCcField do describe "initialization" do it "should initialize" do doing { Mail::ResentCcField.new("Resent-Cc: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ResentCcField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ResentCcField.new('Resent-Cc: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Cc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ResentCcField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Cc' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oResentCcurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ResentCcField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ResentCcField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Resent-Cc: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end end end mail-2.5.4/spec/mail/fields/resent_date_field_spec.rb000066400000000000000000000024441214434061600225720ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::ResentDateField do it "should initialize" do doing { Mail::ResentDateField.new("12 Aug 2009 00:00:02 GMT") }.should_not raise_error end it "should be able to tell the time" do Mail::ResentDateField.new("12 Aug 2009 00:00:02 GMT").date_time.class.should eq DateTime end it "should mix in the CommonAddress module" do Mail::ResentDateField.included_modules.should include(Mail::CommonDate) end it "should accept a string with the field name" do t = Mail::ResentDateField.new('Resent-Date: 12 Aug 2009 00:00:02 GMT') t.name.should eq 'Resent-Date' t.value.should eq 'Wed, 12 Aug 2009 00:00:02 +0000' t.date_time.should eq ::DateTime.parse('12 Aug 2009 00:00:02 GMT') end it "should accept a string without the field name" do t = Mail::ResentDateField.new('12 Aug 2009 00:00:02 GMT') t.name.should eq 'Resent-Date' t.value.should eq 'Wed, 12 Aug 2009 00:00:02 +0000' t.date_time.should eq ::DateTime.parse('12 Aug 2009 00:00:02 GMT') end it "should give today's date if no date is specified" do now = Time.now Time.stub!(:now).and_return(now) t = Mail::ResentDateField.new t.name.should eq 'Resent-Date' t.date_time.should eq ::DateTime.parse(now.to_s) end end mail-2.5.4/spec/mail/fields/resent_from_field_spec.rb000066400000000000000000000046461214434061600226260ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # resent-from = "Resent-From:" mailbox-list CRLF describe Mail::ResentFromField do describe "initialization" do it "should initialize" do doing { Mail::ResentFromField.new("Resent-From: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ResentFromField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ResentFromField.new('Resent-From: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-From' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ResentFromField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-From' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oResentFromurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ResentFromField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ResentFromField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ResentFromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ResentFromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ResentFromField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Resent-From: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end end end mail-2.5.4/spec/mail/fields/resent_message_id_field_spec.rb000066400000000000000000000036701214434061600237570ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::ResentMessageIdField do it "should initialize" do doing { Mail::ResentMessageIdField.new("<1234@test.lindsaar.net>") }.should_not raise_error end it "should accept a string with the field name" do t = Mail::ResentMessageIdField.new('Resent-Message-ID: <1234@test.lindsaar.net>') t.name.should eq 'Resent-Message-ID' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should accept a string without the field name" do t = Mail::ResentMessageIdField.new('<1234@test.lindsaar.net>') t.name.should eq 'Resent-Message-ID' t.value.should eq '<1234@test.lindsaar.net>' t.message_id.should eq '1234@test.lindsaar.net' end it "should output lines shorter than 998 chars" do k = Mail::ResentMessageIdField.new(' ') lines = k.encoded.split("\r\n\s") lines.each { |line| line.length.should < 998 } end end mail-2.5.4/spec/mail/fields/resent_sender_field_spec.rb000066400000000000000000000040311214434061600231270ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # resent-sender = "Resent-Sender:" mailbox CRLF describe Mail::ResentSenderField do describe "initialization" do it "should initialize" do doing { Mail::ResentSenderField.new("Resent-Sender: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ResentSenderField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ResentSenderField.new('Resent-Sender: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Sender' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ResentSenderField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-Sender' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oResentSenderurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ResentSenderField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ResentSenderField.new('Mikel Lindsaar ') t.address.to_s.should eq 'Mikel Lindsaar ' end it "should return the formatted line on to_s" do t = Mail::ResentSenderField.new('Mikel Lindsaar ') t.value.should eq 'Mikel Lindsaar ' end it "should return the encoded line" do t = Mail::ResentSenderField.new('Mikel Lindsaar ') t.encoded.should eq "Resent-Sender: Mikel Lindsaar \r\n" end end end mail-2.5.4/spec/mail/fields/resent_to_field_spec.rb000066400000000000000000000046041214434061600222770ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' # # resent-to = "Resent-To:" address-list CRLF describe Mail::ResentToField do describe "initialization" do it "should initialize" do doing { Mail::ResentToField.new("Resent-To: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ResentToField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ResentToField.new('Resent-To: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ResentToField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'Resent-To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oResentTours in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ResentToField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ResentToField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ResentToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ResentToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ResentToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "Resent-To: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end end end mail-2.5.4/spec/mail/fields/return_path_field_spec.rb000066400000000000000000000031361214434061600226270ustar00rootroot00000000000000require 'spec_helper' describe Mail::ReturnPathField do it "should allow you to specify a field" do rp = Mail::ReturnPathField.new('Return-Path: mikel@test.lindsaar.net') rp.address.should eq 'mikel@test.lindsaar.net' end it "should encode the addr_spec in <>" do rp = Mail::ReturnPathField.new('Return-Path: mikel@test.lindsaar.net') rp.encoded.should eq "Return-Path: \r\n" end it "should accept <>" do rp = Mail::ReturnPathField.new('<>') rp.encoded.should eq "Return-Path: <>\r\n" end it "should set the return path" do mail = Mail.new do to "to@someemail.com" from "from@someemail.com" subject "Can't set the return-path" return_path "bounce@someemail.com" message_id "<1234@someemail.com>" body "body" end mail.return_path.should eq "bounce@someemail.com" end it "should set the return path" do mail = Mail.new do to "to@someemail.com" from "from@someemail.com" subject "Can't set the return-path" return_path "bounce@someemail.com" message_id "<1234@someemail.com>" body "body" end encoded_mail = Mail.new(mail.encoded) encoded_mail.return_path.should eq "bounce@someemail.com" end it "should wrap the return path addr_spec in <>" do mail = Mail.new do to "to@someemail.com" from "from@someemail.com" subject "Can't set the return-path" return_path "bounce@someemail.com" message_id "<1234@someemail.com>" body "body" end mail.encoded.should =~ // end end mail-2.5.4/spec/mail/fields/sender_field_spec.rb000066400000000000000000000041651214434061600215570ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::SenderField do # sender = "Sender:" mailbox CRLF # describe "initialization" do it "should initialize" do doing { Mail::SenderField.new("Sender: Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::SenderField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::SenderField.new('Sender: Mikel Lindsaar ') t.name.should eq 'Sender' t.value.should eq 'Mikel Lindsaar ' end it "should accept a string without the field name" do t = Mail::SenderField.new('Mikel Lindsaar ') t.name.should eq 'Sender' t.value.should eq 'Mikel Lindsaar ' end it "should reject headers with multiple mailboxes" do pending 'Sender accepts an address list now, but should only accept a single address' doing { Mail::SenderField.new('Sender: Mikel Lindsaar , "Bob Smith" ') }.should raise_error end end # Actual testing of CommonAddress methods oSenderurs in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::SenderField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::SenderField.new('Mikel Lindsaar ') t.address.to_s.should eq 'Mikel Lindsaar ' end it "should return the formatted line on to_s" do t = Mail::SenderField.new('Mikel Lindsaar ') t.value.should eq 'Mikel Lindsaar ' end it "should return the encoded line" do t = Mail::SenderField.new('Mikel Lindsaar ') t.encoded.should eq "Sender: Mikel Lindsaar \r\n" end end end mail-2.5.4/spec/mail/fields/structured_field_spec.rb000066400000000000000000000037401214434061600225010ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::StructuredField do describe "initialization" do it "should be instantiated" do doing {Mail::StructuredField.new("From", "bob@me.com")}.should_not raise_error end end describe "manipulation" do before(:each) do @field = Mail::StructuredField.new("From", "bob@me.com") end it "should allow us to set a text value at initialization" do doing{Mail::StructuredField.new("From", "bob@me.com")}.should_not raise_error end it "should provide access to the text of the field once set" do @field.value.should eq "bob@me.com" end it "should provide a means to change the value" do @field.value = "bob@you.com" @field.value.should eq "bob@you.com" end end describe "displaying encoded field and decoded value" do before(:each) do @field = Mail::FromField.new("bob@me.com") end it "should provide a to_s function that returns the decoded string" do @field.to_s.should eq "bob@me.com" end it "should return '' on to_s if there is no value" do @field.value = nil @field.encoded.should eq '' end it "should give an encoded value ready to insert into an email" do @field.encoded.should eq "From: bob@me.com\r\n" end it "should return an empty string on encoded if it has no value" do @field.value = nil @field.encoded.should eq '' end it "should return the field name and value in proper format when called to_s" do @field.encoded.should eq "From: bob@me.com\r\n" end end describe "structured field template methods" do it "should raise an error if attempting to call :encoded or :decoded on the parent StructuredField class" do field = Mail::StructuredField.new doing { field.encoded }.should raise_error(NoMethodError) doing { field.decoded }.should raise_error(NoMethodError) end end end mail-2.5.4/spec/mail/fields/to_field_spec.rb000066400000000000000000000070311214434061600207140ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::ToField do # # The "To:" field contains the address(es) of the primary recipient(s) # of the message. describe "initialization" do it "should initialize" do doing { Mail::ToField.new("Mikel") }.should_not raise_error end it "should mix in the CommonAddress module" do Mail::ToField.included_modules.should include(Mail::CommonAddress) end it "should accept a string with the field name" do t = Mail::ToField.new('To: Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end it "should accept a string without the field name" do t = Mail::ToField.new('Mikel Lindsaar , "Bob Smith" ') t.name.should eq 'To' t.value.should eq 'Mikel Lindsaar , "Bob Smith" ' end end # Actual testing of CommonAddress methods oTours in the address field spec file describe "instance methods" do it "should return an address" do t = Mail::ToField.new('Mikel Lindsaar ') t.formatted.should eq ['Mikel Lindsaar '] end it "should return two addresses" do t = Mail::ToField.new('Mikel Lindsaar , Ada Lindsaar ') t.formatted.first.should eq 'Mikel Lindsaar ' t.addresses.last.should eq 'ada@test.lindsaar.net' end it "should return one address and a group" do t = Mail::ToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses[0].should eq 'sam@me.com' t.addresses[1].should eq 'mikel@me.com' t.addresses[2].should eq 'bob@you.com' end it "should return the formatted line on to_s" do t = Mail::ToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.value.should eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' end it "should return the encoded line" do t = Mail::ToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.encoded.should eq "To: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" end it "should return the decoded line" do t = Mail::ToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.decoded.should eq "sam@me.com, my_group: mikel@me.com, bob@you.com;" end it "should get multiple address out from a group list" do t = Mail::ToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') t.addresses.should eq ["sam@me.com", "mikel@me.com", "bob@you.com"] end it "should handle commas in the address" do t = Mail::ToField.new('"Long, stupid email address" ') t.addresses.should eq ["mikel@test.lindsaar.net"] end it "should handle commas in the address for multiple fields" do t = Mail::ToField.new('"Long, stupid email address" , "Another, really, really, long, stupid email address" ') t.addresses.should eq ["mikel@test.lindsaar.net", "bob@test.lindsaar.net"] end end it "should not crash if it can't understand a name" do t = Mail.new('To: <"Undisclosed-Recipient:"@msr19.hinet.net;>') doing { t.encoded }.should_not raise_error t.encoded.should =~ /To\:\s<"Undisclosed\-Recipient\:"@msr19\.hinet\.net;>\r\n/ end end mail-2.5.4/spec/mail/fields/unstructured_field_spec.rb000066400000000000000000000271321214434061600230450ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::UnstructuredField do describe "initialization" do it "should be instantiated" do doing {Mail::UnstructuredField.new("Name", "Value")}.should_not raise_error end end describe "manipulation" do before(:each) do @field = Mail::UnstructuredField.new("Subject", "Hello Frank") end it "should allow us to set a text value at initialization" do doing{Mail::UnstructuredField.new("Subject", "Value")}.should_not raise_error end it "should provide access to the text of the field once set" do @field.value.should eq "Hello Frank" end it "should provide a means to change the value" do @field.value = "Goodbye Frank" @field.value.should eq "Goodbye Frank" end end describe "displaying encoded field and decoded value" do before(:each) do @field = Mail::UnstructuredField.new("Subject", "Hello Frank") end it "should provide a to_s function that returns the field name and value" do @field.value.should eq "Hello Frank" end it "should return '' on to_s if there is no value" do @field.value = nil @field.to_s.should eq '' end it "should give an encoded value ready to insert into an email" do @field.encoded.should eq "Subject: Hello Frank\r\n" end it "should return nil on encoded if it has no value" do @field.value = nil @field.encoded.should eq '' end it "should handle array" do @field = Mail::UnstructuredField.new("To", ['mikel@example.com', 'bob@example.com']) @field.encoded.should eq "To: mikel@example.com, bob@example.com\r\n" end it "should handle string" do @field.value = 'test' @field.encoded.should eq "Subject: test\r\n" end it "should give an decoded value ready to insert into an email" do @field.decoded.should eq "Hello Frank" end it "should return a nil on decoded if it has no value" do @field.value = nil @field.decoded.should eq nil end it "should just add the CRLF at the end of the line" do @field = Mail::SubjectField.new("Subject: =?utf-8?Q?testing_testing_=D6=A4?=") result = "Subject: =?UTF-8?Q?testing_testing_=D6=A4?=\r\n" @field.encoded.should eq result @field.decoded.should eq "testing testing \326\244" end it "should do encoded-words encoding correctly without extra equal sign" do @field = Mail::SubjectField.new("testing testing æøå") result = "Subject: =?UTF-8?Q?testing_testing_=C3=A6=C3=B8=C3=A5?=\r\n" @field.encoded.should eq result @field.decoded.should eq "testing testing æøå" end it "should encode the space between two adjacent encoded-words" do @field = Mail::SubjectField.new("Her er æ ø å") result = "Subject: =?UTF-8?Q?Her_er_=C3=A6_=C3=B8_=C3=A5?=\r\n" @field.encoded.should eq result @field.decoded.should eq "Her er æ ø å" end it "should encode additional special characters inside encoded-word-encoded strings" do string = %Q(Her er æ()<>@,;:\\"/[]?.=) @field = Mail::SubjectField.new(string) result = %Q(Subject: =?UTF-8?Q?Her_er_=C3=A6=28=29<>@,;:\\=22/[]=3F.=3D?=\r\n) @field.encoded.should eq result @field.decoded.should eq string end if !'1.9'.respond_to?(:force_encoding) it "shouldn't get fooled into encoding on 1.8 due to an unrelated Encoding constant" do begin Mail::UnstructuredField::Encoding = 'derp' @field.encoded.should eq "Subject: Hello Frank\r\n" ensure Mail::UnstructuredField.send :remove_const, :Encoding end end end end describe "folding" do it "should not fold itself if it is 78 chracters long" do @field = Mail::UnstructuredField.new("Subject", "This is a subject header message that is _exactly_ 78 characters....") @field.encoded.should eq "Subject: This is a subject header message that is _exactly_ 78 characters....\r\n" end it "should fold itself if it is 79 chracters long" do @field = Mail::UnstructuredField.new("Subject", "This is a subject header message that is absolutely 79 characters long") result = "Subject: This is a subject header message that is absolutely 79 characters\r\n\slong\r\n" @field.encoded.should eq result end it "should fold itself if it is 997 chracters long" do @field = Mail::UnstructuredField.new("Subject", "This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. This is a subject header message that is going to be 997 characters long. And this makes it 997....") lines = @field.encoded.split("\r\n\s") lines.each { |line| line.length.should < 78 } end it "should fold itself if it is 998 characters long" do value = "This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. This is a subject header message that is going to be 998 characters long. And this makes it 998 long" @field = Mail::UnstructuredField.new("Subject", value) lines = @field.encoded.split("\r\n\s") lines.each { |line| line.length.should < 78 } end it "should fold itself if it is 999 characters long" do value = "This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. This is a subject header message that is going to be 999 characters long. And this makes it 999 long." @field = Mail::UnstructuredField.new("Subject", value) lines = @field.encoded.split("\r\n\s") lines.each { |line| line.length.should < 78 } end it "should fold itself if it is non us-ascii" do @original = $KCODE if RUBY_VERSION < '1.9' string = "This is あ really long string This is あ really long string This is あ really long string This is あ really long string This is あ really long string" @field = Mail::UnstructuredField.new("Subject", string) if string.respond_to?(:force_encoding) string = string.force_encoding('UTF-8') else $KCODE = 'u' end result = "Subject: =?UTF-8?Q?This_is_=E3=81=82_really_long_string_This_is_=E3=81=82?=\r\n\s=?UTF-8?Q?_really_long_string_This_is_=E3=81=82_really_long_string_This_is?=\r\n\s=?UTF-8?Q?_=E3=81=82_really_long_string_This_is_=E3=81=82_really_long?=\r\n\s=?UTF-8?Q?_string?=\r\n" @field.encoded.should eq result @field.decoded.should eq string $KCODE = @original if RUBY_VERSION < '1.9' end it "should fold properly with my actual complicated header" do @original = $KCODE if RUBY_VERSION < '1.9' string = %|{"unique_args": {"mailing_id":147,"account_id":2}, "to": ["larspind@gmail.com"], "category": "mailing", "filters": {"domainkeys": {"settings": {"domain":1,"enable":1}}}, "sub": {"{{open_image_url}}": ["http://betaling.larspind.local/O/token/147/Mailing::FakeRecipient"], "{{name}}": ["[FIRST NAME]"], "{{signup_reminder}}": ["(her kommer til at stå hvornår folk har skrevet sig op ...)"], "{{unsubscribe_url}}": ["http://betaling.larspind.local/U/token/147/Mailing::FakeRecipient"], "{{email}}": ["larspind@gmail.com"], "{{link:308}}": ["http://betaling.larspind.local/L/308/0/Mailing::FakeRecipient"], "{{confirm_url}}": [""], "{{ref}}": ["[REF]"]}}| @field = Mail::UnstructuredField.new("X-SMTPAPI", string) if string.respond_to?(:force_encoding) string = string.force_encoding('UTF-8') else $KCODE = 'u' end result = "X-SMTPAPI: =?UTF-8?Q?{=22unique=5Fargs=22:_{=22mailing=5Fid=22:147,=22a?=\r\n =?UTF-8?Q?ccount=5Fid=22:2},_=22to=22:_[=22larspind@gmail.com=22],_=22categ?=\r\n =?UTF-8?Q?ory=22:_=22mailing=22,_=22filters=22:_{=22domainkeys=22:_{=22sett?=\r\n =?UTF-8?Q?ings=22:_{=22domain=22:1,=22enable=22:1}}},_=22sub=22:_{=22{{op?=\r\n =?UTF-8?Q?en=5Fimage=5Furl}}=22:_[=22http://betaling.larspind.local/O?=\r\n =?UTF-8?Q?/token/147/Mailing::FakeRecipient=22],_=22{{name}}=22:_[=22[FIRST?=\r\n =?UTF-8?Q?_NAME]=22],_=22{{signup=5Freminder}}=22:_[=22=28her_kommer_til_at?=\r\n =?UTF-8?Q?_st=C3=A5_hvorn=C3=A5r_folk_har_skrevet_sig_op_...=29=22],?=\r\n =?UTF-8?Q?_=22{{unsubscribe=5Furl}}=22:_[=22http://betaling.larspind.?=\r\n =?UTF-8?Q?local/U/token/147/Mailing::FakeRecipient=22],_=22{{email}}=22:?=\r\n =?UTF-8?Q?_[=22larspind@gmail.com=22],_=22{{link:308}}=22:_[=22http://beta?=\r\n =?UTF-8?Q?ling.larspind.local/L/308/0/Mailing::FakeRecipient=22],_=22{{con?=\r\n =?UTF-8?Q?firm=5Furl}}=22:_[=22=22],_=22{{ref}}=22:_[=22[REF]=22]}}?=\r\n" @field.encoded.should eq result @field.decoded.should eq string $KCODE = @original if RUBY_VERSION < '1.9' end end describe "encoding non QP safe chars" do it "should encode an ascii string that has carriage returns if asked to" do result = "Subject: =0Aasdf=0A\r\n" @field = Mail::UnstructuredField.new("Subject", "\nasdf\n") @field.encoded.should eq result end end describe "iso-2022-jp Subject" do it "should encoded with ISO-2022-JP encoding" do @field = Mail::UnstructuredField.new("Subject", "あいうえお") @field.charset = 'iso-2022-jp' expect = (RUBY_VERSION < '1.9') ? "Subject: =?ISO-2022-JP?Q?=E3=81=82=E3=81=84=E3=81=86=E3=81=88=E3=81=8A?=\r\n" : "Subject: =?ISO-2022-JP?Q?=1B$B$=22$$$&$=28$*=1B=28B?=\r\n" @field.encoded.should eq expect end end end mail-2.5.4/spec/mail/header_spec.rb000066400000000000000000000617261214434061600171240ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Header do describe "initialization" do it "should instantiate empty" do doing { Mail::Header.new }.should_not raise_error end it "should instantiate with a string passed in" do doing { Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") }.should_not raise_error end end describe "instance methods" do it "should save away the raw source of the header that it is passed" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header.raw_source.should eq "To: Mikel\r\nFrom: bob\r\n" end it "should say if it has a message_id field defined" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header.should_not be_has_message_id end it "should say if it has a message_id field defined" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\nMessage-ID: 1234") header.should be_has_message_id end it "should say if it has a content_id field defined" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header.should_not be_has_content_id end it "should say if it has a content_id field defined" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\nContent-ID: <1234@me.com>") header.should be_has_content_id end it "should know its own charset" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\nContent-ID: <1234@me.com>") header.charset.should eq nil end it "should know its own charset if set" do header = Mail::Header.new header['content-type'] = 'text/plain; charset=utf-8' header.charset.should eq 'utf-8' end it "shouldn't die when queried for a charset and the content-type header is invalid" do header = Mail::Header.new header['Content-Type'] = 'invalid/invalid; charset="iso-8859-1"' doing { header.charset }.should_not raise_error end it "should be Enumerable" do header = Mail::Header.new("To: James Random\r\nFrom: Santa Claus\r\n") header.find {|f| f.responsible_for?('From') }.should be_a(Mail::Field) end end describe "creating fields" do it "should recognise a bcc field" do header = Mail::Header.new header['bcc'] = 'mikel@test.lindsaar.net' header['bcc'].field.class.should eq Mail::BccField end it "should recognise a cc field" do header = Mail::Header.new header['cc'] = 'mikel@test.lindsaar.net' header['cc'].field.class.should eq Mail::CcField end it "should recognise a content-description field" do header = Mail::Header.new header['content-description'] = 'Text' header['content-description'].field.class.should eq Mail::ContentDescriptionField end it "should recognise a content-disposition field" do header = Mail::Header.new header['content-disposition'] = 'attachment; filename=File' header['content-disposition'].field.class.should eq Mail::ContentDispositionField end it "should recognise an inline content-disposition field" do header = Mail::Header.new header['content-disposition'] = 'inline' header['content-disposition'].field.class.should eq Mail::ContentDispositionField end it "should recognise a content-id field" do header = Mail::Header.new header['content-id'] = '<1234@test.lindsaar.net>' header['content-id'].field.class.should eq Mail::ContentIdField end it "should recognise a content-transfer-encoding field" do header = Mail::Header.new header['content-transfer-encoding'] = '7bit' header['content-transfer-encoding'].field.class.should eq Mail::ContentTransferEncodingField end it "should recognise a content-type field" do header = Mail::Header.new header['content-type'] = 'text/plain' header['content-type'].field.class.should eq Mail::ContentTypeField end it "should recognise a date field" do header = Mail::Header.new header['date'] = 'Fri, 21 Nov 1997 09:55:06 -0600' header['date'].field.class.should eq Mail::DateField end it "should recognise a from field" do header = Mail::Header.new header['from'] = 'mikel@test.lindsaar.net' header['from'].field.class.should eq Mail::FromField end it "should recognise a in-reply-to field" do header = Mail::Header.new header['in-reply-to'] = '<1234@test.lindsaar.net>' header['in-reply-to'].field.class.should eq Mail::InReplyToField end it "should recognise a keywords field" do header = Mail::Header.new header['keywords'] = 'mikel test lindsaar net' header['keywords'].field.class.should eq Mail::KeywordsField end it "should recognise a message-id field" do header = Mail::Header.new header['message-id'] = '<1234@test.lindsaar.net>' header['message-id'].field.class.should eq Mail::MessageIdField end it "should recognise a mime-version field" do header = Mail::Header.new header['mime-version'] = '1.0' header['mime-version'].field.class.should eq Mail::MimeVersionField end it "should recognise a received field" do header = Mail::Header.new header['received'] = 'from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500' header['received'].field.class.should eq Mail::ReceivedField end it "should recognise a references field" do header = Mail::Header.new header['references'] = '<1234@test.lindsaar.net>' header['references'].field.class.should eq Mail::ReferencesField end it "should recognise a reply-to field" do header = Mail::Header.new header['reply-to'] = 'mikel@test.lindsaar.net' header['reply-to'].field.class.should eq Mail::ReplyToField end it "should recognise a resent-bcc field" do header = Mail::Header.new header['resent-bcc'] = 'mikel@test.lindsaar.net' header['resent-bcc'].field.class.should eq Mail::ResentBccField end it "should recognise a resent-cc field" do header = Mail::Header.new header['resent-cc'] = 'mikel@test.lindsaar.net' header['resent-cc'].field.class.should eq Mail::ResentCcField end it "should recognise a resent-date field" do header = Mail::Header.new header['resent-date'] = 'Fri, 21 Nov 1997 09:55:06 -0600' header['resent-date'].field.class.should eq Mail::ResentDateField end it "should recognise a resent-from field" do header = Mail::Header.new header['resent-from'] = 'mikel@test.lindsaar.net' header['resent-from'].field.class.should eq Mail::ResentFromField end it "should recognise a resent-message-id field" do header = Mail::Header.new header['resent-message-id'] = '<1234@mail.baci.local>' header['resent-message-id'].field.class.should eq Mail::ResentMessageIdField end it "should recognise a resent-sender field" do header = Mail::Header.new header['resent-sender'] = 'mikel@test.lindsaar.net' header['resent-sender'].field.class.should eq Mail::ResentSenderField end it "should recognise a resent-to field" do header = Mail::Header.new header['resent-to'] = 'mikel@test.lindsaar.net' header['resent-to'].field.class.should eq Mail::ResentToField end it "should recognise a return-path field" do header = Mail::Header.new header['return-path'] = '' header['return-path'].field.class.should eq Mail::ReturnPathField end it "should recognise a sender field" do header = Mail::Header.new header['sender'] = 'mikel@test.lindsaar.net' header['sender'].field.class.should eq Mail::SenderField end it "should recognise a to field" do header = Mail::Header.new header['to'] = 'mikel@test.lindsaar.net' header['to'].field.class.should eq Mail::ToField end it "should maintain header case" do header = Mail::Header.new header['User-Agent'] = 'My funky mailer' header.encoded.should match(/^User-Agent: /) header.encoded.should_not match(/^user-agent: /) end it "should not accept field names containing colons" do doing { Mail::Header.new['a:b'] = 'c' }.should raise_error end end describe "parsing" do it "should split the header into separate fields" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header.fields.length.should eq 2 end it "should not split a wrapped header in two" do header = Mail::Header.new("To: mikel lindsaar\r\n\s\r\nFrom: bob\r\nSubject: This is\r\n a long\r\n\s \t \t \t badly formatted \r\n \t\t \t field") header.fields.length.should eq 3 end # Header fields are lines composed of a field name, followed by a colon # (":"), followed by a field body, and terminated by CRLF. A field # name MUST be composed of printable US-ASCII characters (i.e., # characters that have values between 33 and 126, inclusive), except # colon. it "should accept any valid header field name" do test_name = ascii.reject { |c| c == ':' }.join doing { Mail::Header.new("#{test_name}: This is a crazy name") }.should_not raise_error end it "should not try to accept colons in header field names" do header = Mail::Header.new("Colon:in:header: oops") header.fields.size.should eq 1 header.fields.first.name.should eq 'Colon' header['Colon'].value.should eq 'in:header: oops' end # A field body may be composed of any US-ASCII characters, # except for CR and LF. However, a field body may contain CRLF when # used in header "folding" and "unfolding" as described in section # 2.2.3. it "should accept any valid header field value" do test_value = ascii.reject { |c| c == ':' } test_value << ' ' test_value << '\r\n' doing {Mail::Header.new("header: #{test_value}")}.should_not raise_error end it "should split each field into an name and value" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header.fields[0].name.should eq "From" header.fields[0].value.should eq "bob" header.fields[1].name.should eq "To" header.fields[1].value.should eq "Mikel" end it "should split each field into an name and value - even if whitespace is missing" do header = Mail::Header.new("To: Mikel\r\nFrom:bob\r\n") header.fields[0].name.should eq "From" header.fields[0].value.should eq "bob" header.fields[1].name.should eq "To" header.fields[1].value.should eq "Mikel" end it "should preserve the order of the fields it is given" do header = Mail::Header.new header.fields = ['From: mikel@me.com', 'To: bob@you.com', 'Subject: This is a badly formed email'] header.fields[0].name.should eq 'From' header.fields[1].name.should eq 'To' header.fields[2].name.should eq 'Subject' end it "should allow you to reference each field and value by literal string name" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header['To'].value.should eq "Mikel" header['From'].value.should eq "bob" end it "should return an array of fields if there is more than one match" do header = Mail::Header.new header.fields = ['From: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 23'] header['X-Mail-SPAM'].map { |x| x.value }.should eq ['15', '23'] end it "should return nil if no value in the header" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header['Subject'].should be_nil end it "should add a new field if the field does not exist" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header['Subject'] = "G'Day!" header['Subject'].value.should eq "G'Day!" end it "should allow you to pass in an array of raw fields" do header = Mail::Header.new header.fields = ['From: mikel@test.lindsaar.net', 'To: bob@you.com'] header['To'].value.should eq 'bob@you.com' header['From'].value.should eq 'mikel@test.lindsaar.net' end it "should reset the value of a single-only field if it already exists" do header = Mail::Header.new("To: Mikel\r\nFrom: bob\r\n") header['To'] = 'George' header['To'].value.should eq "George" end it "should allow you to delete a field by setting it to nil" do header = Mail::Header.new header.fields = ['To: bob@you.com'] header.fields.length.should eq 1 header['To'] = nil header.fields.length.should eq 0 end it "should delete all matching fields found if there are multiple options" do header = Mail::Header.new header.fields = ['X-SPAM: 1000', 'X-SPAM: 20'] header['X-SPAM'] = nil header.fields.length.should eq 0 end it "should delete only matching fields found" do header = Mail::Header.new header.fields = ['X-SPAM: 1000', 'X-AUTHOR: Steve'] header['X-SPAM'] = nil header['X-AUTHOR'].should_not be_nil header.fields.length.should eq 1 end # Handle empty X-Optional header from Microsoft Exchange it "should handle an empty X-* header value" do header = Mail::Header.new("X-MS-TNEF-Correlator:\r\n") header.fields.length.should eq 1 header['X-MS-TNEF-Correlator'].decoded.should eq nil header['X-MS-TNEF-Correlator'].encoded.should eq "X-MS-TNEF-Correlator: \r\n" end it "should accept X- option fields from MS-Exchange" do header = Mail::Header.new("X-Ms-Has-Attach:\r\nX-MS-TNEF-Correlator: \r\n") header.fields.length.should eq 2 header['X-Ms-Has-Attach'].decoded.should eq nil header['X-Ms-Has-Attach'].encoded.should eq "X-Ms-Has-Attach: \r\n" header['X-MS-TNEF-Correlator'].decoded.should eq nil header['X-MS-TNEF-Correlator'].encoded.should eq "X-MS-TNEF-Correlator: \r\n" end it "should return nil if asked for the value of a non existent field" do header = Mail::Header.new header['Bobs-Field'].should eq nil end it "should allow you to replace a from field" do header = Mail::Header.new header['From'].should eq nil header['From'] = 'mikel@test.lindsaar.net' header['From'].decoded.should eq 'mikel@test.lindsaar.net' header['From'] = 'bob@test.lindsaar.net' header['From'].decoded.should eq 'bob@test.lindsaar.net' end it "should maintain the class of the field" do header = Mail::Header.new header['From'] = 'mikel@test.lindsaar.net' header['From'].field.class.should eq Mail::FromField header['From'] = 'bob@test.lindsaar.net' header['From'].field.class.should eq Mail::FromField end end describe "folding and unfolding" do it "should unfold a header" do header = Mail::Header.new("To: Mikel,\r\n Lindsaar, Bob") header['To'].value.should eq 'Mikel, Lindsaar, Bob' end it "should remove multiple spaces during unfolding a header" do header = Mail::Header.new("To: Mikel,\r\n Lindsaar, Bob") header['To'].value.should eq 'Mikel, Lindsaar, Bob' end it "should handle a crazy long folded header" do header_text =<) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700 HERE header = Mail::Header.new(header_text.gsub(/\n/, "\r\n")) header['Received'].value.should eq 'from [127.0.220.158] (helo=fg-out-1718.google.com) by smtp.totallyrandom.com with esmtp (Exim 4.68) (envelope-from ) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700' end it "should convert all lonesome LFs to CRLF" do header_text =<) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700 HERE header = Mail::Header.new(header_text.gsub(/\n/, "\n")) header['Received'].value.should eq 'from [127.0.220.158] (helo=fg-out-1718.google.com) by smtp.totallyrandom.com with esmtp (Exim 4.68) (envelope-from ) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700' end it "should convert all lonesome CRs to CRLF" do header_text =<) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700 HERE header = Mail::Header.new(header_text.gsub(/\n/, "\r")) header['Received'].value.should eq 'from [127.0.220.158] (helo=fg-out-1718.google.com) by smtp.totallyrandom.com with esmtp (Exim 4.68) (envelope-from ) id 1K4JeQ-0005Nd-Ij for support@aaa.somewhere.com; Thu, 05 Jun 2008 10:53:29 -0700' end end describe "error handling" do it "should collect up any of its fields' errors" do header = Mail::Header.new("Content-Transfer-Encoding: vl@d\r\nReply-To: a b b") header.errors.should_not be_blank header.errors.size.should eq 2 header.errors[0][0].should eq 'Content-Transfer-Encoding' header.errors[0][1].should eq 'vl@d' header.errors[1][0].should eq 'Reply-To' header.errors[1][1].should eq 'a b b' end end describe "handling date fields with multiple values" do it "should know which fields can only appear once" do %w[ date ].each do |field| header = Mail::Header.new header[field] = "Thu, 05 Jun 2008 10:53:29 -0700" header[field] = "Mon, 15 Nov 2010 11:05:29 -1100" header[field].value.should eq "Mon, 15 Nov 2010 11:05:29 -1100" end end it "should know which fields can only appear once" do %w[ from sender reply-to to cc bcc ].each do |field| header = Mail::Header.new header[field] = "mikel@test.lindsaar.net" header[field] = "ada@test.lindsaar.net" header[field].value.should eq "ada@test.lindsaar.net" end end it "should enforce appear-once rule even with mass assigned header" do header = Mail::Header.new( "Content-Type: multipart/alternative\nContent-Type: text/plain\n" ) header['content-type'].should_not be_kind_of(Array) end it "should add additional fields that can appear more than once" do %w[ comments keywords x-spam].each do |field| header = Mail::Header.new header[field] = "1234" header[field] = "5678" header[field].map { |x| x.value }.should eq ["1234", "5678"] end end it "should delete all references to a field" do header = Mail::Header.new header.fields = ['X-Mail-SPAM: 15', 'X-Mail-SPAM: 20'] header['X-Mail-SPAM'] = '10000' header['X-Mail-SPAM'].map { |x| x.value }.should eq ['15', '20', '10000'] header['X-Mail-SPAM'] = nil header['X-Mail-SPAM'].should eq nil end end describe "handling trace fields" do before(:each) do trace_header =< Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500 Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id j48HUC213279 for ; Sun, 8 May 2005 12:30:13 -0500 Received: from conversion-xxx.xxxx.xxx.net by xxx.xxxx.xxx id <0IG600901LQ64I@xxx.xxxx.xxx> for ; Sun, 8 May 2005 12:30:12 -0500 Received: from agw1 by xxx.xxxx.xxx with ESMTP id <0IG600JFYLYCAxxx@xxxx.xxx> for ; Sun, 8 May 2005 12:30:12 -0500 TRACEHEADER @traced_header = Mail::Header.new(trace_header) end it "should instantiate one trace field object per header" do @traced_header.fields.length.should eq 5 end it "should add a new received header after the other received headers if they exist" do @traced_header['To'] = "Mikel" @traced_header['Received'] = "from agw2 by xxx.xxxx.xxx; Sun, 8 May 2005 12:30:13 -0500" @traced_header.fields[0].addresses.should eq ['xxx@xxxx.xxxtest'] @traced_header.fields[1].info.should eq 'from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ' @traced_header.fields[2].info.should eq 'from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id j48HUC213279 for ' @traced_header.fields[3].info.should eq 'from conversion-xxx.xxxx.xxx.net by xxx.xxxx.xxx id <0IG600901LQ64I@xxx.xxxx.xxx> for ' @traced_header.fields[5].info.should eq "from agw2 by xxx.xxxx.xxx" @traced_header.fields[6].field.class.should eq Mail::ToField end end describe "encoding" do it "should output a parsed version of itself to US-ASCII on encoded and tidy up and sort correctly" do encoded = Mail::Header.new("To: Mikel\r\n\sLindsaar \r\nFrom: bob\r\n\s\r\nSubject: This is\r\n a long\r\n\s \t \t \t badly formatted \r\n \t\t \t field").encoded result = "From: bob \r\nTo: Mikel Lindsaar \r\nSubject: This is a long badly formatted field\r\n" if result.respond_to?(:encode!) result.encode!(Encoding::US_ASCII) encoded.encoding.should eq Encoding::US_ASCII if encoded.respond_to?(:encoding) end encoded.should eq result end if '1.9'.respond_to?(:force_encoding) it "should blow up on encoding mismatches" do junk = "Subject: \xAF".force_encoding(Encoding::ASCII_8BIT) header = Mail::Header.new(junk, 'utf-8') doing { header.encoded }.should raise_error end end end describe "detecting required fields" do it "should not say it has a message id if it doesn't" do Mail::Header.new.should_not be_has_message_id end it "should say it has a message id if it does" do Mail::Header.new('Message-ID: 1234').should be_has_message_id end it "should not say it has a date if it doesn't" do Mail::Header.new.should_not be_has_date end it "should say it has a date id if it does" do Mail::Header.new('Date: Mon, 24 Nov 1997 14:22:01 -0800').should be_has_date end it "should not say it has a mime-version if it doesn't" do Mail::Header.new.should_not be_has_mime_version end it "should say it has a date id if it does" do Mail::Header.new('Mime-Version: 1.0').should be_has_mime_version end end describe "mime version handling" do it "should return the mime version of the email" do header = Mail::Header.new("Mime-Version: 1.0") header['mime-version'].value.should eq '1.0' end it "should return nil if no mime-version header field" do header = Mail::Header.new('To: bob') header['mime_version'].should eq nil end it "should return the transfer-encoding of the email" do header = Mail::Header.new("Content-Transfer-Encoding: Base64") header['content-transfer-encoding'].value.should eq 'Base64' end it "should return nil if no transfer-encoding header field" do header = Mail::Header.new header['content-transfer-encoding'].should eq nil end it "should return the content-description of the email" do header = Mail::Header.new("Content-Description: This is a description") header['Content-Description'].value.should eq 'This is a description' end it "should return nil if no content-description header field" do header = Mail::Header.new header['Content-Description'].should eq nil end end describe "configuration option .maximum_amount" do it "should be 1000 by default" do Mail::Header.maximum_amount.should == 1000 end it "should limit amount of parsed headers" do old_maximum_amount = Mail::Header.maximum_amount begin Mail::Header.maximum_amount = 10 begin $VERBOSE, old_verbose = nil, $VERBOSE header = Mail::Header.new("X-SubscriberID: 345\n" * 11) header.fields.size.should == 10 ensure $VERBOSE = old_verbose end ensure Mail::Header.maximum_amount = old_maximum_amount end end end end mail-2.5.4/spec/mail/mail_spec.rb000066400000000000000000000017271214434061600166110ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "mail" do it "should be able to be instantiated" do doing { Mail }.should_not raise_error end it "should be able to make a new email" do Mail.new.class.should eq Mail::Message end it "should accept headers and body" do # Full tests in Message Spec message = Mail.new do from 'mikel@me.com' to 'mikel@you.com' subject 'Hello there Mikel' body 'This is a body of text' end message.from.should eq ['mikel@me.com'] message.to.should eq ['mikel@you.com'] message.subject.should eq 'Hello there Mikel' message.body.to_s.should eq 'This is a body of text' end it "should read a file" do wrap_method = Mail.read(fixture('emails', 'plain_emails', 'raw_email.eml')).to_s file_method = Mail.new(File.open(fixture('emails', 'plain_emails', 'raw_email.eml'), 'rb', &:read)).to_s wrap_method.should eq file_method end end mail-2.5.4/spec/mail/message_spec.rb000066400000000000000000002226431214434061600173150ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe Mail::Message do def basic_email "To: mikel\r\nFrom: bob\r\nSubject: Hello!\r\n\r\nemail message\r\n" end describe "initialization" do it "should instantiate empty" do Mail::Message.new.class.should eq Mail::Message end it "should return a basic email" do mail = Mail.new mail = Mail.new(mail.to_s) mail.date.should_not be_blank mail.message_id.should_not be_blank mail.mime_version.should eq "1.0" mail.content_type.should eq "text/plain" mail.content_transfer_encoding.should eq "7bit" mail.subject.should be_blank mail.body.should be_blank end it "should instantiate with a string" do Mail::Message.new(basic_email).class.should eq Mail::Message end it "should allow us to pass it a block" do mail = Mail::Message.new do from 'mikel@me.com' to 'lindsaar@you.com' end mail.from.should eq ['mikel@me.com'] mail.to.should eq ['lindsaar@you.com'] end it "should initialize a body and header class even if called with nothing to begin with" do mail = Mail::Message.new mail.header.class.should eq Mail::Header mail.body.class.should eq Mail::Body end it "should not report basic emails as bounced" do Mail::Message.new.should_not be_bounced end it "should be able to parse a basic email" do doing { Mail.read(fixture('emails', 'plain_emails', 'basic_email.eml')) }.should_not raise_error end it "should be able to parse an email with @ in display name" do message = Mail.read(fixture('emails', 'plain_emails', 'raw_email_with_at_display_name.eml')) message.to.should eq ["smith@gmail.com", "raasdnil@gmail.com", "tom@gmail.com"] end it "should be able to parse an email with only blank lines as body" do doing { Mail.read(fixture('emails', 'error_emails', 'missing_body.eml')) }.should_not raise_error end it "should be able to parse an email with a funky date header" do doing { Mail.read(fixture('emails', 'error_emails', 'bad_date_header2.eml')) } end it 'should be able to invoke subject on a funky subject header' do Mail.read(fixture('emails', 'error_emails', 'bad_subject.eml')).subject end it 'should be able to parse an email missing an encoding' do Mail.read(fixture('emails', 'error_emails', 'must_supply_encoding.eml')) end it "should be able to parse every email example we have without raising an exception" do emails = Dir.glob( fixture('emails/**/*') ).delete_if { |f| File.directory?(f) } STDERR.stub!(:puts) # Don't want to get noisy about any warnings errors = false expected_failures = [] emails.each do |email| begin Mail.read(email) rescue => e unless expected_failures.include?(email) puts "Failed on email #{email}" puts "Failure was:\n#{e}\n\n" errors = true end end end errors.should be_false end it "should be able to parse a large email without raising an exception" do m = Mail.new m.add_file(:filename => "attachment.data", :content => "a" * (8 * 1024 * 1024)) raw_email = "From jamis_buck@byu.edu Mon May 2 16:07:05 2005\r\n#{m.to_s}" doing { Mail::Message.new(raw_email) }.should_not raise_error end it "should not raise a warning on having non US-ASCII characters in the header (should just handle it)" do STDERR.should_not_receive(:puts) Mail.read(fixture('emails', 'plain_emails', 'raw_email_string_in_date_field.eml')) end it "should raise a warning (and keep parsing) on having an incorrectly formatted header" do STDERR.should_receive(:puts).with("WARNING: Could not parse (and so ignoring) 'quite Delivered-To: xxx@xxx.xxx'") Mail.read(fixture('emails', 'plain_emails', 'raw_email_incorrect_header.eml')) end it "should read in an email message and basically parse it" do mail = Mail.read(fixture('emails', 'plain_emails', 'basic_email.eml')) mail.to.should eq ["raasdnil@gmail.com"] end it "should not fail parsing message with caps in content_type" do mail = Mail.read(fixture('emails', 'plain_emails', 'mix_caps_content_type.eml')) mail.content_type.should eq 'text/plain; charset=iso-8859-1' mail.main_type.should eq 'text' mail.sub_type.should eq 'plain' end it "should be able to pass an empty reply-to header" do mail = Mail.read(fixture('emails', 'error_emails', 'empty_in_reply_to.eml')) mail.in_reply_to.should be_blank end describe "YAML serialization" do before(:each) do @yaml_mail = Mail::Message.new(:to => 'someone@somewhere.com', :cc => 'someoneelse@somewhere.com', :bcc => 'someonesecret@somewhere.com', :body => 'body', :subject => 'subject') @smtp_settings = { :address=>"smtp.somewhere.net", :port=>"587", :domain=>"somewhere.net", :user_name=>"someone@somewhere.net", :password=>"password", :authentication=>:plain, :enable_starttls_auto => true, :openssl_verify_mode => nil, :ssl=>nil, :tls=>nil } @yaml_mail.delivery_method :smtp, @smtp_settings end it "should serialize the basic information to YAML" do yaml = @yaml_mail.to_yaml yaml_output = YAML.load(yaml) yaml_output['headers']['To'].should eq "someone@somewhere.com" yaml_output['headers']['Cc'].should eq "someoneelse@somewhere.com" yaml_output['headers']['Subject'].should eq "subject" yaml_output['headers']['Bcc'].should eq "someonesecret@somewhere.com" yaml_output['@body_raw'].should eq "body" yaml_output['@delivery_method'].should_not be_blank end it "should deserialize after serializing" do deserialized = Mail::Message.from_yaml(@yaml_mail.to_yaml) deserialized.should eq @yaml_mail deserialized.delivery_method.settings.should eq @smtp_settings end it "should serialize a Message with a custom delivery_handler" do @yaml_mail.delivery_handler = DeliveryAgent yaml = @yaml_mail.to_yaml yaml_output = YAML.load(yaml) yaml_output['delivery_handler'].should eq "DeliveryAgent" end it "should load a serialized delivery handler" do @yaml_mail.delivery_handler = DeliveryAgent deserialized = Mail::Message.from_yaml(@yaml_mail.to_yaml) deserialized.delivery_handler.should eq DeliveryAgent end it "should not deserialize a delivery_handler that does not exist" do yaml = @yaml_mail.to_yaml yaml_hash = YAML.load(yaml) yaml_hash['delivery_handler'] = "NotARealClass" deserialized = Mail::Message.from_yaml(yaml_hash.to_yaml) deserialized.delivery_handler.should be_nil end it "should handle multipart mail" do @yaml_mail.add_part Mail::Part.new(:content_type => 'text/html', :body => 'body') deserialized = Mail::Message.from_yaml(@yaml_mail.to_yaml) deserialized.should be_multipart deserialized.parts.each {|part| part.should be_a(Mail::Part)} deserialized.parts.map(&:body).should == ['body', 'body'] end end describe "splitting" do it "should split the body from the header" do message = Mail::Message.new("To: Example \r\n\r\nHello there\r\n") message.decoded.should == "Hello there\n" end it "should split when the body starts with a space" do message = Mail::Message.new("To: Example \r\n\r\n Hello there\r\n") message.decoded.should == " Hello there\n" end it "should split if the body starts with an empty line" do message = Mail::Message.new("To: Example \r\n\r\n\r\nHello there\r\n") message.decoded.should == "\nHello there\n" end it "should split if the body starts with a blank line" do message = Mail::Message.new("To: Example \r\n\r\n\t\r\nHello there\r\n") message.decoded.should == "\t\nHello there\n" end it 'should split after headers that contain "\r\n "' do message = Mail::Message.new("To: Example\r\n \r\n\r\n Hello there\r\n") message.decoded.should == " Hello there\n" end it 'should split only once if there are "\r\n\r\n"s in the body' do message = Mail::Message.new("To: Example \r\n\r\nHello\r\n\r\nthere\r\n") message.decoded.should == "Hello\n\nthere\n" end # N.B. this is not in any RFCs it "should split on a line with whitespace on it" do message = Mail::Message.new("To: Example \r\n \r\nHello there\r\n") message.decoded.should == "Hello there\n" end end end describe "envelope line handling" do it "should respond to 'envelope from'" do Mail::Message.new.should respond_to(:envelope_from) end it "should strip off the envelope from field if present" do message = Mail.read(fixture('emails', 'plain_emails', 'raw_email.eml')) message.envelope_from.should eq "jamis_buck@byu.edu" message.envelope_date.should eq ::DateTime.parse("Mon May 2 16:07:05 2005") end it "should strip off the envelope from field if present" do message = Mail.read(fixture('emails', 'plain_emails', 'raw_email.eml')) message.raw_envelope.should eq "jamis_buck@byu.edu Mon May 2 16:07:05 2005" message.from.should eq ["jamis@37signals.com"] end it "should not cause any problems if there is no envelope from present" do message = Mail.read(fixture('emails', 'plain_emails', 'basic_email.eml')) message.from.should eq ["test@lindsaar.net"] end it "should ignore a plain text body that starts with ^From" do m = Mail::Message.new("From: mikel@test.lindsaar.net\r\n\r\nThis is a way to break mail by putting\r\nFrom at the start of a body\r\nor elsewhere.") m.from.should_not be_nil m.from.should eq ['mikel@test.lindsaar.net'] end it "should handle a multipart message that has ^From in it" do m = Mail.read(fixture('emails', 'error_emails', 'cant_parse_from.eml')) m.from.should_not be_nil m.from.should eq ["News@InsideApple.Apple.com"] m.should be_multipart end end describe "accepting a plain text string email" do it "should accept some email text to parse and return an email" do mail = Mail::Message.new(basic_email) mail.class.should eq Mail::Message end it "should set a raw source instance variable to equal the passed in message" do mail = Mail::Message.new(basic_email) mail.raw_source.should eq basic_email end it "should set the raw source instance variable to '' if no message is passed in" do mail = Mail::Message.new mail.raw_source.should eq "" end it "should give the header class the header to parse" do header = Mail::Header.new("To: mikel\r\nFrom: bob\r\nSubject: Hello!") Mail::Header.should_receive(:new).with("To: mikel\r\nFrom: bob\r\nSubject: Hello!", 'UTF-8').and_return(header) Mail::Message.new(basic_email) end it "should give the header class the header to parse even if there is no body" do header = Mail::Header.new("To: mikel\r\nFrom: bob\r\nSubject: Hello!") Mail::Header.should_receive(:new).with("To: mikel\r\nFrom: bob\r\nSubject: Hello!", 'UTF-8').and_return(header) Mail::Message.new("To: mikel\r\nFrom: bob\r\nSubject: Hello!") end it "should give the body class the body to parse" do body = Mail::Body.new("email message") Mail::Body.should_receive(:new).with("email message\r\n").and_return(body) mail = Mail::Message.new(basic_email) mail.body #body calculates now lazy so need to ask for it end it "should still ask the body for a new instance even though these is nothing to parse, yet" do body = Mail::Body.new('') Mail::Body.should_receive(:new).and_return(body) Mail::Message.new("To: mikel\r\nFrom: bob\r\nSubject: Hello!") end it "should give the header the part before the line without spaces and the body the part without" do header = Mail::Header.new("To: mikel") body = Mail::Body.new("G'Day!") Mail::Header.should_receive(:new).with("To: mikel", 'UTF-8').and_return(header) Mail::Body.should_receive(:new).with("G'Day!").and_return(body) mail = Mail::Message.new("To: mikel\r\n\r\nG'Day!") mail.body #body calculates now lazy so need to ask for it end it "should give allow for whitespace on the gap line between header and body" do header = Mail::Header.new("To: mikel") body = Mail::Body.new("G'Day!") Mail::Header.should_receive(:new).with("To: mikel", 'UTF-8').and_return(header) Mail::Body.should_receive(:new).with("G'Day!").and_return(body) mail = Mail::Message.new("To: mikel\r\n \r\nG'Day!") mail.body #body calculates now lazy so need to ask for it end it "should allow for whitespace at the start of the email" do mail = Mail.new("\r\n\r\nFrom: mikel\r\n\r\nThis is the body") mail.body.to_s.should eq 'This is the body' mail.from.should eq ['mikel'] end it "should read in an email message with the word 'From' in it multiple times and parse it" do mail = Mail.read(fixture('emails', 'mime_emails', 'two_from_in_message.eml')) mail.to.should_not be_nil mail.to.should eq ["tester2@test.com"] end it "should parse non-UTF8 sources" do mail = Mail.read(fixture('emails', 'multi_charset', 'japanese_shiftjis.eml')) mail.to.should eq ["raasdnil@gmail.com"] mail.decoded.should eq "すみません。\n\n" end end describe "directly setting values of a message" do describe "accessing fields directly" do before(:each) do @mail = Mail::Message.new end it "should allow you to grab field objects if you really want to" do @mail.header_fields.class.should eq Mail::FieldList end it "should give you back the fields in the header" do @mail['bar'] = 'abcd' @mail.header_fields.length.should eq 1 @mail['foo'] = '4321' @mail.header_fields.length.should eq 2 end it "should delete a field if it is set to nil" do @mail['foo'] = '4321' @mail.header_fields.length.should eq 1 @mail['foo'] = nil @mail.header_fields.length.should eq 0 end end describe "with :method=" do before(:each) do @mail = Mail::Message.new end it "should return the to field" do @mail.to = "mikel" @mail.to.should eq ["mikel"] end it "should return the from field" do @mail.from = "bob" @mail.from.should eq ["bob"] end it "should return the subject" do @mail.subject = "Hello!" @mail.subject.should eq "Hello!" end it "should return the body decoded with to_s" do @mail.body "email message\r\n" @mail.body.to_s.should eq "email message\n" end it "should return the body encoded if asked for" do @mail.body "email message\r\n" @mail.body.encoded.should eq "email message\r\n" end it "should return the body decoded if asked for" do @mail.body "email message\r\n" @mail.body.decoded.should eq "email message\n" end end describe "with :method(value)" do before(:each) do @mail = Mail::Message.new end it "should return the to field" do @mail.to "mikel" @mail.to.should eq ["mikel"] end it "should return the from field" do @mail.from "bob" @mail.from.should eq ["bob"] end it "should return the subject" do @mail.subject "Hello!" @mail.subject.should eq "Hello!" end it "should return the body decoded with to_s" do @mail.body "email message\r\n" @mail.body.to_s.should eq "email message\n" end it "should return the body encoded if asked for" do @mail.body "email message\r\n" @mail.body.encoded.should eq "email message\r\n" end it "should return the body decoded if asked for" do @mail.body "email message\r\n" @mail.body.decoded.should eq "email message\n" end end describe "setting arbitrary headers" do before(:each) do @mail = Mail::Message.new end it "should allow you to set them" do doing {@mail['foo'] = 1234}.should_not raise_error end it "should allow you to read arbitrary headers" do @mail['foo'] = 1234 @mail['foo'].value.to_s.should eq '1234' end it "should instantiate a new Header" do @mail['foo'] = 1234 @mail.header_fields.first.class.should eq Mail::Field end end describe "replacing header values" do it "should allow you to replace a from field" do mail = Mail.new mail.from.should eq nil mail.from = 'mikel@test.lindsaar.net' mail.from.should eq ['mikel@test.lindsaar.net'] mail.from = 'bob@test.lindsaar.net' mail.from.should eq ['bob@test.lindsaar.net'] end it "should maintain the class of the field" do mail = Mail.new mail.from = 'mikel@test.lindsaar.net' mail[:from].field.class.should eq Mail::FromField mail.from = 'bob@test.lindsaar.net' mail[:from].field.class.should eq Mail::FromField end end describe "setting headers" do it "should accept them in block form" do message = Mail.new do bcc 'mikel@bcc.lindsaar.net' cc 'mikel@cc.lindsaar.net' comments 'this is a comment' date '12 Aug 2009 00:00:01 GMT' from 'mikel@from.lindsaar.net' in_reply_to '<1234@in_reply_to.lindsaar.net>' keywords 'test, "of the new mail", system' message_id '<1234@message_id.lindsaar.net>' received 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT' references '<1234@references.lindsaar.net>' reply_to 'mikel@reply-to.lindsaar.net' resent_bcc 'mikel@resent-bcc.lindsaar.net' resent_cc 'mikel@resent-cc.lindsaar.net' resent_date '12 Aug 2009 00:00:03 GMT' resent_from 'mikel@resent-from.lindsaar.net' resent_message_id '<1234@resent_message_id.lindsaar.net>' resent_sender 'mikel@resent-sender.lindsaar.net' resent_to 'mikel@resent-to.lindsaar.net' sender 'mikel@sender.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' content_type 'text/plain; charset=UTF-8' content_transfer_encoding '7bit' content_description 'This is a test' content_disposition 'attachment; filename=File' content_id '<1234@message_id.lindsaar.net>' mime_version '1.0' body 'This is a body of text' end message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should accept them in assignment form" do message = Mail.new message.bcc = 'mikel@bcc.lindsaar.net' message.cc = 'mikel@cc.lindsaar.net' message.comments = 'this is a comment' message.date = '12 Aug 2009 00:00:01 GMT' message.from = 'mikel@from.lindsaar.net' message.in_reply_to = '<1234@in_reply_to.lindsaar.net>' message.keywords = 'test, "of the new mail", system' message.message_id = '<1234@message_id.lindsaar.net>' message.received = 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT' message.references = '<1234@references.lindsaar.net>' message.reply_to = 'mikel@reply-to.lindsaar.net' message.resent_bcc = 'mikel@resent-bcc.lindsaar.net' message.resent_cc = 'mikel@resent-cc.lindsaar.net' message.resent_date = '12 Aug 2009 00:00:03 GMT' message.resent_from = 'mikel@resent-from.lindsaar.net' message.resent_message_id = '<1234@resent_message_id.lindsaar.net>' message.resent_sender = 'mikel@resent-sender.lindsaar.net' message.resent_to = 'mikel@resent-to.lindsaar.net' message.sender = 'mikel@sender.lindsaar.net' message.subject = 'Hello there Mikel' message.to = 'mikel@to.lindsaar.net' message.content_type = 'text/plain; charset=UTF-8' message.content_transfer_encoding = '7bit' message.content_description = 'This is a test' message.content_disposition = 'attachment; filename=File' message.content_id = '<1234@message_id.lindsaar.net>' message.mime_version = '1.0' message.body = 'This is a body of text' message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should accept them in key, value form as symbols" do message = Mail.new message[:bcc] = 'mikel@bcc.lindsaar.net' message[:cc] = 'mikel@cc.lindsaar.net' message[:comments] = 'this is a comment' message[:date] = '12 Aug 2009 00:00:01 GMT' message[:from] = 'mikel@from.lindsaar.net' message[:in_reply_to] = '<1234@in_reply_to.lindsaar.net>' message[:keywords] = 'test, "of the new mail", system' message[:message_id] = '<1234@message_id.lindsaar.net>' message[:received] = 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT' message[:references] = '<1234@references.lindsaar.net>' message[:reply_to] = 'mikel@reply-to.lindsaar.net' message[:resent_bcc] = 'mikel@resent-bcc.lindsaar.net' message[:resent_cc] = 'mikel@resent-cc.lindsaar.net' message[:resent_date] = '12 Aug 2009 00:00:03 GMT' message[:resent_from] = 'mikel@resent-from.lindsaar.net' message[:resent_message_id] = '<1234@resent_message_id.lindsaar.net>' message[:resent_sender] = 'mikel@resent-sender.lindsaar.net' message[:resent_to] = 'mikel@resent-to.lindsaar.net' message[:sender] = 'mikel@sender.lindsaar.net' message[:subject] = 'Hello there Mikel' message[:to] = 'mikel@to.lindsaar.net' message[:content_type] = 'text/plain; charset=UTF-8' message[:content_transfer_encoding] = '7bit' message[:content_description] = 'This is a test' message[:content_disposition] = 'attachment; filename=File' message[:content_id] = '<1234@message_id.lindsaar.net>' message[:mime_version]= '1.0' message[:body] = 'This is a body of text' message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should accept them in key, value form as strings" do message = Mail.new message['bcc'] = 'mikel@bcc.lindsaar.net' message['cc'] = 'mikel@cc.lindsaar.net' message['comments'] = 'this is a comment' message['date'] = '12 Aug 2009 00:00:01 GMT' message['from'] = 'mikel@from.lindsaar.net' message['in_reply_to'] = '<1234@in_reply_to.lindsaar.net>' message['keywords'] = 'test, "of the new mail", system' message['message_id'] = '<1234@message_id.lindsaar.net>' message['received'] = 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT' message['references'] = '<1234@references.lindsaar.net>' message['reply_to'] = 'mikel@reply-to.lindsaar.net' message['resent_bcc'] = 'mikel@resent-bcc.lindsaar.net' message['resent_cc'] = 'mikel@resent-cc.lindsaar.net' message['resent_date'] = '12 Aug 2009 00:00:03 GMT' message['resent_from'] = 'mikel@resent-from.lindsaar.net' message['resent_message_id'] = '<1234@resent_message_id.lindsaar.net>' message['resent_sender'] = 'mikel@resent-sender.lindsaar.net' message['resent_to'] = 'mikel@resent-to.lindsaar.net' message['sender'] = 'mikel@sender.lindsaar.net' message['subject'] = 'Hello there Mikel' message['to'] = 'mikel@to.lindsaar.net' message['content_type'] = 'text/plain; charset=UTF-8' message['content_transfer_encoding'] = '7bit' message['content_description'] = 'This is a test' message['content_disposition'] = 'attachment; filename=File' message['content_id'] = '<1234@message_id.lindsaar.net>' message['mime_version'] = '1.0' message['body'] = 'This is a body of text' message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should accept them as a hash with symbols" do message = Mail.new({ :bcc => 'mikel@bcc.lindsaar.net', :cc => 'mikel@cc.lindsaar.net', :comments => 'this is a comment', :date => '12 Aug 2009 00:00:01 GMT', :from => 'mikel@from.lindsaar.net', :in_reply_to => '<1234@in_reply_to.lindsaar.net>', :keywords => 'test, "of the new mail", system', :message_id => '<1234@message_id.lindsaar.net>', :received => 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT', :references => '<1234@references.lindsaar.net>', :reply_to => 'mikel@reply-to.lindsaar.net', :resent_bcc => 'mikel@resent-bcc.lindsaar.net', :resent_cc => 'mikel@resent-cc.lindsaar.net', :resent_date => '12 Aug 2009 00:00:03 GMT', :resent_from => 'mikel@resent-from.lindsaar.net', :resent_message_id => '<1234@resent_message_id.lindsaar.net>', :resent_sender => 'mikel@resent-sender.lindsaar.net', :resent_to => 'mikel@resent-to.lindsaar.net', :sender => 'mikel@sender.lindsaar.net', :subject => 'Hello there Mikel', :to => 'mikel@to.lindsaar.net', :content_type => 'text/plain; charset=UTF-8', :content_transfer_encoding => '7bit', :content_description => 'This is a test', :content_disposition => 'attachment; filename=File', :content_id => '<1234@message_id.lindsaar.net>', :mime_version => '1.0', :body => 'This is a body of text' }) message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should accept them as a hash with strings" do message = Mail.new({ 'bcc' => 'mikel@bcc.lindsaar.net', 'cc' => 'mikel@cc.lindsaar.net', 'comments' => 'this is a comment', 'date' => '12 Aug 2009 00:00:01 GMT', 'from' => 'mikel@from.lindsaar.net', 'in_reply_to' => '<1234@in_reply_to.lindsaar.net>', 'keywords' => 'test, "of the new mail", system', 'message_id' => '<1234@message_id.lindsaar.net>', 'received' => 'from machine.example by x.y.test; 12 Aug 2009 00:00:02 GMT', 'references' => '<1234@references.lindsaar.net>', 'reply_to' => 'mikel@reply-to.lindsaar.net', 'resent_bcc' => 'mikel@resent-bcc.lindsaar.net', 'resent_cc' => 'mikel@resent-cc.lindsaar.net', 'resent_date' => '12 Aug 2009 00:00:03 GMT', 'resent_from' => 'mikel@resent-from.lindsaar.net', 'resent_message_id' => '<1234@resent_message_id.lindsaar.net>', 'resent_sender' => 'mikel@resent-sender.lindsaar.net', 'resent_to' => 'mikel@resent-to.lindsaar.net', 'sender' => 'mikel@sender.lindsaar.net', 'subject' => 'Hello there Mikel', 'to' => 'mikel@to.lindsaar.net', 'content_type' => 'text/plain; charset=UTF-8', 'content_transfer_encoding' => '7bit', 'content_description' => 'This is a test', 'content_disposition' => 'attachment; filename=File', 'content_id' => '<1234@message_id.lindsaar.net>', 'mime_version' => '1.0', 'body' => 'This is a body of text' }) message.bcc.should eq ['mikel@bcc.lindsaar.net'] message.cc.should eq ['mikel@cc.lindsaar.net'] message.comments.should eq 'this is a comment' message.date.should eq DateTime.parse('12 Aug 2009 00:00:01 GMT') message.from.should eq ['mikel@from.lindsaar.net'] message.in_reply_to.should eq '1234@in_reply_to.lindsaar.net' message.keywords.should eq ["test", "of the new mail", "system"] message.message_id.should eq '1234@message_id.lindsaar.net' message.received.date_time.should eq DateTime.parse('12 Aug 2009 00:00:02 GMT') message.references.should eq '1234@references.lindsaar.net' message.reply_to.should eq ['mikel@reply-to.lindsaar.net'] message.resent_bcc.should eq ['mikel@resent-bcc.lindsaar.net'] message.resent_cc.should eq ['mikel@resent-cc.lindsaar.net'] message.resent_date.should eq DateTime.parse('12 Aug 2009 00:00:03 GMT') message.resent_from.should eq ['mikel@resent-from.lindsaar.net'] message.resent_message_id.should eq '1234@resent_message_id.lindsaar.net' message.resent_sender.should eq ['mikel@resent-sender.lindsaar.net'] message.resent_to.should eq ['mikel@resent-to.lindsaar.net'] message.sender.should eq 'mikel@sender.lindsaar.net' message.subject.should eq 'Hello there Mikel' message.to.should eq ['mikel@to.lindsaar.net'] message.content_type.should eq 'text/plain; charset=UTF-8' message.content_transfer_encoding.should eq '7bit' message.content_description.should eq 'This is a test' message.content_disposition.should eq 'attachment; filename=File' message.content_id.should eq '<1234@message_id.lindsaar.net>' message.mime_version.should eq '1.0' message.body.to_s.should eq 'This is a body of text' end it "should let you set custom headers with a :headers => {hash}" do message = Mail.new(:headers => {'custom-header' => 'mikel'}) message['custom-header'].decoded.should eq 'mikel' end it "should assign the body to a part on creation" do message = Mail.new do part({:content_type=>"multipart/alternative", :content_disposition=>"inline", :body=>"Nothing to see here."}) end message.parts.first.body.decoded.should eq "Nothing to see here." end it "should not overwrite bodies on creation" do message = Mail.new do part({:content_type=>"multipart/alternative", :content_disposition=>"inline", :body=>"Nothing to see here."}) do |p| p.part :content_type => "text/html", :body => "test HTML
    " end end message.parts.first.parts[0].body.decoded.should eq "Nothing to see here." message.parts.first.parts[1].body.decoded.should eq "test HTML
    " message.encoded.should match %r{Nothing to see here\.} message.encoded.should match %r{test HTML
    } end it "should allow you to init on an array of addresses from a hash" do mail = Mail.new(:to => ['test1@lindsaar.net', 'Mikel ']) mail.to.should eq ['test1@lindsaar.net', 'test2@lindsaar.net'] end it "should allow you to init on an array of addresses directly" do mail = Mail.new mail.to = ['test1@lindsaar.net', 'Mikel '] mail.to.should eq ['test1@lindsaar.net', 'test2@lindsaar.net'] end it "should allow you to init on an array of addresses directly" do mail = Mail.new mail[:to] = ['test1@lindsaar.net', 'Mikel '] mail.to.should eq ['test1@lindsaar.net', 'test2@lindsaar.net'] end end end describe "handling missing required fields:" do describe "every email" do describe "Message-ID" do it "should say if it has a message id" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.should_not be_has_message_id end it "should preserve any message id that you pass it if add_message_id is called explicitly" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_message_id("") mail.to_s.should =~ /Message-ID: \r\n/ end it "should generate a random message ID if nothing is passed to add_message_id" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_message_id mail.to_s.should =~ /Message-ID: <[\w]+@#{::Socket.gethostname}.mail>\r\n/ end it "should make an email and inject a message ID if none was set if told to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end (mail.to_s =~ /Message-ID: <.+@.+.mail>/i).should_not be_nil end it "should add the message id to the message permanently once sent to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s mail.should be_has_message_id end it "should add a body part if it is missing" do mail = Mail.new mail.to_s mail.body.class.should eq Mail::Body end end describe "Date" do it "should say if it has a date" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.should_not be_has_date end it "should preserve any date that you pass it if add_date is called explicitly" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_date("Mon, 24 Nov 1997 14:22:01 -0800") mail.to_s.should =~ /Date: Mon, 24 Nov 1997 14:22:01 -0800/ end it "should generate a current date if nothing is passed to add_date" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_date mail.to_s.should =~ /Date: \w{3}, [\s\d]\d \w{3} \d{4} \d{2}:\d{2}:\d{2} [-+]?\d{4}\r\n/ end it "should make an email and inject a date if none was set if told to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s.should =~ /Date: \w{3}, [\s\d]\d \w{3} \d{4} \d{2}:\d{2}:\d{2} [-+]?\d{4}\r\n/ end it "should add the date to the message permanently once sent to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s mail.should be_has_date end end end describe "mime emails" do describe "mime-version" do it "should say if it has a mime-version" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.should_not be_has_mime_version end it "should preserve any mime version that you pass it if add_mime_version is called explicitly" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_mime_version("3.0 (This is an unreal version number)") mail.to_s.should =~ /Mime-Version: 3.0\r\n/ end it "should generate a mime version if nothing is passed to add_date" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.add_mime_version mail.to_s.should =~ /Mime-Version: 1.0\r\n/ end it "should make an email and inject a mime_version if none was set if told to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s.should =~ /Mime-Version: 1.0\r\n/ end it "should add the mime version to the message permanently once sent to_s" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s mail.should be_has_mime_version end end describe "content type" do it "should say if it has a content type" do mail = Mail.new('Content-Type: text/plain') mail.should be_has_content_type end it "should say if it does not have a content type" do mail = Mail.new mail.should_not be_has_content_type end it "should say if it has a charset" do mail = Mail.new('Content-Type: text/plain; charset=US-ASCII') mail.should be_has_charset end it "should say if it has a charset" do mail = Mail.new('Content-Type: text/plain') mail.should_not be_has_charset end it "should not raise a warning if there is no charset defined and only US-ASCII chars" do body = "This is plain text US-ASCII" mail = Mail.new mail.body = body STDERR.should_not_receive(:puts) mail.to_s end it "should set the content type to text/plain; charset=us-ascii" do body = "This is plain text US-ASCII" mail = Mail.new mail.body = body mail.to_s =~ %r{Content-Type: text/plain; charset=US-ASCII} end it "should not set the charset if the file is an attachment" do body = "This is plain text US-ASCII" mail = Mail.new mail.body = body mail.content_disposition = 'attachment; filename="foo.jpg"' mail.to_s =~ %r{Content-Type: text/plain;\r\n} end it "should raise a warning if there is no content type and there is non ascii chars and default to text/plain, UTF-8" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.body = body mail.content_transfer_encoding = "8bit" STDERR.should_receive(:puts).with(/Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect./m) mail.to_s =~ %r{Content-Type: text/plain; charset=UTF-8} end it "should raise a warning if there is no charset parameter and there is non ascii chars and default to text/plain, UTF-8" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.body = body mail.content_type = "text/plain" mail.content_transfer_encoding = "8bit" STDERR.should_receive(:puts).with(/Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect./m) mail.to_s =~ %r{Content-Type: text/plain; charset=UTF-8} end it "should not raise a warning if there is a charset defined and there is non ascii chars" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.body = body mail.content_transfer_encoding = "8bit" mail.content_type = "text/plain; charset=UTF-8" STDERR.should_not_receive(:puts) mail.to_s end it "should be able to set a content type with an array and hash" do mail = Mail.new mail.content_type = ["text", "plain", { :charset => 'US-ASCII' }] mail[:content_type].encoded.should eq %Q[Content-Type: text/plain;\r\n\scharset=US-ASCII\r\n] mail.content_type_parameters.should eql({"charset" => "US-ASCII"}) end it "should be able to set a content type with an array and hash with a non-usascii field" do mail = Mail.new mail.content_type = ["text", "plain", { :charset => 'UTF-8' }] mail[:content_type].encoded.should eq %Q[Content-Type: text/plain;\r\n\scharset=UTF-8\r\n] mail.content_type_parameters.should eql({"charset" => "UTF-8"}) end it "should allow us to specify a content type in a block" do mail = Mail.new { content_type ["text", "plain", { "charset" => "UTF-8" }] } mail.content_type_parameters.should eql({"charset" => "UTF-8"}) end end describe "content-transfer-encoding" do it "should use 7bit for only US-ASCII chars" do body = "This is plain text US-ASCII" mail = Mail.new mail.body = body mail.to_s.should =~ %r{Content-Transfer-Encoding: 7bit} end it "should use QP transfer encoding for 8bit text with only a few 8bit characters" do body = "Maxfeldstraße 5, 90409 Nürnberg" mail = Mail.new mail.charset = "UTF-8" mail.body = body mail.to_s.should =~ %r{Content-Transfer-Encoding: quoted-printable} end it "should use base64 transfer encoding for 8-bit text with lots of 8bit characters" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.charset = "UTF-8" mail.body = body mail.content_type = "text/plain; charset=utf-8" mail.should be_has_content_type mail.should be_has_charset mail.to_s.should =~ %r{Content-Transfer-Encoding: base64} end it "should not use 8bit transfer encoding when 8bit is allowed" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.charset = "UTF-8" mail.body = body mail.content_type = "text/plain; charset=utf-8" mail.transport_encoding = "8bit" mail.to_s.should =~ %r{Content-Transfer-Encoding: 8bit} end end end end describe "output" do it "should make an email and allow you to call :to_s on it to get a string" do mail = Mail.new do from 'mikel@test.lindsaar.net' to 'you@test.lindsaar.net' subject 'This is a test email' body 'This is a body of the email' end mail.to_s.should =~ /From: mikel@test.lindsaar.net\r\n/ mail.to_s.should =~ /To: you@test.lindsaar.net\r\n/ mail.to_s.should =~ /Subject: This is a test email\r\n/ mail.to_s.should =~ /This is a body of the email/ end it "should raise an error and message if you try and call decoded on a multipart email" do mail = Mail.new do to 'mikel@test.lindsaar.net' from 'bob@test.lindsaar.net' subject 'Multipart email' text_part do body 'This is plain text' end html_part do content_type 'text/html; charset=UTF-8' body '

    This is HTML

    ' end end doing { mail.decoded }.should raise_error(NoMethodError, 'Can not decode an entire message, try calling #decoded on the various fields and body or parts if it is a multipart message.') end it "should return the decoded body if you call decode and the message is not multipart" do mail = Mail.new do content_transfer_encoding 'base64' body "VGhlIGJvZHk=\n" end mail.decoded.should eq "The body" end describe "decoding bodies" do it "should not change a body on decode if not given an encoding type to decode" do mail = Mail.new do body "The=3Dbody" end mail.body.decoded.should eq "The=3Dbody" mail.body.encoded.should eq "The=3Dbody" end it "should change a body on decode if given an encoding type to decode" do mail = Mail.new do content_transfer_encoding 'quoted-printable' body "The=3Dbody" end mail.body.decoded.should eq "The=body" mail.body.encoded.should eq "The=3Dbody=\r\n" end it "should change a body on decode if given an encoding type to decode" do mail = Mail.new do content_transfer_encoding 'base64' body "VGhlIGJvZHk=\n" end mail.body.decoded.should eq "The body" mail.body.encoded.should eq "VGhlIGJvZHk=\r\n" end it 'should not strip the raw mail source in case the trailing \r\n is meaningful' do Mail.new("Content-Transfer-Encoding: quoted-printable;\r\n\r\nfoo=\r\nbar=\r\nbaz=\r\n").decoded.should eq 'foobarbaz' end end end describe "text messages" do def message_with_iso_8859_1_charset "From: test@example.com\r\n"+ "Content-Type: text/plain; charset=iso-8859-1\r\n"+ "Content-Transfer-Encoding: quoted-printable\r\n"+ "Date: Tue, 27 Sep 2011 16:59:48 +0100 (BST)\r\n"+ "Subject: test\r\n\r\n"+ "Am=E9rica" end before(:each) do @message = Mail.new(message_with_iso_8859_1_charset) end it "should be decoded using content type charset" do @message.decoded.should eq "América" end it "should respond true to text?" do @message.text?.should eq true end end describe "helper methods" do describe "==" do before(:each) do # Ensure specs don't randomly fail due to messages being generated 1 second apart time = Time.now Time.stub!(:now).and_return(time) end it "should be implemented" do doing { Mail.new == Mail.new }.should_not raise_error end it "should ignore the message id value if both have a nil message id" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") m1.should eq m2 end it "should ignore the message id value if self has a nil message id" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m1.should eq m2 end it "should ignore the message id value if other has a nil message id" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") m1.should eq m2 end it "should not be == if both emails have different Message IDs" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <4321@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m1.should_not eq m2 end it "should preserve the message id of self if set" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") (m1 == m2).should be_true # confirm the side-effects of the comparison m1.message_id.should eq '1234@test.lindsaar.net' end it "should preserve the message id of other if set" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") (m1 == m2).should be_true # confirm the side-effects of the comparison m2.message_id.should eq '1234@test.lindsaar.net' end it "should preserve the message id of both if set" do m1 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <4321@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") m2 = Mail.new("To: mikel@test.lindsaar.net\r\nMessage-ID: <1234@test.lindsaar.net>\r\nSubject: Yo!\r\n\r\nHello there") (m1 == m2).should be_false # confirm the side-effects of the comparison m1.message_id.should eq '4321@test.lindsaar.net' m2.message_id.should eq '1234@test.lindsaar.net' end end it "should implement the spaceship operator on the date field" do now = Time.now mail1 = Mail.new do date(now) end mail2 = Mail.new do date(now - 10) # Make mail2 10 seconds 'older' end [mail2, mail1].sort.should eq [mail2, mail1] end it "should have a destinations method" do mail = Mail.new do to 'mikel@test.lindsaar.net' cc 'bob@test.lindsaar.net' bcc 'sam@test.lindsaar.net' end mail.destinations.length.should eq 3 end it "should have a from_addrs method" do mail = Mail.new do from 'mikel@test.lindsaar.net' end mail.from_addrs.length.should eq 1 end it "should have a from_addrs method that is empty if nil" do mail = Mail.new do end mail.from_addrs.length.should eq 0 end it "should have a to_addrs method" do mail = Mail.new do to 'mikel@test.lindsaar.net' end mail.to_addrs.length.should eq 1 end it "should have a to_addrs method that is empty if nil" do mail = Mail.new do end mail.to_addrs.length.should eq 0 end it "should have a cc_addrs method" do mail = Mail.new do cc 'bob@test.lindsaar.net' end mail.cc_addrs.length.should eq 1 end it "should have a cc_addrs method that is empty if nil" do mail = Mail.new do end mail.cc_addrs.length.should eq 0 end it "should have a bcc_addrs method" do mail = Mail.new do bcc 'sam@test.lindsaar.net' end mail.bcc_addrs.length.should eq 1 end it "should have a bcc_addrs method that is empty if nil" do mail = Mail.new do end mail.bcc_addrs.length.should eq 0 end it "should give destinations even if some of the fields are blank" do mail = Mail.new do to 'mikel@test.lindsaar.net' end mail.destinations.length.should eq 1 end it "should be able to encode with only one destination" do mail = Mail.new do to 'mikel@test.lindsaar.net' end mail.encoded end end describe "nested parts" do it "should provide a way to instantiate a new part as you go down" do mail = Mail.new do to 'mikel@test.lindsaar.net' subject "nested multipart" from "test@example.com" content_type "multipart/mixed" part :content_type => "multipart/alternative", :content_disposition => "inline", :headers => { "foo" => "bar" } do |p| p.part :content_type => "text/plain", :body => "test text\nline #2" p.part :content_type => "text/html", :body => "test HTML
    \nline #2" end end mail.parts.first.should be_multipart mail.parts.first.parts.length.should eq 2 mail.parts.first.parts[0][:content_type].string.should eq "text/plain" mail.parts.first.parts[0].body.decoded.should eq "test text\nline #2" mail.parts.first.parts[1][:content_type].string.should eq "text/html" mail.parts.first.parts[1].body.decoded.should eq "test HTML
    \nline #2" end end describe "deliver" do it "should return self after delivery" do mail = Mail.new mail.perform_deliveries = false mail.deliver.should eq mail end class DeliveryAgent def self.deliver_mail(mail) end end it "should pass self to a delivery agent" do mail = Mail.new mail.delivery_handler = DeliveryAgent DeliveryAgent.should_receive(:deliver_mail).with(mail) mail.deliver end class ObserverAgent def self.delivered_email(mail) end end it "should inform observers that the mail was sent" do mail = Mail.new(:from => 'bob@example.com', :to => 'bobette@example.com') mail.delivery_method :test Mail.register_observer(ObserverAgent) ObserverAgent.should_receive(:delivered_email).with(mail) mail.deliver end it "should inform observers that the mail was sent, even if a delivery agent is used" do mail = Mail.new mail.delivery_handler = DeliveryAgent Mail.register_observer(ObserverAgent) ObserverAgent.should_receive(:delivered_email).with(mail) mail.deliver end class InterceptorAgent @@intercept = false def self.intercept=(val) @@intercept = val end def self.delivering_email(mail) if @@intercept mail.to = 'bob@example.com' end end end it "should pass to the interceptor the email just before it gets sent" do mail = Mail.new(:from => 'bob@example.com', :to => 'bobette@example.com') mail.delivery_method :test Mail.register_interceptor(InterceptorAgent) InterceptorAgent.should_receive(:delivering_email).with(mail) InterceptorAgent.intercept = true mail.deliver InterceptorAgent.intercept = false end it "should let the interceptor that the mail was sent" do mail = Mail.new(:from => 'bob@example.com', :to => 'bobette@example.com') mail.to = 'fred@example.com' mail.delivery_method :test Mail.register_interceptor(InterceptorAgent) InterceptorAgent.intercept = true mail.deliver InterceptorAgent.intercept = false mail.to.should eq ['bob@example.com'] end end describe "error handling" do it "should collect up any of its fields' errors" do mail = Mail.new("Content-Transfer-Encoding: vl@d\r\nReply-To: a b b\r\n") mail.errors.should_not be_blank mail.errors.size.should eq 2 mail.errors[0][0].should eq 'Content-Transfer-Encoding' mail.errors[0][1].should eq 'vl@d' mail.errors[1][0].should eq 'Reply-To' mail.errors[1][1].should eq 'a b b' end end describe "header case should be preserved" do it "should handle mail[] and keep the header case" do mail = Mail.new mail['X-Foo-Bar'] = "Some custom text" mail.to_s.should match(/X-Foo-Bar: Some custom text/) end end describe "parsing emails with non usascii in the header" do it "should work" do mail = Mail.new('From: "Foo áëô îü" ') mail.from.should eq ['extended@example.net'] mail[:from].decoded.should eq '"Foo áëô îü" ' mail[:from].encoded.should eq "From: =?UTF-8?B?Rm9vIMOhw6vDtCDDrsO8?= \r\n" end end describe "ordering messages" do it "should put all attachments as the last item" do # XXX: AFAICT, this is not actually working. The code does not appear to implement this. -- singpolyma mail = Mail.new mail.attachments['image.png'] = "\302\302\302\302" p = Mail::Part.new(:content_type => 'multipart/alternative') p.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML TEXT')) p.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN TEXT')) mail.add_part(p) mail.encoded mail.parts[0].mime_type.should eq "multipart/alternative" mail.parts[0].parts[0].mime_type.should eq "text/plain" mail.parts[0].parts[1].mime_type.should eq "text/html" mail.parts[1].mime_type.should eq "image/png" end end describe "attachment query methods" do it "shouldn't die with an invalid Content-Disposition header" do mail = Mail.new('Content-Disposition: invalid') doing { mail.attachment? }.should_not raise_error end it "shouldn't die with an invalid Content-Type header" do mail = Mail.new('Content-Type: invalid/invalid; charset="iso-8859-1"') mail.attachment? doing { mail.attachment? }.should_not raise_error end end describe "without_attachments!" do it "should delete all attachments" do emails_with_attachments = ['content_disposition', 'content_location', 'pdf', 'with_encoded_name', 'with_quoted_filename'] emails_with_attachments.each { |email| mail = Mail.read(fixture(File.join('emails', 'attachment_emails', "attachment_#{email}.eml"))) mail_length_with_attachments = mail.to_s.length mail.has_attachments?.should be_true mail.without_attachments! mail_length_without_attachments = mail.to_s.length mail_length_without_attachments.should be < mail_length_with_attachments mail.has_attachments?.should be_false } end end describe "replying" do describe "to a basic message" do before do @mail = Mail.read(fixture('emails', 'plain_emails', 'basic_email.eml')) end it "should create a new message" do @mail.reply.should be_a_kind_of(Mail::Message) end it "should be in-reply-to the original message" do @mail.reply.in_reply_to.should eq '6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net' end it "should reference the original message" do @mail.reply.references.should eq '6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net' end it "should RE: the original subject" do @mail.reply.subject.should eq 'RE: Testing 123' end it "should be sent to the original sender" do @mail.reply.to.should eq ['test@lindsaar.net'] @mail.reply[:to].to_s.should eq 'Mikel Lindsaar ' end it "should be sent from the original recipient" do @mail.reply.from.should eq ['raasdnil@gmail.com'] @mail.reply[:from].to_s.should eq 'Mikel Lindsaar ' end it "should accept args" do @mail.reply(:from => 'Donald Ball ').from.should eq ['donald.ball@gmail.com'] end it "should accept a block" do @mail.reply { from('Donald Ball ') }.from.should eq ['donald.ball@gmail.com'] end end describe "to a message with an explicit reply-to address" do before do @mail = Mail.read(fixture('emails', 'rfc2822', 'example06.eml')) end it "should be sent to the reply-to address" do @mail.reply[:to].to_s.should eq '"Mary Smith: Personal Account" ' end end describe "to a message with more than one recipient" do before do @mail = Mail.read(fixture('emails', 'rfc2822', 'example03.eml')) end it "should be sent from the first to address" do @mail.reply[:from].to_s.should eq 'Mary Smith ' end end describe "to a reply" do before do @mail = Mail.read(fixture('emails', 'plain_emails', 'raw_email_reply.eml')) end it "should be in-reply-to the original message" do @mail.reply.in_reply_to.should eq '473FFE27.20003@xxx.org' end it "should append to the original's references list" do @mail.reply[:references].message_ids.should eq ['473FF3B8.9020707@xxx.org', '348F04F142D69C21-291E56D292BC@xxxx.net', '473FFE27.20003@xxx.org'] end it "should not append another RE:" do @mail.reply.subject.should eq "Re: Test reply email" end end describe "to a reply with an in-reply-to with a single message id but no references header" do before do @mail = Mail.new do in_reply_to '<1234@test.lindsaar.net>' message_id '5678@test.lindsaar.net' end end it "should have a references consisting of the in-reply-to and message_id fields" do @mail.reply[:references].message_ids.should eq ['1234@test.lindsaar.net', '5678@test.lindsaar.net'] end end describe "to a reply with an in-reply-to with multiple message ids but no references header" do before do @mail = Mail.new do in_reply_to '<1234@test.lindsaar.net> <5678@test.lindsaar.net>' message_id '90@test.lindsaar.net' end end # Behavior is actually not defined in RFC2822, so we'll just leave it empty it "should have no references header" do @mail.references.should be_nil end end end describe 'SMTP envelope From' do it 'should respond' do Mail::Message.new.should respond_to(:smtp_envelope_from) end it 'should default to return_path, sender, or first from address' do message = Mail::Message.new do return_path 'return' sender 'sender' from 'from' end message.smtp_envelope_from.should eq 'return' message.return_path = nil message.smtp_envelope_from.should eq 'sender' message.sender = nil message.smtp_envelope_from.should eq 'from' end it 'can be overridden' do message = Mail::Message.new { return_path 'return' } message.smtp_envelope_from = 'envelope_from' message.smtp_envelope_from.should eq 'envelope_from' message.smtp_envelope_from = 'declared_from' message.smtp_envelope_from.should eq 'declared_from' message.smtp_envelope_from = nil message.smtp_envelope_from.should eq 'return' end end describe 'SMTP envelope To' do it 'should respond' do Mail::Message.new.should respond_to(:smtp_envelope_to) end it 'should default to destinations' do message = Mail::Message.new do to 'to' cc 'cc' bcc 'bcc' end message.smtp_envelope_to.should eq message.destinations end it 'can be overridden' do message = Mail::Message.new { to 'to' } message.smtp_envelope_to = 'envelope_to' message.smtp_envelope_to.should eq %w(envelope_to) message.smtp_envelope_to = 'declared_to' message.smtp_envelope_to.should eq %w(declared_to) message.smtp_envelope_to = nil message.smtp_envelope_to.should eq %w(to) end end end mail-2.5.4/spec/mail/mime_messages_spec.rb000066400000000000000000000525721214434061600205110ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "MIME Emails" do describe "general helper methods" do it "should read a mime version from an email" do mail = Mail.new("Mime-Version: 1.0") mail.mime_version.should eq '1.0' end it "should return nil if the email has no mime version" do mail = Mail.new("To: bob") mail.mime_version.should eq nil end it "should read the content-transfer-encoding" do mail = Mail.new("Content-Transfer-Encoding: quoted-printable") mail.content_transfer_encoding.should eq 'quoted-printable' end it "should read the content-description" do mail = Mail.new("Content-Description: This is a description") mail.content_description.should eq 'This is a description' end it "should return the content-type" do mail = Mail.new("Content-Type: text/plain") mail.mime_type.should eq 'text/plain' end it "should return the charset" do mail = Mail.new("Content-Type: text/plain; charset=utf-8") mail.charset.should eq 'utf-8' end it "should allow you to set the charset" do mail = Mail.new mail.charset = 'utf-8' mail.charset.should eq 'utf-8' end it "should return the main content-type" do mail = Mail.new("Content-Type: text/plain") mail.main_type.should eq 'text' end it "should return the sub content-type" do mail = Mail.new("Content-Type: text/plain") mail.sub_type.should eq 'plain' end it "should return the content-type parameters" do mail = Mail.new("Content-Type: text/plain; charset=US-ASCII; format=flowed") mail.content_type_parameters.should eql({"charset" => 'US-ASCII', "format" => 'flowed'}) end it "should recognize a multipart email" do mail = Mail.read(fixture('emails', 'mime_emails', 'raw_email7.eml')) mail.should be_multipart end it "should recognize a non multipart email" do mail = Mail.read(fixture('emails', 'plain_emails', 'basic_email.eml')) mail.should_not be_multipart end it "should not report the email as :attachment?" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_pdf.eml'))) mail.attachment?.should eq false end it "should report the email as :attachment?" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_only_email.eml'))) mail.attachment?.should eq true end it "should recognize an attachment part" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_pdf.eml'))) mail.should_not be_attachment mail.parts[0].attachment?.should eq false mail.parts[1].attachment?.should eq true end it "should give how may (top level) parts there are" do mail = Mail.read(fixture('emails', 'mime_emails', 'raw_email7.eml')) mail.parts.length.should eq 2 end it "should give the content_type of each part" do mail = Mail.read(fixture('emails', 'mime_emails', 'raw_email11.eml')) mail.mime_type.should eq 'multipart/alternative' mail.parts[0].mime_type.should eq 'text/plain' mail.parts[1].mime_type.should eq 'text/enriched' end it "should report the mail :has_attachments?" do mail = Mail.read(fixture(File.join('emails', 'attachment_emails', 'attachment_pdf.eml'))) mail.should be_has_attachments end it "should only split on exact boundary matches" do mail = Mail.read(fixture('emails', 'mime_emails', 'email_with_similar_boundaries.eml')) mail.parts.size.should eq 2 mail.parts.first.parts.size.should eq 2 mail.boundary.should eq "----=_NextPart_476c4fde88e507bb8028170e8cf47c73" mail.parts.first.boundary.should eq "----=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt" end end describe "multipart emails" do it "should add a boundary if there is none defined and a part is added" do mail = Mail.new do part('This is a part') part('This is another part') end mail.boundary.should_not be_nil end it "should not add a boundary for a message that is only an attachment" do mail = Mail.new mail.attachments['test.png'] = "2938492384923849" mail.boundary.should be_nil end end describe "multipart/alternative emails" do it "should know what its boundary is if it is a multipart document" do mail = Mail.new('Content-Type: multipart/mixed; boundary="--==Boundary"') mail.boundary.should eq "--==Boundary" end it "should return nil if there is no content-type defined" do mail = Mail.new mail.boundary.should eq nil end it "should assign the text part and allow you to reference" do mail = Mail.new text_mail = Mail.new("This is Text") mail.text_part = text_mail mail.text_part.should eq text_mail end it "should not assign a nil text part" do mail = Mail.new mail.text_part = nil mail.text_part.should be_nil end it "should assign the html part and allow you to reference" do mail = Mail.new html_mail = Mail.new("This is HTML") mail.html_part = html_mail mail.html_part.should eq html_mail end it "should not assign a nil html part" do mail = Mail.new mail.html_part = nil mail.html_part.should be_nil end it "should set default content type on assigned text and html parts" do mail = Mail.new mail.text_part = Mail.new mail.text_part.content_type.should eq 'text/plain' mail.html_part = Mail.new mail.html_part.content_type.should eq 'text/html' end it "should set default content type on declared text and html parts" do mail = Mail.new mail.text_part { } mail.text_part.content_type.should eq 'text/plain' mail.html_part { } mail.html_part.content_type.should eq 'text/html' end it "should not override content type" do mail = Mail.new mail.text_part { content_type 'text/plain+foo' } mail.text_part.content_type.should eq 'text/plain+foo' mail.html_part { content_type 'text/html+foo' } mail.html_part.content_type.should eq 'text/html+foo' end it "should add the html part and text part" do mail = Mail.new mail.text_part = Mail::Part.new do body "This is Text" end mail.html_part = Mail::Part.new do content_type "text/html; charset=US-ASCII" body "This is HTML" end mail.parts.length.should eq 2 mail.parts.first.class.should eq Mail::Part mail.parts.last.class.should eq Mail::Part end it "should remove the html part and back out of multipart/alternative if set to nil" do mail = Mail.new mail.text_part = Mail::Part.new mail.html_part = Mail::Part.new mail.parts.length.should eq 2 mail.html_part = nil mail.parts.length.should eq 1 mail.boundary.should be_nil mail.content_type.should be_nil end it "should remove the text part and back out of multipart/alternative if set to nil" do mail = Mail.new mail.text_part = Mail::Part.new mail.html_part = Mail::Part.new mail.parts.length.should eq 2 mail.text_part = nil mail.parts.length.should eq 1 mail.boundary.should be_nil mail.content_type.should be_nil end it "should set the content type to multipart/alternative if you assign html and text parts" do mail = Mail.new mail.text_part = Mail::Part.new do body "This is Text" end mail.html_part = Mail::Part.new do content_type "text/html; charset=US-ASCII" body "This is HTML" end mail.to_s.should =~ %r|Content-Type: multipart/alternative;\s+boundary="#{mail.boundary}"| end it "should set the content type to multipart/alternative if you declare html and text parts" do mail = Mail.new mail.text_part { } mail.html_part { } mail.to_s.should =~ %r|Content-Type: multipart/alternative;\s+boundary="#{mail.boundary}"| end it "should not set the content type to multipart/alternative if you declare an html part but not a text part" do mail = Mail.new mail.html_part { } mail.to_s.should_not =~ %r|Content-Type: multipart/alternative;\s+boundary="#{mail.boundary}"| end it "should not set the content type to multipart/alternative if you declare a text part but not an html part" do mail = Mail.new mail.text_part { } mail.to_s.should_not =~ %r|Content-Type: multipart/alternative;\s+boundary="#{mail.boundary}"| end it "should add the end boundary tag" do mail = Mail.new mail.text_part = Mail::Part.new do body "This is Text" end mail.html_part = Mail::Part.new do content_type "text/html; charset=US-ASCII" body "This is HTML" end mail.to_s.should =~ %r|#{mail.boundary}--| end it "should not put message-ids into parts" do mail = Mail.new('Subject: FooBar') mail.text_part = Mail::Part.new do body "This is Text" end mail.html_part = Mail::Part.new do content_type "text/html; charset=US-ASCII" body "This is HTML" end mail.to_s mail.parts.first.message_id.should be_nil mail.parts.last.message_id.should be_nil end it "should create a multipart/alternative email through a block" do mail = Mail.new do to 'nicolas.fouche@gmail.com' from 'Mikel Lindsaar ' subject 'First multipart email sent with Mail' text_part do body 'This is plain text' end html_part do content_type 'text/html; charset=UTF-8' body '

    This is HTML

    ' end end mail.should be_multipart mail.parts.length.should eq 2 mail.text_part.class.should eq Mail::Part mail.text_part.body.to_s.should eq 'This is plain text' mail.html_part.class.should eq Mail::Part mail.html_part.body.to_s.should eq '

    This is HTML

    ' end it "should detect an html_part in an existing email" do m = Mail.new(:content_type => 'multipart/alternative') m.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML TEXT')) m.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN TEXT')) m.text_part.body.decoded.should eq 'PLAIN TEXT' m.html_part.body.decoded.should eq 'HTML TEXT' end it "should detect a text_part in an existing email with plain text attachment" do m = Mail.new(:content_type => 'multipart/alternative') m.add_file(fixture('attachments', 'てすと.txt')) m.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML TEXT')) m.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN TEXT')) m.text_part.body.decoded.should eq 'PLAIN TEXT' m.html_part.body.decoded.should eq 'HTML TEXT' end it "should detect an html_part in a multi level mime email" do m = Mail.new(:content_type => 'multipart/mixed') a = Mail::Part.new(:content_type => 'text/script', :body => '12345') p = Mail::Part.new(:content_type => 'multipart/alternative') p.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML TEXT')) p.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN TEXT')) m.add_part(p) m.add_part(a) m.text_part.body.decoded.should eq 'PLAIN TEXT' m.html_part.body.decoded.should eq 'HTML TEXT' end it "should only the first part on a stupidly overly complex email" do m = Mail.new(:content_type => 'multipart/mixed') a = Mail::Part.new(:content_type => 'text/script', :body => '12345') m.add_part(a) b = Mail::Part.new(:content_type => 'multipart/alternative') b.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML TEXT')) b.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN TEXT')) m.add_part(b) c = Mail::Part.new(:content_type => 'multipart/alternative') c.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML 2 TEXT')) c.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN 2 TEXT')) b.add_part(c) d = Mail::Part.new(:content_type => 'multipart/alternative') d.add_part(Mail::Part.new(:content_type => 'text/html', :body => 'HTML 3 TEXT')) d.add_part(Mail::Part.new(:content_type => 'text/plain', :body => 'PLAIN 3 TEXT')) b.add_part(d) m.text_part.body.decoded.should eq 'PLAIN TEXT' m.html_part.body.decoded.should eq 'HTML TEXT' end end describe "finding attachments" do it "should return an array of attachments" do mail = Mail.read(fixture('emails', 'attachment_emails', 'attachment_content_disposition.eml')) mail.attachments.length.should eq 1 mail.attachments.first.filename.should eq 'hello.rb' end it "should return an array of attachments" do mail = Mail.read(fixture('emails', 'mime_emails', 'raw_email_with_nested_attachment.eml')) mail.attachments.length.should eq 2 mail.attachments[0].filename.should eq 'byo-ror-cover.png' mail.attachments[1].filename.should eq 'smime.p7s' end end describe "adding a file attachment" do it "should set to multipart/mixed if a text part and you add an attachment" do mail = Mail::Message.new mail.text_part { body("log message goes here") } mail.add_file(fixture('attachments', 'test.png')) mail.mime_type.should eq 'multipart/mixed' end it "should set to multipart/mixed if you add an attachment and then a text part" do mail = Mail::Message.new mail.add_file(fixture('attachments', 'test.png')) mail.text_part { body("log message goes here") } mail.mime_type.should eq 'multipart/mixed' end it "should add a part given a filename" do mail = Mail::Message.new mail.add_file(fixture('attachments', 'test.png')) mail.parts.length.should eq 1 # First part is an empty text body end it "should give the part the right content type" do mail = Mail::Message.new mail.add_file(fixture('attachments', 'test.png')) mail.parts.first[:content_type].content_type.should eq 'image/png' end it "should return attachment objects" do mail = Mail::Message.new mail.add_file(fixture('attachments', 'test.png')) mail.attachments.first.class.should eq Mail::Part end it "should be return an aray of attachments" do mail = Mail::Message.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') add_file fixture('attachments', 'test.jpg') add_file fixture('attachments', 'test.pdf') add_file fixture('attachments', 'test.zip') end mail.attachments.length.should eq 4 mail.attachments.each { |a| a.class.should eq Mail::Part } end it "should return the filename of each attachment" do mail = Mail::Message.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') add_file fixture('attachments', 'test.jpg') add_file fixture('attachments', 'test.pdf') add_file fixture('attachments', 'test.zip') end mail.attachments[0].filename.should eq 'test.png' mail.attachments[1].filename.should eq 'test.jpg' mail.attachments[2].filename.should eq 'test.pdf' mail.attachments[3].filename.should eq 'test.zip' end it "should return the type/subtype of each attachment" do mail = Mail::Message.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') add_file fixture('attachments', 'test.jpg') add_file fixture('attachments', 'test.pdf') add_file fixture('attachments', 'test.zip') end mail.attachments[0].mime_type.should eq 'image/png' mail.attachments[1].mime_type.should eq 'image/jpeg' mail.attachments[2].mime_type.should eq 'application/pdf' mail.attachments[3].mime_type.should eq 'application/zip' end it "should return the content of each attachment" do mail = Mail::Message.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') add_file fixture('attachments', 'test.jpg') add_file fixture('attachments', 'test.pdf') add_file fixture('attachments', 'test.zip') end if RUBY_VERSION >= '1.9' tripped = mail.attachments[0].decoded original = File.open(fixture('attachments', 'test.png'), 'rb', &:read) tripped.should eq original tripped = mail.attachments[1].decoded original = File.open(fixture('attachments', 'test.jpg'), 'rb', &:read) tripped.should eq original tripped = mail.attachments[2].decoded original = File.open(fixture('attachments', 'test.pdf'), 'rb', &:read) tripped.should eq original tripped = mail.attachments[3].decoded original = File.open(fixture('attachments', 'test.zip'), 'rb', &:read) tripped.should eq original else mail.attachments[0].decoded.should eq File.read(fixture('attachments', 'test.png')) mail.attachments[1].decoded.should eq File.read(fixture('attachments', 'test.jpg')) mail.attachments[2].decoded.should eq File.read(fixture('attachments', 'test.pdf')) mail.attachments[3].decoded.should eq File.read(fixture('attachments', 'test.zip')) end end it "should allow you to send in file data instead of having to read it" do file_data = File.open(fixture('attachments', 'test.png'), 'rb', &:read) mail = Mail::Message.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file(:filename => 'test.png', :content => file_data) end if RUBY_VERSION >= '1.9' tripped = mail.attachments[0].decoded original = File.open(fixture('attachments', 'test.png'), 'rb', &:read) tripped.should eq original else mail.attachments[0].decoded.should eq File.open(fixture('attachments', 'test.png'), 'rb', &:read) end end it "should be able to add a body before adding a file" do m = Mail.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' body "Attached" add_file fixture('attachments', 'test.png') end m.attachments.length.should eq 1 m.parts.length.should eq 2 m.parts[0].body.should eq "Attached" m.parts[1].filename.should eq "test.png" end it "should allow you to add a body as text part if you have added a file" do m = Mail.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') body "Attached" end m.parts.length.should eq 2 m.parts.first[:content_type].content_type.should eq 'image/png' m.parts.last[:content_type].content_type.should eq 'text/plain' end it "should allow you to add a body as text part if you have added a file and not truncate after newlines - issue 208" do m = Mail.new do from 'mikel@from.lindsaar.net' subject 'Hello there Mikel' to 'mikel@to.lindsaar.net' add_file fixture('attachments', 'test.png') body "First Line\n\nSecond Line\n\nThird Line\n\n" #Note: trailing \n\n is stripped off by Mail::Part initialization end m.parts.length.should eq 2 m.parts.first[:content_type].content_type.should eq 'image/png' m.parts.last[:content_type].content_type.should eq 'text/plain' m.parts.last.to_s.should match(/^First Line\r\n\r\nSecond Line\r\n\r\nThird Line/) end it "should not raise a warning if there is a charset defined and there are non ascii chars in the body" do body = "This is NOT plain text ASCII − かきくけこ" mail = Mail.new mail.body = body mail.charset = 'UTF-8' mail.add_file fixture('attachments', 'test.png') STDERR.should_not_receive(:puts) mail.to_s end end end mail-2.5.4/spec/mail/multibyte_spec.rb000066400000000000000000000005671214434061600177060ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "multibyte/chars" do Chars = Mail::Multibyte::Chars it "should upcase" do chars = Chars.new('Laurent, où sont les tests ?') chars.upcase.should == "LAURENT, OÙ SONT LES TESTS ?" end it "should downcase" do chars = Chars.new('VĚDA A VÝZKUM') chars.downcase.should == "věda a výzkum" end end mail-2.5.4/spec/mail/multipart_report_spec.rb000066400000000000000000000070741214434061600213040ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "multipart/report emails" do it "should know if it is a multipart report type" do mail = Mail.read(fixture('emails', 'multipart_report_emails', 'report_422.eml')) mail.should be_multipart_report end describe "delivery-status reports" do it "should know if it is a deliver-status report" do mail = Mail.read(fixture('emails', 'multipart_report_emails', 'report_422.eml')) mail.should be_delivery_status_report end it "should find its message/delivery-status part" do mail = Mail.read(fixture('emails', 'multipart_report_emails', 'report_422.eml')) mail.delivery_status_part.should_not be_nil end it "should handle a report that has a human readable message/delivery-status" do mail = Mail.read(fixture('emails', 'multipart_report_emails', 'multipart_report_multiple_status.eml')) mail.should be_bounced end describe "multipart reports with more than one address" do it "should not crash" do mail1 = Mail.read(fixture('emails', 'multipart_report_emails', 'multi_address_bounce1.eml')) mail2 = Mail.read(fixture('emails', 'multipart_report_emails', 'multi_address_bounce2.eml')) doing { mail1.bounced? }.should_not raise_error doing { mail2.bounced? }.should_not raise_error end it "should not know that a multi address email was bounced" do mail1 = Mail.read(fixture('emails', 'multipart_report_emails', 'multi_address_bounce1.eml')) mail2 = Mail.read(fixture('emails', 'multipart_report_emails', 'multi_address_bounce2.eml')) mail1.should be_bounced mail2.should be_bounced end end describe "temporary failure" do before(:each) do @mail = Mail.read(fixture('emails', 'multipart_report_emails', 'report_422.eml')) end it "should be bounced" do @mail.should_not be_bounced end it "should say action 'delayed'" do @mail.action.should eq 'delayed' end it "should give a final recipient" do @mail.final_recipient.should eq 'RFC822; fraser@oooooooo.com.au' end it "should give an error code" do @mail.error_status.should eq '4.2.2' end it "should give a diagostic code" do @mail.diagnostic_code.should eq 'SMTP; 452 4.2.2 ... Mailbox full' end it "should give a remote-mta" do @mail.remote_mta.should eq 'DNS; mail.oooooooo.com.au' end it "should be retryable" do @mail.should be_retryable end end describe "permanent failure" do before(:each) do @mail = Mail.read(fixture('emails', 'multipart_report_emails', 'report_530.eml')) end it "should be bounced" do @mail.should be_bounced end it "should say action 'failed'" do @mail.action.should eq 'failed' end it "should give a final recipient" do @mail.final_recipient.should eq 'RFC822; edwin@zzzzzzz.com' end it "should give an error code" do @mail.error_status.should eq '5.3.0' end it "should give a diagostic code" do @mail.diagnostic_code.should eq 'SMTP; 553 5.3.0 ... Unknown E-Mail Address' end it "should give a remote-mta" do @mail.remote_mta.should eq 'DNS; mail.zzzzzz.com' end it "should be retryable" do @mail.should_not be_retryable end end end end mail-2.5.4/spec/mail/network/000077500000000000000000000000001214434061600160125ustar00rootroot00000000000000mail-2.5.4/spec/mail/network/delivery_methods/000077500000000000000000000000001214434061600213605ustar00rootroot00000000000000mail-2.5.4/spec/mail/network/delivery_methods/exim_spec.rb000066400000000000000000000152721214434061600236700ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "exim delivery agent" do before(:each) do # Reset all defaults back to original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true } end end it "should send an email using exim" do Mail.defaults do delivery_method :exim end mail = Mail.new do from 'roger@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "roger@test.lindsaar.net" --', '"marcel@test.lindsaar.net" "bob@test.lindsaar.net"', mail.encoded) mail.deliver! end describe "return path" do it "should send an email with a return-path using exim" do Mail.defaults do delivery_method :exim end mail = Mail.new do to "to@test.lindsaar.net" from "from@test.lindsaar.net" sender "sender@test.lindsaar.net" subject "Can't set the return-path" return_path "return@test.lindsaar.net" message_id "<1234@test.lindsaar.net>" body "body" end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "return@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should use the sender address is no return path is specified" do Mail.defaults do delivery_method :exim end mail = Mail.new do to "to@test.lindsaar.net" from "from@test.lindsaar.net" sender "sender@test.lindsaar.net" subject "Can't set the return-path" message_id "<1234@test.lindsaar.net>" body "body" end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "sender@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should use the from address is no return path or sender are specified" do Mail.defaults do delivery_method :exim end mail = Mail.new do to "to@test.lindsaar.net" from "from@test.lindsaar.net" subject "Can't set the return-path" message_id "<1234@test.lindsaar.net>" body "body" end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "from@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should escape the return path address" do Mail.defaults do delivery_method :exim end mail = Mail.new do to 'to@test.lindsaar.net' from '"from+suffix test"@test.lindsaar.net' subject 'Can\'t set the return-path' message_id '<1234@test.lindsaar.net>' body 'body' end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "\"from+suffix test\"@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should quote the destinations to ensure leading -hyphen doesn't confuse exim" do Mail.defaults do delivery_method :exim end mail = Mail.new do to '-hyphen@test.lindsaar.net' from 'from@test.lindsaar.net' end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', '-i -t -f "from@test.lindsaar.net" --', '"-hyphen@test.lindsaar.net"', mail.encoded) mail.deliver end end it "should still send an email if the settings have been set to nil" do Mail.defaults do delivery_method :exim, :arguments => nil end mail = Mail.new do from 'from@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', ' -f "from@test.lindsaar.net" --', '"marcel@test.lindsaar.net" "bob@test.lindsaar.net"', mail.encoded) mail.deliver! end it "should escape evil haxxor attemptes" do Mail.defaults do delivery_method :exim, :arguments => nil end mail = Mail.new do from '"foo\";touch /tmp/PWNED;\""@blah.com' to 'marcel@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Exim.should_receive(:call).with('/usr/sbin/exim', " -f \"\\\"foo\\\\\\\"\\;touch /tmp/PWNED\\;\\\\\\\"\\\"@blah.com\" --", '"marcel@test.lindsaar.net"', mail.encoded) mail.deliver! end it "should raise an error if no sender is defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end end mail-2.5.4/spec/mail/network/delivery_methods/file_delivery_spec.rb000066400000000000000000000073551214434061600255530ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "SMTP Delivery Method" do before(:each) do # Reset all defaults back to an original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true } end end after(:each) do files = Dir.glob(File.join(Mail.delivery_method.settings[:location], '*')) files.each do |file| File.delete(file) end end describe "general usage" do tmpdir = File.expand_path('../../../../tmp/mail', __FILE__) it "should send an email to a file" do Mail.defaults do delivery_method :file, :location => tmpdir end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end delivery = File.join(Mail.delivery_method.settings[:location], 'marcel@amont.com') File.read(delivery).should eq mail.encoded end it "should send multiple emails to multiple files" do Mail.defaults do delivery_method :file, :location => tmpdir end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com, bob@me.com' subject 'invalid RFC2822' end delivery_one = File.join(Mail.delivery_method.settings[:location], 'marcel@amont.com') delivery_two = File.join(Mail.delivery_method.settings[:location], 'bob@me.com') File.read(delivery_one).should eq mail.encoded File.read(delivery_two).should eq mail.encoded end it "should only create files based on the addr_spec of the destination" do Mail.defaults do delivery_method :file, :location => tmpdir end Mail.deliver do from 'roger@moore.com' to '"Long, stupid email address" ' subject 'invalid RFC2822' end delivery = File.join(Mail.delivery_method.settings[:location], 'mikel@test.lindsaar.net') File.exists?(delivery).should be_true end it "should use the base name of the file name to prevent file system traversal" do Mail.defaults do delivery_method :file, :location => tmpdir end Mail.deliver do from 'roger@moore.com' to '../../../../../../../../../../../tmp/pwn' subject 'evil hacker' end delivery = File.join(Mail.delivery_method.settings[:location], 'pwn') File.exists?(delivery).should be_true end it "should raise an error if no sender is defined" do Mail.defaults do delivery_method :file, :location => tmpdir end lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do Mail.defaults do delivery_method :file, :location => tmpdir end lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end end end mail-2.5.4/spec/mail/network/delivery_methods/sendmail_spec.rb000066400000000000000000000163311214434061600245170ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "sendmail delivery agent" do before(:each) do # Reset all defaults back to original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true } end end it "should send an email using sendmail" do Mail.defaults do delivery_method :sendmail end mail = Mail.new do from 'roger@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "roger@test.lindsaar.net" --', '"marcel@test.lindsaar.net" "bob@test.lindsaar.net"', mail.encoded) mail.deliver! end it "should spawn a sendmail process" do Mail.defaults do delivery_method :sendmail end mail = Mail.new do from 'roger@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Sendmail.should_receive(:popen).with('/usr/sbin/sendmail -i -f "roger@test.lindsaar.net" -- "marcel@test.lindsaar.net" "bob@test.lindsaar.net"') mail.deliver! end describe 'SMTP From' do it 'should explicitly pass an envelope From address to sendmail' do Mail.defaults do delivery_method :sendmail end mail = Mail.new do to "to@test.lindsaar.net" from "from@test.lindsaar.net" subject 'Can\'t set the return-path' message_id "<1234@test.lindsaar.net>" body "body" smtp_envelope_from 'smtp_from@test.lindsaar.net' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "smtp_from@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should escape the From address" do Mail.defaults do delivery_method :sendmail end mail = Mail.new do to 'to@test.lindsaar.net' from '"from+suffix test"@test.lindsaar.net' subject 'Can\'t set the return-path' message_id '<1234@test.lindsaar.net>' body 'body' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "\"from+suffix test\"@test.lindsaar.net" --', '"to@test.lindsaar.net"', mail.encoded) mail.deliver end end describe 'SMTP To' do it 'should explicitly pass envelope To addresses to sendmail' do Mail.defaults do delivery_method :sendmail end mail = Mail.new do to "to@test.lindsaar.net" from "from@test.lindsaar.net" subject 'Can\'t set the return-path' message_id "<1234@test.lindsaar.net>" body "body" smtp_envelope_to 'smtp_to@test.lindsaar.net' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "from@test.lindsaar.net" --', '"smtp_to@test.lindsaar.net"', mail.encoded) mail.deliver end it "should escape the To address" do Mail.defaults do delivery_method :sendmail end mail = Mail.new do to '"to+suffix test"@test.lindsaar.net' from 'from@test.lindsaar.net' subject 'Can\'t set the return-path' message_id '<1234@test.lindsaar.net>' body 'body' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "from@test.lindsaar.net" --', '"\"to+suffix test\"@test.lindsaar.net"', mail.encoded) mail.deliver end it "should quote the destinations to ensure leading -hyphen doesn't confuse sendmail" do Mail.defaults do delivery_method :sendmail end mail = Mail.new do to '-hyphen@test.lindsaar.net' from 'from@test.lindsaar.net' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', '-i -f "from@test.lindsaar.net" --', '"-hyphen@test.lindsaar.net"', mail.encoded) mail.deliver end end it "should still send an email if the settings have been set to nil" do Mail.defaults do delivery_method :sendmail, :arguments => nil end mail = Mail.new do from 'from@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', ' -f "from@test.lindsaar.net" --', '"marcel@test.lindsaar.net" "bob@test.lindsaar.net"', mail.encoded) mail.deliver! end it "should escape evil haxxor attemptes" do Mail.defaults do delivery_method :sendmail, :arguments => nil end mail = Mail.new do from '"foo\";touch /tmp/PWNED;\""@blah.com' to '"foo\";touch /tmp/PWNED;\""@blah.com' subject 'invalid RFC2822' end Mail::Sendmail.should_receive(:call).with('/usr/sbin/sendmail', " -f \"\\\"foo\\\\\\\"\\;touch /tmp/PWNED\\;\\\\\\\"\\\"@blah.com\" --", %("\\\"foo\\\\\\\"\\;touch /tmp/PWNED\\;\\\\\\\"\\\"@blah.com"), mail.encoded) mail.deliver! end it "should raise an error if no sender is defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end end mail-2.5.4/spec/mail/network/delivery_methods/smtp_connection_spec.rb000066400000000000000000000043221214434061600261220ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "SMTP Delivery Method" do before(:each) do Mail.defaults do smtp = Net::SMTP.start('127.0.0.1', 25) delivery_method :smtp_connection, :connection => smtp end end after(:each) do Mail.delivery_method.smtp.finish end it "should send an email using open SMTP connection" do mail = Mail.deliver do from 'roger@test.lindsaar.net' to 'marcel@test.lindsaar.net, bob@test.lindsaar.net' subject 'invalid RFC2822' smtp_envelope_from 'smtp_from' smtp_envelope_to 'smtp_to' end MockSMTP.deliveries[0][0].should eq mail.encoded MockSMTP.deliveries[0][1].should eq 'smtp_from' MockSMTP.deliveries[0][2].should eq %w(smtp_to) end it "should be able to return actual SMTP protocol response" do Mail.defaults do smtp = Net::SMTP.start('127.0.0.1', 25) delivery_method :smtp_connection, :connection => smtp, :port => 587, :return_response => true end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end response = mail.deliver! response.should eq 'OK' end it "should raise an error if no sender is defined" do Mail.defaults do smtp = Net::SMTP.start('127.0.0.1', 25) delivery_method :smtp_connection, :connection => smtp, :port => 587, :return_response => true end lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do Mail.defaults do smtp = Net::SMTP.start('127.0.0.1', 25) delivery_method :smtp_connection, :connection => smtp, :port => 587, :return_response => true end lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end end mail-2.5.4/spec/mail/network/delivery_methods/smtp_spec.rb000066400000000000000000000132271214434061600237070ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "SMTP Delivery Method" do before(:each) do # Reset all defaults back to original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true, :openssl_verify_mode => nil, :tls => nil, :ssl => nil } end MockSMTP.clear_deliveries end describe "general usage" do it "should send emails from given settings" do mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' smtp_envelope_from 'smtp_from' smtp_envelope_to 'smtp_to' end MockSMTP.deliveries[0][0].should eq mail.encoded MockSMTP.deliveries[0][1].should eq 'smtp_from' MockSMTP.deliveries[0][2].should eq %w(smtp_to) end it "should be able to send itself" do mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end mail.deliver! MockSMTP.deliveries[0][0].should eq mail.encoded MockSMTP.deliveries[0][1].should eq mail.from[0] MockSMTP.deliveries[0][2].should eq mail.destinations end it "should be able to return actual SMTP protocol response" do Mail.defaults do delivery_method :smtp, :address => 'smtp.mockup.com', :port => 587, :return_response => true end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end response = mail.deliver! response.should eq 'OK' end end describe "enabling tls" do def redefine_verify_none(new_value) OpenSSL::SSL.send(:remove_const, :VERIFY_NONE) OpenSSL::SSL.send(:const_set, :VERIFY_NONE, new_value) end it "should use OpenSSL::SSL::VERIFY_NONE if a context" do # config can't be setup until redefined redefine_verify_none(OpenSSL::SSL::SSLContext.new) Mail.defaults do delivery_method :smtp, :address => 'smtp.mockup.com', :port => 587 end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end doing { mail.deliver! }.should_not raise_error(TypeError) end it "should ignore OpenSSL::SSL::VERIFY_NONE if it is 0" do # config can't be setup until redefined redefine_verify_none(0) Mail.defaults do delivery_method :smtp, :address => 'smtp.mockup.com', :port => 587 end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end doing { mail.deliver! }.should_not raise_error(TypeError) end end describe "enabling ssl" do def redefine_verify_none(new_value) OpenSSL::SSL.send(:remove_const, :VERIFY_NONE) OpenSSL::SSL.send(:const_set, :VERIFY_NONE, new_value) end it "should use OpenSSL::SSL::VERIFY_NONE if a context" do # config can't be setup until redefined redefine_verify_none(OpenSSL::SSL::SSLContext.new) Mail.defaults do delivery_method :smtp, :address => 'smtp.mockup.com', :port => 587, :tls => true end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end doing { mail.deliver! }.should_not raise_error(TypeError) end it "should ignore OpenSSL::SSL::VERIFY_NONE if it is 0" do # config can't be setup until redefined redefine_verify_none(0) Mail.defaults do delivery_method :smtp, :address => 'smtp.mockup.com', :port => 587, :tls => true end mail = Mail.deliver do from 'roger@moore.com' to 'marcel@amont.com' subject 'invalid RFC2822' end doing { mail.deliver! }.should_not raise_error(TypeError) end end describe "SMTP Envelope" do it "uses the envelope From and To addresses" do Mail.deliver do to "to@someemail.com" from "from@someemail.com" message_id "<1234@someemail.com>" body "body" smtp_envelope_to "smtp_to@someemail.com" smtp_envelope_from "smtp_from@someemail.com" end MockSMTP.deliveries[0][1].should eq 'smtp_from@someemail.com' MockSMTP.deliveries[0][2].should eq %w(smtp_to@someemail.com) end it "should raise if there is no envelope From address" do lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end end end mail-2.5.4/spec/mail/network/delivery_methods/test_mailer_spec.rb000066400000000000000000000050171214434061600252320ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "Mail::TestMailer" do before(:each) do # Reset all defaults back to original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true } Mail::TestMailer.deliveries.clear end end it "should have no deliveries when first initiated" do Mail.defaults do delivery_method :test end Mail::TestMailer.deliveries.should be_empty end it "should deliver an email to the Mail::TestMailer.deliveries array" do Mail.defaults do delivery_method :test end mail = Mail.new do to 'mikel@me.com' from 'you@you.com' subject 'testing' body 'hello' end mail.deliver Mail::TestMailer.deliveries.length.should eq 1 Mail::TestMailer.deliveries.first.should eq mail end it "should clear the deliveries when told to" do Mail.defaults do delivery_method :test end mail = Mail.new do to 'mikel@me.com' from 'you@you.com' subject 'testing' body 'hello' end mail.deliver Mail::TestMailer.deliveries.length.should eq 1 Mail::TestMailer.deliveries.clear Mail::TestMailer.deliveries.should be_empty end it "should raise an error if no sender is defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do to "to@somemail.com" subject "Email with no sender" body "body" end end.should raise_error('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.') end it "should raise an error if no recipient if defined" do Mail.defaults do delivery_method :test end lambda do Mail.deliver do from "from@somemail.com" subject "Email with no recipient" body "body" end end.should raise_error('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.') end it "should save settings passed to initialize" do Mail::TestMailer.new(:setting => true).settings.should include(:setting => true) end end mail-2.5.4/spec/mail/network/retriever_methods/000077500000000000000000000000001214434061600215445ustar00rootroot00000000000000mail-2.5.4/spec/mail/network/retriever_methods/imap_spec.rb000066400000000000000000000174521214434061600240420ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "IMAP Retriever" do before(:each) do Mail.defaults do retriever_method :imap, { :address => 'localhost', :port => 993, :user_name => nil, :password => nil, :enable_ssl => true } end end describe "find with and without block" do it "should find all emails with a given block" do MockIMAP.should be_disconnected messages = [] Mail.all do |message| messages << message end messages.map { |m| m.raw_source }.sort.should eq MockIMAP.examples.map { |m| m.attr['RFC822']}.sort MockIMAP.should be_disconnected end it "should get all emails without a given block" do MockIMAP.should be_disconnected messages = Mail.all messages.map { |m| m.raw_source }.sort.should eq MockIMAP.examples.map { |m| m.attr['RFC822']}.sort MockIMAP.should be_disconnected end it "should get all emails and yield the imap, uid, and email when given a block of arity 3" do MockIMAP.should be_disconnected messages = [] uids = [] Mail.all do |message, imap, uid| MockIMAP.should === imap messages << message uids << uid end messages.map { |m| m.raw_source }.sort.should eq MockIMAP.examples.map { |m| m.attr['RFC822']}.sort uids.sort.should eq MockIMAP.examples.map { |m| m.number }.sort MockIMAP.should be_disconnected end end describe "find and options" do it "should handle the :count option" do messages = Mail.find(:count => :all, :what => :last, :order => :asc) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] } message = Mail.find(:count => 1, :what => :last) message.raw_source.should eq MockIMAP.examples.last.attr['RFC822'] messages = Mail.find(:count => 2, :what => :last, :order => :asc) messages[0..1].map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] }[-2..-1] end it "should handle the :what option" do messages = Mail.find(:count => :all, :what => :last) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] } messages = Mail.find(:count => 2, :what => :first, :order => :asc) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] }[0..1] end it "should handle the :order option" do messages = Mail.find(:order => :desc, :count => 5, :what => :last) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] }[-5..-1].reverse messages = Mail.find(:order => :asc, :count => 5, :what => :last) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] }[-5..-1] end it "should handle the :mailbox option" do Mail.find(:mailbox => 'SOME-RANDOM-MAILBOX') MockIMAP.mailbox.should eq 'SOME-RANDOM-MAILBOX' end it "should find the last 10 messages by default" do messages = Mail.find messages.size.should eq 10 end it "should search the mailbox 'INBOX' by default" do Mail.find MockIMAP.mailbox.should eq 'INBOX' end it "should handle the delete_after_find_option" do Mail.find(:delete_after_find => false) MockIMAP.examples.size.should eq 20 Mail.find(:delete_after_find => true) MockIMAP.examples.size.should eq 10 Mail.find(:delete_after_find => true) { |message| } MockIMAP.examples.size.should eq 10 end it "should handle the find_and_delete method" do Mail.find_and_delete(:count => 15) MockIMAP.examples.size.should eq 5 end end describe "last" do it "should find the last received messages" do messages = Mail.last(:count => 5) messages.should be_instance_of(Array) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822']}[-5..-1] end it "should find the last received message" do message = Mail.last message.raw_source.should eq MockIMAP.examples.last.attr['RFC822'] end end describe "first" do it "should find the first received messages" do messages = Mail.first(:count => 5) messages.should be_instance_of(Array) messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822']}[0..4] end it "should find the first received message" do message = Mail.first message.raw_source.should eq MockIMAP.examples.first.attr['RFC822'] end end describe "all" do it "should find all messages" do messages = Mail.all messages.size.should eq MockIMAP.examples.size messages.map { |m| m.raw_source }.should eq MockIMAP.examples.map { |m| m.attr['RFC822'] } end end describe "delete_all" do it "should delete all messages" do Mail.all Net::IMAP.should_receive(:encode_utf7).once Mail.delete_all MockIMAP.examples.size.should eq 0 end end describe "connection" do it "should raise an Error if no block is given" do lambda { Mail.connection { |m| raise ArgumentError.new } }.should raise_error end it "should yield the connection object to the given block" do Mail.connection do |connection| connection.should be_an_instance_of(MockIMAP) end end end describe "handling of options" do it "should set default options" do retrievable = Mail::IMAP.new({}) options = retrievable.send(:validate_options, {}) options[:count].should_not be_blank options[:count].should eq 10 options[:order].should_not be_blank options[:order].should eq :asc options[:what].should_not be_blank options[:what].should eq :first options[:mailbox].should_not be_blank options[:mailbox].should eq 'INBOX' end it "should not replace given configuration" do retrievable = Mail::IMAP.new({}) options = retrievable.send(:validate_options, { :mailbox => 'some/mail/box', :count => 2, :order => :asc, :what => :first }) options[:count].should_not be_blank options[:count].should eq 2 options[:order].should_not be_blank options[:order].should eq :asc options[:what].should_not be_blank options[:what].should eq :first options[:mailbox].should_not be_blank options[:mailbox].should eq 'some/mail/box' end it "should ensure utf7 conversion for mailbox names" do retrievable = Mail::IMAP.new({}) Net::IMAP.stub!(:encode_utf7 => 'UTF7_STRING') options = retrievable.send(:validate_options, { :mailbox => 'UTF8_STRING' }) options[:mailbox].should eq 'UTF7_STRING' end end describe "error handling" do it "should finish the IMAP connection if an exception is raised" do MockIMAP.should be_disconnected lambda { Mail.all { |m| raise ArgumentError.new } }.should raise_error MockIMAP.should be_disconnected end end describe "authentication mechanism" do before(:each) do @imap = MockIMAP.new MockIMAP.stub!(:new).and_return(@imap) end it "should be login by default" do @imap.should_not_receive(:authenticate) @imap.should_receive(:login).with('foo', 'secret') Mail.defaults do retriever_method :imap, {:user_name => 'foo', :password => 'secret'} end Mail.find end it "should be changeable" do @imap.should_receive(:authenticate).with('CRAM-MD5', 'foo', 'secret') @imap.should_not_receive(:login) Mail.defaults do retriever_method :imap, {:authentication => 'CRAM-MD5', :user_name => 'foo', :password => 'secret'} end Mail.find end end end mail-2.5.4/spec/mail/network/retriever_methods/pop3_spec.rb000066400000000000000000000147331214434061600237740ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "POP3 Retriever" do before(:each) do # Reset all defaults back to original state Mail.defaults do retriever_method :pop3, { :address => "localhost", :port => 995, :user_name => nil, :password => nil, :enable_ssl => true } end end describe "find with and without block" do it "should find all emails with a given block" do MockPOP3.should_not be_started messages = [] Mail.all do |message| messages << message end messages.map { |m| m.raw_source }.sort.should eq MockPOP3.popmails.map { |p| p.pop }.sort MockPOP3.should_not be_started end it "should get all emails without a given block" do MockPOP3.should_not be_started messages = [] Mail.all do |message| messages << message end messages.map { |m| m.raw_source }.sort.should eq MockPOP3.popmails.map { |p| p.pop }.sort MockPOP3.should_not be_started end end describe "find and options" do it "should handle the :count option" do messages = Mail.find(:count => :all, :what => :last, :order => :asc) messages.map { |m| m.raw_source }.sort.should eq MockPOP3.popmails.map { |p| p.pop } message = Mail.find(:count => 1, :what => :last) message.raw_source.should eq MockPOP3.popmails.map { |p| p.pop }.last messages = Mail.find(:count => 2, :what => :last, :order => :asc) messages[0..1].collect {|m| m.raw_source}.should eq MockPOP3.popmails.map { |p| p.pop }[-2..-1] end it "should handle the :what option" do messages = Mail.find(:count => :all, :what => :last) messages.map { |m| m.raw_source }.sort.should eq MockPOP3.popmails.map { |p| p.pop } messages = Mail.find(:count => 2, :what => :first, :order => :asc) messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop }[0..1] end it "should handle the :order option" do messages = Mail.find(:order => :desc, :count => 5, :what => :last) messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop }[-5..-1].reverse messages = Mail.find(:order => :asc, :count => 5, :what => :last) messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop }[-5..-1] end it "should find the last 10 messages by default" do messages = Mail.find messages.size.should eq 10 end it "should handle the delete_after_find option" do Mail.find(:delete_after_find => false) MockPOP3.popmails.each { |message| message.should_not be_deleted } Mail.find(:delete_after_find => true) MockPOP3.popmails.first(10).each { |message| message.should be_deleted } MockPOP3.popmails.last(10).each { |message| message.should_not be_deleted } Mail.find(:delete_after_find => true) { |message| } MockPOP3.popmails.first(10).each { |message| message.should be_deleted } MockPOP3.popmails.last(10).each { |message| message.should_not be_deleted } end it "should handle the find_and_delete method" do Mail.find_and_delete(:count => 15) MockPOP3.popmails.first(15).each { |message| message.should be_deleted } MockPOP3.popmails.last(5).each { |message| message.should_not be_deleted } end end describe "last" do it "should find the last received messages" do messages = Mail.last(:count => 5) messages.should be_instance_of(Array) messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop }[-5..-1] end it "should find the last received message" do message = Mail.last message.should be_instance_of(Mail::Message) message.raw_source.should eq MockPOP3.popmails.last.pop end end describe "first" do it "should find the first received messages" do messages = Mail.first(:count => 5) messages.should be_instance_of(Array) messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop }[0..4] end it "should find the first received message" do message = Mail.first message.should be_instance_of(Mail::Message) message.raw_source.should eq MockPOP3.popmails.first.pop end end describe "all" do it "should find all messages" do messages = Mail.all messages.size.should eq MockPOP3.popmails.size messages.map { |m| m.raw_source }.should eq MockPOP3.popmails.map { |p| p.pop } end end describe "delete_all" do it "should delete all mesages" do Mail.all Mail.delete_all MockPOP3.popmails.size.should eq 0 end end describe "connection" do it "should raise an Error if no block is given" do lambda { Mail.connection { |m| raise ArgumentError.new } }.should raise_error end it "should yield the connection object to the given block" do Mail.connection do |connection| connection.should be_an_instance_of(MockPOP3) end end end describe "handling of options" do it "should set default options" do retrievable = Mail::POP3.new({}) options = retrievable.send(:validate_options, {}) options[:count].should_not be_blank options[:count].should eq 10 options[:order].should_not be_blank options[:order].should eq :asc options[:what].should_not be_blank options[:what].should eq :first end it "should not replace given configuration" do retrievable = Mail::POP3.new({}) options = retrievable.send(:validate_options, { :count => 2, :order => :asc, :what => :first }) options[:count].should_not be_blank options[:count].should eq 2 options[:order].should_not be_blank options[:order].should eq :asc options[:what].should_not be_blank options[:what].should eq :first end end describe "error handling" do it "should finish the POP3 connection is an exception is raised" do MockPOP3.should_not be_started doing do Mail.all { |m| raise ArgumentError.new } end.should raise_error MockPOP3.should_not be_started end end end mail-2.5.4/spec/mail/network/retriever_methods/test_retriever_spec.rb000066400000000000000000000062041214434061600261530ustar00rootroot00000000000000require 'spec_helper' describe "Test Retriever" do before(:each) do Mail.defaults do retriever_method :test end end it "should have no emails initially" do Mail.all.should be_empty end describe "all" do before do @emails = populate(15) end it "should return all emails without a block" do Mail.all.should eq @emails end it "should return all emails with a block" do messages = [] Mail.all { |message| messages << message } messages.should eq @emails end end describe "find" do before do @emails = populate(15) end it "should handle the :count option" do Mail.find(:count => :all).should eq @emails Mail.find(:count => 1).should eq @emails.first Mail.find(:count => 5).should eq @emails[0, 5] end it "should handle the :order option" do Mail.find(:order => :asc).should eq @emails Mail.find(:order => :desc).should eq @emails.reverse end it "should handle the :what option" do Mail.find(:what => :first).should eq @emails Mail.find(:what => :first, :count => 5).should eq @emails[0, 5] Mail.find(:what => :last).should eq @emails Mail.find(:what => :last, :count => 5).should eq @emails[10, 5] end it "should handle the both of :what and :order option with :count => 1" do Mail.find(:count => 1, :what => :last, :order => :asc).should eq @emails.last Mail.find(:count => 1, :what => :first, :order => :desc).should eq @emails.first end it "should handle the :delete_after_find option" do Mail.find(:delete_after_find => false).should eq @emails Mail.find(:delete_after_find => false).should eq @emails Mail.find(:delete_after_find => true).should eq @emails Mail.find(:delete_after_find => false).should be_empty end it "should handle the both of :delete_after_find and :count option" do expect do Mail.find(:count => 5, :delete_after_find => true).should have(5).items end.to change { Mail.all.size }.by(-5) expect do Mail.find(:count => 5, :delete_after_find => true).should have(5).items end.to change { Mail.all.size }.by(-5) end it "should handle the both of :count and :delete_after_find option" do 15.times do |idx| expect do Mail.find(:count => 1, :delete_after_find => true).should eq @emails[idx] end.to change { Mail.all.size }.by(-1) end Mail.find(:count => 1, :delete_after_find => true).should be_empty end it "should handle the :delete_after_find option with messages marked not for delete" do i = 0 messages = [] Mail.find(:delete_after_find => true) do |message| if i % 2 message.mark_for_delete = false messages << message end i += 1 end Mail.all.should eq messages end end private def populate(count) (1..count).map do Mail.new do to 'mikel@me.com' from 'you@you.com' subject 'testing' body 'hello' end end.tap do |emails| Mail::TestRetriever.emails = emails.dup end end end mail-2.5.4/spec/mail/network_spec.rb000066400000000000000000000315051214434061600173550ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' class MyDelivery; def initialize(settings); end; end class MyRetriever; def initialize(settings); end; end describe "Mail" do before(:each) do # Reset all defaults back to original state Mail.defaults do delivery_method :smtp, { :address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true } retriever_method :pop3, { :address => "localhost", :port => 110, :user_name => nil, :password => nil, :enable_ssl => true } end end describe "default delivery and retriever methods" do it "should set the delivery method" do Mail.defaults do delivery_method :smtp end Mail.delivery_method.class.should eq Mail::SMTP end it "should default to settings for smtp" do Mail.delivery_method.class.should eq Mail::SMTP Mail.delivery_method.settings.should eql({:address => "localhost", :port => 25, :domain => 'localhost.localdomain', :user_name => nil, :password => nil, :authentication => nil, :enable_starttls_auto => true, :openssl_verify_mode => nil, :ssl => nil, :tls => nil }) end it "should set the retriever method" do Mail.defaults do retriever_method :pop3 end Mail.retriever_method.class.should eq Mail::POP3 end it "should default to settings for pop3" do Mail.retriever_method.class.should eq Mail::POP3 Mail.retriever_method.settings.should eql({:address => "localhost", :port => 110, :user_name => nil, :password => nil, :authentication => nil, :enable_ssl => true }) end it "should allow us to overwrite anything we need on SMTP" do Mail.defaults do delivery_method :smtp, :port => 999 end Mail.delivery_method.settings[:address].should eq 'localhost' Mail.delivery_method.settings[:port].should eq 999 end it "should allow us to overwrite anything we need on POP3" do Mail.defaults do retriever_method :pop3, :address => 'foo.bar.com' end Mail.retriever_method.settings[:address].should eq 'foo.bar.com' Mail.retriever_method.settings[:port].should eq 110 end it "should allow you to pass in your own delivery method" do Mail.defaults do delivery_method MyDelivery end Mail.delivery_method.class.should eq MyDelivery end it "should ask the custom delivery agent for its settings" do mock_my_delivery = mock(MyDelivery) mock_my_delivery.should_receive(:settings).and_return({:these_are => :settings}) MyDelivery.should_receive(:new).and_return(mock_my_delivery) Mail.defaults do delivery_method MyDelivery end Mail.delivery_method.settings.should eql({:these_are => :settings}) end it "should allow you to pass in your own retriever method" do Mail.defaults do retriever_method MyRetriever end Mail.retriever_method.class.should eq MyRetriever end it "should ask the custom retriever agent for its settings" do mock_my_retriever = mock(MyRetriever) mock_my_retriever.should_receive(:settings).and_return({:these_are => :settings}) MyRetriever.should_receive(:new).and_return(mock_my_retriever) Mail.defaults do retriever_method MyRetriever end Mail.retriever_method.settings.should eql({:these_are => :settings}) end end describe "instance delivery methods" do it "should copy the defaults defined by Mail.defaults" do mail = Mail.new mail.delivery_method.class.should eq Mail::SMTP end it "should be able to change the delivery_method" do mail = Mail.new mail.delivery_method :file mail.delivery_method.class.should eq Mail::FileDelivery end it "should be able to change the delivery_method and pass in settings" do mail = Mail.new tmpdir = File.expand_path('../../../tmp/mail', __FILE__) mail.delivery_method :file, :location => tmpdir mail.delivery_method.class.should eq Mail::FileDelivery mail.delivery_method.settings.should eql({:location => tmpdir}) end it "should not change the default when it changes the delivery_method" do mail1 = Mail.new mail2 = Mail.new mail1.delivery_method :file Mail.delivery_method.class.should eq Mail::SMTP mail1.delivery_method.class.should eq Mail::FileDelivery mail2.delivery_method.class.should eq Mail::SMTP end it "should not change the default settings when it changes the delivery_method settings" do mail1 = Mail.new mail2 = Mail.new mail1.delivery_method :smtp, :address => 'my.own.address' Mail.delivery_method.settings[:address].should eq 'localhost' mail1.delivery_method.settings[:address].should eq 'my.own.address' mail2.delivery_method.settings[:address].should eq 'localhost' end end describe "retrieving emails via POP3" do it "should retrieve all emails via POP3" do messages = Mail.all messages.should_not be_empty for message in messages message.should be_instance_of(Mail::Message) end end end describe "sending emails via SMTP" do before(:each) do # Set the delivery method to test as the default MockSMTP.clear_deliveries end it "should deliver a mail message" do message = Mail.deliver do from 'mikel@test.lindsaar.net' to 'ada@test.lindsaar.net' subject 'Re: No way!' body 'Yeah sure' # add_file 'New Header Image', '/somefile.png' end MockSMTP.deliveries[0][0].should eq message.encoded MockSMTP.deliveries[0][1].should eq "mikel@test.lindsaar.net" MockSMTP.deliveries[0][2].should eq ["ada@test.lindsaar.net"] end it "should deliver itself" do message = Mail.new do from 'mikel@test.lindsaar.net' to 'ada@test.lindsaar.net' subject 'Re: No way!' body 'Yeah sure' # add_file 'New Header Image', '/somefile.png' end message.deliver! MockSMTP.deliveries[0][0].should eq message.encoded MockSMTP.deliveries[0][1].should eq "mikel@test.lindsaar.net" MockSMTP.deliveries[0][2].should eq ["ada@test.lindsaar.net"] end end describe "deliveries" do class MyDeliveryMethod attr_accessor :settings def initialize(values = {}); end def deliver!(message); true; end end class MyObserver def self.delivered_email(message); end end class MyDeliveryHandler def deliver_mail(mail) postman = MyDeliveryMethod.new postman.deliver!(mail) end end class MyYieldingDeliveryHandler def deliver_mail(mail) yield end end before(:each) do @message = Mail.new do from 'mikel@test.lindsaar.net' to 'ada@test.lindsaar.net' subject 'Re: No way!' body 'Yeah sure' end @message.delivery_method :test end describe "adding to Mail.deliveries" do it "should add itself to the deliveries collection on mail on delivery" do doing { @message.deliver }.should change(Mail::TestMailer.deliveries, :size).by(1) end end describe "perform_deliveries" do it "should call deliver! on the delivery method by default" do delivery_agent = MyDeliveryMethod.new @message.should_receive(:delivery_method).and_return(delivery_agent) delivery_agent.should_receive(:deliver!).with(@message) @message.deliver end it "should not call deliver if perform deliveries is set to false" do @message.perform_deliveries = false delivery_agent = MyDeliveryMethod.new @message.should_not_receive(:delivery_method) delivery_agent.should_not_receive(:deliver!) @message.deliver end it "should add to the deliveries array if perform_deliveries is true" do @message.perform_deliveries = true doing { @message.deliver }.should change(Mail::TestMailer.deliveries, :size).by(1) end it "should not add to the deliveries array if perform_deliveries is false" do @message.perform_deliveries = false doing { @message.deliver }.should_not change(Mail::TestMailer.deliveries, :size) end end describe "observers" do it "should tell its observers that it was told to deliver an email" do Mail.register_observer(MyObserver) MyObserver.should_receive(:delivered_email).with(@message).once @message.deliver end it "should tell its observers that it was told to deliver an email even if perform_deliveries is false" do Mail.register_observer(MyObserver) @message.perform_deliveries = false MyObserver.should_receive(:delivered_email).with(@message).once @message.deliver end it "should tell its observers that it was told to deliver an email even if it is using a delivery_handler" do Mail.register_observer(MyObserver) @message.delivery_handler = MyYieldingDeliveryHandler.new @message.perform_deliveries = false MyObserver.should_receive(:delivered_email).with(@message).once @message.deliver end end describe "raise_delivery_errors" do it "should pass on delivery errors if raised" do delivery_agent = MyDeliveryMethod.new @message.stub!(:delivery_method).and_return(delivery_agent) delivery_agent.stub!(:deliver!).and_raise(Exception) doing { @message.deliver }.should raise_error(Exception) end it "should not pass on delivery errors if raised raise_delivery_errors is set to false" do delivery_agent = MyDeliveryMethod.new @message.stub!(:delivery_method).and_return(delivery_agent) @message.raise_delivery_errors = false delivery_agent.stub!(:deliver!).and_raise(Exception) doing { @message.deliver }.should_not raise_error(Exception) end end describe "delivery_handler" do it "should allow you to hand off performing the actual delivery to another object" do delivery_handler = MyYieldingDeliveryHandler.new delivery_handler.should_receive(:deliver_mail).with(@message).exactly(:once) @message.delivery_handler = delivery_handler @message.deliver end it "mail should be told to :deliver once and then :deliver! once by the delivery handler" do @message.delivery_handler = MyYieldingDeliveryHandler.new @message.should_receive(:do_delivery).exactly(:once) @message.deliver end it "mail only call its delivery_method once" do @message.delivery_handler = MyYieldingDeliveryHandler.new @message.should_receive(:delivery_method).exactly(:once).and_return(Mail::TestMailer.new({})) @message.deliver end it "mail should not catch any exceptions when using a delivery_handler" do @message.delivery_handler = MyYieldingDeliveryHandler.new @message.should_receive(:delivery_method).and_raise(Exception) doing { @message.deliver }.should raise_error(Exception) end it "mail should not modify the Mail.deliveries object if using a delivery_handler that does not append to deliveries" do @message.delivery_handler = MyDeliveryHandler.new doing { @message.deliver }.should_not change(Mail::TestMailer, :deliveries) end it "should be able to just yield and let mail do its thing" do @message.delivery_handler = MyYieldingDeliveryHandler.new @message.should_receive(:do_delivery).exactly(:once) @message.deliver end end end end mail-2.5.4/spec/mail/parsers/000077500000000000000000000000001214434061600160005ustar00rootroot00000000000000mail-2.5.4/spec/mail/parsers/address_lists_parser_spec.rb000066400000000000000000000010351214434061600235550ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "AddressListsParser" do it "should parse an address" do text = 'Mikel Lindsaar , Friends: test2@lindsaar.net, Ada ;' a = Mail::AddressListsParser.new a.parse(text).should_not be_nil end it "should parse an address list separated by semicolons" do text = 'Mikel Lindsaar ; Friends: test2@lindsaar.net; Ada ;' a = Mail::AddressListsParser.new a.parse(text).should_not be_nil end end mail-2.5.4/spec/mail/parsers/content_transfer_encoding_parser_spec.rb000066400000000000000000000035661214434061600261510ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "ContentTransferEncodingParser" do it "should work" do text = "quoted-printable" a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'quoted-printable' end describe "trailing semi colons" do it "should parse" do text = "quoted-printable;" a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'quoted-printable' end it "should parse with pre white space" do text = 'quoted-printable ;' a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'quoted-printable' end it "should parse with trailing white space" do text = 'quoted-printable; ' a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'quoted-printable' end it "should parse with pre and trailing white space" do text = 'quoted-printable ; ' a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'quoted-printable' end end describe "x-token values" do it "should work" do text = 'x-my-token' a = Mail::ContentTransferEncodingParser.new a.parse(text).should_not be_nil a.parse(text).encoding.text_value.should eq 'x-my-token' end end describe "wild content-transfer-encoding" do %w(7bits 8bits 7-bit 8-bit).each do |mechanism| it "should parse #{mechanism} variant" do a = Mail::ContentTransferEncodingParser.new a.parse(mechanism).should_not be_nil a.parse(mechanism).encoding.text_value.should eq mechanism end end end end mail-2.5.4/spec/mail/part_spec.rb000066400000000000000000000121561214434061600166330ustar00rootroot00000000000000require 'spec_helper' describe Mail::Part do it "should not add a default Content-ID" do part = Mail::Part.new part.to_s part.content_id.should be_nil end it "should not add a default Content-ID to non-inline attachments" do part = Mail::Part.new(:content_disposition => 'attachment') part.to_s part.content_id.should be_nil end it "should add a default Content-ID to inline attachments" do part = Mail::Part.new(:content_disposition => 'inline') part.to_s part.content_id.should_not be_nil end it "should not add a Date, MIME-Version, or Message-ID" do part = Mail::Part.new part.to_s part.date.should be_nil part.mime_version.should be_nil part.message_id.should be_nil end it "should preserve any content id that you put into it" do part = Mail::Part.new do content_id "" body "This is Text" end part.content_id.should eq "" end it "should return an inline content_id" do part = Mail::Part.new do content_id "" body "This is Text" end part.cid.should eq "thisis@acontentid" STDERR.should_receive(:puts).with("Part#inline_content_id is deprecated, please call Part#cid instead") part.inline_content_id.should eq "thisis@acontentid" end it "should URL escape its inline content_id" do part = Mail::Part.new do content_id "" body "This is Text" end part.cid.should eq "thi%25%25sis@acontentid" STDERR.should_receive(:puts).with("Part#inline_content_id is deprecated, please call Part#cid instead") part.inline_content_id.should eq "thi%25%25sis@acontentid" end it "should add a content_id if there is none and is asked for an inline_content_id" do part = Mail::Part.new part.cid.should_not be_nil STDERR.should_receive(:puts).with("Part#inline_content_id is deprecated, please call Part#cid instead") part.inline_content_id.should_not be_nil end it "should respond correctly to inline?" do part = Mail::Part.new(:content_disposition => 'attachment') part.should_not be_inline part = Mail::Part.new(:content_disposition => 'inline') part.should be_inline end describe "parts that have a missing header" do it "should not try to init a header if there is none" do part =< (reason: 553 5.3.0 ... Unknown E-Mail Address) ----- Transcript of session follows ----- ... while talking to mail.zzzzzz.com.: >>> DATA <<< 553 5.3.0 ... Unknown E-Mail Address 550 5.1.1 ... User unknown <<< 503 5.0.0 Need RCPT (recipient) -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean. PARTEND STDERR.should_not_receive(:puts) Mail::Part.new(part) end end describe "delivery status reports" do before(:each) do part =<... Unknown E-Mail Address Last-Attempt-Date: Mon, 24 Dec 2007 10:03:53 +1100 ENDPART @delivery_report = Mail::Part.new(part) end it "should know if it is a delivery-status report" do @delivery_report.should be_delivery_status_report_part end it "should create a delivery_status_data header object" do @delivery_report.delivery_status_data.should_not be_nil end it "should be bounced" do @delivery_report.should be_bounced end it "should say action 'delayed'" do @delivery_report.action.should eq 'failed' end it "should give a final recipient" do @delivery_report.final_recipient.should eq 'RFC822; edwin@zzzzzzz.com' end it "should give an error code" do @delivery_report.error_status.should eq '5.3.0' end it "should give a diagostic code" do @delivery_report.diagnostic_code.should eq 'SMTP; 553 5.3.0 ... Unknown E-Mail Address' end it "should give a remote-mta" do @delivery_report.remote_mta.should eq 'DNS; mail.zzzzzz.com' end it "should be retryable" do @delivery_report.should_not be_retryable end end it "should correctly parse plain text raw source and not truncate after newlines - issue 208" do plain_text = "First Line\n\nSecond Line\n\nThird Line\n\n" #Note: trailing \n\n is stripped off by Mail::Part initialization part = Mail::Part.new(plain_text) part[:content_type].content_type.should eq 'text/plain' part.to_s.should match(/^First Line\r\n\r\nSecond Line\r\n\r\nThird Line/) end end mail-2.5.4/spec/mail/parts_list_spec.rb000066400000000000000000000006071214434061600200470ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "PartsList" do it "should return itself on sort" do p = Mail::PartsList.new p << 2 p << 1 p.sort.class.should eq Mail::PartsList end it "should not fail if we do not have a content_type" do p = Mail::PartsList.new order = ['text/plain'] p << 'text/plain' p << 'text/html' p.sort!(order) end end mail-2.5.4/spec/mail/round_tripping_spec.rb000066400000000000000000000032521214434061600207250ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "Round Tripping" do it "should round trip a basic email" do mail = Mail.new('Subject: FooBar') mail.body "This is Text" parsed_mail = Mail.new(mail.to_s) parsed_mail.subject.to_s.should eq "FooBar" parsed_mail.body.to_s.should eq "This is Text" end it "should round trip a html multipart email" do mail = Mail.new('Subject: FooBar') mail.text_part = Mail::Part.new do body "This is Text" end mail.html_part = Mail::Part.new do content_type "text/html; charset=US-ASCII" body "This is HTML" end parsed_mail = Mail.new(mail.to_s) parsed_mail.mime_type.should eq 'multipart/alternative' parsed_mail.boundary.should eq mail.boundary parsed_mail.parts.length.should eq 2 parsed_mail.parts[0].body.to_s.should eq "This is Text" parsed_mail.parts[1].body.to_s.should eq "This is HTML" end it "should round trip an email" do initial = Mail.new do to "mikel@test.lindsaar.net" subject "testing round tripping" body "Really testing round tripping." from "system@test.lindsaar.net" cc "nobody@test.lindsaar.net" bcc "bob@test.lindsaar.net" date Time.local(2009, 11, 6) add_file :filename => "foo.txt", :content => "I have \ntwo lines\n\n" end Mail.new(initial.encoded).encoded.should eq initial.encoded end it "should round trip attachment newlines" do body = "I have \ntwo lines\n\n" initial = Mail.new initial.add_file :filename => "foo.txt", :content => body Mail.new(initial.encoded).attachments.first.decoded.should eq body end end mail-2.5.4/spec/mail/utilities_spec.rb000066400000000000000000000247651214434061600177110ustar00rootroot00000000000000# encoding: utf-8 require 'spec_helper' describe "Utilities Module" do include Mail::Utilities describe "token safe" do describe "checking" do it "should return true if a string is token safe" do token_safe?('.abc').should be_true end it "should return false if a string is token safe" do token_safe?('?=abc').should be_false end it "should work with mb_chars" do token_safe?('.abc'.mb_chars).should be_true token_safe?('?=abc'.mb_chars).should be_false end end describe "quoting" do it "should return true if a string is token safe" do quote_token('.abc').should eq '.abc' end it "should return false if a string is token safe" do quote_token('?=abc').should eq '"?=abc"' end it "should work with mb_chars" do quote_token('.abc'.mb_chars).should eq '.abc' quote_token('?=abc'.mb_chars).should eq '"?=abc"' end end end describe "atom safe" do describe "checking" do it "should return true if a string is token safe" do atom_safe?('?=abc').should be_true end it "should return false if a string is token safe" do atom_safe?('.abc').should be_false end it "should work with mb_chars" do atom_safe?('?=abc'.mb_chars).should be_true atom_safe?('.abc'.mb_chars).should be_false end end describe "quoting" do it "should return true if a string is token safe" do quote_atom('?=abc').should eq '?=abc' end it "should return false if a string is token safe" do quote_atom('.abc').should eq '".abc"' end it "should work with mb_chars" do quote_atom('?=abc'.mb_chars).should eq '?=abc' quote_atom('.abc'.mb_chars).should eq '".abc"' end it "should work with mb_chars" do quote_atom('?=abc'.mb_chars).should eq '?=abc' quote_atom('.abc'.mb_chars).should eq '".abc"' end it "should quote white space" do quote_atom('ab abc'.mb_chars).should eq '"ab abc"' quote_atom("a\sb\ta\r\nbc".mb_chars).should eq %{"a\sb\ta\r\nbc"} end end end describe "escaping parenthesies" do it "should escape parens" do test = 'This is not (escaped)' result = 'This is not \(escaped\)' escape_paren(test).should eq result end it "should not double escape parens" do test = 'This is not \(escaped\)' result = 'This is not \(escaped\)' escape_paren(test).should eq result end it "should escape all parens" do test = 'This is not \()escaped(\)' result = 'This is not \(\)escaped\(\)' escape_paren(test).should eq result end end describe "unescaping parenthesis" do it "should work" do test = '(This is a string)' result = 'This is a string' unparen(test).should eq result end it "should work without parens" do test = 'This is a string' result = 'This is a string' unparen(test).should eq result end it "should work using ActiveSupport mb_chars" do test = '(This is a string)'.mb_chars result = 'This is a string' unparen(test).should eq result end it "should work without parens using ActiveSupport mb_chars" do test = 'This is a string'.mb_chars result = 'This is a string' unparen(test).should eq result end end describe "unescaping brackets" do it "should work" do test = '' result = 'This is a string' unbracket(test).should eq result end it "should work without brackets" do test = 'This is a string' result = 'This is a string' unbracket(test).should eq result end it "should work using ActiveSupport mb_chars" do test = ''.mb_chars result = 'This is a string' unbracket(test).should eq result end it "should work without parens using ActiveSupport mb_chars" do test = 'This is a string'.mb_chars result = 'This is a string' unbracket(test).should eq(result) end end describe "quoting phrases" do it "should quote a phrase if it is unsafe" do test = 'this.needs quoting' result = '"this.needs quoting"' dquote(test).should eq result end it "should properly quote a string, even if quoted but not escaped properly" do test = '"this needs "escaping"' result = '"this needs \"escaping"' dquote(test).should eq result end it "should quote correctly a phrase with an escaped quote in it" do test = 'this needs \"quoting' result = '"this needs \\\\\\"quoting"' dquote(test).should eq result end it "should quote correctly a phrase with an escaped backslash followed by an escaped quote in it" do test = 'this needs \\\"quoting' result = '"this needs \\\\\\\\\\"quoting"' dquote(test).should eq result end end describe "unquoting phrases" do it "should remove quotes from the edge" do unquote('"This is quoted"').should eq 'This is quoted' end it "should remove backslash escaping from quotes" do unquote('"This is \\"quoted\\""').should eq 'This is "quoted"' end it "should remove backslash escaping from any char" do unquote('"This is \\quoted"').should eq 'This is quoted' end it "should be able to handle unquoted strings" do unquote('This is not quoted').should eq 'This is not quoted' end it "should preserve backslashes in unquoted strings" do unquote('This is not \"quoted').should eq 'This is not \"quoted' end it "should be able to handle unquoted quotes" do unquote('"This is "quoted"').should eq 'This is "quoted' end end describe "parenthesizing phrases" do it "should parenthesize a phrase" do test = 'this.needs parenthesizing' result = '(this.needs parenthesizing)' paren(test).should eq result end it "should properly parenthesize a string, and escape properly" do test = 'this needs (escaping' result = '(this needs \(escaping)' paren(test).should eq result end it "should properly parenthesize a string, and escape properly (other way)" do test = 'this needs )escaping' result = '(this needs \)escaping)' paren(test).should eq result end it "should properly parenthesize a string, even if parenthesized but not escaped properly" do test = '(this needs (escaping)' result = '(this needs \(escaping)' paren(test).should eq result end it "should properly parenthesize a string, even if parenthesized but not escaped properly (other way)" do test = '(this needs )escaping)' result = '(this needs \)escaping)' paren(test).should eq result end it "should parenthesize correctly a phrase with an escaped parentheses in it" do test = 'this needs \(parenthesizing' result = '(this needs \(parenthesizing)' paren(test).should eq result end it "should parenthesize correctly a phrase with an escaped parentheses in it (other way)" do test = 'this needs \)parenthesizing' result = '(this needs \)parenthesizing)' paren(test).should eq result end it "should parenthesize correctly a phrase with an escaped backslash followed by an escaped parentheses in it" do test = 'this needs \\\(parenthesizing' result = '(this needs \\\(parenthesizing)' paren(test).should eq result end it "should parenthesize correctly a phrase with an escaped backslash followed by an escaped parentheses in it (other way)" do test = 'this needs \\\)parenthesizing' result = '(this needs \\\)parenthesizing)' paren(test).should eq result end it "should parenthesize correctly a phrase with a set of parentheses" do test = 'this (needs) parenthesizing' result = '(this \(needs\) parenthesizing)' paren(test).should eq result end end describe "bracketizing phrases" do it "should bracketize a phrase" do test = 'this.needs bracketizing' result = '' bracket(test).should eq result end it "should properly bracketize a string, and escape properly" do test = 'this needs rfc822 } @number = number end end class MockIMAP @@connection = false @@mailbox = nil @@marked_for_deletion = [] def self.examples @@examples end def initialize @@examples = [] (0..19).each do |i| @@examples << MockIMAPFetchData.new("test#{i.to_s.rjust(2, '0')}", i) end end def login(user, password) @@connection = true end def disconnect @@connection = false end def select(mailbox) @@mailbox = mailbox end def examine(mailbox) select(mailbox) end def uid_search(keys, charset=nil) [*(0..@@examples.size - 1)] end def uid_fetch(set, attr) [@@examples[set]] end def uid_store(set, attr, flags) if attr == "+FLAGS" && flags.include?(Net::IMAP::DELETED) @@marked_for_deletion << set end end def expunge @@marked_for_deletion.reverse.each do |i| # start with highest index first @@examples.delete_at(i) end @@marked_for_deletion = [] end def self.mailbox; @@mailbox end # test only def self.disconnected?; @@connection == false end def disconnected?; @@connection == false end end require 'net/imap' class Net::IMAP def self.new(*args) MockIMAP.new end end mail-2.5.4/test.rb000066400000000000000000000006521214434061600137540ustar00rootroot00000000000000require 'rubygems' require 'mail' require 'ruby-debug' smtp = { :address => 'mail.fiendz.org', :port => 587, :domain => 'fiendz.org', :user_name => 'test@fiendz.org', :password => 'foobar', :enable_starttls_auto => true, :openssl_verify_mode => 'none' } Mail.defaults { delivery_method :smtp, smtp } mail = Mail.new do from 'test@fiendz.org' to 'donald.ball@gmail.com' subject 'subject' body 'body' end mail.deliver!